📄 can_at91sam7.c
字号:
//===========================================================================
// Stop transmitter
//===========================================================================
static void at91sam7_can_stop_xmit(can_channel* chan)
{
CAN_DECLARE_INFO(chan);
HAL_WRITE_UINT32(CAN_IDR(info), 0x01 << CAN_MBOX_TX(info)); // disable tx interrupt
AT91SAM7_DBG_PRINT("stop_xmit\n");
}
//===========================================================================
// Configure can channel
//===========================================================================
static bool at91sam7_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)
{
//
// If the platform that uses the driver needs to do some platform specific
// initialisation steps, it can do it inside of this macro. I.e. some platforms
// need to setup the CAN transceiver properly here (this is necessary for the
// Atmel AT91SAM7X-EK)
//
#if CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS == 1 && defined(HAL_AT91SAM7_CAN0_PLF_INIT)
HAL_AT91SAM7_CAN0_PLF_INIT();
#else // CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS > 1
#if defined(CYGPKG_DEVS_CAN_AT91SAM7_CAN0) && defined(HAL_AT91SAM7_CAN0_PLF_INIT)
if (info == &at91sam7_can0_info) {
HAL_AT91SAM7_CAN0_PLF_INIT();
}
#endif // defined(CYGPKG_DEVS_CAN_AT91SAM7_CAN0) && defined(HAL_AT91SAM7_CAN0_PLF_INIT)
#if defined(CYGPKG_DEVS_CAN_AT91SAM7_CAN1) && defined(HAL_AT91SAM7_CAN1_PLF_INIT)
if (info == &at91sam7_can1_info) {
HAL_AT91SAM7_CAN1_PLF_INIT();
}
#endif // defined(CYGPKG_DEVS_CAN_AT91SAM7_CAN0) && defined(HAL_AT91SAM7_CAN0_PLF_INIT)
#endif // CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS == 1
HAL_WRITE_UINT32(CAN_IDR(info), 0xFFFFFFFF); // disable all interrupts
HAL_WRITE_UINT32(CAN_MR(info), 0x00); // disable CAN module
HAL_ARM_AT91_PIO_CFG(AT91_CAN_CANRX); // Enable the CAN module to drive the CAN port pins
HAL_ARM_AT91_PIO_CFG(AT91_CAN_CANTX);
HAL_WRITE_UINT32(CAN_MB_MMR(info, CAN_MBOX_TX(info)), MMR_MB_TYPE_DISABLED); // first disable tx message box
HAL_WRITE_UINT32(CAN_MB_MAM(info, CAN_MBOX_TX(info)), 0x00000000); // set acceptance mask once
HAL_WRITE_UINT32(CAN_MB_MMR(info, CAN_MBOX_TX(info)), MMR_MB_TYPE_TX); // setup as tx message box
HAL_WRITE_UINT32(CAN_MR(info), MR_CAN_ENABLE); // enable CAN module
//
// The device should go into error active state right after enabling it
//
HAL_READ_UINT32(CAN_SR(info), temp32);
if (!(temp32 & INT_ERR_ACTIVE))
{
res = false;
}
} // if (init)
res = at91sam7_can_set_baud(chan, &config->baud); // set baudrate
//
// store new config values
//
if (config != &chan->config)
{
chan->config = *config;
}
return res;
}
//===========================================================================
// Low level interrupt handler
//===========================================================================
static cyg_uint32 at91sam7_can_ISR(cyg_vector_t vector, cyg_addrword_t data)
{
can_channel *chan = (can_channel *)data;
at91sam7_can_info_t * const info = (at91sam7_can_info_t *)chan->dev_priv;
cyg_uint32 sr;
cyg_uint32 imr;
HAL_READ_UINT32(CAN_IMR(info), imr);
HAL_READ_UINT32(CAN_SR(info), sr);
AT91SAM7_DBG_PRINT("CAN_ISR SR %x\n", sr);
sr &= imr;
HAL_WRITE_UINT32(CAN_IDR(info), sr);
info->stat |= sr;
cyg_drv_interrupt_acknowledge(vector);
return CYG_ISR_CALL_DSR;
}
//===========================================================================
// High level interrupt handler
//===========================================================================
static void at91sam7_can_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
can_channel *chan = (can_channel *)data;
at91sam7_can_info_t * const info = (at91sam7_can_info_t *)chan->dev_priv;
cyg_uint32 stat = 0;
do
{
//
// If a number of events occured then we process all events now in
// in this DSR the get_event() function clears the flags in the stat
// field
//
while (stat)
{
if (stat & (0x01 << CAN_MBOX_TX(info)))
{
AT91SAM7_DBG_PRINT("TX_DSR\n");
chan->callbacks->xmt_msg(chan, 0); // send next message
stat &= ~INT_MB_TX; // clear flag
}
else if (stat)
{
AT91SAM7_DBG_PRINT("EVENT_DSR\n");
chan->callbacks->rcv_event(chan, &stat);
}
}
//
// We check, if a new event occured while we processed other events. If new events
// occured, then we process the new events
//
cyg_drv_interrupt_mask(vector);
stat = info->stat;
info->stat = 0;
cyg_drv_interrupt_unmask(vector);
} while (stat);
}
//===========================================================================
// Set baudrate of certain can channel
//===========================================================================
static bool at91sam7_can_set_baud(can_channel *chan, cyg_can_baud_rate_t *baudrate)
{
bool res = true;
cyg_uint32 mrbck;
cyg_uint32 canbr;
CAN_DECLARE_INFO(chan);
#ifdef CYGOPT_IO_CAN_AUTOBAUD
if (CYGNUM_CAN_KBAUD_AUTO == *baudrate)
{
cyg_can_baud_rate_t i;
cyg_uint8 j;
cyg_uint32 sr;
res = false;
for (i = CYGNUM_CAN_KBAUD_10; i <= CYGNUM_CAN_KBAUD_1000; ++i)
{
HAL_AT91SAM7_GET_CAN_BR(i, canbr);
if (0 == canbr)
{
continue;
}
HAL_READ_UINT32(CAN_SR(info), sr);
HAL_WRITE_UINT32(CAN_MR(info), 0); // disable the module
HAL_WRITE_UINT32(CAN_BR(info), canbr); // write baudrate register
HAL_WRITE_UINT32(CAN_MR(info), MR_CAN_ENABLE | MR_AUTOBAUD); // enable controller in auto aud mode
for(j = 0; j < 200; ++j)
{
HAL_DELAY_US(1000); // wait at least 11 bit times for synchronization
}
HAL_READ_UINT32(CAN_SR(info), sr); // read status register
if (!(sr & INT_ALL_ERR) && (sr & INT_WAKEUP))
{
HAL_WRITE_UINT32(CAN_MR(info), 0); // disable the module
HAL_WRITE_UINT32(CAN_MR(info), MR_CAN_ENABLE); // enable controller
*baudrate = i; // store baudrate
return true;
} // if (!(sr & INT_ALL_ERR))
}
}
else
#endif // CYGOPT_IO_CAN_AUTOBAUD
{
//
// Get bit timings from HAL because bit timings depend on sysclock
// For main clock of 48 MHz this macro is implemented in this device
// driver. If the macro fills the canbr value with 0 then the baudrate
// is not supported and the function returns false
//
HAL_AT91SAM7_GET_CAN_BR(*baudrate, canbr);
if (0 == canbr)
{
return false;
}
//
// Any modificatons to the baudrate register must be done while CAN
// module is disabled. So we first disable CAN module, then we set
// baudrate and then we reenable the CAN module by setting the CAN enable
// flag
//
HAL_READ_UINT32(CAN_MR(info), mrbck); // backup value of mode register
HAL_WRITE_UINT32(CAN_MR(info), mrbck &~MR_CAN_ENABLE); // disable controller
HAL_WRITE_UINT32(CAN_BR(info), canbr); // write baudrate register
//
// Now restore the previous state - if the module was started then
// it will no be started again, if it was stopped, then it remains stopped
//
HAL_WRITE_UINT32(CAN_MR(info), mrbck);
}
return res;
}
//===========================================================================
// Setup one single message box for reception of can message
//===========================================================================
static void at91sam7_can_setup_mbox(can_channel *chan, cyg_uint8 mbox, cyg_uint32 mid, cyg_uint32 mam, cyg_uint32 rxtype)
{
CAN_DECLARE_INFO(chan);
CYG_ASSERT(mbox < 7, "invalid rx mbox number");
//
// To prevent concurrent access with the internal CAN core, the application
// must disable the mailbox before writing to CAN_MIDx registers - so we
// do this here
//
HAL_WRITE_UINT32(CAN_MB_MMR(info, mbox), MMR_MB_TYPE_DISABLED); // first disable message box
HAL_WRITE_UINT32(CAN_MB_MAM(info, mbox), mam); // set acceptance mask
HAL_WRITE_UINT32(CAN_MB_MID(info, mbox), mid); // set message identifier
HAL_WRITE_UINT32(CAN_MB_MMR(info, mbox), rxtype); // setup message box as rx message box (with or without overwrite)
HAL_WRITE_UINT32(CAN_MB_MCR(info, mbox), MCR_TRANSFER_CMD); // transfer request - we do not enable interrupts here
}
//===========================================================================
// Configure message boxes for reception of any CAN message
//===========================================================================
static void at91sam7_can_mbox_config_rx_all(can_channel *chan)
{
at91sam7_can_info_t * const info = (at91sam7_can_info_t *)chan->dev_priv;
cyg_uint8 i;
cyg_uint8 mbox_int_mask = 0;
cyg_uint8 mbox_rx_all_cnt = CAN_MBOX_RX_ALL_CNT(info);
#ifdef CYGOPT_IO_CAN_STD_CAN_ID
cyg_uint8 last_std_rx_mbox = CAN_MBOX_STD_CNT(info) - 1;
#endif // CYGOPT_IO_CAN_STD_CAN_ID
#ifdef CYGOPT_IO_CAN_EXT_CAN_ID
cyg_uint8 last_ext_rx_mbox = mbox_rx_all_cnt - 1;
#endif// CYGOPT_IO_CAN_EXT_CAN_ID
//
// Now setup all rx message boxes. One message box (the last one - no 8) is
// used for transmission so we have 7 message boxes for reception of can messages
// We setup the message boxes 0 - 5 as RX mboxes and message box 6 as RX mbox with
// overwrite.
//
for (i = 0; i < mbox_rx_all_cnt; ++i)
{
#ifdef CYGOPT_IO_CAN_STD_CAN_ID
if (i < CAN_MBOX_STD_CNT(info))
{
//
// setup message boxes for standard frames
//
if (i < last_std_rx_mbox)
{
at91sam7_can_setup_mbox(chan, i, 0, MID_MIDE, MMR_MB_TYPE_RX);
}
else
{
at91sam7_can_setup_mbox(chan, i, 0, MID_MIDE, MMR_MB_TYPE_RX_OVW);
}
}
else
#endif // CYGOPT_IO_CAN_STD_CAN_ID
{
#ifdef CYGOPT_IO_CAN_EXT_CAN_ID
//
// setup message boxes for extended frames
//
if (i < last_ext_rx_mbox)
{
at91sam7_can_setup_mbox(chan, i, MID_MIDE, MID_MIDE, MMR_MB_TYPE_RX);
}
else
{
at91sam7_can_setup_mbox(chan, i, MID_MIDE, MID_MIDE, MMR_MB_TYPE_RX_OVW);
}
#endif// CYGOPT_IO_CAN_EXT_CAN_ID
} // if (i < CAN_MBOX_STD_CNT(info))
mbox_int_mask = (mbox_int_mask << 1) | 0x01; // enable interrupt
} // for (i = 0; i < CAN_MBOX_RX_CNT; ++i)*/
info->free_mboxes = CAN_MBOX_RX_CNT - mbox_rx_all_cnt;
info->rx_all = true;
HAL_WRITE_UINT32(CAN_IER(info), mbox_int_mask); // Now finally enable the interrupts for als RX mboxes
}
//---------------------------------------------------------------------------
// EOF can_at91am7.c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -