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