⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 can_lpc2xxx.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 5 页
字号:
             {
                 cyg_can_msgbuf_info *mbox_info  = (cyg_can_msgbuf_info*) buf;
                
                 if (*len != sizeof(cyg_can_msgbuf_info)) 
                 {
                     return -EINVAL;
                 }
                 cyg_uint32 end_of_table;
                *len = sizeof(cyg_can_msgbuf_info);
              
                 HAL_READ_UINT32(CAN_ACCFILT_ENDOFTABLE, end_of_table);
                 mbox_info->count = LPC2XXX_CAN_MSG_FILTERS_MAX;
                 mbox_info->free  = (ACCFILT_RAM_SIZE - end_of_table) / ACCFILT_COMMON_ENTRY_SIZE;
             }
             break;
#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG

        
        //
        // Query hardware description of FlexCAN device driver
        //     
        case CYG_IO_GET_CONFIG_CAN_HDI :
             {
                cyg_can_hdi *hdi = (cyg_can_hdi *)buf;
                //
                // comes from high level driver so we do not need to
                // check buffer size here
                //             
                hdi->support_flags = CYGNUM_CAN_HDI_FRAMETYPE_EXT_ACTIVE
                                   | CYGNUM_CAN_HDI_FULLCAN;
             }
             break;
             
        default :
            res = -EINVAL;
    }// switch(key)
    
    return res;
}


//===========================================================================
// Send single message
//===========================================================================
static bool lpc2xxx_can_putmsg(can_channel *chan, CYG_CAN_MSG_T *pmsg, void *pdata)
{
    cyg_uint32 regval;
#ifdef CYGOPT_DEVS_CAN_LPC2XXX_USE_SELF_RECEPTION
    lpc2xxx_can_info_t  *info = (lpc2xxx_can_info_t *) chan->dev_priv;
#else
    CAN_DECLARE_INFO(info);
#endif
    
    //
    // We use only one single transmit buffer of the three available buffers
    // We use buffer 1 (buffer 2 and 3 are unused)
    //
    // The errata sheet tells the following about the transmit buffers:
    // Problem: The Triple Transmit Buffer function cannot be used.
    // Work-around: Use any one Transmit buffer only (Use either Transmit Buffer 1, 
    // Transmit Buffer 2 or Transmit Buffer 3 exclusively). The buffer you decided 
    // to use should be loaded only when there is no pending transmission.
    //
    HAL_READ_UINT32(CAN_CTRL_SR(info), regval);
    if (!(regval & SR_TX_BUF_WRITE_OK))
    {
        return false;    
    }
    
    regval = pmsg->dlc << 16;
    if (pmsg->rtr)
    {
        regval |= TFI_DLC_RTR;
    }
 
#ifdef CYGOPT_IO_CAN_EXT_CAN_ID
    if (pmsg->ext)
    {
        regval |= TFI_DLC_EXT;
    }
#endif // #define CYGOPT_IO_CAN_EXT_CAN_ID
    HAL_WRITE_UINT32(CAN_CTRL_TFI1(info), regval);                       // write DLC
    HAL_WRITE_UINT32(CAN_CTRL_TID1(info), pmsg->id);                     // write ID
    HAL_WRITE_UINT32(CAN_CTRL_TDA1(info), pmsg->data.dwords[0]);         // write first 4 data bytes
    HAL_WRITE_UINT32(CAN_CTRL_TDB1(info), pmsg->data.dwords[1]);         // write second 4 data bytes
    
    //
    // Request transmission of message
    // The errata sheet tells the following about tx request:
    // Introduction: The CAN module can lose arbitration to another CAN node during an 
    // attempt to transmit a CAN message. The message of the CAN node the arbitration was 
    // lost to is supposed to be received correctly by the CAN module.
    // Problem: Messages might not be received correctly if during a CAN Transmission the 
    // CAN bus arbitration is lost to another CAN node.
    // Work-around: Use the Self Reception Request command instead of the Transmission 
    // Request command. However, it has to be taken into account that now all transmitted
    // messages may be received if not prevented by appropriate Acceptance Filter settings. 
    // (Don't set up Acceptance Filter Message Identifiers for the messages you are
    // transmitting yourself.)
    //
#ifdef CYGOPT_DEVS_CAN_LPC2XXX_USE_SELF_RECEPTION
    // Calc last_tx_id
    regval = pmsg->id | (regval & LPC2XXX_CAN_INFO_LAST_TX_ID_FLMASK);
    
    // Save last message id to next last_tx_id
    info->last_tx_index = info->last_tx_index == 0 ? 1 : 0;
    info->last_tx_id[info->last_tx_index] = regval;
    
    // Write self transmission request
    HAL_WRITE_UINT32(CAN_CTRL_CMR(info), CMR_SELF_RX_REQ | CMR_SEND_TX_BUF1);
#else
    // Write transmission request
    HAL_WRITE_UINT32(CAN_CTRL_CMR(info), CMR_TX_REQ | CMR_SEND_TX_BUF1);
#endif
   
    return true;
}


