can_mcf52xx.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,632 行 · 第 1/5 页
C
1,632 行
//===========================================================================
// Check if we received self transmitted frame
//===========================================================================
static bool flexcan_is_no_self_tx(cyg_can_event *pevent, flexcan_info *info, flexcan_mbox_info *pmbox)
{
//
// If we received a self transmitted frame
// then this is not really an rx event and we return false. We rely on the
// fact here that two devices in network do not send the same identifier
//
if (pevent->msg.id == info->last_tx_id)
{
info->last_tx_id = 0xFFFFFFFF; // set last received ID to an invalid value
return false;
}
else
{
pevent->flags |= CYGNUM_CAN_EVENT_RX;
//
// check if an overun occured in this message box
//
if ((pmbox->ctrlstat_shadow & MBOX_RXCODE_OVERRUN) == MBOX_RXCODE_OVERRUN)
{
pevent->flags |= CYGNUM_CAN_EVENT_OVERRUN_RX;
}
return true;
}
}
//===========================================================================
// Read one event from can hardware - called from high level I/O CAN driver
//===========================================================================
static bool flexcan_getevent(can_channel *chan, cyg_can_event *pevent, void *pdata)
{
flexcan_info *info = (flexcan_info *)chan->dev_priv;
flexcan_regs *flexcan = (flexcan_regs *)info->base;
bool res = true;
cyg_uint16 estat;
cyg_uint8 event_id = *((cyg_uint8 *)pdata);
//
// if event_id is 0 - 15 the we have a message box event
//
if (event_id < FLEXCAN_ERR_EVENT)
{
flexcan_mbox_info *pmbox_info;
pmbox_info = &info->mboxes[event_id];
//
// Deceide what to do according to type of message box that caused this event
//
switch (pmbox_info->state)
{
//
// If we have an RX event then we need to read the received data from
// message box that caused this event and fill it into message queue of
// high level I/O CAN driver. We could handle this stuff in a function
// because it is the same like MBOX_STATE_RX_ALL_EXT but speed is more
// important here than codesize
//
case MBOX_STATE_RX_ALL_STD:
case MBOX_STATE_RX_ALL_EXT:
case MBOX_STATE_RX_FILT:
{
//
// read data from message box - during processing of this function
// the message box is locked and cannot receive further messages
//
flexcan_read_from_mbox(chan, event_id, pevent, &(pmbox_info->ctrlstat_shadow));
res = flexcan_is_no_self_tx(pevent, info, pmbox_info);
}
break;
#ifdef CYGOPT_IO_CAN_TX_EVENT_SUPPORT
//
// If a TX message box cause the event then we store the last transmitted
// message into the receive message queue
//
case MBOX_STATE_TX:
pevent->flags = CYGNUM_CAN_EVENT_TX;
pevent->msg = info->last_tx_msg;
break;
#endif // CYGOPT_IO_CAN_TX_EVENT_SUPPORT
case MBOX_STATE_REMOTE_TX:
break;
default:
res = false;
} // switch (pmbox->state)
}
else // (event_id >= FLEXCAN_ERR_EVENT)
{
//
// We have an status event - check if it is an bus off interrupt or an
// error interrupt and provide error information to upper layer
//
HAL_READ_UINT16(&flexcan->ESTAT, estat);
pevent->msg.data.bytes[0] = estat & 0xFF;
pevent->msg.data.bytes[1] = (estat >> 8) & 0xFF;
HAL_READ_UINT8(&flexcan->RXERRCNT, pevent->msg.data.bytes[2]);
HAL_READ_UINT8(&flexcan->TXERRCNT, pevent->msg.data.bytes[3]);
switch (event_id)
{
case FLEXCAN_ERR_EVENT :
//
// indicate error passive event and provide content of estat register
// for a more precise error information
//
if (estat & FLEXCAN_ESTAT_FCS_ERROR_PASSIVE)
{
pevent->flags = CYGNUM_CAN_EVENT_ERR_PASSIVE;
}
//
// If we are not in error passive state then we check if the
// error counters reached the warning level
//
else
{
//
// indicate tx error counter warning level reached
//
if (estat & FLEXCAN_ESTAT_TXWARN)
{
pevent->flags |= CYGNUM_CAN_EVENT_WARNING_TX;
}
//
// indicate rx error counter warning level reached
//
if (estat & FLEXCAN_ESTAT_RXWARN)
{
pevent->flags |= CYGNUM_CAN_EVENT_WARNING_RX;
}
}
break;
case FLEXCAN_BUSOFF_EVENT:
pevent->flags = CYGNUM_CAN_EVENT_BUS_OFF;
break;
case FLEXCAN_WAKE_EVENT:
pevent->flags = CYGNUM_CAN_EVENT_LEAVING_STANDBY;
break;
} // switch (event_id)
}
return res;
}
//===========================================================================
// Send one CAN message to CAN hardware
//===========================================================================
static bool flexcan_putmsg(can_channel *chan, cyg_can_message *pmsg, void *pdata)
{
flexcan_info *info = (flexcan_info *)chan->dev_priv;
flexcan_regs *flexcan = (flexcan_regs *)info->base;
cyg_uint8 mbox = *((cyg_uint8 *)pdata);
flexcan_mbox_info *pmbox = &info->mboxes[mbox];
cyg_uint16 iflag;
HAL_READ_UINT16(&flexcan->IFLAG, iflag);
//
// check if device is busy sending a message
//
if (pmbox->busy)
{
//
// if device is busy and the interrupt flag is set, then we know
// that device is not busy any longer
//
if (iflag & (0x0001 << mbox))
{
HAL_WRITE_UINT16(&flexcan->IFLAG, (0x0001 << mbox));
}
else
{
return false;
}
}
pmbox->busy = true; // mark transmitter as busy
info->last_tx_id = pmsg->id; // store message in order to identify self recieved frames
#ifdef CYGOPT_IO_CAN_TX_EVENT_SUPPORT
info->last_tx_msg = *pmsg; // store the transmitted message for TX events
#endif
flexcan_cfg_mbox_tx(&flexcan->mbox[mbox], pmsg, false); // send message
return true;
}
//===========================================================================
// Flexcan start xmit - If the chip is in standby mode then a call to this
// function will cause the FlexCAN modul to leave the standby mode. So
// the output queue should be empty before entering stadby mode
//===========================================================================
static void flexcan_start_xmit(can_channel* chan)
{
flexcan_info *info = (flexcan_info *)chan->dev_priv;
CYG_INTERRUPT_STATE saved_state;
HAL_DISABLE_INTERRUPTS(saved_state);
//
// if we are in standby state the we leave standby state now. This is
// the reason that the user should wait until the TX queue is empty before
// entering standby mode- or he should drain or flush the TX queue
//
if (CYGNUM_CAN_STATE_STANDBY == info->state)
{
flexcan_leave_standby(chan);
}
//
// Now enable message box 15 interrupts
//
flexcan_mboxint_enable(info, info->tx_all_mbox);
//
// kick transmitter
//
chan->callbacks->xmt_msg(chan, &info->tx_all_mbox); // Kick transmitter (if necessary)
HAL_RESTORE_INTERRUPTS(saved_state);
}
//===========================================================================
// Flexcan stop transmission
//===========================================================================
static void flexcan_stop_xmit(can_channel* chan)
{
flexcan_info *info = (flexcan_info *)chan->dev_priv;
CYG_INTERRUPT_STATE saved_state;
HAL_DISABLE_INTERRUPTS(saved_state);
//
// Now disable message box 15 interrupts
//
flexcan_mboxint_disable(info, info->tx_all_mbox);
HAL_RESTORE_INTERRUPTS(saved_state);
}
//===========================================================================
// Configure flexcan channel
//===========================================================================
static bool flexcan_config(can_channel* chan, cyg_can_info_t* config, cyg_bool init)
{
flexcan_info *info = (flexcan_info *)chan->dev_priv;
flexcan_regs *flexcan = (flexcan_regs *)info->base;
cyg_uint16 tmp16;
cyg_uint8 tmp8;
cyg_uint8 i;
//
// the first thing we need to do is to stop the chip
//
flexcan_stop_chip(chan);
//
// if this is the first initialisation of the FlexCAN modul we need to execute
// some extra steps here
//
if (init)
{
#if defined(CYGPKG_DEVS_CAN_MCF52xx_FLEXCAN0) && defined(HAL_MCF52xx_FLEXCAN0_PROC_INIT)
if (info == &flexcan_can0_info) {
HAL_MCF52xx_FLEXCAN0_PROC_INIT();
}
#endif
//
// Issue a reset in order to go into halt mode. The reset will set the
// the halt bit in mcr
//
HAL_READ_UINT16(&flexcan->CANMCR, tmp16);
tmp16 &= ~FLEXCAN_MCR_FRZ;
HAL_WRITE_UINT16(&flexcan->CANMCR, tmp16);
tmp16 |= FLEXCAN_MCR_SOFTRST;
HAL_WRITE_UINT16(&flexcan->CANMCR, tmp16);
HAL_DELAY_US(10);
//
// Check reset status
//
HAL_READ_UINT16(&flexcan->CANMCR, tmp16);
if (tmp16 & FLEXCAN_MCR_SOFTRST)
{
return false;
}
//
// Initialize the transmit and receive pin modes
//
HAL_WRITE_UINT8(&flexcan->CANCTRL0 , (FLEXCAN_CTRL0_TXMODE_FULL_0_DOMINANT
| FLEXCAN_CTRL0_RXMODE_0_DOMINANT)
& ~FLEXCAN_CTRL0_BOFFMSK
& ~FLEXCAN_CTRL0_ERRMASK);
//
// deactivate all message buffers - this is mandatory for configuration
// of message buffers
//
for (i = FLEXCAN_MBOX_MIN; i <= FLEXCAN_MBOX_MAX; ++i)
{
HAL_WRITE_UINT16(&flexcan->mbox[i], MBOX_RXCODE_NOT_ACTIVE);
}
//
// mask all interrupts
//
info->imask_sha
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?