From 60faa453fdaf110146543161e2b81d469fb42ca6 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Tue, 28 Jul 2015 11:44:32 +0000 Subject: Adjustments to the EXT driver, not yet finished. Moved all STM32 drivers in private subdirectories. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@8119 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/ports/STM32/LLD/CANv1/can_lld.c | 796 +++++++++++++++++++ os/hal/ports/STM32/LLD/CANv1/can_lld.h | 365 +++++++++ os/hal/ports/STM32/LLD/MACv1/mac_lld.c | 740 +++++++++++++++++ os/hal/ports/STM32/LLD/MACv1/mac_lld.h | 363 +++++++++ os/hal/ports/STM32/LLD/SDIOv1/sdc_lld.c | 873 +++++++++++++++++++++ os/hal/ports/STM32/LLD/SDIOv1/sdc_lld.h | 330 ++++++++ os/hal/ports/STM32/LLD/can_lld.c | 796 ------------------- os/hal/ports/STM32/LLD/can_lld.h | 365 --------- os/hal/ports/STM32/LLD/mac_lld.c | 740 ----------------- os/hal/ports/STM32/LLD/mac_lld.h | 363 --------- os/hal/ports/STM32/LLD/sdc_lld.c | 873 --------------------- os/hal/ports/STM32/LLD/sdc_lld.h | 330 -------- os/hal/ports/STM32/STM32F0xx/platform.mk | 13 +- os/hal/ports/STM32/STM32F0xx/stm32_registry.h | 21 +- os/hal/ports/STM32/STM32F1xx/ext_lld_isr.c | 70 +- os/hal/ports/STM32/STM32F1xx/platform.mk | 30 +- os/hal/ports/STM32/STM32F1xx/platform_f105_f107.mk | 38 +- os/hal/ports/STM32/STM32F1xx/stm32_registry.h | 21 +- os/hal/ports/STM32/STM32F37x/ext_lld_isr.c | 26 + os/hal/ports/STM32/STM32F37x/platform.mk | 17 +- os/hal/ports/STM32/STM32F37x/stm32_registry.h | 6 +- os/hal/ports/STM32/STM32F3xx/ext_lld_isr.c | 94 ++- os/hal/ports/STM32/STM32F3xx/platform.mk | 17 +- os/hal/ports/STM32/STM32F3xx/stm32_registry.h | 36 +- os/hal/ports/STM32/STM32F4xx/ext_lld_isr.c | 95 ++- os/hal/ports/STM32/STM32F4xx/platform.mk | 35 +- os/hal/ports/STM32/STM32F4xx/stm32_registry.h | 12 +- os/hal/ports/STM32/STM32L0xx/platform.mk | 14 +- os/hal/ports/STM32/STM32L0xx/stm32_registry.h | 3 +- os/hal/ports/STM32/STM32L1xx/ext_lld_isr.c | 102 ++- os/hal/ports/STM32/STM32L1xx/platform.mk | 8 +- os/hal/ports/STM32/STM32L1xx/stm32_registry.h | 6 +- 32 files changed, 3910 insertions(+), 3688 deletions(-) create mode 100644 os/hal/ports/STM32/LLD/CANv1/can_lld.c create mode 100644 os/hal/ports/STM32/LLD/CANv1/can_lld.h create mode 100644 os/hal/ports/STM32/LLD/MACv1/mac_lld.c create mode 100644 os/hal/ports/STM32/LLD/MACv1/mac_lld.h create mode 100644 os/hal/ports/STM32/LLD/SDIOv1/sdc_lld.c create mode 100644 os/hal/ports/STM32/LLD/SDIOv1/sdc_lld.h delete mode 100644 os/hal/ports/STM32/LLD/can_lld.c delete mode 100644 os/hal/ports/STM32/LLD/can_lld.h delete mode 100644 os/hal/ports/STM32/LLD/mac_lld.c delete mode 100644 os/hal/ports/STM32/LLD/mac_lld.h delete mode 100644 os/hal/ports/STM32/LLD/sdc_lld.c delete mode 100644 os/hal/ports/STM32/LLD/sdc_lld.h (limited to 'os') diff --git a/os/hal/ports/STM32/LLD/CANv1/can_lld.c b/os/hal/ports/STM32/LLD/CANv1/can_lld.c new file mode 100644 index 000000000..7bca76d8e --- /dev/null +++ b/os/hal/ports/STM32/LLD/CANv1/can_lld.c @@ -0,0 +1,796 @@ +/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file STM32/can_lld.c + * @brief STM32 CAN subsystem low level driver source. + * + * @addtogroup CAN + * @{ + */ + +#include "hal.h" + +#if HAL_USE_CAN || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/* + * Addressing differences in the headers, they seem unable to agree on names. + */ +#if STM32_CAN_USE_CAN1 +#if !defined(CAN1) +#define CAN1 CAN +#endif +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief CAN1 driver identifier.*/ +#if STM32_CAN_USE_CAN1 || defined(__DOXYGEN__) +CANDriver CAND1; +#endif + +/** @brief CAN2 driver identifier.*/ +#if STM32_CAN_USE_CAN2 || defined(__DOXYGEN__) +CANDriver CAND2; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Programs the filters. + * + * @param[in] can2sb number of the first filter assigned to CAN2 + * @param[in] num number of entries in the filters array, if zero then + * a default filter is programmed + * @param[in] cfp pointer to the filters array, can be @p NULL if + * (num == 0) + * + * @notapi + */ +static void can_lld_set_filters(uint32_t can2sb, + uint32_t num, + const CANFilter *cfp) { + + /* Temporarily enabling CAN1 clock.*/ + rccEnableCAN1(FALSE); + + /* Filters initialization.*/ + CAN1->FMR = (CAN1->FMR & 0xFFFF0000) | (can2sb << 8) | CAN_FMR_FINIT; + if (num > 0) { + uint32_t i, fmask; + + /* All filters cleared.*/ + CAN1->FA1R = 0; + CAN1->FM1R = 0; + CAN1->FS1R = 0; + CAN1->FFA1R = 0; + for (i = 0; i < STM32_CAN_MAX_FILTERS; i++) { + CAN1->sFilterRegister[i].FR1 = 0; + CAN1->sFilterRegister[i].FR2 = 0; + } + + /* Scanning the filters array.*/ + for (i = 0; i < num; i++) { + fmask = 1 << cfp->filter; + if (cfp->mode) + CAN1->FM1R |= fmask; + if (cfp->scale) + CAN1->FS1R |= fmask; + if (cfp->assignment) + CAN1->FFA1R |= fmask; + CAN1->sFilterRegister[cfp->filter].FR1 = cfp->register1; + CAN1->sFilterRegister[cfp->filter].FR2 = cfp->register2; + CAN1->FA1R |= fmask; + cfp++; + } + } + else { + /* Setting up a single default filter that enables everything for both + CANs.*/ + CAN1->sFilterRegister[0].FR1 = 0; + CAN1->sFilterRegister[0].FR2 = 0; +#if STM32_HAS_CAN2 + CAN1->sFilterRegister[can2sb].FR1 = 0; + CAN1->sFilterRegister[can2sb].FR2 = 0; +#endif + CAN1->FM1R = 0; + CAN1->FFA1R = 0; +#if STM32_HAS_CAN2 + CAN1->FS1R = 1 | (1 << can2sb); + CAN1->FA1R = 1 | (1 << can2sb); +#else + CAN1->FS1R = 1; + CAN1->FA1R = 1; +#endif + } + CAN1->FMR &= ~CAN_FMR_FINIT; + + /* Clock disabled, it will be enabled again in can_lld_start().*/ + rccDisableCAN1(FALSE); +} + +/** + * @brief Common TX ISR handler. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @notapi + */ +static void can_lld_tx_handler(CANDriver *canp) { + + /* No more events until a message is transmitted.*/ + canp->can->TSR = CAN_TSR_RQCP0 | CAN_TSR_RQCP1 | CAN_TSR_RQCP2; + osalSysLockFromISR(); + osalThreadDequeueAllI(&canp->txqueue, MSG_OK); + osalEventBroadcastFlagsI(&canp->txempty_event, CAN_MAILBOX_TO_MASK(1)); + osalSysUnlockFromISR(); +} + +/** + * @brief Common RX0 ISR handler. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @notapi + */ +static void can_lld_rx0_handler(CANDriver *canp) { + uint32_t rf0r; + + rf0r = canp->can->RF0R; + if ((rf0r & CAN_RF0R_FMP0) > 0) { + /* No more receive events until the queue 0 has been emptied.*/ + canp->can->IER &= ~CAN_IER_FMPIE0; + osalSysLockFromISR(); + osalThreadDequeueAllI(&canp->rxqueue, MSG_OK); + osalEventBroadcastFlagsI(&canp->rxfull_event, CAN_MAILBOX_TO_MASK(1)); + osalSysUnlockFromISR(); + } + if ((rf0r & CAN_RF0R_FOVR0) > 0) { + /* Overflow events handling.*/ + canp->can->RF0R = CAN_RF0R_FOVR0; + osalSysLockFromISR(); + osalEventBroadcastFlagsI(&canp->error_event, CAN_OVERFLOW_ERROR); + osalSysUnlockFromISR(); + } +} + +/** + * @brief Common RX1 ISR handler. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @notapi + */ +static void can_lld_rx1_handler(CANDriver *canp) { + uint32_t rf1r; + + rf1r = canp->can->RF1R; + if ((rf1r & CAN_RF1R_FMP1) > 0) { + /* No more receive events until the queue 0 has been emptied.*/ + canp->can->IER &= ~CAN_IER_FMPIE1; + osalSysLockFromISR(); + osalThreadDequeueAllI(&canp->rxqueue, MSG_OK); + osalEventBroadcastFlagsI(&canp->rxfull_event, CAN_MAILBOX_TO_MASK(2)); + osalSysUnlockFromISR(); + } + if ((rf1r & CAN_RF1R_FOVR1) > 0) { + /* Overflow events handling.*/ + canp->can->RF1R = CAN_RF1R_FOVR1; + osalSysLockFromISR(); + osalEventBroadcastFlagsI(&canp->error_event, CAN_OVERFLOW_ERROR); + osalSysUnlockFromISR(); + } +} + +/** + * @brief Common SCE ISR handler. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @notapi + */ +static void can_lld_sce_handler(CANDriver *canp) { + uint32_t msr; + + msr = canp->can->MSR; + canp->can->MSR = CAN_MSR_ERRI | CAN_MSR_WKUI | CAN_MSR_SLAKI; + /* Wakeup event.*/ +#if CAN_USE_SLEEP_MODE + if (msr & CAN_MSR_WKUI) { + canp->state = CAN_READY; + canp->can->MCR &= ~CAN_MCR_SLEEP; + osalSysLockFromISR(); + osalEventBroadcastFlagsI(&canp->wakeup_event, 0); + osalSysUnlockFromISR(); + } +#endif /* CAN_USE_SLEEP_MODE */ + /* Error event.*/ + if (msr & CAN_MSR_ERRI) { + eventflags_t flags; + uint32_t esr = canp->can->ESR; + + canp->can->ESR &= ~CAN_ESR_LEC; + flags = (eventflags_t)(esr & 7); + if ((esr & CAN_ESR_LEC) > 0) + flags |= CAN_FRAMING_ERROR; + + osalSysLockFromISR(); + /* The content of the ESR register is copied unchanged in the upper + half word of the listener flags mask.*/ + osalEventBroadcastFlagsI(&canp->error_event, flags | (eventflags_t)(esr << 16)); + osalSysUnlockFromISR(); + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_CAN_USE_CAN1 || defined(__DOXYGEN__) +#if defined(STM32_CAN1_UNIFIED_HANDLER) +/** + * @brief CAN1 unified interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN1_UNIFIED_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_tx_handler(&CAND1); + can_lld_rx0_handler(&CAND1); + can_lld_rx1_handler(&CAND1); + can_lld_sce_handler(&CAND1); + + OSAL_IRQ_EPILOGUE(); +} +#else /* !defined(STM32_CAN1_UNIFIED_HANDLER) */ + +#if !defined(STM32_CAN1_TX_HANDLER) +#error "STM32_CAN1_TX_HANDLER not defined" +#endif +#if !defined(STM32_CAN1_RX0_HANDLER) +#error "STM32_CAN1_RX0_HANDLER not defined" +#endif +#if !defined(STM32_CAN1_RX1_HANDLER) +#error "STM32_CAN1_RX1_HANDLER not defined" +#endif +#if !defined(STM32_CAN1_SCE_HANDLER) +#error "STM32_CAN1_SCE_HANDLER not defined" +#endif + +/** + * @brief CAN1 TX interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN1_TX_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_tx_handler(&CAND1); + + OSAL_IRQ_EPILOGUE(); +} + +/* + * @brief CAN1 RX0 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN1_RX0_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_rx0_handler(&CAND1); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief CAN1 RX1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN1_RX1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_rx1_handler(&CAND1); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief CAN1 SCE interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN1_SCE_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_sce_handler(&CAND1); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_CAN1_UNIFIED_HANDLER) */ +#endif /* STM32_CAN_USE_CAN1 */ + +#if STM32_CAN_USE_CAN2 || defined(__DOXYGEN__) +#if defined(STM32_CAN2_UNIFIED_HANDLER) +/** + * @brief CAN1 unified interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN2_UNIFIED_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_tx_handler(&CAND2); + can_lld_rx0_handler(&CAND2); + can_lld_rx1_handler(&CAND2); + can_lld_sce_handler(&CAND2); + + OSAL_IRQ_EPILOGUE(); +} +#else /* !defined(STM32_CAN2_UNIFIED_HANDLER) */ + +#if !defined(STM32_CAN1_TX_HANDLER) +#error "STM32_CAN1_TX_HANDLER not defined" +#endif +#if !defined(STM32_CAN1_RX0_HANDLER) +#error "STM32_CAN1_RX0_HANDLER not defined" +#endif +#if !defined(STM32_CAN1_RX1_HANDLER) +#error "STM32_CAN1_RX1_HANDLER not defined" +#endif +#if !defined(STM32_CAN1_SCE_HANDLER) +#error "STM32_CAN1_SCE_HANDLER not defined" +#endif + +/** + * @brief CAN2 TX interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN2_TX_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_tx_handler(&CAND2); + + OSAL_IRQ_EPILOGUE(); +} + +/* + * @brief CAN2 RX0 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN2_RX0_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_rx0_handler(&CAND2); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief CAN2 RX1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN2_RX1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_rx1_handler(&CAND2); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief CAN2 SCE interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_CAN2_SCE_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + can_lld_sce_handler(&CAND2); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(STM32_CAN2_UNIFIED_HANDLER) */ +#endif /* STM32_CAN_USE_CAN2 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level CAN driver initialization. + * + * @notapi + */ +void can_lld_init(void) { + +#if STM32_CAN_USE_CAN1 + /* Driver initialization.*/ + canObjectInit(&CAND1); + CAND1.can = CAN1; +#endif +#if STM32_CAN_USE_CAN2 + /* Driver initialization.*/ + canObjectInit(&CAND2); + CAND2.can = CAN2; +#endif + + /* Filters initialization.*/ +#if STM32_HAS_CAN2 + can_lld_set_filters(STM32_CAN_MAX_FILTERS / 2, 0, NULL); +#else + can_lld_set_filters(STM32_CAN_MAX_FILTERS, 0, NULL); +#endif +} + +/** + * @brief Configures and activates the CAN peripheral. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @notapi + */ +void can_lld_start(CANDriver *canp) { + + /* Clock activation.*/ +#if STM32_CAN_USE_CAN1 + if (&CAND1 == canp) { +#if defined(STM32_CAN1_UNIFIED_NUMBER) + nvicEnableVector(STM32_CAN1_UNIFIED_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY); +#else + nvicEnableVector(STM32_CAN1_TX_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY); + nvicEnableVector(STM32_CAN1_RX0_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY); + nvicEnableVector(STM32_CAN1_RX1_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY); + nvicEnableVector(STM32_CAN1_SCE_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY); +#endif + rccEnableCAN1(FALSE); + } +#endif +#if STM32_CAN_USE_CAN2 + if (&CAND2 == canp) { + + osalDbgAssert(CAND1.state != CAN_STOP, "CAN1 must be started"); + +#if defined(STM32_CAN2_UNIFIED_NUMBER) + nvicEnableVector(STM32_CAN2_UNIFIED_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY); +#else + nvicEnableVector(STM32_CAN2_TX_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY); + nvicEnableVector(STM32_CAN2_RX0_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY); + nvicEnableVector(STM32_CAN2_RX1_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY); + nvicEnableVector(STM32_CAN2_SCE_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY); +#endif + rccEnableCAN2(FALSE); + } +#endif + + /* Configuring CAN. */ + canp->can->MCR = CAN_MCR_INRQ; + while ((canp->can->MSR & CAN_MSR_INAK) == 0) + osalThreadSleepS(1); + canp->can->BTR = canp->config->btr; + canp->can->MCR = canp->config->mcr; + + /* Interrupt sources initialization.*/ + canp->can->IER = CAN_IER_TMEIE | CAN_IER_FMPIE0 | CAN_IER_FMPIE1 | + CAN_IER_WKUIE | CAN_IER_ERRIE | CAN_IER_LECIE | + CAN_IER_BOFIE | CAN_IER_EPVIE | CAN_IER_EWGIE | + CAN_IER_FOVIE0 | CAN_IER_FOVIE1; +} + +/** + * @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) { +#if STM32_CAN_USE_CAN1 + if (&CAND1 == canp) { + +#if STM32_CAN_USE_CAN2 + osalDbgAssert(CAND2.state == CAN_STOP, "CAN2 must be stopped"); +#endif + + CAN1->MCR = 0x00010002; /* Register reset value. */ + CAN1->IER = 0x00000000; /* All sources disabled. */ +#if defined(STM32_CAN1_UNIFIED_NUMBER) + nvicDisableVector(STM32_CAN1_UNIFIED_NUMBER); +#else + nvicDisableVector(STM32_CAN1_TX_NUMBER); + nvicDisableVector(STM32_CAN1_RX0_NUMBER); + nvicDisableVector(STM32_CAN1_RX1_NUMBER); + nvicDisableVector(STM32_CAN1_SCE_NUMBER); +#endif + rccDisableCAN1(FALSE); + } +#endif +#if STM32_CAN_USE_CAN2 + if (&CAND2 == canp) { + CAN2->MCR = 0x00010002; /* Register reset value. */ + CAN2->IER = 0x00000000; /* All sources disabled. */ +#if defined(STM32_CAN2_UNIFIED_NUMBER) + nvicDisableVector(STM32_CAN2_UNIFIED_NUMBER); +#else + nvicDisableVector(STM32_CAN2_TX_NUMBER); + nvicDisableVector(STM32_CAN2_RX0_NUMBER); + nvicDisableVector(STM32_CAN2_RX1_NUMBER); + nvicDisableVector(STM32_CAN2_SCE_NUMBER); +#endif + rccDisableCAN2(FALSE); + } +#endif + } +} + +/** + * @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 can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox) { + + switch (mailbox) { + case CAN_ANY_MAILBOX: + return (canp->can->TSR & CAN_TSR_TME) != 0; + case 1: + return (canp->can->TSR & CAN_TSR_TME0) != 0; + case 2: + return (canp->can->TSR & CAN_TSR_TME1) != 0; + case 3: + return (canp->can->TSR & CAN_TSR_TME2) != 0; + default: + return FALSE; + } +} + +/** + * @brief Inserts a frame into the transmit queue. + * + * @param[in] canp pointer to the @p CANDriver object + * @param[in] ctfp pointer to the CAN frame to be transmitted + * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox + * + * @notapi + */ +void can_lld_transmit(CANDriver *canp, + canmbx_t mailbox, + const CANTxFrame *ctfp) { + uint32_t tir; + CAN_TxMailBox_TypeDef *tmbp; + + /* Pointer to a free transmission mailbox.*/ + switch (mailbox) { + case CAN_ANY_MAILBOX: + tmbp = &canp->can->sTxMailBox[(canp->can->TSR & CAN_TSR_CODE) >> 24]; + break; + case 1: + tmbp = &canp->can->sTxMailBox[0]; + break; + case 2: + tmbp = &canp->can->sTxMailBox[1]; + break; + case 3: + tmbp = &canp->can->sTxMailBox[2]; + break; + default: + return; + } + + /* Preparing the message.*/ + if (ctfp->IDE) + tir = ((uint32_t)ctfp->EID << 3) | ((uint32_t)ctfp->RTR << 1) | + CAN_TI0R_IDE; + else + tir = ((uint32_t)ctfp->SID << 21) | ((uint32_t)ctfp->RTR << 1); + tmbp->TDTR = ctfp->DLC; + tmbp->TDLR = ctfp->data32[0]; + tmbp->TDHR = ctfp->data32[1]; + tmbp->TIR = tir | CAN_TI0R_TXRQ; +} + +/** + * @brief Determines whether a frame has been received. + * + * @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 can_lld_is_rx_nonempty(CANDriver *canp, canmbx_t mailbox) { + + switch (mailbox) { + case CAN_ANY_MAILBOX: + return ((canp->can->RF0R & CAN_RF0R_FMP0) != 0 || + (canp->can->RF1R & CAN_RF1R_FMP1) != 0); + case 1: + return (canp->can->RF0R & CAN_RF0R_FMP0) != 0; + case 2: + return (canp->can->RF1R & CAN_RF1R_FMP1) != 0; + default: + return FALSE; + } +} + +/** + * @brief Receives a frame from the input queue. + * + * @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) { + uint32_t rir, rdtr; + + if (mailbox == CAN_ANY_MAILBOX) { + if ((canp->can->RF0R & CAN_RF0R_FMP0) != 0) + mailbox = 1; + else if ((canp->can->RF1R & CAN_RF1R_FMP1) != 0) + mailbox = 2; + else { + /* Should not happen, do nothing.*/ + return; + } + } + switch (mailbox) { + case 1: + /* Fetches the message.*/ + rir = canp->can->sFIFOMailBox[0].RIR; + rdtr = canp->can->sFIFOMailBox[0].RDTR; + crfp->data32[0] = canp->can->sFIFOMailBox[0].RDLR; + crfp->data32[1] = canp->can->sFIFOMailBox[0].RDHR; + + /* Releases the mailbox.*/ + canp->can->RF0R = CAN_RF0R_RFOM0; + + /* If the queue is empty re-enables the interrupt in order to generate + events again.*/ + if ((canp->can->RF0R & CAN_RF0R_FMP0) == 0) + canp->can->IER |= CAN_IER_FMPIE0; + break; + case 2: + /* Fetches the message.*/ + rir = canp->can->sFIFOMailBox[1].RIR; + rdtr = canp->can->sFIFOMailBox[1].RDTR; + crfp->data32[0] = canp->can->sFIFOMailBox[1].RDLR; + crfp->data32[1] = canp->can->sFIFOMailBox[1].RDHR; + + /* Releases the mailbox.*/ + canp->can->RF1R = CAN_RF1R_RFOM1; + + /* If the queue is empty re-enables the interrupt in order to generate + events again.*/ + if ((canp->can->RF1R & CAN_RF1R_FMP1) == 0) + canp->can->IER |= CAN_IER_FMPIE1; + break; + default: + /* Should not happen, do nothing.*/ + return; + } + + /* Decodes the various fields in the RX frame.*/ + crfp->RTR = (rir & CAN_RI0R_RTR) >> 1; + crfp->IDE = (rir & CAN_RI0R_IDE) >> 2; + if (crfp->IDE) + crfp->EID = rir >> 3; + else + crfp->SID = rir >> 21; + crfp->DLC = rdtr & CAN_RDT0R_DLC; + crfp->FMI = (uint8_t)(rdtr >> 8); + crfp->TIME = (uint16_t)(rdtr >> 16); +} + +#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) { + + canp->can->MCR |= CAN_MCR_SLEEP; +} + +/** + * @brief Enforces leaving the sleep mode. + * + * @param[in] canp pointer to the @p CANDriver object + * + * @notapi + */ +void can_lld_wakeup(CANDriver *canp) { + + canp->can->MCR &= ~CAN_MCR_SLEEP; +} +#endif /* CAN_USE_SLEEP_MODE */ + +/** + * @brief Programs the filters. + * @note This is an STM32-specific API. + * + * @param[in] can2sb number of the first filter assigned to CAN2 + * @param[in] num number of entries in the filters array, if zero then + * a default filter is programmed + * @param[in] cfp pointer to the filters array, can be @p NULL if + * (num == 0) + * + * @api + */ +void canSTM32SetFilters(uint32_t can2sb, uint32_t num, const CANFilter *cfp) { + + osalDbgCheck((can2sb >= 1) && (can2sb < STM32_CAN_MAX_FILTERS) && + (num <= STM32_CAN_MAX_FILTERS)); + +#if STM32_CAN_USE_CAN1 + osalDbgAssert(CAND1.state == CAN_STOP, "invalid state"); +#endif +#if STM32_CAN_USE_CAN2 + osalDbgAssert(CAND2.state == CAN_STOP, "invalid state"); +#endif + + can_lld_set_filters(can2sb, num, cfp); +} + +#endif /* HAL_USE_CAN */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/CANv1/can_lld.h b/os/hal/ports/STM32/LLD/CANv1/can_lld.h new file mode 100644 index 000000000..6297449c6 --- /dev/null +++ b/os/hal/ports/STM32/LLD/CANv1/can_lld.h @@ -0,0 +1,365 @@ +/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file STM32/can_lld.h + * @brief STM32 CAN subsystem low level driver header. + * + * @addtogroup CAN + * @{ + */ + +#ifndef _CAN_LLD_H_ +#define _CAN_LLD_H_ + +#if HAL_USE_CAN || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/* + * The following macros from the ST header file are replaced with better + * equivalents. + */ +#undef CAN_BTR_BRP +#undef CAN_BTR_TS1 +#undef CAN_BTR_TS2 +#undef CAN_BTR_SJW + +/** + * @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 three transmit mailboxes. + */ +#define CAN_TX_MAILBOXES 3 + +/** + * @brief This implementation supports two receive mailboxes. + */ +#define CAN_RX_MAILBOXES 2 + +/** + * @name CAN registers helper macros + * @{ + */ +#define CAN_BTR_BRP(n) (n) /**< @brief BRP field macro.*/ +#define CAN_BTR_TS1(n) ((n) << 16) /**< @brief TS1 field macro.*/ +#define CAN_BTR_TS2(n) ((n) << 20) /**< @brief TS2 field macro.*/ +#define CAN_BTR_SJW(n) ((n) << 24) /**< @brief SJW field macro.*/ + +#define CAN_IDE_STD 0 /**< @brief Standard id. */ +#define CAN_IDE_EXT 1 /**< @brief Extended id. */ + +#define CAN_RTR_DATA 0 /**< @brief Data frame. */ +#define CAN_RTR_REMOTE 1 /**< @brief Remote frame. */ +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief CAN1 driver enable switch. + * @details If set to @p TRUE the support for CAN1 is included. + */ +#if !defined(STM32_CAN_USE_CAN1) || defined(__DOXYGEN__) +#define STM32_CAN_USE_CAN1 FALSE +#endif + +/** + * @brief CAN2 driver enable switch. + * @details If set to @p TRUE the support for CAN2 is included. + */ +#if !defined(STM32_CAN_USE_CAN2) || defined(__DOXYGEN__) +#define STM32_CAN_USE_CAN2 FALSE +#endif + +/** + * @brief CAN1 interrupt priority level setting. + */ +#if !defined(STM32_CAN_CAN1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_CAN_CAN1_IRQ_PRIORITY 11 +#endif +/** @} */ + +/** + * @brief CAN2 interrupt priority level setting. + */ +#if !defined(STM32_CAN_CAN2_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_CAN_CAN2_IRQ_PRIORITY 11 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if STM32_CAN_USE_CAN1 && !STM32_HAS_CAN1 +#error "CAN1 not present in the selected device" +#endif + +#if STM32_CAN_USE_CAN2 && !STM32_HAS_CAN2 +#error "CAN2 not present in the selected device" +#endif + +#if !STM32_CAN_USE_CAN1 && !STM32_CAN_USE_CAN2 +#error "CAN driver activated but no CAN peripheral assigned" +#endif + +#if !STM32_CAN_USE_CAN1 && STM32_CAN_USE_CAN2 +#error "CAN2 requires CAN1, it cannot operate independently" +#endif + +#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; + +/** + * @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 FMI; /**< @brief Filter id. */ + uint16_t TIME; /**< @brief Time stamp. */ + }; + 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. */ + }; +} CANRxFrame; + +/** + * @brief CAN filter. + * @note Refer to the STM32 reference manual for info about filters. + */ +typedef struct { + /** + * @brief Number of the filter to be programmed. + */ + uint32_t filter; + /** + * @brief Filter mode. + * @note This bit represent the CAN_FM1R register bit associated to this + * filter (0=mask mode, 1=list mode). + */ + uint32_t mode:1; + /** + * @brief Filter scale. + * @note This bit represent the CAN_FS1R register bit associated to this + * filter (0=16 bits mode, 1=32 bits mode). + */ + uint32_t scale:1; + /** + * @brief Filter mode. + * @note This bit represent the CAN_FFA1R register bit associated to this + * filter, must be set to zero in this version of the driver. + */ + uint32_t assignment:1; + /** + * @brief Filter register 1 (identifier). + */ + uint32_t register1; + /** + * @brief Filter register 2 (mask/identifier depending on mode=0/1). + */ + uint32_t register2; +} CANFilter; + +/** + * @brief Driver configuration structure. + */ +typedef struct { + /** + * @brief CAN MCR register initialization data. + * @note Some bits in this register are enforced by the driver regardless + * their status in this field. + */ + uint32_t mcr; + /** + * @brief CAN BTR register initialization data. + * @note Some bits in this register are enforced by the driver regardless + * their status in this field. + */ + uint32_t btr; +} CANConfig; + +/** + * @brief Structure representing an CAN driver. + */ +typedef struct { + /** + * @brief Driver state. + */ + canstate_t state; + /** + * @brief Current configuration data. + */ + const CANConfig *config; + /** + * @brief Transmission threads queue. + */ + threads_queue_t txqueue; + /** + * @brief Receive threads queue. + */ + threads_queue_t rxqueue; + /** + * @brief One or more frames become available. + * @note After broadcasting this event it will not be broadcasted again + * until the received frames queue has been completely emptied. It + * is not broadcasted for each received frame. It is + * responsibility of the application to empty the queue by + * repeatedly invoking @p chReceive() when listening to this event. + * This behavior minimizes the interrupt served by the system + * because CAN traffic. + * @note The flags associated to the listeners will indicate which + * receive mailboxes become non-empty. + */ + event_source_t rxfull_event; + /** + * @brief One or more transmission mailbox become available. + * @note The flags associated to the listeners will indicate which + * transmit mailboxes become empty. + * + */ + event_source_t txempty_event; + /** + * @brief A CAN bus error happened. + * @note The flags associated to the listeners will indicate the + * error(s) that have occurred. + */ + event_source_t error_event; +#if CAN_USE_SLEEP_MODE || defined (__DOXYGEN__) + /** + * @brief Entering sleep state event. + */ + event_source_t sleep_event; + /** + * @brief Exiting sleep state event. + */ + event_source_t wakeup_event; +#endif /* CAN_USE_SLEEP_MODE */ + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the CAN registers. + */ + CAN_TypeDef *can; +} CANDriver; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_CAN_USE_CAN1 && !defined(__DOXYGEN__) +extern CANDriver CAND1; +#endif + +#if STM32_CAN_USE_CAN2 && !defined(__DOXYGEN__) +extern CANDriver CAND2; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void can_lld_init(void); + void can_lld_start(CANDriver *canp); + void can_lld_stop(CANDriver *canp); + bool can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox); + void can_lld_transmit(CANDriver *canp, + canmbx_t mailbox, + const CANTxFrame *crfp); + bool 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 */ + void canSTM32SetFilters(uint32_t can2sb, uint32_t num, const CANFilter *cfp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_CAN */ + +#endif /* _CAN_LLD_H_ */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/MACv1/mac_lld.c b/os/hal/ports/STM32/LLD/MACv1/mac_lld.c new file mode 100644 index 000000000..5142df163 --- /dev/null +++ b/os/hal/ports/STM32/LLD/MACv1/mac_lld.c @@ -0,0 +1,740 @@ +/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file STM32/mac_lld.c + * @brief STM32 low level MAC driver code. + * + * @addtogroup MAC + * @{ + */ + +#include + +#include "hal.h" + +#if HAL_USE_MAC || defined(__DOXYGEN__) + +#include "mii.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define BUFFER_SIZE ((((STM32_MAC_BUFFERS_SIZE - 1) | 3) + 1) / 4) + +/* MII divider optimal value.*/ +#if (STM32_HCLK >= 150000000) +#define MACMIIDR_CR ETH_MACMIIAR_CR_Div102 +#elif (STM32_HCLK >= 100000000) +#define MACMIIDR_CR ETH_MACMIIAR_CR_Div62 +#elif (STM32_HCLK >= 60000000) +#define MACMIIDR_CR ETH_MACMIIAR_CR_Div42 +#elif (STM32_HCLK >= 35000000) +#define MACMIIDR_CR ETH_MACMIIAR_CR_Div26 +#elif (STM32_HCLK >= 20000000) +#define MACMIIDR_CR ETH_MACMIIAR_CR_Div16 +#else +#error "STM32_HCLK below minimum frequency for ETH operations (20MHz)" +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief Ethernet driver 1. + */ +MACDriver ETHD1; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +static const uint8_t default_mac_address[] = {0xAA, 0x55, 0x13, + 0x37, 0x01, 0x10}; + +static stm32_eth_rx_descriptor_t rd[STM32_MAC_RECEIVE_BUFFERS]; +static stm32_eth_tx_descriptor_t td[STM32_MAC_TRANSMIT_BUFFERS]; + +static uint32_t rb[STM32_MAC_RECEIVE_BUFFERS][BUFFER_SIZE]; +static uint32_t tb[STM32_MAC_TRANSMIT_BUFFERS][BUFFER_SIZE]; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Writes a PHY register. + * + * @param[in] macp pointer to the @p MACDriver object + * @param[in] reg register number + * @param[in] value new register value + * + * @notapi + */ +void mii_write(MACDriver *macp, uint32_t reg, uint32_t value) { + + ETH->MACMIIDR = value; + ETH->MACMIIAR = macp->phyaddr | (reg << 6) | MACMIIDR_CR | + ETH_MACMIIAR_MW | ETH_MACMIIAR_MB; + while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) != 0) + ; +} + +/** + * @brief Reads a PHY register. + * + * @param[in] macp pointer to the @p MACDriver object + * @param[in] reg register number + * + * @return The PHY register content. + * + * @notapi + */ +uint32_t mii_read(MACDriver *macp, uint32_t reg) { + + ETH->MACMIIAR = macp->phyaddr | (reg << 6) | MACMIIDR_CR | ETH_MACMIIAR_MB; + while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) != 0) + ; + return ETH->MACMIIDR; +} + +#if !defined(BOARD_PHY_ADDRESS) +/** + * @brief PHY address detection. + * + * @param[in] macp pointer to the @p MACDriver object + */ +static void mii_find_phy(MACDriver *macp) { + uint32_t i; + +#if STM32_MAC_PHY_TIMEOUT > 0 + unsigned n = STM32_MAC_PHY_TIMEOUT; + do { +#endif + for (i = 0U; i < 31U; i++) { + macp->phyaddr = i << 11U; + ETH->MACMIIDR = (i << 6U) | MACMIIDR_CR; + if ((mii_read(macp, MII_PHYSID1) == (BOARD_PHY_ID >> 16U)) && + ((mii_read(macp, MII_PHYSID2) & 0xFFF0U) == (BOARD_PHY_ID & 0xFFF0U))) { + return; + } + } +#if STM32_MAC_PHY_TIMEOUT > 0 + n--; + } while (n > 0U); +#endif + /* Wrong or defective board.*/ + osalSysHalt("MAC failure"); +} +#endif + +/** + * @brief MAC address setup. + * + * @param[in] p pointer to a six bytes buffer containing the MAC + * address + */ +static void mac_lld_set_address(const uint8_t *p) { + + /* MAC address configuration, only a single address comparator is used, + hash table not used.*/ + ETH->MACA0HR = ((uint32_t)p[5] << 8) | + ((uint32_t)p[4] << 0); + ETH->MACA0LR = ((uint32_t)p[3] << 24) | + ((uint32_t)p[2] << 16) | + ((uint32_t)p[1] << 8) | + ((uint32_t)p[0] << 0); + ETH->MACA1HR = 0x0000FFFF; + ETH->MACA1LR = 0xFFFFFFFF; + ETH->MACA2HR = 0x0000FFFF; + ETH->MACA2LR = 0xFFFFFFFF; + ETH->MACA3HR = 0x0000FFFF; + ETH->MACA3LR = 0xFFFFFFFF; + ETH->MACHTHR = 0; + ETH->MACHTLR = 0; +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +OSAL_IRQ_HANDLER(ETH_IRQHandler) { + uint32_t dmasr; + + OSAL_IRQ_PROLOGUE(); + + dmasr = ETH->DMASR; + ETH->DMASR = dmasr; /* Clear status bits.*/ + + if (dmasr & ETH_DMASR_RS) { + /* Data Received.*/ + osalSysLockFromISR(); + osalThreadDequeueAllI(ÐD1.rdqueue, MSG_RESET); +#if MAC_USE_EVENTS + osalEventBroadcastFlagsI(ÐD1.rdevent, 0); +#endif + osalSysUnlockFromISR(); + } + + if (dmasr & ETH_DMASR_TS) { + /* Data Transmitted.*/ + osalSysLockFromISR(); + osalThreadDequeueAllI(ÐD1.tdqueue, MSG_RESET); + osalSysUnlockFromISR(); + } + + OSAL_IRQ_EPILOGUE(); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level MAC initialization. + * + * @notapi + */ +void mac_lld_init(void) { + unsigned i; + + macObjectInit(ÐD1); + ETHD1.link_up = false; + + /* Descriptor tables are initialized in chained mode, note that the first + word is not initialized here but in mac_lld_start().*/ + for (i = 0; i < STM32_MAC_RECEIVE_BUFFERS; i++) { + rd[i].rdes1 = STM32_RDES1_RCH | STM32_MAC_BUFFERS_SIZE; + rd[i].rdes2 = (uint32_t)rb[i]; + rd[i].rdes3 = (uint32_t)&rd[(i + 1) % STM32_MAC_RECEIVE_BUFFERS]; + } + for (i = 0; i < STM32_MAC_TRANSMIT_BUFFERS; i++) { + td[i].tdes1 = 0; + td[i].tdes2 = (uint32_t)tb[i]; + td[i].tdes3 = (uint32_t)&td[(i + 1) % STM32_MAC_TRANSMIT_BUFFERS]; + } + + /* Selection of the RMII or MII mode based on info exported by board.h.*/ +#if defined(STM32F10X_CL) +#if defined(BOARD_PHY_RMII) + AFIO->MAPR |= AFIO_MAPR_MII_RMII_SEL; +#else + AFIO->MAPR &= ~AFIO_MAPR_MII_RMII_SEL; +#endif +#elif defined(STM32F2XX) || defined(STM32F4XX) +#if defined(BOARD_PHY_RMII) + SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL; +#else + SYSCFG->PMC &= ~SYSCFG_PMC_MII_RMII_SEL; +#endif +#else +#error "unsupported STM32 platform for MAC driver" +#endif + + /* Reset of the MAC core.*/ + rccResetETH(); + + /* MAC clocks temporary activation.*/ + rccEnableETH(false); + + /* PHY address setup.*/ +#if defined(BOARD_PHY_ADDRESS) + ETHD1.phyaddr = BOARD_PHY_ADDRESS << 11; +#else + mii_find_phy(ÐD1); +#endif + +#if defined(BOARD_PHY_RESET) + /* PHY board-specific reset procedure.*/ + BOARD_PHY_RESET(); +#else + /* PHY soft reset procedure.*/ + mii_write(ÐD1, MII_BMCR, BMCR_RESET); +#if defined(BOARD_PHY_RESET_DELAY) + chSysPolledDelayX(BOARD_PHY_RESET_DELAY); +#endif + while (mii_read(ÐD1, MII_BMCR) & BMCR_RESET) + ; +#endif + +#if STM32_MAC_ETH1_CHANGE_PHY_STATE + /* PHY in power down mode until the driver will be started.*/ + mii_write(ÐD1, MII_BMCR, mii_read(ÐD1, MII_BMCR) | BMCR_PDOWN); +#endif + + /* MAC clocks stopped again.*/ + rccDisableETH(false); +} + +/** + * @brief Configures and activates the MAC peripheral. + * + * @param[in] macp pointer to the @p MACDriver object + * + * @notapi + */ +void mac_lld_start(MACDriver *macp) { + unsigned i; + + /* Resets the state of all descriptors.*/ + for (i = 0; i < STM32_MAC_RECEIVE_BUFFERS; i++) + rd[i].rdes0 = STM32_RDES0_OWN; + macp->rxptr = (stm32_eth_rx_descriptor_t *)rd; + for (i = 0; i < STM32_MAC_TRANSMIT_BUFFERS; i++) + td[i].tdes0 = STM32_TDES0_TCH; + macp->txptr = (stm32_eth_tx_descriptor_t *)td; + + /* MAC clocks activation and commanded reset procedure.*/ + rccEnableETH(false); +#if defined(STM32_MAC_DMABMR_SR) + ETH->DMABMR |= ETH_DMABMR_SR; + while(ETH->DMABMR & ETH_DMABMR_SR) + ; +#endif + + /* ISR vector enabled.*/ + nvicEnableVector(ETH_IRQn, STM32_MAC_ETH1_IRQ_PRIORITY); + +#if STM32_MAC_ETH1_CHANGE_PHY_STATE + /* PHY in power up mode.*/ + mii_write(macp, MII_BMCR, mii_read(macp, MII_BMCR) & ~BMCR_PDOWN); +#endif + + /* MAC configuration.*/ + ETH->MACFFR = 0; + ETH->MACFCR = 0; + ETH->MACVLANTR = 0; + + /* MAC address setup.*/ + if (macp->config->mac_address == NULL) + mac_lld_set_address(default_mac_address); + else + mac_lld_set_address(macp->config->mac_address); + + /* Transmitter and receiver enabled. + Note that the complete setup of the MAC is performed when the link + status is detected.*/ +#if STM32_MAC_IP_CHECKSUM_OFFLOAD + ETH->MACCR = ETH_MACCR_IPCO | ETH_MACCR_RE | ETH_MACCR_TE; +#else + ETH->MACCR = ETH_MACCR_RE | ETH_MACCR_TE; +#endif + + /* DMA configuration: + Descriptor chains pointers.*/ + ETH->DMARDLAR = (uint32_t)rd; + ETH->DMATDLAR = (uint32_t)td; + + /* Enabling required interrupt sources.*/ + ETH->DMASR = ETH->DMASR; + ETH->DMAIER = ETH_DMAIER_NISE | ETH_DMAIER_RIE | ETH_DMAIER_TIE; + + /* DMA general settings.*/ + ETH->DMABMR = ETH_DMABMR_AAB | ETH_DMABMR_RDP_1Beat | ETH_DMABMR_PBL_1Beat; + + /* Transmit FIFO flush.*/ + ETH->DMAOMR = ETH_DMAOMR_FTF; + while (ETH->DMAOMR & ETH_DMAOMR_FTF) + ; + + /* DMA final configuration and start.*/ + ETH->DMAOMR = ETH_DMAOMR_DTCEFD | ETH_DMAOMR_RSF | ETH_DMAOMR_TSF | + ETH_DMAOMR_ST | ETH_DMAOMR_SR; +} + +/** + * @brief Deactivates the MAC peripheral. + * + * @param[in] macp pointer to the @p MACDriver object + * + * @notapi + */ +void mac_lld_stop(MACDriver *macp) { + + if (macp->state != MAC_STOP) { +#if STM32_MAC_ETH1_CHANGE_PHY_STATE + /* PHY in power down mode until the driver will be restarted.*/ + mii_write(macp, MII_BMCR, mii_read(macp, MII_BMCR) | BMCR_PDOWN); +#endif + + /* MAC and DMA stopped.*/ + ETH->MACCR = 0; + ETH->DMAOMR = 0; + ETH->DMAIER = 0; + ETH->DMASR = ETH->DMASR; + + /* MAC clocks stopped.*/ + rccDisableETH(false); + + /* ISR vector disabled.*/ + nvicDisableVector(ETH_IRQn); + } +} + +/** + * @brief Returns a transmission descriptor. + * @details One of the available transmission descriptors is locked and + * returned. + * + * @param[in] macp pointer to the @p MACDriver object + * @param[out] tdp pointer to a @p MACTransmitDescriptor structure + * @return The operation status. + * @retval MSG_OK the descriptor has been obtained. + * @retval MSG_TIMEOUT descriptor not available. + * + * @notapi + */ +msg_t mac_lld_get_transmit_descriptor(MACDriver *macp, + MACTransmitDescriptor *tdp) { + stm32_eth_tx_descriptor_t *tdes; + + if (!macp->link_up) + return MSG_TIMEOUT; + + osalSysLock(); + + /* Get Current TX descriptor.*/ + tdes = macp->txptr; + + /* Ensure that descriptor isn't owned by the Ethernet DMA or locked by + another thread.*/ + if (tdes->tdes0 & (STM32_TDES0_OWN | STM32_TDES0_LOCKED)) { + osalSysUnlock(); + return MSG_TIMEOUT; + } + + /* Marks the current descriptor as locked using a reserved bit.*/ + tdes->tdes0 |= STM32_TDES0_LOCKED; + + /* Next TX descriptor to use.*/ + macp->txptr = (stm32_eth_tx_descriptor_t *)tdes->tdes3; + + osalSysUnlock(); + + /* Set the buffer size and configuration.*/ + tdp->offset = 0; + tdp->size = STM32_MAC_BUFFERS_SIZE; + tdp->physdesc = tdes; + + return MSG_OK; +} + +/** + * @brief Releases a transmit descriptor and starts the transmission of the + * enqueued data as a single frame. + * + * @param[in] tdp the pointer to the @p MACTransmitDescriptor structure + * + * @notapi + */ +void mac_lld_release_transmit_descriptor(MACTransmitDescriptor *tdp) { + + osalDbgAssert(!(tdp->physdesc->tdes0 & STM32_TDES0_OWN), + "attempt to release descriptor already owned by DMA"); + + osalSysLock(); + + /* Unlocks the descriptor and returns it to the DMA engine.*/ + tdp->physdesc->tdes1 = tdp->offset; + tdp->physdesc->tdes0 = STM32_TDES0_CIC(STM32_MAC_IP_CHECKSUM_OFFLOAD) | + STM32_TDES0_IC | STM32_TDES0_LS | STM32_TDES0_FS | + STM32_TDES0_TCH | STM32_TDES0_OWN; + + /* If the DMA engine is stalled then a restart request is issued.*/ + if ((ETH->DMASR & ETH_DMASR_TPS) == ETH_DMASR_TPS_Suspended) { + ETH->DMASR = ETH_DMASR_TBUS; + ETH->DMATPDR = ETH_DMASR_TBUS; /* Any value is OK.*/ + } + + osalSysUnlock(); +} + +/** + * @brief Returns a receive descriptor. + * + * @param[in] macp pointer to the @p MACDriver object + * @param[out] rdp pointer to a @p MACReceiveDescriptor structure + * @return The operation status. + * @retval MSG_OK the descriptor has been obtained. + * @retval MSG_TIMEOUT descriptor not available. + * + * @notapi + */ +msg_t mac_lld_get_receive_descriptor(MACDriver *macp, + MACReceiveDescriptor *rdp) { + stm32_eth_rx_descriptor_t *rdes; + + osalSysLock(); + + /* Get Current RX descriptor.*/ + rdes = macp->rxptr; + + /* Iterates through received frames until a valid one is found, invalid + frames are discarded.*/ + while (!(rdes->rdes0 & STM32_RDES0_OWN)) { + if (!(rdes->rdes0 & (STM32_RDES0_AFM | STM32_RDES0_ES)) +#if STM32_MAC_IP_CHECKSUM_OFFLOAD + && (rdes->rdes0 & STM32_RDES0_FT) + && !(rdes->rdes0 & (STM32_RDES0_IPHCE | STM32_RDES0_PCE)) +#endif + && (rdes->rdes0 & STM32_RDES0_FS) && (rdes->rdes0 & STM32_RDES0_LS)) { + /* Found a valid one.*/ + rdp->offset = 0; + rdp->size = ((rdes->rdes0 & STM32_RDES0_FL_MASK) >> 16) - 4; + rdp->physdesc = rdes; + macp->rxptr = (stm32_eth_rx_descriptor_t *)rdes->rdes3; + + osalSysUnlock(); + return MSG_OK; + } + /* Invalid frame found, purging.*/ + rdes->rdes0 = STM32_RDES0_OWN; + rdes = (stm32_eth_rx_descriptor_t *)rdes->rdes3; + } + + /* Next descriptor to check.*/ + macp->rxptr = rdes; + + osalSysUnlock(); + return MSG_TIMEOUT; +} + +/** + * @brief Releases a receive descriptor. + * @details The descriptor and its buffer are made available for more incoming + * frames. + * + * @param[in] rdp the pointer to the @p MACReceiveDescriptor structure + * + * @notapi + */ +void mac_lld_release_receive_descriptor(MACReceiveDescriptor *rdp) { + + osalDbgAssert(!(rdp->physdesc->rdes0 & STM32_RDES0_OWN), + "attempt to release descriptor already owned by DMA"); + + osalSysLock(); + + /* Give buffer back to the Ethernet DMA.*/ + rdp->physdesc->rdes0 = STM32_RDES0_OWN; + + /* If the DMA engine is stalled then a restart request is issued.*/ + if ((ETH->DMASR & ETH_DMASR_RPS) == ETH_DMASR_RPS_Suspended) { + ETH->DMASR = ETH_DMASR_RBUS; + ETH->DMARPDR = ETH_DMASR_RBUS; /* Any value is OK.*/ + } + + osalSysUnlock(); +} + +/** + * @brief Updates and returns the link status. + * + * @param[in] macp pointer to the @p MACDriver object + * @return The link status. + * @retval true if the link is active. + * @retval false if the link is down. + * + * @notapi + */ +bool mac_lld_poll_link_status(MACDriver *macp) { + uint32_t maccr, bmsr, bmcr; + + maccr = ETH->MACCR; + + /* PHY CR and SR registers read.*/ + (void)mii_read(macp, MII_BMSR); + bmsr = mii_read(macp, MII_BMSR); + bmcr = mii_read(macp, MII_BMCR); + + /* Check on auto-negotiation mode.*/ + if (bmcr & BMCR_ANENABLE) { + uint32_t lpa; + + /* Auto-negotiation must be finished without faults and link established.*/ + if ((bmsr & (BMSR_LSTATUS | BMSR_RFAULT | BMSR_ANEGCOMPLETE)) != + (BMSR_LSTATUS | BMSR_ANEGCOMPLETE)) + return macp->link_up = false; + + /* Auto-negotiation enabled, checks the LPA register.*/ + lpa = mii_read(macp, MII_LPA); + + /* Check on link speed.*/ + if (lpa & (LPA_100HALF | LPA_100FULL | LPA_100BASE4)) + maccr |= ETH_MACCR_FES; + else + maccr &= ~ETH_MACCR_FES; + + /* Check on link mode.*/ + if (lpa & (LPA_10FULL | LPA_100FULL)) + maccr |= ETH_MACCR_DM; + else + maccr &= ~ETH_MACCR_DM; + } + else { + /* Link must be established.*/ + if (!(bmsr & BMSR_LSTATUS)) + return macp->link_up = false; + + /* Check on link speed.*/ + if (bmcr & BMCR_SPEED100) + maccr |= ETH_MACCR_FES; + else + maccr &= ~ETH_MACCR_FES; + + /* Check on link mode.*/ + if (bmcr & BMCR_FULLDPLX) + maccr |= ETH_MACCR_DM; + else + maccr &= ~ETH_MACCR_DM; + } + + /* Changes the mode in the MAC.*/ + ETH->MACCR = maccr; + + /* Returns the link status.*/ + return macp->link_up = true; +} + +/** + * @brief Writes to a transmit descriptor's stream. + * + * @param[in] tdp pointer to a @p MACTransmitDescriptor structure + * @param[in] buf pointer to the buffer containing the data to be + * written + * @param[in] size number of bytes to be written + * @return The number of bytes written into the descriptor's + * stream, this value can be less than the amount + * specified in the parameter @p size if the maximum + * frame size is reached. + * + * @notapi + */ +size_t mac_lld_write_transmit_descriptor(MACTransmitDescriptor *tdp, + uint8_t *buf, + size_t size) { + + osalDbgAssert(!(tdp->physdesc->tdes0 & STM32_TDES0_OWN), + "attempt to write descriptor already owned by DMA"); + + if (size > tdp->size - tdp->offset) + size = tdp->size - tdp->offset; + + if (size > 0) { + memcpy((uint8_t *)(tdp->physdesc->tdes2) + tdp->offset, buf, size); + tdp->offset += size; + } + return size; +} + +/** + * @brief Reads from a receive descriptor's stream. + * + * @param[in] rdp pointer to a @p MACReceiveDescriptor structure + * @param[in] buf pointer to the buffer that will receive the read data + * @param[in] size number of bytes to be read + * @return The number of bytes read from the descriptor's + * stream, this value can be less than the amount + * specified in the parameter @p size if there are + * no more bytes to read. + * + * @notapi + */ +size_t mac_lld_read_receive_descriptor(MACReceiveDescriptor *rdp, + uint8_t *buf, + size_t size) { + + osalDbgAssert(!(rdp->physdesc->rdes0 & STM32_RDES0_OWN), + "attempt to read descriptor already owned by DMA"); + + if (size > rdp->size - rdp->offset) + size = rdp->size - rdp->offset; + + if (size > 0) { + memcpy(buf, (uint8_t *)(rdp->physdesc->rdes2) + rdp->offset, size); + rdp->offset += size; + } + return size; +} + +#if MAC_USE_ZERO_COPY || defined(__DOXYGEN__) +/** + * @brief Returns a pointer to the next transmit buffer in the descriptor + * chain. + * @note The API guarantees that enough buffers can be requested to fill + * a whole frame. + * + * @param[in] tdp pointer to a @p MACTransmitDescriptor structure + * @param[in] size size of the requested buffer. Specify the frame size + * on the first call then scale the value down subtracting + * the amount of data already copied into the previous + * buffers. + * @param[out] sizep pointer to variable receiving the buffer size, it is + * zero when the last buffer has already been returned. + * Note that a returned size lower than the amount + * requested means that more buffers must be requested + * in order to fill the frame data entirely. + * @return Pointer to the returned buffer. + * @retval NULL if the buffer chain has been entirely scanned. + * + * @notapi + */ +uint8_t *mac_lld_get_next_transmit_buffer(MACTransmitDescriptor *tdp, + size_t size, + size_t *sizep) { + + if (tdp->offset == 0) { + *sizep = tdp->size; + tdp->offset = size; + return (uint8_t *)tdp->physdesc->tdes2; + } + *sizep = 0; + return NULL; +} + +/** + * @brief Returns a pointer to the next receive buffer in the descriptor + * chain. + * @note The API guarantees that the descriptor chain contains a whole + * frame. + * + * @param[in] rdp pointer to a @p MACReceiveDescriptor structure + * @param[out] sizep pointer to variable receiving the buffer size, it is + * zero when the last buffer has already been returned. + * @return Pointer to the returned buffer. + * @retval NULL if the buffer chain has been entirely scanned. + * + * @notapi + */ +const uint8_t *mac_lld_get_next_receive_buffer(MACReceiveDescriptor *rdp, + size_t *sizep) { + + if (rdp->size > 0) { + *sizep = rdp->size; + rdp->offset = rdp->size; + rdp->size = 0; + return (uint8_t *)rdp->physdesc->rdes2; + } + *sizep = 0; + return NULL; +} +#endif /* MAC_USE_ZERO_COPY */ + +#endif /* HAL_USE_MAC */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/MACv1/mac_lld.h b/os/hal/ports/STM32/LLD/MACv1/mac_lld.h new file mode 100644 index 000000000..8684192a5 --- /dev/null +++ b/os/hal/ports/STM32/LLD/MACv1/mac_lld.h @@ -0,0 +1,363 @@ +/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file STM32/mac_lld.h + * @brief STM32 low level MAC driver header. + * + * @addtogroup MAC + * @{ + */ + +#ifndef _MAC_LLD_H_ +#define _MAC_LLD_H_ + +#if HAL_USE_MAC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief This implementation supports the zero-copy mode API. + */ +#define MAC_SUPPORTS_ZERO_COPY TRUE + +/** + * @name RDES0 constants + * @{ + */ +#define STM32_RDES0_OWN 0x80000000 +#define STM32_RDES0_AFM 0x40000000 +#define STM32_RDES0_FL_MASK 0x3FFF0000 +#define STM32_RDES0_ES 0x00008000 +#define STM32_RDES0_DESERR 0x00004000 +#define STM32_RDES0_SAF 0x00002000 +#define STM32_RDES0_LE 0x00001000 +#define STM32_RDES0_OE 0x00000800 +#define STM32_RDES0_VLAN 0x00000400 +#define STM32_RDES0_FS 0x00000200 +#define STM32_RDES0_LS 0x00000100 +#define STM32_RDES0_IPHCE 0x00000080 +#define STM32_RDES0_LCO 0x00000040 +#define STM32_RDES0_FT 0x00000020 +#define STM32_RDES0_RWT 0x00000010 +#define STM32_RDES0_RE 0x00000008 +#define STM32_RDES0_DE 0x00000004 +#define STM32_RDES0_CE 0x00000002 +#define STM32_RDES0_PCE 0x00000001 +/** @} */ + +/** + * @name RDES1 constants + * @{ + */ +#define STM32_RDES1_DIC 0x80000000 +#define STM32_RDES1_RBS2_MASK 0x1FFF0000 +#define STM32_RDES1_RER 0x00008000 +#define STM32_RDES1_RCH 0x00004000 +#define STM32_RDES1_RBS1_MASK 0x00001FFF +/** @} */ + +/** + * @name TDES0 constants + * @{ + */ +#define STM32_TDES0_OWN 0x80000000 +#define STM32_TDES0_IC 0x40000000 +#define STM32_TDES0_LS 0x20000000 +#define STM32_TDES0_FS 0x10000000 +#define STM32_TDES0_DC 0x08000000 +#define STM32_TDES0_DP 0x04000000 +#define STM32_TDES0_TTSE 0x02000000 +#define STM32_TDES0_LOCKED 0x01000000 /* NOTE: Pseudo flag. */ +#define STM32_TDES0_CIC_MASK 0x00C00000 +#define STM32_TDES0_CIC(n) ((n) << 22) +#define STM32_TDES0_TER 0x00200000 +#define STM32_TDES0_TCH 0x00100000 +#define STM32_TDES0_TTSS 0x00020000 +#define STM32_TDES0_IHE 0x00010000 +#define STM32_TDES0_ES 0x00008000 +#define STM32_TDES0_JT 0x00004000 +#define STM32_TDES0_FF 0x00002000 +#define STM32_TDES0_IPE 0x00001000 +#define STM32_TDES0_LCA 0x00000800 +#define STM32_TDES0_NC 0x00000400 +#define STM32_TDES0_LCO 0x00000200 +#define STM32_TDES0_EC 0x00000100 +#define STM32_TDES0_VF 0x00000080 +#define STM32_TDES0_CC_MASK 0x00000078 +#define STM32_TDES0_ED 0x00000004 +#define STM32_TDES0_UF 0x00000002 +#define STM32_TDES0_DB 0x00000001 +/** @} */ + +/** + * @name TDES1 constants + * @{ + */ +#define STM32_TDES1_TBS2_MASK 0x1FFF0000 +#define STM32_TDES1_TBS1_MASK 0x00001FFF +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief Number of available transmit buffers. + */ +#if !defined(STM32_MAC_TRANSMIT_BUFFERS) || defined(__DOXYGEN__) +#define STM32_MAC_TRANSMIT_BUFFERS 2 +#endif + +/** + * @brief Number of available receive buffers. + */ +#if !defined(STM32_MAC_RECEIVE_BUFFERS) || defined(__DOXYGEN__) +#define STM32_MAC_RECEIVE_BUFFERS 4 +#endif + +/** + * @brief Maximum supported frame size. + */ +#if !defined(STM32_MAC_BUFFERS_SIZE) || defined(__DOXYGEN__) +#define STM32_MAC_BUFFERS_SIZE 1522 +#endif + +/** + * @brief PHY detection timeout. + * @details Timeout for PHY address detection, the scan for a PHY is performed + * the specified number of times before invoking the failure handler. + * This setting applies only if the PHY address is not explicitly + * set in the board header file using @p BOARD_PHY_ADDRESS. A zero + * value disables the timeout and a single search is performed. + */ +#if !defined(STM32_MAC_PHY_TIMEOUT) || defined(__DOXYGEN__) +#define STM32_MAC_PHY_TIMEOUT 100 +#endif + +/** + * @brief Change the PHY power state inside the driver. + */ +#if !defined(STM32_MAC_ETH1_CHANGE_PHY_STATE) || defined(__DOXYGEN__) +#define STM32_MAC_ETH1_CHANGE_PHY_STATE TRUE +#endif + +/** + * @brief ETHD1 interrupt priority level setting. + */ +#if !defined(STM32_MAC_ETH1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_MAC_ETH1_IRQ_PRIORITY 13 +#endif + +/** + * @brief IP checksum offload. + * @details The following modes are available: + * - 0 Function disabled. + * - 1 Only IP header checksum calculation and insertion are enabled. + * - 2 IP header checksum and payload checksum calculation and + * insertion are enabled, but pseudo-header checksum is not + * calculated in hardware. + * - 3 IP Header checksum and payload checksum calculation and + * insertion are enabled, and pseudo-header checksum is + * calculated in hardware. + * . + */ +#if !defined(STM32_MAC_IP_CHECKSUM_OFFLOAD) || defined(__DOXYGEN__) +#define STM32_MAC_IP_CHECKSUM_OFFLOAD 0 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if (STM32_MAC_PHY_TIMEOUT > 0) && !HAL_IMPLEMENTS_COUNTERS +#error "STM32_MAC_PHY_TIMEOUT requires the realtime counter service" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of an STM32 Ethernet receive descriptor. + */ +typedef struct { + volatile uint32_t rdes0; + volatile uint32_t rdes1; + volatile uint32_t rdes2; + volatile uint32_t rdes3; +} stm32_eth_rx_descriptor_t; + +/** + * @brief Type of an STM32 Ethernet transmit descriptor. + */ +typedef struct { + volatile uint32_t tdes0; + volatile uint32_t tdes1; + volatile uint32_t tdes2; + volatile uint32_t tdes3; +} stm32_eth_tx_descriptor_t; + +/** + * @brief Driver configuration structure. + */ +typedef struct { + /** + * @brief MAC address. + */ + uint8_t *mac_address; + /* End of the mandatory fields.*/ +} MACConfig; + +/** + * @brief Structure representing a MAC driver. + */ +struct MACDriver { + /** + * @brief Driver state. + */ + macstate_t state; + /** + * @brief Current configuration data. + */ + const MACConfig *config; + /** + * @brief Transmit semaphore. + */ + threads_queue_t tdqueue; + /** + * @brief Receive semaphore. + */ + threads_queue_t rdqueue; +#if MAC_USE_EVENTS || defined(__DOXYGEN__) + /** + * @brief Receive event. + */ + event_source_t rdevent; +#endif + /* End of the mandatory fields.*/ + /** + * @brief Link status flag. + */ + bool link_up; + /** + * @brief PHY address (pre shifted). + */ + uint32_t phyaddr; + /** + * @brief Receive next frame pointer. + */ + stm32_eth_rx_descriptor_t *rxptr; + /** + * @brief Transmit next frame pointer. + */ + stm32_eth_tx_descriptor_t *txptr; +}; + +/** + * @brief Structure representing a transmit descriptor. + */ +typedef struct { + /** + * @brief Current write offset. + */ + size_t offset; + /** + * @brief Available space size. + */ + size_t size; + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the physical descriptor. + */ + stm32_eth_tx_descriptor_t *physdesc; +} MACTransmitDescriptor; + +/** + * @brief Structure representing a receive descriptor. + */ +typedef struct { + /** + * @brief Current read offset. + */ + size_t offset; + /** + * @brief Available data size. + */ + size_t size; + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the physical descriptor. + */ + stm32_eth_rx_descriptor_t *physdesc; +} MACReceiveDescriptor; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +extern MACDriver ETHD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void mii_write(MACDriver *macp, uint32_t reg, uint32_t value); + uint32_t mii_read(MACDriver *macp, uint32_t reg); + void mac_lld_init(void); + void mac_lld_start(MACDriver *macp); + void mac_lld_stop(MACDriver *macp); + msg_t mac_lld_get_transmit_descriptor(MACDriver *macp, + MACTransmitDescriptor *tdp); + void mac_lld_release_transmit_descriptor(MACTransmitDescriptor *tdp); + msg_t mac_lld_get_receive_descriptor(MACDriver *macp, + MACReceiveDescriptor *rdp); + void mac_lld_release_receive_descriptor(MACReceiveDescriptor *rdp); + bool mac_lld_poll_link_status(MACDriver *macp); + size_t mac_lld_write_transmit_descriptor(MACTransmitDescriptor *tdp, + uint8_t *buf, + size_t size); + size_t mac_lld_read_receive_descriptor(MACReceiveDescriptor *rdp, + uint8_t *buf, + size_t size); +#if MAC_USE_ZERO_COPY + uint8_t *mac_lld_get_next_transmit_buffer(MACTransmitDescriptor *tdp, + size_t size, + size_t *sizep); + const uint8_t *mac_lld_get_next_receive_buffer(MACReceiveDescriptor *rdp, + size_t *sizep); +#endif /* MAC_USE_ZERO_COPY */ +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_MAC */ + +#endif /* _MAC_LLD_H_ */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/SDIOv1/sdc_lld.c b/os/hal/ports/STM32/LLD/SDIOv1/sdc_lld.c new file mode 100644 index 000000000..f4d23e6d2 --- /dev/null +++ b/os/hal/ports/STM32/LLD/SDIOv1/sdc_lld.c @@ -0,0 +1,873 @@ +/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file STM32/sdc_lld.c + * @brief STM32 SDC subsystem low level driver source. + * + * @addtogroup SDC + * @{ + */ + +#include + +#include "hal.h" + +#if HAL_USE_SDC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_SDC_SDIO_DMA_STREAM, \ + STM32_SDC_SDIO_DMA_CHN) + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief SDCD1 driver identifier.*/ +SDCDriver SDCD1; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +#if STM32_SDC_SDIO_UNALIGNED_SUPPORT +/** + * @brief Buffer for temporary storage during unaligned transfers. + */ +static union { + uint32_t alignment; + uint8_t buf[MMCSD_BLOCK_SIZE]; +} u; +#endif /* STM32_SDC_SDIO_UNALIGNED_SUPPORT */ + + +/** + * @brief SDIO default configuration. + */ +static const SDCConfig sdc_default_cfg = { + NULL, + SDC_MODE_4BIT +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Prepares to handle read transaction. + * @details Designed for read special registers from card. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[out] buf pointer to the read buffer + * @param[in] bytes number of bytes to read + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +static bool sdc_lld_prepare_read_bytes(SDCDriver *sdcp, + uint8_t *buf, uint32_t bytes) { + osalDbgCheck(bytes < 0x1000000); + + sdcp->sdio->DTIMER = STM32_SDC_READ_TIMEOUT; + + /* Checks for errors and waits for the card to be ready for reading.*/ + if (_sdc_wait_for_transfer_state(sdcp)) + return HAL_FAILED; + + /* Prepares the DMA channel for writing.*/ + dmaStreamSetMemory0(sdcp->dma, buf); + dmaStreamSetTransactionSize(sdcp->dma, bytes / sizeof (uint32_t)); + dmaStreamSetMode(sdcp->dma, sdcp->dmamode | STM32_DMA_CR_DIR_P2M); + dmaStreamEnable(sdcp->dma); + + /* Setting up data transfer.*/ + sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS; + sdcp->sdio->MASK = SDIO_MASK_DCRCFAILIE | + SDIO_MASK_DTIMEOUTIE | + SDIO_MASK_STBITERRIE | + SDIO_MASK_RXOVERRIE | + SDIO_MASK_DATAENDIE; + sdcp->sdio->DLEN = bytes; + + /* Transaction starts just after DTEN bit setting.*/ + sdcp->sdio->DCTRL = SDIO_DCTRL_DTDIR | + SDIO_DCTRL_DTMODE | /* multibyte data transfer */ + SDIO_DCTRL_DMAEN | + SDIO_DCTRL_DTEN; + + return HAL_SUCCESS; +} + +/** + * @brief Prepares card to handle read transaction. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to read + * @param[in] n number of blocks to read + * @param[in] resp pointer to the response buffer + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +static bool sdc_lld_prepare_read(SDCDriver *sdcp, uint32_t startblk, + uint32_t n, uint32_t *resp) { + + /* Driver handles data in 512 bytes blocks (just like HC cards). But if we + have not HC card than we must convert address from blocks to bytes.*/ + if (!(sdcp->cardmode & SDC_MODE_HIGH_CAPACITY)) + startblk *= MMCSD_BLOCK_SIZE; + + if (n > 1) { + /* Send read multiple blocks command to card.*/ + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_READ_MULTIPLE_BLOCK, + startblk, resp) || MMCSD_R1_ERROR(resp[0])) + return HAL_FAILED; + } + else{ + /* Send read single block command.*/ + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_READ_SINGLE_BLOCK, + startblk, resp) || MMCSD_R1_ERROR(resp[0])) + return HAL_FAILED; + } + + return HAL_SUCCESS; +} + +/** + * @brief Prepares card to handle write transaction. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to read + * @param[in] n number of blocks to write + * @param[in] resp pointer to the response buffer + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +static bool sdc_lld_prepare_write(SDCDriver *sdcp, uint32_t startblk, + uint32_t n, uint32_t *resp) { + + /* Driver handles data in 512 bytes blocks (just like HC cards). But if we + have not HC card than we must convert address from blocks to bytes.*/ + if (!(sdcp->cardmode & SDC_MODE_HIGH_CAPACITY)) + startblk *= MMCSD_BLOCK_SIZE; + + if (n > 1) { + /* Write multiple blocks command.*/ + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_WRITE_MULTIPLE_BLOCK, + startblk, resp) || MMCSD_R1_ERROR(resp[0])) + return HAL_FAILED; + } + else{ + /* Write single block command.*/ + if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_WRITE_BLOCK, + startblk, resp) || MMCSD_R1_ERROR(resp[0])) + return HAL_FAILED; + } + + return HAL_SUCCESS; +} + +/** + * @brief Wait end of data transaction and performs finalizations. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] n number of blocks in transaction + * @param[in] resp pointer to the response buffer + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + */ +static bool sdc_lld_wait_transaction_end(SDCDriver *sdcp, uint32_t n, + uint32_t *resp) { + + /* Note the mask is checked before going to sleep because the interrupt + may have occurred before reaching the critical zone.*/ + osalSysLock(); + if (sdcp->sdio->MASK != 0) + osalThreadSuspendS(&sdcp->thread); + if ((sdcp->sdio->STA & SDIO_STA_DATAEND) == 0) { + osalSysUnlock(); + return HAL_FAILED; + } + +#if (defined(STM32F4XX) || defined(STM32F2XX)) + /* Wait until DMA channel enabled to be sure that all data transferred.*/ + while (sdcp->dma->stream->CR & STM32_DMA_CR_EN) + ; + + /* DMA event flags must be manually cleared.*/ + dmaStreamClearInterrupt(sdcp->dma); + + sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS; + sdcp->sdio->DCTRL = 0; + osalSysUnlock(); + + /* Wait until interrupt flags to be cleared.*/ + /*while (((DMA2->LISR) >> (sdcp->dma->ishift)) & STM32_DMA_ISR_TCIF) + dmaStreamClearInterrupt(sdcp->dma);*/ +#else + /* Waits for transfer completion at DMA level, the the stream is + disabled and cleared.*/ + dmaWaitCompletion(sdcp->dma); + + sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS; + sdcp->sdio->DCTRL = 0; + osalSysUnlock(); +#endif + + /* Finalize transaction.*/ + if (n > 1) + return sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp); + + return HAL_SUCCESS; +} + +/** + * @brief Gets SDC errors. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] sta value of the STA register + * + * @notapi + */ +static void sdc_lld_collect_errors(SDCDriver *sdcp, uint32_t sta) { + uint32_t errors = SDC_NO_ERROR; + + if (sta & SDIO_STA_CCRCFAIL) + errors |= SDC_CMD_CRC_ERROR; + if (sta & SDIO_STA_DCRCFAIL) + errors |= SDC_DATA_CRC_ERROR; + if (sta & SDIO_STA_CTIMEOUT) + errors |= SDC_COMMAND_TIMEOUT; + if (sta & SDIO_STA_DTIMEOUT) + errors |= SDC_DATA_TIMEOUT; + if (sta & SDIO_STA_TXUNDERR) + errors |= SDC_TX_UNDERRUN; + if (sta & SDIO_STA_RXOVERR) + errors |= SDC_RX_OVERRUN; + if (sta & SDIO_STA_STBITERR) + errors |= SDC_STARTBIT_ERROR; + + sdcp->errors |= errors; +} + +/** + * @brief Performs clean transaction stopping in case of errors. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] n number of blocks in transaction + * @param[in] resp pointer to the response buffer + * + * @notapi + */ +static void sdc_lld_error_cleanup(SDCDriver *sdcp, + uint32_t n, + uint32_t *resp) { + uint32_t sta = sdcp->sdio->STA; + + dmaStreamClearInterrupt(sdcp->dma); + dmaStreamDisable(sdcp->dma); + sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS; + sdcp->sdio->MASK = 0; + sdcp->sdio->DCTRL = 0; + sdc_lld_collect_errors(sdcp, sta); + if (n > 1) + sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp); +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if !defined(STM32_SDIO_HANDLER) +#error "STM32_SDIO_HANDLER not defined" +#endif +/** + * @brief SDIO IRQ handler. + * @details It just wakes transaction thread. All error handling performs in + * that thread. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_SDIO_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + osalSysLockFromISR(); + + /* Disables the source but the status flags are not reset because the + read/write functions needs to check them.*/ + SDIO->MASK = 0; + + osalThreadResumeI(&SDCD1.thread, MSG_OK); + + osalSysUnlockFromISR(); + + OSAL_IRQ_EPILOGUE(); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level SDC driver initialization. + * + * @notapi + */ +void sdc_lld_init(void) { + + sdcObjectInit(&SDCD1); + SDCD1.thread = NULL; + SDCD1.dma = STM32_DMA_STREAM(STM32_SDC_SDIO_DMA_STREAM); + SDCD1.sdio = SDIO; +} + +/** + * @brief Configures and activates the SDC peripheral. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @notapi + */ +void sdc_lld_start(SDCDriver *sdcp) { + + /* Checking configuration, using a default if NULL has been passed.*/ + if (sdcp->config == NULL) { + sdcp->config = &sdc_default_cfg; + } + + sdcp->dmamode = STM32_DMA_CR_CHSEL(DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_SDC_SDIO_DMA_PRIORITY) | + STM32_DMA_CR_PSIZE_WORD | + STM32_DMA_CR_MSIZE_WORD | + STM32_DMA_CR_MINC; + +#if (defined(STM32F4XX) || defined(STM32F2XX)) + sdcp->dmamode |= STM32_DMA_CR_PFCTRL | + STM32_DMA_CR_PBURST_INCR4 | + STM32_DMA_CR_MBURST_INCR4; +#endif + + if (sdcp->state == BLK_STOP) { + /* Note, the DMA must be enabled before the IRQs.*/ + bool b; + b = dmaStreamAllocate(sdcp->dma, STM32_SDC_SDIO_IRQ_PRIORITY, NULL, NULL); + osalDbgAssert(!b, "stream already allocated"); + dmaStreamSetPeripheral(sdcp->dma, &sdcp->sdio->FIFO); +#if (defined(STM32F4XX) || defined(STM32F2XX)) + dmaStreamSetFIFO(sdcp->dma, STM32_DMA_FCR_DMDIS | STM32_DMA_FCR_FTH_FULL); +#endif + nvicEnableVector(STM32_SDIO_NUMBER, STM32_SDC_SDIO_IRQ_PRIORITY); + rccEnableSDIO(FALSE); + } + + /* Configuration, card clock is initially stopped.*/ + sdcp->sdio->POWER = 0; + sdcp->sdio->CLKCR = 0; + sdcp->sdio->DCTRL = 0; + sdcp->sdio->DTIMER = 0; +} + +/** + * @brief Deactivates the SDC peripheral. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @notapi + */ +void sdc_lld_stop(SDCDriver *sdcp) { + + if (sdcp->state != BLK_STOP) { + + /* SDIO deactivation.*/ + sdcp->sdio->POWER = 0; + sdcp->sdio->CLKCR = 0; + sdcp->sdio->DCTRL = 0; + sdcp->sdio->DTIMER = 0; + + /* Clock deactivation.*/ + nvicDisableVector(STM32_SDIO_NUMBER); + dmaStreamRelease(sdcp->dma); + rccDisableSDIO(FALSE); + } +} + +/** + * @brief Starts the SDIO clock and sets it to init mode (400kHz or less). + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @notapi + */ +void sdc_lld_start_clk(SDCDriver *sdcp) { + + /* Initial clock setting: 400kHz, 1bit mode.*/ + sdcp->sdio->CLKCR = STM32_SDIO_DIV_LS; + sdcp->sdio->POWER |= SDIO_POWER_PWRCTRL_0 | SDIO_POWER_PWRCTRL_1; + sdcp->sdio->CLKCR |= SDIO_CLKCR_CLKEN; + + /* Clock activation delay.*/ + osalThreadSleep(MS2ST(STM32_SDC_CLOCK_ACTIVATION_DELAY)); +} + +/** + * @brief Sets the SDIO clock to data mode (25MHz or less). + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] clk the clock mode + * + * @notapi + */ +void sdc_lld_set_data_clk(SDCDriver *sdcp, sdcbusclk_t clk) { +#if 0 + if (SDC_CLK_50MHz == clk) { + sdcp->sdio->CLKCR = (sdcp->sdio->CLKCR & 0xFFFFFF00U) | STM32_SDIO_DIV_HS + | SDIO_CLKCR_BYPASS; + } + else + sdcp->sdio->CLKCR = (sdcp->sdio->CLKCR & 0xFFFFFF00U) | STM32_SDIO_DIV_HS; +#else + (void)clk; + + sdcp->sdio->CLKCR = (sdcp->sdio->CLKCR & 0xFFFFFF00U) | STM32_SDIO_DIV_HS; +#endif +} + +/** + * @brief Stops the SDIO clock. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @notapi + */ +void sdc_lld_stop_clk(SDCDriver *sdcp) { + + sdcp->sdio->CLKCR = 0; + sdcp->sdio->POWER = 0; +} + +/** + * @brief Switches the bus to 4 bits mode. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] mode bus mode + * + * @notapi + */ +void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode) { + uint32_t clk = sdcp->sdio->CLKCR & ~SDIO_CLKCR_WIDBUS; + + switch (mode) { + case SDC_MODE_1BIT: + sdcp->sdio->CLKCR = clk; + break; + case SDC_MODE_4BIT: + sdcp->sdio->CLKCR = clk | SDIO_CLKCR_WIDBUS_0; + break; + case SDC_MODE_8BIT: + sdcp->sdio->CLKCR = clk | SDIO_CLKCR_WIDBUS_1; + break; + } +} + +/** + * @brief Sends an SDIO command with no response expected. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] cmd card command + * @param[in] arg command argument + * + * @notapi + */ +void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg) { + + sdcp->sdio->ARG = arg; + sdcp->sdio->CMD = (uint32_t)cmd | SDIO_CMD_CPSMEN; + while ((sdcp->sdio->STA & SDIO_STA_CMDSENT) == 0) + ; + sdcp->sdio->ICR = SDIO_ICR_CMDSENTC; +} + +/** + * @brief Sends an SDIO command with a short response expected. + * @note The CRC is not verified. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] cmd card command + * @param[in] arg command argument + * @param[out] resp pointer to the response buffer (one word) + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp) { + uint32_t sta; + + sdcp->sdio->ARG = arg; + sdcp->sdio->CMD = (uint32_t)cmd | SDIO_CMD_WAITRESP_0 | SDIO_CMD_CPSMEN; + while (((sta = sdcp->sdio->STA) & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | + SDIO_STA_CCRCFAIL)) == 0) + ; + sdcp->sdio->ICR = sta & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | + SDIO_STA_CCRCFAIL); + if ((sta & (SDIO_STA_CTIMEOUT)) != 0) { + sdc_lld_collect_errors(sdcp, sta); + return HAL_FAILED; + } + *resp = sdcp->sdio->RESP1; + return HAL_SUCCESS; +} + +/** + * @brief Sends an SDIO command with a short response expected and CRC. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] cmd card command + * @param[in] arg command argument + * @param[out] resp pointer to the response buffer (one word) + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_send_cmd_short_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp) { + uint32_t sta; + + sdcp->sdio->ARG = arg; + sdcp->sdio->CMD = (uint32_t)cmd | SDIO_CMD_WAITRESP_0 | SDIO_CMD_CPSMEN; + while (((sta = sdcp->sdio->STA) & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | + SDIO_STA_CCRCFAIL)) == 0) + ; + sdcp->sdio->ICR = sta & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | SDIO_STA_CCRCFAIL); + if ((sta & (SDIO_STA_CTIMEOUT | SDIO_STA_CCRCFAIL)) != 0) { + sdc_lld_collect_errors(sdcp, sta); + return HAL_FAILED; + } + *resp = sdcp->sdio->RESP1; + return HAL_SUCCESS; +} + +/** + * @brief Sends an SDIO command with a long response expected and CRC. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] cmd card command + * @param[in] arg command argument + * @param[out] resp pointer to the response buffer (four words) + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_send_cmd_long_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp) { + uint32_t sta; + + (void)sdcp; + + sdcp->sdio->ARG = arg; + sdcp->sdio->CMD = (uint32_t)cmd | SDIO_CMD_WAITRESP_0 | SDIO_CMD_WAITRESP_1 | + SDIO_CMD_CPSMEN; + while (((sta = sdcp->sdio->STA) & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | + SDIO_STA_CCRCFAIL)) == 0) + ; + sdcp->sdio->ICR = sta & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | + SDIO_STA_CCRCFAIL); + if ((sta & (STM32_SDIO_STA_ERROR_MASK)) != 0) { + sdc_lld_collect_errors(sdcp, sta); + return HAL_FAILED; + } + /* Save bytes in reverse order because MSB in response comes first.*/ + *resp++ = sdcp->sdio->RESP4; + *resp++ = sdcp->sdio->RESP3; + *resp++ = sdcp->sdio->RESP2; + *resp = sdcp->sdio->RESP1; + return HAL_SUCCESS; +} + +/** + * @brief Reads special registers using data bus. + * @details Needs only during card detection procedure. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[out] buf pointer to the read buffer + * @param[in] bytes number of bytes to read + * @param[in] cmd card command + * @param[in] arg argument for command + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_read_special(SDCDriver *sdcp, uint8_t *buf, size_t bytes, + uint8_t cmd, uint32_t arg) { + uint32_t resp[1]; + + if(sdc_lld_prepare_read_bytes(sdcp, buf, bytes)) + goto error; + + if (sdc_lld_send_cmd_short_crc(sdcp, cmd, arg, resp) + || MMCSD_R1_ERROR(resp[0])) + goto error; + + if (sdc_lld_wait_transaction_end(sdcp, 1, resp)) + goto error; + + return HAL_SUCCESS; + +error: + sdc_lld_error_cleanup(sdcp, 1, resp); + return HAL_FAILED; +} + +/** + * @brief Reads one or more blocks. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to read + * @param[out] buf pointer to the read buffer + * @param[in] blocks number of blocks to read + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_read_aligned(SDCDriver *sdcp, uint32_t startblk, + uint8_t *buf, uint32_t blocks) { + uint32_t resp[1]; + + osalDbgCheck(blocks < 0x1000000 / MMCSD_BLOCK_SIZE); + + sdcp->sdio->DTIMER = STM32_SDC_READ_TIMEOUT; + + /* Checks for errors and waits for the card to be ready for reading.*/ + if (_sdc_wait_for_transfer_state(sdcp)) + return HAL_FAILED; + + /* Prepares the DMA channel for writing.*/ + dmaStreamSetMemory0(sdcp->dma, buf); + dmaStreamSetTransactionSize(sdcp->dma, + (blocks * MMCSD_BLOCK_SIZE) / sizeof (uint32_t)); + dmaStreamSetMode(sdcp->dma, sdcp->dmamode | STM32_DMA_CR_DIR_P2M); + dmaStreamEnable(sdcp->dma); + + /* Setting up data transfer.*/ + sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS; + sdcp->sdio->MASK = SDIO_MASK_DCRCFAILIE | + SDIO_MASK_DTIMEOUTIE | + SDIO_MASK_STBITERRIE | + SDIO_MASK_RXOVERRIE | + SDIO_MASK_DATAENDIE; + sdcp->sdio->DLEN = blocks * MMCSD_BLOCK_SIZE; + + /* Transaction starts just after DTEN bit setting.*/ + sdcp->sdio->DCTRL = SDIO_DCTRL_DTDIR | + SDIO_DCTRL_DBLOCKSIZE_3 | + SDIO_DCTRL_DBLOCKSIZE_0 | + SDIO_DCTRL_DMAEN | + SDIO_DCTRL_DTEN; + + if (sdc_lld_prepare_read(sdcp, startblk, blocks, resp) == TRUE) + goto error; + + if (sdc_lld_wait_transaction_end(sdcp, blocks, resp) == TRUE) + goto error; + + return HAL_SUCCESS; + +error: + sdc_lld_error_cleanup(sdcp, blocks, resp); + return HAL_FAILED; +} + +/** + * @brief Writes one or more blocks. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to write + * @param[out] buf pointer to the write buffer + * @param[in] n number of blocks to write + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_write_aligned(SDCDriver *sdcp, uint32_t startblk, + const uint8_t *buf, uint32_t blocks) { + uint32_t resp[1]; + + osalDbgCheck(blocks < 0x1000000 / MMCSD_BLOCK_SIZE); + + sdcp->sdio->DTIMER = STM32_SDC_WRITE_TIMEOUT; + + /* Checks for errors and waits for the card to be ready for writing.*/ + if (_sdc_wait_for_transfer_state(sdcp)) + return HAL_FAILED; + + /* Prepares the DMA channel for writing.*/ + dmaStreamSetMemory0(sdcp->dma, buf); + dmaStreamSetTransactionSize(sdcp->dma, + (blocks * MMCSD_BLOCK_SIZE) / sizeof (uint32_t)); + dmaStreamSetMode(sdcp->dma, sdcp->dmamode | STM32_DMA_CR_DIR_M2P); + dmaStreamEnable(sdcp->dma); + + /* Setting up data transfer.*/ + sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS; + sdcp->sdio->MASK = SDIO_MASK_DCRCFAILIE | + SDIO_MASK_DTIMEOUTIE | + SDIO_MASK_STBITERRIE | + SDIO_MASK_TXUNDERRIE | + SDIO_MASK_DATAENDIE; + sdcp->sdio->DLEN = blocks * MMCSD_BLOCK_SIZE; + + /* Talk to card what we want from it.*/ + if (sdc_lld_prepare_write(sdcp, startblk, blocks, resp) == TRUE) + goto error; + + /* Transaction starts just after DTEN bit setting.*/ + sdcp->sdio->DCTRL = SDIO_DCTRL_DBLOCKSIZE_3 | + SDIO_DCTRL_DBLOCKSIZE_0 | + SDIO_DCTRL_DMAEN | + SDIO_DCTRL_DTEN; + + if (sdc_lld_wait_transaction_end(sdcp, blocks, resp) == TRUE) + goto error; + + return HAL_SUCCESS; + +error: + sdc_lld_error_cleanup(sdcp, blocks, resp); + return HAL_FAILED; +} + +/** + * @brief Reads one or more blocks. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to read + * @param[out] buf pointer to the read buffer + * @param[in] blocks number of blocks to read + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_read(SDCDriver *sdcp, uint32_t startblk, + uint8_t *buf, uint32_t blocks) { + +#if STM32_SDC_SDIO_UNALIGNED_SUPPORT + if (((unsigned)buf & 3) != 0) { + uint32_t i; + for (i = 0; i < blocks; i++) { + if (sdc_lld_read_aligned(sdcp, startblk, u.buf, 1)) + return HAL_FAILED; + memcpy(buf, u.buf, MMCSD_BLOCK_SIZE); + buf += MMCSD_BLOCK_SIZE; + startblk++; + } + return HAL_SUCCESS; + } +#endif /* STM32_SDC_SDIO_UNALIGNED_SUPPORT */ + return sdc_lld_read_aligned(sdcp, startblk, buf, blocks); +} + +/** + * @brief Writes one or more blocks. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] startblk first block to write + * @param[out] buf pointer to the write buffer + * @param[in] blocks number of blocks to write + * + * @return The operation status. + * @retval HAL_SUCCESS operation succeeded. + * @retval HAL_FAILED operation failed. + * + * @notapi + */ +bool sdc_lld_write(SDCDriver *sdcp, uint32_t startblk, + const uint8_t *buf, uint32_t blocks) { + +#if STM32_SDC_SDIO_UNALIGNED_SUPPORT + if (((unsigned)buf & 3) != 0) { + uint32_t i; + for (i = 0; i < blocks; i++) { + memcpy(u.buf, buf, MMCSD_BLOCK_SIZE); + buf += MMCSD_BLOCK_SIZE; + if (sdc_lld_write_aligned(sdcp, startblk, u.buf, 1)) + return HAL_FAILED; + startblk++; + } + return HAL_SUCCESS; + } +#endif /* STM32_SDC_SDIO_UNALIGNED_SUPPORT */ + return sdc_lld_write_aligned(sdcp, startblk, buf, blocks); +} + +/** + * @brief Waits for card idle condition. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * + * @return The operation status. + * @retval HAL_SUCCESS the operation succeeded. + * @retval HAL_FAILED the operation failed. + * + * @api + */ +bool sdc_lld_sync(SDCDriver *sdcp) { + + /* TODO: Implement.*/ + (void)sdcp; + return HAL_SUCCESS; +} + +#endif /* HAL_USE_SDC */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/SDIOv1/sdc_lld.h b/os/hal/ports/STM32/LLD/SDIOv1/sdc_lld.h new file mode 100644 index 000000000..ae258e5f1 --- /dev/null +++ b/os/hal/ports/STM32/LLD/SDIOv1/sdc_lld.h @@ -0,0 +1,330 @@ +/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file STM32/sdc_lld.h + * @brief STM32 SDC subsystem low level driver header. + * + * @addtogroup SDC + * @{ + */ + +#ifndef _SDC_LLD_H_ +#define _SDC_LLD_H_ + +#if HAL_USE_SDC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Value to clear all interrupts flag at once. + */ +#define STM32_SDIO_ICR_ALL_FLAGS (SDIO_ICR_CCRCFAILC | SDIO_ICR_DCRCFAILC | \ + SDIO_ICR_CTIMEOUTC | SDIO_ICR_DTIMEOUTC | \ + SDIO_ICR_TXUNDERRC | SDIO_ICR_RXOVERRC | \ + SDIO_ICR_CMDRENDC | SDIO_ICR_CMDSENTC | \ + SDIO_ICR_DATAENDC | SDIO_ICR_STBITERRC | \ + SDIO_ICR_DBCKENDC | SDIO_ICR_SDIOITC | \ + SDIO_ICR_CEATAENDC) + +/** + * @brief Mask of error flags in STA register. + */ +#define STM32_SDIO_STA_ERROR_MASK (SDIO_STA_CCRCFAIL | SDIO_STA_DCRCFAIL | \ + SDIO_STA_CTIMEOUT | SDIO_STA_DTIMEOUT | \ + SDIO_STA_TXUNDERR | SDIO_STA_RXOVERR) + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief SDIO DMA priority (0..3|lowest..highest). + */ +#if !defined(STM32_SDC_SDIO_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SDC_SDIO_DMA_PRIORITY 3 +#endif + +/** + * @brief SDIO interrupt priority level setting. + */ +#if !defined(STM32_SDC_SDIO_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_SDC_SDIO_IRQ_PRIORITY 9 +#endif + +/** + * @brief Write timeout in milliseconds. + */ +#if !defined(STM32_SDC_WRITE_TIMEOUT_MS) || defined(__DOXYGEN__) +#define STM32_SDC_WRITE_TIMEOUT_MS 250 +#endif + +/** + * @brief Read timeout in milliseconds. + */ +#if !defined(STM32_SDC_READ_TIMEOUT_MS) || defined(__DOXYGEN__) +#define STM32_SDC_READ_TIMEOUT_MS 25 +#endif + +/** + * @brief Card clock activation delay in milliseconds. + */ +#if !defined(STM32_SDC_CLOCK_ACTIVATION_DELAY) || defined(__DOXYGEN__) +#define STM32_SDC_CLOCK_ACTIVATION_DELAY 10 +#endif + +/** + * @brief Support for unaligned transfers. + * @note Unaligned transfers are much slower. + */ +#if !defined(STM32_SDC_SDIO_UNALIGNED_SUPPORT) || defined(__DOXYGEN__) +#define STM32_SDC_SDIO_UNALIGNED_SUPPORT TRUE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !STM32_HAS_SDIO +#error "SDIO not present in the selected device" +#endif + +#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SDC_SDIO_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to SDIO" +#endif + +#if !STM32_DMA_IS_VALID_PRIORITY(STM32_SDC_SDIO_DMA_PRIORITY) +#error "Invalid DMA priority assigned to SDIO" +#endif + +/* The following checks are only required when there is a DMA able to + reassign streams to different channels.*/ +#if STM32_ADVANCED_DMA +/* Check on the presence of the DMA streams settings in mcuconf.h.*/ +#if !defined(STM32_SDC_SDIO_DMA_STREAM) +#error "SDIO DMA streams not defined" +#endif + +/* Check on the validity of the assigned DMA channels.*/ +#if !STM32_DMA_IS_VALID_ID(STM32_SDC_SDIO_DMA_STREAM, STM32_SDC_SDIO_DMA_MSK) +#error "invalid DMA stream associated to SDIO" +#endif +#endif /* STM32_ADVANCED_DMA */ + +#if !defined(STM32_DMA_REQUIRED) +#define STM32_DMA_REQUIRED +#endif + +/* + * SDIO clock divider. + */ +#if (defined(STM32F4XX) || defined(STM32F2XX)) +#define STM32_SDIO_DIV_HS 0 +#define STM32_SDIO_DIV_LS 120 + +#elif STM32_HCLK > 48000000 +#define STM32_SDIO_DIV_HS 1 +#define STM32_SDIO_DIV_LS 178 +#else + +#define STM32_SDIO_DIV_HS 0 +#define STM32_SDIO_DIV_LS 118 +#endif + +/** + * @brief SDIO data timeouts in SDIO clock cycles. + */ +#if (defined(STM32F4XX) || defined(STM32F2XX)) +#if !STM32_CLOCK48_REQUIRED +#error "SDIO requires STM32_CLOCK48_REQUIRED to be enabled" +#endif + +#if STM32_PLL48CLK != 48000000 +#error "invalid STM32_PLL48CLK clock value" +#endif + +#define STM32_SDC_WRITE_TIMEOUT \ + (((STM32_PLL48CLK / (STM32_SDIO_DIV_HS + 2)) / 1000) * \ + STM32_SDC_WRITE_TIMEOUT_MS) +#define STM32_SDC_READ_TIMEOUT \ + (((STM32_PLL48CLK / (STM32_SDIO_DIV_HS + 2)) / 1000) * \ + STM32_SDC_READ_TIMEOUT_MS) + +#else /* !(defined(STM32F4XX) || defined(STM32F2XX)) */ + +#define STM32_SDC_WRITE_TIMEOUT \ + (((STM32_HCLK / (STM32_SDIO_DIV_HS + 2)) / 1000) * \ + STM32_SDC_WRITE_TIMEOUT_MS) +#define STM32_SDC_READ_TIMEOUT \ + (((STM32_HCLK / (STM32_SDIO_DIV_HS + 2)) / 1000) * \ + STM32_SDC_READ_TIMEOUT_MS) + +#endif /* !(defined(STM32F4XX) || defined(STM32F2XX)) */ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of card flags. + */ +typedef uint32_t sdcmode_t; + +/** + * @brief SDC Driver condition flags type. + */ +typedef uint32_t sdcflags_t; + +/** + * @brief Type of a structure representing an SDC driver. + */ +typedef struct SDCDriver SDCDriver; + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + /** + * @brief Working area for memory consuming operations. + * @note Buffer must be word aligned and big enough to store 512 bytes. + * @note It is mandatory for detecting MMC cards bigger than 2GB else it + * can be @p NULL. SD cards do NOT need it. + * @note Memory pointed by this buffer is only used by @p sdcConnect(), + * afterward it can be reused for other purposes. + */ + uint8_t *scratchpad; + /** + * @brief Bus width. + */ + sdcbusmode_t bus_width; + /* End of the mandatory fields.*/ +} SDCConfig; + +/** + * @brief @p SDCDriver specific methods. + */ +#define _sdc_driver_methods \ + _mmcsd_block_device_methods + +/** + * @extends MMCSDBlockDeviceVMT + * + * @brief @p SDCDriver virtual methods table. + */ +struct SDCDriverVMT { + _sdc_driver_methods +}; + +/** + * @brief Structure representing an SDC driver. + */ +struct SDCDriver { + /** + * @brief Virtual Methods Table. + */ + const struct SDCDriverVMT *vmt; + _mmcsd_block_device_data + /** + * @brief Current configuration data. + */ + const SDCConfig *config; + /** + * @brief Various flags regarding the mounted card. + */ + sdcmode_t cardmode; + /** + * @brief Errors flags. + */ + sdcflags_t errors; + /** + * @brief Card RCA. + */ + uint32_t rca; + /* End of the mandatory fields.*/ + /** + * @brief Thread waiting for I/O completion IRQ. + */ + thread_reference_t thread; + /** + * @brief DMA mode bit mask. + */ + uint32_t dmamode; + /** + * @brief Transmit DMA channel. + */ + const stm32_dma_stream_t *dma; + /** + * @brief Pointer to the SDIO registers block. + * @note Needed for debugging aid. + */ + SDIO_TypeDef *sdio; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +extern SDCDriver SDCD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void sdc_lld_init(void); + void sdc_lld_start(SDCDriver *sdcp); + void sdc_lld_stop(SDCDriver *sdcp); + void sdc_lld_start_clk(SDCDriver *sdcp); + void sdc_lld_set_data_clk(SDCDriver *sdcp, sdcbusclk_t clk); + void sdc_lld_stop_clk(SDCDriver *sdcp); + void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode); + void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg); + bool sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp); + bool sdc_lld_send_cmd_short_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp); + bool sdc_lld_send_cmd_long_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, + uint32_t *resp); + bool sdc_lld_read_special(SDCDriver *sdcp, uint8_t *buf, size_t bytes, + uint8_t cmd, uint32_t argument); + bool sdc_lld_read(SDCDriver *sdcp, uint32_t startblk, + uint8_t *buf, uint32_t blocks); + bool sdc_lld_write(SDCDriver *sdcp, uint32_t startblk, + const uint8_t *buf, uint32_t blocks); + bool sdc_lld_sync(SDCDriver *sdcp); + bool sdc_lld_is_card_inserted(SDCDriver *sdcp); + bool sdc_lld_is_write_protected(SDCDriver *sdcp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_SDC */ + +#endif /* _SDC_LLD_H_ */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/can_lld.c b/os/hal/ports/STM32/LLD/can_lld.c deleted file mode 100644 index 7bca76d8e..000000000 --- a/os/hal/ports/STM32/LLD/can_lld.c +++ /dev/null @@ -1,796 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/** - * @file STM32/can_lld.c - * @brief STM32 CAN subsystem low level driver source. - * - * @addtogroup CAN - * @{ - */ - -#include "hal.h" - -#if HAL_USE_CAN || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/* - * Addressing differences in the headers, they seem unable to agree on names. - */ -#if STM32_CAN_USE_CAN1 -#if !defined(CAN1) -#define CAN1 CAN -#endif -#endif - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/** @brief CAN1 driver identifier.*/ -#if STM32_CAN_USE_CAN1 || defined(__DOXYGEN__) -CANDriver CAND1; -#endif - -/** @brief CAN2 driver identifier.*/ -#if STM32_CAN_USE_CAN2 || defined(__DOXYGEN__) -CANDriver CAND2; -#endif - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/** - * @brief Programs the filters. - * - * @param[in] can2sb number of the first filter assigned to CAN2 - * @param[in] num number of entries in the filters array, if zero then - * a default filter is programmed - * @param[in] cfp pointer to the filters array, can be @p NULL if - * (num == 0) - * - * @notapi - */ -static void can_lld_set_filters(uint32_t can2sb, - uint32_t num, - const CANFilter *cfp) { - - /* Temporarily enabling CAN1 clock.*/ - rccEnableCAN1(FALSE); - - /* Filters initialization.*/ - CAN1->FMR = (CAN1->FMR & 0xFFFF0000) | (can2sb << 8) | CAN_FMR_FINIT; - if (num > 0) { - uint32_t i, fmask; - - /* All filters cleared.*/ - CAN1->FA1R = 0; - CAN1->FM1R = 0; - CAN1->FS1R = 0; - CAN1->FFA1R = 0; - for (i = 0; i < STM32_CAN_MAX_FILTERS; i++) { - CAN1->sFilterRegister[i].FR1 = 0; - CAN1->sFilterRegister[i].FR2 = 0; - } - - /* Scanning the filters array.*/ - for (i = 0; i < num; i++) { - fmask = 1 << cfp->filter; - if (cfp->mode) - CAN1->FM1R |= fmask; - if (cfp->scale) - CAN1->FS1R |= fmask; - if (cfp->assignment) - CAN1->FFA1R |= fmask; - CAN1->sFilterRegister[cfp->filter].FR1 = cfp->register1; - CAN1->sFilterRegister[cfp->filter].FR2 = cfp->register2; - CAN1->FA1R |= fmask; - cfp++; - } - } - else { - /* Setting up a single default filter that enables everything for both - CANs.*/ - CAN1->sFilterRegister[0].FR1 = 0; - CAN1->sFilterRegister[0].FR2 = 0; -#if STM32_HAS_CAN2 - CAN1->sFilterRegister[can2sb].FR1 = 0; - CAN1->sFilterRegister[can2sb].FR2 = 0; -#endif - CAN1->FM1R = 0; - CAN1->FFA1R = 0; -#if STM32_HAS_CAN2 - CAN1->FS1R = 1 | (1 << can2sb); - CAN1->FA1R = 1 | (1 << can2sb); -#else - CAN1->FS1R = 1; - CAN1->FA1R = 1; -#endif - } - CAN1->FMR &= ~CAN_FMR_FINIT; - - /* Clock disabled, it will be enabled again in can_lld_start().*/ - rccDisableCAN1(FALSE); -} - -/** - * @brief Common TX ISR handler. - * - * @param[in] canp pointer to the @p CANDriver object - * - * @notapi - */ -static void can_lld_tx_handler(CANDriver *canp) { - - /* No more events until a message is transmitted.*/ - canp->can->TSR = CAN_TSR_RQCP0 | CAN_TSR_RQCP1 | CAN_TSR_RQCP2; - osalSysLockFromISR(); - osalThreadDequeueAllI(&canp->txqueue, MSG_OK); - osalEventBroadcastFlagsI(&canp->txempty_event, CAN_MAILBOX_TO_MASK(1)); - osalSysUnlockFromISR(); -} - -/** - * @brief Common RX0 ISR handler. - * - * @param[in] canp pointer to the @p CANDriver object - * - * @notapi - */ -static void can_lld_rx0_handler(CANDriver *canp) { - uint32_t rf0r; - - rf0r = canp->can->RF0R; - if ((rf0r & CAN_RF0R_FMP0) > 0) { - /* No more receive events until the queue 0 has been emptied.*/ - canp->can->IER &= ~CAN_IER_FMPIE0; - osalSysLockFromISR(); - osalThreadDequeueAllI(&canp->rxqueue, MSG_OK); - osalEventBroadcastFlagsI(&canp->rxfull_event, CAN_MAILBOX_TO_MASK(1)); - osalSysUnlockFromISR(); - } - if ((rf0r & CAN_RF0R_FOVR0) > 0) { - /* Overflow events handling.*/ - canp->can->RF0R = CAN_RF0R_FOVR0; - osalSysLockFromISR(); - osalEventBroadcastFlagsI(&canp->error_event, CAN_OVERFLOW_ERROR); - osalSysUnlockFromISR(); - } -} - -/** - * @brief Common RX1 ISR handler. - * - * @param[in] canp pointer to the @p CANDriver object - * - * @notapi - */ -static void can_lld_rx1_handler(CANDriver *canp) { - uint32_t rf1r; - - rf1r = canp->can->RF1R; - if ((rf1r & CAN_RF1R_FMP1) > 0) { - /* No more receive events until the queue 0 has been emptied.*/ - canp->can->IER &= ~CAN_IER_FMPIE1; - osalSysLockFromISR(); - osalThreadDequeueAllI(&canp->rxqueue, MSG_OK); - osalEventBroadcastFlagsI(&canp->rxfull_event, CAN_MAILBOX_TO_MASK(2)); - osalSysUnlockFromISR(); - } - if ((rf1r & CAN_RF1R_FOVR1) > 0) { - /* Overflow events handling.*/ - canp->can->RF1R = CAN_RF1R_FOVR1; - osalSysLockFromISR(); - osalEventBroadcastFlagsI(&canp->error_event, CAN_OVERFLOW_ERROR); - osalSysUnlockFromISR(); - } -} - -/** - * @brief Common SCE ISR handler. - * - * @param[in] canp pointer to the @p CANDriver object - * - * @notapi - */ -static void can_lld_sce_handler(CANDriver *canp) { - uint32_t msr; - - msr = canp->can->MSR; - canp->can->MSR = CAN_MSR_ERRI | CAN_MSR_WKUI | CAN_MSR_SLAKI; - /* Wakeup event.*/ -#if CAN_USE_SLEEP_MODE - if (msr & CAN_MSR_WKUI) { - canp->state = CAN_READY; - canp->can->MCR &= ~CAN_MCR_SLEEP; - osalSysLockFromISR(); - osalEventBroadcastFlagsI(&canp->wakeup_event, 0); - osalSysUnlockFromISR(); - } -#endif /* CAN_USE_SLEEP_MODE */ - /* Error event.*/ - if (msr & CAN_MSR_ERRI) { - eventflags_t flags; - uint32_t esr = canp->can->ESR; - - canp->can->ESR &= ~CAN_ESR_LEC; - flags = (eventflags_t)(esr & 7); - if ((esr & CAN_ESR_LEC) > 0) - flags |= CAN_FRAMING_ERROR; - - osalSysLockFromISR(); - /* The content of the ESR register is copied unchanged in the upper - half word of the listener flags mask.*/ - osalEventBroadcastFlagsI(&canp->error_event, flags | (eventflags_t)(esr << 16)); - osalSysUnlockFromISR(); - } -} - -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ - -#if STM32_CAN_USE_CAN1 || defined(__DOXYGEN__) -#if defined(STM32_CAN1_UNIFIED_HANDLER) -/** - * @brief CAN1 unified interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_CAN1_UNIFIED_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - can_lld_tx_handler(&CAND1); - can_lld_rx0_handler(&CAND1); - can_lld_rx1_handler(&CAND1); - can_lld_sce_handler(&CAND1); - - OSAL_IRQ_EPILOGUE(); -} -#else /* !defined(STM32_CAN1_UNIFIED_HANDLER) */ - -#if !defined(STM32_CAN1_TX_HANDLER) -#error "STM32_CAN1_TX_HANDLER not defined" -#endif -#if !defined(STM32_CAN1_RX0_HANDLER) -#error "STM32_CAN1_RX0_HANDLER not defined" -#endif -#if !defined(STM32_CAN1_RX1_HANDLER) -#error "STM32_CAN1_RX1_HANDLER not defined" -#endif -#if !defined(STM32_CAN1_SCE_HANDLER) -#error "STM32_CAN1_SCE_HANDLER not defined" -#endif - -/** - * @brief CAN1 TX interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_CAN1_TX_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - can_lld_tx_handler(&CAND1); - - OSAL_IRQ_EPILOGUE(); -} - -/* - * @brief CAN1 RX0 interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_CAN1_RX0_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - can_lld_rx0_handler(&CAND1); - - OSAL_IRQ_EPILOGUE(); -} - -/** - * @brief CAN1 RX1 interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_CAN1_RX1_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - can_lld_rx1_handler(&CAND1); - - OSAL_IRQ_EPILOGUE(); -} - -/** - * @brief CAN1 SCE interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_CAN1_SCE_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - can_lld_sce_handler(&CAND1); - - OSAL_IRQ_EPILOGUE(); -} -#endif /* !defined(STM32_CAN1_UNIFIED_HANDLER) */ -#endif /* STM32_CAN_USE_CAN1 */ - -#if STM32_CAN_USE_CAN2 || defined(__DOXYGEN__) -#if defined(STM32_CAN2_UNIFIED_HANDLER) -/** - * @brief CAN1 unified interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_CAN2_UNIFIED_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - can_lld_tx_handler(&CAND2); - can_lld_rx0_handler(&CAND2); - can_lld_rx1_handler(&CAND2); - can_lld_sce_handler(&CAND2); - - OSAL_IRQ_EPILOGUE(); -} -#else /* !defined(STM32_CAN2_UNIFIED_HANDLER) */ - -#if !defined(STM32_CAN1_TX_HANDLER) -#error "STM32_CAN1_TX_HANDLER not defined" -#endif -#if !defined(STM32_CAN1_RX0_HANDLER) -#error "STM32_CAN1_RX0_HANDLER not defined" -#endif -#if !defined(STM32_CAN1_RX1_HANDLER) -#error "STM32_CAN1_RX1_HANDLER not defined" -#endif -#if !defined(STM32_CAN1_SCE_HANDLER) -#error "STM32_CAN1_SCE_HANDLER not defined" -#endif - -/** - * @brief CAN2 TX interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_CAN2_TX_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - can_lld_tx_handler(&CAND2); - - OSAL_IRQ_EPILOGUE(); -} - -/* - * @brief CAN2 RX0 interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_CAN2_RX0_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - can_lld_rx0_handler(&CAND2); - - OSAL_IRQ_EPILOGUE(); -} - -/** - * @brief CAN2 RX1 interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_CAN2_RX1_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - can_lld_rx1_handler(&CAND2); - - OSAL_IRQ_EPILOGUE(); -} - -/** - * @brief CAN2 SCE interrupt handler. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_CAN2_SCE_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - can_lld_sce_handler(&CAND2); - - OSAL_IRQ_EPILOGUE(); -} -#endif /* !defined(STM32_CAN2_UNIFIED_HANDLER) */ -#endif /* STM32_CAN_USE_CAN2 */ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief Low level CAN driver initialization. - * - * @notapi - */ -void can_lld_init(void) { - -#if STM32_CAN_USE_CAN1 - /* Driver initialization.*/ - canObjectInit(&CAND1); - CAND1.can = CAN1; -#endif -#if STM32_CAN_USE_CAN2 - /* Driver initialization.*/ - canObjectInit(&CAND2); - CAND2.can = CAN2; -#endif - - /* Filters initialization.*/ -#if STM32_HAS_CAN2 - can_lld_set_filters(STM32_CAN_MAX_FILTERS / 2, 0, NULL); -#else - can_lld_set_filters(STM32_CAN_MAX_FILTERS, 0, NULL); -#endif -} - -/** - * @brief Configures and activates the CAN peripheral. - * - * @param[in] canp pointer to the @p CANDriver object - * - * @notapi - */ -void can_lld_start(CANDriver *canp) { - - /* Clock activation.*/ -#if STM32_CAN_USE_CAN1 - if (&CAND1 == canp) { -#if defined(STM32_CAN1_UNIFIED_NUMBER) - nvicEnableVector(STM32_CAN1_UNIFIED_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY); -#else - nvicEnableVector(STM32_CAN1_TX_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY); - nvicEnableVector(STM32_CAN1_RX0_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY); - nvicEnableVector(STM32_CAN1_RX1_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY); - nvicEnableVector(STM32_CAN1_SCE_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY); -#endif - rccEnableCAN1(FALSE); - } -#endif -#if STM32_CAN_USE_CAN2 - if (&CAND2 == canp) { - - osalDbgAssert(CAND1.state != CAN_STOP, "CAN1 must be started"); - -#if defined(STM32_CAN2_UNIFIED_NUMBER) - nvicEnableVector(STM32_CAN2_UNIFIED_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY); -#else - nvicEnableVector(STM32_CAN2_TX_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY); - nvicEnableVector(STM32_CAN2_RX0_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY); - nvicEnableVector(STM32_CAN2_RX1_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY); - nvicEnableVector(STM32_CAN2_SCE_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY); -#endif - rccEnableCAN2(FALSE); - } -#endif - - /* Configuring CAN. */ - canp->can->MCR = CAN_MCR_INRQ; - while ((canp->can->MSR & CAN_MSR_INAK) == 0) - osalThreadSleepS(1); - canp->can->BTR = canp->config->btr; - canp->can->MCR = canp->config->mcr; - - /* Interrupt sources initialization.*/ - canp->can->IER = CAN_IER_TMEIE | CAN_IER_FMPIE0 | CAN_IER_FMPIE1 | - CAN_IER_WKUIE | CAN_IER_ERRIE | CAN_IER_LECIE | - CAN_IER_BOFIE | CAN_IER_EPVIE | CAN_IER_EWGIE | - CAN_IER_FOVIE0 | CAN_IER_FOVIE1; -} - -/** - * @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) { -#if STM32_CAN_USE_CAN1 - if (&CAND1 == canp) { - -#if STM32_CAN_USE_CAN2 - osalDbgAssert(CAND2.state == CAN_STOP, "CAN2 must be stopped"); -#endif - - CAN1->MCR = 0x00010002; /* Register reset value. */ - CAN1->IER = 0x00000000; /* All sources disabled. */ -#if defined(STM32_CAN1_UNIFIED_NUMBER) - nvicDisableVector(STM32_CAN1_UNIFIED_NUMBER); -#else - nvicDisableVector(STM32_CAN1_TX_NUMBER); - nvicDisableVector(STM32_CAN1_RX0_NUMBER); - nvicDisableVector(STM32_CAN1_RX1_NUMBER); - nvicDisableVector(STM32_CAN1_SCE_NUMBER); -#endif - rccDisableCAN1(FALSE); - } -#endif -#if STM32_CAN_USE_CAN2 - if (&CAND2 == canp) { - CAN2->MCR = 0x00010002; /* Register reset value. */ - CAN2->IER = 0x00000000; /* All sources disabled. */ -#if defined(STM32_CAN2_UNIFIED_NUMBER) - nvicDisableVector(STM32_CAN2_UNIFIED_NUMBER); -#else - nvicDisableVector(STM32_CAN2_TX_NUMBER); - nvicDisableVector(STM32_CAN2_RX0_NUMBER); - nvicDisableVector(STM32_CAN2_RX1_NUMBER); - nvicDisableVector(STM32_CAN2_SCE_NUMBER); -#endif - rccDisableCAN2(FALSE); - } -#endif - } -} - -/** - * @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 can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox) { - - switch (mailbox) { - case CAN_ANY_MAILBOX: - return (canp->can->TSR & CAN_TSR_TME) != 0; - case 1: - return (canp->can->TSR & CAN_TSR_TME0) != 0; - case 2: - return (canp->can->TSR & CAN_TSR_TME1) != 0; - case 3: - return (canp->can->TSR & CAN_TSR_TME2) != 0; - default: - return FALSE; - } -} - -/** - * @brief Inserts a frame into the transmit queue. - * - * @param[in] canp pointer to the @p CANDriver object - * @param[in] ctfp pointer to the CAN frame to be transmitted - * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox - * - * @notapi - */ -void can_lld_transmit(CANDriver *canp, - canmbx_t mailbox, - const CANTxFrame *ctfp) { - uint32_t tir; - CAN_TxMailBox_TypeDef *tmbp; - - /* Pointer to a free transmission mailbox.*/ - switch (mailbox) { - case CAN_ANY_MAILBOX: - tmbp = &canp->can->sTxMailBox[(canp->can->TSR & CAN_TSR_CODE) >> 24]; - break; - case 1: - tmbp = &canp->can->sTxMailBox[0]; - break; - case 2: - tmbp = &canp->can->sTxMailBox[1]; - break; - case 3: - tmbp = &canp->can->sTxMailBox[2]; - break; - default: - return; - } - - /* Preparing the message.*/ - if (ctfp->IDE) - tir = ((uint32_t)ctfp->EID << 3) | ((uint32_t)ctfp->RTR << 1) | - CAN_TI0R_IDE; - else - tir = ((uint32_t)ctfp->SID << 21) | ((uint32_t)ctfp->RTR << 1); - tmbp->TDTR = ctfp->DLC; - tmbp->TDLR = ctfp->data32[0]; - tmbp->TDHR = ctfp->data32[1]; - tmbp->TIR = tir | CAN_TI0R_TXRQ; -} - -/** - * @brief Determines whether a frame has been received. - * - * @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 can_lld_is_rx_nonempty(CANDriver *canp, canmbx_t mailbox) { - - switch (mailbox) { - case CAN_ANY_MAILBOX: - return ((canp->can->RF0R & CAN_RF0R_FMP0) != 0 || - (canp->can->RF1R & CAN_RF1R_FMP1) != 0); - case 1: - return (canp->can->RF0R & CAN_RF0R_FMP0) != 0; - case 2: - return (canp->can->RF1R & CAN_RF1R_FMP1) != 0; - default: - return FALSE; - } -} - -/** - * @brief Receives a frame from the input queue. - * - * @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) { - uint32_t rir, rdtr; - - if (mailbox == CAN_ANY_MAILBOX) { - if ((canp->can->RF0R & CAN_RF0R_FMP0) != 0) - mailbox = 1; - else if ((canp->can->RF1R & CAN_RF1R_FMP1) != 0) - mailbox = 2; - else { - /* Should not happen, do nothing.*/ - return; - } - } - switch (mailbox) { - case 1: - /* Fetches the message.*/ - rir = canp->can->sFIFOMailBox[0].RIR; - rdtr = canp->can->sFIFOMailBox[0].RDTR; - crfp->data32[0] = canp->can->sFIFOMailBox[0].RDLR; - crfp->data32[1] = canp->can->sFIFOMailBox[0].RDHR; - - /* Releases the mailbox.*/ - canp->can->RF0R = CAN_RF0R_RFOM0; - - /* If the queue is empty re-enables the interrupt in order to generate - events again.*/ - if ((canp->can->RF0R & CAN_RF0R_FMP0) == 0) - canp->can->IER |= CAN_IER_FMPIE0; - break; - case 2: - /* Fetches the message.*/ - rir = canp->can->sFIFOMailBox[1].RIR; - rdtr = canp->can->sFIFOMailBox[1].RDTR; - crfp->data32[0] = canp->can->sFIFOMailBox[1].RDLR; - crfp->data32[1] = canp->can->sFIFOMailBox[1].RDHR; - - /* Releases the mailbox.*/ - canp->can->RF1R = CAN_RF1R_RFOM1; - - /* If the queue is empty re-enables the interrupt in order to generate - events again.*/ - if ((canp->can->RF1R & CAN_RF1R_FMP1) == 0) - canp->can->IER |= CAN_IER_FMPIE1; - break; - default: - /* Should not happen, do nothing.*/ - return; - } - - /* Decodes the various fields in the RX frame.*/ - crfp->RTR = (rir & CAN_RI0R_RTR) >> 1; - crfp->IDE = (rir & CAN_RI0R_IDE) >> 2; - if (crfp->IDE) - crfp->EID = rir >> 3; - else - crfp->SID = rir >> 21; - crfp->DLC = rdtr & CAN_RDT0R_DLC; - crfp->FMI = (uint8_t)(rdtr >> 8); - crfp->TIME = (uint16_t)(rdtr >> 16); -} - -#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) { - - canp->can->MCR |= CAN_MCR_SLEEP; -} - -/** - * @brief Enforces leaving the sleep mode. - * - * @param[in] canp pointer to the @p CANDriver object - * - * @notapi - */ -void can_lld_wakeup(CANDriver *canp) { - - canp->can->MCR &= ~CAN_MCR_SLEEP; -} -#endif /* CAN_USE_SLEEP_MODE */ - -/** - * @brief Programs the filters. - * @note This is an STM32-specific API. - * - * @param[in] can2sb number of the first filter assigned to CAN2 - * @param[in] num number of entries in the filters array, if zero then - * a default filter is programmed - * @param[in] cfp pointer to the filters array, can be @p NULL if - * (num == 0) - * - * @api - */ -void canSTM32SetFilters(uint32_t can2sb, uint32_t num, const CANFilter *cfp) { - - osalDbgCheck((can2sb >= 1) && (can2sb < STM32_CAN_MAX_FILTERS) && - (num <= STM32_CAN_MAX_FILTERS)); - -#if STM32_CAN_USE_CAN1 - osalDbgAssert(CAND1.state == CAN_STOP, "invalid state"); -#endif -#if STM32_CAN_USE_CAN2 - osalDbgAssert(CAND2.state == CAN_STOP, "invalid state"); -#endif - - can_lld_set_filters(can2sb, num, cfp); -} - -#endif /* HAL_USE_CAN */ - -/** @} */ diff --git a/os/hal/ports/STM32/LLD/can_lld.h b/os/hal/ports/STM32/LLD/can_lld.h deleted file mode 100644 index 6297449c6..000000000 --- a/os/hal/ports/STM32/LLD/can_lld.h +++ /dev/null @@ -1,365 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/** - * @file STM32/can_lld.h - * @brief STM32 CAN subsystem low level driver header. - * - * @addtogroup CAN - * @{ - */ - -#ifndef _CAN_LLD_H_ -#define _CAN_LLD_H_ - -#if HAL_USE_CAN || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ - -/* - * The following macros from the ST header file are replaced with better - * equivalents. - */ -#undef CAN_BTR_BRP -#undef CAN_BTR_TS1 -#undef CAN_BTR_TS2 -#undef CAN_BTR_SJW - -/** - * @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 three transmit mailboxes. - */ -#define CAN_TX_MAILBOXES 3 - -/** - * @brief This implementation supports two receive mailboxes. - */ -#define CAN_RX_MAILBOXES 2 - -/** - * @name CAN registers helper macros - * @{ - */ -#define CAN_BTR_BRP(n) (n) /**< @brief BRP field macro.*/ -#define CAN_BTR_TS1(n) ((n) << 16) /**< @brief TS1 field macro.*/ -#define CAN_BTR_TS2(n) ((n) << 20) /**< @brief TS2 field macro.*/ -#define CAN_BTR_SJW(n) ((n) << 24) /**< @brief SJW field macro.*/ - -#define CAN_IDE_STD 0 /**< @brief Standard id. */ -#define CAN_IDE_EXT 1 /**< @brief Extended id. */ - -#define CAN_RTR_DATA 0 /**< @brief Data frame. */ -#define CAN_RTR_REMOTE 1 /**< @brief Remote frame. */ -/** @} */ - -/*===========================================================================*/ -/* Driver pre-compile time settings. */ -/*===========================================================================*/ - -/** - * @name Configuration options - * @{ - */ -/** - * @brief CAN1 driver enable switch. - * @details If set to @p TRUE the support for CAN1 is included. - */ -#if !defined(STM32_CAN_USE_CAN1) || defined(__DOXYGEN__) -#define STM32_CAN_USE_CAN1 FALSE -#endif - -/** - * @brief CAN2 driver enable switch. - * @details If set to @p TRUE the support for CAN2 is included. - */ -#if !defined(STM32_CAN_USE_CAN2) || defined(__DOXYGEN__) -#define STM32_CAN_USE_CAN2 FALSE -#endif - -/** - * @brief CAN1 interrupt priority level setting. - */ -#if !defined(STM32_CAN_CAN1_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_CAN_CAN1_IRQ_PRIORITY 11 -#endif -/** @} */ - -/** - * @brief CAN2 interrupt priority level setting. - */ -#if !defined(STM32_CAN_CAN2_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_CAN_CAN2_IRQ_PRIORITY 11 -#endif -/** @} */ - -/*===========================================================================*/ -/* Derived constants and error checks. */ -/*===========================================================================*/ - -#if STM32_CAN_USE_CAN1 && !STM32_HAS_CAN1 -#error "CAN1 not present in the selected device" -#endif - -#if STM32_CAN_USE_CAN2 && !STM32_HAS_CAN2 -#error "CAN2 not present in the selected device" -#endif - -#if !STM32_CAN_USE_CAN1 && !STM32_CAN_USE_CAN2 -#error "CAN driver activated but no CAN peripheral assigned" -#endif - -#if !STM32_CAN_USE_CAN1 && STM32_CAN_USE_CAN2 -#error "CAN2 requires CAN1, it cannot operate independently" -#endif - -#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; - -/** - * @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 FMI; /**< @brief Filter id. */ - uint16_t TIME; /**< @brief Time stamp. */ - }; - 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. */ - }; -} CANRxFrame; - -/** - * @brief CAN filter. - * @note Refer to the STM32 reference manual for info about filters. - */ -typedef struct { - /** - * @brief Number of the filter to be programmed. - */ - uint32_t filter; - /** - * @brief Filter mode. - * @note This bit represent the CAN_FM1R register bit associated to this - * filter (0=mask mode, 1=list mode). - */ - uint32_t mode:1; - /** - * @brief Filter scale. - * @note This bit represent the CAN_FS1R register bit associated to this - * filter (0=16 bits mode, 1=32 bits mode). - */ - uint32_t scale:1; - /** - * @brief Filter mode. - * @note This bit represent the CAN_FFA1R register bit associated to this - * filter, must be set to zero in this version of the driver. - */ - uint32_t assignment:1; - /** - * @brief Filter register 1 (identifier). - */ - uint32_t register1; - /** - * @brief Filter register 2 (mask/identifier depending on mode=0/1). - */ - uint32_t register2; -} CANFilter; - -/** - * @brief Driver configuration structure. - */ -typedef struct { - /** - * @brief CAN MCR register initialization data. - * @note Some bits in this register are enforced by the driver regardless - * their status in this field. - */ - uint32_t mcr; - /** - * @brief CAN BTR register initialization data. - * @note Some bits in this register are enforced by the driver regardless - * their status in this field. - */ - uint32_t btr; -} CANConfig; - -/** - * @brief Structure representing an CAN driver. - */ -typedef struct { - /** - * @brief Driver state. - */ - canstate_t state; - /** - * @brief Current configuration data. - */ - const CANConfig *config; - /** - * @brief Transmission threads queue. - */ - threads_queue_t txqueue; - /** - * @brief Receive threads queue. - */ - threads_queue_t rxqueue; - /** - * @brief One or more frames become available. - * @note After broadcasting this event it will not be broadcasted again - * until the received frames queue has been completely emptied. It - * is not broadcasted for each received frame. It is - * responsibility of the application to empty the queue by - * repeatedly invoking @p chReceive() when listening to this event. - * This behavior minimizes the interrupt served by the system - * because CAN traffic. - * @note The flags associated to the listeners will indicate which - * receive mailboxes become non-empty. - */ - event_source_t rxfull_event; - /** - * @brief One or more transmission mailbox become available. - * @note The flags associated to the listeners will indicate which - * transmit mailboxes become empty. - * - */ - event_source_t txempty_event; - /** - * @brief A CAN bus error happened. - * @note The flags associated to the listeners will indicate the - * error(s) that have occurred. - */ - event_source_t error_event; -#if CAN_USE_SLEEP_MODE || defined (__DOXYGEN__) - /** - * @brief Entering sleep state event. - */ - event_source_t sleep_event; - /** - * @brief Exiting sleep state event. - */ - event_source_t wakeup_event; -#endif /* CAN_USE_SLEEP_MODE */ - /* End of the mandatory fields.*/ - /** - * @brief Pointer to the CAN registers. - */ - CAN_TypeDef *can; -} CANDriver; - -/*===========================================================================*/ -/* Driver macros. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#if STM32_CAN_USE_CAN1 && !defined(__DOXYGEN__) -extern CANDriver CAND1; -#endif - -#if STM32_CAN_USE_CAN2 && !defined(__DOXYGEN__) -extern CANDriver CAND2; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - void can_lld_init(void); - void can_lld_start(CANDriver *canp); - void can_lld_stop(CANDriver *canp); - bool can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox); - void can_lld_transmit(CANDriver *canp, - canmbx_t mailbox, - const CANTxFrame *crfp); - bool 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 */ - void canSTM32SetFilters(uint32_t can2sb, uint32_t num, const CANFilter *cfp); -#ifdef __cplusplus -} -#endif - -#endif /* HAL_USE_CAN */ - -#endif /* _CAN_LLD_H_ */ - -/** @} */ diff --git a/os/hal/ports/STM32/LLD/mac_lld.c b/os/hal/ports/STM32/LLD/mac_lld.c deleted file mode 100644 index 5142df163..000000000 --- a/os/hal/ports/STM32/LLD/mac_lld.c +++ /dev/null @@ -1,740 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/** - * @file STM32/mac_lld.c - * @brief STM32 low level MAC driver code. - * - * @addtogroup MAC - * @{ - */ - -#include - -#include "hal.h" - -#if HAL_USE_MAC || defined(__DOXYGEN__) - -#include "mii.h" - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -#define BUFFER_SIZE ((((STM32_MAC_BUFFERS_SIZE - 1) | 3) + 1) / 4) - -/* MII divider optimal value.*/ -#if (STM32_HCLK >= 150000000) -#define MACMIIDR_CR ETH_MACMIIAR_CR_Div102 -#elif (STM32_HCLK >= 100000000) -#define MACMIIDR_CR ETH_MACMIIAR_CR_Div62 -#elif (STM32_HCLK >= 60000000) -#define MACMIIDR_CR ETH_MACMIIAR_CR_Div42 -#elif (STM32_HCLK >= 35000000) -#define MACMIIDR_CR ETH_MACMIIAR_CR_Div26 -#elif (STM32_HCLK >= 20000000) -#define MACMIIDR_CR ETH_MACMIIAR_CR_Div16 -#else -#error "STM32_HCLK below minimum frequency for ETH operations (20MHz)" -#endif - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/** - * @brief Ethernet driver 1. - */ -MACDriver ETHD1; - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -static const uint8_t default_mac_address[] = {0xAA, 0x55, 0x13, - 0x37, 0x01, 0x10}; - -static stm32_eth_rx_descriptor_t rd[STM32_MAC_RECEIVE_BUFFERS]; -static stm32_eth_tx_descriptor_t td[STM32_MAC_TRANSMIT_BUFFERS]; - -static uint32_t rb[STM32_MAC_RECEIVE_BUFFERS][BUFFER_SIZE]; -static uint32_t tb[STM32_MAC_TRANSMIT_BUFFERS][BUFFER_SIZE]; - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/** - * @brief Writes a PHY register. - * - * @param[in] macp pointer to the @p MACDriver object - * @param[in] reg register number - * @param[in] value new register value - * - * @notapi - */ -void mii_write(MACDriver *macp, uint32_t reg, uint32_t value) { - - ETH->MACMIIDR = value; - ETH->MACMIIAR = macp->phyaddr | (reg << 6) | MACMIIDR_CR | - ETH_MACMIIAR_MW | ETH_MACMIIAR_MB; - while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) != 0) - ; -} - -/** - * @brief Reads a PHY register. - * - * @param[in] macp pointer to the @p MACDriver object - * @param[in] reg register number - * - * @return The PHY register content. - * - * @notapi - */ -uint32_t mii_read(MACDriver *macp, uint32_t reg) { - - ETH->MACMIIAR = macp->phyaddr | (reg << 6) | MACMIIDR_CR | ETH_MACMIIAR_MB; - while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) != 0) - ; - return ETH->MACMIIDR; -} - -#if !defined(BOARD_PHY_ADDRESS) -/** - * @brief PHY address detection. - * - * @param[in] macp pointer to the @p MACDriver object - */ -static void mii_find_phy(MACDriver *macp) { - uint32_t i; - -#if STM32_MAC_PHY_TIMEOUT > 0 - unsigned n = STM32_MAC_PHY_TIMEOUT; - do { -#endif - for (i = 0U; i < 31U; i++) { - macp->phyaddr = i << 11U; - ETH->MACMIIDR = (i << 6U) | MACMIIDR_CR; - if ((mii_read(macp, MII_PHYSID1) == (BOARD_PHY_ID >> 16U)) && - ((mii_read(macp, MII_PHYSID2) & 0xFFF0U) == (BOARD_PHY_ID & 0xFFF0U))) { - return; - } - } -#if STM32_MAC_PHY_TIMEOUT > 0 - n--; - } while (n > 0U); -#endif - /* Wrong or defective board.*/ - osalSysHalt("MAC failure"); -} -#endif - -/** - * @brief MAC address setup. - * - * @param[in] p pointer to a six bytes buffer containing the MAC - * address - */ -static void mac_lld_set_address(const uint8_t *p) { - - /* MAC address configuration, only a single address comparator is used, - hash table not used.*/ - ETH->MACA0HR = ((uint32_t)p[5] << 8) | - ((uint32_t)p[4] << 0); - ETH->MACA0LR = ((uint32_t)p[3] << 24) | - ((uint32_t)p[2] << 16) | - ((uint32_t)p[1] << 8) | - ((uint32_t)p[0] << 0); - ETH->MACA1HR = 0x0000FFFF; - ETH->MACA1LR = 0xFFFFFFFF; - ETH->MACA2HR = 0x0000FFFF; - ETH->MACA2LR = 0xFFFFFFFF; - ETH->MACA3HR = 0x0000FFFF; - ETH->MACA3LR = 0xFFFFFFFF; - ETH->MACHTHR = 0; - ETH->MACHTLR = 0; -} - -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ - -OSAL_IRQ_HANDLER(ETH_IRQHandler) { - uint32_t dmasr; - - OSAL_IRQ_PROLOGUE(); - - dmasr = ETH->DMASR; - ETH->DMASR = dmasr; /* Clear status bits.*/ - - if (dmasr & ETH_DMASR_RS) { - /* Data Received.*/ - osalSysLockFromISR(); - osalThreadDequeueAllI(ÐD1.rdqueue, MSG_RESET); -#if MAC_USE_EVENTS - osalEventBroadcastFlagsI(ÐD1.rdevent, 0); -#endif - osalSysUnlockFromISR(); - } - - if (dmasr & ETH_DMASR_TS) { - /* Data Transmitted.*/ - osalSysLockFromISR(); - osalThreadDequeueAllI(ÐD1.tdqueue, MSG_RESET); - osalSysUnlockFromISR(); - } - - OSAL_IRQ_EPILOGUE(); -} - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief Low level MAC initialization. - * - * @notapi - */ -void mac_lld_init(void) { - unsigned i; - - macObjectInit(ÐD1); - ETHD1.link_up = false; - - /* Descriptor tables are initialized in chained mode, note that the first - word is not initialized here but in mac_lld_start().*/ - for (i = 0; i < STM32_MAC_RECEIVE_BUFFERS; i++) { - rd[i].rdes1 = STM32_RDES1_RCH | STM32_MAC_BUFFERS_SIZE; - rd[i].rdes2 = (uint32_t)rb[i]; - rd[i].rdes3 = (uint32_t)&rd[(i + 1) % STM32_MAC_RECEIVE_BUFFERS]; - } - for (i = 0; i < STM32_MAC_TRANSMIT_BUFFERS; i++) { - td[i].tdes1 = 0; - td[i].tdes2 = (uint32_t)tb[i]; - td[i].tdes3 = (uint32_t)&td[(i + 1) % STM32_MAC_TRANSMIT_BUFFERS]; - } - - /* Selection of the RMII or MII mode based on info exported by board.h.*/ -#if defined(STM32F10X_CL) -#if defined(BOARD_PHY_RMII) - AFIO->MAPR |= AFIO_MAPR_MII_RMII_SEL; -#else - AFIO->MAPR &= ~AFIO_MAPR_MII_RMII_SEL; -#endif -#elif defined(STM32F2XX) || defined(STM32F4XX) -#if defined(BOARD_PHY_RMII) - SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL; -#else - SYSCFG->PMC &= ~SYSCFG_PMC_MII_RMII_SEL; -#endif -#else -#error "unsupported STM32 platform for MAC driver" -#endif - - /* Reset of the MAC core.*/ - rccResetETH(); - - /* MAC clocks temporary activation.*/ - rccEnableETH(false); - - /* PHY address setup.*/ -#if defined(BOARD_PHY_ADDRESS) - ETHD1.phyaddr = BOARD_PHY_ADDRESS << 11; -#else - mii_find_phy(ÐD1); -#endif - -#if defined(BOARD_PHY_RESET) - /* PHY board-specific reset procedure.*/ - BOARD_PHY_RESET(); -#else - /* PHY soft reset procedure.*/ - mii_write(ÐD1, MII_BMCR, BMCR_RESET); -#if defined(BOARD_PHY_RESET_DELAY) - chSysPolledDelayX(BOARD_PHY_RESET_DELAY); -#endif - while (mii_read(ÐD1, MII_BMCR) & BMCR_RESET) - ; -#endif - -#if STM32_MAC_ETH1_CHANGE_PHY_STATE - /* PHY in power down mode until the driver will be started.*/ - mii_write(ÐD1, MII_BMCR, mii_read(ÐD1, MII_BMCR) | BMCR_PDOWN); -#endif - - /* MAC clocks stopped again.*/ - rccDisableETH(false); -} - -/** - * @brief Configures and activates the MAC peripheral. - * - * @param[in] macp pointer to the @p MACDriver object - * - * @notapi - */ -void mac_lld_start(MACDriver *macp) { - unsigned i; - - /* Resets the state of all descriptors.*/ - for (i = 0; i < STM32_MAC_RECEIVE_BUFFERS; i++) - rd[i].rdes0 = STM32_RDES0_OWN; - macp->rxptr = (stm32_eth_rx_descriptor_t *)rd; - for (i = 0; i < STM32_MAC_TRANSMIT_BUFFERS; i++) - td[i].tdes0 = STM32_TDES0_TCH; - macp->txptr = (stm32_eth_tx_descriptor_t *)td; - - /* MAC clocks activation and commanded reset procedure.*/ - rccEnableETH(false); -#if defined(STM32_MAC_DMABMR_SR) - ETH->DMABMR |= ETH_DMABMR_SR; - while(ETH->DMABMR & ETH_DMABMR_SR) - ; -#endif - - /* ISR vector enabled.*/ - nvicEnableVector(ETH_IRQn, STM32_MAC_ETH1_IRQ_PRIORITY); - -#if STM32_MAC_ETH1_CHANGE_PHY_STATE - /* PHY in power up mode.*/ - mii_write(macp, MII_BMCR, mii_read(macp, MII_BMCR) & ~BMCR_PDOWN); -#endif - - /* MAC configuration.*/ - ETH->MACFFR = 0; - ETH->MACFCR = 0; - ETH->MACVLANTR = 0; - - /* MAC address setup.*/ - if (macp->config->mac_address == NULL) - mac_lld_set_address(default_mac_address); - else - mac_lld_set_address(macp->config->mac_address); - - /* Transmitter and receiver enabled. - Note that the complete setup of the MAC is performed when the link - status is detected.*/ -#if STM32_MAC_IP_CHECKSUM_OFFLOAD - ETH->MACCR = ETH_MACCR_IPCO | ETH_MACCR_RE | ETH_MACCR_TE; -#else - ETH->MACCR = ETH_MACCR_RE | ETH_MACCR_TE; -#endif - - /* DMA configuration: - Descriptor chains pointers.*/ - ETH->DMARDLAR = (uint32_t)rd; - ETH->DMATDLAR = (uint32_t)td; - - /* Enabling required interrupt sources.*/ - ETH->DMASR = ETH->DMASR; - ETH->DMAIER = ETH_DMAIER_NISE | ETH_DMAIER_RIE | ETH_DMAIER_TIE; - - /* DMA general settings.*/ - ETH->DMABMR = ETH_DMABMR_AAB | ETH_DMABMR_RDP_1Beat | ETH_DMABMR_PBL_1Beat; - - /* Transmit FIFO flush.*/ - ETH->DMAOMR = ETH_DMAOMR_FTF; - while (ETH->DMAOMR & ETH_DMAOMR_FTF) - ; - - /* DMA final configuration and start.*/ - ETH->DMAOMR = ETH_DMAOMR_DTCEFD | ETH_DMAOMR_RSF | ETH_DMAOMR_TSF | - ETH_DMAOMR_ST | ETH_DMAOMR_SR; -} - -/** - * @brief Deactivates the MAC peripheral. - * - * @param[in] macp pointer to the @p MACDriver object - * - * @notapi - */ -void mac_lld_stop(MACDriver *macp) { - - if (macp->state != MAC_STOP) { -#if STM32_MAC_ETH1_CHANGE_PHY_STATE - /* PHY in power down mode until the driver will be restarted.*/ - mii_write(macp, MII_BMCR, mii_read(macp, MII_BMCR) | BMCR_PDOWN); -#endif - - /* MAC and DMA stopped.*/ - ETH->MACCR = 0; - ETH->DMAOMR = 0; - ETH->DMAIER = 0; - ETH->DMASR = ETH->DMASR; - - /* MAC clocks stopped.*/ - rccDisableETH(false); - - /* ISR vector disabled.*/ - nvicDisableVector(ETH_IRQn); - } -} - -/** - * @brief Returns a transmission descriptor. - * @details One of the available transmission descriptors is locked and - * returned. - * - * @param[in] macp pointer to the @p MACDriver object - * @param[out] tdp pointer to a @p MACTransmitDescriptor structure - * @return The operation status. - * @retval MSG_OK the descriptor has been obtained. - * @retval MSG_TIMEOUT descriptor not available. - * - * @notapi - */ -msg_t mac_lld_get_transmit_descriptor(MACDriver *macp, - MACTransmitDescriptor *tdp) { - stm32_eth_tx_descriptor_t *tdes; - - if (!macp->link_up) - return MSG_TIMEOUT; - - osalSysLock(); - - /* Get Current TX descriptor.*/ - tdes = macp->txptr; - - /* Ensure that descriptor isn't owned by the Ethernet DMA or locked by - another thread.*/ - if (tdes->tdes0 & (STM32_TDES0_OWN | STM32_TDES0_LOCKED)) { - osalSysUnlock(); - return MSG_TIMEOUT; - } - - /* Marks the current descriptor as locked using a reserved bit.*/ - tdes->tdes0 |= STM32_TDES0_LOCKED; - - /* Next TX descriptor to use.*/ - macp->txptr = (stm32_eth_tx_descriptor_t *)tdes->tdes3; - - osalSysUnlock(); - - /* Set the buffer size and configuration.*/ - tdp->offset = 0; - tdp->size = STM32_MAC_BUFFERS_SIZE; - tdp->physdesc = tdes; - - return MSG_OK; -} - -/** - * @brief Releases a transmit descriptor and starts the transmission of the - * enqueued data as a single frame. - * - * @param[in] tdp the pointer to the @p MACTransmitDescriptor structure - * - * @notapi - */ -void mac_lld_release_transmit_descriptor(MACTransmitDescriptor *tdp) { - - osalDbgAssert(!(tdp->physdesc->tdes0 & STM32_TDES0_OWN), - "attempt to release descriptor already owned by DMA"); - - osalSysLock(); - - /* Unlocks the descriptor and returns it to the DMA engine.*/ - tdp->physdesc->tdes1 = tdp->offset; - tdp->physdesc->tdes0 = STM32_TDES0_CIC(STM32_MAC_IP_CHECKSUM_OFFLOAD) | - STM32_TDES0_IC | STM32_TDES0_LS | STM32_TDES0_FS | - STM32_TDES0_TCH | STM32_TDES0_OWN; - - /* If the DMA engine is stalled then a restart request is issued.*/ - if ((ETH->DMASR & ETH_DMASR_TPS) == ETH_DMASR_TPS_Suspended) { - ETH->DMASR = ETH_DMASR_TBUS; - ETH->DMATPDR = ETH_DMASR_TBUS; /* Any value is OK.*/ - } - - osalSysUnlock(); -} - -/** - * @brief Returns a receive descriptor. - * - * @param[in] macp pointer to the @p MACDriver object - * @param[out] rdp pointer to a @p MACReceiveDescriptor structure - * @return The operation status. - * @retval MSG_OK the descriptor has been obtained. - * @retval MSG_TIMEOUT descriptor not available. - * - * @notapi - */ -msg_t mac_lld_get_receive_descriptor(MACDriver *macp, - MACReceiveDescriptor *rdp) { - stm32_eth_rx_descriptor_t *rdes; - - osalSysLock(); - - /* Get Current RX descriptor.*/ - rdes = macp->rxptr; - - /* Iterates through received frames until a valid one is found, invalid - frames are discarded.*/ - while (!(rdes->rdes0 & STM32_RDES0_OWN)) { - if (!(rdes->rdes0 & (STM32_RDES0_AFM | STM32_RDES0_ES)) -#if STM32_MAC_IP_CHECKSUM_OFFLOAD - && (rdes->rdes0 & STM32_RDES0_FT) - && !(rdes->rdes0 & (STM32_RDES0_IPHCE | STM32_RDES0_PCE)) -#endif - && (rdes->rdes0 & STM32_RDES0_FS) && (rdes->rdes0 & STM32_RDES0_LS)) { - /* Found a valid one.*/ - rdp->offset = 0; - rdp->size = ((rdes->rdes0 & STM32_RDES0_FL_MASK) >> 16) - 4; - rdp->physdesc = rdes; - macp->rxptr = (stm32_eth_rx_descriptor_t *)rdes->rdes3; - - osalSysUnlock(); - return MSG_OK; - } - /* Invalid frame found, purging.*/ - rdes->rdes0 = STM32_RDES0_OWN; - rdes = (stm32_eth_rx_descriptor_t *)rdes->rdes3; - } - - /* Next descriptor to check.*/ - macp->rxptr = rdes; - - osalSysUnlock(); - return MSG_TIMEOUT; -} - -/** - * @brief Releases a receive descriptor. - * @details The descriptor and its buffer are made available for more incoming - * frames. - * - * @param[in] rdp the pointer to the @p MACReceiveDescriptor structure - * - * @notapi - */ -void mac_lld_release_receive_descriptor(MACReceiveDescriptor *rdp) { - - osalDbgAssert(!(rdp->physdesc->rdes0 & STM32_RDES0_OWN), - "attempt to release descriptor already owned by DMA"); - - osalSysLock(); - - /* Give buffer back to the Ethernet DMA.*/ - rdp->physdesc->rdes0 = STM32_RDES0_OWN; - - /* If the DMA engine is stalled then a restart request is issued.*/ - if ((ETH->DMASR & ETH_DMASR_RPS) == ETH_DMASR_RPS_Suspended) { - ETH->DMASR = ETH_DMASR_RBUS; - ETH->DMARPDR = ETH_DMASR_RBUS; /* Any value is OK.*/ - } - - osalSysUnlock(); -} - -/** - * @brief Updates and returns the link status. - * - * @param[in] macp pointer to the @p MACDriver object - * @return The link status. - * @retval true if the link is active. - * @retval false if the link is down. - * - * @notapi - */ -bool mac_lld_poll_link_status(MACDriver *macp) { - uint32_t maccr, bmsr, bmcr; - - maccr = ETH->MACCR; - - /* PHY CR and SR registers read.*/ - (void)mii_read(macp, MII_BMSR); - bmsr = mii_read(macp, MII_BMSR); - bmcr = mii_read(macp, MII_BMCR); - - /* Check on auto-negotiation mode.*/ - if (bmcr & BMCR_ANENABLE) { - uint32_t lpa; - - /* Auto-negotiation must be finished without faults and link established.*/ - if ((bmsr & (BMSR_LSTATUS | BMSR_RFAULT | BMSR_ANEGCOMPLETE)) != - (BMSR_LSTATUS | BMSR_ANEGCOMPLETE)) - return macp->link_up = false; - - /* Auto-negotiation enabled, checks the LPA register.*/ - lpa = mii_read(macp, MII_LPA); - - /* Check on link speed.*/ - if (lpa & (LPA_100HALF | LPA_100FULL | LPA_100BASE4)) - maccr |= ETH_MACCR_FES; - else - maccr &= ~ETH_MACCR_FES; - - /* Check on link mode.*/ - if (lpa & (LPA_10FULL | LPA_100FULL)) - maccr |= ETH_MACCR_DM; - else - maccr &= ~ETH_MACCR_DM; - } - else { - /* Link must be established.*/ - if (!(bmsr & BMSR_LSTATUS)) - return macp->link_up = false; - - /* Check on link speed.*/ - if (bmcr & BMCR_SPEED100) - maccr |= ETH_MACCR_FES; - else - maccr &= ~ETH_MACCR_FES; - - /* Check on link mode.*/ - if (bmcr & BMCR_FULLDPLX) - maccr |= ETH_MACCR_DM; - else - maccr &= ~ETH_MACCR_DM; - } - - /* Changes the mode in the MAC.*/ - ETH->MACCR = maccr; - - /* Returns the link status.*/ - return macp->link_up = true; -} - -/** - * @brief Writes to a transmit descriptor's stream. - * - * @param[in] tdp pointer to a @p MACTransmitDescriptor structure - * @param[in] buf pointer to the buffer containing the data to be - * written - * @param[in] size number of bytes to be written - * @return The number of bytes written into the descriptor's - * stream, this value can be less than the amount - * specified in the parameter @p size if the maximum - * frame size is reached. - * - * @notapi - */ -size_t mac_lld_write_transmit_descriptor(MACTransmitDescriptor *tdp, - uint8_t *buf, - size_t size) { - - osalDbgAssert(!(tdp->physdesc->tdes0 & STM32_TDES0_OWN), - "attempt to write descriptor already owned by DMA"); - - if (size > tdp->size - tdp->offset) - size = tdp->size - tdp->offset; - - if (size > 0) { - memcpy((uint8_t *)(tdp->physdesc->tdes2) + tdp->offset, buf, size); - tdp->offset += size; - } - return size; -} - -/** - * @brief Reads from a receive descriptor's stream. - * - * @param[in] rdp pointer to a @p MACReceiveDescriptor structure - * @param[in] buf pointer to the buffer that will receive the read data - * @param[in] size number of bytes to be read - * @return The number of bytes read from the descriptor's - * stream, this value can be less than the amount - * specified in the parameter @p size if there are - * no more bytes to read. - * - * @notapi - */ -size_t mac_lld_read_receive_descriptor(MACReceiveDescriptor *rdp, - uint8_t *buf, - size_t size) { - - osalDbgAssert(!(rdp->physdesc->rdes0 & STM32_RDES0_OWN), - "attempt to read descriptor already owned by DMA"); - - if (size > rdp->size - rdp->offset) - size = rdp->size - rdp->offset; - - if (size > 0) { - memcpy(buf, (uint8_t *)(rdp->physdesc->rdes2) + rdp->offset, size); - rdp->offset += size; - } - return size; -} - -#if MAC_USE_ZERO_COPY || defined(__DOXYGEN__) -/** - * @brief Returns a pointer to the next transmit buffer in the descriptor - * chain. - * @note The API guarantees that enough buffers can be requested to fill - * a whole frame. - * - * @param[in] tdp pointer to a @p MACTransmitDescriptor structure - * @param[in] size size of the requested buffer. Specify the frame size - * on the first call then scale the value down subtracting - * the amount of data already copied into the previous - * buffers. - * @param[out] sizep pointer to variable receiving the buffer size, it is - * zero when the last buffer has already been returned. - * Note that a returned size lower than the amount - * requested means that more buffers must be requested - * in order to fill the frame data entirely. - * @return Pointer to the returned buffer. - * @retval NULL if the buffer chain has been entirely scanned. - * - * @notapi - */ -uint8_t *mac_lld_get_next_transmit_buffer(MACTransmitDescriptor *tdp, - size_t size, - size_t *sizep) { - - if (tdp->offset == 0) { - *sizep = tdp->size; - tdp->offset = size; - return (uint8_t *)tdp->physdesc->tdes2; - } - *sizep = 0; - return NULL; -} - -/** - * @brief Returns a pointer to the next receive buffer in the descriptor - * chain. - * @note The API guarantees that the descriptor chain contains a whole - * frame. - * - * @param[in] rdp pointer to a @p MACReceiveDescriptor structure - * @param[out] sizep pointer to variable receiving the buffer size, it is - * zero when the last buffer has already been returned. - * @return Pointer to the returned buffer. - * @retval NULL if the buffer chain has been entirely scanned. - * - * @notapi - */ -const uint8_t *mac_lld_get_next_receive_buffer(MACReceiveDescriptor *rdp, - size_t *sizep) { - - if (rdp->size > 0) { - *sizep = rdp->size; - rdp->offset = rdp->size; - rdp->size = 0; - return (uint8_t *)rdp->physdesc->rdes2; - } - *sizep = 0; - return NULL; -} -#endif /* MAC_USE_ZERO_COPY */ - -#endif /* HAL_USE_MAC */ - -/** @} */ diff --git a/os/hal/ports/STM32/LLD/mac_lld.h b/os/hal/ports/STM32/LLD/mac_lld.h deleted file mode 100644 index 8684192a5..000000000 --- a/os/hal/ports/STM32/LLD/mac_lld.h +++ /dev/null @@ -1,363 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/** - * @file STM32/mac_lld.h - * @brief STM32 low level MAC driver header. - * - * @addtogroup MAC - * @{ - */ - -#ifndef _MAC_LLD_H_ -#define _MAC_LLD_H_ - -#if HAL_USE_MAC || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ - -/** - * @brief This implementation supports the zero-copy mode API. - */ -#define MAC_SUPPORTS_ZERO_COPY TRUE - -/** - * @name RDES0 constants - * @{ - */ -#define STM32_RDES0_OWN 0x80000000 -#define STM32_RDES0_AFM 0x40000000 -#define STM32_RDES0_FL_MASK 0x3FFF0000 -#define STM32_RDES0_ES 0x00008000 -#define STM32_RDES0_DESERR 0x00004000 -#define STM32_RDES0_SAF 0x00002000 -#define STM32_RDES0_LE 0x00001000 -#define STM32_RDES0_OE 0x00000800 -#define STM32_RDES0_VLAN 0x00000400 -#define STM32_RDES0_FS 0x00000200 -#define STM32_RDES0_LS 0x00000100 -#define STM32_RDES0_IPHCE 0x00000080 -#define STM32_RDES0_LCO 0x00000040 -#define STM32_RDES0_FT 0x00000020 -#define STM32_RDES0_RWT 0x00000010 -#define STM32_RDES0_RE 0x00000008 -#define STM32_RDES0_DE 0x00000004 -#define STM32_RDES0_CE 0x00000002 -#define STM32_RDES0_PCE 0x00000001 -/** @} */ - -/** - * @name RDES1 constants - * @{ - */ -#define STM32_RDES1_DIC 0x80000000 -#define STM32_RDES1_RBS2_MASK 0x1FFF0000 -#define STM32_RDES1_RER 0x00008000 -#define STM32_RDES1_RCH 0x00004000 -#define STM32_RDES1_RBS1_MASK 0x00001FFF -/** @} */ - -/** - * @name TDES0 constants - * @{ - */ -#define STM32_TDES0_OWN 0x80000000 -#define STM32_TDES0_IC 0x40000000 -#define STM32_TDES0_LS 0x20000000 -#define STM32_TDES0_FS 0x10000000 -#define STM32_TDES0_DC 0x08000000 -#define STM32_TDES0_DP 0x04000000 -#define STM32_TDES0_TTSE 0x02000000 -#define STM32_TDES0_LOCKED 0x01000000 /* NOTE: Pseudo flag. */ -#define STM32_TDES0_CIC_MASK 0x00C00000 -#define STM32_TDES0_CIC(n) ((n) << 22) -#define STM32_TDES0_TER 0x00200000 -#define STM32_TDES0_TCH 0x00100000 -#define STM32_TDES0_TTSS 0x00020000 -#define STM32_TDES0_IHE 0x00010000 -#define STM32_TDES0_ES 0x00008000 -#define STM32_TDES0_JT 0x00004000 -#define STM32_TDES0_FF 0x00002000 -#define STM32_TDES0_IPE 0x00001000 -#define STM32_TDES0_LCA 0x00000800 -#define STM32_TDES0_NC 0x00000400 -#define STM32_TDES0_LCO 0x00000200 -#define STM32_TDES0_EC 0x00000100 -#define STM32_TDES0_VF 0x00000080 -#define STM32_TDES0_CC_MASK 0x00000078 -#define STM32_TDES0_ED 0x00000004 -#define STM32_TDES0_UF 0x00000002 -#define STM32_TDES0_DB 0x00000001 -/** @} */ - -/** - * @name TDES1 constants - * @{ - */ -#define STM32_TDES1_TBS2_MASK 0x1FFF0000 -#define STM32_TDES1_TBS1_MASK 0x00001FFF -/** @} */ - -/*===========================================================================*/ -/* Driver pre-compile time settings. */ -/*===========================================================================*/ - -/** - * @name Configuration options - * @{ - */ -/** - * @brief Number of available transmit buffers. - */ -#if !defined(STM32_MAC_TRANSMIT_BUFFERS) || defined(__DOXYGEN__) -#define STM32_MAC_TRANSMIT_BUFFERS 2 -#endif - -/** - * @brief Number of available receive buffers. - */ -#if !defined(STM32_MAC_RECEIVE_BUFFERS) || defined(__DOXYGEN__) -#define STM32_MAC_RECEIVE_BUFFERS 4 -#endif - -/** - * @brief Maximum supported frame size. - */ -#if !defined(STM32_MAC_BUFFERS_SIZE) || defined(__DOXYGEN__) -#define STM32_MAC_BUFFERS_SIZE 1522 -#endif - -/** - * @brief PHY detection timeout. - * @details Timeout for PHY address detection, the scan for a PHY is performed - * the specified number of times before invoking the failure handler. - * This setting applies only if the PHY address is not explicitly - * set in the board header file using @p BOARD_PHY_ADDRESS. A zero - * value disables the timeout and a single search is performed. - */ -#if !defined(STM32_MAC_PHY_TIMEOUT) || defined(__DOXYGEN__) -#define STM32_MAC_PHY_TIMEOUT 100 -#endif - -/** - * @brief Change the PHY power state inside the driver. - */ -#if !defined(STM32_MAC_ETH1_CHANGE_PHY_STATE) || defined(__DOXYGEN__) -#define STM32_MAC_ETH1_CHANGE_PHY_STATE TRUE -#endif - -/** - * @brief ETHD1 interrupt priority level setting. - */ -#if !defined(STM32_MAC_ETH1_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_MAC_ETH1_IRQ_PRIORITY 13 -#endif - -/** - * @brief IP checksum offload. - * @details The following modes are available: - * - 0 Function disabled. - * - 1 Only IP header checksum calculation and insertion are enabled. - * - 2 IP header checksum and payload checksum calculation and - * insertion are enabled, but pseudo-header checksum is not - * calculated in hardware. - * - 3 IP Header checksum and payload checksum calculation and - * insertion are enabled, and pseudo-header checksum is - * calculated in hardware. - * . - */ -#if !defined(STM32_MAC_IP_CHECKSUM_OFFLOAD) || defined(__DOXYGEN__) -#define STM32_MAC_IP_CHECKSUM_OFFLOAD 0 -#endif -/** @} */ - -/*===========================================================================*/ -/* Derived constants and error checks. */ -/*===========================================================================*/ - -#if (STM32_MAC_PHY_TIMEOUT > 0) && !HAL_IMPLEMENTS_COUNTERS -#error "STM32_MAC_PHY_TIMEOUT requires the realtime counter service" -#endif - -/*===========================================================================*/ -/* Driver data structures and types. */ -/*===========================================================================*/ - -/** - * @brief Type of an STM32 Ethernet receive descriptor. - */ -typedef struct { - volatile uint32_t rdes0; - volatile uint32_t rdes1; - volatile uint32_t rdes2; - volatile uint32_t rdes3; -} stm32_eth_rx_descriptor_t; - -/** - * @brief Type of an STM32 Ethernet transmit descriptor. - */ -typedef struct { - volatile uint32_t tdes0; - volatile uint32_t tdes1; - volatile uint32_t tdes2; - volatile uint32_t tdes3; -} stm32_eth_tx_descriptor_t; - -/** - * @brief Driver configuration structure. - */ -typedef struct { - /** - * @brief MAC address. - */ - uint8_t *mac_address; - /* End of the mandatory fields.*/ -} MACConfig; - -/** - * @brief Structure representing a MAC driver. - */ -struct MACDriver { - /** - * @brief Driver state. - */ - macstate_t state; - /** - * @brief Current configuration data. - */ - const MACConfig *config; - /** - * @brief Transmit semaphore. - */ - threads_queue_t tdqueue; - /** - * @brief Receive semaphore. - */ - threads_queue_t rdqueue; -#if MAC_USE_EVENTS || defined(__DOXYGEN__) - /** - * @brief Receive event. - */ - event_source_t rdevent; -#endif - /* End of the mandatory fields.*/ - /** - * @brief Link status flag. - */ - bool link_up; - /** - * @brief PHY address (pre shifted). - */ - uint32_t phyaddr; - /** - * @brief Receive next frame pointer. - */ - stm32_eth_rx_descriptor_t *rxptr; - /** - * @brief Transmit next frame pointer. - */ - stm32_eth_tx_descriptor_t *txptr; -}; - -/** - * @brief Structure representing a transmit descriptor. - */ -typedef struct { - /** - * @brief Current write offset. - */ - size_t offset; - /** - * @brief Available space size. - */ - size_t size; - /* End of the mandatory fields.*/ - /** - * @brief Pointer to the physical descriptor. - */ - stm32_eth_tx_descriptor_t *physdesc; -} MACTransmitDescriptor; - -/** - * @brief Structure representing a receive descriptor. - */ -typedef struct { - /** - * @brief Current read offset. - */ - size_t offset; - /** - * @brief Available data size. - */ - size_t size; - /* End of the mandatory fields.*/ - /** - * @brief Pointer to the physical descriptor. - */ - stm32_eth_rx_descriptor_t *physdesc; -} MACReceiveDescriptor; - -/*===========================================================================*/ -/* Driver macros. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#if !defined(__DOXYGEN__) -extern MACDriver ETHD1; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - void mii_write(MACDriver *macp, uint32_t reg, uint32_t value); - uint32_t mii_read(MACDriver *macp, uint32_t reg); - void mac_lld_init(void); - void mac_lld_start(MACDriver *macp); - void mac_lld_stop(MACDriver *macp); - msg_t mac_lld_get_transmit_descriptor(MACDriver *macp, - MACTransmitDescriptor *tdp); - void mac_lld_release_transmit_descriptor(MACTransmitDescriptor *tdp); - msg_t mac_lld_get_receive_descriptor(MACDriver *macp, - MACReceiveDescriptor *rdp); - void mac_lld_release_receive_descriptor(MACReceiveDescriptor *rdp); - bool mac_lld_poll_link_status(MACDriver *macp); - size_t mac_lld_write_transmit_descriptor(MACTransmitDescriptor *tdp, - uint8_t *buf, - size_t size); - size_t mac_lld_read_receive_descriptor(MACReceiveDescriptor *rdp, - uint8_t *buf, - size_t size); -#if MAC_USE_ZERO_COPY - uint8_t *mac_lld_get_next_transmit_buffer(MACTransmitDescriptor *tdp, - size_t size, - size_t *sizep); - const uint8_t *mac_lld_get_next_receive_buffer(MACReceiveDescriptor *rdp, - size_t *sizep); -#endif /* MAC_USE_ZERO_COPY */ -#ifdef __cplusplus -} -#endif - -#endif /* HAL_USE_MAC */ - -#endif /* _MAC_LLD_H_ */ - -/** @} */ diff --git a/os/hal/ports/STM32/LLD/sdc_lld.c b/os/hal/ports/STM32/LLD/sdc_lld.c deleted file mode 100644 index f4d23e6d2..000000000 --- a/os/hal/ports/STM32/LLD/sdc_lld.c +++ /dev/null @@ -1,873 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/** - * @file STM32/sdc_lld.c - * @brief STM32 SDC subsystem low level driver source. - * - * @addtogroup SDC - * @{ - */ - -#include - -#include "hal.h" - -#if HAL_USE_SDC || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -#define DMA_CHANNEL \ - STM32_DMA_GETCHANNEL(STM32_SDC_SDIO_DMA_STREAM, \ - STM32_SDC_SDIO_DMA_CHN) - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/** @brief SDCD1 driver identifier.*/ -SDCDriver SDCD1; - -/*===========================================================================*/ -/* Driver local variables and types. */ -/*===========================================================================*/ - -#if STM32_SDC_SDIO_UNALIGNED_SUPPORT -/** - * @brief Buffer for temporary storage during unaligned transfers. - */ -static union { - uint32_t alignment; - uint8_t buf[MMCSD_BLOCK_SIZE]; -} u; -#endif /* STM32_SDC_SDIO_UNALIGNED_SUPPORT */ - - -/** - * @brief SDIO default configuration. - */ -static const SDCConfig sdc_default_cfg = { - NULL, - SDC_MODE_4BIT -}; - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/** - * @brief Prepares to handle read transaction. - * @details Designed for read special registers from card. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[out] buf pointer to the read buffer - * @param[in] bytes number of bytes to read - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @notapi - */ -static bool sdc_lld_prepare_read_bytes(SDCDriver *sdcp, - uint8_t *buf, uint32_t bytes) { - osalDbgCheck(bytes < 0x1000000); - - sdcp->sdio->DTIMER = STM32_SDC_READ_TIMEOUT; - - /* Checks for errors and waits for the card to be ready for reading.*/ - if (_sdc_wait_for_transfer_state(sdcp)) - return HAL_FAILED; - - /* Prepares the DMA channel for writing.*/ - dmaStreamSetMemory0(sdcp->dma, buf); - dmaStreamSetTransactionSize(sdcp->dma, bytes / sizeof (uint32_t)); - dmaStreamSetMode(sdcp->dma, sdcp->dmamode | STM32_DMA_CR_DIR_P2M); - dmaStreamEnable(sdcp->dma); - - /* Setting up data transfer.*/ - sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS; - sdcp->sdio->MASK = SDIO_MASK_DCRCFAILIE | - SDIO_MASK_DTIMEOUTIE | - SDIO_MASK_STBITERRIE | - SDIO_MASK_RXOVERRIE | - SDIO_MASK_DATAENDIE; - sdcp->sdio->DLEN = bytes; - - /* Transaction starts just after DTEN bit setting.*/ - sdcp->sdio->DCTRL = SDIO_DCTRL_DTDIR | - SDIO_DCTRL_DTMODE | /* multibyte data transfer */ - SDIO_DCTRL_DMAEN | - SDIO_DCTRL_DTEN; - - return HAL_SUCCESS; -} - -/** - * @brief Prepares card to handle read transaction. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[in] startblk first block to read - * @param[in] n number of blocks to read - * @param[in] resp pointer to the response buffer - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @notapi - */ -static bool sdc_lld_prepare_read(SDCDriver *sdcp, uint32_t startblk, - uint32_t n, uint32_t *resp) { - - /* Driver handles data in 512 bytes blocks (just like HC cards). But if we - have not HC card than we must convert address from blocks to bytes.*/ - if (!(sdcp->cardmode & SDC_MODE_HIGH_CAPACITY)) - startblk *= MMCSD_BLOCK_SIZE; - - if (n > 1) { - /* Send read multiple blocks command to card.*/ - if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_READ_MULTIPLE_BLOCK, - startblk, resp) || MMCSD_R1_ERROR(resp[0])) - return HAL_FAILED; - } - else{ - /* Send read single block command.*/ - if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_READ_SINGLE_BLOCK, - startblk, resp) || MMCSD_R1_ERROR(resp[0])) - return HAL_FAILED; - } - - return HAL_SUCCESS; -} - -/** - * @brief Prepares card to handle write transaction. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[in] startblk first block to read - * @param[in] n number of blocks to write - * @param[in] resp pointer to the response buffer - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @notapi - */ -static bool sdc_lld_prepare_write(SDCDriver *sdcp, uint32_t startblk, - uint32_t n, uint32_t *resp) { - - /* Driver handles data in 512 bytes blocks (just like HC cards). But if we - have not HC card than we must convert address from blocks to bytes.*/ - if (!(sdcp->cardmode & SDC_MODE_HIGH_CAPACITY)) - startblk *= MMCSD_BLOCK_SIZE; - - if (n > 1) { - /* Write multiple blocks command.*/ - if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_WRITE_MULTIPLE_BLOCK, - startblk, resp) || MMCSD_R1_ERROR(resp[0])) - return HAL_FAILED; - } - else{ - /* Write single block command.*/ - if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_WRITE_BLOCK, - startblk, resp) || MMCSD_R1_ERROR(resp[0])) - return HAL_FAILED; - } - - return HAL_SUCCESS; -} - -/** - * @brief Wait end of data transaction and performs finalizations. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[in] n number of blocks in transaction - * @param[in] resp pointer to the response buffer - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - */ -static bool sdc_lld_wait_transaction_end(SDCDriver *sdcp, uint32_t n, - uint32_t *resp) { - - /* Note the mask is checked before going to sleep because the interrupt - may have occurred before reaching the critical zone.*/ - osalSysLock(); - if (sdcp->sdio->MASK != 0) - osalThreadSuspendS(&sdcp->thread); - if ((sdcp->sdio->STA & SDIO_STA_DATAEND) == 0) { - osalSysUnlock(); - return HAL_FAILED; - } - -#if (defined(STM32F4XX) || defined(STM32F2XX)) - /* Wait until DMA channel enabled to be sure that all data transferred.*/ - while (sdcp->dma->stream->CR & STM32_DMA_CR_EN) - ; - - /* DMA event flags must be manually cleared.*/ - dmaStreamClearInterrupt(sdcp->dma); - - sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS; - sdcp->sdio->DCTRL = 0; - osalSysUnlock(); - - /* Wait until interrupt flags to be cleared.*/ - /*while (((DMA2->LISR) >> (sdcp->dma->ishift)) & STM32_DMA_ISR_TCIF) - dmaStreamClearInterrupt(sdcp->dma);*/ -#else - /* Waits for transfer completion at DMA level, the the stream is - disabled and cleared.*/ - dmaWaitCompletion(sdcp->dma); - - sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS; - sdcp->sdio->DCTRL = 0; - osalSysUnlock(); -#endif - - /* Finalize transaction.*/ - if (n > 1) - return sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp); - - return HAL_SUCCESS; -} - -/** - * @brief Gets SDC errors. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[in] sta value of the STA register - * - * @notapi - */ -static void sdc_lld_collect_errors(SDCDriver *sdcp, uint32_t sta) { - uint32_t errors = SDC_NO_ERROR; - - if (sta & SDIO_STA_CCRCFAIL) - errors |= SDC_CMD_CRC_ERROR; - if (sta & SDIO_STA_DCRCFAIL) - errors |= SDC_DATA_CRC_ERROR; - if (sta & SDIO_STA_CTIMEOUT) - errors |= SDC_COMMAND_TIMEOUT; - if (sta & SDIO_STA_DTIMEOUT) - errors |= SDC_DATA_TIMEOUT; - if (sta & SDIO_STA_TXUNDERR) - errors |= SDC_TX_UNDERRUN; - if (sta & SDIO_STA_RXOVERR) - errors |= SDC_RX_OVERRUN; - if (sta & SDIO_STA_STBITERR) - errors |= SDC_STARTBIT_ERROR; - - sdcp->errors |= errors; -} - -/** - * @brief Performs clean transaction stopping in case of errors. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[in] n number of blocks in transaction - * @param[in] resp pointer to the response buffer - * - * @notapi - */ -static void sdc_lld_error_cleanup(SDCDriver *sdcp, - uint32_t n, - uint32_t *resp) { - uint32_t sta = sdcp->sdio->STA; - - dmaStreamClearInterrupt(sdcp->dma); - dmaStreamDisable(sdcp->dma); - sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS; - sdcp->sdio->MASK = 0; - sdcp->sdio->DCTRL = 0; - sdc_lld_collect_errors(sdcp, sta); - if (n > 1) - sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_STOP_TRANSMISSION, 0, resp); -} - -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ - -#if !defined(STM32_SDIO_HANDLER) -#error "STM32_SDIO_HANDLER not defined" -#endif -/** - * @brief SDIO IRQ handler. - * @details It just wakes transaction thread. All error handling performs in - * that thread. - * - * @isr - */ -OSAL_IRQ_HANDLER(STM32_SDIO_HANDLER) { - - OSAL_IRQ_PROLOGUE(); - - osalSysLockFromISR(); - - /* Disables the source but the status flags are not reset because the - read/write functions needs to check them.*/ - SDIO->MASK = 0; - - osalThreadResumeI(&SDCD1.thread, MSG_OK); - - osalSysUnlockFromISR(); - - OSAL_IRQ_EPILOGUE(); -} - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief Low level SDC driver initialization. - * - * @notapi - */ -void sdc_lld_init(void) { - - sdcObjectInit(&SDCD1); - SDCD1.thread = NULL; - SDCD1.dma = STM32_DMA_STREAM(STM32_SDC_SDIO_DMA_STREAM); - SDCD1.sdio = SDIO; -} - -/** - * @brief Configures and activates the SDC peripheral. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * - * @notapi - */ -void sdc_lld_start(SDCDriver *sdcp) { - - /* Checking configuration, using a default if NULL has been passed.*/ - if (sdcp->config == NULL) { - sdcp->config = &sdc_default_cfg; - } - - sdcp->dmamode = STM32_DMA_CR_CHSEL(DMA_CHANNEL) | - STM32_DMA_CR_PL(STM32_SDC_SDIO_DMA_PRIORITY) | - STM32_DMA_CR_PSIZE_WORD | - STM32_DMA_CR_MSIZE_WORD | - STM32_DMA_CR_MINC; - -#if (defined(STM32F4XX) || defined(STM32F2XX)) - sdcp->dmamode |= STM32_DMA_CR_PFCTRL | - STM32_DMA_CR_PBURST_INCR4 | - STM32_DMA_CR_MBURST_INCR4; -#endif - - if (sdcp->state == BLK_STOP) { - /* Note, the DMA must be enabled before the IRQs.*/ - bool b; - b = dmaStreamAllocate(sdcp->dma, STM32_SDC_SDIO_IRQ_PRIORITY, NULL, NULL); - osalDbgAssert(!b, "stream already allocated"); - dmaStreamSetPeripheral(sdcp->dma, &sdcp->sdio->FIFO); -#if (defined(STM32F4XX) || defined(STM32F2XX)) - dmaStreamSetFIFO(sdcp->dma, STM32_DMA_FCR_DMDIS | STM32_DMA_FCR_FTH_FULL); -#endif - nvicEnableVector(STM32_SDIO_NUMBER, STM32_SDC_SDIO_IRQ_PRIORITY); - rccEnableSDIO(FALSE); - } - - /* Configuration, card clock is initially stopped.*/ - sdcp->sdio->POWER = 0; - sdcp->sdio->CLKCR = 0; - sdcp->sdio->DCTRL = 0; - sdcp->sdio->DTIMER = 0; -} - -/** - * @brief Deactivates the SDC peripheral. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * - * @notapi - */ -void sdc_lld_stop(SDCDriver *sdcp) { - - if (sdcp->state != BLK_STOP) { - - /* SDIO deactivation.*/ - sdcp->sdio->POWER = 0; - sdcp->sdio->CLKCR = 0; - sdcp->sdio->DCTRL = 0; - sdcp->sdio->DTIMER = 0; - - /* Clock deactivation.*/ - nvicDisableVector(STM32_SDIO_NUMBER); - dmaStreamRelease(sdcp->dma); - rccDisableSDIO(FALSE); - } -} - -/** - * @brief Starts the SDIO clock and sets it to init mode (400kHz or less). - * - * @param[in] sdcp pointer to the @p SDCDriver object - * - * @notapi - */ -void sdc_lld_start_clk(SDCDriver *sdcp) { - - /* Initial clock setting: 400kHz, 1bit mode.*/ - sdcp->sdio->CLKCR = STM32_SDIO_DIV_LS; - sdcp->sdio->POWER |= SDIO_POWER_PWRCTRL_0 | SDIO_POWER_PWRCTRL_1; - sdcp->sdio->CLKCR |= SDIO_CLKCR_CLKEN; - - /* Clock activation delay.*/ - osalThreadSleep(MS2ST(STM32_SDC_CLOCK_ACTIVATION_DELAY)); -} - -/** - * @brief Sets the SDIO clock to data mode (25MHz or less). - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[in] clk the clock mode - * - * @notapi - */ -void sdc_lld_set_data_clk(SDCDriver *sdcp, sdcbusclk_t clk) { -#if 0 - if (SDC_CLK_50MHz == clk) { - sdcp->sdio->CLKCR = (sdcp->sdio->CLKCR & 0xFFFFFF00U) | STM32_SDIO_DIV_HS - | SDIO_CLKCR_BYPASS; - } - else - sdcp->sdio->CLKCR = (sdcp->sdio->CLKCR & 0xFFFFFF00U) | STM32_SDIO_DIV_HS; -#else - (void)clk; - - sdcp->sdio->CLKCR = (sdcp->sdio->CLKCR & 0xFFFFFF00U) | STM32_SDIO_DIV_HS; -#endif -} - -/** - * @brief Stops the SDIO clock. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * - * @notapi - */ -void sdc_lld_stop_clk(SDCDriver *sdcp) { - - sdcp->sdio->CLKCR = 0; - sdcp->sdio->POWER = 0; -} - -/** - * @brief Switches the bus to 4 bits mode. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[in] mode bus mode - * - * @notapi - */ -void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode) { - uint32_t clk = sdcp->sdio->CLKCR & ~SDIO_CLKCR_WIDBUS; - - switch (mode) { - case SDC_MODE_1BIT: - sdcp->sdio->CLKCR = clk; - break; - case SDC_MODE_4BIT: - sdcp->sdio->CLKCR = clk | SDIO_CLKCR_WIDBUS_0; - break; - case SDC_MODE_8BIT: - sdcp->sdio->CLKCR = clk | SDIO_CLKCR_WIDBUS_1; - break; - } -} - -/** - * @brief Sends an SDIO command with no response expected. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[in] cmd card command - * @param[in] arg command argument - * - * @notapi - */ -void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg) { - - sdcp->sdio->ARG = arg; - sdcp->sdio->CMD = (uint32_t)cmd | SDIO_CMD_CPSMEN; - while ((sdcp->sdio->STA & SDIO_STA_CMDSENT) == 0) - ; - sdcp->sdio->ICR = SDIO_ICR_CMDSENTC; -} - -/** - * @brief Sends an SDIO command with a short response expected. - * @note The CRC is not verified. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[in] cmd card command - * @param[in] arg command argument - * @param[out] resp pointer to the response buffer (one word) - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @notapi - */ -bool sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, - uint32_t *resp) { - uint32_t sta; - - sdcp->sdio->ARG = arg; - sdcp->sdio->CMD = (uint32_t)cmd | SDIO_CMD_WAITRESP_0 | SDIO_CMD_CPSMEN; - while (((sta = sdcp->sdio->STA) & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | - SDIO_STA_CCRCFAIL)) == 0) - ; - sdcp->sdio->ICR = sta & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | - SDIO_STA_CCRCFAIL); - if ((sta & (SDIO_STA_CTIMEOUT)) != 0) { - sdc_lld_collect_errors(sdcp, sta); - return HAL_FAILED; - } - *resp = sdcp->sdio->RESP1; - return HAL_SUCCESS; -} - -/** - * @brief Sends an SDIO command with a short response expected and CRC. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[in] cmd card command - * @param[in] arg command argument - * @param[out] resp pointer to the response buffer (one word) - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @notapi - */ -bool sdc_lld_send_cmd_short_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, - uint32_t *resp) { - uint32_t sta; - - sdcp->sdio->ARG = arg; - sdcp->sdio->CMD = (uint32_t)cmd | SDIO_CMD_WAITRESP_0 | SDIO_CMD_CPSMEN; - while (((sta = sdcp->sdio->STA) & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | - SDIO_STA_CCRCFAIL)) == 0) - ; - sdcp->sdio->ICR = sta & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | SDIO_STA_CCRCFAIL); - if ((sta & (SDIO_STA_CTIMEOUT | SDIO_STA_CCRCFAIL)) != 0) { - sdc_lld_collect_errors(sdcp, sta); - return HAL_FAILED; - } - *resp = sdcp->sdio->RESP1; - return HAL_SUCCESS; -} - -/** - * @brief Sends an SDIO command with a long response expected and CRC. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[in] cmd card command - * @param[in] arg command argument - * @param[out] resp pointer to the response buffer (four words) - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @notapi - */ -bool sdc_lld_send_cmd_long_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, - uint32_t *resp) { - uint32_t sta; - - (void)sdcp; - - sdcp->sdio->ARG = arg; - sdcp->sdio->CMD = (uint32_t)cmd | SDIO_CMD_WAITRESP_0 | SDIO_CMD_WAITRESP_1 | - SDIO_CMD_CPSMEN; - while (((sta = sdcp->sdio->STA) & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | - SDIO_STA_CCRCFAIL)) == 0) - ; - sdcp->sdio->ICR = sta & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | - SDIO_STA_CCRCFAIL); - if ((sta & (STM32_SDIO_STA_ERROR_MASK)) != 0) { - sdc_lld_collect_errors(sdcp, sta); - return HAL_FAILED; - } - /* Save bytes in reverse order because MSB in response comes first.*/ - *resp++ = sdcp->sdio->RESP4; - *resp++ = sdcp->sdio->RESP3; - *resp++ = sdcp->sdio->RESP2; - *resp = sdcp->sdio->RESP1; - return HAL_SUCCESS; -} - -/** - * @brief Reads special registers using data bus. - * @details Needs only during card detection procedure. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[out] buf pointer to the read buffer - * @param[in] bytes number of bytes to read - * @param[in] cmd card command - * @param[in] arg argument for command - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @notapi - */ -bool sdc_lld_read_special(SDCDriver *sdcp, uint8_t *buf, size_t bytes, - uint8_t cmd, uint32_t arg) { - uint32_t resp[1]; - - if(sdc_lld_prepare_read_bytes(sdcp, buf, bytes)) - goto error; - - if (sdc_lld_send_cmd_short_crc(sdcp, cmd, arg, resp) - || MMCSD_R1_ERROR(resp[0])) - goto error; - - if (sdc_lld_wait_transaction_end(sdcp, 1, resp)) - goto error; - - return HAL_SUCCESS; - -error: - sdc_lld_error_cleanup(sdcp, 1, resp); - return HAL_FAILED; -} - -/** - * @brief Reads one or more blocks. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[in] startblk first block to read - * @param[out] buf pointer to the read buffer - * @param[in] blocks number of blocks to read - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @notapi - */ -bool sdc_lld_read_aligned(SDCDriver *sdcp, uint32_t startblk, - uint8_t *buf, uint32_t blocks) { - uint32_t resp[1]; - - osalDbgCheck(blocks < 0x1000000 / MMCSD_BLOCK_SIZE); - - sdcp->sdio->DTIMER = STM32_SDC_READ_TIMEOUT; - - /* Checks for errors and waits for the card to be ready for reading.*/ - if (_sdc_wait_for_transfer_state(sdcp)) - return HAL_FAILED; - - /* Prepares the DMA channel for writing.*/ - dmaStreamSetMemory0(sdcp->dma, buf); - dmaStreamSetTransactionSize(sdcp->dma, - (blocks * MMCSD_BLOCK_SIZE) / sizeof (uint32_t)); - dmaStreamSetMode(sdcp->dma, sdcp->dmamode | STM32_DMA_CR_DIR_P2M); - dmaStreamEnable(sdcp->dma); - - /* Setting up data transfer.*/ - sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS; - sdcp->sdio->MASK = SDIO_MASK_DCRCFAILIE | - SDIO_MASK_DTIMEOUTIE | - SDIO_MASK_STBITERRIE | - SDIO_MASK_RXOVERRIE | - SDIO_MASK_DATAENDIE; - sdcp->sdio->DLEN = blocks * MMCSD_BLOCK_SIZE; - - /* Transaction starts just after DTEN bit setting.*/ - sdcp->sdio->DCTRL = SDIO_DCTRL_DTDIR | - SDIO_DCTRL_DBLOCKSIZE_3 | - SDIO_DCTRL_DBLOCKSIZE_0 | - SDIO_DCTRL_DMAEN | - SDIO_DCTRL_DTEN; - - if (sdc_lld_prepare_read(sdcp, startblk, blocks, resp) == TRUE) - goto error; - - if (sdc_lld_wait_transaction_end(sdcp, blocks, resp) == TRUE) - goto error; - - return HAL_SUCCESS; - -error: - sdc_lld_error_cleanup(sdcp, blocks, resp); - return HAL_FAILED; -} - -/** - * @brief Writes one or more blocks. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[in] startblk first block to write - * @param[out] buf pointer to the write buffer - * @param[in] n number of blocks to write - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @notapi - */ -bool sdc_lld_write_aligned(SDCDriver *sdcp, uint32_t startblk, - const uint8_t *buf, uint32_t blocks) { - uint32_t resp[1]; - - osalDbgCheck(blocks < 0x1000000 / MMCSD_BLOCK_SIZE); - - sdcp->sdio->DTIMER = STM32_SDC_WRITE_TIMEOUT; - - /* Checks for errors and waits for the card to be ready for writing.*/ - if (_sdc_wait_for_transfer_state(sdcp)) - return HAL_FAILED; - - /* Prepares the DMA channel for writing.*/ - dmaStreamSetMemory0(sdcp->dma, buf); - dmaStreamSetTransactionSize(sdcp->dma, - (blocks * MMCSD_BLOCK_SIZE) / sizeof (uint32_t)); - dmaStreamSetMode(sdcp->dma, sdcp->dmamode | STM32_DMA_CR_DIR_M2P); - dmaStreamEnable(sdcp->dma); - - /* Setting up data transfer.*/ - sdcp->sdio->ICR = STM32_SDIO_ICR_ALL_FLAGS; - sdcp->sdio->MASK = SDIO_MASK_DCRCFAILIE | - SDIO_MASK_DTIMEOUTIE | - SDIO_MASK_STBITERRIE | - SDIO_MASK_TXUNDERRIE | - SDIO_MASK_DATAENDIE; - sdcp->sdio->DLEN = blocks * MMCSD_BLOCK_SIZE; - - /* Talk to card what we want from it.*/ - if (sdc_lld_prepare_write(sdcp, startblk, blocks, resp) == TRUE) - goto error; - - /* Transaction starts just after DTEN bit setting.*/ - sdcp->sdio->DCTRL = SDIO_DCTRL_DBLOCKSIZE_3 | - SDIO_DCTRL_DBLOCKSIZE_0 | - SDIO_DCTRL_DMAEN | - SDIO_DCTRL_DTEN; - - if (sdc_lld_wait_transaction_end(sdcp, blocks, resp) == TRUE) - goto error; - - return HAL_SUCCESS; - -error: - sdc_lld_error_cleanup(sdcp, blocks, resp); - return HAL_FAILED; -} - -/** - * @brief Reads one or more blocks. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[in] startblk first block to read - * @param[out] buf pointer to the read buffer - * @param[in] blocks number of blocks to read - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @notapi - */ -bool sdc_lld_read(SDCDriver *sdcp, uint32_t startblk, - uint8_t *buf, uint32_t blocks) { - -#if STM32_SDC_SDIO_UNALIGNED_SUPPORT - if (((unsigned)buf & 3) != 0) { - uint32_t i; - for (i = 0; i < blocks; i++) { - if (sdc_lld_read_aligned(sdcp, startblk, u.buf, 1)) - return HAL_FAILED; - memcpy(buf, u.buf, MMCSD_BLOCK_SIZE); - buf += MMCSD_BLOCK_SIZE; - startblk++; - } - return HAL_SUCCESS; - } -#endif /* STM32_SDC_SDIO_UNALIGNED_SUPPORT */ - return sdc_lld_read_aligned(sdcp, startblk, buf, blocks); -} - -/** - * @brief Writes one or more blocks. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * @param[in] startblk first block to write - * @param[out] buf pointer to the write buffer - * @param[in] blocks number of blocks to write - * - * @return The operation status. - * @retval HAL_SUCCESS operation succeeded. - * @retval HAL_FAILED operation failed. - * - * @notapi - */ -bool sdc_lld_write(SDCDriver *sdcp, uint32_t startblk, - const uint8_t *buf, uint32_t blocks) { - -#if STM32_SDC_SDIO_UNALIGNED_SUPPORT - if (((unsigned)buf & 3) != 0) { - uint32_t i; - for (i = 0; i < blocks; i++) { - memcpy(u.buf, buf, MMCSD_BLOCK_SIZE); - buf += MMCSD_BLOCK_SIZE; - if (sdc_lld_write_aligned(sdcp, startblk, u.buf, 1)) - return HAL_FAILED; - startblk++; - } - return HAL_SUCCESS; - } -#endif /* STM32_SDC_SDIO_UNALIGNED_SUPPORT */ - return sdc_lld_write_aligned(sdcp, startblk, buf, blocks); -} - -/** - * @brief Waits for card idle condition. - * - * @param[in] sdcp pointer to the @p SDCDriver object - * - * @return The operation status. - * @retval HAL_SUCCESS the operation succeeded. - * @retval HAL_FAILED the operation failed. - * - * @api - */ -bool sdc_lld_sync(SDCDriver *sdcp) { - - /* TODO: Implement.*/ - (void)sdcp; - return HAL_SUCCESS; -} - -#endif /* HAL_USE_SDC */ - -/** @} */ diff --git a/os/hal/ports/STM32/LLD/sdc_lld.h b/os/hal/ports/STM32/LLD/sdc_lld.h deleted file mode 100644 index ae258e5f1..000000000 --- a/os/hal/ports/STM32/LLD/sdc_lld.h +++ /dev/null @@ -1,330 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/** - * @file STM32/sdc_lld.h - * @brief STM32 SDC subsystem low level driver header. - * - * @addtogroup SDC - * @{ - */ - -#ifndef _SDC_LLD_H_ -#define _SDC_LLD_H_ - -#if HAL_USE_SDC || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ - -/** - * @brief Value to clear all interrupts flag at once. - */ -#define STM32_SDIO_ICR_ALL_FLAGS (SDIO_ICR_CCRCFAILC | SDIO_ICR_DCRCFAILC | \ - SDIO_ICR_CTIMEOUTC | SDIO_ICR_DTIMEOUTC | \ - SDIO_ICR_TXUNDERRC | SDIO_ICR_RXOVERRC | \ - SDIO_ICR_CMDRENDC | SDIO_ICR_CMDSENTC | \ - SDIO_ICR_DATAENDC | SDIO_ICR_STBITERRC | \ - SDIO_ICR_DBCKENDC | SDIO_ICR_SDIOITC | \ - SDIO_ICR_CEATAENDC) - -/** - * @brief Mask of error flags in STA register. - */ -#define STM32_SDIO_STA_ERROR_MASK (SDIO_STA_CCRCFAIL | SDIO_STA_DCRCFAIL | \ - SDIO_STA_CTIMEOUT | SDIO_STA_DTIMEOUT | \ - SDIO_STA_TXUNDERR | SDIO_STA_RXOVERR) - -/*===========================================================================*/ -/* Driver pre-compile time settings. */ -/*===========================================================================*/ - -/** - * @name Configuration options - * @{ - */ -/** - * @brief SDIO DMA priority (0..3|lowest..highest). - */ -#if !defined(STM32_SDC_SDIO_DMA_PRIORITY) || defined(__DOXYGEN__) -#define STM32_SDC_SDIO_DMA_PRIORITY 3 -#endif - -/** - * @brief SDIO interrupt priority level setting. - */ -#if !defined(STM32_SDC_SDIO_IRQ_PRIORITY) || defined(__DOXYGEN__) -#define STM32_SDC_SDIO_IRQ_PRIORITY 9 -#endif - -/** - * @brief Write timeout in milliseconds. - */ -#if !defined(STM32_SDC_WRITE_TIMEOUT_MS) || defined(__DOXYGEN__) -#define STM32_SDC_WRITE_TIMEOUT_MS 250 -#endif - -/** - * @brief Read timeout in milliseconds. - */ -#if !defined(STM32_SDC_READ_TIMEOUT_MS) || defined(__DOXYGEN__) -#define STM32_SDC_READ_TIMEOUT_MS 25 -#endif - -/** - * @brief Card clock activation delay in milliseconds. - */ -#if !defined(STM32_SDC_CLOCK_ACTIVATION_DELAY) || defined(__DOXYGEN__) -#define STM32_SDC_CLOCK_ACTIVATION_DELAY 10 -#endif - -/** - * @brief Support for unaligned transfers. - * @note Unaligned transfers are much slower. - */ -#if !defined(STM32_SDC_SDIO_UNALIGNED_SUPPORT) || defined(__DOXYGEN__) -#define STM32_SDC_SDIO_UNALIGNED_SUPPORT TRUE -#endif -/** @} */ - -/*===========================================================================*/ -/* Derived constants and error checks. */ -/*===========================================================================*/ - -#if !STM32_HAS_SDIO -#error "SDIO not present in the selected device" -#endif - -#if !OSAL_IRQ_IS_VALID_PRIORITY(STM32_SDC_SDIO_IRQ_PRIORITY) -#error "Invalid IRQ priority assigned to SDIO" -#endif - -#if !STM32_DMA_IS_VALID_PRIORITY(STM32_SDC_SDIO_DMA_PRIORITY) -#error "Invalid DMA priority assigned to SDIO" -#endif - -/* The following checks are only required when there is a DMA able to - reassign streams to different channels.*/ -#if STM32_ADVANCED_DMA -/* Check on the presence of the DMA streams settings in mcuconf.h.*/ -#if !defined(STM32_SDC_SDIO_DMA_STREAM) -#error "SDIO DMA streams not defined" -#endif - -/* Check on the validity of the assigned DMA channels.*/ -#if !STM32_DMA_IS_VALID_ID(STM32_SDC_SDIO_DMA_STREAM, STM32_SDC_SDIO_DMA_MSK) -#error "invalid DMA stream associated to SDIO" -#endif -#endif /* STM32_ADVANCED_DMA */ - -#if !defined(STM32_DMA_REQUIRED) -#define STM32_DMA_REQUIRED -#endif - -/* - * SDIO clock divider. - */ -#if (defined(STM32F4XX) || defined(STM32F2XX)) -#define STM32_SDIO_DIV_HS 0 -#define STM32_SDIO_DIV_LS 120 - -#elif STM32_HCLK > 48000000 -#define STM32_SDIO_DIV_HS 1 -#define STM32_SDIO_DIV_LS 178 -#else - -#define STM32_SDIO_DIV_HS 0 -#define STM32_SDIO_DIV_LS 118 -#endif - -/** - * @brief SDIO data timeouts in SDIO clock cycles. - */ -#if (defined(STM32F4XX) || defined(STM32F2XX)) -#if !STM32_CLOCK48_REQUIRED -#error "SDIO requires STM32_CLOCK48_REQUIRED to be enabled" -#endif - -#if STM32_PLL48CLK != 48000000 -#error "invalid STM32_PLL48CLK clock value" -#endif - -#define STM32_SDC_WRITE_TIMEOUT \ - (((STM32_PLL48CLK / (STM32_SDIO_DIV_HS + 2)) / 1000) * \ - STM32_SDC_WRITE_TIMEOUT_MS) -#define STM32_SDC_READ_TIMEOUT \ - (((STM32_PLL48CLK / (STM32_SDIO_DIV_HS + 2)) / 1000) * \ - STM32_SDC_READ_TIMEOUT_MS) - -#else /* !(defined(STM32F4XX) || defined(STM32F2XX)) */ - -#define STM32_SDC_WRITE_TIMEOUT \ - (((STM32_HCLK / (STM32_SDIO_DIV_HS + 2)) / 1000) * \ - STM32_SDC_WRITE_TIMEOUT_MS) -#define STM32_SDC_READ_TIMEOUT \ - (((STM32_HCLK / (STM32_SDIO_DIV_HS + 2)) / 1000) * \ - STM32_SDC_READ_TIMEOUT_MS) - -#endif /* !(defined(STM32F4XX) || defined(STM32F2XX)) */ - -/*===========================================================================*/ -/* Driver data structures and types. */ -/*===========================================================================*/ - -/** - * @brief Type of card flags. - */ -typedef uint32_t sdcmode_t; - -/** - * @brief SDC Driver condition flags type. - */ -typedef uint32_t sdcflags_t; - -/** - * @brief Type of a structure representing an SDC driver. - */ -typedef struct SDCDriver SDCDriver; - -/** - * @brief Driver configuration structure. - * @note It could be empty on some architectures. - */ -typedef struct { - /** - * @brief Working area for memory consuming operations. - * @note Buffer must be word aligned and big enough to store 512 bytes. - * @note It is mandatory for detecting MMC cards bigger than 2GB else it - * can be @p NULL. SD cards do NOT need it. - * @note Memory pointed by this buffer is only used by @p sdcConnect(), - * afterward it can be reused for other purposes. - */ - uint8_t *scratchpad; - /** - * @brief Bus width. - */ - sdcbusmode_t bus_width; - /* End of the mandatory fields.*/ -} SDCConfig; - -/** - * @brief @p SDCDriver specific methods. - */ -#define _sdc_driver_methods \ - _mmcsd_block_device_methods - -/** - * @extends MMCSDBlockDeviceVMT - * - * @brief @p SDCDriver virtual methods table. - */ -struct SDCDriverVMT { - _sdc_driver_methods -}; - -/** - * @brief Structure representing an SDC driver. - */ -struct SDCDriver { - /** - * @brief Virtual Methods Table. - */ - const struct SDCDriverVMT *vmt; - _mmcsd_block_device_data - /** - * @brief Current configuration data. - */ - const SDCConfig *config; - /** - * @brief Various flags regarding the mounted card. - */ - sdcmode_t cardmode; - /** - * @brief Errors flags. - */ - sdcflags_t errors; - /** - * @brief Card RCA. - */ - uint32_t rca; - /* End of the mandatory fields.*/ - /** - * @brief Thread waiting for I/O completion IRQ. - */ - thread_reference_t thread; - /** - * @brief DMA mode bit mask. - */ - uint32_t dmamode; - /** - * @brief Transmit DMA channel. - */ - const stm32_dma_stream_t *dma; - /** - * @brief Pointer to the SDIO registers block. - * @note Needed for debugging aid. - */ - SDIO_TypeDef *sdio; -}; - -/*===========================================================================*/ -/* Driver macros. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#if !defined(__DOXYGEN__) -extern SDCDriver SDCD1; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - void sdc_lld_init(void); - void sdc_lld_start(SDCDriver *sdcp); - void sdc_lld_stop(SDCDriver *sdcp); - void sdc_lld_start_clk(SDCDriver *sdcp); - void sdc_lld_set_data_clk(SDCDriver *sdcp, sdcbusclk_t clk); - void sdc_lld_stop_clk(SDCDriver *sdcp); - void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode); - void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg); - bool sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, - uint32_t *resp); - bool sdc_lld_send_cmd_short_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, - uint32_t *resp); - bool sdc_lld_send_cmd_long_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, - uint32_t *resp); - bool sdc_lld_read_special(SDCDriver *sdcp, uint8_t *buf, size_t bytes, - uint8_t cmd, uint32_t argument); - bool sdc_lld_read(SDCDriver *sdcp, uint32_t startblk, - uint8_t *buf, uint32_t blocks); - bool sdc_lld_write(SDCDriver *sdcp, uint32_t startblk, - const uint8_t *buf, uint32_t blocks); - bool sdc_lld_sync(SDCDriver *sdcp); - bool sdc_lld_is_card_inserted(SDCDriver *sdcp); - bool sdc_lld_is_write_protected(SDCDriver *sdcp); -#ifdef __cplusplus -} -#endif - -#endif /* HAL_USE_SDC */ - -#endif /* _SDC_LLD_H_ */ - -/** @} */ diff --git a/os/hal/ports/STM32/STM32F0xx/platform.mk b/os/hal/ports/STM32/STM32F0xx/platform.mk index 171a9d5f5..f7a35d22d 100644 --- a/os/hal/ports/STM32/STM32F0xx/platform.mk +++ b/os/hal/ports/STM32/STM32F0xx/platform.mk @@ -5,12 +5,13 @@ HALCONF := $(strip $(shell cat halconf.h | egrep -e "define")) PLATFORMSRC := $(CHIBIOS)/os/hal/ports/common/ARMCMx/nvic.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32F0xx/stm32_dma.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32F0xx/hal_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/STM32F0xx/ext_lld_isr.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/st_lld.c ifneq ($(findstring HAL_USE_ADC TRUE,$(HALCONF)),) -PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/STM32F0xx/adc_lld.c +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv1/adc_lld.c endif ifneq ($(findstring HAL_USE_CAN TRUE,$(HALCONF)),) -PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/can_lld.c +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1/can_lld.c endif ifneq ($(findstring HAL_USE_DAC TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/dac_lld.c @@ -52,8 +53,9 @@ else PLATFORMSRC := $(CHIBIOS)/os/hal/ports/common/ARMCMx/nvic.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32F0xx/stm32_dma.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32F0xx/hal_lld.c \ - $(CHIBIOS)/os/hal/ports/STM32/STM32F0xx/adc_lld.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/can_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/STM32F0xx/ext_lld_isr.c \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv1/adc_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1/can_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/dac_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/ext_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2/pal_lld.c \ @@ -72,7 +74,8 @@ endif # Required include directories PLATFORMINC := $(CHIBIOS)/os/hal/ports/common/ARMCMx \ $(CHIBIOS)/os/hal/ports/STM32/STM32F0xx \ - $(CHIBIOS)/os/hal/ports/STM32/LLD \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv1 \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2 \ diff --git a/os/hal/ports/STM32/STM32F0xx/stm32_registry.h b/os/hal/ports/STM32/STM32F0xx/stm32_registry.h index 273ca70e6..7874cef34 100644 --- a/os/hal/ports/STM32/STM32F0xx/stm32_registry.h +++ b/os/hal/ports/STM32/STM32F0xx/stm32_registry.h @@ -71,7 +71,8 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 28 +#define STM32_EXTI_NUM_LINES 32 +#define STM32_EXTI_IMR_MASK 0x0F940000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -247,7 +248,8 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 28 +#define STM32_EXTI_NUM_LINES 32 +#define STM32_EXTI_IMR_MASK 0x7F840000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -425,7 +427,8 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 28 +#define STM32_EXTI_NUM_LINES 32 +#define STM32_EXTI_IMR_MASK 0x7FF40000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -584,7 +587,8 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 28 +#define STM32_EXTI_NUM_LINES 32 +#define STM32_EXTI_IMR_MASK 0x0FF40000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -742,7 +746,8 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 28 +#define STM32_EXTI_NUM_LINES 32 +#define STM32_EXTI_IMR_MASK 0x7FF40000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -896,7 +901,8 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 28 +#define STM32_EXTI_NUM_LINES 20 +#define STM32_EXTI_IMR_MASK 0xFFF40000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -1062,7 +1068,8 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 28 +#define STM32_EXTI_NUM_LINES 32 +#define STM32_EXTI_IMR_MASK 0x7F840000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE diff --git a/os/hal/ports/STM32/STM32F1xx/ext_lld_isr.c b/os/hal/ports/STM32/STM32F1xx/ext_lld_isr.c index 6dc0e5888..ded663b36 100644 --- a/os/hal/ports/STM32/STM32F1xx/ext_lld_isr.c +++ b/os/hal/ports/STM32/STM32F1xx/ext_lld_isr.c @@ -54,11 +54,14 @@ * @isr */ OSAL_IRQ_HANDLER(Vector58) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 0); - EXTD1.config->channels[0].cb(&EXTD1, 0); + pr = EXTI->PR & EXTI->IMR & (1 << 0); + EXTI->PR = pr; + if (pr & (1 << 0)) + EXTD1.config->channels[0].cb(&EXTD1, 0); OSAL_IRQ_EPILOGUE(); } @@ -69,11 +72,14 @@ OSAL_IRQ_HANDLER(Vector58) { * @isr */ OSAL_IRQ_HANDLER(Vector5C) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 1); - EXTD1.config->channels[1].cb(&EXTD1, 1); + pr = EXTI->PR & EXTI->IMR & (1 << 1); + EXTI->PR = pr; + if (pr & (1 << 1)) + EXTD1.config->channels[1].cb(&EXTD1, 1); OSAL_IRQ_EPILOGUE(); } @@ -84,11 +90,14 @@ OSAL_IRQ_HANDLER(Vector5C) { * @isr */ OSAL_IRQ_HANDLER(Vector60) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 2); - EXTD1.config->channels[2].cb(&EXTD1, 2); + pr = EXTI->PR & EXTI->IMR & (1 << 2); + EXTI->PR = pr; + if (pr & (1 << 2)) + EXTD1.config->channels[2].cb(&EXTD1, 2); OSAL_IRQ_EPILOGUE(); } @@ -99,11 +108,14 @@ OSAL_IRQ_HANDLER(Vector60) { * @isr */ OSAL_IRQ_HANDLER(Vector64) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 3); - EXTD1.config->channels[3].cb(&EXTD1, 3); + pr = EXTI->PR & EXTI->IMR & (1 << 3); + EXTI->PR = pr; + if (pr & (1 << 3)) + EXTD1.config->channels[3].cb(&EXTD1, 3); OSAL_IRQ_EPILOGUE(); } @@ -114,11 +126,14 @@ OSAL_IRQ_HANDLER(Vector64) { * @isr */ OSAL_IRQ_HANDLER(Vector68) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 4); - EXTD1.config->channels[4].cb(&EXTD1, 4); + pr = EXTI->PR & EXTI->IMR & (1 << 4); + EXTI->PR = pr; + if (pr & (1 << 4)) + EXTD1.config->channels[4].cb(&EXTD1, 4); OSAL_IRQ_EPILOGUE(); } @@ -184,11 +199,14 @@ OSAL_IRQ_HANDLER(VectorE0) { * @isr */ OSAL_IRQ_HANDLER(Veector44) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 16); - EXTD1.config->channels[16].cb(&EXTD1, 16); + pr = EXTI->PR & EXTI->IMR & (1 << 16); + EXTI->PR = pr; + if (pr & (1 << 16)) + EXTD1.config->channels[16].cb(&EXTD1, 16); OSAL_IRQ_EPILOGUE(); } @@ -199,11 +217,14 @@ OSAL_IRQ_HANDLER(Veector44) { * @isr */ OSAL_IRQ_HANDLER(VectorE4) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 17); - EXTD1.config->channels[17].cb(&EXTD1, 17); + pr = EXTI->PR & EXTI->IMR & (1 << 17); + EXTI->PR = pr; + if (pr & (1 << 17)) + EXTD1.config->channels[17].cb(&EXTD1, 17); OSAL_IRQ_EPILOGUE(); } @@ -215,11 +236,14 @@ OSAL_IRQ_HANDLER(VectorE4) { * @isr */ OSAL_IRQ_HANDLER(VectorE8) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 18); - EXTD1.config->channels[18].cb(&EXTD1, 18); + pr = EXTI->PR & EXTI->IMR & (1 << 18); + EXTI->PR = pr; + if (pr & (1 << 18)) + EXTD1.config->channels[18].cb(&EXTD1, 18); OSAL_IRQ_EPILOGUE(); } @@ -230,11 +254,14 @@ OSAL_IRQ_HANDLER(VectorE8) { * @isr */ OSAL_IRQ_HANDLER(Vector138) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 19); - EXTD1.config->channels[19].cb(&EXTD1, 19); + pr = EXTI->PR & EXTI->IMR & (1 << 19); + EXTI->PR = pr; + if (pr & (1 << 19)) + EXTD1.config->channels[19].cb(&EXTD1, 19); OSAL_IRQ_EPILOGUE(); } @@ -248,11 +275,14 @@ OSAL_IRQ_HANDLER(Vector138) { * @isr */ OSAL_IRQ_HANDLER(VectorE8) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 18); - EXTD1.config->channels[18].cb(&EXTD1, 18); + pr = EXTI->PR & EXTI->IMR & (1 << 18); + EXTI->PR = pr; + if (pr & (1 << 18)) + EXTD1.config->channels[18].cb(&EXTD1, 18); OSAL_IRQ_EPILOGUE(); } diff --git a/os/hal/ports/STM32/STM32F1xx/platform.mk b/os/hal/ports/STM32/STM32F1xx/platform.mk index fa15a055f..eba585447 100644 --- a/os/hal/ports/STM32/STM32F1xx/platform.mk +++ b/os/hal/ports/STM32/STM32F1xx/platform.mk @@ -9,22 +9,16 @@ PLATFORMSRC := $(CHIBIOS)/os/hal/ports/common/ARMCMx/nvic.c \ ifneq ($(findstring HAL_USE_ADC TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/STM32F1xx/adc_lld.c endif -ifneq ($(findstring HAL_USE_EXT TRUE,$(HALCONF)),) -PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/STM32F1xx/ext_lld_isr.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/ext_lld.c -endif ifneq ($(findstring HAL_USE_CAN TRUE,$(HALCONF)),) -PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/can_lld.c -endif -ifneq ($(findstring HAL_USE_MAC TRUE,$(HALCONF)),) -PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/mac_lld.c -endif -ifneq ($(findstring HAL_USE_SDC TRUE,$(HALCONF)),) -PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/sdc_lld.c +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1/can_lld.c endif ifneq ($(findstring HAL_USE_DAC TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/dac_lld.c endif +ifneq ($(findstring HAL_USE_EXT TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/ext_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/STM32F1xx/ext_lld_isr.c +endif ifneq ($(findstring HAL_USE_PAL TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv1/pal_lld.c endif @@ -34,6 +28,9 @@ endif ifneq ($(findstring HAL_USE_RTC TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv1/rtc_lld.c endif +ifneq ($(findstring HAL_USE_SDC TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SDIOv1/sdc_lld.c +endif ifneq ($(findstring HAL_USE_SPI TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1/spi_lld.c endif @@ -61,14 +58,13 @@ PLATFORMSRC := $(CHIBIOS)/os/hal/ports/common/ARMCMx/nvic.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32F1xx/hal_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32F1xx/adc_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32F1xx/ext_lld_isr.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/can_lld.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/ext_lld.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/mac_lld.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/sdc_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1/can_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/dac_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/ext_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv1/pal_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv1/i2c_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv1/rtc_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/SDIOv1/sdc_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1/spi_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/gpt_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/icu_lld.c \ @@ -82,11 +78,13 @@ endif # Required include directories PLATFORMINC := $(CHIBIOS)/os/hal/ports/common/ARMCMx \ $(CHIBIOS)/os/hal/ports/STM32/STM32F1xx \ - $(CHIBIOS)/os/hal/ports/STM32/LLD \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1 \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv1 \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/SDIOv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv1 \ diff --git a/os/hal/ports/STM32/STM32F1xx/platform_f105_f107.mk b/os/hal/ports/STM32/STM32F1xx/platform_f105_f107.mk index 0a90ed152..446179a3a 100644 --- a/os/hal/ports/STM32/STM32F1xx/platform_f105_f107.mk +++ b/os/hal/ports/STM32/STM32F1xx/platform_f105_f107.mk @@ -9,34 +9,34 @@ PLATFORMSRC := $(CHIBIOS)/os/hal/ports/common/ARMCMx/nvic.c \ ifneq ($(findstring HAL_USE_ADC TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/STM32F1xx/adc_lld.c endif -ifneq ($(findstring HAL_USE_EXT TRUE,$(HALCONF)),) -PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/STM32F1xx/ext_lld_isr.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/ext_lld.c -endif ifneq ($(findstring HAL_USE_CAN TRUE,$(HALCONF)),) -PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/can_lld.c -endif -ifneq ($(findstring HAL_USE_MAC TRUE,$(HALCONF)),) -PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/mac_lld.c -endif -ifneq ($(findstring HAL_USE_SDC TRUE,$(HALCONF)),) -PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/sdc_lld.c +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1/can_lld.c endif ifneq ($(findstring HAL_USE_DAC TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/dac_lld.c endif +ifneq ($(findstring HAL_USE_EXT TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/ext_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/STM32F1xx/ext_lld_isr.c +endif ifneq ($(findstring HAL_USE_PAL TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv1/pal_lld.c endif ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv1/i2c_lld.c endif +ifneq ($(findstring HAL_USE_MAC TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/MACv1/mac_lld.c +endif ifneq ($(findstring HAL_USE_USB TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/OTGv1/usb_lld.c endif ifneq ($(findstring HAL_USE_RTC TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv1/rtc_lld.c endif +ifneq ($(findstring HAL_USE_SDC TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SDIOv1/sdc_lld.c +endif ifneq ($(findstring HAL_USE_SPI TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1/spi_lld.c endif @@ -61,15 +61,15 @@ PLATFORMSRC := $(CHIBIOS)/os/hal/ports/common/ARMCMx/nvic.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32F1xx/hal_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32F1xx/adc_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32F1xx/ext_lld_isr.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/can_lld.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/ext_lld.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/mac_lld.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/sdc_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1/can_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/dac_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/ext_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv1/pal_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv1/i2c_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/MACv1/mac_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/OTGv1/usb_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv1/rtc_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/SDIOv1/sdc_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1/spi_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/gpt_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/icu_lld.c \ @@ -82,12 +82,14 @@ endif # Required include directories PLATFORMINC := $(CHIBIOS)/os/hal/ports/common/ARMCMx \ $(CHIBIOS)/os/hal/ports/STM32/STM32F1xx \ - $(CHIBIOS)/os/hal/ports/STM32/LLD \ $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1 \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv1 \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/MACv1 \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/OTGv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv1 \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/SDIOv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1 \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv1 \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/OTGv1 + $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv1 diff --git a/os/hal/ports/STM32/STM32F1xx/stm32_registry.h b/os/hal/ports/STM32/STM32F1xx/stm32_registry.h index 015c8423a..5517505cf 100644 --- a/os/hal/ports/STM32/STM32F1xx/stm32_registry.h +++ b/os/hal/ports/STM32/STM32F1xx/stm32_registry.h @@ -68,7 +68,8 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 18 +#define STM32_EXTI_NUM_LINES 18 +#define STM32_EXTI_IMR_MASK 0xFFFC0000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -231,7 +232,8 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 19 +#define STM32_EXTI_NUM_LINES 19 +#define STM32_EXTI_IMR_MASK 0xFFF80000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -402,7 +404,8 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 19 +#define STM32_EXTI_NUM_LINES 19 +#define STM32_EXTI_IMR_MASK 0xFFF80000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -546,7 +549,8 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 19 +#define STM32_EXTI_NUM_LINES 19 +#define STM32_EXTI_IMR_MASK 0xFFF80000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -709,7 +713,8 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 19 +#define STM32_EXTI_NUM_LINES 19 +#define STM32_EXTI_IMR_MASK 0xFFF80000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -908,7 +913,8 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 19 +#define STM32_EXTI_NUM_LINES 19 +#define STM32_EXTI_IMR_MASK 0xFFF80000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -1107,7 +1113,8 @@ #define STM32_HAS_ETH TRUE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 20 +#define STM32_EXTI_NUM_LINES 20 +#define STM32_EXTI_IMR_MASK 0xFFF00000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE diff --git a/os/hal/ports/STM32/STM32F37x/ext_lld_isr.c b/os/hal/ports/STM32/STM32F37x/ext_lld_isr.c index 24ba72a0d..57fc65bef 100644 --- a/os/hal/ports/STM32/STM32F37x/ext_lld_isr.c +++ b/os/hal/ports/STM32/STM32F37x/ext_lld_isr.c @@ -48,6 +48,7 @@ /* Driver interrupt handlers. */ /*===========================================================================*/ +#if !defined(STM32_DISABLE_EXTI0_HANDLER) /** * @brief EXTI[0] interrupt handler. * @@ -65,7 +66,9 @@ OSAL_IRQ_HANDLER(Vector58) { OSAL_IRQ_EPILOGUE(); } +#endif +#if !defined(STM32_DISABLE_EXTI1_HANDLER) /** * @brief EXTI[1] interrupt handler. * @@ -83,7 +86,9 @@ OSAL_IRQ_HANDLER(Vector5C) { OSAL_IRQ_EPILOGUE(); } +#endif +#if !defined(STM32_DISABLE_EXTI2_HANDLER) /** * @brief EXTI[2] interrupt handler. * @@ -101,7 +106,9 @@ OSAL_IRQ_HANDLER(Vector60) { OSAL_IRQ_EPILOGUE(); } +#endif +#if !defined(STM32_DISABLE_EXTI3_HANDLER) /** * @brief EXTI[3] interrupt handler. * @@ -119,7 +126,9 @@ OSAL_IRQ_HANDLER(Vector64) { OSAL_IRQ_EPILOGUE(); } +#endif +#if !defined(STM32_DISABLE_EXTI4_HANDLER) /** * @brief EXTI[4] interrupt handler. * @@ -137,7 +146,9 @@ OSAL_IRQ_HANDLER(Vector68) { OSAL_IRQ_EPILOGUE(); } +#endif +#if !defined(STM32_DISABLE_EXTI5_9_HANDLER) /** * @brief EXTI[5]...EXTI[9] interrupt handler. * @@ -164,7 +175,9 @@ OSAL_IRQ_HANDLER(Vector9C) { OSAL_IRQ_EPILOGUE(); } +#endif +#if !defined(STM32_DISABLE_EXTI10_15_HANDLER) /** * @brief EXTI[10]...EXTI[15] interrupt handler. * @@ -193,7 +206,9 @@ OSAL_IRQ_HANDLER(VectorE0) { OSAL_IRQ_EPILOGUE(); } +#endif +#if !defined(STM32_DISABLE_EXTI16_HANDLER) /** * @brief EXTI[16] interrupt handler (PVD). * @@ -211,7 +226,9 @@ OSAL_IRQ_HANDLER(Vector44) { OSAL_IRQ_EPILOGUE(); } +#endif +#if !defined(STM32_DISABLE_EXTI17_HANDLER) /** * @brief EXTI[17] interrupt handler (RTC Alarm). * @@ -229,7 +246,9 @@ OSAL_IRQ_HANDLER(VectorE4) { OSAL_IRQ_EPILOGUE(); } +#endif +#if STM32_HAS_USB && !defined(STM32_DISABLE_EXTI18_HANDLER) /** * @brief EXTI[18] interrupt handler (USB Wakeup). * @@ -247,7 +266,9 @@ OSAL_IRQ_HANDLER(Vector170) { OSAL_IRQ_EPILOGUE(); } +#endif +#if !defined(STM32_DISABLE_EXTI19_HANDLER) /** * @brief EXTI[19] interrupt handler (Tamper TimeStamp). * @@ -265,7 +286,9 @@ OSAL_IRQ_HANDLER(Vector48) { OSAL_IRQ_EPILOGUE(); } +#endif +#if !defined(STM32_DISABLE_EXTI20_HANDLER) /** * @brief EXTI[20] interrupt handler (RTC Wakeup). * @@ -283,7 +306,9 @@ OSAL_IRQ_HANDLER(Vector4C) { OSAL_IRQ_EPILOGUE(); } +#endif +#if !defined(STM32_DISABLE_EXTI21_22_HANDLER) /** * @brief EXTI[21]..EXTI[22] interrupt handler (COMP1, COMP2). * @@ -303,6 +328,7 @@ OSAL_IRQ_HANDLER(Vector140) { OSAL_IRQ_EPILOGUE(); } +#endif /*===========================================================================*/ /* Driver exported functions. */ diff --git a/os/hal/ports/STM32/STM32F37x/platform.mk b/os/hal/ports/STM32/STM32F37x/platform.mk index c8d65981b..8fc7c2854 100644 --- a/os/hal/ports/STM32/STM32F37x/platform.mk +++ b/os/hal/ports/STM32/STM32F37x/platform.mk @@ -9,16 +9,16 @@ PLATFORMSRC := $(CHIBIOS)/os/hal/ports/common/ARMCMx/nvic.c \ ifneq ($(findstring HAL_USE_ADC TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/STM32F37x/adc_lld.c endif -ifneq ($(findstring HAL_USE_EXT TRUE,$(HALCONF)),) -PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/STM32F37x/ext_lld_isr.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/ext_lld.c -endif ifneq ($(findstring HAL_USE_CAN TRUE,$(HALCONF)),) -PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/can_lld.c +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1/can_lld.c endif ifneq ($(findstring HAL_USE_DAC TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/dac_lld.c endif +ifneq ($(findstring HAL_USE_EXT TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/ext_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/STM32F37x/ext_lld_isr.c +endif ifneq ($(findstring HAL_USE_PAL TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2/pal_lld.c endif @@ -55,9 +55,9 @@ PLATFORMSRC := $(CHIBIOS)/os/hal/ports/common/ARMCMx/nvic.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32F37x/hal_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32F37x/adc_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32F37x/ext_lld_isr.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/can_lld.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/ext_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1/can_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/dac_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/ext_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2/pal_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv2/i2c_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv2/rtc_lld.c \ @@ -74,8 +74,9 @@ endif # Required include directories PLATFORMINC := $(CHIBIOS)/os/hal/ports/common/ARMCMx \ $(CHIBIOS)/os/hal/ports/STM32/STM32F37x \ - $(CHIBIOS)/os/hal/ports/STM32/LLD \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1 \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv2 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv2 \ diff --git a/os/hal/ports/STM32/STM32F37x/stm32_registry.h b/os/hal/ports/STM32/STM32F37x/stm32_registry.h index bc25f1d7c..52676b5f7 100644 --- a/os/hal/ports/STM32/STM32F37x/stm32_registry.h +++ b/os/hal/ports/STM32/STM32F37x/stm32_registry.h @@ -73,7 +73,8 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 29 +#define STM32_EXTI_NUM_LINES 29 +#define STM32_EXTI_IMR_MASK 0xE0000000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -277,7 +278,8 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 29 +#define STM32_EXTI_NUM_LINES 29 +#define STM32_EXTI_IMR_MASK 0xE0000000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE diff --git a/os/hal/ports/STM32/STM32F3xx/ext_lld_isr.c b/os/hal/ports/STM32/STM32F3xx/ext_lld_isr.c index 7d5e38cff..e83378c16 100644 --- a/os/hal/ports/STM32/STM32F3xx/ext_lld_isr.c +++ b/os/hal/ports/STM32/STM32F3xx/ext_lld_isr.c @@ -55,11 +55,14 @@ * @isr */ OSAL_IRQ_HANDLER(Vector58) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 0); - EXTD1.config->channels[0].cb(&EXTD1, 0); + pr = EXTI->PR & EXTI->IMR & (1 << 0); + EXTI->PR = pr; + if (pr & (1 << 0)) + EXTD1.config->channels[0].cb(&EXTD1, 0); OSAL_IRQ_EPILOGUE(); } @@ -72,11 +75,14 @@ OSAL_IRQ_HANDLER(Vector58) { * @isr */ OSAL_IRQ_HANDLER(Vector5C) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 1); - EXTD1.config->channels[1].cb(&EXTD1, 1); + pr = EXTI->PR & EXTI->IMR & (1 << 1); + EXTI->PR = pr; + if (pr & (1 << 1)) + EXTD1.config->channels[1].cb(&EXTD1, 1); OSAL_IRQ_EPILOGUE(); } @@ -89,11 +95,14 @@ OSAL_IRQ_HANDLER(Vector5C) { * @isr */ OSAL_IRQ_HANDLER(Vector60) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 2); - EXTD1.config->channels[2].cb(&EXTD1, 2); + pr = EXTI->PR & EXTI->IMR & (1 << 2); + EXTI->PR = pr; + if (pr & (1 << 2)) + EXTD1.config->channels[2].cb(&EXTD1, 2); OSAL_IRQ_EPILOGUE(); } @@ -106,11 +115,14 @@ OSAL_IRQ_HANDLER(Vector60) { * @isr */ OSAL_IRQ_HANDLER(Vector64) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 3); - EXTD1.config->channels[3].cb(&EXTD1, 3); + pr = EXTI->PR & EXTI->IMR & (1 << 3); + EXTI->PR = pr; + if (pr & (1 << 3)) + EXTD1.config->channels[3].cb(&EXTD1, 3); OSAL_IRQ_EPILOGUE(); } @@ -123,11 +135,14 @@ OSAL_IRQ_HANDLER(Vector64) { * @isr */ OSAL_IRQ_HANDLER(Vector68) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 4); - EXTD1.config->channels[4].cb(&EXTD1, 4); + pr = EXTI->PR & EXTI->IMR & (1 << 4); + EXTI->PR = pr; + if (pr & (1 << 4)) + EXTD1.config->channels[4].cb(&EXTD1, 4); OSAL_IRQ_EPILOGUE(); } @@ -144,7 +159,8 @@ OSAL_IRQ_HANDLER(Vector9C) { OSAL_IRQ_PROLOGUE(); - pr = EXTI->PR & ((1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9)); + pr = EXTI->PR & EXTI->IMR & ((1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | + (1 << 9)); EXTI->PR = pr; if (pr & (1 << 5)) EXTD1.config->channels[5].cb(&EXTD1, 5); @@ -172,8 +188,8 @@ OSAL_IRQ_HANDLER(VectorE0) { OSAL_IRQ_PROLOGUE(); - pr = EXTI->PR & ((1 << 10) | (1 << 11) | (1 << 12) | (1 << 13) | (1 << 14) | - (1 << 15)); + pr = EXTI->PR & EXTI->IMR & ((1 << 10) | (1 << 11) | (1 << 12) | (1 << 13) | + (1 << 14) | (1 << 15)); EXTI->PR = pr; if (pr & (1 << 10)) EXTD1.config->channels[10].cb(&EXTD1, 10); @@ -199,11 +215,14 @@ OSAL_IRQ_HANDLER(VectorE0) { * @isr */ OSAL_IRQ_HANDLER(Vector44) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 16); - EXTD1.config->channels[16].cb(&EXTD1, 16); + pr = EXTI->PR & EXTI->IMR & (1 << 16); + EXTI->PR = pr; + if (pr & (1 << 16)) + EXTD1.config->channels[16].cb(&EXTD1, 16); OSAL_IRQ_EPILOGUE(); } @@ -216,11 +235,14 @@ OSAL_IRQ_HANDLER(Vector44) { * @isr */ OSAL_IRQ_HANDLER(VectorE4) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 17); - EXTD1.config->channels[17].cb(&EXTD1, 17); + pr = EXTI->PR & EXTI->IMR & (1 << 17); + EXTI->PR = pr; + if (pr & (1 << 17)) + EXTD1.config->channels[17].cb(&EXTD1, 17); OSAL_IRQ_EPILOGUE(); } @@ -233,11 +255,14 @@ OSAL_IRQ_HANDLER(VectorE4) { * @isr */ OSAL_IRQ_HANDLER(VectorE8) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 18); - EXTD1.config->channels[18].cb(&EXTD1, 18); + pr = EXTI->PR & EXTI->IMR & (1 << 18); + EXTI->PR = pr; + if (pr & (1 << 18)) + EXTD1.config->channels[18].cb(&EXTD1, 18); OSAL_IRQ_EPILOGUE(); } @@ -250,11 +275,14 @@ OSAL_IRQ_HANDLER(VectorE8) { * @isr */ OSAL_IRQ_HANDLER(Vector48) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 19); - EXTD1.config->channels[19].cb(&EXTD1, 19); + pr = EXTI->PR & EXTI->IMR & (1 << 19); + EXTI->PR = pr; + if (pr & (1 << 19)) + EXTD1.config->channels[19].cb(&EXTD1, 19); OSAL_IRQ_EPILOGUE(); } @@ -267,11 +295,14 @@ OSAL_IRQ_HANDLER(Vector48) { * @isr */ OSAL_IRQ_HANDLER(Vector4C) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 20); - EXTD1.config->channels[20].cb(&EXTD1, 20); + pr = EXTI->PR & EXTI->IMR & (1 << 20); + EXTI->PR = pr; + if (pr & (1 << 20)) + EXTD1.config->channels[20].cb(&EXTD1, 20); OSAL_IRQ_EPILOGUE(); } @@ -288,7 +319,7 @@ OSAL_IRQ_HANDLER(Vector140) { OSAL_IRQ_PROLOGUE(); - pr = EXTI->PR & ((1 << 21) | (1 << 22) | (1 << 29)); + pr = EXTI->PR & EXTI->IMR & ((1 << 21) | (1 << 22) | (1 << 29)); EXTI->PR = pr; if (pr & (1 << 21)) EXTD1.config->channels[21].cb(&EXTD1, 21); @@ -312,14 +343,14 @@ OSAL_IRQ_HANDLER(Vector144) { OSAL_IRQ_PROLOGUE(); - pr = EXTI->PR & ((1 << 30) | (1 << 31)); + pr = EXTI->PR & EXTI->IMR & ((1 << 30) | (1 << 31)); EXTI->PR = pr; if (pr & (1 << 30)) EXTD1.config->channels[30].cb(&EXTD1, 30); if (pr & (1 << 31)) EXTD1.config->channels[31].cb(&EXTD1, 31); - pr = EXTI->PR2 & (1 << 0); + pr = EXTI->PR2 & EXTI->IMR2 & (1 << 0); EXTI->PR2 = pr; if (pr & (1 << 0)) EXTD1.config->channels[32].cb(&EXTD1, 32); @@ -335,11 +366,14 @@ OSAL_IRQ_HANDLER(Vector144) { * @isr */ OSAL_IRQ_HANDLER(RTC_WKUP_IRQHandler) { + uint32_t pr2; OSAL_IRQ_PROLOGUE(); - EXTI->PR2 = (1 << 1); - EXTD1.config->channels[33].cb(&EXTD1, 33); + pr2 = EXTI->PR2 & EXTI->IMR & (1 << 1); + EXTI->PR2 = pr2; + if (pr2 & (1 << 1)) + EXTD1.config->channels[33].cb(&EXTD1, 33); OSAL_IRQ_EPILOGUE(); } @@ -372,7 +406,7 @@ void ext_lld_exti_irq_enable(void) { nvicEnableVector(RTC_WKUP_IRQn, STM32_EXT_EXTI20_IRQ_PRIORITY); nvicEnableVector(COMP1_2_3_IRQn, STM32_EXT_EXTI21_22_29_IRQ_PRIORITY); nvicEnableVector(COMP4_5_6_IRQn, STM32_EXT_EXTI30_32_IRQ_PRIORITY); -#if STM32_EXTI_NUM_CHANNELS >= 34 +#if STM32_EXTI_NUM_LINES >= 34 nvicEnableVector(COMP7_IRQn, STM32_EXT_EXTI33_IRQ_PRIORITY); #endif } @@ -400,7 +434,7 @@ void ext_lld_exti_irq_disable(void) { nvicDisableVector(RTC_WKUP_IRQn); nvicDisableVector(COMP1_2_3_IRQn); nvicDisableVector(COMP4_5_6_IRQn); -#if STM32_EXTI_NUM_CHANNELS >= 34 +#if STM32_EXTI_NUM_LINES >= 34 nvicDisableVector(COMP7_IRQn); #endif } diff --git a/os/hal/ports/STM32/STM32F3xx/platform.mk b/os/hal/ports/STM32/STM32F3xx/platform.mk index 8dfd9cf13..0f0837cab 100644 --- a/os/hal/ports/STM32/STM32F3xx/platform.mk +++ b/os/hal/ports/STM32/STM32F3xx/platform.mk @@ -9,16 +9,16 @@ PLATFORMSRC := $(CHIBIOS)/os/hal/ports/common/ARMCMx/nvic.c \ ifneq ($(findstring HAL_USE_ADC TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/STM32F3xx/adc_lld.c endif -ifneq ($(findstring HAL_USE_EXT TRUE,$(HALCONF)),) -PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/STM32F3xx/ext_lld_isr.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/ext_lld.c -endif ifneq ($(findstring HAL_USE_CAN TRUE,$(HALCONF)),) -PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/can_lld.c +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1/can_lld.c endif ifneq ($(findstring HAL_USE_DAC TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/dac_lld.c endif +ifneq ($(findstring HAL_USE_EXT TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/ext_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/STM32F3xx/ext_lld_isr.c +endif ifneq ($(findstring HAL_USE_PAL TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2/pal_lld.c endif @@ -55,9 +55,9 @@ PLATFORMSRC := $(CHIBIOS)/os/hal/ports/common/ARMCMx/nvic.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32F3xx/hal_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32F3xx/adc_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32F3xx/ext_lld_isr.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/can_lld.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/ext_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1/can_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/dac_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/ext_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2/pal_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv2/i2c_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv2/rtc_lld.c \ @@ -74,8 +74,9 @@ endif # Required include directories PLATFORMINC := $(CHIBIOS)/os/hal/ports/common/ARMCMx \ $(CHIBIOS)/os/hal/ports/STM32/STM32F3xx \ - $(CHIBIOS)/os/hal/ports/STM32/LLD \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1 \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv2 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv2 \ diff --git a/os/hal/ports/STM32/STM32F3xx/stm32_registry.h b/os/hal/ports/STM32/STM32F3xx/stm32_registry.h index 067f5dc00..02f095809 100644 --- a/os/hal/ports/STM32/STM32F3xx/stm32_registry.h +++ b/os/hal/ports/STM32/STM32F3xx/stm32_registry.h @@ -79,7 +79,9 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 34 +#define STM32_EXTI_NUM_LINES 34 +#define STM32_EXTI_IMR_MASK 0x1F800000U +#define STM32_EXTI_IMR2_MASK 0xFFFFFFFCU /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -274,7 +276,9 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 34 +#define STM32_EXTI_NUM_LINES 34 +#define STM32_EXTI_IMR_MASK 0x1F800000U +#define STM32_EXTI_IMR2_MASK 0xFFFFFFFCU /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -446,7 +450,9 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 33 +#define STM32_EXTI_NUM_LINES 33 +#define STM32_EXTI_IMR_MASK 0x1F800000U +#define STM32_EXTI_IMR2_MASK 0xFFFFFFFCU /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -617,7 +623,9 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 33 +#define STM32_EXTI_NUM_LINES 33 +#define STM32_EXTI_IMR_MASK 0x1F800000U +#define STM32_EXTI_IMR2_MASK 0xFFFFFFFCU /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -791,7 +799,9 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 34 +#define STM32_EXTI_NUM_LINES 34 +#define STM32_EXTI_IMR_MASK 0x1F800000U +#define STM32_EXTI_IMR2_MASK 0xFFFFFFFCU /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -977,7 +987,9 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 33 +#define STM32_EXTI_NUM_LINES 33 +#define STM32_EXTI_IMR_MASK 0x1F800000U +#define STM32_EXTI_IMR2_MASK 0xFFFFFFFCU /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -1151,7 +1163,9 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 33 +#define STM32_EXTI_NUM_LINES 33 +#define STM32_EXTI_IMR_MASK 0x1F800000U +#define STM32_EXTI_IMR2_MASK 0xFFFFFFFCU /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -1322,7 +1336,9 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 34 +#define STM32_EXTI_NUM_LINES 34 +#define STM32_EXTI_IMR_MASK 0x1F800000U +#define STM32_EXTI_IMR2_MASK 0xFFFFFFFCU /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -1512,7 +1528,9 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 33 +#define STM32_EXTI_NUM_LINES 33 +#define STM32_EXTI_IMR_MASK 0x1F800000U +#define STM32_EXTI_IMR2_MASK 0xFFFFFFFCU /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE diff --git a/os/hal/ports/STM32/STM32F4xx/ext_lld_isr.c b/os/hal/ports/STM32/STM32F4xx/ext_lld_isr.c index 3a877c7d9..36d4f5b36 100644 --- a/os/hal/ports/STM32/STM32F4xx/ext_lld_isr.c +++ b/os/hal/ports/STM32/STM32F4xx/ext_lld_isr.c @@ -54,11 +54,14 @@ * @isr */ OSAL_IRQ_HANDLER(Vector58) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 0); - EXTD1.config->channels[0].cb(&EXTD1, 0); + pr = EXTI->PR & EXTI->IMR & (1 << 0); + EXTI->PR = pr; + if (pr & (1 << 0)) + EXTD1.config->channels[0].cb(&EXTD1, 0); OSAL_IRQ_EPILOGUE(); } @@ -69,11 +72,14 @@ OSAL_IRQ_HANDLER(Vector58) { * @isr */ OSAL_IRQ_HANDLER(Vector5C) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 1); - EXTD1.config->channels[1].cb(&EXTD1, 1); + pr = EXTI->PR & EXTI->IMR & (1 << 1); + EXTI->PR = pr; + if (pr & (1 << 1)) + EXTD1.config->channels[1].cb(&EXTD1, 1); OSAL_IRQ_EPILOGUE(); } @@ -84,11 +90,14 @@ OSAL_IRQ_HANDLER(Vector5C) { * @isr */ OSAL_IRQ_HANDLER(Vector60) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 2); - EXTD1.config->channels[2].cb(&EXTD1, 2); + pr = EXTI->PR & EXTI->IMR & (1 << 2); + EXTI->PR = pr; + if (pr & (1 << 2)) + EXTD1.config->channels[2].cb(&EXTD1, 2); OSAL_IRQ_EPILOGUE(); } @@ -99,11 +108,14 @@ OSAL_IRQ_HANDLER(Vector60) { * @isr */ OSAL_IRQ_HANDLER(Vector64) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 3); - EXTD1.config->channels[3].cb(&EXTD1, 3); + pr = EXTI->PR & EXTI->IMR & (1 << 3); + EXTI->PR = pr; + if (pr & (1 << 3)) + EXTD1.config->channels[3].cb(&EXTD1, 3); OSAL_IRQ_EPILOGUE(); } @@ -114,11 +126,14 @@ OSAL_IRQ_HANDLER(Vector64) { * @isr */ OSAL_IRQ_HANDLER(Vector68) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 4); - EXTD1.config->channels[4].cb(&EXTD1, 4); + pr = EXTI->PR & EXTI->IMR & (1 << 4); + EXTI->PR = pr; + if (pr & (1 << 4)) + EXTD1.config->channels[4].cb(&EXTD1, 4); OSAL_IRQ_EPILOGUE(); } @@ -133,7 +148,8 @@ OSAL_IRQ_HANDLER(Vector9C) { OSAL_IRQ_PROLOGUE(); - pr = EXTI->PR & ((1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9)); + pr = EXTI->PR & EXTI->IMR & ((1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | + (1 << 9)); EXTI->PR = pr; if (pr & (1 << 5)) EXTD1.config->channels[5].cb(&EXTD1, 5); @@ -159,8 +175,8 @@ OSAL_IRQ_HANDLER(VectorE0) { OSAL_IRQ_PROLOGUE(); - pr = EXTI->PR & ((1 << 10) | (1 << 11) | (1 << 12) | (1 << 13) | (1 << 14) | - (1 << 15)); + pr = EXTI->PR & EXTI->IMR & ((1 << 10) | (1 << 11) | (1 << 12) | (1 << 13) | + (1 << 14) | (1 << 15)); EXTI->PR = pr; if (pr & (1 << 10)) EXTD1.config->channels[10].cb(&EXTD1, 10); @@ -184,11 +200,14 @@ OSAL_IRQ_HANDLER(VectorE0) { * @isr */ OSAL_IRQ_HANDLER(Vector44) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 16); - EXTD1.config->channels[16].cb(&EXTD1, 16); + pr = EXTI->PR & EXTI->IMR & (1 << 16); + EXTI->PR = pr; + if (pr & (1 << 16)) + EXTD1.config->channels[16].cb(&EXTD1, 16); OSAL_IRQ_EPILOGUE(); } @@ -199,11 +218,14 @@ OSAL_IRQ_HANDLER(Vector44) { * @isr */ OSAL_IRQ_HANDLER(VectorE4) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 17); - EXTD1.config->channels[17].cb(&EXTD1, 17); + pr = EXTI->PR & EXTI->IMR & (1 << 17); + EXTI->PR = pr; + if (pr & (1 << 17)) + EXTD1.config->channels[17].cb(&EXTD1, 17); OSAL_IRQ_EPILOGUE(); } @@ -214,44 +236,53 @@ OSAL_IRQ_HANDLER(VectorE4) { * @isr */ OSAL_IRQ_HANDLER(VectorE8) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 18); - EXTD1.config->channels[18].cb(&EXTD1, 18); + pr = EXTI->PR & EXTI->IMR & (1 << 18); + EXTI->PR = pr; + if (pr & (1 << 18)) + EXTD1.config->channels[18].cb(&EXTD1, 18); OSAL_IRQ_EPILOGUE(); } -#if STM32_HAS_ETH +#if STM32_HAS_ETH || defined(__DOXYGEN__) /** * @brief EXTI[19] interrupt handler (ETH_WKUP). * * @isr */ OSAL_IRQ_HANDLER(Vector138) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 19); - EXTD1.config->channels[19].cb(&EXTD1, 19); + pr = EXTI->PR & EXTI->IMR & (1 << 19); + EXTI->PR = pr; + if (pr & (1 << 19)) + EXTD1.config->channels[19].cb(&EXTD1, 19); OSAL_IRQ_EPILOGUE(); } #endif /* STM32_HAS_ETH */ -#if STM32_HAS_OTG2 +#if STM32_HAS_OTG2 || defined(__DOXYGEN__) /** * @brief EXTI[20] interrupt handler (OTG_HS_WKUP). * * @isr */ OSAL_IRQ_HANDLER(Vector170) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 20); - EXTD1.config->channels[20].cb(&EXTD1, 20); + pr = EXTI->PR & EXTI->IMR & (1 << 20); + EXTI->PR = pr; + if (pr & (1 << 20)) + EXTD1.config->channels[20].cb(&EXTD1, 20); OSAL_IRQ_EPILOGUE(); } @@ -264,11 +295,14 @@ OSAL_IRQ_HANDLER(Vector170) { * @isr */ OSAL_IRQ_HANDLER(Vector48) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 21); - EXTD1.config->channels[21].cb(&EXTD1, 21); + pr = EXTI->PR & EXTI->IMR & (1 << 21); + EXTI->PR = pr; + if (pr & (1 << 21)) + EXTD1.config->channels[21].cb(&EXTD1, 21); OSAL_IRQ_EPILOGUE(); } @@ -280,11 +314,14 @@ OSAL_IRQ_HANDLER(Vector48) { * @isr */ OSAL_IRQ_HANDLER(Vector4C) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 22); - EXTD1.config->channels[22].cb(&EXTD1, 22); + pr = EXTI->PR & EXTI->IMR & (1 << 22); + EXTI->PR = pr; + if (pr & (1 << 22)) + EXTD1.config->channels[22].cb(&EXTD1, 22); OSAL_IRQ_EPILOGUE(); } diff --git a/os/hal/ports/STM32/STM32F4xx/platform.mk b/os/hal/ports/STM32/STM32F4xx/platform.mk index 3b6566efe..336991b75 100644 --- a/os/hal/ports/STM32/STM32F4xx/platform.mk +++ b/os/hal/ports/STM32/STM32F4xx/platform.mk @@ -9,28 +9,25 @@ PLATFORMSRC := $(CHIBIOS)/os/hal/ports/common/ARMCMx/nvic.c \ ifneq ($(findstring HAL_USE_ADC TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/STM32F4xx/adc_lld.c endif -ifneq ($(findstring HAL_USE_EXT TRUE,$(HALCONF)),) -PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/STM32F4xx/ext_lld_isr.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/ext_lld.c -endif ifneq ($(findstring HAL_USE_CAN TRUE,$(HALCONF)),) -PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/can_lld.c -endif -ifneq ($(findstring HAL_USE_MAC TRUE,$(HALCONF)),) -PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/mac_lld.c -endif -ifneq ($(findstring HAL_USE_SDC TRUE,$(HALCONF)),) -PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/sdc_lld.c +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/CANV1/can_lld.c endif ifneq ($(findstring HAL_USE_DAC TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/dac_lld.c endif +ifneq ($(findstring HAL_USE_EXT TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/ext_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/STM32F4xx/ext_lld_isr.c +endif ifneq ($(findstring HAL_USE_PAL TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2/pal_lld.c endif ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv1/i2c_lld.c endif +ifneq ($(findstring HAL_USE_MAC TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/MACv1/mac_lld.c +endif ifneq ($(findstring HAL_USE_USB TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/OTGv1/usb_lld.c endif @@ -40,6 +37,9 @@ endif ifneq ($(findstring HAL_USE_I2S TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1/i2s_lld.c endif +ifneq ($(findstring HAL_USE_SDC TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SDIOv1/sdc_lld.c +endif ifneq ($(findstring HAL_USE_SPI TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1/spi_lld.c endif @@ -64,15 +64,15 @@ PLATFORMSRC := $(CHIBIOS)/os/hal/ports/common/ARMCMx/nvic.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32F4xx/hal_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32F4xx/adc_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32F4xx/ext_lld_isr.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/can_lld.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/ext_lld.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/mac_lld.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/sdc_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1/can_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/ext_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/dac_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2/pal_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv1/i2c_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/MACv1/mac_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/OTGv1/usb_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv2/rtc_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/SDIOv1/sdc_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1/i2s_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1/spi_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/gpt_lld.c \ @@ -86,12 +86,15 @@ endif # Required include directories PLATFORMINC := $(CHIBIOS)/os/hal/ports/common/ARMCMx \ $(CHIBIOS)/os/hal/ports/STM32/STM32F4xx \ - $(CHIBIOS)/os/hal/ports/STM32/LLD \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1 \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv1 \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/MACv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/OTGv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/RTCv2 \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/SDIOv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv1 \ diff --git a/os/hal/ports/STM32/STM32F4xx/stm32_registry.h b/os/hal/ports/STM32/STM32F4xx/stm32_registry.h index ef5c81b77..e7a27f389 100644 --- a/os/hal/ports/STM32/STM32F4xx/stm32_registry.h +++ b/os/hal/ports/STM32/STM32F4xx/stm32_registry.h @@ -109,7 +109,8 @@ #define STM32_HAS_ETH TRUE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 23 +#define STM32_EXTI_NUM_LINES 23 +#define STM32_EXTI_IMR_MASK 0xFF800000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -406,7 +407,8 @@ #endif /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 23 +#define STM32_EXTI_NUM_LINES 23 +#define STM32_EXTI_IMR_MASK 0xFF800000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -678,7 +680,8 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 23 +#define STM32_EXTI_NUM_LINES 23 +#define STM32_EXTI_IMR_MASK 0xFF800000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -898,7 +901,8 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 23 +#define STM32_EXTI_NUM_LINES 23 +#define STM32_EXTI_IMR_MASK 0xFF800000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE diff --git a/os/hal/ports/STM32/STM32L0xx/platform.mk b/os/hal/ports/STM32/STM32L0xx/platform.mk index 8a6dca296..4f3b33b5e 100644 --- a/os/hal/ports/STM32/STM32L0xx/platform.mk +++ b/os/hal/ports/STM32/STM32L0xx/platform.mk @@ -3,16 +3,16 @@ ifeq ($(USE_SMART_BUILD),yes) HALCONF := $(strip $(shell cat halconf.h | egrep -e "define")) PLATFORMSRC := $(CHIBIOS)/os/hal/ports/common/ARMCMx/nvic.c \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32L0xx/hal_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32L0xx/ext_lld_isr.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/st_lld.c -ifneq ($(findstring HAL_USE_CAN TRUE,$(HALCONF)),) -PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/can_lld.c -endif ifneq ($(findstring HAL_USE_ADC TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv1/adc_lld.c endif +ifneq ($(findstring HAL_USE_CAN TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1/can_lld.c +endif ifneq ($(findstring HAL_USE_DAC TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/dac_lld.c endif @@ -53,8 +53,8 @@ else PLATFORMSRC := $(CHIBIOS)/os/hal/ports/common/ARMCMx/nvic.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32L0xx/hal_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32L0xx/ext_lld_isr.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/can_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv1/adc_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1/can_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/dac_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/ext_lld.c \ @@ -75,6 +75,7 @@ endif PLATFORMINC := $(CHIBIOS)/os/hal/ports/common/ARMCMx \ $(CHIBIOS)/os/hal/ports/STM32/STM32L0xx \ $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv1 \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/CANv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/DMAv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1 \ @@ -84,5 +85,4 @@ PLATFORMINC := $(CHIBIOS)/os/hal/ports/common/ARMCMx \ $(CHIBIOS)/os/hal/ports/STM32/LLD/SPIv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/USARTv2 \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/USBv1 \ - $(CHIBIOS)/os/hal/ports/STM32/LLD + $(CHIBIOS)/os/hal/ports/STM32/LLD/USBv1 diff --git a/os/hal/ports/STM32/STM32L0xx/stm32_registry.h b/os/hal/ports/STM32/STM32L0xx/stm32_registry.h index 515dc5616..7ea436f9c 100644 --- a/os/hal/ports/STM32/STM32L0xx/stm32_registry.h +++ b/os/hal/ports/STM32/STM32L0xx/stm32_registry.h @@ -80,7 +80,8 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 23 +#define STM32_EXTI_NUM_LINES 23 +#define STM32_EXTI_IMR_MASK 0xFF840000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE diff --git a/os/hal/ports/STM32/STM32L1xx/ext_lld_isr.c b/os/hal/ports/STM32/STM32L1xx/ext_lld_isr.c index 9292fb603..148883fcf 100644 --- a/os/hal/ports/STM32/STM32L1xx/ext_lld_isr.c +++ b/os/hal/ports/STM32/STM32L1xx/ext_lld_isr.c @@ -54,11 +54,14 @@ * @isr */ OSAL_IRQ_HANDLER(Vector58) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 0); - EXTD1.config->channels[0].cb(&EXTD1, 0); + pr = EXTI->PR & EXTI->IMR & (1 << 0); + EXTI->PR = pr; + if (pr & (1 << 0)) + EXTD1.config->channels[0].cb(&EXTD1, 0); OSAL_IRQ_EPILOGUE(); } @@ -69,11 +72,14 @@ OSAL_IRQ_HANDLER(Vector58) { * @isr */ OSAL_IRQ_HANDLER(Vector5C) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 1); - EXTD1.config->channels[1].cb(&EXTD1, 1); + pr = EXTI->PR & EXTI->IMR & (1 << 1); + EXTI->PR = pr; + if (pr & (1 << 1)) + EXTD1.config->channels[1].cb(&EXTD1, 1); OSAL_IRQ_EPILOGUE(); } @@ -84,11 +90,14 @@ OSAL_IRQ_HANDLER(Vector5C) { * @isr */ OSAL_IRQ_HANDLER(Vector60) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 2); - EXTD1.config->channels[2].cb(&EXTD1, 2); + pr = EXTI->PR & EXTI->IMR & (1 << 2); + EXTI->PR = pr; + if (pr & (1 << 2)) + EXTD1.config->channels[2].cb(&EXTD1, 2); OSAL_IRQ_EPILOGUE(); } @@ -99,11 +108,14 @@ OSAL_IRQ_HANDLER(Vector60) { * @isr */ OSAL_IRQ_HANDLER(Vector64) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 3); - EXTD1.config->channels[3].cb(&EXTD1, 3); + pr = EXTI->PR & EXTI->IMR & (1 << 3); + EXTI->PR = pr; + if (pr & (1 << 3)) + EXTD1.config->channels[3].cb(&EXTD1, 3); OSAL_IRQ_EPILOGUE(); } @@ -114,11 +126,14 @@ OSAL_IRQ_HANDLER(Vector64) { * @isr */ OSAL_IRQ_HANDLER(Vector68) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 4); - EXTD1.config->channels[4].cb(&EXTD1, 4); + pr = EXTI->PR & EXTI->IMR & (1 << 4); + EXTI->PR = pr; + if (pr & (1 << 4)) + EXTD1.config->channels[4].cb(&EXTD1, 4); OSAL_IRQ_EPILOGUE(); } @@ -133,7 +148,8 @@ OSAL_IRQ_HANDLER(Vector9C) { OSAL_IRQ_PROLOGUE(); - pr = EXTI->PR & ((1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9)); + pr = EXTI->PR & EXTI->IMR & ((1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | + (1 << 9)); EXTI->PR = pr; if (pr & (1 << 5)) EXTD1.config->channels[5].cb(&EXTD1, 5); @@ -159,8 +175,8 @@ OSAL_IRQ_HANDLER(VectorE0) { OSAL_IRQ_PROLOGUE(); - pr = EXTI->PR & ((1 << 10) | (1 << 11) | (1 << 12) | (1 << 13) | (1 << 14) | - (1 << 15)); + pr = EXTI->PR & EXTI->IMR & ((1 << 10) | (1 << 11) | (1 << 12) | (1 << 13) | + (1 << 14) | (1 << 15)); EXTI->PR = pr; if (pr & (1 << 10)) EXTD1.config->channels[10].cb(&EXTD1, 10); @@ -184,11 +200,14 @@ OSAL_IRQ_HANDLER(VectorE0) { * @isr */ OSAL_IRQ_HANDLER(Vector44) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - EXTI->PR = (1 << 16); - EXTD1.config->channels[16].cb(&EXTD1, 16); + pr = EXTI->PR & EXTI->IMR & (1 << 16); + EXTI->PR = pr; + if (pr & (1 << 16)) + EXTD1.config->channels[16].cb(&EXTD1, 16); OSAL_IRQ_EPILOGUE(); } @@ -199,11 +218,13 @@ OSAL_IRQ_HANDLER(Vector44) { * @isr */ OSAL_IRQ_HANDLER(VectorE4) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - - EXTI->PR = (1 << 17); - EXTD1.config->channels[17].cb(&EXTD1, 17); + pr = EXTI->PR & EXTI->IMR & (1 << 17); + EXTI->PR = pr; + if (pr & (1 << 17)) + EXTD1.config->channels[17].cb(&EXTD1, 17); OSAL_IRQ_EPILOGUE(); } @@ -213,11 +234,13 @@ OSAL_IRQ_HANDLER(VectorE4) { * @isr */ OSAL_IRQ_HANDLER(VectorE8) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - - EXTI->PR = (1 << 18); - EXTD1.config->channels[18].cb(&EXTD1, 18); + pr = EXTI->PR & EXTI->IMR & (1 << 18); + EXTI->PR = pr; + if (pr & (1 << 18)) + EXTD1.config->channels[18].cb(&EXTD1, 18); OSAL_IRQ_EPILOGUE(); } @@ -228,11 +251,13 @@ OSAL_IRQ_HANDLER(VectorE8) { * @isr */ OSAL_IRQ_HANDLER(Vector48) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - - EXTI->PR = (1 << 19); - EXTD1.config->channels[19].cb(&EXTD1, 19); + pr = EXTI->PR & EXTI->IMR & (1 << 19); + EXTI->PR = pr; + if (pr & (1 << 19)) + EXTD1.config->channels[19].cb(&EXTD1, 19); OSAL_IRQ_EPILOGUE(); } @@ -243,11 +268,13 @@ OSAL_IRQ_HANDLER(Vector48) { * @isr */ OSAL_IRQ_HANDLER(Vector4C) { + uint32_t pr; OSAL_IRQ_PROLOGUE(); - - EXTI->PR = (1 << 20); - EXTD1.config->channels[20].cb(&EXTD1, 20); + pr = EXTI->PR & EXTI->IMR & (1 << 20); + EXTI->PR = pr; + if (pr & (1 << 20)) + EXTD1.config->channels[20].cb(&EXTD1, 20); OSAL_IRQ_EPILOGUE(); } @@ -262,7 +289,7 @@ OSAL_IRQ_HANDLER(Vector98) { OSAL_IRQ_PROLOGUE(); - pr = EXTI->PR & ((1 << 21) | (1 << 22)); + pr = EXTI->PR & EXTI->IMR & ((1 << 21) | (1 << 22)); EXTI->PR = pr; if (pr & (1 << 21)) EXTD1.config->channels[21].cb(&EXTD1, 21); @@ -272,6 +299,25 @@ OSAL_IRQ_HANDLER(Vector98) { OSAL_IRQ_EPILOGUE(); } +#if (STM32_EXTI_NUM_LINES > 23) || defined(__DOXYGEN__) +/** + * @brief EXTI[23] interrupt handler (Channel Acquisition). + * + * @isr + */ +OSAL_IRQ_HANDLER(Vector120) { + uint32_t pr; + + OSAL_IRQ_PROLOGUE(); + pr = EXTI->PR & EXTI->IMR & (1 << 23); + EXTI->PR = pr; + if (pr & (1 << 23)) + EXTD1.config->channels[23].cb(&EXTD1, 23); + + OSAL_IRQ_EPILOGUE(); +} +#endif + /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ diff --git a/os/hal/ports/STM32/STM32L1xx/platform.mk b/os/hal/ports/STM32/STM32L1xx/platform.mk index 6f8e8d053..673edb3b0 100644 --- a/os/hal/ports/STM32/STM32L1xx/platform.mk +++ b/os/hal/ports/STM32/STM32L1xx/platform.mk @@ -10,8 +10,8 @@ ifneq ($(findstring HAL_USE_ADC TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/STM32L1xx/adc_lld.c endif ifneq ($(findstring HAL_USE_EXT TRUE,$(HALCONF)),) -PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/STM32L1xx/ext_lld_isr.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/ext_lld.c +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/ext_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/STM32L1xx/ext_lld_isr.c endif ifneq ($(findstring HAL_USE_DAC TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/dac_lld.c @@ -52,7 +52,7 @@ PLATFORMSRC := $(CHIBIOS)/os/hal/ports/common/ARMCMx/nvic.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32L1xx/hal_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32L1xx/adc_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32L1xx/ext_lld_isr.c \ - $(CHIBIOS)/os/hal/ports/STM32/LLD/ext_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1/ext_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1/dac_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2/pal_lld.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv1/i2c_lld.c \ @@ -70,7 +70,7 @@ endif # Required include directories PLATFORMINC := $(CHIBIOS)/os/hal/ports/common/ARMCMx \ $(CHIBIOS)/os/hal/ports/STM32/STM32L1xx \ - $(CHIBIOS)/os/hal/ports/STM32/LLD \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/EXTIv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/DACv1 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/GPIOv2 \ $(CHIBIOS)/os/hal/ports/STM32/LLD/I2Cv1 \ diff --git a/os/hal/ports/STM32/STM32L1xx/stm32_registry.h b/os/hal/ports/STM32/STM32L1xx/stm32_registry.h index 53833f657..dd84ad6b6 100644 --- a/os/hal/ports/STM32/STM32L1xx/stm32_registry.h +++ b/os/hal/ports/STM32/STM32L1xx/stm32_registry.h @@ -65,7 +65,8 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 23 +#define STM32_EXTI_NUM_LINES 23 +#define STM32_EXTI_IMR_MASK 0xFF800000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE @@ -245,7 +246,8 @@ #define STM32_HAS_ETH FALSE /* EXTI attributes.*/ -#define STM32_EXTI_NUM_CHANNELS 24 +#define STM32_EXTI_NUM_LINES 24 +#define STM32_EXTI_IMR_MASK 0xFF000000U /* GPIO attributes.*/ #define STM32_HAS_GPIOA TRUE -- cgit v1.2.3