//===========================================================================
// Read event from device driver
//===========================================================================
static bool lpc2xxx_can_getevent(can_channel *chan, CYG_CAN_EVENT_T *pevent, void *pdata)
{
    lpc2xxx_can_info_t   *info       = (lpc2xxx_can_info_t *)chan->dev_priv;
    bool                  res        = true;
    cyg_uint32            regval;
    cyg_uint32            event      = *((cyg_uint32*)pdata);
    lsc_buf_t             data;
      
    //
    // Handle RX event
    //
    if (event & ICR_RX)
    {
        cyg_uint32            id;
        
        pevent->flags |= CYGNUM_CAN_EVENT_RX;
        HAL_READ_UINT32(CAN_CTRL_RFS(info), regval); 
        HAL_READ_UINT32(CAN_CTRL_RID(info), id);

#ifdef CYGOPT_IO_CAN_EXT_CAN_ID
        if (regval & RFS_EXT)
        {
            pevent->msg.ext = CYGNUM_CAN_ID_EXT;
            pevent->msg.id = id & 0x1FFFFFFF;
        }
        else
#endif // #define CYGOPT_IO_CAN_EXT_CAN_ID
        {
#ifdef CYGOPT_IO_CAN_STD_CAN_ID
            pevent->msg.ext = CYGNUM_CAN_ID_STD;
            pevent->msg.id = id & 0x7FF;
#endif // #ifdef CYGOPT_IO_CAN_STD_CAN_ID
        } // if (regval & RFS_EXT)
        
        if (regval & RFS_RTR)
        {
            pevent->msg.rtr = CYGNUM_CAN_FRAME_RTR;
        }
        else
        {
            pevent->msg.rtr = CYGNUM_CAN_FRAME_DATA;  
            HAL_READ_UINT32(CAN_CTRL_RDA(info), pevent->msg.data.dwords[0]);
            HAL_READ_UINT32(CAN_CTRL_RDB(info), pevent->msg.data.dwords[1]);
        } //if (regval & RFS_RTR)
        pevent->msg.dlc = RFS_GET_DLC(regval);
    
        //
        // Now check if an data overrun occured - a message was lost because the 
        // preceeding message to this CAN controller was not read and released 
        // quickly enough. After reading the status we clear the overrun bit
        // 
        HAL_READ_UINT32(CAN_CTRL_GSR(info), regval);
        if (regval & GSR_DATA_OVR)
        {
            pevent->flags |= CYGNUM_CAN_EVENT_OVERRUN_RX;
            HAL_WRITE_UINT32(CAN_CTRL_CMR(info), CMR_CLEAR_DATA_OVR);
        }
    }
    
    //
    // Handle TX events
    //
    if (event & ICR_TX1)
    {
    }
    
    //
    // Handle all other events
    //
    if (event & (CAN_MISC_INT | ICR_LUT_ERR))
    {
        HAL_READ_UINT32(CAN_CTRL_GSR(info), data.dword);
        
        //
        // 1: Error Warning Interrupt -- this bit is set on every change (set or clear) of the Error
        // Status or Bus Status bit in CANSR, if the EIE bit in CAN is 1 at the time of the
        // change.
        //
        if (event & ICR_ERR_WARN)
        {
            //
            // If one of the warning counters is above 96 then the controller is in bus warning
            // state. If both counters are below 96 the this interrupt indicates that the
            // controller has left the bus warning state and is error active again
            //
            if (data.bytes[2] >= 96)
            {
                pevent->flags |= CYGNUM_CAN_EVENT_WARNING_RX;  
                info->state = CYGNUM_CAN_STATE_BUS_WARN;
            }
            else if (data.bytes[3] >= 96)
            {
                pevent->flags |= CYGNUM_CAN_EVENT_WARNING_TX;
                info->state = CYGNUM_CAN_STATE_BUS_WARN;
            }
            else
            {
                info->state = CYGNUM_CAN_STATE_ACTIVE;
            }
            LPC2XXX_DBG_PRINT("ICR_ERR_WARN (%p)\n", (void*) chan);
        }
        
        //
        // 1: Wake-Up Interrupt: this bit is set if the CAN controller is sleeping and bus activity
        // is detected, if the WUIE bit in CANIE is 1.
        //
        if (event & ICR_WAKE_UP)
        {
            pevent->flags |= CYGNUM_CAN_EVENT_LEAVING_STANDBY; 
            info->state = CYGNUM_CAN_STATE_ACTIVE;
            LPC2XXX_DBG_PRINT("ICR_WAKE_UP (%p)\n", (void*) chan);
        }
        
        //
        // Error Passive Interrupt -- this bit is set if the EPIE bit in CANIE is 1, and the CAN
        // controller switches between Error Passive and Error Active mode in either
        // direction. We have to check if the ERR bit is set in global status register.
        // If it is set, then it is a switch to error passive else it is a switch to
        // error active state
        //
        if (event & ICR_ERR_PASSIVE)
        {
            if (data.dword & GSR_ERR)
            {
                pevent->flags |= CYGNUM_CAN_EVENT_ERR_PASSIVE;    
                info->state = CYGNUM_CAN_STATE_ERR_PASSIVE;
            }
            else
            {
                info->state = CYGNUM_CAN_STATE_ACTIVE;    
            }
            LPC2XXX_DBG_PRINT("ICR_ERR_PASSIVE (%p)\n", (void*) chan);
        }
        
        //
        // Arbitration Lost Interrupt -- this bit is set if the ALIE bit in CANIE is 1, and the
        // CAN controller loses arbitration while attempting to transmit.
        //
        if (event & ICR_ARBITR_LOST)
        {
            pevent->flags |= CYGNUM_CAN_EVENT_ARBITRATION_LOST;   
            LPC2XXX_DBG_PRINT("ICR_ARBITR_LOST (%p)\n", (void*) chan);
        }
        
        //
        // 1: Bus Error Interrupt -- this bit is set if the BEIE bit in CANIE is 1, and the CAN
        // controller detects an error on the bus.
        //
        if (event & ICR_BUS_ERR)
        {
            pevent->flags |= CYGNUM_CAN_EVENT_BUS_OFF; 
            LPC2XXX_DBG_PRINT("ICR_BUS_ERR (%p)\n", (void*) chan);
        }
        
#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
        //
        // LUT error interrupt -- this bit is set if bit 0 in LUTerr is 1 and LUTerrAd
        // points to entry in filter table for this CAN controller
        //
        if(event & ICR_LUT_ERR)
        {
            pevent->flags |= CYGNUM_CAN_EVENT_FILTER_ERR;
            LPC2XXX_DBG_PRINT("ICR_LUT_ERR (%p)\n", (void*) chan);
        }
#endif

    } // if (event & (CAN_MISC_INT | ICR_LUT_ERR))
          
    return res;
}


