📄 can_at91sam7.c
字号:
}
//===========================================================================
// Query device configuration
//===========================================================================
static Cyg_ErrNo at91sam7_can_get_config(can_channel *chan, cyg_uint32 key, const void* buf, cyg_uint32* len)
{
Cyg_ErrNo res = ENOERR;
at91sam7_can_info_t *info = (at91sam7_can_info_t *)chan->dev_priv;
switch(key)
{
//
// query state of CAN controller
//
case CYG_IO_GET_CONFIG_CAN_STATE :
{
cyg_can_state *can_state = (cyg_can_state*) buf;
if (*len != sizeof(cyg_can_state))
{
return -EINVAL;
}
*len = sizeof(cyg_can_state);
*can_state = at91sam7_get_state(info);
}
break;
#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
//
// Query message box information - returns available and free message
// boxes
//
case CYG_IO_GET_CONFIG_CAN_MSGBUF_INFO :
{
cyg_can_msgbuf_info *mbox_info = (cyg_can_msgbuf_info*) buf;
if (*len != sizeof(cyg_can_msgbuf_info))
{
return -EINVAL;
}
*len = sizeof(cyg_can_msgbuf_info);
mbox_info->count = CAN_MBOX_RX_CNT;
mbox_info->free = info->free_mboxes;
}
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
| CYGNUM_CAN_HDI_AUTBAUD;
#ifdef CYGOPT_IO_CAN_SUPPORT_TIMESTAMP
hdi->support_flags |= CYGNUM_CAN_HDI_TIMESTAMP;
#endif
}
break;
default :
res = -EINVAL;
}// switch(key)
return res;
}
//===========================================================================
// Send single message
//===========================================================================
static bool at91sam7_can_putmsg(can_channel *priv, CYG_CAN_MSG_T *pmsg, void *pdata)
{
CAN_DECLARE_INFO(priv);
cyg_uint32 msr;
cyg_uint32 mcr = 0;
//
// First check if this message box is ready fro 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, CAN_MBOX_TX(info)), msr);
if (!(msr & MSR_RDY))
{
AT91SAM7_DBG_PRINT("!MSR_RDY\n");
return false;
}
//
// 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 now
//
HAL_WRITE_UINT32(CAN_MB_MMR(info, CAN_MBOX_TX(info)), MMR_MB_TYPE_DISABLED);
//
// Setup the message identifier - this depends on the frame type (standard or extended)
//
#ifdef CYGOPT_IO_CAN_EXT_CAN_ID
if (AT91SAM7_CAN_IS_EXT(*pmsg))
{
HAL_WRITE_UINT32(CAN_MB_MID(info, CAN_MBOX_TX(info)),
pmsg->id | MID_MIDE); // set extended message id
}
else
#endif // CYGOPT_IO_CAN_EXT_CAN_ID
{
#ifdef CYGOPT_IO_CAN_STD_CAN_ID
HAL_WRITE_UINT32(CAN_MB_MID(info, CAN_MBOX_TX(info)),
(pmsg->id << MID_MIDvA_SHIFTER) & MID_MIDvA_BITMASK); // set standard message id
#endif // CYGOPT_IO_CAN_STD_CAN_ID
}
HAL_WRITE_UINT32(CAN_MB_MDL(info, CAN_MBOX_TX(info)), pmsg->data.dwords[0]); // set data
HAL_WRITE_UINT32(CAN_MB_MDH(info, CAN_MBOX_TX(info)), pmsg->data.dwords[1]); // set data
HAL_WRITE_UINT32(CAN_MB_MMR(info, CAN_MBOX_TX(info)), MMR_MB_TYPE_TX); // reenable the message box
mcr = (AT91SAM7_CAN_GET_DLC(*pmsg) << MCR_DLC_SHIFTER) | MCR_TRANSFER_CMD; // set data lengt and transfer request
if (AT91SAM7_CAN_IS_RTR(*pmsg))
{
mcr |= MCR_RTR;
}
HAL_WRITE_UINT32(CAN_MB_MCR(info, CAN_MBOX_TX(info)), mcr);
return true;
}
//===========================================================================
// Read event from device driver
//===========================================================================
static bool at91sam7_can_getevent(can_channel *chan, CYG_CAN_EVENT_T *pevent, void *pdata)
{
at91sam7_can_info_t *info = (at91sam7_can_info_t *)chan->dev_priv;
cyg_uint32* pstat = (cyg_uint32 *)pdata;
cyg_uint8 mboxflags = (*pstat & INT_MB_RX);
cyg_uint8 mbox = 0;
bool res = true;
//
// First check if a message box interrupt occured if a message box interrupt
// occured process the lowest message box that caused an interrupt
//
if (mboxflags)
{
cyg_uint32 msr;
cyg_uint32 mid;
cyg_uint32 mmr;
while (!(mboxflags & 0x01))
{
mboxflags >>= 1;
mbox++;
}
//
// If the message box that caused the interrupt is an PRODUCER message box,
// then we received an remote request message, if not, then this is a normal
// RX message
//
HAL_READ_UINT32(CAN_MB_MMR(info, mbox), mmr);
HAL_READ_UINT32(CAN_MB_MSR(info, mbox), msr);
*pstat &= ~(0x01 << mbox); // clear flag
if (MMR_MB_GET_TYPE(mmr) != MMR_MB_TYPE_PRODUCE)
{
HAL_READ_UINT32(CAN_MB_MID(info, mbox), mid);
pevent->flags |= CYGNUM_CAN_EVENT_RX;
if (msr & MSR_MSG_IGNORED)
{
pevent->flags |= CYGNUM_CAN_EVENT_OVERRUN_RX;
}
//
// It is important to set the DLC first because this also clears the ctrl
// field if extended identifiers are supported
//
AT91SAM7_CAN_SET_DLC(pevent->msg, MSR_DLC_GET(msr));
#ifdef CYGOPT_IO_CAN_EXT_CAN_ID
if (mid & MID_MIDE)
{
pevent->msg.id = MID_GET_EXT(mid);
AT91SAM7_CAN_SET_EXT(pevent->msg);
}
else
#endif // CYGOPT_IO_CAN_EXT_CAN_ID
{
#ifdef CYGOPT_IO_CAN_STD_CAN_ID
pevent->msg.id = MID_GET_STD(mid);
#endif // CYGOPT_IO_CAN_STD_CAN_ID
}
if (msr & MSR_RTR)
{
AT91SAM7_CAN_SET_RTR(pevent->msg);
}
else
{
HAL_READ_UINT32(CAN_MB_MDL(info, mbox), pevent->msg.data.dwords[0]);
HAL_READ_UINT32(CAN_MB_MDH(info, mbox), pevent->msg.data.dwords[1]);
}
#ifdef CYGOPT_IO_CAN_SUPPORT_TIMESTAMP
pevent->timestamp = msr & MSR_TIMESTAMP;
#endif
HAL_WRITE_UINT32(CAN_MB_MCR(info, mbox), MCR_TRANSFER_CMD); // transfer request
AT91SAM7_DBG_PRINT("RXID: %x\n", AT91SAM7_CAN_GET_ID(pevent->msg));
} // if (!(mbox & info->rtr_mboxes)
else
{
HAL_WRITE_UINT32(CAN_MB_MCR(info, mbox), (msr & MSR_DLC) | MCR_TRANSFER_CMD); // transfer request
//
// We do not need to store an event into receive queue if the stat field does
// not contain any further event flags. If stat is empty we can set res
// to false and no event will bestore
//
res = !(*pstat == 0);
}
HAL_WRITE_UINT32(CAN_IER(info), 0x01 << mbox); // enable interruptfor this message box
} // if (mboxflags)
//
// Now check if additional events occured
//
if (*pstat)
{
if (*pstat & INT_WAKEUP)
{
AT91SAM7_DBG_PRINT("WAKE\n");
pevent->flags |= CYGNUM_CAN_EVENT_LEAVING_STANDBY;
*pstat &= ~INT_WAKEUP;
info->state = CYGNUM_CAN_STATE_ACTIVE;
}
if (*pstat & INT_ERR_PASSIVE)
{
AT91SAM7_DBG_PRINT("ERRP\n");
pevent->flags |= CYGNUM_CAN_EVENT_ERR_PASSIVE;
*pstat &= ~INT_ERR_PASSIVE;
info->state = CYGNUM_CAN_STATE_ERR_PASSIVE;
HAL_WRITE_UINT32(CAN_IER(info), INT_WAKEUP);
}
if (*pstat & INT_WARN)
{
//
// check which counter reached its warning level (> 96)
//
cyg_uint8 ecr;
HAL_READ_UINT32(CAN_ECR(info), ecr);
if (ECR_GET_REC(ecr) > 96)
{
pevent->flags |= CYGNUM_CAN_EVENT_WARNING_RX;
AT91SAM7_DBG_PRINT("WARN TX\n");
}
if (ECR_GET_TEC(ecr) > 96)
{
pevent->flags |= CYGNUM_CAN_EVENT_WARNING_TX;
AT91SAM7_DBG_PRINT("WARN RX\n");
}
*pstat &= ~INT_WARN;
info->state = CYGNUM_CAN_STATE_BUS_WARN;
HAL_WRITE_UINT32(CAN_IER(info), INT_ERR_PASSIVE | INT_BUS_OFF);
}
if (*pstat & INT_BUS_OFF)
{
pevent->flags |= CYGNUM_CAN_EVENT_BUS_OFF;
AT91SAM7_DBG_PRINT("BOFF\n");
*pstat &= ~INT_BUS_OFF;
info->state = CYGNUM_CAN_STATE_BUS_OFF;
HAL_WRITE_UINT32(CAN_IER(info), INT_WAKEUP);
}
if (*pstat & INT_SLEEP)
{
pevent->flags |= CYGNUM_CAN_EVENT_ENTERING_STANDBY;
AT91SAM7_DBG_PRINT("SLEEP\n");
*pstat &= ~INT_SLEEP;
HAL_WRITE_UINT32(AT91_PMC+AT91_PMC_PCDR, 1 << CAN_PID(info)); // disable module clock
info->state = CYGNUM_CAN_STATE_STANDBY; // set state variable
HAL_WRITE_UINT32(CAN_IER(info), INT_WAKEUP); // enable wakeup interrupt
}
if (*pstat & (INT_CRC_ERR | INT_STUFF_ERR | INT_ACKN_ERR | INT_FORM_ERR | INT_BIT_ERR))
{
pevent->flags |= CYGNUM_CAN_EVENT_CAN_ERR;
AT91SAM7_DBG_PRINT("CERR\n");
*pstat &= ~(INT_CRC_ERR | INT_STUFF_ERR | INT_ACKN_ERR | INT_FORM_ERR | INT_BIT_ERR);
}
} // if (*pstat)
return res;
}
//===========================================================================
// Kick transmitter
//===========================================================================
static void at91sam7_can_start_xmit(can_channel* chan)
{
CAN_DECLARE_INFO(chan);
AT91SAM7_DBG_PRINT("start_xmit\n");
cyg_drv_dsr_lock();
HAL_WRITE_UINT32(CAN_IER(info), 0x01 << CAN_MBOX_TX(info)); // enable tx interrupt
cyg_drv_dsr_unlock();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -