can_mcf52xx.c

来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,632 行 · 第 1/5 页

C
1,632
字号

//===========================================================================
//  Check if we received self transmitted frame
//===========================================================================
static bool flexcan_is_no_self_tx(cyg_can_event *pevent, flexcan_info *info, flexcan_mbox_info *pmbox)
{
    //
    // If we received a self transmitted frame
    // then this is not really an rx event and we return false. We rely on the
    // fact here that two devices in network do not send the same identifier
    //
    if (pevent->msg.id == info->last_tx_id)
    {
        info->last_tx_id = 0xFFFFFFFF; // set last received ID to an invalid value
        return false;
    }
    else
    {
        pevent->flags |= CYGNUM_CAN_EVENT_RX;

        //
        // check if an overun occured in this message box
        //
        if ((pmbox->ctrlstat_shadow & MBOX_RXCODE_OVERRUN) == MBOX_RXCODE_OVERRUN)
        {
            pevent->flags |= CYGNUM_CAN_EVENT_OVERRUN_RX;
        }

        return true;
    }
}


//===========================================================================
//  Read one event from can hardware - called from high level I/O CAN driver
//===========================================================================
static bool flexcan_getevent(can_channel *chan, cyg_can_event *pevent, void *pdata)
{
    flexcan_info *info           = (flexcan_info *)chan->dev_priv;
    flexcan_regs *flexcan        = (flexcan_regs *)info->base;
    bool          res            = true;
    cyg_uint16    estat;
    cyg_uint8     event_id       = *((cyg_uint8 *)pdata);
     
    //   
    // if event_id is 0 - 15 the we have a message box event
    //
    if (event_id < FLEXCAN_ERR_EVENT)
    {   
        flexcan_mbox_info *pmbox_info;
        pmbox_info = &info->mboxes[event_id];
        
        //
        // Deceide what to do according to type of message box that caused this event
        //
        switch (pmbox_info->state)
        {
            //
            // If we have an RX event then we need to read the received data from
            // message box that caused this event and fill it into message queue of
            // high level I/O CAN driver. We could handle this stuff in a function
            // because it is the same like MBOX_STATE_RX_ALL_EXT but speed is more
            // important here than codesize
            //
            case MBOX_STATE_RX_ALL_STD:
            case MBOX_STATE_RX_ALL_EXT:
            case MBOX_STATE_RX_FILT:
            {
                 //
                 // read data from message box - during processing of this function
                 // the message box is locked and cannot receive further messages
                 //
                 flexcan_read_from_mbox(chan, event_id, pevent, &(pmbox_info->ctrlstat_shadow));
                 res = flexcan_is_no_self_tx(pevent, info, pmbox_info);
                 }
                 break;           

#ifdef CYGOPT_IO_CAN_TX_EVENT_SUPPORT
            //
            // If a TX message box cause the event then we store the last transmitted
            // message into the receive message queue
            //
            case MBOX_STATE_TX:  
                 pevent->flags = CYGNUM_CAN_EVENT_TX;
                 pevent->msg = info->last_tx_msg;
                 break;
#endif // CYGOPT_IO_CAN_TX_EVENT_SUPPORT
                            
            case MBOX_STATE_REMOTE_TX:
                 break;
                 
            default:
                 res = false;
        } // switch (pmbox->state)
    }
    else // (event_id >= FLEXCAN_ERR_EVENT)
    {
        //
        // We have an status event - check if it is an bus off interrupt or an
        // error interrupt and provide error information to upper layer
        //
        HAL_READ_UINT16(&flexcan->ESTAT, estat);
        pevent->msg.data.bytes[0] = estat & 0xFF;
        pevent->msg.data.bytes[1] = (estat >> 8) & 0xFF; 
        HAL_READ_UINT8(&flexcan->RXERRCNT, pevent->msg.data.bytes[2]);
        HAL_READ_UINT8(&flexcan->TXERRCNT, pevent->msg.data.bytes[3]);
        switch (event_id)
        {
            case FLEXCAN_ERR_EVENT :
                 //
                 // indicate error passive event and provide content of estat register
                 // for a more precise error information
                 //
                 if (estat & FLEXCAN_ESTAT_FCS_ERROR_PASSIVE)
                 {
                    pevent->flags = CYGNUM_CAN_EVENT_ERR_PASSIVE;
                 }
                 //
                 // If we are not in error passive state then we check if the
                 // error counters reached the warning level
                 //
                 else
                 {               
                     //
                     // indicate tx error counter warning level reached
                     //
                     if (estat & FLEXCAN_ESTAT_TXWARN)
                     {
                         pevent->flags |= CYGNUM_CAN_EVENT_WARNING_TX;
                     }
                 
                     //
                     // indicate rx error counter warning level reached
                     //
                     if (estat & FLEXCAN_ESTAT_RXWARN)
                     {
                         pevent->flags |= CYGNUM_CAN_EVENT_WARNING_RX;
                     }
                 }
                 break;
                 
            case FLEXCAN_BUSOFF_EVENT:
                 pevent->flags = CYGNUM_CAN_EVENT_BUS_OFF;
                 break;
                 
            case FLEXCAN_WAKE_EVENT:
                 pevent->flags = CYGNUM_CAN_EVENT_LEAVING_STANDBY;
                 break;
        } // switch (event_id)
    }
    
    return res;
}


