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

📄 can_lpc2xxx.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 5 页
字号:

DEVTAB_ENTRY(lpc2xxx_can1_devtab, 
             CYGPKG_DEVS_CAN_LPC2XXX_CAN1_NAME,
             0,                     // Does not depend on a lower level interface
             &cyg_io_can_devio, 
             lpc2xxx_can_init, 
             lpc2xxx_can_lookup,    // CAN driver may need initializing
             &lpc2xxx_can1_chan
    );
#endif // CYGPKG_DEVS_CAN_LPC2XXX_CAN1


//---------------------------------------------------------------------------
// CAN channel 2
//
#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN2
CYG_CAN_EVENT_T  lpc2xxx_can2_rxbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN2_QUEUESIZE_RX]; // buffer for RX can events
CYG_CAN_MSG_T    lpc2xxx_can2_txbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN2_QUEUESIZE_TX]; // buffer for TX can messages


CAN_CHANNEL_USING_INTERRUPTS(lpc2xxx_can2_chan,
                             lpc2xxx_can_lowlevel_funs,
                             lpc2xxx_can2_info,
                             CYG_CAN_BAUD_RATE(CYGNUM_DEVS_CAN_LPC2XXX_CAN2_KBAUD),
                             lpc2xxx_can2_txbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN2_QUEUESIZE_TX,
                             lpc2xxx_can2_rxbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN2_QUEUESIZE_RX
    );


DEVTAB_ENTRY(lpc2xxx_can2_devtab, 
             CYGPKG_DEVS_CAN_LPC2XXX_CAN2_NAME,
             0,                     // Does not depend on a lower level interface
             &cyg_io_can_devio, 
             lpc2xxx_can_init, 
             lpc2xxx_can_lookup,    // CAN driver may need initializing
             &lpc2xxx_can2_chan
    );
#endif // CYGPKG_DEVS_CAN_LPC2XXX_CAN2


//---------------------------------------------------------------------------
// CAN channel 3
//
#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN3
CYG_CAN_EVENT_T  lpc2xxx_can3_rxbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN3_QUEUESIZE_RX]; // buffer for RX can events
CYG_CAN_MSG_T    lpc2xxx_can3_txbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN3_QUEUESIZE_TX]; // buffer for TX can messages


CAN_CHANNEL_USING_INTERRUPTS(lpc2xxx_can3_chan,
                             lpc2xxx_can_lowlevel_funs,
                             lpc2xxx_can3_info,
                             CYG_CAN_BAUD_RATE(CYGNUM_DEVS_CAN_LPC2XXX_CAN3_KBAUD),
                             lpc2xxx_can3_txbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN3_QUEUESIZE_TX,
                             lpc2xxx_can3_rxbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN3_QUEUESIZE_RX
    );


DEVTAB_ENTRY(lpc2xxx_can3_devtab, 
             CYGPKG_DEVS_CAN_LPC2XXX_CAN3_NAME,
             0,                     // Does not depend on a lower level interface
             &cyg_io_can_devio, 
             lpc2xxx_can_init, 
             lpc2xxx_can_lookup,    // CAN driver may need initializing
             &lpc2xxx_can3_chan
    );
#endif // CYGPKG_DEVS_CAN_LPC2XXX_CAN3


//===========================================================================
//                            IMPLEMENTATION
//===========================================================================