//===========================================================================
// Kick transmitter
//===========================================================================
static void lpc2xxx_can_start_xmit(can_channel* chan)
{
    cyg_uint32 regval;
    CAN_DECLARE_INFO(chan);
    
    LPC2XXX_DBG_PRINT("start_xmit (%p)\n", (void*) chan);

    cyg_drv_dsr_lock();
    HAL_READ_UINT32(CAN_CTRL_IER(info), regval);
    regval |= IER_TX1;                           // enable tx interrupt for tx buf 1
    HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); 
    cyg_drv_dsr_unlock();
    
    //
    // kick transmitter
    //
    chan->callbacks->xmt_msg(chan, 0);  // Kick transmitter (if necessary)
}


//===========================================================================
// Stop transmitter
//===========================================================================
static void lpc2xxx_can_stop_xmit(can_channel* chan)
{
    cyg_uint32 regval; 
    CAN_DECLARE_INFO(chan);
    
    LPC2XXX_DBG_PRINT("stop_xmit (%p)\n", (void*) chan);
     
    cyg_drv_dsr_lock();
    HAL_READ_UINT32(CAN_CTRL_IER(info), regval);
    regval &= ~IER_TX1;                           // disable tx interrupt for tx buf 1
    HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); 
    cyg_drv_dsr_unlock();
}


//===========================================================================
// Low level transmit interrupt handler
//===============================================

⌨️ 快捷键说明

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