//===========================================================================
// Send one CAN message to CAN hardware
//===========================================================================
static bool flexcan_putmsg(can_channel *chan, cyg_can_message *pmsg, void *pdata)
{
    flexcan_info      *info    = (flexcan_info *)chan->dev_priv;
    flexcan_regs      *flexcan = (flexcan_regs *)info->base;
    cyg_uint8          mbox    = *((cyg_uint8 *)pdata);
    flexcan_mbox_info *pmbox   = &info->mboxes[mbox];
    cyg_uint16         iflag;
   
    HAL_READ_UINT16(&flexcan->IFLAG, iflag);
    
    //
    // check if device is busy sending a message
    //
    if (pmbox->busy)
    {
        //
        // if device is busy and the interrupt flag is set, then we know
        // that device is not busy any longer
        //
        if (iflag & (0x0001 << mbox))
        {
            HAL_WRITE_UINT16(&flexcan->IFLAG, (0x0001 << mbox));
        }
        else
        {
            return false;
        }
    }
    
    pmbox->busy    = true;        // mark transmitter as busy
    info->last_tx_id  = pmsg->id; // store message in order to identify self recieved frames 

#ifdef CYGOPT_IO_CAN_TX_EVENT_SUPPORT 
    info->last_tx_msg = *pmsg;    // store the transmitted message for TX events
#endif  
  
    flexcan_cfg_mbox_tx(&flexcan->mbox[mbox], pmsg, false); // send message
    
    return true;
}


//===========================================================================
// Flexcan start xmit - If the chip is in standby mode then a call to this
// function will cause the FlexCAN modul to leave the standby mode. So
// the output queue should be empty before entering stadby mode
//===========================================================================
static void flexcan_start_xmit(can_channel* chan)
{
    flexcan_info         *info    = (flexcan_info *)chan->dev_priv;
    CYG_INTERRUPT_STATE   saved_state;

    HAL_DISABLE_INTERRUPTS(saved_state);
    
    //
    // if we are in standby state the we leave standby state now. This is
    // the reason that the user should wait until the TX queue is empty before 
    // entering standby mode- or he should drain or flush the TX queue
    //
    if (CYGNUM_CAN_STATE_STANDBY == info->state)
    {
        flexcan_leave_standby(chan);
    }
    
    //
    // Now enable message box 15 interrupts
    //
    flexcan_mboxint_enable(info, info->tx_all_mbox);
    
    //
    // kick transmitter
    //
    chan->callbacks->xmt_msg(chan, &info->tx_all_mbox);  // Kick transmitter (if necessary)
    
    HAL_RESTORE_INTERRUPTS(saved_state);
}


//===========================================================================
// Flexcan stop transmission
//===========================================================================
static void flexcan_stop_xmit(can_channel* chan)
{
    flexcan_info         *info    = (flexcan_info *)chan->dev_priv;
    CYG_INTERRUPT_STATE  saved_state;

    HAL_DISABLE_INTERRUPTS(saved_state);
    
    //
    // Now disable message box 15 interrupts
    //
    flexcan_mboxint_disable(info, info->tx_all_mbox);

    HAL_RESTORE_INTERRUPTS(saved_state);
}


//===========================================================================
// Configure flexcan channel
//===========================================================================
static bool flexcan_config(can_channel* chan, cyg_can_info_t* config, cyg_bool init)
{
    flexcan_info    *info    = (flexcan_info *)chan->dev_priv;
    flexcan_regs    *flexcan = (flexcan_regs *)info->base;
    cyg_uint16       tmp16;
    cyg_uint8        tmp8;
    cyg_uint8        i;
    
    //
    // the first thing we need to do is to stop the chip
    //
    flexcan_stop_chip(chan);  
    
    //
    // if this is the first initialisation of the FlexCAN modul we need to execute
    // some extra steps here
    //
    if (init)
    {
#if defined(CYGPKG_DEVS_CAN_MCF52xx_FLEXCAN0) && defined(HAL_MCF52xx_FLEXCAN0_PROC_INIT)
        if (info == &flexcan_can0_info) {
            HAL_MCF52xx_FLEXCAN0_PROC_INIT();
        }
#endif
        
        //
        // Issue a reset in order to go into halt mode. The reset will set the
        // the halt bit in mcr
        //
        HAL_READ_UINT16(&flexcan->CANMCR, tmp16);
        tmp16 &= ~FLEXCAN_MCR_FRZ;
        HAL_WRITE_UINT16(&flexcan->CANMCR, tmp16);
        tmp16 |= FLEXCAN_MCR_SOFTRST;
        HAL_WRITE_UINT16(&flexcan->CANMCR, tmp16);
        HAL_DELAY_US(10);
    
        //
        // Check reset status
        //
        HAL_READ_UINT16(&flexcan->CANMCR, tmp16);
        if (tmp16 & FLEXCAN_MCR_SOFTRST)
        {
            return false;
        }
    
        //
        // Initialize the transmit and receive pin modes
        //
        HAL_WRITE_UINT8(&flexcan->CANCTRL0 , (FLEXCAN_CTRL0_TXMODE_FULL_0_DOMINANT  
                                            | FLEXCAN_CTRL0_RXMODE_0_DOMINANT)
                                            & ~FLEXCAN_CTRL0_BOFFMSK
                                            & ~FLEXCAN_CTRL0_ERRMASK);
                                            
        //
        // deactivate all message buffers - this is mandatory for configuration
        // of message buffers
        //
        for (i = FLEXCAN_MBOX_MIN; i <= FLEXCAN_MBOX_MAX; ++i)
        {
            HAL_WRITE_UINT16(&flexcan->mbox[i], MBOX_RXCODE_NOT_ACTIVE);
        }   
        
        //
        // mask all interrupts
        //
        info->imask_sha

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?