📄 can_at91sam7.c
字号:
for (i = (CAN_MBOX_RX_CNT - info->free_mboxes); i <= CAN_MBOX_RX_MAX; ++i)
{
cyg_uint32 mmr;
HAL_READ_UINT32(CAN_MB_MMR(info, i), mmr);
if ((mmr & MMR_MB_TYPE_BITMASK) == MMR_MB_TYPE_DISABLED)
{
info->free_mboxes--;
res = i;
break;
}
}
} // if (info->free_mboxes)
return res;
}
#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
#ifdef CYGOPT_IO_CAN_REMOTE_BUF
//===========================================================================
// Setup a RTR response message box
//===========================================================================
static bool at91sam7_can_setup_rtrmbox(can_channel *chan,
cyg_uint32 mbox,
cyg_can_message *pmsg,
bool init)
{
CAN_DECLARE_INFO(chan);
cyg_uint32 mcr;
//
// 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
//
if (init)
{
if (pmsg->ext)
{
at91sam7_can_setup_mbox(chan, mbox, MID_SET_EXT(pmsg->id), MAM_SET_EXT, MMR_MB_TYPE_PRODUCE);
}
else
{
at91sam7_can_setup_mbox(chan, mbox, MID_SET_STD(pmsg->id), MAM_SET_STD, MMR_MB_TYPE_PRODUCE);
}
HAL_WRITE_UINT32(CAN_IER(info), 0x01 << mbox); // enable interrupt
}
else
{
cyg_uint32 msr;
//
// Check if this message box is ready for transmission or if it still transmits
// a message - we read the MSR register to check the ready flag
//
HAL_READ_UINT32(CAN_MB_MSR(info, mbox), msr);
if (!(msr & MSR_RDY))
{
AT91SAM7_DBG_PRINT("(RTR) !MSR_RDY\n");
return false;
}
}
HAL_WRITE_UINT32(CAN_MB_MDL(info, mbox), pmsg->data.dwords[0]); // set data
HAL_WRITE_UINT32(CAN_MB_MDH(info, mbox), pmsg->data.dwords[1]); // set data
mcr = (pmsg->dlc << MCR_DLC_SHIFTER) | MCR_TRANSFER_CMD; // set data lengt and transfer request
HAL_WRITE_UINT32(CAN_MB_MCR(info, mbox), mcr); // transfer request
return true;
}
#endif // CYGOPT_IO_CAN_REMOTE_BUF
#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
//===========================================================================
// Configure message buffers
//===========================================================================
static Cyg_ErrNo at91sam7_can_set_config_msgbuf(can_channel *chan, cyg_can_msgbuf_cfg *buf)
{
Cyg_ErrNo res = ENOERR;
at91sam7_can_info_t *info = (at91sam7_can_info_t *)chan->dev_priv;
switch (buf->cfg_id)
{
//
// clear all message filters and remote buffers - prepare for message buffer
// configuration
//
case CYGNUM_CAN_MSGBUF_RESET_ALL :
{
at91sam7_can_config_rx_none(chan);
}
break;
//
// setup AT91SAM7 CAN module for reception of all standard and extended messages
//
case CYGNUM_CAN_MSGBUF_RX_FILTER_ALL :
{
if (!info->rx_all) // if rx_all is enabled we do not need to do anything
{
at91sam7_can_mbox_config_rx_all(chan); // setup RX all state
}
}
break;
//
// add single message filter, message with filter ID will be received
//
case CYGNUM_CAN_MSGBUF_RX_FILTER_ADD :
{
cyg_can_filter *filter = (cyg_can_filter*) buf;
//
// if AT91SAM7 CAN module is configured to receive all messages then
// it is not allowed to add single message filters because then more
// than one message buffer would receive the same CAN id
//
if (info->rx_all)
{
return -EPERM;
}
//
// try to allocate a free message box - if we have a free one
// then we can prepare the message box for reception of the
// desired message id
//
filter->handle = at91sam7_can_alloc_mbox(info);
if (filter->handle > CYGNUM_CAN_MSGBUF_NA)
{
at91sam7_can_add_rx_filter(chan, filter->handle, &filter->msg);
}
}
break; //CYGNUM_CAN_MSGBUF_RX_FILTER_ADD
#ifdef CYGOPT_IO_CAN_REMOTE_BUF
//
// Try to add a new RTR response message buffer for automatic transmisson
// of data frame on reception of a remote frame
//
case CYGNUM_CAN_MSGBUF_REMOTE_BUF_ADD :
{
cyg_can_remote_buf *rtr_buf = (cyg_can_remote_buf*) buf;
rtr_buf->handle = at91sam7_can_alloc_mbox(info);
if (rtr_buf->handle > CYGNUM_CAN_MSGBUF_NA)
{
//
// if we have a free message buffer then we setup this buffer
// for remote frame reception
//
at91sam7_can_setup_rtrmbox(chan, rtr_buf->handle, &rtr_buf->msg, true);
}
}
break;
//
// write data into remote response buffer
//
case CYGNUM_CAN_MSGBUF_REMOTE_BUF_WRITE :
{
cyg_can_remote_buf *rtr_buf = (cyg_can_remote_buf*) buf;
//
// If we have a valid rtr buf handle then we can store data into
// rtr message box
//
if ((rtr_buf->handle >= 0) && (rtr_buf->handle <= CAN_MBOX_RX_MAX))
{
if (!at91sam7_can_setup_rtrmbox(chan, rtr_buf->handle, &rtr_buf->msg, false))
{
res = -EAGAIN;
}
}
else
{
res = -EINVAL;
}
}
break;
#endif // #ifdef CYGOPT_IO_CAN_REMOTE_BUF
} // switch (buf->cfg_id)
return res;
}
#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
//===========================================================================
// Read state of CAN controller
// The CAN state variable for each channel is modiefied by DSR so if we
// read the state we need to lock DSRs to protect the data access
//===========================================================================
static cyg_can_state at91sam7_get_state(at91sam7_can_info_t *info)
{
cyg_can_state result;
cyg_drv_dsr_lock();
result = info->state;
cyg_drv_dsr_unlock();
return result;
}
//===========================================================================
// Enter low power mode
// Before stopping the CAN clock (PMC), the CAN Controller must be in
// Low-power Mode to complete the current transfer. After restarting the
// clock, the application must disable the Low-power Mode of the
// CAN controller. If the power mode is entered, a sleep interrupt is
// generated.
//===========================================================================
static void at91sam7_enter_lowpower_mode(can_channel *chan)
{
CAN_DECLARE_INFO(chan);
cyg_uint32 mr;
HAL_READ_UINT32(CAN_MR(info), mr);
HAL_WRITE_UINT32(CAN_MR(info), mr | MR_LOW_POWER);
HAL_WRITE_UINT32(CAN_IER(info), INT_SLEEP);
}
//===========================================================================
// Start CAN module (or leave the low power mode)
// If the CAN module is in STANDBY state then we enable the module clock
// and leave the low power mode by clearing the low power flag.
//===========================================================================
static void at91sam7_start_module(can_channel *chan)
{
CAN_DECLARE_INFO(chan);
cyg_uint32 mr;
HAL_WRITE_UINT32(CAN_IER(info), INT_DEFAULT); // enable wakeup interrupt
HAL_WRITE_UINT32(AT91_PMC+AT91_PMC_PCER, 1 << CAN_PID(info)); // restart peripheral clock
HAL_READ_UINT32(CAN_MR(info), mr);
mr &= ~MR_LOW_POWER ;
HAL_WRITE_UINT32(CAN_MR(info), mr | MR_CAN_ENABLE); // clear the low power flag to leave standby
}
//===========================================================================
// Change device configuration
//===========================================================================
static Cyg_ErrNo at91sam7_can_set_config(can_channel *chan, cyg_uint32 key, const void* buf, cyg_uint32* len)
{
Cyg_ErrNo res = ENOERR;
switch (key)
{
//
// Setup a new CAN configuration. This will i.e. setup a new baud rate
//
case CYG_IO_SET_CONFIG_CAN_INFO:
{
cyg_can_info_t* config = (cyg_can_info_t*) buf;
if (*len < sizeof(cyg_can_info_t))
{
return -EINVAL;
}
*len = sizeof(cyg_can_info_t);
if (!at91sam7_can_config_channel(chan, config, false))
{
return -EINVAL;
}
}
break;
#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
//
// configure message buffers
//
case CYG_IO_SET_CONFIG_CAN_MSGBUF :
{
cyg_can_msgbuf_cfg *msg_buf = (cyg_can_msgbuf_cfg *)buf;
if (*len != sizeof(cyg_can_msgbuf_cfg))
{
return -EINVAL;
}
res = at91sam7_can_set_config_msgbuf(chan, msg_buf);
}
break;
#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
//
// Change CAN state of AT91SAM7 CAN module
//
case CYG_IO_SET_CONFIG_CAN_MODE :
{
cyg_can_mode *can_mode = (cyg_can_mode*) buf;
if (*len != sizeof(cyg_can_mode))
{
return -EINVAL;
}
*len = sizeof(cyg_can_mode);
//
// decide what to do acording to mode
//
switch (*can_mode)
{
//
// The controller does not support a stopped and standby state so we
// simply enter the low power state here. This state is also safe for
// message buffer configuration
//
case CYGNUM_CAN_MODE_STOP : at91sam7_enter_lowpower_mode(chan); break;
case CYGNUM_CAN_MODE_START : at91sam7_start_module(chan); break;
case CYGNUM_CAN_MODE_STANDBY : at91sam7_enter_lowpower_mode(chan); break;
case CYGNUM_CAN_MODE_CONFIG : at91sam7_enter_lowpower_mode(chan); break;
}
}
break; // case CYG_IO_SET_CONFIG_CAN_MODE :
} // switch (key)
return res;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -