📄 can_lpc2xxx.c
字号:
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 + -