//===========================================================================
/// First initialisation and reset of CAN modul.
//===========================================================================
static bool lpc2xxx_can_init(struct cyg_devtab_entry* devtab_entry)
{
    can_channel          *chan    = (can_channel*)devtab_entry->priv;
    lpc2xxx_can_info_t   *info    = (lpc2xxx_can_info_t *)chan->dev_priv;
    bool                  res;

#ifdef CYGDBG_IO_INIT
    diag_printf("LPC2XXX CAN init\n");
#endif  
    
    //
    // Create TX interrupt
    //
    cyg_drv_interrupt_create(CAN_ISRVEC(info),
                             0,                        // Priority does not matter LPC2xxx
                             (cyg_addrword_t)chan,     // Data item passed to interrupt handler
                             lpc2xxx_can_tx_ISR,
                             lpc2xxx_can_tx_DSR,
                             &info->tx_interrupt_handle,
                             &info->tx_interrupt);
    cyg_drv_interrupt_attach(info->tx_interrupt_handle);
    cyg_drv_interrupt_unmask(CAN_ISRVEC(info));
    
    //
    // Create RX interrupt
    //
    cyg_drv_interrupt_create(CAN_ISRVEC(info) + 6,
                             0,                        // Priority does not matter for LPC2xxx
                             (cyg_addrword_t)chan,     // Data item passed to interrupt handler
                             lpc2xxx_can_rx_ISR,
                             lpc2xxx_can_rx_DSR,
                             &info->rx_interrupt_handle,
                             &info->rx_interrupt);
    cyg_drv_interrupt_attach(info->rx_interrupt_handle);
    cyg_drv_interrupt_unmask(CAN_ISRVEC(info) + 6);
    
    //
    // Now create and enable error interrupt. This interrupt is global for all channels
    // and so we need to call it only one times - when the first channel is
    // initialized
    //
    if (!lpc2xxx_global_can_info.init_cnt)
    {
        //
        // Create err interrupt
        //
        cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_CAN,
                                 0,                        // Priority does not matter for LPX2xxx
                                 0,                        // Data item passed to interrupt handler
                                 lpc2xxx_can_err_ISR,
                                 lpc2xxx_can_err_DSR,
                                 &lpc2xxx_global_can_info.err_interrupt_handle,
                                 &lpc2xxx_global_can_info.err_interrupt);
        cyg_drv_interrupt_attach(lpc2xxx_global_can_info.err_interrupt_handle);
        cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_CAN);     
    }   
   
    res = lpc2xxx_can_config_channel(chan, &chan->config, true);
    lpc2xxx_global_can_info.active_channels[lpc2xxx_global_can_info.init_cnt++] = chan;
    return res; 
}


//===========================================================================
// Configure can channel
//===========================================================================
static bool lpc2xxx_can_config_channel(can_channel* chan, cyg_can_info_t* config, cyg_bool init)
{
    CAN_DECLARE_INFO(chan);
    cyg_uint32 temp32;
    bool       res = true;
    
    if (init)
    {
        //
        // In case platform needs extra initialization (i.e. setup of CAN transcievers)
        // it should implement this macro
        //
#ifdef CYGPRI_IO_CAN_LPC2XXX_PLF_INIT_HOOK
        CYGPRI_IO_CAN_LPC2XXX_PLF_INIT_HOOK(chan, config);
#endif
        
        HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, AFMR_OFF);       // Acceptance Filter Mode Register = off
        HAL_WRITE_UINT32(CAN_CTRL_MOD(info), CANMOD_RESET); // Go into reset mode
        HAL_WRITE_UINT32(CAN_CTRL_IER(info), 0);            // disable all interrupts
        HAL_WRITE_UINT32(CAN_CTRL_GSR(info), 0);            // Clear Status register - clears error counters  
        
        //
        // If this is the first channel to initialize then we reset the CAN registers
        // and setup the CAN I/O pins
        //
        if (!lpc2xxx_global_can_info.init_cnt)
        {
            lpc2xxx_can_accfilt_reset();  
#if defined(CYGPKG_DEVS_CAN_LPC2XXX_CAN0) || defined(CYGPKG_DEVS_CAN_LPC2XXX_CAN1) || defined(CYGPKG_DEVS_CAN_LPC2XXX_CAN3)
        HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_PIN_BASE + CYGARC_HAL_LPC2XXX_REG_PINSEL1, temp32);
#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN0
        temp32 |= 0x00040000L; // Set bit 18
#endif // CYGPKG_DEVS_CAN_LPC2XXX_CAN0   
#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN1
        temp32 |= 0x00014000L; // Set bits 14 and 16
#endif // CYGPKG_DEVS_CAN_LPC2XXX_CAN1
#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN2
        temp32 |= 0x00001800L; // Set bits 11 and 12
#endif
        HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_PIN_BASE + CYGARC_HAL_LPC2XXX_REG_PINSEL1, temp32);
#endif // defined(CYGPKG_DEVS_CAN_LPC2XXX_CAN0) || defined(CYGPKG_DEVS_CAN_LPC2XXX_CAN1)


#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN3
        HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_PIN_BASE + CYGARC_HAL_LPC2XXX_REG_PINSEL0, temp32);
        temp32 |= 0x0F000000L;
        HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_PIN_BASE + CYGARC_HAL_LPC2XXX_REG_PINSEL0, temp32);
#endif // CYGPKG_DEVS_CAN_LPC2XXX_CAN3
        }   
    } // if (init)
    
    res = lpc2xxx_can_set_baud(chan, &config->baud);           // set baudrate
    // $$$$ enable receive interrupt?
    HAL_WRITE_UINT32(CAN_CTRL_MOD(info), CANMOD_OPERATIONAL);  // enter normal operating mode
            
    //
    // store new config values
    //
    if (config != &chan->config) 
    {
        chan->config = *config;
    }   
    
    return res;
}


