/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,2011 Giovanni Di Sirio.
2012,2013 Martin Schüßler and Florian Sehl, Embedded Software Laboratory,
RWTH Aachen University
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file AT91SAM7/can_lld.c
* @brief AT91SAM7 CAN Driver subsystem low level driver source.
*
* @pre - Make sure that the Mailbox you are receiving from is holding your
* data.
* - If you have more than one use the rxfull_event provided by the
* Driver.
* - In order to use the Events APIs the CH_USE_EVENTS option must
* be enabled in chconf.h.
* - In order to use the CAN driver the HAL_USE_CAN option must be
* enabled in halconf.h.
* - Mailbox0 is used as a Transmitmailbox.
* - Mailboxes 1-7 are used as receive Mailboxes.
*
* @addtogroup CAN
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_CAN || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief CAN driver identifier.
*/
#if AT91SAM7_CAN_USE_CAN || defined(__DOXYGEN__)
CANDriver CAND;
#endif
/*===========================================================================*/
/* Driver local variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/**
* @brief CAN[0] interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(CANIrqHandler) {
CH_IRQ_PROLOGUE();
can_lld_serve_interrupt(&CAND);
AT91C_BASE_AIC->AIC_EOICR = 0;
CH_IRQ_EPILOGUE();
}
#if defined(__GNUC__)
__attribute__((noinline))
#endif
/**
* @brief Handles CAN interrupts.
*
* @param[in] pointer to the driver that received the interrupt
*/
void can_lld_serve_interrupt(CANDriver *canp) {
canstatus_t status;
chSysLockFromIsr();
status = canp->base->CAN_SR & canp->base->CAN_IMR;
/* if AT91C_CAN_WAKEUP is set, the can test was successful
* such that the CAN is now able to Transmit and Receive Data.
*/
if ((status & AT91C_CAN_WAKEUP) == AT91C_CAN_WAKEUP) {
canp->base->CAN_IDR = AT91C_CAN_WAKEUP;
canp->testok = AT91C_TEST_OK;
}
else {
/* check the mailboxes (MB0-MB7) and broadcast the corresponding event.*/
/* configure send mailbox, mailbox 0 */
#if CAN_USE_MB0
if(status & AT91C_CAN_MB0 && canp->mb[CAN_TxMB0-1]->CAN_MB_MSR & AT91C_CAN_MRDY) {
canp->base->CAN_IDR = AT91C_CAN_MB0;
chSemSignalI(&(canp->txsem));
}
#else
#warning You need to acivate Mailbox0 to transmit.
#endif
#if CAN_USE_MB1
if (status & AT91C_CAN_MB1 &&
canp->mb[CAN_RxMB1-1]->CAN_MB_MSR & AT91C_CAN_MRDY) {
chSemSignalI(&(canp->rxsem));
chEvtBroadcastFlagsI(&(canp->rxfull_event), EVENT_MASK (CAN_RxMB1-1));
canp->base->CAN_IDR = AT91C_CAN_MB1;
}
#endif
#if CAN_USE_MB2
if (status & AT91C_CAN_MB2 &&
canp->mb[CAN_RxMB2-1]->CAN_MB_MSR & AT91C_CAN_MRDY) {
chSemSignalI(&(canp->rxsem));
chEvtBroadcastFlagsI(&(canp->rxfull_event), EVENT_MASK (CAN_RxMB2-1));
canp->base->CAN_IDR = AT91C_CAN_MB2;
}
#endif
#if CAN_USE_MB3
if (status & AT91C_CAN_MB3 &&
canp->mb[CAN_RxMB3-1]->CAN_MB_MSR & AT91C_CAN_MRDY) {
chSemSignalI(&(canp->rxsem));
chEvtBroadcastFlagsI(&(canp->rxfull_event), EVENT_MASK (CAN_RxMB3-1));
canp->base->CAN_IDR = AT91C_CAN_MB3;
}
#endif
#if CAN_USE_MB4
if (status & AT91C_CAN_MB4 && c
anp->mb[CAN_RxMB4-1]->CAN_MB_MSR & AT91C_CAN_MRDY) {
chSemSignalI(&(canp->rxsem));
chEvtBroadcastFlagsI(&(canp->rxfull_event), EVENT_MASK (CAN_RxMB4-1));
canp->base->CAN_IDR = AT91C_CAN_MB4;
}
#endif
#if CAN_USE_MB5
if (status & AT91C_CAN_MB5 &&
canp->mb[CAN_RxMB5-1]->CAN_MB_MSR & AT91C_CAN_MRDY) {
chSemSignalI(&(canp->rxsem));
chEvtBroadcastFlagsI(&(canp->rxfull_event), EVENT_MASK (CAN_RxMB5-1));
canp->base->CAN_IDR = AT91C_CAN_MB5;
}
#endif
#if CAN_USE_MB6
if (status & AT91C_CAN_MB6 &&
canp->mb[CAN_RxMB6-1]->CAN_MB_MSR & AT91C_CAN_MRDY) {
chSemSignalI(&(canp->rxsem));
chEvtBroadcastFlagsI(&(canp->rxfull_event, EVENT_MASK (CAN_RxMB6-1));
canp->base->CAN_IDR = AT91C_CAN_MB6;
}
#endif
#if CAN_USE_MB7
if (status & AT91C_CAN_MB7 &&
canp->mb[CAN_RxMB7-1]->CAN_MB_MSR & AT91C_CAN_MRDY) {
chSemSignalI(&(canp->rxsem));
chEvtBroadcastFlagsI(&(canp->rxfull_event), EVENT_MASK (CAN_RxMB7-1));
canp->base->CAN_IDR = AT91C_CAN_MB7;
}
#endif
}
/*check if error event is detected*/
if ((status & 0xFFCF0000) != 0) {
/*The content of the SR register is copied unchanged in the upper
half word of the listener flags mask*/
chEvtBroadcastFlagsI(&(canp->error_event), (eventmask_t)(status&0xFFFF0000));
}
chSysUnlockFromIsr();
}
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level CAN driver initialization.
*
* @notapi
*/
void can_lld_init(void) {
/* Driver initialization.*/
canObjectInit(&CAND);
/*
* mailbox vector initialization
*/
#if CAN_USE_MB0
CAND.mb[CAN_TxMB0-1] = AT91C_BASE_CAN_MB0;
#endif
#if CAN_USE_MB1
CAND.mb[CAN_RxMB1-1] = AT91C_BASE_CAN_MB1;
#endif
#if CAN_USE_MB2
CAND.mb[CAN_RxMB2-1] = AT91C_BASE_CAN_MB2;
#endif
#if CAN_USE_MB3
CAND.mb[CAN_RxMB3-1] = AT91C_BASE_CAN_MB3;
#endif
#if CAN_USE_MB4
CAND.mb[CAN_RxMB4-1] = AT91C_BASE_CAN_MB4;
#endif
#if CAN_USE_MB5
CAND.mb[CAN_RxMB5-1] = AT91C_BASE_CAN_MB5;
#endif
#if CAN_USE_MB6
CAND.mb[CAN_RxMB6-1] = AT91C_BASE_CAN_MB6;
#endif
#if CAN_USE_MB7
CAND.mb[CAN_RxMB7-1] = AT91C_BASE_CAN_MB7;
#endif
/*
* PIO
*/
/* Disable interrupts on the pin(s)*/
AT91C_BASE_PIOA->PIO_IDR = AT91C_PA19_CANRX;
AT91C_BASE_PIOA->PIO_IDR = AT91C_PA20_CANTX;
/* Select peripheral function A*/
AT91C_BASE_PIOA->PIO_ASR = AT91C_PA19_CANRX;
AT91C_BASE_PIOA->PIO_ASR = AT91C_PA20_CANTX;
/* Disables the PIO from controlling the corresponding pin
* (enables peripheral control of the pin)
*/
AT91C_BASE_PIOA->PIO_PDR = AT91C_PA19_CANRX;
AT91C_BASE_PIOA->PIO_PDR = AT91C_PA20_CANTX;
/* Disable pull up */
AT91C_BASE_PIOA->PIO_PPUDR = AT91C_PA19_CANRX | AT91C_PA20_CANTX;
/* Configure the AIC for CAN interrupts */
AIC_ConfigureIT(AT91C_ID_CAN, AT91C_AIC_PRIOR_HIGHEST, CANIrqHandler);
CAND.base = AT91C_BASE_CAN;
}
/**
* @brief configures and starts the CAN peripheral.
*/
static void can_startsequence(CANDriver *canp) {
canp->state = CAN_STARTING;
canp->testok = AT91C_TEST_NOK;
/* clock */
/* Enable clock for PIOA */
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_PIOA);
/* Enable the CAN controller peripheral clock */
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_CAN);
/* interrupts */
/* disable all interrupts */
canp->base->CAN_IDR = 0x1FFFFFFF;
/* Enable the interrupt on the interrupt controller*/
AIC_EnableIT(AT91C_ID_CAN);
canp->base->CAN_BR = canp->config->br;
/* configure send mailbox, mailbox 0 */
#if CAN_USE_MB0
canp->mb[CAN_TxMB0-1]->CAN_MB_MCR = 0x0;
canp->mb[CAN_TxMB0-1]->CAN_MB_MMR = AT91C_CAN_MOT_TX | AT91C_CAN_PRIOR;
canp->mb[CAN_TxMB0-1]->CAN_MB_MAM = 0x00000000;
canp->mb[CAN_TxMB0-1]->CAN_MB_MID = AT91C_CAN_MIDE;
canp->mb[CAN_TxMB0-1]->CAN_MB_MDL = 0x11223344;
canp->mb[CAN_TxMB0-1]->CAN_MB_MDH = 0x01234567;
canp->mb[CAN_TxMB0-1]->CAN_MB_MCR = (AT91C_CAN_MDLC & (0x8 << 16));
canp->mb[CAN_TxMB0-1]->CAN_MB_MMR = AT91C_CAN_MOT_TX | AT91C_CAN_PRIOR;
#else
#warning You need to acivate Mailbox0 to transmit.
#endif
#if CAN_USE_MB1
canp->mb[CAN_RxMB1-1]->CAN_MB_MCR = 0x0;
canp->mb[CAN_RxMB1-1]->CAN_MB_MMR = AT91C_CAN_MOT_RX | AT91C_CAN_PRIOR;
canp->mb[CAN_RxMB1-1]->CAN_MB_MAM = AT91C_CAN_MIDE
|(AT91C_CAN_MIDvB & canp->config->mb1_acceptance_mask)
| (AT91C_CAN_MIDvA & canp->config->mb1_acceptance_mask);
canp->mb[CAN_RxMB1-1]->CAN_MB_MID = AT91C_CAN_MIDE
| (AT91C_CAN_MIDvB & canp->config->mb1_can_id)
| (AT91C_CAN_MIDvA & canp->config->mb1_can_id);
canp->mb[CAN_RxMB1-1]->CAN_MB_MDL = 0x00000000;
canp->mb[CAN_RxMB1-1]->CAN_MB_MDH = 0x00000000;
#endif
#if CAN_USE_MB2
canp->mb[CAN_RxMB2-1]->CAN_MB_MCR = 0x0;
canp->mb[CAN_RxMB2-1]->CAN_MB_MMR = AT91C_CAN_MOT_RX | AT91C_CAN_PRIOR;
canp->mb[CAN_RxMB2-1]->CAN_MB_MAM = AT91C_CAN_MIDE
| (AT91C_CAN_MIDvB & canp->config->mb2_acceptance_mask)
| (AT91C_CAN_MIDvA & canp->config->mb2_acceptance_mask);
canp->mb[CAN_RxMB2-1]->CAN_MB_MID = AT91C_CAN_MIDE
| (AT91C_CAN_MIDvB & canp->config->mb2_can_id)
| (AT91C_CAN_MIDvA & canp->config->mb2_can_id);
canp->mb[CAN_RxMB2-1]->CAN_MB_MDL = 0x00000000;
canp->mb[CAN_RxMB2-1]->CAN_MB_MDH = 0x00000000;
#endif
#if CAN_USE_MB3
canp->mb[CAN_RxMB3-1]->CAN_MB_MCR = 0x0;
canp->mb[CAN_RxMB3-1]->CAN_MB_MMR = AT91C_CAN_MOT_RX | AT91C_CAN_PRIOR;
canp->mb[CAN_RxMB3-1]->CAN_MB_MAM = AT91C_CAN_MIDE
| (AT91C_CAN_MIDvB & canp->config->mb3_acceptance_mask)
| (AT91C_CAN_MIDvA & canp->config->mb3_acceptance_mask);
canp->mb[CAN_RxMB3-1]->CAN_MB_MID = AT91C_CAN_MIDE
| (AT91C_CAN_MIDvB & canp->config->mb3_can_id)
| (AT91C_CAN_MIDvA & canp->config->mb3_can_id);
canp->mb[CAN_RxMB3-1]->CAN_MB_MDL = 0x00000000;
canp->mb[CAN_RxMB3-1]->CAN_MB_MDH = 0x00000000;
#endif
#if CAN_USE_MB4
canp->mb[CAN_RxMB4-1]->CAN_MB_MCR = 0x0;
canp->mb[CAN_RxMB4-1]->CAN_MB_MMR = AT91C_CAN_MOT_RX | AT91C_CAN_PRIOR;_MAM = AT91C_CAN_MIDE
| (AT91C_CAN_MIDvB & canp->config->mb4_acceptance_mask)
| (AT91C_CAN_MIDvA & canp->config->mb4_acceptance_mask);
canp->mb[CAN_RxMB4-1]->CAN_MB_MID = AT91C_CAN_MIDE
| (AT91C_CAN_MIDvB & canp->config->mb4_can_id)
| (AT91C_CAN_MIDvA & canp->config->mb4_can_id);
canp->mb[CAN_RxMB4-1]->CAN_MB_MDL = 0x00000000;
canp->mb[CAN_RxMB4-1]->CAN_MB_MDH = 0x00000000;
#endif
#if CAN_USE_MB5
canp->mb[CAN_RxMB5-1]->CAN_MB_MCR = 0x0;
canp->mb[CAN_RxMB4-1]->CAN_MB_MMR = AT91C_CAN_MOT_RX | AT91C_CAN_PRIOR;
canp->mb[CAN_RxMB5-1]->CAN_MB_MAM = AT91C_CAN_MIDE
| (AT91C_CAN_MIDvB & canp->config->mb5_acceptance_mask)
| (AT91C_CAN_MIDvA & canp->config->mb5_acceptance_mask);
canp->mb[CAN_RxMB5-1]->CAN_MB_MID = AT91C_CAN_MIDE
| (AT91C_CAN_MIDvB & canp->config->mb5_can_id)
| (AT91C_CAN_MIDvA & canp->config->mb5_can_id);
canp->mb[CAN_RxMB5-1]->CAN_MB_MDL = 0x00000000;
canp->mb[CAN_RxMB5-1]->CAN_MB_MDH = 0x00000000;
#endif
#if CAN_USE_MB6
canp->mb[CAN_RxMB6-1]->CAN_MB_MCR = 0x0;
canp->mb[CAN_RxMB6-1]->CAN_MB_MMR = AT91C_CAN_MOT_RX | AT91C_CAN_PRIOR;
canp->mb[CAN_RxMB6-1]->CAN_MB_MAM = AT91C_CAN_MIDE
| (AT91C_CAN_MIDvB & canp->config->mb6_acceptance_mask)
| (AT91C_CAN_MIDvA & canp->config->mb6_acceptance_mask);
canp->mb[CAN_RxMB6-1]->CAN_MB_MID = AT91C_CAN_MIDE
| (AT91C_CAN_MIDvB & canp->config->mb6_can_id)
| (AT91C_CAN_MIDvA & canp->config->mb6_can_id);
canp->mb[CAN_RxMB6-1]->CAN_MB_MDL = 0x00000000;
canp->mb[CAN_RxMB6-1]->CAN_MB_MDH = 0x00000000;
#endif
#if CAN_USE_MB7
canp->mb[CAN_RxMB7-1]->CAN_MB_MCR = 0x0;
canp->mb[CAN_RxMB7-1]->CAN_MB_MMR = AT91C_CAN_MOT_RX | AT91C_CAN_PRIOR;
canp->mb[CAN_RxMB7-1]->CAN_MB_MAM = AT91C_CAN_MIDE
| (AT91C_CAN_MIDvB & canp->config->mb7_acceptance_mask)
| (AT91C_CAN_MIDvA & canp->config->mb7_acceptance_mask);
canp->mb[CAN_RxMB7-1]->CAN_MB_MID = AT91C_CAN_MIDE
| (AT91C_CAN_MIDvB & canp->config->mb7_can_id)
| (AT91C_CAN_MIDvA & canp->config->mb7_can_id);
canp->mb[CAN_RxMB7-1]->CAN_MB_MDL = 0x00000000;
canp->mb[CAN_RxMB7-1]->CAN_MB_MDH = 0x00000000;
#endif
/* Enable the interrupt with all error cases */
canp->base->CAN_IER = AT91C_CAN_CERR /* (CAN) CRC Error */
| AT91C_CAN_SERR /* (CAN) Stuffing Error */
| AT91C_CAN_BERR /* (CAN) Bit Error */
| AT91C_CAN_FERR /* (CAN) Form Error */
| AT91C_CAN_AERR; /* (CAN) Acknowledgment Error */
/* Enable CAN and */
canp->base->CAN_IER = AT91C_CAN_WAKEUP;
/* CAN Controller Enable */
canp->base->CAN_MR = AT91C_CAN_CANEN;
}
/**
* @brief Configures and activates the CAN peripheral.
*
* @param[in] canp pointer to the @p CANDriver object
*
* @notapi
*/
void can_lld_start(CANDriver *canp) {
/*start CAN*/
can_startsequence(canp);
/* wait until wakeup. If no wakeup after 1 sec restart. */
chThdSleepS(1);
while( (canp->testok) == AT91C_TEST_NOK) {
/* stop CAN */
/* Disable all interrupts */
canp->base->CAN_IDR = 0x1FFFFFFF;
/* Disable the interrupt on the interrupt controller */
AIC_DisableIT(AT91C_ID_CAN);
/* Disable the CAN controller peripheral clock */
AT91C_BASE_PMC->PMC_PCER = (0 << AT91C_ID_CAN);
/* restart CAN */
can_startsequence(canp);
chThdSleepS(1);
}
/*enable Mailboxes */
#if CAN_USE_MB1
canp->base->CAN_IER = (0x1 << 1);
#endif
#if CAN_USE_MB2
canp->base->CAN_IER = (0x1 << 2);
#endif
#if CAN_USE_MB3
canp->base->CAN_IER = (0x1 << 3);
#endif
#if CAN_USE_MB4
canp->base->CAN_IER = (0x1 << 4);
#endif
#if CAN_USE_MB5
canp->base->CAN_IER = (0x1 << 5);
#endif
#if CAN_USE_MB6
canp->base->CAN_IER = (0x1 << 6);
#endif
#if CAN_USE_MB7
canp->base->CAN_IER = (0x1 << 7);
#endif
}
/**
* @brief Deactivates the CAN peripheral.
*
* @param[in] canp pointer to the @p CANDriver object
*
* @notapi
*/
void can_lld_stop(CANDriver *canp) {
/* If in ready state then disables the CAN peripheral.*/
if (canp->state == CAN_READY) {
/* Disable all interrupts */
canp->base->CAN_IDR = 0x1FFFFFFF;
/* Disable the interrupt on the interrupt controller */
AIC_DisableIT(AT91C_ID_CAN);
/* Disable the CAN controller peripheral clock */
AT91C_BASE_PMC->PMC_PCER = (0 << AT91C_ID_CAN);
}
}
/**
* @brief Determines whether a frame can be transmitted.
*
* @param[in] canp pointer to the @p CANDriver object
* @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox
* @return The queue space availability.
* @retval FALSE no space in the transmit queue.
* @retval TRUE transmit slot available.
*
* @notapi
*/
bool_t can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox) {
return ((canp->mb[CAN_TxMB0-1]->CAN_MB_MSR & AT91C_CAN_MRDY) != 0);
}
/**
* @brief Send specified frame.
*
* @param[in] canp pointer to the @p CANDriver object
* @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox
* @param[in] ctfp pointer to the CAN frame to be transmitted
*
* @notapi
*/
void can_lld_transmit(CANDriver *canp, canmbx_t mailbox, const CANTxFrame *ctfp) {
while (!( canp->mb[CAN_TxMB0-1]->CAN_MB_MSR & AT91C_CAN_MRDY)){
}
#if CAN_IDE_EXT
canp->mb[CAN_TxMB0-1]->CAN_MB_MID =
AT91C_CAN_MIDE | (AT91C_CAN_MIDvB & ctfp->EID)
| (AT91C_CAN_MIDvA & (ctfp->EID)); //configure the id
#else
canp->mb[CAN_TxMB0-1]->CAN_MB_MID = AT91C_CAN_MIDE |
(AT91C_CAN_MIDvB & 0x0)
| (AT91C_CAN_MIDvA & ctfp->SID); //configure the id
#endif
/* set length of data */
canp->mb[CAN_TxMB0-1]->CAN_MB_MCR = (AT91C_CAN_MDLC & (ctfp->DLC << 16));
/* fill low register if 0DLC>0)
canp->mb[CAN_TxMB0-1]->CAN_MB_MDL = ctfp->data32[0];
/* fill high register 4DLC>4)
canp->mb[CAN_TxMB0-1]->CAN_MB_MDH = ctfp->data32[1];
canp->base->CAN_IER = 1 << CAN_TxMB0-1;
canp->base->CAN_TCR = 1 << 0; //send msg
}
/**
* @brief check if some data is available mailbox.
*
* @param[in] canp pointer to the @p CANDriver object
* @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox
* @return The queue space availability.
* @retval FALSE mailbox is empty
* @retval TRUE some data in the mailbox
*
* @notapi
*/
bool_t can_lld_is_rx_nonempty(CANDriver *canp, canmbx_t mailbox) {
if(mailbox == CAN_ANY_MAILBOX){
/* get status of all receive mailboxes (Mailbox0 is transmit mailbox) */
if((canp->base->CAN_SR & 0xFE) != 0){
return TRUE;
}
} else{
/* get status of specified mailbox */
if((canp->base->CAN_SR & (1<<(mailbox-1))) != 0){
/* data available */
return TRUE;
} else{
/* no data */
return FALSE;
}
}
}
/**
* @brief Receives a frame from the specified mailbox.
*
* @pre Make sure that the Mailbox you are receiving from is holding
* your data. If you have more than one use the rxfull_event
* provided by the Driver.
*
* @param[in] canp pointer to the @p CANDriver object
* @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox
* @param[out] crfp pointer to the buffer where the CAN frame is copied
*
* @notapi
*/
void can_lld_receive(CANDriver *canp, canmbx_t mailbox, CANRxFrame *crfp) {
if(mailbox != CAN_ANY_MAILBOX){
/* get length of data */
crfp->DLC = (canp->mb[mailbox-1]->CAN_MB_MSR &
AT91C_CAN_MDLC) >> 16;
/* store data */
if(crfp->DLC>0){
crfp->data32[0] = canp->mb[mailbox-1]->CAN_MB_MDL;
}
if(crfp->DLC>=4){
crfp->data32[1] = canp->mb[mailbox-1]->CAN_MB_MDH;
}
}
else{
/* TODO implement can_lld_receive for CAN_ANY_MAILBOX */
}
/* clear register */
canp->base->CAN_TCR = (0x1 << (mailbox-1));
/* reenable interrupt */
canp->base->CAN_IER = (0x1 << (mailbox-1));
}
#if CAN_USE_SLEEP_MODE || defined(__DOXYGEN__)
/**
* @brief Enters the sleep mode.
*
* @param[in] canp pointer to the @p CANDriver object
*
* @notapi
*/
void can_lld_sleep(CANDriver *canp) {
/* Wait till Tx Mailbox is ready */
while(!((canp->mb[CAN_TxMB0-1]->CAN_MB_MSR & AT91C_CAN_MRDY) == AT91C_CAN_MRDY)){
}
/* enable low power mode */
canp->base->CAN_MR |= AT91C_CAN_LPM;
/* wait till CAN is in low power mode */
while(!((canp->base->CAN_SR & AT91C_CAN_SLEEP) == AT91C_CAN_SLEEP)){
}
/* disable Clock */
AT91C_BASE_PMC->PMC_PCDR = (1 << AT91C_ID_CAN);
}
/**
* @brief Enforces leaving the sleep mode.
*
* @param[in] canp pointer to the @p CANDriver object
*
* @notapi
*/
void can_lld_wakeup(CANDriver *canp) {
/* enable clock */
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_CAN);
/* disable low power mode */
canp->base->CAN_MR &= ~(AT91C_CAN_SLEEP);
while(!((canp->base->CAN_SR & AT91C_CAN_WAKEUP)==AT91C_CAN_WAKEUP)){
}
}
#endif /* CAN_USE_SLEEP_MODE */
#endif /* HAL_USE_CAN */
/** @} */