diff options
Diffstat (limited to 'os/hal')
-rw-r--r-- | os/hal/platforms/AT91SAM7/can_lld.c | 640 | ||||
-rw-r--r-- | os/hal/platforms/AT91SAM7/can_lld.h | 407 | ||||
-rw-r--r-- | os/hal/platforms/AT91SAM7/platform.dox | 15 | ||||
-rw-r--r-- | os/hal/platforms/AT91SAM7/platform.mk | 1 |
4 files changed, 1063 insertions, 0 deletions
diff --git a/os/hal/platforms/AT91SAM7/can_lld.c b/os/hal/platforms/AT91SAM7/can_lld.c new file mode 100644 index 000000000..38cc6c166 --- /dev/null +++ b/os/hal/platforms/AT91SAM7/can_lld.c @@ -0,0 +1,640 @@ +/*
+ 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 <http://www.gnu.org/licenses/>.
+
+ ---
+
+ 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 0<Length<=8 */
+ if(ctfp->DLC>0)
+ canp->mb[CAN_TxMB0-1]->CAN_MB_MDL = ctfp->data32[0];
+ /* fill high register 4<Length<=8 */
+ if(ctfp->DLC>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 */
+
+/** @} */
diff --git a/os/hal/platforms/AT91SAM7/can_lld.h b/os/hal/platforms/AT91SAM7/can_lld.h new file mode 100644 index 000000000..f9ea7f6c2 --- /dev/null +++ b/os/hal/platforms/AT91SAM7/can_lld.h @@ -0,0 +1,407 @@ +/*
+ 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 <http://www.gnu.org/licenses/>.
+
+ ---
+
+ 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.h
+ * @brief AT91SAM7 CAN Driver subsystem low level driver header.
+ *
+ * @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
+ * @{
+ */
+
+#ifndef _CAN_LLD_H_
+#define _CAN_LLD_H_
+
+#if HAL_USE_CAN || defined(__DOXYGEN__)
+
+
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @brief This switch defines whether the driver implementation supports
+ * a low power switch mode with automatic an wakeup feature.
+ */
+#define CAN_SUPPORTS_SLEEP TRUE
+
+/**
+ * @brief This implementation supports one transmit mailboxes.
+ */
+#define CAN_TX_MAILBOXES 1
+
+/**
+ * @brief This implementation supports two receive mailboxes.
+ */
+#define CAN_RX_MAILBOXES 7
+
+/**
+ * @brief CAN mailboxes (Mailbox0 should always enabled to transmit)
+ */
+#ifndef CAN_USE_MB0
+#define CAN_USE_MB0 TRUE
+#endif
+#ifndef CAN_USE_MB1
+#define CAN_USE_MB1 TRUE
+#endif
+#ifndef CAN_USE_MB2
+#define CAN_USE_MB2 TRUE
+#endif
+#ifndef CAN_USE_MB3
+#define CAN_USE_MB3 TRUE
+#endif
+#ifndef CAN_USE_MB4
+#define CAN_USE_MB4 FALSE
+#endif
+#ifndef CAN_USE_MB5
+#define CAN_USE_MB5 FALSE
+#endif
+#ifndef CAN_USE_MB6
+#define CAN_USE_MB6 FALSE
+#endif
+#ifndef CAN_USE_MB7
+#define CAN_USE_MB7 FALSE
+#endif
+
+
+#define CAN_IDE_STD FALSE /**< @brief Standard id. */
+#define CAN_IDE_EXT TRUE /**< @brief Extended id. */
+
+#define CAN_RTR_DATA FALSE /**< @brief Data frame. */
+#define CAN_RTR_REMOTE TRUE /**< @brief Remote frame. */
+
+/**
+ * @brief timeout until can_lld_start stops waiting
+ * on CAN and ends up in error state
+ */
+#define AT91C_CAN_TIMEOUT 100
+
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @brief CAN driver enable switch.
+ * @details If set to @p TRUE the support for CAN0 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(AT91SAM7_CAN_USE_CAN) || defined(__DOXYGEN__)
+#define AT91SAM7_CAN_USE_CAN TRUE
+#endif
+
+/**
+ * @brief CAN interrupt priority level setting.
+ */
+#if !defined(AT91SAM7_CAN_CAN_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define AT91SAM7_CAN_CAN_IRQ_PRIORITY 11
+#endif
+
+/**
+ * @brief Sleep mode related APIs inclusion switch.
+ * @note This switch is enforced to @p FALSE if the driver implementation
+ * does not support the sleep mode.
+ */
+#if CAN_SUPPORTS_SLEEP || defined(__DOXYGEN__)
+#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__)
+#define CAN_USE_SLEEP_MODE TRUE
+#endif
+#else /* !CAN_SUPPORTS_SLEEP */
+#define CAN_USE_SLEEP_MODE FALSE
+#endif /* !CAN_SUPPORTS_SLEEP */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if CAN_USE_SLEEP_MODE && !CAN_SUPPORTS_SLEEP
+#error "CAN sleep mode not supported in this architecture"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of a transmission mailbox index
+ */
+typedef uint32_t canmbx_t;
+
+/**
+ * wakeup status possible states
+ */
+typedef enum {
+ AT91C_TEST_NOK = 0, /**< waiting for wakeup event */
+ AT91C_TEST_OK = 1 /**< wakeup event occured */
+} canteststate_t;
+
+/**
+ * @brief possible receive mailboxes.
+ * These Mailboxes get an offset to ensure that the Mailbox are not uninitialized.
+ *
+ */
+typedef enum {
+ CAN_TxMB0 = 1, /**< Transmit Mailbox. */
+ CAN_RxMB1 = 2, /**< Receive Mailbox 1. */
+ CAN_RxMB2 = 3, /**< Receive Mailbox 2. */
+ CAN_RxMB3 = 4, /**< Receive Mailbox 3. */
+ CAN_RxMB4 = 5, /**< Receive Mailbox 4. */
+ CAN_RxMB5 = 6, /**< Receive Mailbox 5. */
+ CAN_RxMB6 = 7, /**< Receive Mailbox 6. */
+ CAN_RxMB7 = 8 /**< Receive Mailbox 7. */
+} canmailbox_t;
+
+/**
+ * @brief CAN status flags.
+ */
+typedef uint32_t canstatus_t;
+
+/**
+ * @brief CAN transmission frame.
+ * @note Accessing the frame data as word16 or word32 is not portable
+ * because machine data endianness, it can be still useful for a
+ * quick filling.
+ */
+typedef struct {
+ struct {
+ uint8_t DLC:4; /**< @brief Data length. */
+ uint8_t RTR:1; /**< @brief Frame type. */
+ uint8_t IDE:1; /**< @brief Identifier type. */
+ };
+ union {
+ struct {
+ uint32_t SID:11; /**< @brief Standard identifier.*/
+ };
+ struct {
+ uint32_t EID:29; /**< @brief Extended identifier.*/
+ };
+ };
+ union {
+ uint8_t data8[8]; /**< @brief Frame data. */
+ uint16_t data16[4]; /**< @brief Frame data. */
+ uint32_t data32[2]; /**< @brief Frame data. */
+ };
+}CANTxFrame;
+
+/**
+ * @brief CAN received frame.
+ * @note Accessing the frame data as word16 or word32 is not portable
+ * because machine data endianness, it can be still useful for a
+ * quick filling.
+ */
+typedef struct {
+ struct {
+ uint8_t DLC:4; /**< @brief Data length. */
+ uint8_t RTR:1; /**< @brief Frame type. */
+ uint8_t IDE:1; /**< @brief Identifier type. */
+ };
+ union {
+ struct {
+ uint32_t SID:11; /**< @brief Standard identifier.*/
+ };
+ struct {
+ uint32_t EID:29; /**< @brief Extended identifier.*/
+ };
+ };
+ union {
+ uint8_t data8[8]; /**< @brief Frame data. */
+ uint16_t data16[4]; /**< @brief Frame data. */
+ uint32_t data32[2]; /**< @brief Frame data. */
+ };
+ canmailbox_t mbid; /**< @brief mailbox to read from */
+}CANRxFrame;
+
+/**
+ * @brief CAN filter.
+ * @note NOT used on this platform
+ */
+typedef struct {
+}CANFilter;
+
+/**
+ * @brief Driver configuration structure.
+ */
+typedef struct {
+
+#if CAN_USE_MB1
+ uint32_t mb1_can_id; /**< @brief mailbox 1 can id */
+ uint32_t mb1_acceptance_mask; /**< @brief mailbox 1 acceptance mask */
+#endif
+#if CAN_USE_MB2
+ uint32_t mb2_can_id; /**< @brief mailbox 2 can id */
+ uint32_t mb2_acceptance_mask; /**< @brief mailbox 2 acceptance mask */
+#endif
+#if CAN_USE_MB3
+ uint32_t mb3_can_id; /**< @brief mailbox 3 can id */
+ uint32_t mb3_acceptance_mask; /**< @brief mailbox 3 acceptance mask */
+#endif
+#if CAN_USE_MB4
+ uint32_t mb4_can_id; /**< @brief mailbox 4 can id */
+ uint32_t mb4_acceptance_mask; /**< @brief mailbox 4 acceptance mask */
+#endif
+#if CAN_USE_MB5
+ uint32_t mb5_can_id; /**< @brief mailbox 5 can id */
+ uint32_t mb5_acceptance_mask; /**< @brief mailbox 5 acceptance mask */
+#endif
+#if CAN_USE_MB6
+ uint32_t mb6_can_id; /**< @brief mailbox 6 can id */
+ uint32_t mb6_acceptance_mask; /**< @brief mailbox 6 acceptance mask */
+#endif
+#if CAN_USE_MB7
+ uint32_t mb7_can_id; /**< @brief mailbox 7 can id */
+ uint32_t mb7_acceptance_mask; /**< @brief mailbox 7 acceptance mask */
+#endif
+ /**
+ * @brief value of the BR register
+ * @note use 0x00050301 for 1MBit/s!
+ *
+ */
+ uint32_t br;
+
+}CANConfig;
+
+
+/**
+ * @brief Structure representing an CAN driver.
+ * @note Implementations may extend this structure to contain more,
+ * architecture dependent, fields.
+ */
+typedef struct {
+ /**
+ * @brief Driver state.
+ */
+ canstate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const CANConfig *config;
+ /**
+ * @brief Transmission queue semaphore.
+ */
+ Semaphore txsem;
+ /**
+ * @brief Receive queue semaphore.
+ */
+ Semaphore rxsem;
+ /**
+ * @brief One frame for one specified mailbox become available.
+ * @note The number of the mailbox will be broadcasted to all listening threads.
+ * It is responsibility of the application(thread) to empty the specified mailbox
+ * by invoking @p chReceive() when listening to this event.
+ */
+ EventSource rxfull_event;
+ /**
+ * @brief transmission slot become available.
+ */
+ EventSource txempty_event;
+ /**
+ * @brief A CAN bus error happened.
+ */
+ EventSource error_event;
+#if CAN_USE_SLEEP_MODE || defined (__DOXYGEN__)
+ /**
+ * @brief Entering sleep state event.
+ */
+ EventSource sleep_event;
+ /**
+ * @brief Exiting sleep state event.
+ */
+ EventSource wakeup_event;
+#endif /* CAN_USE_SLEEP_MODE */
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Driver test OK (wakeup event occurred).
+ */
+ volatile canteststate_t testok;
+ /**
+ * @brief Pointer to the Mailboxes registers block.
+ */
+ AT91PS_CAN_MB mb[8];
+ /**
+ * @brief Pointer to the CAN registers.
+ */
+ AT91PS_CAN base;
+}CANDriver;
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+ /**
+ * @brief create event mask using enum of the corresponding mailbox.
+ */
+#define CAN_EVENT_MASK(mailbox) EVENT_MASK(mailbox-1)
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if AT91SAM7_CAN_USE_CAN && !defined(__DOXYGEN__)
+extern CANDriver CAND;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void can_lld_init(void);
+ void can_lld_serve_interrupt(CANDriver *canp);
+ void can_lld_start(CANDriver *canp);
+ void can_lld_stop(CANDriver *canp);
+ bool_t can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox);
+ void can_lld_transmit(CANDriver *canp,
+ canmbx_t mailbox,
+ const CANTxFrame *crfp);
+ bool_t can_lld_is_rx_nonempty(CANDriver *canp, canmbx_t mailbox);
+ void can_lld_receive(CANDriver *canp,
+ canmbx_t mailbox,
+ CANRxFrame *ctfp);
+#if CAN_USE_SLEEP_MODE
+ void can_lld_sleep(CANDriver *canp);
+ void can_lld_wakeup(CANDriver *canp);
+
+#endif /* CAN_USE_SLEEP_MODE */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_CAN */
+
+#endif /* _CAN_LLD_H_ */
+
+/** @} */
diff --git a/os/hal/platforms/AT91SAM7/platform.dox b/os/hal/platforms/AT91SAM7/platform.dox index b423bb461..ec810c211 100644 --- a/os/hal/platforms/AT91SAM7/platform.dox +++ b/os/hal/platforms/AT91SAM7/platform.dox @@ -134,3 +134,18 @@ * .
* @ingroup AT91SAM7
*/
+
+/**
+ * @defgroup AT91SAM7_CAN AT91SAM7 CAN Support
+ * @details The CAN driver supports the AT91SAM7 CAN peripherals.
+ *
+ * @section at91sam7_can_1 Supported HW resources
+ * - CAN.
+ * .
+ * @section at91sam7_can_1 AT91SAM7 CAN driver implementation features
+ * - one send mailbox and seven receive mailboxes.
+ * - wakeup event on receive data.
+ * - deactivate unused mailbox to decrease memory usage and CPU usage
+ * .
+ * @ingroup AT91SAM7
+ */
diff --git a/os/hal/platforms/AT91SAM7/platform.mk b/os/hal/platforms/AT91SAM7/platform.mk index 40a71afc9..6b8438c6d 100644 --- a/os/hal/platforms/AT91SAM7/platform.mk +++ b/os/hal/platforms/AT91SAM7/platform.mk @@ -8,6 +8,7 @@ PLATFORMSRC = ${CHIBIOS}/os/hal/platforms/AT91SAM7/hal_lld.c \ ${CHIBIOS}/os/hal/platforms/AT91SAM7/spi_lld.c \
${CHIBIOS}/os/hal/platforms/AT91SAM7/mac_lld.c \
${CHIBIOS}/os/hal/platforms/AT91SAM7/pwm_lld.c \
+ ${CHIBIOS}/os/hal/platforms/AT91SAM7/can_lld.c \
${CHIBIOS}/os/hal/platforms/AT91SAM7/at91sam7_mii.c \
${CHIBIOS}/os/hal/platforms/AT91SAM7/at91lib/aic.c
|