//===========================================================================
// Set baudrate of certain can channel
//===========================================================================
static bool lpc2xxx_can_set_baud(can_channel *chan, cyg_can_baud_rate_t *baudrate)
{
    bool                  res = true;
    cyg_uint32            canbtr;
    cyg_uint32            canmod;
    CAN_DECLARE_INFO(chan);
    
    //
    // Get bit timings from HAL because bit timings depend on sysclock
    // If the macro fills the canbtr value with 0 then the baudrate
    // is not supported and the function returns false
    //
    HAL_LPC2XXX_GET_CAN_BR(*baudrate, canbtr);   
    if (0 == canbtr)
    {
        return false;
    }
    
    //
    // Any modificatons to the baudrate register must be done while CAN
    // module is in reset mode. So we first set the CAN moduel in reset
    // mode, then we set baudrate and then we restore content of CANMOD 
    // register
    //
    HAL_READ_UINT32(CAN_CTRL_MOD(info), canmod);        // backup canmod register
    HAL_WRITE_UINT32(CAN_CTRL_MOD(info), CANMOD_RESET); // Go into reset mode
    HAL_WRITE_UINT32(CAN_CTRL_BTR(info), canbtr);       // write baudrate value
    HAL_WRITE_UINT32(CAN_CTRL_MOD(info), canmod);       // restore previous value
       
    return res;
}


//===========================================================================
//  Lookup the device and return its handle
//===========================================================================
static Cyg_ErrNo lpc2xxx_can_lookup(struct cyg_devtab_entry** tab, struct cyg_devtab_entry* sub_tab, const char* name)
{
    can_channel* chan    = (can_channel*) (*tab)->priv;
    lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv;
    cyg_uint32   regval;

    chan->callbacks->can_init(chan); 
    
    //
    // If runtime acceptance filter configuration is supported then we only
    // configure RX ALL if the user selected the RX ALL setup in config utility
    //
#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
    if (info->flags & INFO_FLAG_STARTUP_RX_ALL)
#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
    {
       lpc2xxx_can_config_rx_all(chan); 
    }
    
    HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, AFMR_ON);       // Activate acceptance filter
    HAL_READ_UINT32(CAN_CTRL_IER(info), regval);
    regval = regval | IER_RX | CAN_MISC_INT;           // enable all interrupts     
    HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval);  
      
    return ENOERR;
}


#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
//===========================================================================
// Setup LPC2XXX CAN module in a state where all message boxes are disabled
// After this call it is possible to add single message buffers and filters
//===========================================================================
static void lpc2xxx_can_config_rx_none(can_channel *chan)
{
    lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv;
      
    //
    // Remove all acceptance filters
    // $$$$ maybe we should also abort any pending transfers and
    // disable receive interrupts ?
    //
    lpc2xxx_can_accfilt_remove_all_ctrl_entries(info);
    info->flags  &= ~INFO_FLAG_RX_ALL;
#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG
    lpc2xxx_can_accfilt_dbg_dump();
#endif
}


//===========================================================================
// Add one single message filter to acceptance filter
//===========================================================================
static bool lpc2xxx_can_add_rx_filter(lpc2xxx_can_info_t *info, cyg_can_filter *filter)
{
    bool res;
    
    res = lpc2xxx_can_accfilt_add(info, filter->msg.id, 0, filter->msg.ext); 
    if (!res)
    {
        filter->handle = CYGNUM_CAN_MSGBUF_NA;
    }
#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG
    lpc2xxx_can_accfilt_dbg_dump();
#endif    
    return res;
}
#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG



#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
//===========================================================================
// Configure message buffers
//===========================================================================
static Cyg_ErrNo lpc2xxx_can_config_msgbuf(can_channel *chan, const void* buf, cyg_uint32* len)
{
    Cyg_ErrNo             res  = ENOERR;
    lpc2xxx_can_info_t   *info = (lpc2xxx_can_info_t *)chan->dev_priv;   
    cyg_can_msgbuf_cfg   *msg_buf = (cyg_can_msgbuf_cfg *)buf;

    if (*len != sizeof(cyg_can_msgbuf_cfg))
    {
        return -EINVAL;
    }

    switch (msg_buf->cfg_id)
    {
        //
        // clear all message filters and remote buffers - prepare for message buffer

⌨️ 快捷键说明

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