aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal/platforms/STM32
diff options
context:
space:
mode:
Diffstat (limited to 'os/hal/platforms/STM32')
-rw-r--r--os/hal/platforms/STM32/DMAv1/stm32_dma.c496
-rw-r--r--os/hal/platforms/STM32/DMAv1/stm32_dma.h275
-rw-r--r--os/hal/platforms/STM32/DMAv2/stm32_dma.c540
-rw-r--r--os/hal/platforms/STM32/DMAv2/stm32_dma.h327
-rw-r--r--os/hal/platforms/STM32/GPIOv1/pal_lld.c4
-rw-r--r--os/hal/platforms/STM32/GPIOv1/pal_lld.h17
-rw-r--r--os/hal/platforms/STM32/GPIOv2/pal_lld.c31
-rw-r--r--os/hal/platforms/STM32/GPIOv2/pal_lld.h58
-rw-r--r--os/hal/platforms/STM32/I2Cv1/i2c_lld.c1100
-rw-r--r--os/hal/platforms/STM32/I2Cv1/i2c_lld.h318
-rw-r--r--os/hal/platforms/STM32/RTCv1/rtc_lld.c319
-rw-r--r--os/hal/platforms/STM32/RTCv1/rtc_lld.h (renamed from os/hal/platforms/STM32/rtc_lld.h)106
-rw-r--r--os/hal/platforms/STM32/USBv1/stm32_usb.h38
-rw-r--r--os/hal/platforms/STM32/USBv1/usb_lld.c160
-rw-r--r--os/hal/platforms/STM32/USBv1/usb_lld.h22
-rw-r--r--os/hal/platforms/STM32/can_lld.c4
-rw-r--r--os/hal/platforms/STM32/can_lld.h5
-rw-r--r--os/hal/platforms/STM32/ext_lld.c609
-rw-r--r--os/hal/platforms/STM32/ext_lld.h280
-rw-r--r--os/hal/platforms/STM32/gpt_lld.c60
-rw-r--r--os/hal/platforms/STM32/gpt_lld.h7
-rw-r--r--os/hal/platforms/STM32/i2c_lld.c1122
-rw-r--r--os/hal/platforms/STM32/i2c_lld.h314
-rw-r--r--os/hal/platforms/STM32/icu_lld.c86
-rw-r--r--os/hal/platforms/STM32/icu_lld.h15
-rw-r--r--os/hal/platforms/STM32/mac_lld.c358
-rw-r--r--os/hal/platforms/STM32/mac_lld.h280
-rw-r--r--os/hal/platforms/STM32/pwm_lld.c90
-rw-r--r--os/hal/platforms/STM32/pwm_lld.h11
-rw-r--r--os/hal/platforms/STM32/rtc_lld.c264
-rw-r--r--os/hal/platforms/STM32/sdc_lld.c (renamed from os/hal/platforms/STM32/DMAv1/sdc_lld.c)3
-rw-r--r--os/hal/platforms/STM32/sdc_lld.h (renamed from os/hal/platforms/STM32/DMAv1/sdc_lld.h)5
-rw-r--r--os/hal/platforms/STM32/serial_lld.c74
-rw-r--r--os/hal/platforms/STM32/serial_lld.h38
-rw-r--r--os/hal/platforms/STM32/spi_lld.c (renamed from os/hal/platforms/STM32/DMAv1/spi_lld.c)209
-rw-r--r--os/hal/platforms/STM32/spi_lld.h (renamed from os/hal/platforms/STM32/DMAv1/spi_lld.h)154
-rw-r--r--os/hal/platforms/STM32/stm32.h154
-rw-r--r--os/hal/platforms/STM32/uart_lld.c (renamed from os/hal/platforms/STM32/DMAv1/uart_lld.c)108
-rw-r--r--os/hal/platforms/STM32/uart_lld.h (renamed from os/hal/platforms/STM32/DMAv1/uart_lld.h)105
39 files changed, 4889 insertions, 3277 deletions
diff --git a/os/hal/platforms/STM32/DMAv1/stm32_dma.c b/os/hal/platforms/STM32/DMAv1/stm32_dma.c
deleted file mode 100644
index 1df93bb2f..000000000
--- a/os/hal/platforms/STM32/DMAv1/stm32_dma.c
+++ /dev/null
@@ -1,496 +0,0 @@
-/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
- 2011 Giovanni Di Sirio.
-
- This file is part of ChibiOS/RT.
-
- ChibiOS/RT is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- ChibiOS/RT is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file DMAv1/stm32_dma.c
- * @brief DMA helper driver code.
- *
- * @addtogroup STM32_DMA
- * @details DMA sharing helper driver. In the STM32 the DMA streams are a
- * shared resource, this driver allows to allocate and free DMA
- * streams at runtime in order to allow all the other device
- * drivers to coordinate the access to the resource.
- * @note The DMA ISR handlers are all declared into this module because
- * sharing, the various device drivers can associate a callback to
- * IRSs when allocating streams.
- * @{
- */
-
-#include "ch.h"
-#include "hal.h"
-
-/* The following macro is only defined if some driver requiring DMA services
- has been enabled.*/
-#if defined(STM32_DMA_REQUIRED) || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Driver local definitions. */
-/*===========================================================================*/
-
-/**
- * @brief Mask of the DMA1 streams in @p dma_streams_mask.
- */
-#define STM32_DMA1_STREAMS_MASK 0x0000007F
-
-/**
- * @brief Mask of the DMA2 streams in @p dma_streams_mask.
- */
-#define STM32_DMA2_STREAMS_MASK 0x00000F80
-
-/**
- * @brief Post-reset value of the stream CCR register.
- */
-#define STM32_DMA_CCR_RESET_VALUE 0x00000000
-
-/*===========================================================================*/
-/* Driver exported variables. */
-/*===========================================================================*/
-
-/**
- * @brief DMA streams descriptors.
- * @details This table keeps the association between an unique stream
- * identifier and the involved physical registers.
- * @note Don't use this array directly, use the appropriate wrapper macros
- * instead: @p STM32_DMA1_STREAM1, @p STM32_DMA1_STREAM2 etc.
- */
-const stm32_dma_stream_t _stm32_dma_streams[STM32_DMA_STREAMS] = {
- {DMA1_Channel1, &DMA1->IFCR, 0, 0, DMA1_Channel1_IRQn},
- {DMA1_Channel2, &DMA1->IFCR, 4, 1, DMA1_Channel2_IRQn},
- {DMA1_Channel3, &DMA1->IFCR, 8, 2, DMA1_Channel3_IRQn},
- {DMA1_Channel4, &DMA1->IFCR, 12, 3, DMA1_Channel4_IRQn},
- {DMA1_Channel5, &DMA1->IFCR, 16, 4, DMA1_Channel5_IRQn},
- {DMA1_Channel6, &DMA1->IFCR, 20, 5, DMA1_Channel6_IRQn},
- {DMA1_Channel7, &DMA1->IFCR, 24, 6, DMA1_Channel7_IRQn},
-#if STM32_HAS_DMA2 || defined(__DOXYGEN__)
- {DMA2_Channel1, &DMA2->IFCR, 0, 7, DMA2_Channel1_IRQn},
- {DMA2_Channel2, &DMA2->IFCR, 4, 8, DMA2_Channel2_IRQn},
- {DMA2_Channel3, &DMA2->IFCR, 8, 9, DMA2_Channel3_IRQn},
-#if defined(STM32F10X_CL) || defined(__DOXYGEN__)
- {DMA2_Channel4, &DMA2->IFCR, 12, 10, DMA2_Channel4_IRQn},
- {DMA2_Channel5, &DMA2->IFCR, 16, 11, DMA2_Channel5_IRQn},
-#else /* !STM32F10X_CL */
- {DMA2_Channel4, &DMA2->IFCR, 12, 10, DMA2_Channel4_5_IRQn},
- {DMA2_Channel5, &DMA2->IFCR, 16, 11, DMA2_Channel4_5_IRQn},
-#endif /* !STM32F10X_CL */
-#endif /* STM32_HAS_DMA2 */
-};
-
-/*===========================================================================*/
-/* Driver local variables and types. */
-/*===========================================================================*/
-
-/**
- * @brief DMA ISR redirector type.
- */
-typedef struct {
- stm32_dmaisr_t dma_func;
- void *dma_param;
-} dma_isr_redir_t;
-
-/**
- * @brief Mask of the allocated streams.
- */
-static uint32_t dma_streams_mask;
-
-/**
- * @brief DMA IRQ redirectors.
- */
-static dma_isr_redir_t dma_isr_redir[STM32_DMA_STREAMS];
-
-/*===========================================================================*/
-/* Driver local functions. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver interrupt handlers. */
-/*===========================================================================*/
-
-/**
- * @brief DMA1 stream 1 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Ch1_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA1->ISR >> 0) & STM32_DMA_ISR_MASK;
- DMA1->IFCR = STM32_DMA_ISR_MASK << 0;
- if (dma_isr_redir[0].dma_func)
- dma_isr_redir[0].dma_func(dma_isr_redir[0].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA1 stream 2 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Ch2_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA1->ISR >> 4) & STM32_DMA_ISR_MASK;
- DMA1->IFCR = STM32_DMA_ISR_MASK << 4;
- if (dma_isr_redir[1].dma_func)
- dma_isr_redir[1].dma_func(dma_isr_redir[1].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA1 stream 3 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Ch3_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA1->ISR >> 8) & STM32_DMA_ISR_MASK;
- DMA1->IFCR = STM32_DMA_ISR_MASK << 8;
- if (dma_isr_redir[2].dma_func)
- dma_isr_redir[2].dma_func(dma_isr_redir[2].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA1 stream 4 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Ch4_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA1->ISR >> 12) & STM32_DMA_ISR_MASK;
- DMA1->IFCR = STM32_DMA_ISR_MASK << 12;
- if (dma_isr_redir[3].dma_func)
- dma_isr_redir[3].dma_func(dma_isr_redir[3].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA1 stream 5 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Ch5_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA1->ISR >> 16) & STM32_DMA_ISR_MASK;
- DMA1->IFCR = STM32_DMA_ISR_MASK << 16;
- if (dma_isr_redir[4].dma_func)
- dma_isr_redir[4].dma_func(dma_isr_redir[4].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA1 stream 6 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Ch6_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA1->ISR >> 20) & STM32_DMA_ISR_MASK;
- DMA1->IFCR = STM32_DMA_ISR_MASK << 20;
- if (dma_isr_redir[5].dma_func)
- dma_isr_redir[5].dma_func(dma_isr_redir[5].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA1 stream 7 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Ch7_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA1->ISR >> 24) & STM32_DMA_ISR_MASK;
- DMA1->IFCR = STM32_DMA_ISR_MASK << 24;
- if (dma_isr_redir[6].dma_func)
- dma_isr_redir[6].dma_func(dma_isr_redir[6].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-#if STM32_HAS_DMA2 || defined(__DOXYGEN__)
-/**
- * @brief DMA2 stream 1 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA2_Ch1_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA2->ISR >> 0) & STM32_DMA_ISR_MASK;
- DMA2->IFCR = STM32_DMA_ISR_MASK << 0;
- if (dma_isr_redir[7].dma_func)
- dma_isr_redir[7].dma_func(dma_isr_redir[7].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA2 stream 2 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA2_Ch2_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA2->ISR >> 4) & STM32_DMA_ISR_MASK;
- DMA2->IFCR = STM32_DMA_ISR_MASK << 4;
- if (dma_isr_redir[8].dma_func)
- dma_isr_redir[8].dma_func(dma_isr_redir[8].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA2 stream 3 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA2_Ch3_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA2->ISR >> 8) & STM32_DMA_ISR_MASK;
- DMA2->IFCR = STM32_DMA_ISR_MASK << 8;
- if (dma_isr_redir[9].dma_func)
- dma_isr_redir[9].dma_func(dma_isr_redir[9].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-#if defined(STM32F10X_CL) || defined(__DOXYGEN__)
-/**
- * @brief DMA2 stream 4 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA2_Ch4_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA2->ISR >> 12) & STM32_DMA_ISR_MASK;
- DMA2->IFCR = STM32_DMA_ISR_MASK << 12;
- if (dma_isr_redir[10].dma_func)
- dma_isr_redir[10].dma_func(dma_isr_redir[10].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA2 stream 5 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA2_Ch5_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA2->ISR >> 16) & STM32_DMA_ISR_MASK;
- DMA2->IFCR = STM32_DMA_ISR_MASK << 16;
- if (dma_isr_redir[11].dma_func)
- dma_isr_redir[11].dma_func(dma_isr_redir[11].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-#else /* !STM32F10X_CL */
-/**
- * @brief DMA2 streams 4 and 5 shared interrupt handler.
- * @note This IRQ is shared between DMA2 channels 4 and 5 so it is a
- * bit less efficient because an extra check.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA2_Ch4_5_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- /* Check on channel 4.*/
- flags = (DMA2->ISR >> 12) & STM32_DMA_ISR_MASK;
- if (flags & STM32_DMA_ISR_MASK) {
- DMA2->IFCR = STM32_DMA_ISR_MASK << 12;
- if (dma_isr_redir[10].dma_func)
- dma_isr_redir[10].dma_func(dma_isr_redir[10].dma_param, flags);
- }
-
- /* Check on channel 5.*/
- flags = (DMA2->ISR >> 16) & STM32_DMA_ISR_MASK;
- if (flags & STM32_DMA_ISR_MASK) {
- DMA2->IFCR = STM32_DMA_ISR_MASK << 16;
- if (dma_isr_redir[11].dma_func)
- dma_isr_redir[11].dma_func(dma_isr_redir[11].dma_param, flags);
- }
-
- CH_IRQ_EPILOGUE();
-}
-#endif /* !STM32F10X_CL */
-#endif /* STM32_HAS_DMA2 */
-
-/*===========================================================================*/
-/* Driver exported functions. */
-/*===========================================================================*/
-
-/**
- * @brief STM32 DMA helper initialization.
- *
- * @init
- */
-void dmaInit(void) {
- int i;
-
- dma_streams_mask = 0;
- for (i = 0; i < STM32_DMA_STREAMS; i++) {
- _stm32_dma_streams[i].channel->CCR = 0;
- dma_isr_redir[i].dma_func = NULL;
- }
- DMA1->IFCR = 0xFFFFFFFF;
-#if STM32_HAS_DMA2
- DMA2->IFCR = 0xFFFFFFFF;
-#endif
-}
-
-/**
- * @brief Allocates a DMA stream.
- * @details The stream is allocated and, if required, the DMA clock enabled.
- * The function also enables the IRQ vector associated to the stream
- * and initializes its priority.
- * @pre The stream must not be already in use or an error is returned.
- * @post The stream is allocated and the default ISR handler redirected
- * to the specified function.
- * @post The stream ISR vector is enabled and its priority configured.
- * @post The stream must be freed using @p dmaStreamRelease() before it can
- * be reused with another peripheral.
- * @post The stream is in its post-reset state.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmastp pointer to a stm32_dma_stream_t structure
- * @param[in] func handling function pointer, can be @p NULL
- * @param[in] param a parameter to be passed to the handling function
- * @return The operation status.
- * @retval FALSE no error, stream taken.
- * @retval TRUE error, stream already taken.
- *
- * @special
- */
-bool_t dmaStreamAllocate(const stm32_dma_stream_t *dmastp,
- uint32_t priority,
- stm32_dmaisr_t func,
- void *param) {
-
- chDbgCheck(dmastp != NULL, "dmaAllocate");
-
- /* Checks if the stream is already taken.*/
- if ((dma_streams_mask & (1 << dmastp->selfindex)) != 0)
- return TRUE;
-
- /* Marks the stream as allocated.*/
- dma_isr_redir[dmastp->selfindex].dma_func = func;
- dma_isr_redir[dmastp->selfindex].dma_param = param;
- dma_streams_mask |= (1 << dmastp->selfindex);
-
- /* Enabling DMA clocks required by the current streams set.*/
- if ((dma_streams_mask & STM32_DMA1_STREAMS_MASK) != 0)
- RCC->AHBENR |= RCC_AHBENR_DMA1EN;
-#if STM32_HAS_DMA2
- if ((dma_streams_mask & STM32_DMA2_STREAMS_MASK) != 0)
- RCC->AHBENR |= RCC_AHBENR_DMA2EN;
-#endif
-
- /* Putting the stream in a safe state.*/
- dmaStreamDisable(dmastp);
- dmaStreamClearInterrupt(dmastp);
- dmastp->channel->CCR = STM32_DMA_CCR_RESET_VALUE;
-
- /* Enables the associated IRQ vector if a callback is defined.*/
- if (func != NULL)
- NVICEnableVector(dmastp->vector, CORTEX_PRIORITY_MASK(priority));
-
- return FALSE;
-}
-
-/**
- * @brief Releases a DMA stream.
- * @details The stream is freed and, if required, the DMA clock disabled.
- * Trying to release a unallocated stream is an illegal operation
- * and is trapped if assertions are enabled.
- * @pre The stream must have been allocated using @p dmaStreamAllocate().
- * @post The stream is again available.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmastp pointer to a stm32_dma_stream_t structure
- *
- * @special
- */
-void dmaStreamRelease(const stm32_dma_stream_t *dmastp) {
-
- chDbgCheck(dmastp != NULL, "dmaRelease");
-
- /* Check if the streams is not taken.*/
- chDbgAssert((dma_streams_mask & (1 << dmastp->selfindex)) != 0,
- "dmaRelease(), #1", "not allocated");
-
- /* Disables the associated IRQ vector.*/
- NVICDisableVector(dmastp->vector);
-
- /* Marks the stream as not allocated.*/
- dma_streams_mask &= ~(1 << dmastp->selfindex);
-
- /* Shutting down clocks that are no more required, if any.*/
- if ((dma_streams_mask & STM32_DMA1_STREAMS_MASK) == 0)
- RCC->AHBENR &= ~RCC_AHBENR_DMA1EN;
-#if STM32_HAS_DMA2
- if ((dma_streams_mask & STM32_DMA2_STREAMS_MASK) == 0)
- RCC->AHBENR &= ~RCC_AHBENR_DMA2EN;
-#endif
-}
-
-#endif /* STM32_DMA_REQUIRED */
-
-/** @} */
diff --git a/os/hal/platforms/STM32/DMAv1/stm32_dma.h b/os/hal/platforms/STM32/DMAv1/stm32_dma.h
deleted file mode 100644
index 473bbe851..000000000
--- a/os/hal/platforms/STM32/DMAv1/stm32_dma.h
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
- 2011 Giovanni Di Sirio.
-
- This file is part of ChibiOS/RT.
-
- ChibiOS/RT is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- ChibiOS/RT is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file DMAv1/stm32_dma.h
- * @brief DMA helper driver header.
- * @note This file requires definitions from the ST header files
- * stm32f10x.h or stm32l1xx.h.
- * @note This driver uses the new naming convention used for the STM32F2xx
- * so the "DMA channels" are referred as "DMA streams".
- *
- * @addtogroup STM32_DMA
- * @{
- */
-
-#ifndef _STM32_DMA_H_
-#define _STM32_DMA_H_
-
-/*===========================================================================*/
-/* Driver constants. */
-/*===========================================================================*/
-
-/**
- * @brief Total number of DMA streams.
- * @note This is the total number of streams among all the DMA units.
- */
-#if STM32_HAS_DMA2 || defined(__DOXYGEN__)
-#define STM32_DMA_STREAMS 12
-#else
-#define STM32_DMA_STREAMS 7
-#endif
-
-/**
- * @brief Mask of the ISR bits passed to the DMA callback functions.
- */
-#define STM32_DMA_ISR_MASK 0x0F
-
-/**
- * @name DMA streams identifiers
- * @{
- */
-#define STM32_DMA1_STREAM1 (&_stm32_dma_streams[0])
-#define STM32_DMA1_STREAM2 (&_stm32_dma_streams[1])
-#define STM32_DMA1_STREAM3 (&_stm32_dma_streams[2])
-#define STM32_DMA1_STREAM4 (&_stm32_dma_streams[3])
-#define STM32_DMA1_STREAM5 (&_stm32_dma_streams[4])
-#define STM32_DMA1_STREAM6 (&_stm32_dma_streams[5])
-#define STM32_DMA1_STREAM7 (&_stm32_dma_streams[6])
-#define STM32_DMA2_STREAM1 (&_stm32_dma_streams[8])
-#define STM32_DMA2_STREAM2 (&_stm32_dma_streams[9])
-#define STM32_DMA2_STREAM3 (&_stm32_dma_streams[10])
-#define STM32_DMA2_STREAM4 (&_stm32_dma_streams[11])
-#define STM32_DMA2_STREAM5 (&_stm32_dma_streams[12])
-/** @} */
-
-/**
- * @name CR register constants common to all DMA types
- */
-#define STM32_DMA_CR_EN DMA_CCR1_EN
-#define STM32_DMA_CR_TEIE DMA_CCR1_TEIE
-#define STM32_DMA_CR_HTIE DMA_CCR1_HTIE
-#define STM32_DMA_CR_TCIE DMA_CCR1_TCIE
-#define STM32_DMA_CR_DIR_MASK (DMA_CCR1_DIR | DMA_CCR1_MEM2MEM)
-#define STM32_DMA_CR_DIR_P2M 0
-#define STM32_DMA_CR_DIR_M2P DMA_CCR1_DIR
-#define STM32_DMA_CR_DIR_M2M DMA_CCR1_MEM2MEM
-#define STM32_DMA_CR_CIRC DMA_CCR1_CIRC
-#define STM32_DMA_CR_PINC DMA_CCR1_PINC
-#define STM32_DMA_CR_MINC DMA_CCR1_MINC
-#define STM32_DMA_CR_PSIZE_MASK DMA_CCR1_PSIZE
-#define STM32_DMA_CR_PSIZE_BYTE 0
-#define STM32_DMA_CR_PSIZE_HWORD DMA_CCR1_PSIZE_0
-#define STM32_DMA_CR_PSIZE_WORD DMA_CCR1_PSIZE_1
-#define STM32_DMA_CR_MSIZE_MASK DMA_CCR1_MSIZE
-#define STM32_DMA_CR_MSIZE_BYTE 0
-#define STM32_DMA_CR_MSIZE_HWORD DMA_CCR1_MSIZE_0
-#define STM32_DMA_CR_MSIZE_WORD DMA_CCR1_MSIZE_1
-#define STM32_DMA_CR_PL_MASK DMA_CCR1_PL
-#define STM32_DMA_CR_PL(n) ((n) << 12)
-/** @} */
-
-/**
- * @name CR register constants only found in enhanced DMA
- */
-#define STM32_DMA_CR_CHSEL_MASK 0 /**< @brief Ignored by normal DMA. */
-#define STM32_DMA_CR_CHSEL(n) 0 /**< @brief Ignored by normal DMA. */
-/** @} */
-
-/**
- * @name Status flags passed to the ISR callbacks
- */
-#define STM32_DMA_ISR_FEIF 0
-#define STM32_DMA_ISR_DMEIF 0
-#define STM32_DMA_ISR_TEIF DMA_ISR_TEIF1
-#define STM32_DMA_ISR_HTIF DMA_ISR_HTIF1
-#define STM32_DMA_ISR_TCIF DMA_ISR_TCIF1
-/** @} */
-
-/*===========================================================================*/
-/* Driver pre-compile time settings. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Derived constants and error checks. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver data structures and types. */
-/*===========================================================================*/
-
-/**
- * @brief STM32 DMA stream descriptor structure.
- */
-typedef struct {
- DMA_Channel_TypeDef *channel; /**< @brief Associated DMA channel. */
- volatile uint32_t *ifcr; /**< @brief Associated IFCR reg. */
- uint8_t ishift; /**< @brief Bits offset in xIFCR
- register. */
- uint8_t selfindex; /**< @brief Index to self in array. */
- uint8_t vector; /**< @brief Associated IRQ vector. */
-} stm32_dma_stream_t;
-
-/**
- * @brief STM32 DMA ISR function type.
- *
- * @param[in] p parameter for the registered function
- * @param[in] flags pre-shifted content of the ISR register, the bits
- * are aligned to bit zero
- */
-typedef void (*stm32_dmaisr_t)(void *p, uint32_t flags);
-
-/*===========================================================================*/
-/* Driver macros. */
-/*===========================================================================*/
-
-/**
- * @brief Associates a peripheral data register to a DMA stream.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmastp pointer to a stm32_dma_stream_t structure
- * @param[in] addr value to be written in the CPAR register
- *
- * @special
- */
-#define dmaStreamSetPeripheral(dmastp, addr) { \
- (dmastp)->channel->CPAR = (uint32_t)(addr); \
-}
-
-/**
- * @brief Associates a memory destination to a DMA stream.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmastp pointer to a stm32_dma_stream_t structure
- * @param[in] addr value to be written in the CMAR register
- *
- * @special
- */
-#define dmaStreamSetMemory0(dmastp, addr) { \
- (dmastp)->channel->CMAR = (uint32_t)(addr); \
-}
-
-/**
- * @brief Sets the number of transfers to be performed.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmastp pointer to a stm32_dma_stream_t structure
- * @param[in] size value to be written in the CNDTR register
- *
- * @special
- */
-#define dmaStreamSetTransactionSize(dmastp, size) { \
- (dmastp)->channel->CNDTR = (uint32_t)(size); \
-}
-
-/**
- * @brief Returns the number of transfers to be performed.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmastp pointer to a stm32_dma_stream_t structure
- * @return The number of transfers to be performed.
- *
- * @special
- */
-#define dmaStreamGetTransactionSize(dmastp) ((size_t)((dmastp)->channel->CNDTR))
-
-/**
- * @brief Programs the stream mode settings.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmastp pointer to a stm32_dma_stream_t structure
- * @param[in] mode value to be written in the CCR register
- *
- * @special
- */
-#define dmaStreamSetMode(dmastp, mode) { \
- (dmastp)->channel->CCR = (uint32_t)(mode); \
-}
-
-/**
- * @brief DMA stream enable.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmachp pointer to a stm32_dma_stream_t structure
- *
- * @special
- */
-#define dmaStreamEnable(dmastp) { \
- (dmastp)->channel->CCR |= STM32_DMA_CR_EN; \
-}
-
-/**
- * @brief DMA stream disable.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmastp pointer to a stm32_dma_stream_t structure
- *
- * @special
- */
-#define dmaStreamDisable(dmastp) { \
- (dmastp)->channel->CCR &= ~STM32_DMA_CR_EN; \
-}
-
-/**
- * @brief DMA stream interrupt sources clear.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmastp pointer to a stm32_dma_stream_t structure
- *
- * @special
- */
-#define dmaStreamClearInterrupt(dmastp) { \
- *(dmastp)->ifcr = STM32_DMA_ISR_MASK << (dmastp)->ishift; \
-}
-
-/*===========================================================================*/
-/* External declarations. */
-/*===========================================================================*/
-
-#if !defined(__DOXYGEN__)
-extern const stm32_dma_stream_t _stm32_dma_streams[STM32_DMA_STREAMS];
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
- void dmaInit(void);
- bool_t dmaStreamAllocate(const stm32_dma_stream_t *dmastp,
- uint32_t priority,
- stm32_dmaisr_t func,
- void *param);
- void dmaStreamRelease(const stm32_dma_stream_t *dmastp);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _STM32_DMA_H_ */
-
-/** @} */
diff --git a/os/hal/platforms/STM32/DMAv2/stm32_dma.c b/os/hal/platforms/STM32/DMAv2/stm32_dma.c
deleted file mode 100644
index 2b6851ad6..000000000
--- a/os/hal/platforms/STM32/DMAv2/stm32_dma.c
+++ /dev/null
@@ -1,540 +0,0 @@
-/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
- 2011 Giovanni Di Sirio.
-
- This file is part of ChibiOS/RT.
-
- ChibiOS/RT is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- ChibiOS/RT is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file DMAv2/stm32_dma.c
- * @brief Enhanced DMA helper driver code.
- *
- * @addtogroup STM32_DMA
- * @details DMA sharing helper driver. In the STM32 the DMA streams are a
- * shared resource, this driver allows to allocate and free DMA
- * streams at runtime in order to allow all the other device
- * drivers to coordinate the access to the resource.
- * @note The DMA ISR handlers are all declared into this module because
- * sharing, the various device drivers can associate a callback to
- * IRSs when allocating streams.
- * @{
- */
-
-#include "ch.h"
-#include "hal.h"
-
-/* The following macro is only defined if some driver requiring DMA services
- has been enabled.*/
-#if defined(STM32_DMA_REQUIRED) || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Driver local definitions. */
-/*===========================================================================*/
-
-/**
- * @brief Mask of the DMA1 streams in @p dma_streams_mask.
- */
-#define STM32_DMA1_STREAMS_MASK 0x000000FF
-
-/**
- * @brief Mask of the DMA2 streams in @p dma_streams_mask.
- */
-#define STM32_DMA2_STREAMS_MASK 0x0000FF00
-
-/**
- * @brief Post-reset value of the stream CR register.
- */
-#define STM32_DMA_CR_RESET_VALUE 0x00000000
-
-/**
- * @brief Post-reset value of the stream FCR register.
- */
-#define STM32_DMA_FCR_RESET_VALUE 0x00000021
-
-/*===========================================================================*/
-/* Driver exported variables. */
-/*===========================================================================*/
-
-/**
- * @brief DMA streams descriptors.
- * @details This table keeps the association between an unique stream
- * identifier and the involved physical registers.
- * @note Don't use this array directly, use the appropriate wrapper macros
- * instead: @p STM32_DMA1_STREAM0, @p STM32_DMA1_STREAM1 etc.
- */
-const stm32_dma_stream_t _stm32_dma_streams[STM32_DMA_STREAMS] = {
- {0, DMA1, DMA1_Stream0, &DMA1->LIFCR, 0},
- {1, DMA1, DMA1_Stream1, &DMA1->LIFCR, 6},
- {2, DMA1, DMA1_Stream2, &DMA1->LIFCR, 16},
- {3, DMA1, DMA1_Stream3, &DMA1->LIFCR, 22},
- {4, DMA1, DMA1_Stream4, &DMA1->HIFCR, 0},
- {5, DMA1, DMA1_Stream5, &DMA1->HIFCR, 6},
- {6, DMA1, DMA1_Stream6, &DMA1->HIFCR, 16},
- {7, DMA1, DMA1_Stream7, &DMA1->HIFCR, 22},
- {8, DMA2, DMA2_Stream0, &DMA2->LIFCR, 0},
- {9, DMA2, DMA2_Stream1, &DMA2->LIFCR, 6},
- {10, DMA2, DMA2_Stream2, &DMA2->LIFCR, 16},
- {11, DMA2, DMA2_Stream3, &DMA2->LIFCR, 22},
- {12, DMA2, DMA2_Stream4, &DMA2->HIFCR, 0},
- {13, DMA2, DMA2_Stream5, &DMA2->HIFCR, 6},
- {14, DMA2, DMA2_Stream6, &DMA2->HIFCR, 16},
- {15, DMA2, DMA2_Stream7, &DMA2->HIFCR, 22},
-};
-
-/*===========================================================================*/
-/* Driver local variables and types. */
-/*===========================================================================*/
-
-/**
- * @brief DMA ISR redirector type.
- */
-typedef struct {
- stm32_dmaisr_t dma_func;
- void *dma_param;
-} dma_isr_redir_t;
-
-/**
- * @brief Mask of the allocated streams.
- */
-static uint32_t dma_streams_mask;
-
-/**
- * @brief DMA IRQ redirectors.
- */
-static dma_isr_redir_t dma_isr_redir[STM32_DMA_STREAMS];
-
-/*===========================================================================*/
-/* Driver local functions. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver interrupt handlers. */
-/*===========================================================================*/
-
-/**
- * @brief DMA1 stream 0 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Stream0_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA1->LISR >> 0) & STM32_DMA_ISR_MASK;
- DMA1->LIFCR = STM32_DMA_ISR_MASK << 0;
- if (dma_isr_redir[0].dma_func)
- dma_isr_redir[0].dma_func(dma_isr_redir[0].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA1 stream 1 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Stream1_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA1->LISR >> 6) & STM32_DMA_ISR_MASK;
- DMA1->LIFCR = STM32_DMA_ISR_MASK << 6;
- if (dma_isr_redir[1].dma_func)
- dma_isr_redir[1].dma_func(dma_isr_redir[0].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA1 stream 2 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Stream2_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA1->LISR >> 16) & STM32_DMA_ISR_MASK;
- DMA1->LIFCR = STM32_DMA_ISR_MASK << 16;
- if (dma_isr_redir[2].dma_func)
- dma_isr_redir[2].dma_func(dma_isr_redir[2].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA1 stream 3 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Stream3_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA1->LISR >> 22) & STM32_DMA_ISR_MASK;
- DMA1->LIFCR = STM32_DMA_ISR_MASK << 22;
- if (dma_isr_redir[3].dma_func)
- dma_isr_redir[3].dma_func(dma_isr_redir[3].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA1 stream 4 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Stream4_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA1->HISR >> 0) & STM32_DMA_ISR_MASK;
- DMA1->HIFCR = STM32_DMA_ISR_MASK << 0;
- if (dma_isr_redir[4].dma_func)
- dma_isr_redir[4].dma_func(dma_isr_redir[4].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA1 stream 5 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Stream5_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA1->HISR >> 6) & STM32_DMA_ISR_MASK;
- DMA1->HIFCR = STM32_DMA_ISR_MASK << 6;
- if (dma_isr_redir[5].dma_func)
- dma_isr_redir[5].dma_func(dma_isr_redir[5].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA1 stream 6 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Stream6_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA1->HISR >> 16) & STM32_DMA_ISR_MASK;
- DMA1->HIFCR = STM32_DMA_ISR_MASK << 16;
- if (dma_isr_redir[6].dma_func)
- dma_isr_redir[6].dma_func(dma_isr_redir[6].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA1 stream 7 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Stream7_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA1->HISR >> 22) & STM32_DMA_ISR_MASK;
- DMA1->HIFCR = STM32_DMA_ISR_MASK << 22;
- if (dma_isr_redir[7].dma_func)
- dma_isr_redir[7].dma_func(dma_isr_redir[7].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA2 stream 0 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA2_Stream0_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA2->LISR >> 0) & STM32_DMA_ISR_MASK;
- DMA2->LIFCR = STM32_DMA_ISR_MASK << 0;
- if (dma_isr_redir[8].dma_func)
- dma_isr_redir[8].dma_func(dma_isr_redir[8].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA2 stream 1 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA2_Stream1_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA2->LISR >> 6) & STM32_DMA_ISR_MASK;
- DMA2->LIFCR = STM32_DMA_ISR_MASK << 6;
- if (dma_isr_redir[9].dma_func)
- dma_isr_redir[9].dma_func(dma_isr_redir[9].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA2 stream 2 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA2_Stream2_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA2->LISR >> 16) & STM32_DMA_ISR_MASK;
- DMA2->LIFCR = STM32_DMA_ISR_MASK << 16;
- if (dma_isr_redir[10].dma_func)
- dma_isr_redir[10].dma_func(dma_isr_redir[10].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA2 stream 3 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA2_Stream3_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA2->LISR >> 22) & STM32_DMA_ISR_MASK;
- DMA2->LIFCR = STM32_DMA_ISR_MASK << 22;
- if (dma_isr_redir[11].dma_func)
- dma_isr_redir[11].dma_func(dma_isr_redir[11].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA2 stream 4 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA2_Stream4_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA2->HISR >> 0) & STM32_DMA_ISR_MASK;
- DMA2->HIFCR = STM32_DMA_ISR_MASK << 0;
- if (dma_isr_redir[12].dma_func)
- dma_isr_redir[12].dma_func(dma_isr_redir[12].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA2 stream 5 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA2_Stream5_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA2->HISR >> 6) & STM32_DMA_ISR_MASK;
- DMA2->HIFCR = STM32_DMA_ISR_MASK << 6;
- if (dma_isr_redir[13].dma_func)
- dma_isr_redir[13].dma_func(dma_isr_redir[13].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA2 stream 6 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA2_Stream6_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA2->HISR >> 16) & STM32_DMA_ISR_MASK;
- DMA2->HIFCR = STM32_DMA_ISR_MASK << 16;
- if (dma_isr_redir[14].dma_func)
- dma_isr_redir[14].dma_func(dma_isr_redir[14].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief DMA2 stream 7 shared interrupt handler.
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA2_Stream7_IRQHandler) {
- uint32_t flags;
-
- CH_IRQ_PROLOGUE();
-
- flags = (DMA2->HISR >> 22) & STM32_DMA_ISR_MASK;
- DMA2->HIFCR = STM32_DMA_ISR_MASK << 22;
- if (dma_isr_redir[15].dma_func)
- dma_isr_redir[15].dma_func(dma_isr_redir[15].dma_param, flags);
-
- CH_IRQ_EPILOGUE();
-}
-
-/*===========================================================================*/
-/* Driver exported functions. */
-/*===========================================================================*/
-
-/**
- * @brief STM32 DMA helper initialization.
- *
- * @init
- */
-void dmaInit(void) {
- int i;
-
- dma_streams_mask = 0;
- for (i = 0; i < STM32_DMA_STREAMS; i++) {
- _stm32_dma_streams[i].stream->CR = 0;
- dma_isr_redir[i].dma_func = NULL;
- }
- DMA1->LIFCR = 0xFFFFFFFF;
- DMA1->HIFCR = 0xFFFFFFFF;
- DMA2->LIFCR = 0xFFFFFFFF;
- DMA2->HIFCR = 0xFFFFFFFF;
-}
-
-/**
- * @brief Allocates a DMA stream.
- * @details The stream is allocated and, if required, the DMA clock enabled.
- * The function also enables the IRQ vector associated to the stream
- * and initializes its priority.
- * @pre The stream must not be already in use or an error is returned.
- * @post The stream is allocated and the default ISR handler redirected
- * to the specified function.
- * @post The stream ISR vector is enabled and its priority configured.
- * @post The stream must be freed using @p dmaStreamRelease() before it can
- * be reused with another peripheral.
- * @post The stream is in its post-reset state.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmastp pointer to a stm32_dma_stream_t structure
- * @param[in] func handling function pointer, can be @p NULL
- * @param[in] param a parameter to be passed to the handling function
- * @return The operation status.
- * @retval FALSE no error, stream taken.
- * @retval TRUE error, stream already taken.
- *
- * @special
- */
-bool_t dmaStreamAllocate(const stm32_dma_stream_t *dmastp,
- uint32_t priority,
- stm32_dmaisr_t func,
- void *param) {
-
- chDbgCheck(dmastp != NULL, "dmaAllocate");
-
- /* Checks if the stream is already taken.*/
- if ((dma_streams_mask & dmastp->mask) != 0)
- return TRUE;
-
- /* Marks the stream as allocated.*/
- dma_isr_redir[dmastp->selfindex].dma_func = func;
- dma_isr_redir[dmastp->selfindex].dma_param = param;
- dma_streams_mask |= (1 << dmastp->selfindex);
-
- /* Enabling DMA clocks required by the current streams set.*/
- if ((dma_streams_mask & STM32_DMA1_STREAMS_MASK) != 0) {
- RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN;
- RCC->AHB1LPENR |= RCC_AHB1LPENR_DMA1LPEN;
- }
- if ((dma_streams_mask & STM32_DMA2_STREAMS_MASK) != 0) {
- RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;
- RCC->AHB1LPENR |= RCC_AHB1LPENR_DMA2LPEN;
- }
-
- /* Putting the stream in a safe state.*/
- dmaStreamDisable(dmastp);
- dmaStreamClearInterrupt(dmastp);
- dmastp->channel->CR = STM32_DMA_CR_RESET_VALUE;
- dmastp->channel->FCR = STM32_DMA_FCR_RESET_VALUE;
-
- /* Enables the associated IRQ vector if a callback is defined.*/
- if (func != NULL)
- NVICEnableVector(dmastp->vector, CORTEX_PRIORITY_MASK(priority));
-
- return FALSE;
-}
-
-/**
- * @brief Releases a DMA stream.
- * @details The stream is freed and, if required, the DMA clock disabled.
- * Trying to release a unallocated stream is an illegal operation
- * and is trapped if assertions are enabled.
- * @pre The stream must have been allocated using @p dmaStreamAllocate().
- * @post The stream is again available.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmastp pointer to a stm32_dma_stream_t structure
- *
- * @special
- */
-void dmaStreamRelease(const stm32_dma_stream_t *dmastp) {
-
- chDbgCheck(dmastp != NULL, "dmaRelease");
-
- /* Check if the streams is not taken.*/
- chDbgAssert((dma_streams_mask & dmastp->mask) != 0,
- "dmaRelease(), #1", "not allocated");
-
- /* Disables the associated IRQ vector.*/
- NVICDisableVector(dmastp->vector);
-
- /* Marks the stream as not allocated.*/
- dma_streams_mask &= ~(1 << dmastp->selfindex);
-
- /* Shutting down clocks that are no more required, if any.*/
- if ((dma_streams_mask & STM32_DMA1_STREAMS_MASK) == 0) {
- RCC->AHB1ENR &= ~RCC_AHB1ENR_DMA1EN;
- RCC->AHB1LPENR &= ~RCC_AHB1LPENR_DMA1LPEN;
- }
- if ((dma_streams_mask & STM32_DMA2_STREAMS_MASK) == 0) {
- RCC->AHB1ENR &= ~RCC_AHB1ENR_DMA2EN;
- RCC->AHB1LPENR &= ~RCC_AHB1LPENR_DMA2LPEN;
- }
-}
-
-#endif /* STM32_DMA_REQUIRED */
-
-/** @} */
diff --git a/os/hal/platforms/STM32/DMAv2/stm32_dma.h b/os/hal/platforms/STM32/DMAv2/stm32_dma.h
deleted file mode 100644
index af18497fc..000000000
--- a/os/hal/platforms/STM32/DMAv2/stm32_dma.h
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
- 2011 Giovanni Di Sirio.
-
- This file is part of ChibiOS/RT.
-
- ChibiOS/RT is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- ChibiOS/RT is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file DMAv2/stm32_dma.h
- * @brief Enhanced-DMA helper driver header.
- * @note This file requires definitions from the ST STM32F2xx header file
- * stm32f2xx.h.
- *
- * @addtogroup STM32_DMA
- * @{
- */
-
-#ifndef _STM32_DMA_H_
-#define _STM32_DMA_H_
-
-/*===========================================================================*/
-/* Driver constants. */
-/*===========================================================================*/
-
-/**
- * @brief Total number of DMA streams.
- * @note This is the total number of streams among all the DMA units.
- */
-#define STM32_DMA_STREAMS 16
-
-/**
- * @brief Mask of the ISR bits passed to the DMA callback functions.
- */
-#define STM32_DMA_ISR_MASK 0x3D
-
-/**
- * @name DMA streams identifiers
- * @{
- */
-#define STM32_DMA1_STREAM0 (&_stm32_dma_streams[0])
-#define STM32_DMA1_STREAM1 (&_stm32_dma_streams[1])
-#define STM32_DMA1_STREAM2 (&_stm32_dma_streams[2])
-#define STM32_DMA1_STREAM3 (&_stm32_dma_streams[3])
-#define STM32_DMA1_STREAM4 (&_stm32_dma_streams[4])
-#define STM32_DMA1_STREAM5 (&_stm32_dma_streams[5])
-#define STM32_DMA1_STREAM6 (&_stm32_dma_streams[6])
-#define STM32_DMA1_STREAM7 (&_stm32_dma_streams[7])
-#define STM32_DMA2_STREAM0 (&_stm32_dma_streams[8])
-#define STM32_DMA2_STREAM1 (&_stm32_dma_streams[9])
-#define STM32_DMA2_STREAM2 (&_stm32_dma_streams[10])
-#define STM32_DMA2_STREAM3 (&_stm32_dma_streams[11])
-#define STM32_DMA2_STREAM4 (&_stm32_dma_streams[12])
-#define STM32_DMA2_STREAM5 (&_stm32_dma_streams[13])
-#define STM32_DMA2_STREAM6 (&_stm32_dma_streams[14])
-#define STM32_DMA2_STREAM7 (&_stm32_dma_streams[15])
-/** @} */
-
-/**
- * @name CR register constants common to all DMA types
- */
-#define STM32_DMA_CR_EN DMA_SxCR_EN
-#define STM32_DMA_CR_TEIE DMA_SxCR_TEIE
-#define STM32_DMA_CR_HTIE DMA_SxCR_HTIE
-#define STM32_DMA_CR_TCIE DMA_SxCR_TCIE
-#define STM32_DMA_CR_DIR_MASK DMA_SxCR_DIR
-#define STM32_DMA_CR_DIR_P2M 0
-#define STM32_DMA_CR_DIR_M2P DMA_SxCR_DIR_0
-#define STM32_DMA_CR_DIR_M2M DMA_SxCR_DIR_1
-#define STM32_DMA_CR_CIRC DMA_SxCR_CIRC
-#define STM32_DMA_CR_PINC DMA_SxCR_PINC
-#define STM32_DMA_CR_MINC DMA_SxCR_MINC
-#define STM32_DMA_CR_PSIZE_MASK DMA_SxCR_PSIZE
-#define STM32_DMA_CR_PSIZE_BYTE 0
-#define STM32_DMA_CR_PSIZE_HWORD DMA_SxCR_PSIZE_0
-#define STM32_DMA_CR_PSIZE_WORD DMA_SxCR_PSIZE_1
-#define STM32_DMA_CR_MSIZE_MASK DMA_SxCR_MSIZE
-#define STM32_DMA_CR_MSIZE_BYTE 0
-#define STM32_DMA_CR_MSIZE_HWORD DMA_SxCR_MSIZE_0
-#define STM32_DMA_CR_MSIZE_WORD DMA_SxCR_MSIZE_1
-#define STM32_DMA_CR_PL_MASK DMA_SxCR_PL
-#define STM32_DMA_CR_PL(n) ((n) << 16)
-/** @} */
-
-/**
- * @name CR register constants only found in STM32F2xx
- */
-#define STM32_DMA_CR_DMEIE DMA_SxCR_DMEIE
-#define STM32_DMA_CR_PFCTRL DMA_SxCR_PFCTRL
-#define STM32_DMA_CR_PINCOS DMA_SxCR_PINCOS
-#define STM32_DMA_CR_DBM DMA_SxCR_DBM
-#define STM32_DMA_CR_CT DMA_SxCR_CT
-#define STM32_DMA_CR_PBURST_MASK DMA_SxCR_PBURST
-#define STM32_DMA_CR_PBURST_SINGLE 0
-#define STM32_DMA_CR_PBURST_INCR4 DMA_SxCR_PBURST_0
-#define STM32_DMA_CR_PBURST_INCR8 DMA_SxCR_PBURST_1
-#define STM32_DMA_CR_PBURST_INCR16 (DMA_SxCR_PBURST_0 | DMA_SxCR_PBURST_1)
-#define STM32_DMA_CR_MBURST_MASK DMA_SxCR_MBURST
-#define STM32_DMA_CR_MBURST_SINGLE 0
-#define STM32_DMA_CR_MBURST_INCR4 DMA_SxCR_MBURST_0
-#define STM32_DMA_CR_MBURST_INCR8 DMA_SxCR_MBURST_1
-#define STM32_DMA_CR_MBURST_INCR16 (DMA_SxCR_MBURST_0 | DMA_SxCR_MBURST_1)
-#define STM32_DMA_CR_CHSEL_MASK DMA_SxCR_CHSEL
-#define STM32_DMA_CR_CHSEL(n) ((n) << 25)
-/** @} */
-
-/**
- * @name FCR register constants only found in STM32F2xx
- */
-#define STM32_DMA_FCR_FEIE DMA_SxFCR_FEIE
-#define STM32_DMA_FCR_FS_MASK DMA_SxFCR_FS
-#define STM32_DMA_FCR_DMDIS DMA_SxFCR_DMDIS
-#define STM32_DMA_FCR_FTH_MASK DMA_SxFCR_FTH
-#define STM32_DMA_FCR_FTH_1Q 0
-#define STM32_DMA_FCR_FTH_HALF DMA_SxFCR_FTH_0
-#define STM32_DMA_FCR_FTH_3Q DMA_SxFCR_FTH_1
-#define STM32_DMA_FCR_FTH_FULL (DMA_SxFCR_FTH_0 | DMA_SxFCR_FTH_1)
-/** @} */
-
-/**
- * @name Status flags passed to the ISR callbacks
- */
-#define STM32_DMA_ISR_FEIF DMA_LISR_FEIF0
-#define STM32_DMA_ISR_DMEIF DMA_LISR_DMEIF0
-#define STM32_DMA_ISR_TEIF DMA_LISR_TEIF0
-#define STM32_DMA_ISR_HTIF DMA_LISR_HTIF0
-#define STM32_DMA_ISR_TCIF DMA_LISR_TCIF0
-/** @} */
-
-/*===========================================================================*/
-/* Driver pre-compile time settings. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Derived constants and error checks. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver data structures and types. */
-/*===========================================================================*/
-
-/**
- * @brief STM32 DMA stream descriptor structure.
- */
-typedef struct {
- DMA_Channel_TypeDef *channel; /**< @brief Associated DMA channel. */
- volatile uint32_t *ifcr; /**< @brief Associated IFCR reg. */
- uint8_t ishift; /**< @brief Bits offset in xIFCR
- register. */
- uint8_t selfindex; /**< @brief Index to self in array. */
- uint8_t vector; /**< @brief Associated IRQ vector. */
-} stm32_dma_stream_t;
-
-/**
- * @brief STM32 DMA ISR function type.
- *
- * @param[in] p parameter for the registered function
- * @param[in] flags pre-shifted content of the xISR register, the bits
- * are aligned to bit zero
- */
-typedef void (*stm32_dmaisr_t)(void *p, uint32_t flags);
-
-/*===========================================================================*/
-/* Driver macros. */
-/*===========================================================================*/
-
-/**
- * @brief Associates a peripheral data register to a DMA stream.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmastp pointer to a stm32_dma_stream_t structure
- * @param[in] addr value to be written in the PAR register
- *
- * @special
- */
-#define dmaStreamSetPeripheral(dmastp, addr) { \
- (dmastp)->stream->PAR = (uint32_t)(addr); \
-}
-
-/**
- * @brief Associates a memory destination to a DMA stream.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmastp pointer to a stm32_dma_stream_t structure
- * @param[in] addr value to be written in the M0AR register
- *
- * @special
- */
-#define dmaStreamSetMemory0(dmastp, addr) { \
- (dmastp)->stream->M0AR = (uint32_t)(addr); \
-}
-
-/**
- * @brief Associates an alternate memory destination to a DMA stream.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmastp pointer to a stm32_dma_stream_t structure
- * @param[in] addr value to be written in the M1AR register
- *
- * @special
- */
-#define dmaStreamSetMemory1(dmastp, addr) { \
- (dmastp)->stream->M1AR = (uint32_t)(addr); \
-}
-
-/**
- * @brief Sets the number of transfers to be performed.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmastp pointer to a stm32_dma_stream_t structure
- * @param[in] size value to be written in the CNDTR register
- *
- * @special
- */
-#define dmaStreamSetTransactionSize(dmastp, size) { \
- (dmastp)->stream->NDTR = (uint32_t)(size); \
-}
-
-/**
- * @brief Returns the number of transfers to be performed.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmastp pointer to a stm32_dma_stream_t structure
- * @return The number of transfers to be performed.
- *
- * @special
- */
-#define dmaStreamGetTransactionSize(dmastp) ((size_t)((dmastp)->stream->NDTR))
-
-/**
- * @brief Programs the stream mode settings.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmastp pointer to a stm32_dma_stream_t structure
- * @param[in] mode value to be written in the CR register
- *
- * @special
- */
-#define dmaStreamSetMode(dmastp, mode) { \
- (dmastp)->stream->CR = (uint32_t)(mode); \
-}
-
-/**
- * @brief Programs the stream FIFO settings.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmastp pointer to a stm32_dma_stream_t structure
- * @param[in] mode value to be written in the FCR register
- *
- * @special
- */
-#define dmaStreamSetFIFO(dmastp, mode) { \
- (dmastp)->stream->FCR = (uint32_t)(mode); \
-}
-
-/**
- * @brief DMA stream enable.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmachp pointer to a stm32_dma_stream_t structure
- *
- * @special
- */
-#define dmaStreamEnable(dmachp) { \
- (dmastp)->stream->CR |= STM32_DMA_CR_EN; \
-}
-
-/**
- * @brief DMA stream disable.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmastp pointer to a stm32_dma_stream_t structure
- *
- * @special
- */
-#define dmaStreamDisable(dmastp) { \
- (dmastp)->stream->CR &= ~STM32_DMA_CR_EN; \
-}
-
-/**
- * @brief DMA stream interrupt sources clear.
- * @note This function can be invoked in both ISR or thread context.
- *
- * @param[in] dmastp pointer to a stm32_dma_stream_t structure
- *
- * @special
- */
-#define dmaStreamClearInterrupt(dmastp) { \
- *(dmastp)->ifcr = STM32_DMA_ISR_MASK << (dmastp)->ishift; \
-}
-
-/*===========================================================================*/
-/* External declarations. */
-/*===========================================================================*/
-
-#if !defined(__DOXYGEN__)
-extern const stm32_dma_stream_t _stm32_dma_streams[STM32_DMA_STREAMS];
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
- void dmaInit(void);
- bool_t dmaStreamAllocate(const stm32_dma_stream_t *dmastp,
- uint32_t priority,
- stm32_dmaisr_t func,
- void *param);
- void dmaStreamRelease(const stm32_dma_stream_t *dmastp);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _STM32_DMA_H_ */
-
-/** @} */
diff --git a/os/hal/platforms/STM32/GPIOv1/pal_lld.c b/os/hal/platforms/STM32/GPIOv1/pal_lld.c
index 81846fa58..6b4b806b9 100644
--- a/os/hal/platforms/STM32/GPIOv1/pal_lld.c
+++ b/os/hal/platforms/STM32/GPIOv1/pal_lld.c
@@ -79,7 +79,7 @@ void _pal_lld_init(const PALConfig *config) {
/*
* Enables the GPIO related clocks.
*/
- RCC->APB2ENR |= APB2_EN_MASK;
+ rccEnableAPB2(APB2_EN_MASK, FALSE);
/*
* Initial GPIO setup.
@@ -117,8 +117,6 @@ void _pal_lld_init(const PALConfig *config) {
* @brief Pads mode setup.
* @details This function programs a pads group belonging to the same port
* with the specified mode.
- * @note This function is not meant to be invoked directly by the
- * application code.
* @note @p PAL_MODE_UNCONNECTED is implemented as push pull output at 2MHz.
* @note Writing on pads programmed as pull-up or pull-down has the side
* effect to modify the resistor setting because the output latched
diff --git a/os/hal/platforms/STM32/GPIOv1/pal_lld.h b/os/hal/platforms/STM32/GPIOv1/pal_lld.h
index 65e660944..ab1c273bc 100644
--- a/os/hal/platforms/STM32/GPIOv1/pal_lld.h
+++ b/os/hal/platforms/STM32/GPIOv1/pal_lld.h
@@ -36,6 +36,10 @@
/*===========================================================================*/
/**
+ * @name STM32-specific I/O mode flags
+ * @{
+ */
+/**
* @brief STM32 specific alternate push-pull output mode.
*/
#define PAL_MODE_STM32_ALTERNATE_PUSHPULL 16
@@ -44,6 +48,7 @@
* @brief STM32 specific alternate open-drain output mode.
*/
#define PAL_MODE_STM32_ALTERNATE_OPENDRAIN 17
+/** @} */
/*===========================================================================*/
/* I/O Ports Types and constants. */
@@ -219,8 +224,6 @@ typedef GPIO_TypeDef * ioportid_t;
* @brief Writes on a I/O port.
* @details This function is implemented by writing the GPIO ODR register, the
* implementation has no side effects.
- * @note This function is not meant to be invoked directly by the
- * application code.
* @note Writing on pads programmed as pull-up or pull-down has the side
* effect to modify the resistor setting because the output latched
* data is used for the resistor selection.
@@ -236,8 +239,6 @@ typedef GPIO_TypeDef * ioportid_t;
* @brief Sets a bits mask on a I/O port.
* @details This function is implemented by writing the GPIO BSRR register, the
* implementation has no side effects.
- * @note This function is not meant to be invoked directly by the
- * application code.
* @note Writing on pads programmed as pull-up or pull-down has the side
* effect to modify the resistor setting because the output latched
* data is used for the resistor selection.
@@ -253,8 +254,6 @@ typedef GPIO_TypeDef * ioportid_t;
* @brief Clears a bits mask on a I/O port.
* @details This function is implemented by writing the GPIO BRR register, the
* implementation has no side effects.
- * @note This function is not meant to be invoked directly by the
- * application code.
* @note Writing on pads programmed as pull-up or pull-down has the side
* effect to modify the resistor setting because the output latched
* data is used for the resistor selection.
@@ -270,8 +269,6 @@ typedef GPIO_TypeDef * ioportid_t;
* @brief Writes a group of bits.
* @details This function is implemented by writing the GPIO BSRR register, the
* implementation has no side effects.
- * @note This function is not meant to be invoked directly by the
- * application code.
* @note Writing on pads programmed as pull-up or pull-down has the side
* effect to modify the resistor setting because the output latched
* data is used for the resistor selection.
@@ -292,8 +289,6 @@ typedef GPIO_TypeDef * ioportid_t;
* @brief Pads group mode setup.
* @details This function programs a pads group belonging to the same port
* with the specified mode.
- * @note This function is not meant to be invoked directly by the
- * application code.
* @note Writing on pads programmed as pull-up or pull-down has the side
* effect to modify the resistor setting because the output latched
* data is used for the resistor selection.
@@ -309,8 +304,6 @@ typedef GPIO_TypeDef * ioportid_t;
/**
* @brief Writes a logical state on an output pad.
- * @note This function is not meant to be invoked directly by the
- * application code.
* @note Writing on pads programmed as pull-up or pull-down has the side
* effect to modify the resistor setting because the output latched
* data is used for the resistor selection.
diff --git a/os/hal/platforms/STM32/GPIOv2/pal_lld.c b/os/hal/platforms/STM32/GPIOv2/pal_lld.c
index c84df64f6..cb9c102df 100644
--- a/os/hal/platforms/STM32/GPIOv2/pal_lld.c
+++ b/os/hal/platforms/STM32/GPIOv2/pal_lld.c
@@ -20,7 +20,7 @@
/**
* @file STM32/GPIOv2/pal_lld.c
- * @brief STM32L1xx/STM32F2xx GPIO low level driver code.
+ * @brief STM32L1xx/STM32F2xx/STM32F4xx GPIO low level driver code.
*
* @addtogroup PAL
* @{
@@ -32,16 +32,22 @@
#if HAL_USE_PAL || defined(__DOXYGEN__)
#if defined(STM32L1XX_MD)
-#define AHB_EN_MASK (RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | \
- RCC_AHBENR_GPIOCEN | RCC_AHBENR_GPIODEN | \
+#define AHB_EN_MASK (RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | \
+ RCC_AHBENR_GPIOCEN | RCC_AHBENR_GPIODEN | \
RCC_AHBENR_GPIOEEN | RCC_AHBENR_GPIOHEN)
-#define AHB_LPEN_MASK AHB_EN_MASK
#elif defined(STM32F2XX)
-#define AHB1_EN_MASK (RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | \
- RCC_AHB1ENR_GPIOCEN | RCC_AHB1ENR_GPIODEN | \
- RCC_AHB1ENR_GPIOEEN | RCC_AHB1ENR_GPIOFEN | \
- RCC_AHB1ENR_GPIOGEN | RCC_AHB1ENR_GPIOHEN | \
- RCC_AHB1ENR_GPIOIEN)
+#define AHB1_EN_MASK (RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | \
+ RCC_AHB1ENR_GPIOCEN | RCC_AHB1ENR_GPIODEN | \
+ RCC_AHB1ENR_GPIOEEN | RCC_AHB1ENR_GPIOFEN | \
+ RCC_AHB1ENR_GPIOGEN | RCC_AHB1ENR_GPIOHEN | \
+ RCC_AHB1ENR_GPIOIEN)
+#define AHB1_LPEN_MASK AHB1_EN_MASK
+#elif defined(STM32F4XX)
+#define AHB1_EN_MASK (RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | \
+ RCC_AHB1ENR_GPIOCEN | RCC_AHB1ENR_GPIODEN | \
+ RCC_AHB1ENR_GPIOEEN | RCC_AHB1ENR_GPIOFEN | \
+ RCC_AHB1ENR_GPIOGEN | RCC_AHB1ENR_GPIOHEN | \
+ RCC_AHB1ENR_GPIOIEN)
#define AHB1_LPEN_MASK AHB1_EN_MASK
#else
#error "missing or usupported platform for GPIOv2 PAL driver"
@@ -92,9 +98,8 @@ void _pal_lld_init(const PALConfig *config) {
* Enables the GPIO related clocks.
*/
#if defined(STM32L1XX_MD)
- RCC->AHBENR |= AHB_EN_MASK;
- RCC->AHBLPENR |= AHB_LPEN_MASK;
-#elif defined(STM32F2XX)
+ rccEnableAHB(AHB_EN_MASK, TRUE);
+#elif defined(STM32F2XX) || defined(STM32F4XX)
RCC->AHB1ENR |= AHB1_EN_MASK;
RCC->AHB1LPENR |= AHB1_LPEN_MASK;
#endif
@@ -127,8 +132,6 @@ void _pal_lld_init(const PALConfig *config) {
* @brief Pads mode setup.
* @details This function programs a pads group belonging to the same port
* with the specified mode.
- * @note This function is not meant to be invoked directly by the
- * application code.
* @note @p PAL_MODE_UNCONNECTED is implemented as push pull at minimum
* speed.
*
diff --git a/os/hal/platforms/STM32/GPIOv2/pal_lld.h b/os/hal/platforms/STM32/GPIOv2/pal_lld.h
index 0f9f22441..ac564e8e3 100644
--- a/os/hal/platforms/STM32/GPIOv2/pal_lld.h
+++ b/os/hal/platforms/STM32/GPIOv2/pal_lld.h
@@ -20,7 +20,7 @@
/**
* @file STM32/GPIOv2/pal_lld.h
- * @brief STM32L1xx/STM32F2xx GPIO low level driver header.
+ * @brief STM32L1xx/STM32F2xx/STM32F4xx GPIO low level driver header.
*
* @addtogroup PAL
* @{
@@ -44,6 +44,10 @@
#undef PAL_MODE_OUTPUT_PUSHPULL
#undef PAL_MODE_OUTPUT_OPENDRAIN
+/**
+ * @name STM32-specific I/O mode flags
+ * @{
+ */
#define PAL_STM32_MODE_MASK (3 << 0)
#define PAL_STM32_MODE_INPUT (0 << 0)
#define PAL_STM32_MODE_OUTPUT (1 << 0)
@@ -55,10 +59,10 @@
#define PAL_STM32_OTYPE_OPENDRAIN (1 << 2)
#define PAL_STM32_OSPEED_MASK (3 << 3)
-#define PAL_STM32_OSPEED_400K (0 << 3)
-#define PAL_STM32_OSPEED_2M (1 << 3)
-#define PAL_STM32_OSPEED_10M (2 << 3)
-#define PAL_STM32_OSPEED_40M (3 << 3)
+#define PAL_STM32_OSPEED_LOWEST (0 << 3)
+#define PAL_STM32_OSPEED_MID1 (1 << 3)
+#define PAL_STM32_OSPEED_MID2 (2 << 3)
+#define PAL_STM32_OSPEED_HIGHEST (3 << 3)
#define PAL_STM32_PUDR_MASK (3 << 5)
#define PAL_STM32_PUDR_FLOATING (0 << 5)
@@ -69,6 +73,19 @@
#define PAL_STM32_ALTERNATE(n) ((n) << 7)
/**
+ * @brief Alternate function.
+ *
+ * @param[in] n alternate function selector
+ */
+#define PAL_MODE_ALTERNATE(n) (PAL_STM32_MODE_ALTERNATE | \
+ PAL_STM32_ALTERNATE(n))
+/** @} */
+
+/**
+ * @name Standard I/O mode flags
+ * @{
+ */
+/**
* @brief This mode is implemented as input.
*/
#define PAL_MODE_RESET PAL_STM32_MODE_INPUT
@@ -111,24 +128,7 @@
*/
#define PAL_MODE_OUTPUT_OPENDRAIN (PAL_STM32_MODE_OUTPUT | \
PAL_STM32_OTYPE_OPENDRAIN)
-
-/**
- * @brief Alternate push-pull output.
- *
- * @param[in] n alternate function selector
- */
-#define PAL_MODE_ALTERNATE_PUSHPULL(n) (PAL_STM32_MODE_ALTERNATE | \
- PAL_STM32_OTYPE_PUSHPULL | \
- PAL_STM32_ALTERNATE(n))
-
-/**
- * @brief Alternate push-pull output.
- *
- * @param[in] n alternate function selector
- */
-#define PAL_MODE_ALTERNATE_OPENDRAIN(n) (PAL_STM32_MODE_ALTERNATE | \
- PAL_STM32_OTYPE_OPENDRAIN | \
- PAL_STM32_ALTERNATE(n))
+/** @} */
/*===========================================================================*/
/* I/O Ports Types and constants. */
@@ -357,8 +357,6 @@ typedef GPIO_TypeDef * ioportid_t;
* @brief Writes on a I/O port.
* @details This function is implemented by writing the GPIO ODR register, the
* implementation has no side effects.
- * @note This function is not meant to be invoked directly by the
- * application code.
* @note Writing on pads programmed as pull-up or pull-down has the side
* effect to modify the resistor setting because the output latched
* data is used for the resistor selection.
@@ -374,8 +372,6 @@ typedef GPIO_TypeDef * ioportid_t;
* @brief Sets a bits mask on a I/O port.
* @details This function is implemented by writing the GPIO BSRR register, the
* implementation has no side effects.
- * @note This function is not meant to be invoked directly by the
- * application code.
* @note Writing on pads programmed as pull-up or pull-down has the side
* effect to modify the resistor setting because the output latched
* data is used for the resistor selection.
@@ -391,8 +387,6 @@ typedef GPIO_TypeDef * ioportid_t;
* @brief Clears a bits mask on a I/O port.
* @details This function is implemented by writing the GPIO BSRR register, the
* implementation has no side effects.
- * @note This function is not meant to be invoked directly by the
- * application code.
* @note Writing on pads programmed as pull-up or pull-down has the side
* effect to modify the resistor setting because the output latched
* data is used for the resistor selection.
@@ -408,8 +402,6 @@ typedef GPIO_TypeDef * ioportid_t;
* @brief Writes a group of bits.
* @details This function is implemented by writing the GPIO BSRR register, the
* implementation has no side effects.
- * @note This function is not meant to be invoked directly by the
- * application code.
* @note Writing on pads programmed as pull-up or pull-down has the side
* effect to modify the resistor setting because the output latched
* data is used for the resistor selection.
@@ -430,8 +422,6 @@ typedef GPIO_TypeDef * ioportid_t;
* @brief Pads group mode setup.
* @details This function programs a pads group belonging to the same port
* with the specified mode.
- * @note This function is not meant to be invoked directly by the
- * application code.
* @note Writing on pads programmed as pull-up or pull-down has the side
* effect to modify the resistor setting because the output latched
* data is used for the resistor selection.
@@ -447,8 +437,6 @@ typedef GPIO_TypeDef * ioportid_t;
/**
* @brief Writes a logical state on an output pad.
- * @note This function is not meant to be invoked directly by the
- * application code.
* @note Writing on pads programmed as pull-up or pull-down has the side
* effect to modify the resistor setting because the output latched
* data is used for the resistor selection.
diff --git a/os/hal/platforms/STM32/I2Cv1/i2c_lld.c b/os/hal/platforms/STM32/I2Cv1/i2c_lld.c
new file mode 100644
index 000000000..93b4c4061
--- /dev/null
+++ b/os/hal/platforms/STM32/I2Cv1/i2c_lld.c
@@ -0,0 +1,1100 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file STM32/i2c_lld.c
+ * @brief STM32 I2C subsystem low level driver source. Slave mode not implemented.
+ * @addtogroup I2C
+ * @{
+ */
+
+#include "ch.h"
+#include "hal.h"
+#include "i2c_lld.h"
+
+#if HAL_USE_I2C || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Datasheet notes. */
+/*===========================================================================*/
+/**
+ * From RM0008.pdf
+ *
+ * Note:
+ * When the STOP, START or PEC bit is set, the software must NOT perform
+ * any write access to I2C_CR1 before this bit is cleared by hardware.
+ * Otherwise there is a risk of setting a second STOP, START or PEC request.
+ */
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+#define I2C_STOP_GPT_TIMEOUT 50 /* waiting timer value */
+#define I2C_START_GPT_TIMEOUT 50 /* waiting timer value */
+#define I2C_POLLING_TIMEOUT 0xFFFF
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief I2C1 driver identifier.*/
+#if STM32_I2C_USE_I2C1 || defined(__DOXYGEN__)
+I2CDriver I2CD1;
+#endif
+
+/** @brief I2C2 driver identifier.*/
+#if STM32_I2C_USE_I2C2 || defined(__DOXYGEN__)
+I2CDriver I2CD2;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables. */
+/*===========================================================================*/
+
+/* Debugging variables */
+#if CH_DBG_ENABLE_ASSERTS
+static volatile uint16_t dbgSR1 = 0;
+static volatile uint16_t dbgSR2 = 0;
+static volatile uint16_t dbgCR1 = 0;
+static volatile uint16_t dbgCR2 = 0;
+#endif /* CH_DBG_ENABLE_ASSERTS */
+
+/* defines for convenience purpose */
+#if I2C_SUPPORTS_CALLBACKS
+#define txBuffp (i2cp->txbuff_p)
+#define rxBuffp (i2cp->rxbuff_p)
+#endif /* I2C_SUPPORTS_CALLBACKS */
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+#if I2C_SUPPORTS_CALLBACKS
+#if (!(STM32_I2C_I2C1_USE_POLLING_WAIT)) && STM32_I2C_USE_I2C1
+/* I2C1 GPT callback. */
+static void i2c1gptcb(GPTDriver *gptp) {
+ (void)gptp;
+ I2CDriver *i2cp = &I2CD1;
+
+ chSysLockFromIsr();
+ i2cp->flags &= ~I2C_FLG_TIMER_ARMED;
+
+ switch(i2cp->id_state){
+ case I2C_ACTIVE_TRANSMIT:
+ i2c_lld_master_transmit(i2cp, i2cp->slave_addr, i2cp->txbuf, i2cp->txbytes, i2cp->rxbuf, i2cp->rxbytes);
+ break;
+
+ case I2C_ACTIVE_RECEIVE:
+ i2c_lld_master_receive(i2cp, i2cp->slave_addr, i2cp->rxbuf, i2cp->rxbytes);
+ break;
+
+ case I2C_ACTIVE_TRANSCEIVE:
+ i2c_lld_master_transceive(i2cp);
+ break;
+
+ default:
+ break;
+ }
+ chSysUnlockFromIsr();
+}
+/* I2C1 GPT configuration. */
+static const GPTConfig i2c1gptcfg = {
+ 1000000, /* 1MHz timer clock.*/
+ i2c1gptcb /* Timer callback.*/
+};
+#endif /* STM32_I2C_I2C1_USE_POLLING_WAIT */
+
+#if (!(STM32_I2C_I2C2_USE_POLLING_WAIT)) && STM32_I2C_USE_I2C2
+/* I2C2 GPT callback. */
+static void i2c2gptcb(GPTDriver *gptp) {
+ (void)gptp;
+ I2CDriver *i2cp = &I2CD2;
+
+ chSysLockFromIsr();
+ i2cp->flags &= ~I2C_FLG_TIMER_ARMED;
+
+ switch(i2cp->id_state){
+ case I2C_ACTIVE_TRANSMIT:
+ i2c_lld_master_transmit(i2cp, i2cp->slave_addr, i2cp->txbuf, i2cp->txbytes, i2cp->rxbuf, i2cp->rxbytes);
+ break;
+
+ case I2C_ACTIVE_RECEIVE:
+ i2c_lld_master_receive(i2cp, i2cp->slave_addr, i2cp->rxbuf, i2cp->rxbytes);
+ break;
+
+ case I2C_ACTIVE_TRANSCEIVE:
+ i2c_lld_master_transceive(i2cp);
+ break;
+
+ default:
+ break;
+ }
+ chSysUnlockFromIsr();
+}
+/* I2C2 GPT configuration. */
+static const GPTConfig i2c2gptcfg = {
+ 1000000, /* 1MHz timer clock.*/
+ i2c2gptcb /* Timer callback.*/
+};
+#endif /* STM32_I2C_I2C2_USE_POLLING_WAIT */
+#endif /* I2C_SUPPORTS_CALLBACKS */
+
+/**
+ * @brief Function for I2C debugging purpose.
+ * @note Internal use only.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+#if CH_DBG_ENABLE_ASSERTS
+void _i2c_unhandled_case(I2CDriver *i2cp){
+ dbgCR1 = i2cp->id_i2c->CR1;
+ dbgCR2 = i2cp->id_i2c->CR2;
+ chDbgAssert((dbgSR1 + dbgSR2) == 0,
+ "i2c_serve_event_interrupt(), #1",
+ "unhandled case");
+}
+#else
+#define _i2c_unhandled_case(i2cp)
+#endif /* CH_DBG_ENABLE_ASSERTS */
+
+#if I2C_SUPPORTS_CALLBACKS
+/**
+ * @brief Return the last event value from I2C status registers.
+ * @note Internal use only.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+static uint32_t i2c_get_event(I2CDriver *i2cp){
+ uint16_t regSR1 = i2cp->id_i2c->SR1;
+ uint16_t regSR2 = i2cp->id_i2c->SR2;
+ #if CH_DBG_ENABLE_ASSERTS
+ dbgSR1 = regSR1;
+ dbgSR2 = regSR2;
+ #endif /* CH_DBG_ENABLE_ASSERTS */
+
+ return (I2C_EV_MASK & (regSR1 | (regSR2 << 16)));
+}
+
+/**
+ * @brief Handle the flags/interrupts.
+ * @note Internal use only.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+void _i2c_ev6_master_rec_mode_selected(I2CDriver *i2cp){
+ I2C_TypeDef *dp = i2cp->id_i2c;
+
+ switch(i2cp->flags & EV6_SUBEV_MASK) {
+
+ case I2C_EV6_3_MASTER_REC_1BTR_MODE_SELECTED: /* only an single byte to receive */
+ dp->CR1 &= (uint16_t)~I2C_CR1_ACK; /* Clear ACK */
+ dp->CR1 |= I2C_CR1_STOP; /* Program the STOP */
+ break;
+
+ case I2C_EV6_1_MASTER_REC_2BTR_MODE_SELECTED: /* only two bytes to receive */
+ dp->CR1 &= (uint16_t)~I2C_CR1_ACK; /* Clear ACK */
+ dp->CR2 &= (uint16_t)~I2C_CR2_ITBUFEN; /* Disable the ITBUF in order to have only the BTF interrupt */
+ break;
+
+ default: /* more than 2 bytes to receive */
+ break;
+ }
+}
+
+/**
+ * @brief Handle cases of 2 or 3 bytes receiving.
+ * @note Internal use only.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+void _i2c_ev7_master_rec_byte_qued(I2CDriver *i2cp){
+ I2C_TypeDef *dp = i2cp->id_i2c;
+
+ switch(i2cp->flags & EV7_SUBEV_MASK) {
+
+ case I2C_EV7_2_MASTER_REC_3BYTES_TO_PROCESS:
+ /* Only for case of three bytes to be received.
+ * DataN-2 and DataN-1 already received. */
+ dp->CR1 &= (uint16_t)~I2C_CR1_ACK; /* Clear ACK */
+ *rxBuffp = dp->DR; /* Read the DataN-2. This clear the RXE & BFT flags and launch the DataN exception in the shift register (ending the SCL stretch) */
+ rxBuffp++;
+ chSysLockFromIsr();
+ dp->CR1 |= I2C_CR1_STOP; /* Program the STOP */
+ *rxBuffp = dp->DR; /* Read the DataN-1 */
+ chSysUnlockFromIsr();
+ rxBuffp++;
+ i2cp->rxbytes -= 2; /* Decrement the number of readed bytes */
+ i2cp->flags = 0;
+ dp->CR2 |= I2C_CR2_ITBUFEN; /* ready for read DataN. Enable interrupt for next (and last) RxNE event*/
+ break;
+
+ case I2C_EV7_3_MASTER_REC_2BYTES_TO_PROCESS:
+ /* only for case of two bytes to be received
+ * DataN-1 and DataN are received */
+ dp->CR2 &= (uint16_t)~I2C_CR2_ITEVTEN;
+ dp->CR2 &= (uint16_t)~I2C_CR2_ITBUFEN;
+ chSysLockFromIsr();
+ dp->CR1 |= I2C_CR1_STOP; /* Program the STOP */
+ *rxBuffp = dp->DR; /* Read the DataN-1*/
+ rxBuffp++;
+ *rxBuffp = dp->DR; /* Read the DataN*/
+ chSysUnlockFromIsr();
+ i2cp->rxbytes = 0;
+ i2cp->flags = 0;
+ _i2c_isr_code(i2cp, i2cp->id_slave_config); /* Portable I2C ISR code defined in the high level driver. */
+ break;
+
+ case I2C_FLG_MASTER_RECEIVER:
+ /* Some times in hi load scenarions it is possible to "miss" interrupt
+ * because STM32 I2C has OR'ed interrupt sources. This case handle that
+ * scenario. */
+ if (i2cp->rxbytes > 3){
+ *rxBuffp = dp->DR;
+ rxBuffp++;
+ (i2cp->rxbytes)--;
+ }
+ else{
+ _i2c_unhandled_case(i2cp);
+ }
+ break;
+
+ default:
+ _i2c_unhandled_case(i2cp);
+ break;
+ }
+}
+
+/**
+ * @brief Main I2C interrupt handler.
+ * @note Internal use only.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+static void i2c_serve_event_interrupt(I2CDriver *i2cp) {
+ I2C_TypeDef *dp = i2cp->id_i2c;
+
+ switch(i2c_get_event(i2cp)) {
+
+ case I2C_EV5_MASTER_MODE_SELECT:
+ i2cp->flags &= ~I2C_FLG_HEADER_SENT;
+ dp->DR = i2cp->slave_addr1;
+ break;
+
+ case I2C_EV9_MASTER_ADDR_10BIT:
+ if(i2cp->flags & I2C_FLG_MASTER_RECEIVER) {
+ i2cp->slave_addr1 |= 0x01;
+ i2cp->flags |= I2C_FLG_HEADER_SENT;
+ }
+ dp->DR = i2cp->slave_addr2;
+ break;
+
+ /**************************************************************************
+ * Master Transmitter part
+ */
+ case I2C_EV6_MASTER_TRA_MODE_SELECTED:
+ if(i2cp->flags & I2C_FLG_HEADER_SENT){
+ dp->CR1 |= I2C_CR1_START; /* re-send the start in 10-Bit address mode */
+ break;
+ }
+ txBuffp = (uint8_t*)i2cp->txbuf; /* Initialize the transmit buffer pointer */
+ i2cp->txbytes--;
+ if(i2cp->txbytes == 0) { /* If no further data to be sent, disable the I2C ITBUF in order to not have a TxE interrupt */
+ dp->CR2 &= (uint16_t)~I2C_CR2_ITBUFEN;
+ }
+ dp->DR = *txBuffp; /* EV8_1 write the first data */
+ txBuffp++;
+ break;
+
+ case I2C_EV8_MASTER_BYTE_TRANSMITTING:
+ if(i2cp->txbytes > 0) {
+ i2cp->txbytes--;
+ if(i2cp->txbytes == 0) { /* If no further data to be sent, disable the ITBUF in order to not have a TxE interrupt */
+ dp->CR2 &= (uint16_t)~I2C_CR2_ITBUFEN;
+ }
+ dp->DR = *txBuffp;
+ txBuffp++;
+ }
+ break;
+
+ case I2C_EV8_2_MASTER_BYTE_TRANSMITTED:
+ dp->CR2 &= (uint16_t)~I2C_CR2_ITEVTEN; /* Disable ITEVT In order to not have again a BTF IT */
+ if (i2cp->rxbytes == 0){ /* if nothing to read then generate stop */
+ dp->CR1 |= I2C_CR1_STOP;
+ _i2c_isr_code(i2cp, i2cp->id_slave_config); /* Portable I2C ISR code defined in the high level driver. */
+ }
+ else{ /* start reading operation */
+ i2cp->id_i2c->CR1 |= I2C_CR1_START; /* send start bit */
+ i2c_lld_master_transceive(i2cp);
+ }
+ break;
+
+ /**************************************************************************
+ * Master Receiver part
+ */
+ case I2C_EV6_MASTER_REC_MODE_SELECTED:
+ _i2c_ev6_master_rec_mode_selected(i2cp);
+ rxBuffp = i2cp->rxbuf; /* Initialize receive buffer pointer */
+ break;
+
+ case I2C_EV7_MASTER_REC_BYTE_RECEIVED:
+ if(i2cp->rxbytes > 3) {
+ *rxBuffp = dp->DR; /* Read the data register */
+ rxBuffp++;
+ i2cp->rxbytes--;
+ if(i2cp->rxbytes == 3){ /* Disable the ITBUF in order to have only the BTF interrupt */
+ dp->CR2 &= (uint16_t)~I2C_CR2_ITBUFEN;
+ i2cp->flags |= I2C_FLG_3BTR;
+ }
+ }
+ else if (i2cp->rxbytes == 3){ /* Disable the ITBUF in order to have only the BTF interrupt */
+ dp->CR2 &= (uint16_t)~I2C_CR2_ITBUFEN;
+ i2cp->flags |= I2C_FLG_3BTR;
+ }
+ break;
+
+ case I2C_EV7_MASTER_REC_BYTE_QUEUED:
+ _i2c_ev7_master_rec_byte_qued(i2cp);
+ break;
+
+ default: /* only 1 byte must to be read to complete trasfer. Stop already sent to bus. */
+ chDbgAssert((i2cp->rxbytes) == 1,
+ "i2c_serve_event_interrupt(), #1",
+ "more than 1 byte to be received");
+ *rxBuffp = dp->DR; /* Read the data register */
+ i2cp->rxbytes = 0;
+ dp->CR2 &= (uint16_t)~I2C_CR2_ITEVTEN; /* disable interrupts */
+ dp->CR2 &= (uint16_t)~I2C_CR2_ITBUFEN;
+ _i2c_isr_code(i2cp, i2cp->id_slave_config); /* Portable I2C ISR code defined in the high level driver.*/
+ break;
+ }
+}
+#endif /* I2C_SUPPORTS_CALLBACKS */
+
+static void i2c_serve_error_interrupt(I2CDriver *i2cp) {
+ i2cflags_t flags;
+ I2C_TypeDef *reg;
+
+ reg = i2cp->id_i2c;
+ flags = I2CD_NO_ERROR;
+
+ if(reg->SR1 & I2C_SR1_BERR) { /* Bus error */
+ reg->SR1 &= ~I2C_SR1_BERR;
+ flags |= I2CD_BUS_ERROR;
+ }
+ if(reg->SR1 & I2C_SR1_ARLO) { /* Arbitration lost */
+ reg->SR1 &= ~I2C_SR1_ARLO;
+ flags |= I2CD_ARBITRATION_LOST;
+ }
+ if(reg->SR1 & I2C_SR1_AF) { /* Acknowledge fail */
+ reg->SR1 &= ~I2C_SR1_AF;
+ reg->CR1 |= I2C_CR1_STOP; /* setting stop bit */
+ while(i2cp->id_i2c->CR1 & I2C_CR1_STOP)
+ ;
+ flags |= I2CD_ACK_FAILURE;
+ }
+ if(reg->SR1 & I2C_SR1_OVR) { /* Overrun */
+ reg->SR1 &= ~I2C_SR1_OVR;
+ flags |= I2CD_OVERRUN;
+ }
+ if(reg->SR1 & I2C_SR1_PECERR) { /* PEC error */
+ reg->SR1 &= ~I2C_SR1_PECERR;
+ flags |= I2CD_PEC_ERROR;
+ }
+ if(reg->SR1 & I2C_SR1_TIMEOUT) { /* SMBus Timeout */
+ reg->SR1 &= ~I2C_SR1_TIMEOUT;
+ flags |= I2CD_TIMEOUT;
+ }
+ if(reg->SR1 & I2C_SR1_SMBALERT) { /* SMBus alert */
+ reg->SR1 &= ~I2C_SR1_SMBALERT;
+ flags |= I2CD_SMB_ALERT;
+ }
+
+ if(flags != I2CD_NO_ERROR) { /* send communication end signal */
+ chSysLockFromIsr();
+ i2cAddFlagsI(i2cp, flags);
+ chSysUnlockFromIsr();
+ #if I2C_SUPPORTS_CALLBACKS
+ _i2c_isr_err_code(i2cp, i2cp->id_slave_config);
+ #endif /* I2C_SUPPORTS_CALLBACKS */
+ }
+}
+
+
+#if STM32_I2C_USE_I2C1 || defined(__DOXYGEN__)
+/**
+ * @brief I2C1 event interrupt handler.
+ */
+#if I2C_SUPPORTS_CALLBACKS
+CH_IRQ_HANDLER(VectorBC) {
+
+ CH_IRQ_PROLOGUE();
+ i2c_serve_event_interrupt(&I2CD1);
+ CH_IRQ_EPILOGUE();
+}
+#endif /* I2C_SUPPORTS_CALLBACKS */
+/**
+ * @brief I2C1 error interrupt handler.
+ */
+CH_IRQ_HANDLER(VectorC0) {
+
+ CH_IRQ_PROLOGUE();
+ i2c_serve_error_interrupt(&I2CD1);
+ CH_IRQ_EPILOGUE();
+}
+#endif /* STM32_I2C_USE_I2C1 */
+
+#if STM32_I2C_USE_I2C2 || defined(__DOXYGEN__)
+/**
+ * @brief I2C2 event interrupt handler.
+ */
+#if I2C_SUPPORTS_CALLBACKS
+CH_IRQ_HANDLER(VectorC4) {
+
+ CH_IRQ_PROLOGUE();
+ i2c_serve_event_interrupt(&I2CD2);
+ CH_IRQ_EPILOGUE();
+}
+#endif /* I2C_SUPPORTS_CALLBACKS */
+/**
+ * @brief I2C2 error interrupt handler.
+ */
+CH_IRQ_HANDLER(VectorC8) {
+
+ CH_IRQ_PROLOGUE();
+ i2c_serve_error_interrupt(&I2CD2);
+ CH_IRQ_EPILOGUE();
+}
+#endif /* STM32_I2C_USE_I2C2 */
+
+/**
+ * @brief Low level I2C driver initialization.
+ */
+void i2c_lld_init(void) {
+
+#if STM32_I2C_USE_I2C1
+ i2cObjectInit(&I2CD1);
+ I2CD1.id_i2c = I2C1;
+
+#if I2C_SUPPORTS_CALLBACKS
+#if !(STM32_I2C_I2C1_USE_POLLING_WAIT)
+ I2CD1.timer = &(STM32_I2C_I2C1_USE_GPT_TIM);
+ I2CD1.timer_cfg = &i2c1gptcfg;
+#endif /* !(STM32_I2C_I2C1_USE_POLLING_WAIT) */
+#endif /* I2C_SUPPORTS_CALLBACKS */
+
+#endif /* STM32_I2C_USE_I2C */
+
+#if STM32_I2C_USE_I2C2
+ i2cObjectInit(&I2CD2);
+ I2CD2.id_i2c = I2C2;
+
+#if I2C_SUPPORTS_CALLBACKS
+#if !(STM32_I2C_I2C2_USE_POLLING_WAIT)
+ I2CD2.timer = &(STM32_I2C_I2C2_USE_GPT_TIM);
+ I2CD2.timer_cfg = &i2c2gptcfg;
+#endif /* !(STM32_I2C_I2C2_USE_POLLING_WAIT) */
+#endif /* I2C_SUPPORTS_CALLBACKS */
+
+#endif /* STM32_I2C_USE_I2C2 */
+}
+
+/**
+ * @brief Configures and activates the I2C peripheral.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ */
+void i2c_lld_start(I2CDriver *i2cp) {
+ if (i2cp->id_state == I2C_STOP) { /* If in stopped state then enables the I2C clock.*/
+#if STM32_I2C_USE_I2C1
+ if (&I2CD1 == i2cp) {
+#if I2C_SUPPORTS_CALLBACKS
+ NVICEnableVector(I2C1_EV_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_I2C_I2C1_IRQ_PRIORITY));
+#endif /* I2C_SUPPORTS_CALLBACKS */
+ NVICEnableVector(I2C1_ER_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_I2C_I2C1_IRQ_PRIORITY));
+ rccEnableI2C1(FALSE);
+ }
+#endif
+#if STM32_I2C_USE_I2C2
+ if (&I2CD2 == i2cp) {
+#if I2C_SUPPORTS_CALLBACKS
+ NVICEnableVector(I2C2_EV_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_I2C_I2C1_IRQ_PRIORITY));
+#endif /* I2C_SUPPORTS_CALLBACKS */
+ NVICEnableVector(I2C2_ER_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_I2C_I2C1_IRQ_PRIORITY));
+ rccEnableI2C2(FALSE);
+ }
+#endif
+ }
+
+ i2cp->id_i2c->CR1 = I2C_CR1_SWRST; /* reset i2c peripherial */
+ i2cp->id_i2c->CR1 = 0;
+ i2c_lld_set_clock(i2cp);
+ i2c_lld_set_opmode(i2cp);
+ i2cp->id_i2c->CR1 |= 1; /* enable interface */
+}
+
+void i2c_lld_reset(I2CDriver *i2cp){
+ chDbgCheck((i2cp->id_state == I2C_STOP)||(i2cp->id_state == I2C_READY),
+ "i2c_lld_reset: invalid state");
+
+ rccResetI2C1();
+}
+
+
+/**
+ * @brief Set clock speed.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ */
+void i2c_lld_set_clock(I2CDriver *i2cp) {
+ volatile uint16_t regCCR, regCR2, freq, clock_div;
+ volatile uint16_t pe_bit_saved;
+ int32_t clock_speed = i2cp->id_config->clock_speed;
+ i2cdutycycle_t duty = i2cp->id_config->duty_cycle;
+
+ chDbgCheck((i2cp != NULL) && (clock_speed > 0) && (clock_speed <= 4000000),
+ "i2c_lld_set_clock");
+
+ /**************************************************************************
+ * CR2 Configuration
+ */
+ regCR2 = i2cp->id_i2c->CR2; /* Get the I2Cx CR2 value */
+ regCR2 &= (uint16_t)~I2C_CR2_FREQ; /* Clear frequency FREQ[5:0] bits */
+ freq = (uint16_t)(STM32_PCLK1 / 1000000); /* Set frequency bits depending on pclk1 value */
+#ifdef STM32F4XX
+ chDbgCheck((freq >= 2) && (freq <= 42),
+ "i2c_lld_set_clock() : Peripheral clock freq. out of range");
+#else
+ chDbgCheck((freq >= 2) && (freq <= 36),
+ "i2c_lld_set_clock() : Peripheral clock freq. out of range");
+#endif
+ regCR2 |= freq;
+ i2cp->id_i2c->CR2 = regCR2;
+
+ /**************************************************************************
+ * CCR Configuration
+ */
+ pe_bit_saved = (i2cp->id_i2c->CR1 & I2C_CR1_PE);
+ i2cp->id_i2c->CR1 &= (uint16_t)~I2C_CR1_PE; /* Disable the selected I2C peripheral to configure TRISE */
+ regCCR = 0; /* Clear F/S, DUTY and CCR[11:0] bits */
+ clock_div = I2C_CCR_CCR;
+
+ if (clock_speed <= 100000) { /* Configure clock_div in standard mode */
+ chDbgAssert(duty == STD_DUTY_CYCLE,
+ "i2c_lld_set_clock(), #1",
+ "Invalid standard mode duty cycle");
+ clock_div = (uint16_t)(STM32_PCLK1 / (clock_speed * 2)); /* Standard mode clock_div calculate: Tlow/Thigh = 1/1 */
+ if (clock_div < 0x04) clock_div = 0x04; /* Test if CCR value is under 0x4, and set the minimum allowed value */
+ regCCR |= (clock_div & I2C_CCR_CCR); /* Set clock_div value for standard mode */
+ i2cp->id_i2c->TRISE = freq + 1; /* Set Maximum Rise Time for standard mode */
+ }
+ else if(clock_speed <= 400000) { /* Configure clock_div in fast mode */
+ chDbgAssert((duty == FAST_DUTY_CYCLE_2) ||
+ (duty == FAST_DUTY_CYCLE_16_9),
+ "i2c_lld_set_clock(), #2",
+ "Invalid fast mode duty cycle");
+ if(duty == FAST_DUTY_CYCLE_2) {
+ clock_div = (uint16_t)(STM32_PCLK1 / (clock_speed * 3)); /* Fast mode clock_div calculate: Tlow/Thigh = 2/1 */
+ }
+ else if(duty == FAST_DUTY_CYCLE_16_9) {
+ clock_div = (uint16_t)(STM32_PCLK1 / (clock_speed * 25)); /* Fast mode clock_div calculate: Tlow/Thigh = 16/9 */
+ regCCR |= I2C_CCR_DUTY; /* Set DUTY bit */
+ }
+ if(clock_div < 0x01) clock_div = 0x01; /* Test if CCR value is under 0x1, and set the minimum allowed value */
+ regCCR |= (I2C_CCR_FS | (clock_div & I2C_CCR_CCR)); /* Set clock_div value and F/S bit for fast mode*/
+ i2cp->id_i2c->TRISE = (freq * 300 / 1000) + 1; /* Set Maximum Rise Time for fast mode */
+ }
+ chDbgAssert((clock_div <= I2C_CCR_CCR),
+ "i2c_lld_set_clock(), #3", "Too low clock clock speed selected");
+
+ i2cp->id_i2c->CCR = regCCR; /* Write to I2Cx CCR */
+ i2cp->id_i2c->CR1 |= pe_bit_saved; /* restore the I2C peripheral enabled state */
+}
+
+/**
+ * @brief Set operation mode of I2C hardware.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ */
+void i2c_lld_set_opmode(I2CDriver *i2cp) {
+ i2copmode_t opmode = i2cp->id_config->op_mode;
+ uint16_t regCR1;
+
+ regCR1 = i2cp->id_i2c->CR1; /* Get the I2Cx CR1 value */
+ switch(opmode){
+ case OPMODE_I2C:
+ regCR1 &= (uint16_t)~(I2C_CR1_SMBUS|I2C_CR1_SMBTYPE);
+ break;
+ case OPMODE_SMBUS_DEVICE:
+ regCR1 |= I2C_CR1_SMBUS;
+ regCR1 &= (uint16_t)~(I2C_CR1_SMBTYPE);
+ break;
+ case OPMODE_SMBUS_HOST:
+ regCR1 |= (I2C_CR1_SMBUS|I2C_CR1_SMBTYPE);
+ break;
+ }
+
+ i2cp->id_i2c->CR1 = regCR1; /* Write to I2Cx CR1 */
+}
+
+/**
+ * @brief Set own address.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ */
+void i2c_lld_set_own_address(I2CDriver *i2cp) {
+ /* TODO: dual address mode */
+
+ i2cp->id_i2c->OAR1 |= 1 << 14;
+
+ if (&(i2cp->id_config->own_addr_10) == NULL){ /* only 7-bit address */
+ i2cp->id_i2c->OAR1 &= (~I2C_OAR1_ADDMODE);
+ i2cp->id_i2c->OAR1 |= i2cp->id_config->own_addr_7 << 1;
+ }
+ else {
+ chDbgAssert((i2cp->id_config->own_addr_10 < 1024),
+ "i2c_lld_set_own_address(), #1", "10-bit address longer then 10 bit")
+ i2cp->id_i2c->OAR1 |= I2C_OAR1_ADDMODE;
+ i2cp->id_i2c->OAR1 |= i2cp->id_config->own_addr_10;
+ }
+}
+
+
+/**
+ * @brief Deactivates the I2C peripheral.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ */
+void i2c_lld_stop(I2CDriver *i2cp) {
+ if (i2cp->id_state == I2C_READY) { /* If in ready state then disables the I2C clock.*/
+#if STM32_I2C_USE_I2C1
+ if (&I2CD1 == i2cp) {
+ NVICDisableVector(I2C1_EV_IRQn);
+ NVICDisableVector(I2C1_ER_IRQn);
+ rccDisableI2C1(FALSE);
+ }
+#endif
+#if STM32_I2C_USE_I2C2
+ if (&I2CD2 == i2cp) {
+ NVICDisableVector(I2C2_EV_IRQn);
+ NVICDisableVector(I2C2_ER_IRQn);
+ rccDisableI2C2(FALSE);
+ }
+#endif
+ }
+
+ i2cp->id_state = I2C_STOP;
+}
+
+
+#if I2C_SUPPORTS_CALLBACKS
+/**
+ * @brief Transmits data via the I2C bus as master.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] slave_addr Slave device address. Bits 0-9 contain slave
+ * device address. Bit 15 must be set to 1 if 10-bit
+ * addressing modes used. Otherwise keep it cleared.
+ * Bits 10-14 unused.
+ * @param[in] txbuf pointer to the transmit buffer
+ * @param[in] txbytes number of bytes to be transmitted
+ * @param[in] rxbuf pointer to the receive buffer
+ * @param[in] rxbytes number of bytes to be received
+ */
+void i2c_lld_master_transmit(I2CDriver *i2cp, uint16_t slave_addr,
+ uint8_t *txbuf, size_t txbytes, uint8_t *rxbuf, size_t rxbytes) {
+
+ /* "waiting" for STOP bit routine*/
+ #if STM32_I2C_I2C1_USE_POLLING_WAIT
+ uint32_t timeout = I2C_POLLING_TIMEOUT;
+ while((i2cp->id_i2c->CR1 & I2C_CR1_STOP) && timeout)
+ timeout--;
+ chDbgAssert((timeout > 0), "i2c_lld_master_transmit(), #1", "time to STOP is out");
+ #else
+ chDbgAssert(!(i2cp->flags & I2C_FLG_TIMER_ARMED), "i2c_lld_master_transmit(), #1", "time to STOP is out");
+ if ((i2cp->id_i2c->CR1 & I2C_CR1_STOP) && i2cp->timer != NULL && i2cp->timer_cfg != NULL){
+ chSysLockFromIsr();
+ gptStartOneShotI(i2cp->timer, I2C_STOP_GPT_TIMEOUT);
+ i2cp->flags |= I2C_FLG_TIMER_ARMED;
+ chSysUnlockFromIsr();
+ return;
+ }
+ #endif /* STM32_I2C_I2C1_USE_POLLING_WAIT */
+
+ /* init driver fields */
+ i2cp->slave_addr = slave_addr;
+ i2cp->txbytes = txbytes;
+ i2cp->rxbytes = rxbytes;
+ i2cp->txbuf = txbuf;
+ i2cp->rxbuf = rxbuf;
+
+ /* init address fields */
+ if(slave_addr & 0x8000){ /* 10-bit mode used */
+ i2cp->slave_addr1 = ((slave_addr >>7) & 0x0006); /* add the two msb of 10-bit address to the header */
+ i2cp->slave_addr1 |= 0xF0; /* add the header bits with LSB = 0 -> write */
+ i2cp->slave_addr2 = slave_addr & 0x00FF; /* the remaining 8 bit of 10-bit address */
+ }
+ else{
+ i2cp->slave_addr1 = ((slave_addr <<1) & 0x00FE); /* LSB = 0 -> write */
+ }
+
+ /* setting flags and register bits */
+ i2cp->flags = 0;
+ i2cp->errors = 0;
+ i2cp->id_i2c->CR1 &= ~I2C_CR1_POS;
+ i2cp->id_i2c->CR1 |= I2C_CR1_START;
+ i2cp->id_i2c->CR2 |= (I2C_CR2_ITERREN|I2C_CR2_ITEVTEN|I2C_CR2_ITBUFEN); /* enable ERR, EVT & BUF ITs */
+}
+
+/**
+ * @brief Receives data from the I2C bus.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] slave_addr Slave device address. Bits 0-9 contain slave
+ * device address. Bit 15 must be set to 1 if 10-bit
+ * addressing modes used. Otherwise keep it cleared.
+ * Bits 10-14 unused.
+ * @param[in] rxbuf pointer to the receive buffer
+ * @param[in] rxbytes number of bytes to be received
+ */
+void i2c_lld_master_receive(I2CDriver *i2cp, uint16_t slave_addr,
+ uint8_t *rxbuf, size_t rxbytes){
+
+ chDbgAssert((i2cp->id_i2c->SR1 + i2cp->id_i2c->SR2) == 0,
+ "i2c_lld_master_receive(), #1",
+ "some interrupt sources not clear");
+
+ /* "waiting" for STOP bit routine*/
+ #if STM32_I2C_I2C1_USE_POLLING_WAIT
+ uint32_t timeout = I2C_POLLING_TIMEOUT;
+ while((i2cp->id_i2c->CR1 & I2C_CR1_STOP) && timeout)
+ timeout--;
+ chDbgAssert((timeout > 0), "i2c_lld_master_receive(), #1", "time to STOP is out");
+ #else
+ chDbgAssert(!(i2cp->flags & I2C_FLG_TIMER_ARMED), "i2c_lld_master_receive(), #1", "time to STOP is out");
+ if ((i2cp->id_i2c->CR1 & I2C_CR1_STOP) && i2cp->timer != NULL && i2cp->timer_cfg != NULL){
+ chSysLockFromIsr();
+ gptStartOneShotI(i2cp->timer, I2C_STOP_GPT_TIMEOUT);
+ i2cp->flags |= I2C_FLG_TIMER_ARMED;
+ chSysUnlockFromIsr();
+ return;
+ }
+ #endif /* STM32_I2C_I2C1_USE_POLLING_WAIT */
+
+ /* init driver fields */
+ i2cp->slave_addr = slave_addr;
+ i2cp->rxbytes = rxbytes;
+ i2cp->rxbuf = rxbuf;
+
+ /* init address fields */
+ if(slave_addr & 0x8000){ /* 10-bit mode used */
+ i2cp->slave_addr1 = ((slave_addr >>7) & 0x0006); /* add the two msb of 10-bit address to the header */
+ i2cp->slave_addr1 |= 0xF0; /* add the header bits (the LSB -> 1 will be add to second */
+ i2cp->slave_addr2 = slave_addr & 0x00FF; /* the remaining 8 bit of 10-bit address */
+ }
+ else{
+ i2cp->slave_addr1 = ((slave_addr <<1) | 0x01); /* LSB = 1 -> receive */
+ }
+
+ /* setting flags and register bits */
+ i2cp->flags |= I2C_FLG_MASTER_RECEIVER;
+ i2cp->errors = 0;
+
+ i2cp->id_i2c->CR1 |= I2C_CR1_ACK; /* acknowledge returned */
+ i2cp->id_i2c->CR1 &= ~I2C_CR1_POS;
+
+ if(i2cp->rxbytes == 1) { /* Only one byte to be received */
+ i2cp->flags |= I2C_FLG_1BTR;
+ }
+ else if(i2cp->rxbytes == 2) { /* Only two bytes to be received */
+ i2cp->flags |= I2C_FLG_2BTR;
+ i2cp->id_i2c->CR1 |= I2C_CR1_POS; /* Acknowledge Position */
+ }
+
+ i2cp->id_i2c->CR1 |= I2C_CR1_START; /* send start bit */
+ i2cp->id_i2c->CR2 |= (I2C_CR2_ITERREN|I2C_CR2_ITEVTEN|I2C_CR2_ITBUFEN); /* enable ERR, EVT & BUF ITs */
+}
+
+
+/**
+ * @brief Realize read-though-write behavior.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ *
+ * @notapi
+ */
+void i2c_lld_master_transceive(I2CDriver *i2cp){
+
+ chDbgAssert((i2cp != NULL) && (i2cp->slave_addr1 != 0) &&\
+ (i2cp->rxbytes > 0) && (i2cp->rxbuf != NULL),
+ "i2c_lld_master_transceive(), #1",
+ "");
+
+ i2cp->id_state = I2C_ACTIVE_TRANSCEIVE;
+
+ /* "waiting" for START bit routine*/
+ #if STM32_I2C_I2C1_USE_POLLING_WAIT
+ uint32_t timeout = I2C_POLLING_TIMEOUT;
+ while((i2cp->id_i2c->CR1 & I2C_CR1_START) && timeout);
+ timeout--;
+ chDbgAssert((timeout > 0), "i2c_lld_master_transceive(), #1", "time to START is out");
+ #else
+ chDbgAssert(!(i2cp->flags & I2C_FLG_TIMER_ARMED), "i2c_lld_master_transceive(), #1", "time to START is out");
+ if ((i2cp->id_i2c->CR1 & I2C_CR1_START) && i2cp->timer != NULL && i2cp->timer_cfg != NULL){
+ chSysLockFromIsr();
+ gptStartOneShotI(i2cp->timer, I2C_START_GPT_TIMEOUT);
+ i2cp->flags |= I2C_FLG_TIMER_ARMED;
+ chSysUnlockFromIsr();
+ return;
+ }
+ #endif /* STM32_I2C_I2C1_USE_POLLING_WAIT */
+
+ /* init address fields */
+ if(i2cp->slave_addr & 0x8000){ /* 10-bit mode used */
+ i2cp->slave_addr1 = ((i2cp->slave_addr >>7) & 0x0006);/* add the two msb of 10-bit address to the header */
+ i2cp->slave_addr1 |= 0xF0; /* add the header bits (the LSB -> 1 will be add to second */
+ i2cp->slave_addr2 = i2cp->slave_addr & 0x00FF; /* the remaining 8 bit of 10-bit address */
+ }
+ else{
+ i2cp->slave_addr1 |= 0x01;
+ }
+
+ /* setting flags and register bits */
+ i2cp->flags |= I2C_FLG_MASTER_RECEIVER;
+ i2cp->errors = 0;
+ i2cp->id_i2c->CR1 |= I2C_CR1_ACK; /* acknowledge returned */
+ i2cp->id_i2c->CR1 &= ~I2C_CR1_POS;
+
+ if(i2cp->rxbytes == 1) { /* Only one byte to be received */
+ i2cp->flags |= I2C_FLG_1BTR;
+ }
+ else if(i2cp->rxbytes == 2) { /* Only two bytes to be received */
+ i2cp->flags |= I2C_FLG_2BTR;
+ i2cp->id_i2c->CR1 |= I2C_CR1_POS; /* Acknowledge Position */
+ }
+
+ i2cp->id_i2c->CR2 |= (I2C_CR2_ITERREN|I2C_CR2_ITEVTEN|I2C_CR2_ITBUFEN); /* enable ERR, EVT & BUF ITs */
+}
+
+#else /*I2C_SUPPORTS_CALLBACKS*/
+
+/**
+ * @brief Synchronously transmits data via the I2C bus as master.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] slave_addr Slave device address. Bits 0-9 contain slave
+ * device address. Bit 15 must be set to 1 if 10-bit
+ * addressing modes used. Otherwise keep it cleared.
+ * Bits 10-14 unused.
+ * @param[in] txbuf pointer to the transmit buffer
+ * @param[in] txbytes number of bytes to be transmitted
+ * @param[in] rxbuf pointer to the receive buffer
+ * @param[in] rxbytes number of bytes to be received
+ */
+void i2c_lld_master_transmit(I2CDriver *i2cp, uint16_t slave_addr,
+ uint8_t *txbuf, size_t txbytes, uint8_t *rxbuf, size_t rxbytes) {
+
+ /* init driver fields */
+ i2cp->slave_addr = slave_addr;
+ i2cp->txbytes = txbytes;
+ i2cp->rxbytes = rxbytes;
+ i2cp->txbuf = txbuf;
+ i2cp->rxbuf = rxbuf;
+
+ /* init address fields */
+ if(slave_addr & 0x8000){ /* 10-bit mode used */
+ i2cp->slave_addr1 = ((slave_addr >>7) & 0x0006); /* add the two msb of 10-bit address to the header */
+ i2cp->slave_addr1 |= 0xF0; /* add the header bits with LSB = 0 -> write */
+ i2cp->slave_addr2 = slave_addr & 0x00FF; /* the remaining 8 bit of 10-bit address */
+ }
+ else{
+ i2cp->slave_addr1 = ((slave_addr <<1) & 0x00FE); /* LSB = 0 -> write */
+ }
+
+ i2cp->flags = 0;
+ i2cp->errors = 0;
+ i2cp->id_i2c->CR1 &= ~I2C_CR1_POS;
+ i2cp->id_i2c->CR2 &= ~I2C_CR2_ITEVTEN; /* disable event interrupts */
+ i2cp->id_i2c->CR2 |= I2C_CR2_ITERREN; /* enable error interrupts */
+
+ i2cp->id_i2c->CR1 |= I2C_CR1_START;
+ while (!(i2cp->id_i2c->SR1 & I2C_SR1_SB))
+ ;
+ i2cp->id_i2c->DR = i2cp->slave_addr1;
+ while (!(i2cp->id_i2c->SR1 & I2C_SR1_ADDR))
+ ;
+ while (!(i2cp->id_i2c->SR2 & I2C_SR2_BUSY))
+ ;
+ i2cp->id_i2c->DR = *txbuf;
+ txbuf++;
+ i2cp->txbytes--;
+ while(i2cp->txbytes > 0){
+ while(!(i2cp->id_i2c->SR1 & I2C_SR1_BTF))
+ ;
+ i2cp->id_i2c->DR = *txbuf;
+ txbuf++;
+ i2cp->txbytes--;
+ }
+ while(!(i2cp->id_i2c->SR1 & I2C_SR1_BTF))
+ ;
+ if(rxbytes == 0){
+ i2cp->id_i2c->CR1 |= I2C_CR1_STOP;
+ while (i2cp->id_i2c->CR1 & I2C_CR1_STOP)
+ ;
+ }
+ else{
+ i2c_lld_master_receive(i2cp, slave_addr, rxbuf, rxbytes);
+ }
+}
+
+
+/**
+ * @brief Synchronously receives data from the I2C bus.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] slave_addr Slave device address. Bits 0-9 contain slave
+ * device address. Bit 15 must be set to 1 if 10-bit
+ * addressing modes used. Otherwise keep it cleared.
+ * Bits 10-14 unused.
+ * @param[in] rxbuf pointer to the receive buffer
+ * @param[in] rxbytes number of bytes to be received
+ */
+void i2c_lld_master_receive(I2CDriver *i2cp, uint16_t slave_addr,
+ uint8_t *rxbuf, size_t rxbytes){
+
+ /* init driver fields */
+ i2cp->slave_addr = slave_addr;
+ i2cp->rxbytes = rxbytes;
+ i2cp->rxbuf = rxbuf;
+
+ /* init address fields */
+ if(slave_addr & 0x8000){ /* 10-bit mode used */
+ i2cp->slave_addr1 = ((slave_addr >>7) & 0x0006); /* add the two msb of 10-bit address to the header */
+ i2cp->slave_addr1 |= 0xF0; /* add the header bits (the LSB -> 1 will be add to second */
+ i2cp->slave_addr2 = slave_addr & 0x00FF; /* the remaining 8 bit of 10-bit address */
+ }
+ else{
+ i2cp->slave_addr1 = ((slave_addr <<1) | 0x01); /* LSB = 1 -> receive */
+ }
+
+
+ /* setting flags and register bits */
+ i2cp->flags = 0;
+ i2cp->errors = 0;
+ i2cp->id_i2c->CR1 &= ~I2C_CR1_POS;
+ i2cp->id_i2c->CR2 &= ~I2C_CR2_ITEVTEN; /* disable event interrupts */
+ i2cp->id_i2c->CR2 |= I2C_CR2_ITERREN; /* enable error interrupts */
+
+ i2cp->id_i2c->CR1 |= I2C_CR1_START;
+ while (!(i2cp->id_i2c->SR1 & I2C_SR1_SB))
+ ;
+
+ i2cp->id_i2c->DR = i2cp->slave_addr1;
+ while (!(i2cp->id_i2c->SR1 & I2C_SR1_ADDR))
+ ;
+
+ if(i2cp->rxbytes >= 3){ /* more than 2 bytes receiving procedure */
+ while(!(i2cp->id_i2c->SR2 & I2C_SR2_BUSY)) /* to clear ADDR bit */
+ ;
+ while(i2cp->rxbytes > 3){
+ while(!(i2cp->id_i2c->SR1 & I2C_SR1_BTF))
+ ;
+ *rxbuf = i2cp->id_i2c->DR;
+ rxbuf++;
+ i2cp->rxbytes--;
+ }
+ while(!(i2cp->id_i2c->SR1 & I2C_SR1_BTF)) /* stopping procedure */
+ ;
+ i2cp->id_i2c->CR1 &= ~I2C_CR1_ACK;
+ chSysLock();
+ i2cp->id_i2c->CR1 |= I2C_CR1_STOP;
+ *rxbuf = i2cp->id_i2c->DR;
+ rxbuf++;
+ i2cp->rxbytes--;
+ chSysUnlock();
+ while(!(i2cp->id_i2c->SR1 & I2C_SR1_RXNE))
+ ;
+ *rxbuf = i2cp->id_i2c->DR;
+ rxbuf++;
+ i2cp->rxbytes--;
+ while (i2cp->id_i2c->CR1 & I2C_CR1_STOP)
+ ;
+ i2cp->id_i2c->CR1 |= I2C_CR1_ACK;
+ }
+ else{ /* 1 or 2 bytes receiving procedure */
+ if(i2cp->rxbytes == 2){
+ i2cp->id_i2c->CR1 |= I2C_CR1_POS;
+ chSysLock();
+ while(!(i2cp->id_i2c->SR2 & I2C_SR2_BUSY)) /* to clear ADDR bit */
+ ;
+ i2cp->id_i2c->CR1 &= ~I2C_CR1_ACK;
+ chSysUnlock();
+ while(!(i2cp->id_i2c->SR1 & I2C_SR1_BTF))
+ ;
+ chSysLock();
+ i2cp->id_i2c->CR1 |= I2C_CR1_STOP;
+ *rxbuf = i2cp->id_i2c->DR;
+ rxbuf++;
+ i2cp->rxbytes--;
+ chSysUnlock();
+ *rxbuf = i2cp->id_i2c->DR;
+ rxbuf++;
+ i2cp->rxbytes--;
+ while (i2cp->id_i2c->CR1 & I2C_CR1_STOP)
+ ;
+ i2cp->id_i2c->CR1 &= ~I2C_CR1_POS;
+ i2cp->id_i2c->CR1 |= I2C_CR1_ACK;
+ }
+ else{ /* 1 byte */
+ i2cp->id_i2c->CR1 &= ~I2C_CR1_ACK;
+ chSysLock();
+ while(!(i2cp->id_i2c->SR2 & I2C_SR2_BUSY)) /* to clear ADDR bit */
+ ;
+ i2cp->id_i2c->CR1 |= I2C_CR1_STOP;
+ chSysUnlock();
+ while(!(i2cp->id_i2c->SR1 & I2C_SR1_RXNE))
+ ;
+ *rxbuf = i2cp->id_i2c->DR;
+ rxbuf++;
+ i2cp->rxbytes--;
+ while (i2cp->id_i2c->CR1 & I2C_CR1_STOP)
+ ;
+ i2cp->id_i2c->CR1 |= I2C_CR1_ACK;
+ }
+ }
+}
+#endif /* I2C_SUPPORTS_CALLBACKS */
+
+#undef rxBuffp
+#undef txBuffp
+
+#endif /* HAL_USE_I2C */
diff --git a/os/hal/platforms/STM32/I2Cv1/i2c_lld.h b/os/hal/platforms/STM32/I2Cv1/i2c_lld.h
new file mode 100644
index 000000000..81a9f62dc
--- /dev/null
+++ b/os/hal/platforms/STM32/I2Cv1/i2c_lld.h
@@ -0,0 +1,318 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file STM32/i2c_lld.h
+ * @brief STM32 I2C subsystem low level driver header.
+ * @addtogroup I2C
+ * @{
+ */
+
+#ifndef _I2C_LLD_H_
+#define _I2C_LLD_H_
+
+#if HAL_USE_I2C || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief Switch between callback based and synchronouse driver.
+ * @note The default is synchronouse.
+ */
+#if !defined(I2C_SUPPORTS_CALLBACKS) || defined(__DOXYGEN__)
+#define I2C_SUPPORTS_CALLBACKS TRUE
+#endif
+
+/**
+ * @brief I2C1 driver synchronization choice between GPT and polling.
+ * @note The default is polling wait.
+ */
+#if !defined(STM32_I2C_I2C1_USE_GPT_TIM) || \
+ !defined(STM32_I2C_I2C1_USE_POLLING_WAIT) || \
+ defined(__DOXYGEN__)
+#define STM32_I2C_I2C1_USE_POLLING_WAIT TRUE
+#endif
+
+/**
+ * @brief I2C2 driver synchronization choice between GPT and polling.
+ * @note The default is polling wait.
+ */
+#if !defined(STM32_I2C_I2C2_USE_GPT_TIM) || \
+ !defined(STM32_I2C_I2C2_USE_POLLING_WAIT) || \
+ defined(__DOXYGEN__)
+#define STM32_I2C_I2C2_USE_POLLING_WAIT TRUE
+#endif
+
+/**
+ * @brief I2C1 driver enable switch.
+ * @details If set to @p TRUE the support for I2C1 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_I2C_USE_I2C1) || defined(__DOXYGEN__)
+#define STM32_I2C_USE_I2C1 TRUE
+#endif
+
+/**
+ * @brief I2C2 driver enable switch.
+ * @details If set to @p TRUE the support for I2C2 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_I2C_USE_I2C2) || defined(__DOXYGEN__)
+#define STM32_I2C_USE_I2C2 TRUE
+#endif
+
+/**
+ * @brief I2C1 interrupt priority level setting.
+ * @note @p BASEPRI_KERNEL >= @p STM32_I2C_I2C1_IRQ_PRIORITY > @p PRIORITY_PENDSV.
+ */
+#if !defined(STM32_I2C_I2C1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C1_IRQ_PRIORITY 0xA0
+#endif
+
+/**
+ * @brief I2C2 interrupt priority level setting.
+ * @note @p BASEPRI_KERNEL >= @p STM32_I2C_I2C2_IRQ_PRIORITY > @p PRIORITY_PENDSV.
+ */
+#if !defined(STM32_I2C_I2C2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C2_IRQ_PRIORITY 0xA0
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/** @brief EV5 */
+#define I2C_EV5_MASTER_MODE_SELECT ((uint32_t)(((I2C_SR2_MSL|I2C_SR2_BUSY)<< 16)|I2C_SR1_SB)) /* BUSY, MSL and SB flag */
+/** @brief EV6 */
+#define I2C_EV6_MASTER_TRA_MODE_SELECTED ((uint32_t)(((I2C_SR2_MSL|I2C_SR2_BUSY|I2C_SR2_TRA)<< 16)|I2C_SR1_ADDR|I2C_SR1_TXE)) /* BUSY, MSL, ADDR, TXE and TRA flags */
+#define I2C_EV6_MASTER_REC_MODE_SELECTED ((uint32_t)(((I2C_SR2_MSL|I2C_SR2_BUSY)<< 16)|I2C_SR1_ADDR)) /* BUSY, MSL and ADDR flags */
+/** @brief EV7 */
+#define I2C_EV7_MASTER_REC_BYTE_RECEIVED ((uint32_t)(((I2C_SR2_MSL|I2C_SR2_BUSY)<< 16)|I2C_SR1_RXNE)) /* BUSY, MSL and RXNE flags */
+#define I2C_EV7_MASTER_REC_BYTE_QUEUED ((uint32_t)(((I2C_SR2_MSL|I2C_SR2_BUSY)<< 16)|I2C_SR1_BTF|I2C_SR1_RXNE)) /* BUSY, MSL, RXNE and BTF flags*/
+/** @brief EV8 */
+#define I2C_EV8_MASTER_BYTE_TRANSMITTING ((uint32_t)(((I2C_SR2_MSL|I2C_SR2_BUSY|I2C_SR2_TRA)<< 16)|I2C_SR1_TXE)) /* TRA, BUSY, MSL, TXE flags */
+/** @brief EV8_2 */
+#define I2C_EV8_2_MASTER_BYTE_TRANSMITTED ((uint32_t)(((I2C_SR2_MSL|I2C_SR2_BUSY|I2C_SR2_TRA)<< 16)|I2C_SR1_BTF|I2C_SR1_TXE)) /* TRA, BUSY, MSL, TXE and BTF flags */
+/** @brief EV9 */
+#define I2C_EV9_MASTER_ADDR_10BIT ((uint32_t)(((I2C_SR2_MSL|I2C_SR2_BUSY)<< 16)|I2C_SR1_ADD10)) /* BUSY, MSL and ADD10 flags */
+#define I2C_EV_MASK 0x00FFFFFF /* First byte zeroed because there is no need of PEC register part from SR2 */
+
+#define I2C_FLG_1BTR 0x01 /* Single byte to be received and processed */
+#define I2C_FLG_2BTR 0x02 /* Two bytes to be received and processed */
+#define I2C_FLG_3BTR 0x04 /* Last three received bytes to be processed */
+#define I2C_FLG_MASTER_RECEIVER 0x10
+#define I2C_FLG_HEADER_SENT 0x80
+#define I2C_FLG_TIMER_ARMED 0x40 /* Used to check locks on the bus */
+
+#define EV6_SUBEV_MASK (I2C_FLG_1BTR|I2C_FLG_2BTR|I2C_FLG_MASTER_RECEIVER)
+#define EV7_SUBEV_MASK (I2C_FLG_2BTR|I2C_FLG_3BTR|I2C_FLG_MASTER_RECEIVER)
+
+#define I2C_EV6_1_MASTER_REC_2BTR_MODE_SELECTED (I2C_FLG_2BTR|I2C_FLG_MASTER_RECEIVER)
+#define I2C_EV6_3_MASTER_REC_1BTR_MODE_SELECTED (I2C_FLG_1BTR|I2C_FLG_MASTER_RECEIVER)
+#define I2C_EV7_2_MASTER_REC_3BYTES_TO_PROCESS (I2C_FLG_3BTR|I2C_FLG_MASTER_RECEIVER)
+#define I2C_EV7_3_MASTER_REC_2BYTES_TO_PROCESS (I2C_FLG_2BTR|I2C_FLG_MASTER_RECEIVER)
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief I2C Driver condition flags type.
+ */
+typedef uint32_t i2cflags_t;
+
+typedef enum {
+ OPMODE_I2C = 1,
+ OPMODE_SMBUS_DEVICE = 2,
+ OPMODE_SMBUS_HOST = 3,
+} i2copmode_t;
+
+typedef enum {
+ STD_DUTY_CYCLE = 1,
+ FAST_DUTY_CYCLE_2 = 2,
+ FAST_DUTY_CYCLE_16_9 = 3,
+} i2cdutycycle_t;
+
+/**
+ * @brief Driver configuration structure.
+ */
+typedef struct {
+ i2copmode_t op_mode; /**< @brief Specifies the I2C mode.*/
+ uint32_t clock_speed; /**< @brief Specifies the clock frequency. Must be set to a value lower than 400kHz */
+ i2cdutycycle_t duty_cycle; /**< @brief Specifies the I2C fast mode duty cycle */
+ uint8_t own_addr_7; /**< @brief Specifies the first device 7-bit own address. */
+ uint16_t own_addr_10; /**< @brief Specifies the second part of device own address in 10-bit mode. Set to NULL if not used. */
+ uint8_t nbit_own_addr; /**< @brief Specifies if 7-bit or 10-bit address is acknowledged */
+} I2CConfig;
+
+
+/**
+ * @brief Type of a structure representing an I2C driver.
+ */
+typedef struct I2CDriver I2CDriver;
+
+/**
+ * @brief Type of a structure representing an I2C slave config.
+ */
+typedef struct I2CSlaveConfig I2CSlaveConfig;
+
+/**
+ * @brief Structure representing an I2C driver.
+ */
+struct I2CDriver{
+ /**
+ * @brief Driver state.
+ */
+ i2cstate_t id_state;
+
+#if I2C_USE_WAIT
+ /**
+ * @brief Thread waiting for I/O completion.
+ */
+ Thread *id_thread;
+#endif /* I2C_USE_WAIT */
+#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
+#if CH_USE_MUTEXES || defined(__DOXYGEN__)
+ /**
+ * @brief Mutex protecting the bus.
+ */
+ Mutex id_mutex;
+#elif CH_USE_SEMAPHORES
+ Semaphore id_semaphore;
+#endif
+#endif /* I2C_USE_MUTUAL_EXCLUSION */
+
+ /**
+ * @brief Current configuration data.
+ */
+ const I2CConfig *id_config;
+ /**
+ * @brief Current slave configuration data.
+ */
+ const I2CSlaveConfig *id_slave_config;
+
+ __IO size_t txbytes; /*!< @brief Number of bytes to be transmitted. */
+ __IO size_t rxbytes; /*!< @brief Number of bytes to be received. */
+ uint8_t *rxbuf; /*!< @brief Pointer to receive buffer. */
+ uint8_t *txbuf; /*!< @brief Pointer to transmit buffer.*/
+ uint8_t *rxbuff_p; /*!< @brief Pointer to the current byte in slave rx buffer. */
+ uint8_t *txbuff_p; /*!< @brief Pointer to the current byte in slave tx buffer. */
+
+ __IO i2cflags_t errors; /*!< @brief Error flags.*/
+ __IO i2cflags_t flags; /*!< @brief State flags.*/
+
+ uint16_t slave_addr; /*!< @brief Current slave address. */
+ uint8_t slave_addr1;/*!< @brief 7-bit address of the slave with r\w bit.*/
+ uint8_t slave_addr2;/*!< @brief Uses in 10-bit address mode. */
+
+#if CH_USE_EVENTS
+ EventSource sevent; /*!< @brief Status Change @p EventSource.*/
+#endif
+
+ /*********** End of the mandatory fields. **********************************/
+
+ /**
+ * @brief Pointer to the I2Cx registers block.
+ */
+ I2C_TypeDef *id_i2c;
+
+#if !(STM32_I2C_I2C1_USE_POLLING_WAIT)
+ /* TODO: capability to switch this GPT fields off */
+ /**
+ * @brief Timer for waiting STOP condition on the bus.
+ * @details This is workaround for STM32 buggy I2C cell.
+ */
+ GPTDriver *timer;
+
+ /**
+ * @brief Config for workaround timer.
+ */
+ const GPTConfig *timer_cfg;
+#endif /* !(STM32_I2C_I2C1_USE_POLLING_WAIT) */
+};
+
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+#define i2c_lld_bus_is_busy(i2cp) \
+ (i2cp->id_i2c->SR2 & I2C_SR2_BUSY)
+
+
+/* Wait until BUSY flag is reset: a STOP has been generated on the bus
+ * signaling the end of transmission. Normally this wait function
+ * does not block thread, only if slave not response it does.
+ */
+#define i2c_lld_wait_bus_free(i2cp) { \
+ uint32_t tmo = 0xfffff; \
+ while((i2cp->id_i2c->SR2 & I2C_SR2_BUSY) && tmo--) \
+ ; \
+}
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+/** @cond never*/
+#if STM32_I2C_USE_I2C1
+extern I2CDriver I2CD1;
+#endif
+
+#if STM32_I2C_USE_I2C2
+extern I2CDriver I2CD2;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void i2c_lld_init(void);
+void i2c_lld_reset(I2CDriver *i2cp);
+void i2c_lld_set_clock(I2CDriver *i2cp);
+void i2c_lld_set_opmode(I2CDriver *i2cp);
+void i2c_lld_set_own_address(I2CDriver *i2cp);
+void i2c_lld_start(I2CDriver *i2cp);
+void i2c_lld_stop(I2CDriver *i2cp);
+void i2c_lld_master_transmit(I2CDriver *i2cp, uint16_t slave_addr,
+ uint8_t *txbuf, size_t txbytes, uint8_t *rxbuf, size_t rxbytes);
+void i2c_lld_master_receive(I2CDriver *i2cp, uint16_t slave_addr,
+ uint8_t *rxbuf, size_t rxbytes);
+void i2c_lld_master_transceive(I2CDriver *i2cp);
+
+#ifdef __cplusplus
+}
+#endif
+/** @endcond*/
+
+#endif /* CH_HAL_USE_I2C */
+
+#endif /* _I2C_LLD_H_ */
diff --git a/os/hal/platforms/STM32/RTCv1/rtc_lld.c b/os/hal/platforms/STM32/RTCv1/rtc_lld.c
new file mode 100644
index 000000000..cae23525f
--- /dev/null
+++ b/os/hal/platforms/STM32/RTCv1/rtc_lld.c
@@ -0,0 +1,319 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file STM32/RTCv1/rtc_lld.c
+ * @brief STM32 RTC subsystem low level driver header.
+ *
+ * @addtogroup RTC
+ * @{
+ */
+
+#include "ch.h"
+#include "hal.h"
+
+#if HAL_USE_RTC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief RTC driver identifier.
+ */
+RTCDriver RTCD1;
+
+/*===========================================================================*/
+/* Driver local variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Shared IRQ handler.
+ *
+ * @param[in] rtcp pointer to a @p RTCDriver object
+ *
+ * @notapi
+ */
+static void rtc_lld_serve_interrupt(RTCDriver *rtcp) {
+
+ chSysLockFromIsr();
+
+ if ((RTC->CRH & RTC_CRH_SECIE) && (RTC->CRL & RTC_CRL_SECF)) {
+ rtcp->rtc_cb(rtcp, RTC_EVENT_SECOND);
+ RTC->CRL &= ~RTC_CRL_SECF;
+ }
+ if ((RTC->CRH & RTC_CRH_ALRIE) && (RTC->CRL & RTC_CRL_ALRF)) {
+ rtcp->rtc_cb(rtcp, RTC_EVENT_ALARM);
+ RTC->CRL &= ~RTC_CRL_ALRF;
+ }
+ if ((RTC->CRH & RTC_CRH_OWIE) && (RTC->CRL & RTC_CRL_OWF)) {
+ rtcp->rtc_cb(rtcp, RTC_EVENT_OVERFLOW);
+ RTC->CRL &= ~RTC_CRL_OWF;
+ }
+
+ chSysUnlockFromIsr();
+}
+
+/**
+ * @brief Waits for the previous registers write to finish.
+ *
+ * @notapi
+ */
+static void rtc_lld_wait_write(void) {
+
+ /* Waits registers write completion.*/
+ while (!(RTC->CRL & RTC_CRL_RTOFF))
+ ;
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/**
+ * @brief RTC interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(RTC_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ rtc_lld_serve_interrupt(&RTCD1);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Enable access to registers and initialize RTC if BKP domain
+ * was previously reseted.
+ * @note: Cold start time of LSE oscillator on STM32 platform
+ * takes about 3 seconds.
+ *
+ * @notapi
+ */
+void rtc_lld_init(void){
+ uint32_t preload;
+
+ rccEnableBKPInterface(FALSE);
+
+ /* Enables access to BKP registers.*/
+ PWR->CR |= PWR_CR_DBP;
+
+ /* If the RTC is not enabled then performs a reset of the backup domain.*/
+ if (!(RCC->BDCR & RCC_BDCR_RTCEN)) {
+ RCC->BDCR = RCC_BDCR_BDRST;
+ RCC->BDCR = 0;
+ }
+
+#if STM32_RTC == STM32_RTC_LSE
+ if (!(RCC->BDCR & RCC_BDCR_LSEON)) {
+ RCC->BDCR |= RCC_BDCR_LSEON;
+ while (!(RCC->BDCR & RCC_BDCR_LSERDY))
+ ;
+ }
+ preload = STM32_LSECLK - 1;
+#elif STM32_RTC == STM32_RTC_LSI
+ /* TODO: Move the LSI clock initialization in the HAL low level driver.*/
+ RCC->CSR |= RCC_CSR_LSION;
+ while (!(RCC->CSR & RCC_CSR_LSIRDY))
+ ;
+ /* According to errata sheet we must wait additional 100 uS for
+ stabilization.
+ TODO: Change this code, software loops are not reliable.*/
+ uint32_t tmo = (STM32_SYSCLK / 1000000) * 100;
+ while (tmo--)
+ ;
+ preload = STM32_LSICLK - 1;
+#elif STM32_RTC == STM32_RTC_HSE
+ preload = (STM32_HSICLK / 128) - 1;
+#endif
+
+ /* Selects clock source (previously enabled and stabilized).*/
+ RCC->BDCR = (RCC->BDCR & ~RCC_BDCR_RTCSEL) | STM32_RTC;
+
+ /* RTC enabled regardless its previous status.*/
+ RCC->BDCR |= RCC_BDCR_RTCEN;
+
+ /* Ensure that RTC_CNT and RTC_DIV contain actual values after enabling
+ clocking on APB1, because these values only update when APB1
+ functioning.*/
+ RTC->CRL = 0;
+ while (!(RTC->CRL & RTC_CRL_RSF))
+ ;
+
+ /* Write preload register only if its value differs.*/
+ if (preload != ((((uint32_t)(RTC->PRLH)) << 16) + (uint32_t)RTC->PRLL)) {
+
+ rtc_lld_wait_write();
+
+ /* Enters configuration mode and writes PRLx registers then leaves the
+ configuration mode.*/
+ RTC->CRL |= RTC_CRL_CNF;
+ RTC->PRLH = (uint16_t)(preload >> 16);
+ RTC->PRLL = (uint16_t)(preload & 0xFFFF);
+ RTC->CRL &= ~RTC_CRL_CNF;
+ }
+
+ /* All interrupts initially disabled.*/
+ RTC->CRH = 0;
+
+ /* Callback initially disabled.*/
+ RTCD1.rtc_cb = NULL;
+}
+
+/**
+ * @brief Set current time.
+ * @note Fractional part will be silently ignored. There is no possibility
+ * to change it on STM32F1xx platform.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] timespec pointer to a @p RTCTime structure
+ *
+ * @notapi
+ */
+void rtc_lld_set_time(RTCDriver *rtcp, const RTCTime *timespec) {
+
+ (void)rtcp;
+
+ rtc_lld_wait_write();
+
+ RTC->CRL |= RTC_CRL_CNF;
+ RTC->CNTH = (uint16_t)(timespec->tv_sec >> 16);
+ RTC->CNTL = (uint16_t)(timespec->tv_sec & 0xFFFF);
+ RTC->CRL &= ~RTC_CRL_CNF;
+}
+
+/**
+ * @brief Get current time.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[out] timespec pointer to a @p RTCTime structure
+ *
+ * @notapi
+ */
+void rtc_lld_get_time(RTCDriver *rtcp, RTCTime *timespec) {
+ uint32_t time_frac;
+
+ (void)rtcp;
+
+ time_frac = (((uint32_t)RTC->DIVH) << 16) + (uint32_t)RTC->DIVL;
+ timespec->tv_msec = (uint16_t)(((STM32_LSECLK - time_frac) * 1000) /
+ STM32_LSECLK);
+ timespec->tv_sec = (RTC->CNTH << 16) + RTC->CNTL;
+}
+
+/**
+ * @brief Set alarm time.
+ *
+ * @note Default value after BKP domain reset is 0xFFFFFFFF
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] alarm alarm identifier
+ * @param[in] alarmspec pointer to a @p RTCAlarm structure
+ *
+ * @notapi
+ */
+void rtc_lld_set_alarm(RTCDriver *rtcp,
+ rtcalarm_t alarm,
+ const RTCAlarm *alarmspec) {
+
+ (void)rtcp;
+ (void)alarm;
+
+ rtc_lld_wait_write();
+
+ /* Enters configuration mode and writes ALRHx registers then leaves the
+ configuration mode.*/
+ RTC->CRL |= RTC_CRL_CNF;
+ if (alarmspec != NULL) {
+ RTC->ALRH = (uint16_t)(alarmspec->tv_sec >> 16);
+ RTC->ALRL = (uint16_t)(alarmspec->tv_sec & 0xFFFF);
+ }
+ else {
+ RTC->ALRH = 0;
+ RTC->ALRL = 0;
+ }
+ RTC->CRL &= ~RTC_CRL_CNF;
+}
+
+/**
+ * @brief Get current alarm.
+ * @note If an alarm has not been set then the returned alarm specification
+ * is not meaningful.
+ *
+ * @note Default value after BKP domain reset is 0xFFFFFFFF.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] alarm alarm identifier
+ * @param[out] alarmspec pointer to a @p RTCAlarm structure
+ *
+ * @notapi
+ */
+void rtc_lld_get_alarm(RTCDriver *rtcp,
+ rtcalarm_t alarm,
+ RTCAlarm *alarmspec) {
+
+ (void)rtcp;
+ (void)alarm;
+
+ alarmspec->tv_sec = ((RTC->ALRH << 16) + RTC->ALRL);
+}
+
+/**
+ * @brief Enables or disables RTC callbacks.
+ * @details This function enables or disables callbacks, use a @p NULL pointer
+ * in order to disable a callback.
+ *
+ * @param[in] rtcp pointer to RTC driver structure
+ * @param[in] callback callback function pointer or @p NULL
+ *
+ * @notapi
+ */
+void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback) {
+
+ if (callback != NULL) {
+ rtcp->rtc_cb = callback;
+ NVICEnableVector(RTC_IRQn, CORTEX_PRIORITY_MASK(STM32_RTC_IRQ_PRIORITY));
+
+ /* Interrupts are enabled only after setting up the callback, this
+ way there is no need to check for the NULL callback pointer inside
+ the IRQ handler.*/
+ RTC->CRL &= ~(RTC_CRL_OWF | RTC_CRL_ALRF | RTC_CRL_SECF);
+ RTC->CRH |= RTC_CRH_OWIE | RTC_CRH_ALRIE | RTC_CRH_SECIE;
+ }
+ else {
+ NVICDisableVector(RTC_IRQn);
+ RTC->CRL = 0;
+ RTC->CRH = 0;
+ }
+}
+
+#endif /* HAL_USE_RTC */
+
+/** @} */
diff --git a/os/hal/platforms/STM32/rtc_lld.h b/os/hal/platforms/STM32/RTCv1/rtc_lld.h
index 3b4f69665..e3ce0e365 100644
--- a/os/hal/platforms/STM32/rtc_lld.h
+++ b/os/hal/platforms/STM32/RTCv1/rtc_lld.h
@@ -19,7 +19,7 @@
*/
/**
- * @file STM32/rtc_lld.h
+ * @file STM32/RTCv1/rtc_lld.h
* @brief STM32 RTC subsystem low level driver header.
*
* @addtogroup RTC
@@ -35,25 +35,19 @@
/* Driver constants. */
/*===========================================================================*/
-/*===========================================================================*/
-/* Driver pre-compile time settings. */
-/*===========================================================================*/
/**
- * @brief Switch to TRUE if you need callbacks from RTC. Switch to FALSE
- * if you need only time keeping.
- * @note Default is true.
+ * @brief This RTC implementation supports callbacks.
*/
-#if !defined(RTC_SUPPORTS_CALLBACKS) || defined(__DOXYGEN__)
-#define RTC_SUPPORTS_CALLBACKS TRUE
-#endif
+#define RTC_SUPPORTS_CALLBACKS TRUE
/**
- * @brief Clock source selecting. LSE by default.
+ * @brief One alarm comparator available.
*/
-#if !defined(RTC_CLOCK_SOURCE) || defined(__DOXYGEN__)
-#define RTC_CLOCK_SOURCE RCC_BDCR_RTCSEL_LSE
-#endif
+#define RTC_ALARMS 1
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
@@ -63,38 +57,71 @@
#error "RTC not present in the selected device"
#endif
+#if !(STM32_RTC == STM32_RTC_LSE) && !(STM32_RTC == STM32_RTC_LSI) && \
+ !(STM32_RTC == STM32_RTC_HSE)
+#error "invalid source selected for RTC clock"
+#endif
+
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
+
+/**
+ * @brief Type of a structure representing an RTC alarm stamp.
+ */
+typedef struct RTCAlarm RTCAlarm;
+
+/**
+ * @brief Type of an RTC alarm.
+ */
+typedef uint32_t rtcalarm_t;
+
/**
- * @brief Structure representing an RTC driver config.
+ * @brief Type of an RTC event.
*/
-typedef struct {
+typedef enum {
+ RTC_EVENT_SECOND = 0, /** Triggered every second. */
+ RTC_EVENT_ALARM = 1, /** Triggered on alarm. */
+ RTC_EVENT_OVERFLOW = 2 /** Triggered on counter overflow. */
+} rtcevent_t;
+
+/**
+ * @brief Type of a generic RTC callback.
+ */
+typedef void (*rtccb_t)(RTCDriver *rtcp, rtcevent_t event);
+
+/**
+ * @brief Structure representing an RTC time stamp.
+ */
+struct RTCTime {
/**
- * @brief Overflow callback. Set it to NULL if not used.
+ * @brief Seconds since UNIX epoch.
*/
- rtccb_t overflow_cb;
-
+ uint32_t tv_sec;
/**
- * @brief Every second callback. Set it to NULL if not used.
+ * @brief Fractional part.
*/
- rtccb_t second_cb;
+ uint32_t tv_msec;
+};
+/**
+ * @brief Structure representing an RTC alarm specification.
+ */
+struct RTCAlarm {
/**
- * @brief Alarm callback. Set it to NULL if not used.
+ * @brief Seconds since UNIX epoch.
*/
- rtccb_t alarm_cb;
-}RTCConfig;
-
+ uint32_t tv_sec;
+};
/**
- * @brief Structure representing an RTC driver.
+ * @brief Structure representing an RTC driver.
*/
struct RTCDriver{
/**
- * @brief Pointer to RCT config.
+ * @brief Callback pointer.
*/
- const RTCConfig *config;
+ rtccb_t rtc_cb;
};
/*===========================================================================*/
@@ -105,26 +132,29 @@ struct RTCDriver{
/* External declarations. */
/*===========================================================================*/
-extern RTCDriver RTCD;
-
+#if !defined(__DOXYGEN__)
+extern RTCDriver RTCD1;
+#endif
#ifdef __cplusplus
extern "C" {
#endif
void rtc_lld_init(void);
- void rtc_lld_start(RTCDriver *rtcp, const RTCConfig *rtccfgp);
- void rtc_lld_stop(void);
- void rtc_lld_set_time(uint32_t tv_sec);
- uint32_t rtc_lld_get_sec(void);
- uint16_t rtc_lld_get_msec(void);
- uint32_t rtc_lld_get_alarm(void);
- void rtc_lld_set_alarm(uint32_t);
+ void rtc_lld_set_time(RTCDriver *rtcp, const RTCTime *timespec);
+ void rtc_lld_get_time(RTCDriver *rtcp, RTCTime *timespec);
+ void rtc_lld_set_alarm(RTCDriver *rtcp,
+ rtcalarm_t alarm,
+ const RTCAlarm *alarmspec);
+ void rtc_lld_get_alarm(RTCDriver *rtcp,
+ rtcalarm_t alarm,
+ RTCAlarm *alarmspec);
+ void rtc_lld_set_callback(RTCDriver *rtcp, rtccb_t callback);
#ifdef __cplusplus
}
#endif
-
#endif /* HAL_USE_RTC */
+
#endif /* _RTC_LLD_H_ */
/** @} */
diff --git a/os/hal/platforms/STM32/USBv1/stm32_usb.h b/os/hal/platforms/STM32/USBv1/stm32_usb.h
index 51e7510c4..435224033 100644
--- a/os/hal/platforms/STM32/USBv1/stm32_usb.h
+++ b/os/hal/platforms/STM32/USBv1/stm32_usb.h
@@ -21,10 +21,10 @@
/**
* @file stm32_usb.h
* @brief STM32 USB registers layout header.
- * @note This file requires definitions from the ST STM32 header file
- * stm3232f10x.h.
+ * @note This file requires definitions from the ST STM32 header files
+ * stm32f10x.h or stm32l1xx.h.
*
- * @addtogroup STM32_USB
+ * @addtogroup USB
* @{
*/
@@ -78,22 +78,38 @@ typedef struct {
/**
* @brief TX buffer offset register.
*/
- volatile uint32_t TXADDR;
+ volatile uint32_t TXADDR0;
/**
- * @brief TX counter register.
+ * @brief TX counter register 0.
*/
- volatile uint32_t TXCOUNT;
+ volatile uint16_t TXCOUNT0;
+ /**
+ * @brief TX counter register 1.
+ */
+ volatile uint16_t TXCOUNT1;
/**
* @brief RX buffer offset register.
*/
- volatile uint32_t RXADDR;
+ volatile uint32_t RXADDR0;
/**
- * @brief RX counter register.
+ * @brief RX counter register 0.
*/
- volatile uint32_t RXCOUNT;
+ volatile uint16_t RXCOUNT0;
+ /**
+ * @brief RX counter register 1.
+ */
+ volatile uint16_t RXCOUNT1;
} stm32_usb_descriptor_t;
/**
+ * @name Register aliases
+ * @{
+ */
+#define RXADDR1 TXADDR0
+#define TXADDR1 RXADDR0
+/** @} */
+
+/**
* @brief USB registers block numeric address.
*/
#define STM32_USB_BASE (APB1PERIPH_BASE + 0x5C00)
@@ -132,8 +148,11 @@ typedef struct {
#define EPR_STAT_TX_NAK 0x0020
#define EPR_STAT_TX_VALID 0x0030
#define EPR_DTOG_TX 0x0040
+#define EPR_SWBUF_RX EPR_DTOG_TX
#define EPR_CTR_TX 0x0080
#define EPR_EP_KIND 0x0100
+#define EPR_EP_DBL_BUF EPR_EP_KIND
+#define EPR_EP_STATUS_OUT EPR_EP_KIND
#define EPR_EP_TYPE_MASK 0x0600
#define EPR_EP_TYPE_BULK 0x0000
#define EPR_EP_TYPE_CONTROL 0x0200
@@ -146,6 +165,7 @@ typedef struct {
#define EPR_STAT_RX_NAK 0x2000
#define EPR_STAT_RX_VALID 0x3000
#define EPR_DTOG_RX 0x4000
+#define EPR_SWBUF_TX EPR_DTOG_RX
#define EPR_CTR_RX 0x8000
#define CNTR_FRES 0x0001
diff --git a/os/hal/platforms/STM32/USBv1/usb_lld.c b/os/hal/platforms/STM32/USBv1/usb_lld.c
index 34b8d9bf0..e61fcadae 100644
--- a/os/hal/platforms/STM32/USBv1/usb_lld.c
+++ b/os/hal/platforms/STM32/USBv1/usb_lld.c
@@ -19,7 +19,7 @@
*/
/**
- * @file STM32/usb_lld.c
+ * @file STM32/USBv1/usb_lld.c
* @brief STM32 USB subsystem low level driver source.
*
* @addtogroup USB
@@ -109,58 +109,6 @@ static uint32_t pm_alloc(USBDriver *usbp, size_t size) {
return next;
}
-/**
- * @brief Copies a packet from memory into a packet buffer.
- *
- * @param[in] ep endpoint number
- * @param[in] buf buffer where to fetch the endpoint data
- * @param[in] n maximum number of bytes to copy
- */
-static void write_packet(usbep_t ep, const uint8_t *buf, size_t n){
- uint32_t *pmap;
- stm32_usb_descriptor_t *udp;
- size_t count;
-
- udp = USB_GET_DESCRIPTOR(ep);
- pmap = USB_ADDR2PTR(udp->TXADDR);
- udp->TXCOUNT = n;
- count = (n + 1) / 2;
- while (count) {
- *pmap++ = *(uint16_t *)buf;
- buf += 2;
- count--;
- }
- EPR_SET_STAT_TX(ep, EPR_STAT_TX_VALID);
-}
-
-/**
- * @brief Copies a packet from a packet buffer into memory.
- *
- * @param[in] ep endpoint number
- * @param[in] buf buffer where to copy the endpoint data
- * @param[in] n maximum number of bytes to copy
- * @return The packet size.
- * @retval 0 Special case, zero sized packet.
- */
-static size_t read_packet(usbep_t ep, uint8_t *buf, size_t n){
- uint32_t *pmap;
- stm32_usb_descriptor_t *udp;
- size_t count;
-
- udp = USB_GET_DESCRIPTOR(ep);
- pmap = USB_ADDR2PTR(udp->RXADDR);
- count = udp->RXCOUNT & RXCOUNT_COUNT_MASK;
- if (n > count)
- n = count;
- count = (n + 1) / 2;
- while (count) {
- *(uint16_t *)buf = (uint16_t)*pmap++;
- buf += 2;
- count--;
- }
- return n;
-}
-
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
@@ -247,7 +195,7 @@ CH_IRQ_HANDLER(Vector90) {
}
else {
/* Transaction mode.*/
- n = USB_GET_DESCRIPTOR(ep)->TXCOUNT;
+ n = (size_t)USB_GET_DESCRIPTOR(ep)->TXCOUNT0;
epcp->in_state->txbuf += n;
epcp->in_state->txcnt += n;
epcp->in_state->txsize -= n;
@@ -257,7 +205,8 @@ CH_IRQ_HANDLER(Vector90) {
n = epcp->in_maxsize;
else
n = epcp->in_state->txsize;
- write_packet(ep, epcp->in_state->txbuf, n);
+ usb_lld_write_packet_buffer(usbp, ep, epcp->in_state->txbuf, n);
+ usb_lld_start_in(usbp, ep);
}
else {
/* Transfer completed, invokes the callback.*/
@@ -279,7 +228,10 @@ CH_IRQ_HANDLER(Vector90) {
}
else {
/* Transaction mode.*/
- n = read_packet(ep, epcp->out_state->rxbuf, epcp->out_state->rxsize);
+ n = usb_lld_read_packet_buffer(usbp, ep,
+ epcp->out_state->rxbuf,
+ epcp->out_state->rxsize);
+ usb_lld_start_out(usbp, ep);
epcp->out_state->rxbuf += n;
epcp->out_state->rxcnt += n;
epcp->out_state->rxsize -= n;
@@ -330,7 +282,7 @@ void usb_lld_start(USBDriver *usbp) {
#if STM32_USB_USE_USB1
if (&USBD1 == usbp) {
/* USB clock enabled.*/
- RCC->APB1ENR |= RCC_APB1ENR_USBEN;
+ rccEnableUSB(FALSE);
/* Powers up the transceiver while holding the USB in reset state.*/
STM32_USB->CNTR = CNTR_FRES;
/* Enabling the USB IRQ vectors, this also gives enough time to allow
@@ -360,12 +312,12 @@ void usb_lld_stop(USBDriver *usbp) {
/* If in ready state then disables the USB clock.*/
if (usbp->state == USB_STOP) {
-#if STM32_ADC_USE_ADC1
+#if STM32_USB_USE_USB1
if (&USBD1 == usbp) {
NVICDisableVector(19);
NVICDisableVector(20);
STM32_USB->CNTR = CNTR_PDWN | CNTR_FRES;
- RCC->APB1ENR &= ~RCC_APB1ENR_USBEN;
+ rccDisableUSB(FALSE);
}
#endif
}
@@ -467,10 +419,10 @@ void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) {
else
nblocks = ((((epcp->out_maxsize - 1) | 1) + 1) / 2) << 10;
dp = USB_GET_DESCRIPTOR(ep);
- dp->TXCOUNT = 0;
- dp->RXCOUNT = nblocks;
- dp->TXADDR = pm_alloc(usbp, epcp->in_maxsize);
- dp->RXADDR = pm_alloc(usbp, epcp->out_maxsize);
+ dp->TXCOUNT0 = 0;
+ dp->RXCOUNT0 = nblocks;
+ dp->TXADDR0 = pm_alloc(usbp, epcp->in_maxsize);
+ dp->RXADDR0 = pm_alloc(usbp, epcp->out_maxsize);
}
/**
@@ -564,19 +516,18 @@ void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf) {
(void)usbp;
udp = USB_GET_DESCRIPTOR(ep);
- pmap = USB_ADDR2PTR(udp->RXADDR);
+ pmap = USB_ADDR2PTR(udp->RXADDR0);
for (n = 0; n < 4; n++) {
*(uint16_t *)buf = (uint16_t)*pmap++;
buf += 2;
}
- EPR_SET_STAT_RX(ep, EPR_STAT_RX_VALID);
}
/**
- * @brief Reads a packet from the dedicated packet buffer.
+ * @brief Reads from a dedicated packet buffer.
* @pre In order to use this function he endpoint must have been
* initialized in packet mode.
- * @post The endpoint is ready to accept another packet.
+ * @note This function can be invoked both in thread and IRQ context.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
@@ -589,16 +540,16 @@ void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf) {
*
* @notapi
*/
-size_t usb_lld_read_packet(USBDriver *usbp, usbep_t ep,
- uint8_t *buf, size_t n) {
+size_t usb_lld_read_packet_buffer(USBDriver *usbp, usbep_t ep,
+ uint8_t *buf, size_t n) {
uint32_t *pmap;
stm32_usb_descriptor_t *udp;
size_t count;
(void)usbp;
udp = USB_GET_DESCRIPTOR(ep);
- pmap = USB_ADDR2PTR(udp->RXADDR);
- count = udp->RXCOUNT & RXCOUNT_COUNT_MASK;
+ pmap = USB_ADDR2PTR(udp->RXADDR0);
+ count = (size_t)udp->RXCOUNT0 & RXCOUNT_COUNT_MASK;
if (n > count)
n = count;
n = (n + 1) / 2;
@@ -607,15 +558,14 @@ size_t usb_lld_read_packet(USBDriver *usbp, usbep_t ep,
buf += 2;
n--;
}
- EPR_SET_STAT_RX(ep, EPR_STAT_RX_VALID);
return count;
}
/**
- * @brief Writes a packet to the dedicated packet buffer.
+ * @brief Writes to a dedicated packet buffer.
* @pre In order to use this function he endpoint must have been
* initialized in packet mode.
- * @post The endpoint is ready to transmit the packet.
+ * @note This function can be invoked both in thread and IRQ context.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
@@ -625,36 +575,35 @@ size_t usb_lld_read_packet(USBDriver *usbp, usbep_t ep,
*
* @notapi
*/
-void usb_lld_write_packet(USBDriver *usbp, usbep_t ep,
- const uint8_t *buf, size_t n) {
+void usb_lld_write_packet_buffer(USBDriver *usbp, usbep_t ep,
+ const uint8_t *buf, size_t n) {
uint32_t *pmap;
stm32_usb_descriptor_t *udp;
(void)usbp;
udp = USB_GET_DESCRIPTOR(ep);
- pmap = USB_ADDR2PTR(udp->TXADDR);
- udp->TXCOUNT = n;
+ pmap = USB_ADDR2PTR(udp->TXADDR0);
+ udp->TXCOUNT0 = (uint16_t)n;
n = (n + 1) / 2;
while (n > 0) {
*pmap++ = *(uint16_t *)buf;
buf += 2;
n--;
}
- EPR_SET_STAT_TX(ep, EPR_STAT_TX_VALID);
}
/**
- * @brief Starts a receive operation on an OUT endpoint.
+ * @brief Prepares for a receive operation.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
- * @param[out] buf buffer where to copy the endpoint data
- * @param[in] n maximum number of bytes to copy in the buffer
+ * @param[out] buf buffer where to copy the received data
+ * @param[in] n maximum number of bytes to copy
*
* @notapi
*/
-void usb_lld_start_out(USBDriver *usbp, usbep_t ep,
- uint8_t *buf, size_t n) {
+void usb_lld_prepare_receive(USBDriver *usbp, usbep_t ep,
+ uint8_t *buf, size_t n) {
USBOutEndpointState *osp = usbp->epc[ep]->out_state;
osp->rxbuf = buf;
@@ -665,21 +614,20 @@ void usb_lld_start_out(USBDriver *usbp, usbep_t ep,
else
osp->rxpkts = (uint16_t)((n + usbp->epc[ep]->out_maxsize - 1) /
usbp->epc[ep]->out_maxsize);
- EPR_SET_STAT_RX(ep, EPR_STAT_RX_VALID);
}
/**
- * @brief Starts a transmit operation on an IN endpoint.
+ * @brief Prepares for a transmit operation.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
- * @param[in] buf buffer where to fetch the endpoint data
+ * @param[in] buf buffer where to fetch the data to be transmitted
* @param[in] n maximum number of bytes to copy
*
* @notapi
*/
-void usb_lld_start_in(USBDriver *usbp, usbep_t ep,
- const uint8_t *buf, size_t n) {
+void usb_lld_prepare_transmit(USBDriver *usbp, usbep_t ep,
+ const uint8_t *buf, size_t n) {
USBInEndpointState *isp = usbp->epc[ep]->in_state;
isp->txbuf = buf;
@@ -687,7 +635,37 @@ void usb_lld_start_in(USBDriver *usbp, usbep_t ep,
isp->txcnt = 0;
if (n > (size_t)usbp->epc[ep]->in_maxsize)
n = (size_t)usbp->epc[ep]->in_maxsize;
- write_packet(ep, buf, n);
+ usb_lld_write_packet_buffer(usbp, ep, buf, n);
+}
+
+/**
+ * @brief Starts a receive operation on an OUT endpoint.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ *
+ * @notapi
+ */
+void usb_lld_start_out(USBDriver *usbp, usbep_t ep) {
+
+ (void)usbp;
+
+ EPR_SET_STAT_RX(ep, EPR_STAT_RX_VALID);
+}
+
+/**
+ * @brief Starts a transmit operation on an IN endpoint.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ *
+ * @notapi
+ */
+void usb_lld_start_in(USBDriver *usbp, usbep_t ep) {
+
+ (void)usbp;
+
+ EPR_SET_STAT_TX(ep, EPR_STAT_TX_VALID);
}
/**
@@ -701,6 +679,7 @@ void usb_lld_start_in(USBDriver *usbp, usbep_t ep,
void usb_lld_stall_out(USBDriver *usbp, usbep_t ep) {
(void)usbp;
+
EPR_SET_STAT_RX(ep, EPR_STAT_RX_STALL);
}
@@ -715,6 +694,7 @@ void usb_lld_stall_out(USBDriver *usbp, usbep_t ep) {
void usb_lld_stall_in(USBDriver *usbp, usbep_t ep) {
(void)usbp;
+
EPR_SET_STAT_TX(ep, EPR_STAT_TX_STALL);
}
diff --git a/os/hal/platforms/STM32/USBv1/usb_lld.h b/os/hal/platforms/STM32/USBv1/usb_lld.h
index 9b5e9dad2..0ee9fd6c2 100644
--- a/os/hal/platforms/STM32/USBv1/usb_lld.h
+++ b/os/hal/platforms/STM32/USBv1/usb_lld.h
@@ -19,7 +19,7 @@
*/
/**
- * @file STM32/usb_lld.h
+ * @file STM32/USBv1/usb_lld.h
* @brief STM32 USB subsystem low level driver header.
*
* @addtogroup USB
@@ -375,16 +375,18 @@ extern "C" {
usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep);
usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep);
void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf);
- size_t usb_lld_read_packet(USBDriver *usbp, usbep_t ep,
- uint8_t *buf, size_t n);
- void usb_lld_write_packet(USBDriver *usbp, usbep_t ep,
- const uint8_t *buf, size_t n);
- void usb_lld_start_out(USBDriver *usbp, usbep_t ep,
- uint8_t *buf, size_t n);
- void usb_lld_start_in(USBDriver *usbp, usbep_t ep,
- const uint8_t *buf, size_t n);
- void usb_lld_stall_in(USBDriver *usbp, usbep_t ep);
+ size_t usb_lld_read_packet_buffer(USBDriver *usbp, usbep_t ep,
+ uint8_t *buf, size_t n);
+ void usb_lld_write_packet_buffer(USBDriver *usbp, usbep_t ep,
+ const uint8_t *buf, size_t n);
+ void usb_lld_prepare_receive(USBDriver *usbp, usbep_t ep,
+ uint8_t *buf, size_t n);
+ void usb_lld_prepare_transmit(USBDriver *usbp, usbep_t ep,
+ const uint8_t *buf, size_t n);
+ void usb_lld_start_out(USBDriver *usbp, usbep_t ep);
+ void usb_lld_start_in(USBDriver *usbp, usbep_t ep);
void usb_lld_stall_out(USBDriver *usbp, usbep_t ep);
+ void usb_lld_stall_in(USBDriver *usbp, usbep_t ep);
void usb_lld_clear_out(USBDriver *usbp, usbep_t ep);
void usb_lld_clear_in(USBDriver *usbp, usbep_t ep);
#ifdef __cplusplus
diff --git a/os/hal/platforms/STM32/can_lld.c b/os/hal/platforms/STM32/can_lld.c
index e180a87cb..64ccb3af3 100644
--- a/os/hal/platforms/STM32/can_lld.c
+++ b/os/hal/platforms/STM32/can_lld.c
@@ -192,7 +192,7 @@ void can_lld_start(CANDriver *canp) {
CORTEX_PRIORITY_MASK(STM32_CAN_CAN1_IRQ_PRIORITY));
NVICEnableVector(CAN1_SCE_IRQn,
CORTEX_PRIORITY_MASK(STM32_CAN_CAN1_IRQ_PRIORITY));
- RCC->APB1ENR |= RCC_APB1ENR_CAN1EN;
+ rccEnableCAN1(FALSE);
}
#endif
@@ -276,7 +276,7 @@ void can_lld_stop(CANDriver *canp) {
NVICDisableVector(USB_LP_CAN1_RX0_IRQn);
NVICDisableVector(CAN1_RX1_IRQn);
NVICDisableVector(CAN1_SCE_IRQn);
- RCC->APB1ENR &= ~RCC_APB1ENR_CAN1EN;
+ rccDisableCAN1(FALSE);
}
#endif
}
diff --git a/os/hal/platforms/STM32/can_lld.h b/os/hal/platforms/STM32/can_lld.h
index a9a086e5b..d99897935 100644
--- a/os/hal/platforms/STM32/can_lld.h
+++ b/os/hal/platforms/STM32/can_lld.h
@@ -75,6 +75,10 @@
/*===========================================================================*/
/**
+ * @name Configuration options
+ * @{
+ */
+/**
* @brief CAN1 driver enable switch.
* @details If set to @p TRUE the support for ADC1 is included.
* @note The default is @p TRUE.
@@ -89,6 +93,7 @@
#if !defined(STM32_CAN_CAN1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_CAN_CAN1_IRQ_PRIORITY 11
#endif
+/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
diff --git a/os/hal/platforms/STM32/ext_lld.c b/os/hal/platforms/STM32/ext_lld.c
new file mode 100644
index 000000000..c9b4b75c2
--- /dev/null
+++ b/os/hal/platforms/STM32/ext_lld.c
@@ -0,0 +1,609 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file STM32/ext_lld.c
+ * @brief STM32 EXT subsystem low level driver source.
+ *
+ * @addtogroup EXT
+ * @{
+ */
+
+#include "ch.h"
+#include "hal.h"
+
+#if HAL_USE_EXT || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief EXTD1 driver identifier.
+ */
+EXTDriver EXTD1;
+
+/*===========================================================================*/
+/* Driver local variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/**
+ * @brief EXTI[0] interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(EXTI0_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ EXTI->PR = (1 << 0);
+ EXTD1.config->channels[0].cb(&EXTD1, 0);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EXTI[1] interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(EXTI1_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ EXTI->PR = (1 << 1);
+ EXTD1.config->channels[1].cb(&EXTD1, 1);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EXTI[2] interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(EXTI2_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ EXTI->PR = (1 << 2);
+ EXTD1.config->channels[2].cb(&EXTD1, 2);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EXTI[3] interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(EXTI3_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ EXTI->PR = (1 << 3);
+ EXTD1.config->channels[3].cb(&EXTD1, 3);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EXTI[4] interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(EXTI4_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ EXTI->PR = (1 << 4);
+ EXTD1.config->channels[4].cb(&EXTD1, 4);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EXTI[5]...EXTI[9] interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(EXTI9_5_IRQHandler) {
+ uint32_t pr;
+
+ CH_IRQ_PROLOGUE();
+
+ pr = EXTI->PR & ((1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9));
+ EXTI->PR = pr;
+ if (pr & (1 << 5))
+ EXTD1.config->channels[5].cb(&EXTD1, 5);
+ if (pr & (1 << 6))
+ EXTD1.config->channels[6].cb(&EXTD1, 6);
+ if (pr & (1 << 7))
+ EXTD1.config->channels[7].cb(&EXTD1, 7);
+ if (pr & (1 << 8))
+ EXTD1.config->channels[8].cb(&EXTD1, 8);
+ if (pr & (1 << 9))
+ EXTD1.config->channels[9].cb(&EXTD1, 9);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EXTI[10]...EXTI[15] interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(EXTI15_10_IRQHandler) {
+ uint32_t pr;
+
+ CH_IRQ_PROLOGUE();
+
+ pr = EXTI->PR & ((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);
+ if (pr & (1 << 11))
+ EXTD1.config->channels[11].cb(&EXTD1, 11);
+ if (pr & (1 << 12))
+ EXTD1.config->channels[12].cb(&EXTD1, 12);
+ if (pr & (1 << 13))
+ EXTD1.config->channels[13].cb(&EXTD1, 13);
+ if (pr & (1 << 14))
+ EXTD1.config->channels[14].cb(&EXTD1, 14);
+ if (pr & (1 << 15))
+ EXTD1.config->channels[15].cb(&EXTD1, 15);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EXTI[16] interrupt handler (PVD).
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(PVD_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ EXTI->PR = (1 << 16);
+ EXTD1.config->channels[16].cb(&EXTD1, 16);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EXTI[17] interrupt handler (RTC).
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(RTCAlarm_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ EXTI->PR = (1 << 17);
+ EXTD1.config->channels[17].cb(&EXTD1, 17);
+
+ CH_IRQ_EPILOGUE();
+}
+
+#if defined(STM32L1XX_MD)
+/**
+ * @brief EXTI[18] interrupt handler (USB_FS_WKUP).
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(USB_FS_WKUP_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ EXTI->PR = (1 << 18);
+ EXTD1.config->channels[18].cb(&EXTD1, 18);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EXTI[19] interrupt handler (TAMPER_STAMP).
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(TAMPER_STAMP_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ EXTI->PR = (1 << 19);
+ EXTD1.config->channels[19].cb(&EXTD1, 19);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EXTI[20] interrupt handler (RTC_WKUP).
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(RTC_WKUP_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ EXTI->PR = (1 << 20);
+ EXTD1.config->channels[20].cb(&EXTD1, 20);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EXTI[21]...EXTI[22] interrupt handler (COMP).
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(COMP_IRQHandler) {
+ uint32_t pr;
+
+ CH_IRQ_PROLOGUE();
+
+ pr = EXTI->PR & ((1 << 21) | (1 << 22));
+ EXTI->PR = pr;
+ if (pr & (1 << 21))
+ EXTD1.config->channels[21].cb(&EXTD1, 21);
+ if (pr & (1 << 22))
+ EXTD1.config->channels[22].cb(&EXTD1, 22);
+
+ CH_IRQ_EPILOGUE();
+}
+
+#elif defined(STM32F2XX) || defined(STM32F4XX)
+/**
+ * @brief EXTI[18] interrupt handler (OTG_FS_WKUP).
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(OTG_FS_WKUP_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ EXTI->PR = (1 << 18);
+ EXTD1.config->channels[18].cb(&EXTD1, 18);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EXTI[19] interrupt handler (ETH_WKUP).
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(ETH_WKUP_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ EXTI->PR = (1 << 19);
+ EXTD1.config->channels[19].cb(&EXTD1, 19);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EXTI[20] interrupt handler (OTG_HS_WKUP).
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(OTG_HS_WKUP_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ EXTI->PR = (1 << 20);
+ EXTD1.config->channels[20].cb(&EXTD1, 20);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EXTI[21] interrupt handler (TAMPER_STAMP).
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(TAMPER_STAMP_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ EXTI->PR = (1 << 21);
+ EXTD1.config->channels[21].cb(&EXTD1, 21);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EXTI[22] interrupt handler (RTC_WKUP).
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(RTC_WKUP_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ EXTI->PR = (1 << 22);
+ EXTD1.config->channels[22].cb(&EXTD1, 22);
+
+ CH_IRQ_EPILOGUE();
+}
+
+#elif defined(STM32F10X_CL)
+/**
+ * @brief EXTI[18] interrupt handler (OTG_FS_WKUP).
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(OTG_FS_WKUP_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ EXTI->PR = (1 << 18);
+ EXTD1.config->channels[18].cb(&EXTD1, 18);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EXTI[19] interrupt handler (ETH_WKUP).
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(ETH_WKUP_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ EXTI->PR = (1 << 19);
+ EXTD1.config->channels[19].cb(&EXTD1, 19);
+
+ CH_IRQ_EPILOGUE();
+}
+
+#else
+/**
+ * @brief EXTI[18] interrupt handler (USB_FS_WKUP).
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(USB_FS_WKUP_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ EXTI->PR = (1 << 18);
+ EXTD1.config->channels[18].cb(&EXTD1, 18);
+
+ CH_IRQ_EPILOGUE();
+}
+#endif
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level EXT driver initialization.
+ *
+ * @notapi
+ */
+void ext_lld_init(void) {
+
+ /* Driver initialization.*/
+ extObjectInit(&EXTD1);
+}
+
+/**
+ * @brief Configures and activates the EXT peripheral.
+ *
+ * @param[in] extp pointer to the @p EXTDriver object
+ *
+ * @notapi
+ */
+void ext_lld_start(EXTDriver *extp) {
+ unsigned i;
+ uint32_t imr, emr, rtsr, ftsr;
+
+ if (extp->state == EXT_STOP) {
+ /* Clock activation.*/
+ NVICEnableVector(EXTI0_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EXT_EXTI0_IRQ_PRIORITY));
+ NVICEnableVector(EXTI1_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EXT_EXTI1_IRQ_PRIORITY));
+ NVICEnableVector(EXTI2_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EXT_EXTI2_IRQ_PRIORITY));
+ NVICEnableVector(EXTI3_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EXT_EXTI3_IRQ_PRIORITY));
+ NVICEnableVector(EXTI4_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EXT_EXTI4_IRQ_PRIORITY));
+ NVICEnableVector(EXTI9_5_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EXT_EXTI5_9_IRQ_PRIORITY));
+ NVICEnableVector(EXTI15_10_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EXT_EXTI10_15_IRQ_PRIORITY));
+ NVICEnableVector(PVD_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EXT_EXTI16_IRQ_PRIORITY));
+ NVICEnableVector(RTC_Alarm_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EXT_EXTI17_IRQ_PRIORITY));
+#if defined(STM32L1XX_MD)
+ /* EXTI vectors specific to STM32L1xx.*/
+ NVICEnableVector(USB_FS_WKUP_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EXT_EXTI18_IRQ_PRIORITY));
+ NVICEnableVector(TAMPER_STAMP_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EXT_EXTI19_IRQ_PRIORITY));
+ NVICEnableVector(RTC_WKUP_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EXT_EXTI20_IRQ_PRIORITY));
+ NVICEnableVector(COMP_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EXT_EXTI21_IRQ_PRIORITY));
+#elif defined(STM32F2XX) || defined(STM32F4XX)
+ /* EXTI vectors specific to STM32F2xx/STM32F4xx.*/
+ NVICEnableVector(OTG_FS_WKUP_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EXT_EXTI18_IRQ_PRIORITY));
+ NVICEnableVector(ETH_WKUP_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EXT_EXTI19_IRQ_PRIORITY));
+ NVICEnableVector(OTG_HS_WKUP_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EXT_EXTI20_IRQ_PRIORITY));
+ NVICEnableVector(TAMP_STAMP_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EXT_EXTI21_IRQ_PRIORITY));
+ NVICEnableVector(RTC_WKUP_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EXT_EXTI22_IRQ_PRIORITY));
+#elif defined(STM32F10X_CL)
+ /* EXTI vectors specific to STM32F1xx Connectivity Line.*/
+ NVICEnableVector(OTG_FS_WKUP_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EXT_EXTI18_IRQ_PRIORITY));
+ NVICEnableVector(ETH_WKUP_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EXT_EXTI19_IRQ_PRIORITY));
+#else
+ /* EXTI vectors specific to STM32F1xx except Connectivity Line.*/
+ NVICEnableVector(USB_FS_WKUP_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EXT_EXTI18_IRQ_PRIORITY));
+#endif
+ }
+ /* Configuration.*/
+ imr = emr = rtsr = ftsr = 0;
+ for (i = 0; i < EXT_MAX_CHANNELS; i++) {
+ if (extp->config->channels[i].mode & EXT_CH_MODE_AUTOSTART) {
+ if (extp->config->channels[i].cb != NULL)
+ imr |= (1 << i);
+ else
+ emr |= (1 << i);
+ if (extp->config->channels[i].mode & EXT_CH_MODE_RISING_EDGE)
+ rtsr |= (1 << i);
+ if (extp->config->channels[i].mode & EXT_CH_MODE_FALLING_EDGE)
+ ftsr |= (1 << i);
+ }
+ }
+#if defined(STM32L1XX_MD) || defined(STM32F2XX) || defined(STM32F4XX)
+ SYSCFG->EXTICR[0] = extp->config->exti[0];
+ SYSCFG->EXTICR[1] = extp->config->exti[1];
+ SYSCFG->EXTICR[2] = extp->config->exti[2];
+ SYSCFG->EXTICR[3] = extp->config->exti[3];
+#else /* STM32F1XX */
+ AFIO->EXTICR[0] = extp->config->exti[0];
+ AFIO->EXTICR[1] = extp->config->exti[1];
+ AFIO->EXTICR[2] = extp->config->exti[2];
+ AFIO->EXTICR[3] = extp->config->exti[3];
+#endif /* STM32F1XX */
+ EXTI->SWIER = 0;
+ EXTI->RTSR = rtsr;
+ EXTI->FTSR = ftsr;
+ EXTI->PR = EXT_CHANNELS_MASK;
+ EXTI->EMR = emr;
+ EXTI->IMR = imr;
+}
+
+/**
+ * @brief Deactivates the EXT peripheral.
+ *
+ * @param[in] extp pointer to the @p EXTDriver object
+ *
+ * @notapi
+ */
+void ext_lld_stop(EXTDriver *extp) {
+
+ if (extp->state == EXT_ACTIVE) {
+ NVICDisableVector(EXTI0_IRQn);
+ NVICDisableVector(EXTI1_IRQn);
+ NVICDisableVector(EXTI2_IRQn);
+ NVICDisableVector(EXTI3_IRQn);
+ NVICDisableVector(EXTI4_IRQn);
+ NVICDisableVector(EXTI9_5_IRQn);
+ NVICDisableVector(EXTI15_10_IRQn);
+ NVICDisableVector(PVD_IRQn);
+ NVICDisableVector(RTC_Alarm_IRQn);
+#if defined(STM32L1XX_MD)
+ /* EXTI vectors specific to STM32L1xx.*/
+ NVICDisableVector(USB_FS_WKUP_IRQn);
+ NVICDisableVector(TAMPER_STAMP_IRQn);
+ NVICDisableVector(RTC_WKUP_IRQn);
+ NVICDisableVector(COMP_IRQn);
+#elif defined(STM32F2XX) || defined(STM32F4XX)
+ /* EXTI vectors specific to STM32F2xx/STM32F4xx.*/
+ NVICDisableVector(OTG_FS_WKUP_IRQn);
+ NVICDisableVector(ETH_WKUP_IRQn);
+ NVICDisableVector(OTG_HS_WKUP_IRQn);
+ NVICDisableVector(TAMP_STAMP_IRQn);
+ NVICDisableVector(RTC_WKUP_IRQn);
+#elif defined(STM32F10X_CL)
+ /* EXTI vectors specific to STM32F1xx Connectivity Line.*/
+ NVICDisableVector(OTG_FS_WKUP_IRQn);
+ NVICDisableVector(ETH_WKUP_IRQn);
+#else
+ /* EXTI vectors specific to STM32F1xx except Connectivity Line.*/
+ NVICDisableVector(USB_FS_WKUP_IRQn);
+#endif
+ }
+ EXTI->EMR = 0;
+ EXTI->IMR = 0;
+ EXTI->PR = EXT_CHANNELS_MASK;
+}
+
+/**
+ * @brief Enables an EXT channel.
+ *
+ * @param[in] extp pointer to the @p EXTDriver object
+ * @param[in] channel channel to be enabled
+ *
+ * @notapi
+ */
+void ext_lld_channel_enable(EXTDriver *extp, expchannel_t channel) {
+
+ if (extp->config->channels[channel].cb != NULL)
+ EXTI->IMR |= (1 << channel);
+ else
+ EXTI->EMR |= (1 << channel);
+ if (extp->config->channels[channel].mode & EXT_CH_MODE_RISING_EDGE)
+ EXTI->RTSR |= (1 << channel);
+ if (extp->config->channels[channel].mode & EXT_CH_MODE_FALLING_EDGE)
+ EXTI->FTSR |= (1 << channel);
+}
+
+/**
+ * @brief Disables an EXT channel.
+ *
+ * @param[in] extp pointer to the @p EXTDriver object
+ * @param[in] channel channel to be disabled
+ *
+ * @notapi
+ */
+void ext_lld_channel_disable(EXTDriver *extp, expchannel_t channel) {
+
+ (void)extp;
+
+ EXTI->IMR &= ~(1 << channel);
+ EXTI->EMR &= ~(1 << channel);
+ EXTI->RTSR &= ~(1 << channel);
+ EXTI->FTSR &= ~(1 << channel);
+ EXTI->PR = (1 << channel);
+}
+
+#endif /* HAL_USE_EXT */
+
+/** @} */
diff --git a/os/hal/platforms/STM32/ext_lld.h b/os/hal/platforms/STM32/ext_lld.h
new file mode 100644
index 000000000..1a6102057
--- /dev/null
+++ b/os/hal/platforms/STM32/ext_lld.h
@@ -0,0 +1,280 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file STM32/ext_lld.h
+ * @brief STM32 EXT subsystem low level driver header.
+ *
+ * @addtogroup EXT
+ * @{
+ */
+
+#ifndef _EXT_LLD_H_
+#define _EXT_LLD_H_
+
+#if HAL_USE_EXT || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @brief Available number of EXT channels.
+ */
+#define EXT_MAX_CHANNELS STM32_EXTI_NUM_CHANNELS
+
+/**
+ * @brief Mask of the available channels.
+ */
+#define EXT_CHANNELS_MASK (EXT_MAX_CHANNELS - 1)
+
+/**
+ * @name EXTI configuration helpers
+ * @{
+ */
+/**
+ * @brief EXTI-GPIO association macro.
+ * @details Helper macro to associate a GPIO to each of the Mx EXTI inputs.
+ */
+#define EXT_MODE_EXTI(m0, m1, m2, m3, m4, m5, m6, m7, \
+ m8, m9, m10, m11, m12, m13, m14, m15) \
+ { \
+ ((m0) << 0) | ((m1) << 4) | ((m2) << 8) | ((m3) << 12), \
+ ((m4) << 0) | ((m5) << 4) | ((m6) << 8) | ((m7) << 12), \
+ ((m8) << 0) | ((m9) << 4) | ((m10) << 8) | ((m11) << 12), \
+ ((m12) << 0) | ((m13) << 4) | ((m14) << 8) | ((m15) << 12) \
+ }
+
+#define EXT_MODE_GPIOA 0 /**< @brief GPIOA identifier. */
+#define EXT_MODE_GPIOB 1 /**< @brief GPIOB identifier. */
+#define EXT_MODE_GPIOC 2 /**< @brief GPIOC identifier. */
+#define EXT_MODE_GPIOD 3 /**< @brief GPIOD identifier. */
+#define EXT_MODE_GPIOE 4 /**< @brief GPIOE identifier. */
+#define EXT_MODE_GPIOF 5 /**< @brief GPIOF identifier. */
+#define EXT_MODE_GPIOG 6 /**< @brief GPIOG identifier. */
+#define EXT_MODE_GPIOH 7 /**< @brief GPIOH identifier. */
+#define EXT_MODE_GPIOI 8 /**< @brief GPIOI identifier. */
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief EXTI0 interrupt priority level setting.
+ */
+#if !defined(STM32_EXT_EXTI0_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_EXT_EXTI0_IRQ_PRIORITY 6
+#endif
+
+/**
+ * @brief EXTI1 interrupt priority level setting.
+ */
+#if !defined(STM32_EXT_EXTI1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_EXT_EXTI1_IRQ_PRIORITY 6
+#endif
+
+/**
+ * @brief EXTI2 interrupt priority level setting.
+ */
+#if !defined(STM32_EXT_EXTI2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_EXT_EXTI2_IRQ_PRIORITY 6
+#endif
+
+/**
+ * @brief EXTI3 interrupt priority level setting.
+ */
+#if !defined(STM32_EXT_EXTI3_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_EXT_EXTI3_IRQ_PRIORITY 6
+#endif
+
+/**
+ * @brief EXTI4 interrupt priority level setting.
+ */
+#if !defined(STM32_EXT_EXTI4_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_EXT_EXTI4_IRQ_PRIORITY 6
+#endif
+
+/**
+ * @brief EXTI9..5 interrupt priority level setting.
+ */
+#if !defined(STM32_EXT_EXTI5_9_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_EXT_EXTI5_9_IRQ_PRIORITY 6
+#endif
+
+/**
+ * @brief EXTI15..10 interrupt priority level setting.
+ */
+#if !defined(STM32_EXT_EXTI10_15_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_EXT_EXTI10_15_IRQ_PRIORITY 6
+#endif
+
+/**
+ * @brief EXTI16 interrupt priority level setting.
+ */
+#if !defined(STM32_EXT_EXTI16_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_EXT_EXTI16_IRQ_PRIORITY 6
+#endif
+
+/**
+ * @brief EXTI17 interrupt priority level setting.
+ */
+#if !defined(STM32_EXT_EXTI17_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_EXT_EXTI17_IRQ_PRIORITY 6
+#endif
+
+/**
+ * @brief EXTI18 interrupt priority level setting.
+ */
+#if !defined(STM32_EXT_EXTI18_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_EXT_EXTI18_IRQ_PRIORITY 6
+#endif
+
+/**
+ * @brief EXTI19 interrupt priority level setting.
+ */
+#if !defined(STM32_EXT_EXTI19_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_EXT_EXTI19_IRQ_PRIORITY 6
+#endif
+
+/**
+ * @brief EXTI20 interrupt priority level setting.
+ */
+#if !defined(STM32_EXT_EXTI20_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_EXT_EXTI20_IRQ_PRIORITY 6
+#endif
+
+/**
+ * @brief EXTI21 interrupt priority level setting.
+ */
+#if !defined(STM32_EXT_EXTI21_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_EXT_EXTI21_IRQ_PRIORITY 6
+#endif
+
+/**
+ * @brief EXTI22 interrupt priority level setting.
+ */
+#if !defined(STM32_EXT_EXTI22_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_EXT_EXTI22_IRQ_PRIORITY 6
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief EXT channel identifier.
+ */
+typedef uint32_t expchannel_t;
+
+/**
+ * @brief Type of an EXT generic notification callback.
+ *
+ * @param[in] extp pointer to the @p EXPDriver object triggering the
+ * callback
+ */
+typedef void (*extcallback_t)(EXTDriver *extp, expchannel_t channel);
+
+/**
+ * @brief Channel configuration structure.
+ */
+typedef struct {
+ /**
+ * @brief Channel mode.
+ */
+ uint32_t mode;
+ /**
+ * @brief Channel callback.
+ * @details In the STM32 implementation a @p NULL callback pointer is
+ * valid and configures the channel as an event sources instead
+ * of an interrupt source.
+ */
+ extcallback_t cb;
+} EXTChannelConfig;
+
+/**
+ * @brief Driver configuration structure.
+ * @note It could be empty on some architectures.
+ */
+typedef struct {
+ /**
+ * @brief Channel configurations.
+ */
+ EXTChannelConfig channels[EXT_MAX_CHANNELS];
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Initialization values for EXTICRx registers.
+ */
+ uint16_t exti[4];
+} EXTConfig;
+
+/**
+ * @brief Structure representing an EXT driver.
+ */
+struct EXTDriver {
+ /**
+ * @brief Driver state.
+ */
+ extstate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const EXTConfig *config;
+ /* End of the mandatory fields.*/
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if !defined(__DOXYGEN__)
+extern EXTDriver EXTD1;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void ext_lld_init(void);
+ void ext_lld_start(EXTDriver *extp);
+ void ext_lld_stop(EXTDriver *extp);
+ void ext_lld_channel_enable(EXTDriver *extp, expchannel_t channel);
+ void ext_lld_channel_disable(EXTDriver *extp, expchannel_t channel);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_EXT */
+
+#endif /* _EXT_LLD_H_ */
+
+/** @} */
diff --git a/os/hal/platforms/STM32/gpt_lld.c b/os/hal/platforms/STM32/gpt_lld.c
index f7a9226ad..34468ccc3 100644
--- a/os/hal/platforms/STM32/gpt_lld.c
+++ b/os/hal/platforms/STM32/gpt_lld.c
@@ -192,7 +192,7 @@ CH_IRQ_HANDLER(TIM5_IRQHandler) {
#if STM32_GPT_USE_TIM8
/**
- * @brief TIM5 interrupt handler.
+ * @brief TIM8 interrupt handler.
*
* @isr
*/
@@ -219,37 +219,37 @@ void gpt_lld_init(void) {
#if STM32_GPT_USE_TIM1
/* Driver initialization.*/
- GPTD1.tim = TIM1;
+ GPTD1.tim = STM32_TIM1;
gptObjectInit(&GPTD1);
#endif
#if STM32_GPT_USE_TIM2
/* Driver initialization.*/
- GPTD2.tim = TIM2;
+ GPTD2.tim = STM32_TIM2;
gptObjectInit(&GPTD2);
#endif
#if STM32_GPT_USE_TIM3
/* Driver initialization.*/
- GPTD3.tim = TIM3;
+ GPTD3.tim = STM32_TIM3;
gptObjectInit(&GPTD3);
#endif
#if STM32_GPT_USE_TIM4
/* Driver initialization.*/
- GPTD4.tim = TIM4;
+ GPTD4.tim = STM32_TIM4;
gptObjectInit(&GPTD4);
#endif
#if STM32_GPT_USE_TIM5
/* Driver initialization.*/
- GPTD5.tim = TIM5;
+ GPTD5.tim = STM32_TIM5;
gptObjectInit(&GPTD5);
#endif
#if STM32_GPT_USE_TIM8
/* Driver initialization.*/
- GPTD5.tim = TIM8;
+ GPTD8.tim = STM32_TIM8;
gptObjectInit(&GPTD8);
#endif
}
@@ -268,9 +268,8 @@ void gpt_lld_start(GPTDriver *gptp) {
/* Clock activation.*/
#if STM32_GPT_USE_TIM1
if (&GPTD1 == gptp) {
- RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
- RCC->APB2RSTR = RCC_APB2RSTR_TIM1RST;
- RCC->APB2RSTR = 0;
+ rccEnableTIM1(FALSE);
+ rccResetTIM1();
NVICEnableVector(TIM1_UP_IRQn,
CORTEX_PRIORITY_MASK(STM32_GPT_TIM1_IRQ_PRIORITY));
gptp->clock = STM32_TIMCLK2;
@@ -278,9 +277,8 @@ void gpt_lld_start(GPTDriver *gptp) {
#endif
#if STM32_GPT_USE_TIM2
if (&GPTD2 == gptp) {
- RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
- RCC->APB1RSTR = RCC_APB1RSTR_TIM2RST;
- RCC->APB1RSTR = 0;
+ rccEnableTIM2(FALSE);
+ rccResetTIM2();
NVICEnableVector(TIM2_IRQn,
CORTEX_PRIORITY_MASK(STM32_GPT_TIM2_IRQ_PRIORITY));
gptp->clock = STM32_TIMCLK1;
@@ -288,9 +286,8 @@ void gpt_lld_start(GPTDriver *gptp) {
#endif
#if STM32_GPT_USE_TIM3
if (&GPTD3 == gptp) {
- RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
- RCC->APB1RSTR = RCC_APB1RSTR_TIM3RST;
- RCC->APB1RSTR = 0;
+ rccEnableTIM3(FALSE);
+ rccResetTIM3();
NVICEnableVector(TIM3_IRQn,
CORTEX_PRIORITY_MASK(STM32_GPT_TIM3_IRQ_PRIORITY));
gptp->clock = STM32_TIMCLK1;
@@ -298,9 +295,8 @@ void gpt_lld_start(GPTDriver *gptp) {
#endif
#if STM32_GPT_USE_TIM4
if (&GPTD4 == gptp) {
- RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
- RCC->APB1RSTR = RCC_APB1RSTR_TIM4RST;
- RCC->APB1RSTR = 0;
+ rccEnableTIM4(FALSE);
+ rccResetTIM4();
NVICEnableVector(TIM4_IRQn,
CORTEX_PRIORITY_MASK(STM32_GPT_TIM4_IRQ_PRIORITY));
gptp->clock = STM32_TIMCLK1;
@@ -309,9 +305,8 @@ void gpt_lld_start(GPTDriver *gptp) {
#if STM32_GPT_USE_TIM5
if (&GPTD5 == gptp) {
- RCC->APB1ENR |= RCC_APB1ENR_TIM5EN;
- RCC->APB1RSTR = RCC_APB1RSTR_TIM5RST;
- RCC->APB1RSTR = 0;
+ rccEnableTIM5(FALSE);
+ rccResetTIM5();
NVICEnableVector(TIM5_IRQn,
CORTEX_PRIORITY_MASK(STM32_GPT_TIM5_IRQ_PRIORITY));
gptp->clock = STM32_TIMCLK1;
@@ -320,9 +315,8 @@ void gpt_lld_start(GPTDriver *gptp) {
#if STM32_GPT_USE_TIM8
if (&GPTD8 == gptp) {
- RCC->APB2ENR |= RCC_APB2ENR_TIM8EN;
- RCC->APB2RSTR = RCC_APB2RSTR_TIM8RST;
- RCC->APB2RSTR = 0;
+ rccEnableTIM8(FALSE);
+ rccResetTIM8();
NVICEnableVector(TIM8_UP_IRQn,
CORTEX_PRIORITY_MASK(STM32_GPT_TIM8_IRQ_PRIORITY));
gptp->clock = STM32_TIMCLK2;
@@ -359,37 +353,37 @@ void gpt_lld_stop(GPTDriver *gptp) {
#if STM32_GPT_USE_TIM1
if (&GPTD1 == gptp) {
NVICDisableVector(TIM1_UP_IRQn);
- RCC->APB2ENR &= ~RCC_APB2ENR_TIM1EN;
+ rccDisableTIM1(FALSE);
}
#endif
#if STM32_GPT_USE_TIM2
if (&GPTD2 == gptp) {
NVICDisableVector(TIM2_IRQn);
- RCC->APB1ENR &= ~RCC_APB1ENR_TIM2EN;
+ rccDisableTIM2(FALSE);
}
#endif
#if STM32_GPT_USE_TIM3
if (&GPTD3 == gptp) {
NVICDisableVector(TIM3_IRQn);
- RCC->APB1ENR &= ~RCC_APB1ENR_TIM3EN;
+ rccDisableTIM3(FALSE);
}
#endif
#if STM32_GPT_USE_TIM4
if (&GPTD4 == gptp) {
NVICDisableVector(TIM4_IRQn);
- RCC->APB1ENR &= ~RCC_APB1ENR_TIM4EN;
+ rccDisableTIM4(FALSE);
}
#endif
#if STM32_GPT_USE_TIM5
if (&GPTD5 == gptp) {
NVICDisableVector(TIM5_IRQn);
- RCC->APB1ENR &= ~RCC_APB1ENR_TIM5EN;
+ rccDisableTIM5(FALSE);
}
#endif
#if STM32_GPT_USE_TIM8
if (&GPTD8 == gptp) {
NVICDisableVector(TIM8_UP_IRQn);
- RCC->APB2ENR &= ~RCC_APB2ENR_TIM8EN;
+ rccDisableTIM8(FALSE);
}
#endif
}
@@ -407,6 +401,10 @@ void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t interval) {
gptp->tim->ARR = interval - 1; /* Time constant. */
gptp->tim->EGR = TIM_EGR_UG; /* Update event. */
+ gptp->tim->CNT = 0; /* Reset counter. */
+ /* NOTE: After generating the UG event it takes several clock cycles before
+ SR bit 0 goes to 1. This is because the clearing of CNT has been inserted
+ before the clearing of SR, to give it some time.*/
gptp->tim->SR = 0; /* Clear pending IRQs (if any). */
gptp->tim->DIER = TIM_DIER_UIE; /* Update Event IRQ enabled. */
gptp->tim->CR1 = TIM_CR1_URS | TIM_CR1_CEN;
diff --git a/os/hal/platforms/STM32/gpt_lld.h b/os/hal/platforms/STM32/gpt_lld.h
index ef00c23a9..13c5e1f4b 100644
--- a/os/hal/platforms/STM32/gpt_lld.h
+++ b/os/hal/platforms/STM32/gpt_lld.h
@@ -40,6 +40,10 @@
/*===========================================================================*/
/**
+ * @name Configuration options
+ * @{
+ */
+/**
* @brief GPTD1 driver enable switch.
* @details If set to @p TRUE the support for GPTD1 is included.
* @note The default is @p TRUE.
@@ -134,6 +138,7 @@
#if !defined(STM32_GPT_TIM8_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_GPT_TIM8_IRQ_PRIORITY 7
#endif
+/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
@@ -225,7 +230,7 @@ struct GPTDriver {
/**
* @brief Pointer to the TIMx registers block.
*/
- TIM_TypeDef *tim;
+ stm32_tim_t *tim;
};
/*===========================================================================*/
diff --git a/os/hal/platforms/STM32/i2c_lld.c b/os/hal/platforms/STM32/i2c_lld.c
index d10cb4031..84decd64f 100644
--- a/os/hal/platforms/STM32/i2c_lld.c
+++ b/os/hal/platforms/STM32/i2c_lld.c
@@ -1,3 +1,23 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
/**
* @file STM32/i2c_lld.c
* @brief STM32 I2C subsystem low level driver source. Slave mode not implemented.
@@ -15,20 +35,65 @@
/* Datasheet notes. */
/*===========================================================================*/
/**
- * From RM0008.pdf
+ * From reference manuals from ST:
*
* Note:
* When the STOP, START or PEC bit is set, the software must NOT perform
* any write access to I2C_CR1 before this bit is cleared by hardware.
- * Otherwise there is a risk of setting a second STOP, START or PEC request.
+ * Otherwise there is a risk of setting a second STOP, START or PEC request.
*/
/*===========================================================================*/
+/* Knowledge base. */
+/*===========================================================================*/
+/*
+Not all system functions are usable in a given context.
+
+The most restrictive type are the i-class, an I-class function is a function that must:
+- Not access the "current" thread in any way (from an ISR the current thread
+is random so it is meaningless).
+- Not reschedule internally (from an ISR the reschedule is done at the end of
+the ISR chain, rescheduling from within an ISR is forbidden because would
+leave the IRQ stack not empty with all kind of funny consequences.
+- Not try to change state for the current thread.
+- Must be invoked between a lock() and an unlock() but never lock/unlock internally.
+
+A bit less restrictive are the S-class that must simply:
+- Be invoked between a lock() and an unlock() but never lock/unlock internally.
+S-class can reschedule internally, access the current thread implicitly and
+also change state so are not eligible for ISR context.
+
+Normal functions can be invoked from thread context only but have no internal
+restrictions.
+*/
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+#define I2C1_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_RX_DMA_STREAM, \
+ STM32_I2C1_RX_DMA_CHN)
+#define I2C1_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_TX_DMA_STREAM, \
+ STM32_I2C1_TX_DMA_CHN)
+
+#define I2C2_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2C_I2C2_RX_DMA_STREAM, \
+ STM32_I2C2_RX_DMA_CHN)
+#define I2C2_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2C_I2C2_TX_DMA_STREAM, \
+ STM32_I2C2_TX_DMA_CHN)
+
+#define I2C3_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_RX_DMA_STREAM, \
+ STM32_I2C3_RX_DMA_CHN)
+#define I2C3_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_TX_DMA_STREAM, \
+ STM32_I2C3_TX_DMA_CHN)
+
+/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
-#define I2C_STOP_GPT_TIMEOUT 50 /* waiting timer value */
-#define I2C_START_GPT_TIMEOUT 50 /* waiting timer value */
-#define I2C_POLLING_TIMEOUT 0xFFFF
/*===========================================================================*/
/* Driver exported variables. */
@@ -44,10 +109,14 @@ I2CDriver I2CD1;
I2CDriver I2CD2;
#endif
+/** @brief I2C2 driver identifier.*/
+#if STM32_I2C_USE_I2C3 || defined(__DOXYGEN__)
+I2CDriver I2CD3;
+#endif
+
/*===========================================================================*/
/* Driver local variables. */
/*===========================================================================*/
-
/* Debugging variables */
#if CH_DBG_ENABLE_ASSERTS
static volatile uint16_t dbgSR1 = 0;
@@ -56,108 +125,13 @@ static volatile uint16_t dbgCR1 = 0;
static volatile uint16_t dbgCR2 = 0;
#endif /* CH_DBG_ENABLE_ASSERTS */
-/* defines for convenience purpose */
-#if I2C_SUPPORTS_CALLBACKS
-#define txBuffp (i2cp->txbuff_p)
-#define rxBuffp (i2cp->rxbuff_p)
-#endif /* I2C_SUPPORTS_CALLBACKS */
-
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
-#if I2C_SUPPORTS_CALLBACKS
-#if !(STM32_I2C_I2C1_USE_POLLING_WAIT)
-/* I2C1 GPT callback. */
-static void i2c1gptcb(GPTDriver *gptp) {
- (void)gptp;
- I2CDriver *i2cp = &I2CD1;
-
- chSysLockFromIsr();
- i2cp->flags &= ~I2C_FLG_TIMER_ARMED;
-
- switch(i2cp->id_state){
- case I2C_ACTIVE_TRANSMIT:
- i2c_lld_master_transmit(i2cp, i2cp->slave_addr, i2cp->txbuf, i2cp->txbytes, i2cp->rxbuf, i2cp->rxbytes);
- break;
-
- case I2C_ACTIVE_RECEIVE:
- i2c_lld_master_receive(i2cp, i2cp->slave_addr, i2cp->rxbuf, i2cp->rxbytes);
- break;
-
- case I2C_ACTIVE_TRANSCEIVE:
- i2c_lld_master_transceive(i2cp);
- break;
-
- default:
- break;
- }
- chSysUnlockFromIsr();
-}
-/* I2C1 GPT configuration. */
-static const GPTConfig i2c1gptcfg = {
- 1000000, /* 1MHz timer clock.*/
- i2c1gptcb /* Timer callback.*/
-};
-#endif /* STM32_I2C_I2C1_USE_POLLING_WAIT */
-
-#if !(STM32_I2C_I2C2_USE_POLLING_WAIT)
-/* I2C2 GPT callback. */
-static void i2c2gptcb(GPTDriver *gptp) {
- (void)gptp;
- I2CDriver *i2cp = &I2CD2;
-
- chSysLockFromIsr();
- i2cp->flags &= ~I2C_FLG_TIMER_ARMED;
-
- switch(i2cp->id_state){
- case I2C_ACTIVE_TRANSMIT:
- i2c_lld_master_transmit(i2cp, i2cp->slave_addr, i2cp->txbuf, i2cp->txbytes, i2cp->rxbuf, i2cp->rxbytes);
- break;
-
- case I2C_ACTIVE_RECEIVE:
- i2c_lld_master_receive(i2cp, i2cp->slave_addr, i2cp->rxbuf, i2cp->rxbytes);
- break;
-
- case I2C_ACTIVE_TRANSCEIVE:
- i2c_lld_master_transceive(i2cp);
- break;
-
- default:
- break;
- }
- chSysUnlockFromIsr();
-}
-/* I2C2 GPT configuration. */
-static const GPTConfig i2c2gptcfg = {
- 1000000, /* 1MHz timer clock.*/
- i2c2gptcb /* Timer callback.*/
-};
-#endif /* STM32_I2C_I2C2_USE_POLLING_WAIT */
-#endif /* I2C_SUPPORTS_CALLBACKS */
-
-/**
- * @brief Function for I2C debugging purpose.
- * @note Internal use only.
- *
- * @param[in] i2cp pointer to the @p I2CDriver object
- *
- * @notapi
- */
-#if CH_DBG_ENABLE_ASSERTS
-void _i2c_unhandled_case(I2CDriver *i2cp){
- dbgCR1 = i2cp->id_i2c->CR1;
- dbgCR2 = i2cp->id_i2c->CR2;
- chDbgAssert((dbgSR1 + dbgSR2) == 0,
- "i2c_serve_event_interrupt(), #1",
- "unhandled case");
-}
-#else
-#define _i2c_unhandled_case(i2cp)
-#endif /* CH_DBG_ENABLE_ASSERTS */
-#if I2C_SUPPORTS_CALLBACKS
/**
* @brief Return the last event value from I2C status registers.
+ * @details Important but implicit function is clearing interrupts flags.
* @note Internal use only.
*
* @param[in] i2cp pointer to the @p I2CDriver object
@@ -175,253 +149,126 @@ static uint32_t i2c_get_event(I2CDriver *i2cp){
return (I2C_EV_MASK & (regSR1 | (regSR2 << 16)));
}
+
/**
- * @brief Handle the flags/interrupts.
- * @note Internal use only.
+ * @brief I2C interrupts handler.
*
* @param[in] i2cp pointer to the @p I2CDriver object
- *
- * @notapi
*/
-void _i2c_ev6_master_rec_mode_selected(I2CDriver *i2cp){
+static void i2c_serve_event_interrupt(I2CDriver *i2cp) {
I2C_TypeDef *dp = i2cp->id_i2c;
- switch(i2cp->flags & EV6_SUBEV_MASK) {
-
- case I2C_EV6_3_MASTER_REC_1BTR_MODE_SELECTED: /* only an single byte to receive */
- dp->CR1 &= (uint16_t)~I2C_CR1_ACK; /* Clear ACK */
- dp->CR1 |= I2C_CR1_STOP; /* Program the STOP */
- break;
-
- case I2C_EV6_1_MASTER_REC_2BTR_MODE_SELECTED: /* only two bytes to receive */
- dp->CR1 &= (uint16_t)~I2C_CR1_ACK; /* Clear ACK */
- dp->CR2 &= (uint16_t)~I2C_CR2_ITBUFEN; /* Disable the ITBUF in order to have only the BTF interrupt */
- break;
-
- default: /* more than 2 bytes to receive */
+ switch(i2c_get_event(i2cp)){
+ case I2C_EV5_MASTER_MODE_SELECT:
+ dp->DR = i2cp->slave_addr;
break;
- }
-}
-
-/**
- * @brief Handle cases of 2 or 3 bytes receiving.
- * @note Internal use only.
- *
- * @param[in] i2cp pointer to the @p I2CDriver object
- *
- * @notapi
- */
-void _i2c_ev7_master_rec_byte_qued(I2CDriver *i2cp){
- I2C_TypeDef *dp = i2cp->id_i2c;
- switch(i2cp->flags & EV7_SUBEV_MASK) {
-
- case I2C_EV7_2_MASTER_REC_3BYTES_TO_PROCESS:
- /* Only for case of three bytes to be received.
- * DataN-2 and DataN-1 already received. */
- dp->CR1 &= (uint16_t)~I2C_CR1_ACK; /* Clear ACK */
- *rxBuffp = dp->DR; /* Read the DataN-2. This clear the RXE & BFT flags and launch the DataN exception in the shift register (ending the SCL stretch) */
- rxBuffp++;
- chSysLockFromIsr();
- dp->CR1 |= I2C_CR1_STOP; /* Program the STOP */
- *rxBuffp = dp->DR; /* Read the DataN-1 */
- chSysUnlockFromIsr();
- rxBuffp++;
- i2cp->rxbytes -= 2; /* Decrement the number of readed bytes */
- i2cp->flags = 0;
- dp->CR2 |= I2C_CR2_ITBUFEN; /* ready for read DataN. Enable interrupt for next (and last) RxNE event*/
+ case I2C_EV6_MASTER_REC_MODE_SELECTED:
+ dmaStreamEnable(i2cp->dmarx);
+ i2cp->id_i2c->CR2 |= I2C_CR2_DMAEN | I2C_CR2_LAST;
break;
- case I2C_EV7_3_MASTER_REC_2BYTES_TO_PROCESS:
- /* only for case of two bytes to be received
- * DataN-1 and DataN are received */
- dp->CR2 &= (uint16_t)~I2C_CR2_ITEVTEN;
- dp->CR2 &= (uint16_t)~I2C_CR2_ITBUFEN;
- chSysLockFromIsr();
- dp->CR1 |= I2C_CR1_STOP; /* Program the STOP */
- *rxBuffp = dp->DR; /* Read the DataN-1*/
- rxBuffp++;
- *rxBuffp = dp->DR; /* Read the DataN*/
- chSysUnlockFromIsr();
- i2cp->rxbytes = 0;
- i2cp->flags = 0;
- _i2c_isr_code(i2cp, i2cp->id_slave_config); /* Portable I2C ISR code defined in the high level driver. */
+ case I2C_EV6_MASTER_TRA_MODE_SELECTED:
+ dmaStreamEnable(i2cp->dmatx);
+ i2cp->id_i2c->CR2 |= I2C_CR2_DMAEN | I2C_CR2_LAST;
break;
- case I2C_FLG_MASTER_RECEIVER:
- /* Some times in hi load scenarions it is possible to "miss" interrupt
- * because STM32 I2C has OR'ed interrupt sources. This case handle that
- * scenario. */
- if (i2cp->rxbytes > 3){
- *rxBuffp = dp->DR;
- rxBuffp++;
- (i2cp->rxbytes)--;
+ case I2C_EV8_2_MASTER_BYTE_TRANSMITTED:
+ /* catch BTF event after the end of transmission */
+ if (i2cp->rxbytes > 1){
+ /* start "read after write" operation */
+ i2c_lld_master_receive(i2cp, (i2cp->slave_addr >> 1),
+ i2cp->rxbuf, i2cp->rxbytes);
+ return;
}
else
- _i2c_unhandled_case(i2cp);
+ i2cp->id_i2c->CR1 |= I2C_CR1_STOP;
+ _i2c_isr_code(i2cp, i2cp->id_slave_config);
break;
default:
- _i2c_unhandled_case(i2cp);
break;
}
}
+
/**
- * @brief Main I2C interrupt handler.
- * @note Internal use only.
+ * @brief DMA rx end IRQ handler.
*
* @param[in] i2cp pointer to the @p I2CDriver object
- *
- * @notapi
*/
-static void i2c_serve_event_interrupt(I2CDriver *i2cp) {
- I2C_TypeDef *dp = i2cp->id_i2c;
+static void i2c_lld_serve_rx_end_irq(I2CDriver *i2cp){
+ dmaStreamDisable(i2cp->dmarx);
- switch(i2c_get_event(i2cp)) {
-
- case I2C_EV5_MASTER_MODE_SELECT:
- i2cp->flags &= ~I2C_FLG_HEADER_SENT;
- dp->DR = i2cp->slave_addr1;
- break;
-
- case I2C_EV9_MASTER_ADDR_10BIT:
- if(i2cp->flags & I2C_FLG_MASTER_RECEIVER) {
- i2cp->slave_addr1 |= 0x01;
- i2cp->flags |= I2C_FLG_HEADER_SENT;
- }
- dp->DR = i2cp->slave_addr2;
- break;
-
- /**************************************************************************
- * Master Transmitter part
- */
- case I2C_EV6_MASTER_TRA_MODE_SELECTED:
- if(i2cp->flags & I2C_FLG_HEADER_SENT){
- dp->CR1 |= I2C_CR1_START; /* re-send the start in 10-Bit address mode */
- break;
- }
- txBuffp = (uint8_t*)i2cp->txbuf; /* Initialize the transmit buffer pointer */
- i2cp->txbytes--;
- if(i2cp->txbytes == 0) { /* If no further data to be sent, disable the I2C ITBUF in order to not have a TxE interrupt */
- dp->CR2 &= (uint16_t)~I2C_CR2_ITBUFEN;
- }
- dp->DR = *txBuffp; /* EV8_1 write the first data */
- txBuffp++;
- break;
-
- case I2C_EV8_MASTER_BYTE_TRANSMITTING:
- if(i2cp->txbytes > 0) {
- i2cp->txbytes--;
- if(i2cp->txbytes == 0) { /* If no further data to be sent, disable the ITBUF in order to not have a TxE interrupt */
- dp->CR2 &= (uint16_t)~I2C_CR2_ITBUFEN;
- }
- dp->DR = *txBuffp;
- txBuffp++;
- }
- break;
-
- case I2C_EV8_2_MASTER_BYTE_TRANSMITTED:
- dp->CR2 &= (uint16_t)~I2C_CR2_ITEVTEN; /* Disable ITEVT In order to not have again a BTF IT */
- if (i2cp->rxbytes == 0){ /* if nothing to read then generate stop */
- dp->CR1 |= I2C_CR1_STOP;
- _i2c_isr_code(i2cp, i2cp->id_slave_config); /* Portable I2C ISR code defined in the high level driver. */
- }
- else{ /* start reading operation */
- i2cp->id_i2c->CR1 |= I2C_CR1_START; /* send start bit */
- i2c_lld_master_transceive(i2cp);
- }
- break;
-
- /**************************************************************************
- * Master Receiver part
- */
- case I2C_EV6_MASTER_REC_MODE_SELECTED:
- _i2c_ev6_master_rec_mode_selected(i2cp);
- rxBuffp = i2cp->rxbuf; /* Initialize receive buffer pointer */
- break;
-
- case I2C_EV7_MASTER_REC_BYTE_RECEIVED:
- if(i2cp->rxbytes > 3) {
- *rxBuffp = dp->DR; /* Read the data register */
- rxBuffp++;
- i2cp->rxbytes--;
- if(i2cp->rxbytes == 3){ /* Disable the ITBUF in order to have only the BTF interrupt */
- dp->CR2 &= (uint16_t)~I2C_CR2_ITBUFEN;
- i2cp->flags |= I2C_FLG_3BTR;
- }
- }
- else if (i2cp->rxbytes == 3){ /* Disable the ITBUF in order to have only the BTF interrupt */
- dp->CR2 &= (uint16_t)~I2C_CR2_ITBUFEN;
- i2cp->flags |= I2C_FLG_3BTR;
- }
- break;
+ i2cp->id_i2c->CR1 |= I2C_CR1_STOP;
+ _i2c_isr_code(i2cp, i2cp->id_slave_config);
+}
- case I2C_EV7_MASTER_REC_BYTE_QUEUED:
- _i2c_ev7_master_rec_byte_qued(i2cp);
- break;
- default: /* only 1 byte must to be read to complete trasfer. Stop already sent to bus. */
- chDbgAssert((i2cp->rxbytes) == 1,
- "i2c_serve_event_interrupt(), #1",
- "more than 1 byte to be received");
- *rxBuffp = dp->DR; /* Read the data register */
- i2cp->rxbytes = 0;
- dp->CR2 &= (uint16_t)~I2C_CR2_ITEVTEN; /* disable interrupts */
- dp->CR2 &= (uint16_t)~I2C_CR2_ITBUFEN;
- _i2c_isr_code(i2cp, i2cp->id_slave_config); /* Portable I2C ISR code defined in the high level driver.*/
- break;
- }
+/**
+ * @brief DMA tx enr IRQ handler.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ */
+static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp){
+ dmaStreamDisable(i2cp->dmatx);
}
-#endif /* I2C_SUPPORTS_CALLBACKS */
+
+/**
+ * @brief I2C error handler.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ */
static void i2c_serve_error_interrupt(I2CDriver *i2cp) {
- i2cflags_t flags;
- I2C_TypeDef *reg;
+ i2cflags_t errors;
+
+ chSysLockFromIsr();
+ /* clear interrupt falgs just to be safe */
+ dmaStreamDisable(i2cp->dmatx);
+ dmaStreamDisable(i2cp->dmarx);
+ dmaStreamClearInterrupt(i2cp->dmatx);
+ dmaStreamClearInterrupt(i2cp->dmarx);
+ chSysUnlockFromIsr();
- reg = i2cp->id_i2c;
- flags = I2CD_NO_ERROR;
+ #define reg (i2cp->id_i2c)
+ errors = I2CD_NO_ERROR;
if(reg->SR1 & I2C_SR1_BERR) { /* Bus error */
reg->SR1 &= ~I2C_SR1_BERR;
- flags |= I2CD_BUS_ERROR;
+ errors |= I2CD_BUS_ERROR;
}
if(reg->SR1 & I2C_SR1_ARLO) { /* Arbitration lost */
reg->SR1 &= ~I2C_SR1_ARLO;
- flags |= I2CD_ARBITRATION_LOST;
+ errors |= I2CD_ARBITRATION_LOST;
}
if(reg->SR1 & I2C_SR1_AF) { /* Acknowledge fail */
reg->SR1 &= ~I2C_SR1_AF;
reg->CR1 |= I2C_CR1_STOP; /* setting stop bit */
- while(i2cp->id_i2c->CR1 & I2C_CR1_STOP)
- ;
- flags |= I2CD_ACK_FAILURE;
+ errors |= I2CD_ACK_FAILURE;
}
if(reg->SR1 & I2C_SR1_OVR) { /* Overrun */
reg->SR1 &= ~I2C_SR1_OVR;
- flags |= I2CD_OVERRUN;
+ errors |= I2CD_OVERRUN;
}
if(reg->SR1 & I2C_SR1_PECERR) { /* PEC error */
reg->SR1 &= ~I2C_SR1_PECERR;
- flags |= I2CD_PEC_ERROR;
+ errors |= I2CD_PEC_ERROR;
}
if(reg->SR1 & I2C_SR1_TIMEOUT) { /* SMBus Timeout */
reg->SR1 &= ~I2C_SR1_TIMEOUT;
- flags |= I2CD_TIMEOUT;
+ errors |= I2CD_TIMEOUT;
}
if(reg->SR1 & I2C_SR1_SMBALERT) { /* SMBus alert */
reg->SR1 &= ~I2C_SR1_SMBALERT;
- flags |= I2CD_SMB_ALERT;
+ errors |= I2CD_SMB_ALERT;
}
- if(flags != I2CD_NO_ERROR) { /* send communication end signal */
- chSysLockFromIsr();
- i2cAddFlagsI(i2cp, flags);
- chSysUnlockFromIsr();
- #if I2C_SUPPORTS_CALLBACKS
+ if(errors != I2CD_NO_ERROR) { /* send communication end signal */
+ i2cp->errors |= errors;
_i2c_isr_err_code(i2cp, i2cp->id_slave_config);
- #endif /* I2C_SUPPORTS_CALLBACKS */
}
+ #undef reg
}
@@ -429,19 +276,15 @@ static void i2c_serve_error_interrupt(I2CDriver *i2cp) {
/**
* @brief I2C1 event interrupt handler.
*/
-#if I2C_SUPPORTS_CALLBACKS
-CH_IRQ_HANDLER(VectorBC) {
-
+CH_IRQ_HANDLER(I2C1_EV_IRQHandler) {
CH_IRQ_PROLOGUE();
i2c_serve_event_interrupt(&I2CD1);
CH_IRQ_EPILOGUE();
}
-#endif /* I2C_SUPPORTS_CALLBACKS */
/**
* @brief I2C1 error interrupt handler.
*/
-CH_IRQ_HANDLER(VectorC0) {
-
+CH_IRQ_HANDLER(I2C1_ER_IRQHandler) {
CH_IRQ_PROLOGUE();
i2c_serve_error_interrupt(&I2CD1);
CH_IRQ_EPILOGUE();
@@ -452,59 +295,66 @@ CH_IRQ_HANDLER(VectorC0) {
/**
* @brief I2C2 event interrupt handler.
*/
-#if I2C_SUPPORTS_CALLBACKS
-CH_IRQ_HANDLER(VectorC4) {
-
+CH_IRQ_HANDLER(I2C2_EV_IRQHandler) {
CH_IRQ_PROLOGUE();
i2c_serve_event_interrupt(&I2CD2);
CH_IRQ_EPILOGUE();
}
-#endif /* I2C_SUPPORTS_CALLBACKS */
/**
* @brief I2C2 error interrupt handler.
*/
-CH_IRQ_HANDLER(VectorC8) {
-
+CH_IRQ_HANDLER(I2C2_ER_IRQHandler) {
CH_IRQ_PROLOGUE();
i2c_serve_error_interrupt(&I2CD2);
CH_IRQ_EPILOGUE();
}
#endif /* STM32_I2C_USE_I2C2 */
+#if STM32_I2C_USE_I2C3 || defined(__DOXYGEN__)
+/**
+ * @brief I2C3 event interrupt handler.
+ */
+CH_IRQ_HANDLER(I2C3_EV_IRQHandler) {
+ CH_IRQ_PROLOGUE();
+ i2c_serve_event_interrupt(&I2CD3);
+ CH_IRQ_EPILOGUE();
+}
+/**
+ * @brief I2C3 error interrupt handler.
+ */
+CH_IRQ_HANDLER(I2C3_ER_IRQHandler) {
+ CH_IRQ_PROLOGUE();
+ i2c_serve_error_interrupt(&I2CD3);
+ CH_IRQ_EPILOGUE();
+}
+#endif /* STM32_I2C_USE_I2C3 */
+
+
/**
* @brief Low level I2C driver initialization.
*/
void i2c_lld_init(void) {
#if STM32_I2C_USE_I2C1
- RCC->APB1RSTR = RCC_APB1RSTR_I2C1RST; /* reset I2C 1 */
- RCC->APB1RSTR = 0;
i2cObjectInit(&I2CD1);
- I2CD1.id_i2c = I2C1;
-
-#if I2C_SUPPORTS_CALLBACKS
-#if !(STM32_I2C_I2C1_USE_POLLING_WAIT)
- I2CD1.timer = &(STM32_I2C_I2C1_USE_GPT_TIM);
- I2CD1.timer_cfg = &i2c1gptcfg;
-#endif /* !(STM32_I2C_I2C1_USE_POLLING_WAIT) */
-#endif /* I2C_SUPPORTS_CALLBACKS */
-
-#endif /* STM32_I2C_USE_I2C */
+ I2CD1.id_i2c = I2C1;
+ I2CD1.dmarx = STM32_DMA_STREAM(STM32_I2C_I2C1_RX_DMA_STREAM);
+ I2CD1.dmatx = STM32_DMA_STREAM(STM32_I2C_I2C1_TX_DMA_STREAM);
+#endif /* STM32_I2C_USE_I2C1 */
#if STM32_I2C_USE_I2C2
- RCC->APB1RSTR = RCC_APB1RSTR_I2C2RST; /* reset I2C 2 */
- RCC->APB1RSTR = 0;
i2cObjectInit(&I2CD2);
- I2CD2.id_i2c = I2C2;
-
-#if I2C_SUPPORTS_CALLBACKS
-#if !(STM32_I2C_I2C2_USE_POLLING_WAIT)
- I2CD2.timer = &(STM32_I2C_I2C2_USE_GPT_TIM);
- I2CD2.timer_cfg = &i2c2gptcfg;
-#endif /* !(STM32_I2C_I2C2_USE_POLLING_WAIT) */
-#endif /* I2C_SUPPORTS_CALLBACKS */
-
+ I2CD2.id_i2c = I2C2;
+ I2CD2.dmarx = STM32_DMA_STREAM(STM32_I2C_I2C2_RX_DMA_STREAM);
+ I2CD2.dmatx = STM32_DMA_STREAM(STM32_I2C_I2C2_TX_DMA_STREAM);
#endif /* STM32_I2C_USE_I2C2 */
+
+#if STM32_I2C_USE_I2C3
+ i2cObjectInit(&I2CD3);
+ I2CD3.id_i2c = I2C3;
+ I2CD3.dmarx = STM32_DMA_STREAM(STM32_I2C_I2C3_RX_DMA_STREAM);
+ I2CD3.dmatx = STM32_DMA_STREAM(STM32_I2C_I2C3_TX_DMA_STREAM);
+#endif /* STM32_I2C_USE_I2C3 */
}
/**
@@ -513,44 +363,207 @@ void i2c_lld_init(void) {
* @param[in] i2cp pointer to the @p I2CDriver object
*/
void i2c_lld_start(I2CDriver *i2cp) {
+
+ i2cp->dmamode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+
if (i2cp->id_state == I2C_STOP) { /* If in stopped state then enables the I2C clock.*/
#if STM32_I2C_USE_I2C1
if (&I2CD1 == i2cp) {
-#if I2C_SUPPORTS_CALLBACKS
+
+ bool_t b;
+ b = dmaStreamAllocate(i2cp->dmarx,
+ STM32_I2C_I2C1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq,
+ (void *)i2cp);
+ chDbgAssert(!b, "uart_lld_start(), #3", "stream already allocated");
+ b = dmaStreamAllocate(i2cp->dmatx,
+ STM32_I2C_I2C1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq,
+ (void *)i2cp);
+ chDbgAssert(!b, "uart_lld_start(), #4", "stream already allocated");
+ rccEnableI2C1(FALSE);
NVICEnableVector(I2C1_EV_IRQn,
CORTEX_PRIORITY_MASK(STM32_I2C_I2C1_IRQ_PRIORITY));
-#endif /* I2C_SUPPORTS_CALLBACKS */
NVICEnableVector(I2C1_ER_IRQn,
CORTEX_PRIORITY_MASK(STM32_I2C_I2C1_IRQ_PRIORITY));
- RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; /* I2C 1 clock enable */
+
+ i2cp->dmamode |= STM32_DMA_CR_CHSEL(I2C1_RX_DMA_CHANNEL) | \
+ STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY);
+ __NOP();
}
-#endif
+#endif /* STM32_I2C_USE_I2C1 */
+
#if STM32_I2C_USE_I2C2
if (&I2CD2 == i2cp) {
-#if I2C_SUPPORTS_CALLBACKS
+
+ bool_t b;
+ b = dmaStreamAllocate(i2cp->dmarx,
+ STM32_I2C_I2C2_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq,
+ (void *)i2cp);
+ chDbgAssert(!b, "uart_lld_start(), #3", "stream already allocated");
+ b = dmaStreamAllocate(i2cp->dmatx,
+ STM32_I2C_I2C2_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq,
+ (void *)i2cp);
+ chDbgAssert(!b, "uart_lld_start(), #4", "stream already allocated");
+ rccEnableI2C2(FALSE);
NVICEnableVector(I2C2_EV_IRQn,
- CORTEX_PRIORITY_MASK(STM32_I2C_I2C1_IRQ_PRIORITY));
-#endif /* I2C_SUPPORTS_CALLBACKS */
+ CORTEX_PRIORITY_MASK(STM32_I2C_I2C2_IRQ_PRIORITY));
NVICEnableVector(I2C2_ER_IRQn,
- CORTEX_PRIORITY_MASK(STM32_I2C_I2C1_IRQ_PRIORITY));
- RCC->APB1ENR |= RCC_APB1ENR_I2C2EN; /* I2C 2 clock enable */
+ CORTEX_PRIORITY_MASK(STM32_I2C_I2C2_IRQ_PRIORITY));
+
+ i2cp->dmamode |= STM32_DMA_CR_CHSEL(I2C2_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY);
}
-#endif
+#endif /* STM32_I2C_USE_I2C2 */
+
+#if STM32_I2C_USE_I2C3
+ if (&I2CD3 == i2cp) {
+
+ bool_t b;
+ b = dmaStreamAllocate(i2cp->dmarx,
+ STM32_I2C_I2C3_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq,
+ (void *)i2cp);
+ chDbgAssert(!b, "uart_lld_start(), #3", "stream already allocated");
+ b = dmaStreamAllocate(i2cp->dmatx,
+ STM32_I2C_I2C3_IRQ_PRIORITY,
+ (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq,
+ (void *)i2cp);
+ chDbgAssert(!b, "uart_lld_start(), #4", "stream already allocated");
+ rccEnableI2C3(FALSE);
+ NVICEnableVector(I2C3_EV_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_I2C_I2C3_IRQ_PRIORITY));
+ NVICEnableVector(I2C3_ER_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_I2C_I2C3_IRQ_PRIORITY));
+
+ i2cp->dmamode |= STM32_DMA_CR_CHSEL(I2C3_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY);
+ }
+#endif /* STM32_I2C_USE_I2C2 */
+
}
+ i2cp->dmamode |= STM32_DMA_CR_PSIZE_BYTE |
+ STM32_DMA_CR_MSIZE_BYTE |
+ STM32_DMA_CR_MINC |
+ STM32_DMA_CR_TCIE;
+ dmaStreamSetPeripheral(i2cp->dmarx, &i2cp->id_i2c->DR);
+ dmaStreamSetPeripheral(i2cp->dmatx, &i2cp->id_i2c->DR);
- i2cp->id_i2c->CR1 = I2C_CR1_SWRST; /* reset i2c peripherial */
+ i2cp->id_i2c->CR1 = I2C_CR1_SWRST; /* reset i2c peripheral */
i2cp->id_i2c->CR1 = 0;
i2c_lld_set_clock(i2cp);
i2c_lld_set_opmode(i2cp);
+
i2cp->id_i2c->CR1 |= 1; /* enable interface */
}
+
+/**
+ * @brief Reset interface via RCC.
+ */
void i2c_lld_reset(I2CDriver *i2cp){
chDbgCheck((i2cp->id_state == I2C_STOP)||(i2cp->id_state == I2C_READY),
"i2c_lld_reset: invalid state");
- RCC->APB1RSTR = RCC_APB1RSTR_I2C1RST; /* reset I2C 1 */
- RCC->APB1RSTR = 0;
+ #if STM32_I2C_USE_I2C1
+ if (&I2CD1 == i2cp)
+ rccResetI2C1();
+ #endif /* STM32_I2C_USE_I2C1 */
+
+ #if STM32_I2C_USE_I2C2
+ if (&I2CD2 == i2cp)
+ rccResetI2C2();
+ #endif /* STM32_I2C_USE_I2C2 */
+
+ #if STM32_I2C_USE_I2C3
+ if (&I2CD3 == i2cp)
+ rccResetI2C3();
+ #endif /* STM32_I2C_USE_I2C3 */
+}
+
+
+/**
+ * @brief Receive data via the I2C bus as master.
+ * @details Number of receiving bytes must be more than 1 because of stm32
+ * hardware restrictions.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] slave_addr slave device address
+ * @param[in] rxbuf pointer to the receive buffer
+ * @param[in] rxbytes number of bytes to be received
+ */
+void i2c_lld_master_receive(I2CDriver *i2cp, uint8_t slave_addr,
+ uint8_t *rxbuf, size_t rxbytes){
+
+ uint32_t mode = 0;
+
+ chDbgCheck((rxbytes > 1), "i2c_lld_master_receive");
+
+ /* init driver fields */
+ i2cp->slave_addr = (slave_addr << 1) | 0x01; /* LSB = 1 -> receive */
+ i2cp->rxbytes = rxbytes;
+ i2cp->rxbuf = rxbuf;
+ i2cp->errors = 0;
+
+ mode = STM32_DMA_CR_DIR_P2M;
+ // TODO: DMA error handling
+ dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
+ dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
+ dmaStreamSetMode(i2cp->dmarx, ((i2cp->dmamode) | mode));
+
+ /* wait stop bit from previous transaction*/
+ while(i2cp->id_i2c->CR1 & I2C_CR1_STOP)
+ ;
+
+ i2cp->id_i2c->CR2 |= I2C_CR2_ITERREN | I2C_CR2_ITEVTEN;
+ i2cp->id_i2c->CR1 |= I2C_CR1_START | I2C_CR1_ACK;
+}
+
+
+/**
+ * @brief Transmits data via the I2C bus as master.
+ *
+ * @details Number of receiving bytes must be 0 or more than 1 because of stm32
+ * hardware restrictions.
+ *
+ * @param[in] i2cp pointer to the @p I2CDriver object
+ * @param[in] slave_addr slave device address
+ * @param[in] txbuf pointer to the transmit buffer
+ * @param[in] txbytes number of bytes to be transmitted
+ * @param[in] rxbuf pointer to the receive buffer
+ * @param[in] rxbytes number of bytes to be received
+ */
+void i2c_lld_master_transmit(I2CDriver *i2cp, uint8_t slave_addr,
+ uint8_t *txbuf, size_t txbytes,
+ uint8_t *rxbuf, size_t rxbytes){
+
+ uint32_t mode = 0;
+
+ chDbgCheck(((rxbytes == 0) || ((rxbytes > 1) && (rxbuf != NULL))),
+ "i2cMasterTransmit");
+
+ /* init driver fields */
+ i2cp->slave_addr = (slave_addr << 1) & 0x00FE; /* LSB = 0 -> write */
+ i2cp->txbytes = txbytes;
+ i2cp->rxbytes = rxbytes;
+ i2cp->txbuf = txbuf;
+ i2cp->rxbuf = rxbuf;
+ i2cp->errors = 0;
+
+ mode = STM32_DMA_CR_DIR_M2P;
+ // TODO: DMA error handling
+ dmaStreamSetMemory0(i2cp->dmatx, txbuf);
+ dmaStreamSetTransactionSize(i2cp->dmatx, txbytes);
+ dmaStreamSetMode(i2cp->dmatx, ((i2cp->dmamode) | mode));
+
+ /* wait stop bit from previouse transaction*/
+ while(i2cp->id_i2c->CR1 & I2C_CR1_STOP)
+ ;
+
+ i2cp->id_i2c->CR2 |= I2C_CR2_ITERREN | I2C_CR2_ITEVTEN;
+ i2cp->id_i2c->CR1 |= I2C_CR1_START;
}
@@ -574,8 +587,13 @@ void i2c_lld_set_clock(I2CDriver *i2cp) {
regCR2 = i2cp->id_i2c->CR2; /* Get the I2Cx CR2 value */
regCR2 &= (uint16_t)~I2C_CR2_FREQ; /* Clear frequency FREQ[5:0] bits */
freq = (uint16_t)(STM32_PCLK1 / 1000000); /* Set frequency bits depending on pclk1 value */
+#ifdef STM32F4XX
+ chDbgCheck((freq >= 2) && (freq <= 42),
+ "i2c_lld_set_clock() : Peripheral clock freq. out of range");
+#else
chDbgCheck((freq >= 2) && (freq <= 36),
"i2c_lld_set_clock() : Peripheral clock freq. out of range");
+#endif /* define STM32F4XX */
regCR2 |= freq;
i2cp->id_i2c->CR2 = regCR2;
@@ -619,6 +637,7 @@ void i2c_lld_set_clock(I2CDriver *i2cp) {
i2cp->id_i2c->CR1 |= pe_bit_saved; /* restore the I2C peripheral enabled state */
}
+
/**
* @brief Set operation mode of I2C hardware.
*
@@ -645,28 +664,6 @@ void i2c_lld_set_opmode(I2CDriver *i2cp) {
i2cp->id_i2c->CR1 = regCR1; /* Write to I2Cx CR1 */
}
-/**
- * @brief Set own address.
- *
- * @param[in] i2cp pointer to the @p I2CDriver object
- */
-void i2c_lld_set_own_address(I2CDriver *i2cp) {
- /* TODO: dual address mode */
-
- i2cp->id_i2c->OAR1 |= 1 << 14;
-
- if (&(i2cp->id_config->own_addr_10) == NULL){ /* only 7-bit address */
- i2cp->id_i2c->OAR1 &= (~I2C_OAR1_ADDMODE);
- i2cp->id_i2c->OAR1 |= i2cp->id_config->own_addr_7 << 1;
- }
- else {
- chDbgAssert((i2cp->id_config->own_addr_10 < 1024),
- "i2c_lld_set_own_address(), #1", "10-bit address longer then 10 bit")
- i2cp->id_i2c->OAR1 |= I2C_OAR1_ADDMODE;
- i2cp->id_i2c->OAR1 |= i2cp->id_config->own_addr_10;
- }
-}
-
/**
* @brief Deactivates the I2C peripheral.
@@ -674,406 +671,43 @@ void i2c_lld_set_own_address(I2CDriver *i2cp) {
* @param[in] i2cp pointer to the @p I2CDriver object
*/
void i2c_lld_stop(I2CDriver *i2cp) {
- if (i2cp->id_state == I2C_READY) { /* If in ready state then disables the I2C clock.*/
+
+ if (i2cp->id_state != I2C_STOP) { /* If in ready state then disables the I2C clock.*/
+
+ dmaStreamDisable(i2cp->dmatx);
+ dmaStreamDisable(i2cp->dmarx);
+ dmaStreamClearInterrupt(i2cp->dmatx);
+ dmaStreamClearInterrupt(i2cp->dmarx);
+ dmaStreamRelease(i2cp->dmatx);
+ dmaStreamRelease(i2cp->dmarx);
+
#if STM32_I2C_USE_I2C1
if (&I2CD1 == i2cp) {
NVICDisableVector(I2C1_EV_IRQn);
NVICDisableVector(I2C1_ER_IRQn);
- RCC->APB1ENR &= ~RCC_APB1ENR_I2C1EN;
+ rccDisableI2C1(FALSE);
}
#endif
+
#if STM32_I2C_USE_I2C2
if (&I2CD2 == i2cp) {
NVICDisableVector(I2C2_EV_IRQn);
NVICDisableVector(I2C2_ER_IRQn);
- RCC->APB1ENR &= ~RCC_APB1ENR_I2C2EN;
+ rccDisableI2C2(FALSE);
}
#endif
- }
-
- i2cp->id_state = I2C_STOP;
-}
-
-
-#if I2C_SUPPORTS_CALLBACKS
-/**
- * @brief Transmits data via the I2C bus as master.
- *
- * @param[in] i2cp pointer to the @p I2CDriver object
- * @param[in] slave_addr Slave device address. Bits 0-9 contain slave
- * device address. Bit 15 must be set to 1 if 10-bit
- * addressing modes used. Otherwise keep it cleared.
- * Bits 10-14 unused.
- * @param[in] txbuf pointer to the transmit buffer
- * @param[in] txbytes number of bytes to be transmitted
- * @param[in] rxbuf pointer to the receive buffer
- * @param[in] rxbytes number of bytes to be received
- */
-void i2c_lld_master_transmit(I2CDriver *i2cp, uint16_t slave_addr,
- uint8_t *txbuf, size_t txbytes, uint8_t *rxbuf, size_t rxbytes) {
-
- /* "waiting" for STOP bit routine*/
- #if STM32_I2C_I2C1_USE_POLLING_WAIT
- uint32_t timeout = I2C_POLLING_TIMEOUT;
- while((i2cp->id_i2c->CR1 & I2C_CR1_STOP) && timeout)
- timeout--;
- chDbgAssert((timeout > 0), "i2c_lld_master_transmit(), #1", "time to STOP is out");
- #else
- chDbgAssert(!(i2cp->flags & I2C_FLG_TIMER_ARMED), "i2c_lld_master_transmit(), #1", "time to STOP is out");
- if ((i2cp->id_i2c->CR1 & I2C_CR1_STOP) && i2cp->timer != NULL && i2cp->timer_cfg != NULL){
- chSysLockFromIsr();
- gptStartOneShotI(i2cp->timer, I2C_STOP_GPT_TIMEOUT);
- i2cp->flags |= I2C_FLG_TIMER_ARMED;
- chSysUnlockFromIsr();
- return;
- }
- #endif /* STM32_I2C_I2C1_USE_POLLING_WAIT */
- /* init driver fields */
- i2cp->slave_addr = slave_addr;
- i2cp->txbytes = txbytes;
- i2cp->rxbytes = rxbytes;
- i2cp->txbuf = txbuf;
- i2cp->rxbuf = rxbuf;
-
- /* init address fields */
- if(slave_addr & 0x8000){ /* 10-bit mode used */
- i2cp->slave_addr1 = ((slave_addr >>7) & 0x0006); /* add the two msb of 10-bit address to the header */
- i2cp->slave_addr1 |= 0xF0; /* add the header bits with LSB = 0 -> write */
- i2cp->slave_addr2 = slave_addr & 0x00FF; /* the remaining 8 bit of 10-bit address */
- }
- else{
- i2cp->slave_addr1 = ((slave_addr <<1) & 0x00FE); /* LSB = 0 -> write */
- }
-
- /* setting flags and register bits */
- i2cp->flags = 0;
- i2cp->errors = 0;
- i2cp->id_i2c->CR1 &= ~I2C_CR1_POS;
- i2cp->id_i2c->CR1 |= I2C_CR1_START;
- i2cp->id_i2c->CR2 |= (I2C_CR2_ITERREN|I2C_CR2_ITEVTEN|I2C_CR2_ITBUFEN); /* enable ERR, EVT & BUF ITs */
-}
-
-/**
- * @brief Receives data from the I2C bus.
- *
- * @param[in] i2cp pointer to the @p I2CDriver object
- * @param[in] slave_addr Slave device address. Bits 0-9 contain slave
- * device address. Bit 15 must be set to 1 if 10-bit
- * addressing modes used. Otherwise keep it cleared.
- * Bits 10-14 unused.
- * @param[in] rxbuf pointer to the receive buffer
- * @param[in] rxbytes number of bytes to be received
- */
-void i2c_lld_master_receive(I2CDriver *i2cp, uint16_t slave_addr,
- uint8_t *rxbuf, size_t rxbytes){
-
- chDbgAssert((i2cp->id_i2c->SR1 + i2cp->id_i2c->SR2) == 0,
- "i2c_lld_master_receive(), #1",
- "some interrupt sources not clear");
-
- /* "waiting" for STOP bit routine*/
- #if STM32_I2C_I2C1_USE_POLLING_WAIT
- uint32_t timeout = I2C_POLLING_TIMEOUT;
- while((i2cp->id_i2c->CR1 & I2C_CR1_STOP) && timeout)
- timeout--;
- chDbgAssert((timeout > 0), "i2c_lld_master_receive(), #1", "time to STOP is out");
- #else
- chDbgAssert(!(i2cp->flags & I2C_FLG_TIMER_ARMED), "i2c_lld_master_receive(), #1", "time to STOP is out");
- if ((i2cp->id_i2c->CR1 & I2C_CR1_STOP) && i2cp->timer != NULL && i2cp->timer_cfg != NULL){
- chSysLockFromIsr();
- gptStartOneShotI(i2cp->timer, I2C_STOP_GPT_TIMEOUT);
- i2cp->flags |= I2C_FLG_TIMER_ARMED;
- chSysUnlockFromIsr();
- return;
+#if STM32_I2C_USE_I2C3
+ if (&I2CD3 == i2cp) {
+ NVICDisableVector(I2C3_EV_IRQn);
+ NVICDisableVector(I2C3_ER_IRQn);
+ rccDisableI2C3(FALSE);
}
- #endif /* STM32_I2C_I2C1_USE_POLLING_WAIT */
-
- /* init driver fields */
- i2cp->slave_addr = slave_addr;
- i2cp->rxbytes = rxbytes;
- i2cp->rxbuf = rxbuf;
-
- /* init address fields */
- if(slave_addr & 0x8000){ /* 10-bit mode used */
- i2cp->slave_addr1 = ((slave_addr >>7) & 0x0006); /* add the two msb of 10-bit address to the header */
- i2cp->slave_addr1 |= 0xF0; /* add the header bits (the LSB -> 1 will be add to second */
- i2cp->slave_addr2 = slave_addr & 0x00FF; /* the remaining 8 bit of 10-bit address */
- }
- else{
- i2cp->slave_addr1 = ((slave_addr <<1) | 0x01); /* LSB = 1 -> receive */
- }
-
- /* setting flags and register bits */
- i2cp->flags |= I2C_FLG_MASTER_RECEIVER;
- i2cp->errors = 0;
-
- i2cp->id_i2c->CR1 |= I2C_CR1_ACK; /* acknowledge returned */
- i2cp->id_i2c->CR1 &= ~I2C_CR1_POS;
-
- if(i2cp->rxbytes == 1) { /* Only one byte to be received */
- i2cp->flags |= I2C_FLG_1BTR;
- }
- else if(i2cp->rxbytes == 2) { /* Only two bytes to be received */
- i2cp->flags |= I2C_FLG_2BTR;
- i2cp->id_i2c->CR1 |= I2C_CR1_POS; /* Acknowledge Position */
- }
-
- i2cp->id_i2c->CR1 |= I2C_CR1_START; /* send start bit */
- i2cp->id_i2c->CR2 |= (I2C_CR2_ITERREN|I2C_CR2_ITEVTEN|I2C_CR2_ITBUFEN); /* enable ERR, EVT & BUF ITs */
-}
-
-
-/**
- * @brief Realize read-though-write behavior.
- *
- * @param[in] i2cp pointer to the @p I2CDriver object
- *
- * @notapi
- */
-void i2c_lld_master_transceive(I2CDriver *i2cp){
-
- chDbgAssert((i2cp != NULL) && (i2cp->slave_addr1 != 0) &&\
- (i2cp->rxbytes > 0) && (i2cp->rxbuf != NULL),
- "i2c_lld_master_transceive(), #1",
- "");
-
- i2cp->id_state = I2C_ACTIVE_TRANSCEIVE;
-
- /* "waiting" for START bit routine*/
- #if STM32_I2C_I2C1_USE_POLLING_WAIT
- uint32_t timeout = I2C_POLLING_TIMEOUT;
- while((i2cp->id_i2c->CR1 & I2C_CR1_START) && timeout);
- timeout--;
- chDbgAssert((timeout > 0), "i2c_lld_master_transceive(), #1", "time to START is out");
- #else
- chDbgAssert(!(i2cp->flags & I2C_FLG_TIMER_ARMED), "i2c_lld_master_transceive(), #1", "time to START is out");
- if ((i2cp->id_i2c->CR1 & I2C_CR1_START) && i2cp->timer != NULL && i2cp->timer_cfg != NULL){
- chSysLockFromIsr();
- gptStartOneShotI(i2cp->timer, I2C_START_GPT_TIMEOUT);
- i2cp->flags |= I2C_FLG_TIMER_ARMED;
- chSysUnlockFromIsr();
- return;
- }
- #endif /* STM32_I2C_I2C1_USE_POLLING_WAIT */
-
- /* init address fields */
- if(i2cp->slave_addr & 0x8000){ /* 10-bit mode used */
- i2cp->slave_addr1 = ((i2cp->slave_addr >>7) & 0x0006);/* add the two msb of 10-bit address to the header */
- i2cp->slave_addr1 |= 0xF0; /* add the header bits (the LSB -> 1 will be add to second */
- i2cp->slave_addr2 = i2cp->slave_addr & 0x00FF; /* the remaining 8 bit of 10-bit address */
- }
- else{
- i2cp->slave_addr1 |= 0x01;
- }
-
- /* setting flags and register bits */
- i2cp->flags |= I2C_FLG_MASTER_RECEIVER;
- i2cp->errors = 0;
- i2cp->id_i2c->CR1 |= I2C_CR1_ACK; /* acknowledge returned */
- i2cp->id_i2c->CR1 &= ~I2C_CR1_POS;
-
- if(i2cp->rxbytes == 1) { /* Only one byte to be received */
- i2cp->flags |= I2C_FLG_1BTR;
- }
- else if(i2cp->rxbytes == 2) { /* Only two bytes to be received */
- i2cp->flags |= I2C_FLG_2BTR;
- i2cp->id_i2c->CR1 |= I2C_CR1_POS; /* Acknowledge Position */
- }
-
- i2cp->id_i2c->CR2 |= (I2C_CR2_ITERREN|I2C_CR2_ITEVTEN|I2C_CR2_ITBUFEN); /* enable ERR, EVT & BUF ITs */
-}
-
-#else /*I2C_SUPPORTS_CALLBACKS*/
-
-/**
- * @brief Synchronously transmits data via the I2C bus as master.
- *
- * @param[in] i2cp pointer to the @p I2CDriver object
- * @param[in] slave_addr Slave device address. Bits 0-9 contain slave
- * device address. Bit 15 must be set to 1 if 10-bit
- * addressing modes used. Otherwise keep it cleared.
- * Bits 10-14 unused.
- * @param[in] txbuf pointer to the transmit buffer
- * @param[in] txbytes number of bytes to be transmitted
- * @param[in] rxbuf pointer to the receive buffer
- * @param[in] rxbytes number of bytes to be received
- */
-void i2c_lld_master_transmit(I2CDriver *i2cp, uint16_t slave_addr,
- uint8_t *txbuf, size_t txbytes, uint8_t *rxbuf, size_t rxbytes) {
-
- /* init driver fields */
- i2cp->slave_addr = slave_addr;
- i2cp->txbytes = txbytes;
- i2cp->rxbytes = rxbytes;
- i2cp->txbuf = txbuf;
- i2cp->rxbuf = rxbuf;
-
- /* init address fields */
- if(slave_addr & 0x8000){ /* 10-bit mode used */
- i2cp->slave_addr1 = ((slave_addr >>7) & 0x0006); /* add the two msb of 10-bit address to the header */
- i2cp->slave_addr1 |= 0xF0; /* add the header bits with LSB = 0 -> write */
- i2cp->slave_addr2 = slave_addr & 0x00FF; /* the remaining 8 bit of 10-bit address */
- }
- else{
- i2cp->slave_addr1 = ((slave_addr <<1) & 0x00FE); /* LSB = 0 -> write */
- }
-
- i2cp->flags = 0;
- i2cp->errors = 0;
- i2cp->id_i2c->CR1 &= ~I2C_CR1_POS;
- i2cp->id_i2c->CR2 &= ~I2C_CR2_ITEVTEN; /* disable event interrupts */
- i2cp->id_i2c->CR2 |= I2C_CR2_ITERREN; /* enable error interrupts */
-
- i2cp->id_i2c->CR1 |= I2C_CR1_START;
- while (!(i2cp->id_i2c->SR1 & I2C_SR1_SB))
- ;
- i2cp->id_i2c->DR = i2cp->slave_addr1;
- while (!(i2cp->id_i2c->SR1 & I2C_SR1_ADDR))
- ;
- while (!(i2cp->id_i2c->SR2 & I2C_SR2_BUSY))
- ;
- i2cp->id_i2c->DR = *txbuf;
- txbuf++;
- i2cp->txbytes--;
- while(i2cp->txbytes > 0){
- while(!(i2cp->id_i2c->SR1 & I2C_SR1_BTF))
- ;
- i2cp->id_i2c->DR = *txbuf;
- txbuf++;
- i2cp->txbytes--;
- }
- while(!(i2cp->id_i2c->SR1 & I2C_SR1_BTF))
- ;
- if(rxbytes == 0){
- i2cp->id_i2c->CR1 |= I2C_CR1_STOP;
- while (i2cp->id_i2c->CR1 & I2C_CR1_STOP)
- ;
- }
- else{
- i2c_lld_master_receive(i2cp, slave_addr, rxbuf, rxbytes);
- }
-}
-
-
-/**
- * @brief Synchronously receives data from the I2C bus.
- *
- * @param[in] i2cp pointer to the @p I2CDriver object
- * @param[in] slave_addr Slave device address. Bits 0-9 contain slave
- * device address. Bit 15 must be set to 1 if 10-bit
- * addressing modes used. Otherwise keep it cleared.
- * Bits 10-14 unused.
- * @param[in] rxbuf pointer to the receive buffer
- * @param[in] rxbytes number of bytes to be received
- */
-void i2c_lld_master_receive(I2CDriver *i2cp, uint16_t slave_addr,
- uint8_t *rxbuf, size_t rxbytes){
-
- /* init driver fields */
- i2cp->slave_addr = slave_addr;
- i2cp->rxbytes = rxbytes;
- i2cp->rxbuf = rxbuf;
-
- /* init address fields */
- if(slave_addr & 0x8000){ /* 10-bit mode used */
- i2cp->slave_addr1 = ((slave_addr >>7) & 0x0006); /* add the two msb of 10-bit address to the header */
- i2cp->slave_addr1 |= 0xF0; /* add the header bits (the LSB -> 1 will be add to second */
- i2cp->slave_addr2 = slave_addr & 0x00FF; /* the remaining 8 bit of 10-bit address */
- }
- else{
- i2cp->slave_addr1 = ((slave_addr <<1) | 0x01); /* LSB = 1 -> receive */
+#endif
}
-
- /* setting flags and register bits */
- i2cp->flags = 0;
- i2cp->errors = 0;
- i2cp->id_i2c->CR1 &= ~I2C_CR1_POS;
- i2cp->id_i2c->CR2 &= ~I2C_CR2_ITEVTEN; /* disable event interrupts */
- i2cp->id_i2c->CR2 |= I2C_CR2_ITERREN; /* enable error interrupts */
-
- i2cp->id_i2c->CR1 |= I2C_CR1_START;
- while (!(i2cp->id_i2c->SR1 & I2C_SR1_SB))
- ;
-
- i2cp->id_i2c->DR = i2cp->slave_addr1;
- while (!(i2cp->id_i2c->SR1 & I2C_SR1_ADDR))
- ;
-
- if(i2cp->rxbytes >= 3){ /* more than 2 bytes receiving procedure */
- while(!(i2cp->id_i2c->SR2 & I2C_SR2_BUSY)) /* to clear ADDR bit */
- ;
- while(i2cp->rxbytes > 3){
- while(!(i2cp->id_i2c->SR1 & I2C_SR1_BTF))
- ;
- *rxbuf = i2cp->id_i2c->DR;
- rxbuf++;
- i2cp->rxbytes--;
- }
- while(!(i2cp->id_i2c->SR1 & I2C_SR1_BTF)) /* stopping procedure */
- ;
- i2cp->id_i2c->CR1 &= ~I2C_CR1_ACK;
- chSysLock();
- i2cp->id_i2c->CR1 |= I2C_CR1_STOP;
- *rxbuf = i2cp->id_i2c->DR;
- rxbuf++;
- i2cp->rxbytes--;
- chSysUnlock();
- while(!(i2cp->id_i2c->SR1 & I2C_SR1_RXNE))
- ;
- *rxbuf = i2cp->id_i2c->DR;
- rxbuf++;
- i2cp->rxbytes--;
- while (i2cp->id_i2c->CR1 & I2C_CR1_STOP)
- ;
- i2cp->id_i2c->CR1 |= I2C_CR1_ACK;
- }
- else{ /* 1 or 2 bytes receiving procedure */
- if(i2cp->rxbytes == 2){
- i2cp->id_i2c->CR1 |= I2C_CR1_POS;
- chSysLock();
- while(!(i2cp->id_i2c->SR2 & I2C_SR2_BUSY)) /* to clear ADDR bit */
- ;
- i2cp->id_i2c->CR1 &= ~I2C_CR1_ACK;
- chSysUnlock();
- while(!(i2cp->id_i2c->SR1 & I2C_SR1_BTF))
- ;
- chSysLock();
- i2cp->id_i2c->CR1 |= I2C_CR1_STOP;
- *rxbuf = i2cp->id_i2c->DR;
- rxbuf++;
- i2cp->rxbytes--;
- chSysUnlock();
- *rxbuf = i2cp->id_i2c->DR;
- rxbuf++;
- i2cp->rxbytes--;
- while (i2cp->id_i2c->CR1 & I2C_CR1_STOP)
- ;
- i2cp->id_i2c->CR1 &= ~I2C_CR1_POS;
- i2cp->id_i2c->CR1 |= I2C_CR1_ACK;
- }
- else{ /* 1 byte */
- i2cp->id_i2c->CR1 &= ~I2C_CR1_ACK;
- chSysLock();
- while(!(i2cp->id_i2c->SR2 & I2C_SR2_BUSY)) /* to clear ADDR bit */
- ;
- i2cp->id_i2c->CR1 |= I2C_CR1_STOP;
- chSysUnlock();
- while(!(i2cp->id_i2c->SR1 & I2C_SR1_RXNE))
- ;
- *rxbuf = i2cp->id_i2c->DR;
- rxbuf++;
- i2cp->rxbytes--;
- while (i2cp->id_i2c->CR1 & I2C_CR1_STOP)
- ;
- i2cp->id_i2c->CR1 |= I2C_CR1_ACK;
- }
- }
+ i2cp->id_state = I2C_STOP;
}
-#endif /* I2C_SUPPORTS_CALLBACKS */
-#undef rxBuffp
-#undef txBuffp
#endif /* HAL_USE_I2C */
diff --git a/os/hal/platforms/STM32/i2c_lld.h b/os/hal/platforms/STM32/i2c_lld.h
index 9bf56985c..378b3a335 100644
--- a/os/hal/platforms/STM32/i2c_lld.h
+++ b/os/hal/platforms/STM32/i2c_lld.h
@@ -1,3 +1,23 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
/**
* @file STM32/i2c_lld.h
* @brief STM32 I2C subsystem low level driver header.
@@ -17,50 +37,37 @@
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
-/**
- * @brief Switch between callback based and synchronouse driver.
- * @note The default is synchronouse.
- */
-#if !defined(I2C_SUPPORTS_CALLBACKS) || defined(__DOXYGEN__)
-#define I2C_SUPPORTS_CALLBACKS TRUE
-#endif
-
-/**
- * @brief I2C1 driver synchronization choice between GPT and polling.
- * @note The default is polling wait.
- */
-#if !defined(STM32_I2C_I2C1_USE_GPT_TIM) || \
- !defined(STM32_I2C_I2C1_USE_POLLING_WAIT) || \
- defined(__DOXYGEN__)
-#define STM32_I2C_I2C1_USE_POLLING_WAIT TRUE
-#endif
/**
- * @brief I2C2 driver synchronization choice between GPT and polling.
- * @note The default is polling wait.
+ * @name Configuration options
+ * @{
*/
-#if !defined(STM32_I2C_I2C2_USE_GPT_TIM) || \
- !defined(STM32_I2C_I2C2_USE_POLLING_WAIT) || \
- defined(__DOXYGEN__)
-#define STM32_I2C_I2C2_USE_POLLING_WAIT TRUE
-#endif
/**
* @brief I2C1 driver enable switch.
* @details If set to @p TRUE the support for I2C1 is included.
- * @note The default is @p TRUE.
+ * @note The default is @p FALSE.
*/
#if !defined(STM32_I2C_USE_I2C1) || defined(__DOXYGEN__)
-#define STM32_I2C_USE_I2C1 TRUE
+#define STM32_I2C_USE_I2C1 FALSE
#endif
/**
* @brief I2C2 driver enable switch.
* @details If set to @p TRUE the support for I2C2 is included.
- * @note The default is @p TRUE.
+ * @note The default is @p FALSE.
*/
#if !defined(STM32_I2C_USE_I2C2) || defined(__DOXYGEN__)
-#define STM32_I2C_USE_I2C2 TRUE
+#define STM32_I2C_USE_I2C2 FALSE
+#endif
+
+/**
+ * @brief I2C3 driver enable switch.
+ * @details If set to @p TRUE the support for I2C3 is included.
+ * @note The default is @p FALSE.
+ */
+#if !defined(STM32_I2C_USE_I2C3) || defined(__DOXYGEN__)
+#define STM32_I2C_USE_I2C3 FALSE
#endif
/**
@@ -79,40 +86,153 @@
#define STM32_I2C_I2C2_IRQ_PRIORITY 0xA0
#endif
+/**
+ * @brief I2C2 interrupt priority level setting.
+ * @note @p BASEPRI_KERNEL >= @p STM32_I2C_I2C2_IRQ_PRIORITY > @p PRIORITY_PENDSV.
+ */
+#if !defined(STM32_I2C_I2C3_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C3_IRQ_PRIORITY 0xA0
+#endif
+
+/**
+ * @brief I2C1 DMA error hook.
+ * @note The default action for DMA errors is a system halt because DMA
+ * error can only happen because programming errors.
+ */
+#if !defined(STM32_I2C_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define STM32_I2C_DMA_ERROR_HOOK(uartp) chSysHalt()
+#endif
+
+#if STM32_ADVANCED_DMA || defined(__DOXYGEN__)
+
+/**
+ * @brief DMA stream used for I2C1 RX operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_I2C_I2C1_RX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
+#endif
+
+/**
+ * @brief DMA stream used for I2C1 TX operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_I2C_I2C1_TX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
+#endif
+
+/**
+ * @brief DMA stream used for I2C2 RX operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_I2C_I2C2_RX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
+#endif
+
+/**
+ * @brief DMA stream used for I2C2 TX operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_I2C_I2C2_TX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
+#endif
+
+/**
+ * @brief DMA stream used for I2C3 RX operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_I2C_I2C3_RX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
+#endif
+
+/**
+ * @brief DMA stream used for I2C3 TX operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_I2C_I2C3_TX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_I2C_I2C3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
+#endif
+
+#else /* !STM32_ADVANCED_DMA */
+
+/* Fixed streams for platforms using the old DMA peripheral, the values are
+ valid for both STM32F1xx and STM32L1xx.*/
+#define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
+#define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
+#define STM32_I2C_I2C2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 5)
+#define STM32_I2C_I2C2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
+
+#endif /* !STM32_ADVANCED_DMA*/
+/** @} */
+
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
-/** @brief EV5 */
-#define I2C_EV5_MASTER_MODE_SELECT ((uint32_t)(((I2C_SR2_MSL|I2C_SR2_BUSY)<< 16)|I2C_SR1_SB)) /* BUSY, MSL and SB flag */
-/** @brief EV6 */
+/** @brief flags for interrupt handling */
+#define I2C_EV5_MASTER_MODE_SELECT ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY) << 16) | I2C_SR1_SB)) /* BUSY, MSL and SB flag */
#define I2C_EV6_MASTER_TRA_MODE_SELECTED ((uint32_t)(((I2C_SR2_MSL|I2C_SR2_BUSY|I2C_SR2_TRA)<< 16)|I2C_SR1_ADDR|I2C_SR1_TXE)) /* BUSY, MSL, ADDR, TXE and TRA flags */
#define I2C_EV6_MASTER_REC_MODE_SELECTED ((uint32_t)(((I2C_SR2_MSL|I2C_SR2_BUSY)<< 16)|I2C_SR1_ADDR)) /* BUSY, MSL and ADDR flags */
-/** @brief EV7 */
-#define I2C_EV7_MASTER_REC_BYTE_RECEIVED ((uint32_t)(((I2C_SR2_MSL|I2C_SR2_BUSY)<< 16)|I2C_SR1_RXNE)) /* BUSY, MSL and RXNE flags */
-#define I2C_EV7_MASTER_REC_BYTE_QUEUED ((uint32_t)(((I2C_SR2_MSL|I2C_SR2_BUSY)<< 16)|I2C_SR1_BTF|I2C_SR1_RXNE)) /* BUSY, MSL, RXNE and BTF flags*/
-/** @brief EV8 */
-#define I2C_EV8_MASTER_BYTE_TRANSMITTING ((uint32_t)(((I2C_SR2_MSL|I2C_SR2_BUSY|I2C_SR2_TRA)<< 16)|I2C_SR1_TXE)) /* TRA, BUSY, MSL, TXE flags */
-/** @brief EV8_2 */
-#define I2C_EV8_2_MASTER_BYTE_TRANSMITTED ((uint32_t)(((I2C_SR2_MSL|I2C_SR2_BUSY|I2C_SR2_TRA)<< 16)|I2C_SR1_BTF|I2C_SR1_TXE)) /* TRA, BUSY, MSL, TXE and BTF flags */
-/** @brief EV9 */
-#define I2C_EV9_MASTER_ADDR_10BIT ((uint32_t)(((I2C_SR2_MSL|I2C_SR2_BUSY)<< 16)|I2C_SR1_ADD10)) /* BUSY, MSL and ADD10 flags */
+#define I2C_EV8_2_MASTER_BYTE_TRANSMITTED ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA) << 16) | I2C_SR1_BTF | I2C_SR1_TXE)) /* TRA, BUSY, MSL, TXE and BTF flags */
#define I2C_EV_MASK 0x00FFFFFF /* First byte zeroed because there is no need of PEC register part from SR2 */
-#define I2C_FLG_1BTR 0x01 /* Single byte to be received and processed */
-#define I2C_FLG_2BTR 0x02 /* Two bytes to be received and processed */
-#define I2C_FLG_3BTR 0x04 /* Last three received bytes to be processed */
-#define I2C_FLG_MASTER_RECEIVER 0x10
-#define I2C_FLG_HEADER_SENT 0x80
-#define I2C_FLG_TIMER_ARMED 0x40 /* Used to check locks on the bus */
+/** @brief error checks */
+#if STM32_I2C_USE_I2C1 && !STM32_HAS_I2C1
+#error "I2C1 not present in the selected device"
+#endif
+
+#if STM32_I2C_USE_I2C2 && !STM32_HAS_I2C2
+#error "I2C2 not present in the selected device"
+#endif
+
+#if STM32_I2C_USE_I2C3 && !STM32_HAS_I2C3
+#error "I2C3 not present in the selected device"
+#endif
+
+#if !STM32_I2C_USE_I2C1 && !STM32_I2C_USE_I2C2 && \
+ !STM32_I2C_USE_I2C3
+#error "I2C driver activated but no I2C peripheral assigned"
+#endif
+
+#if STM32_I2C_USE_I2C1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C1_RX_DMA_STREAM, \
+ STM32_I2C1_RX_DMA_MSK)
+#error "invalid DMA stream associated to I2C1 RX"
+#endif
+
+#if STM32_I2C_USE_I2C1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C1_TX_DMA_STREAM, \
+ STM32_I2C1_TX_DMA_MSK)
+#error "invalid DMA stream associated to I2C1 TX"
+#endif
+
+#if STM32_I2C_USE_I2C2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C2_RX_DMA_STREAM, \
+ STM32_I2C2_RX_DMA_MSK)
+#error "invalid DMA stream associated to I2C2 RX"
+#endif
-#define EV6_SUBEV_MASK (I2C_FLG_1BTR|I2C_FLG_2BTR|I2C_FLG_MASTER_RECEIVER)
-#define EV7_SUBEV_MASK (I2C_FLG_2BTR|I2C_FLG_3BTR|I2C_FLG_MASTER_RECEIVER)
+#if STM32_I2C_USE_I2C2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C2_TX_DMA_STREAM, \
+ STM32_I2C2_TX_DMA_MSK)
+#error "invalid DMA stream associated to I2C2 TX"
+#endif
-#define I2C_EV6_1_MASTER_REC_2BTR_MODE_SELECTED (I2C_FLG_2BTR|I2C_FLG_MASTER_RECEIVER)
-#define I2C_EV6_3_MASTER_REC_1BTR_MODE_SELECTED (I2C_FLG_1BTR|I2C_FLG_MASTER_RECEIVER)
-#define I2C_EV7_2_MASTER_REC_3BYTES_TO_PROCESS (I2C_FLG_3BTR|I2C_FLG_MASTER_RECEIVER)
-#define I2C_EV7_3_MASTER_REC_2BYTES_TO_PROCESS (I2C_FLG_2BTR|I2C_FLG_MASTER_RECEIVER)
+#if STM32_I2C_USE_I2C3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C3_RX_DMA_STREAM, \
+ STM32_I2C3_RX_DMA_MSK)
+#error "invalid DMA stream associated to I2C3 RX"
+#endif
+
+#if STM32_I2C_USE_I2C3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C3_TX_DMA_STREAM, \
+ STM32_I2C3_TX_DMA_MSK)
+#error "invalid DMA stream associated to I2C3 TX"
+#endif
+
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
/*===========================================================================*/
/* Driver data structures and types. */
@@ -142,10 +262,6 @@ typedef struct {
i2copmode_t op_mode; /**< @brief Specifies the I2C mode.*/
uint32_t clock_speed; /**< @brief Specifies the clock frequency. Must be set to a value lower than 400kHz */
i2cdutycycle_t duty_cycle; /**< @brief Specifies the I2C fast mode duty cycle */
- uint8_t own_addr_7; /**< @brief Specifies the first device 7-bit own address. */
- uint16_t own_addr_10; /**< @brief Specifies the second part of device own address in 10-bit mode. Set to NULL if not used. */
- uint16_t ack; /**< @brief Enables or disables the acknowledgment. */
- uint8_t nbit_own_addr; /**< @brief Specifies if 7-bit or 10-bit address is acknowledged */
} I2CConfig;
@@ -155,83 +271,51 @@ typedef struct {
typedef struct I2CDriver I2CDriver;
/**
- * @brief Type of a structure representing an I2C slave config.
- */
-typedef struct I2CSlaveConfig I2CSlaveConfig;
-
-/**
* @brief Structure representing an I2C driver.
*/
struct I2CDriver{
/**
* @brief Driver state.
*/
- i2cstate_t id_state;
+ i2cstate_t id_state;
-#if I2C_USE_WAIT
/**
* @brief Thread waiting for I/O completion.
*/
- Thread *id_thread;
-#endif /* I2C_USE_WAIT */
+ Thread *id_thread;
+
#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the bus.
*/
- Mutex id_mutex;
+ Mutex id_mutex;
#elif CH_USE_SEMAPHORES
- Semaphore id_semaphore;
+ Semaphore id_semaphore;
#endif
#endif /* I2C_USE_MUTUAL_EXCLUSION */
/**
* @brief Current configuration data.
*/
- const I2CConfig *id_config;
- /**
- * @brief Current slave configuration data.
- */
- const I2CSlaveConfig *id_slave_config;
+ const I2CConfig *id_config;
- __IO size_t txbytes; /*!< @brief Number of bytes to be transmitted. */
- __IO size_t rxbytes; /*!< @brief Number of bytes to be received. */
- uint8_t *rxbuf; /*!< @brief Pointer to receive buffer. */
- uint8_t *txbuf; /*!< @brief Pointer to transmit buffer.*/
- uint8_t *rxbuff_p; /*!< @brief Pointer to the current byte in slave rx buffer. */
- uint8_t *txbuff_p; /*!< @brief Pointer to the current byte in slave tx buffer. */
+ __IO size_t txbytes; /*!< @brief Number of bytes to be transmitted. */
+ __IO size_t rxbytes; /*!< @brief Number of bytes to be received. */
+ uint8_t *rxbuf; /*!< @brief Pointer to receive buffer. */
+ uint8_t *txbuf; /*!< @brief Pointer to transmit buffer.*/
- __IO i2cflags_t errors; /*!< @brief Error flags.*/
- __IO i2cflags_t flags; /*!< @brief State flags.*/
+ __IO i2cflags_t errors; /*!< @brief Error flags.*/
- uint16_t slave_addr; /*!< @brief Current slave address. */
- uint8_t slave_addr1;/*!< @brief 7-bit address of the slave with r\w bit.*/
- uint8_t slave_addr2;/*!< @brief Uses in 10-bit address mode. */
-
-#if CH_USE_EVENTS
- EventSource sevent; /*!< @brief Status Change @p EventSource.*/
-#endif
+ uint8_t slave_addr; /*!< @brief Current slave address without R/W bit. */
/*********** End of the mandatory fields. **********************************/
- /**
- * @brief Pointer to the I2Cx registers block.
- */
- I2C_TypeDef *id_i2c;
-
-#if !(STM32_I2C_I2C1_USE_POLLING_WAIT)
- /* TODO: capability to switch this GPT fields off */
- /**
- * @brief Timer for waiting STOP condition on the bus.
- * @details This is workaround for STM32 buggy I2C cell.
- */
- GPTDriver *timer;
+ uint32_t dmamode; /*!< @brief DMA mode bit mask.*/
+ const stm32_dma_stream_t *dmarx; /*!< @brief Receive DMA channel.*/
+ const stm32_dma_stream_t *dmatx; /*!< @brief Transmit DMA channel.*/
- /**
- * @brief Config for workaround timer.
- */
- const GPTConfig *timer_cfg;
-#endif /* !(STM32_I2C_I2C1_USE_POLLING_WAIT) */
+ I2C_TypeDef *id_i2c; /*!< @brief Pointer to the I2Cx registers block. */
};
@@ -239,17 +323,11 @@ struct I2CDriver{
/* Driver macros. */
/*===========================================================================*/
-#define i2c_lld_bus_is_busy(i2cp) \
- (i2cp->id_i2c->SR2 & I2C_SR2_BUSY)
-
-
-/* Wait until BUSY flag is reset: a STOP has been generated on the bus
- * signaling the end of transmission. Normally this wait function
- * does not block thread, only if slave not response it does.
+/**
+ * Wait until BUSY flag is reset.
*/
#define i2c_lld_wait_bus_free(i2cp) { \
- uint32_t tmo = 0xfffff; \
- while((i2cp->id_i2c->SR2 & I2C_SR2_BUSY) && tmo--) \
+ while(i2cp->id_i2c->SR2 & I2C_SR2_BUSY) \
; \
}
@@ -266,6 +344,10 @@ extern I2CDriver I2CD1;
extern I2CDriver I2CD2;
#endif
+#if STM32_I2C_USE_I2C3
+extern I2CDriver I2CD3;
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -274,14 +356,12 @@ void i2c_lld_init(void);
void i2c_lld_reset(I2CDriver *i2cp);
void i2c_lld_set_clock(I2CDriver *i2cp);
void i2c_lld_set_opmode(I2CDriver *i2cp);
-void i2c_lld_set_own_address(I2CDriver *i2cp);
void i2c_lld_start(I2CDriver *i2cp);
void i2c_lld_stop(I2CDriver *i2cp);
-void i2c_lld_master_transmit(I2CDriver *i2cp, uint16_t slave_addr,
+void i2c_lld_master_transmit(I2CDriver *i2cp, uint8_t slave_addr,
uint8_t *txbuf, size_t txbytes, uint8_t *rxbuf, size_t rxbytes);
-void i2c_lld_master_receive(I2CDriver *i2cp, uint16_t slave_addr,
+void i2c_lld_master_receive(I2CDriver *i2cp, uint8_t slave_addr,
uint8_t *rxbuf, size_t rxbytes);
-void i2c_lld_master_transceive(I2CDriver *i2cp);
#ifdef __cplusplus
}
diff --git a/os/hal/platforms/STM32/icu_lld.c b/os/hal/platforms/STM32/icu_lld.c
index 054ce1e3d..dfbcee5e6 100644
--- a/os/hal/platforms/STM32/icu_lld.c
+++ b/os/hal/platforms/STM32/icu_lld.c
@@ -239,37 +239,37 @@ void icu_lld_init(void) {
#if STM32_ICU_USE_TIM1
/* Driver initialization.*/
icuObjectInit(&ICUD1);
- ICUD1.tim = TIM1;
+ ICUD1.tim = STM32_TIM1;
#endif
#if STM32_ICU_USE_TIM2
/* Driver initialization.*/
icuObjectInit(&ICUD2);
- ICUD2.tim = TIM2;
+ ICUD2.tim = STM32_TIM2;
#endif
#if STM32_ICU_USE_TIM3
/* Driver initialization.*/
icuObjectInit(&ICUD3);
- ICUD3.tim = TIM3;
+ ICUD3.tim = STM32_TIM3;
#endif
#if STM32_ICU_USE_TIM4
/* Driver initialization.*/
icuObjectInit(&ICUD4);
- ICUD4.tim = TIM4;
+ ICUD4.tim = STM32_TIM4;
#endif
#if STM32_ICU_USE_TIM5
/* Driver initialization.*/
icuObjectInit(&ICUD5);
- ICUD5.tim = TIM5;
+ ICUD5.tim = STM32_TIM5;
#endif
#if STM32_ICU_USE_TIM8
/* Driver initialization.*/
icuObjectInit(&ICUD8);
- ICUD5.tim = TIM8;
+ ICUD5.tim = STM32_TIM8;
#endif
}
@@ -281,92 +281,86 @@ void icu_lld_init(void) {
* @notapi
*/
void icu_lld_start(ICUDriver *icup) {
- uint32_t clock, psc;
+ uint32_t psc;
if (icup->state == ICU_STOP) {
/* Clock activation and timer reset.*/
#if STM32_ICU_USE_TIM1
if (&ICUD1 == icup) {
- RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
- RCC->APB2RSTR = RCC_APB2RSTR_TIM1RST;
- RCC->APB2RSTR = 0;
+ rccEnableTIM1(FALSE);
+ rccResetTIM1();
NVICEnableVector(TIM1_CC_IRQn,
CORTEX_PRIORITY_MASK(STM32_ICU_TIM1_IRQ_PRIORITY));
- clock = STM32_TIMCLK2;
+ icup->clock = STM32_TIMCLK2;
}
#endif
#if STM32_ICU_USE_TIM2
if (&ICUD2 == icup) {
- RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
- RCC->APB1RSTR = RCC_APB1RSTR_TIM2RST;
- RCC->APB1RSTR = 0;
+ rccEnableTIM2(FALSE);
+ rccResetTIM2();
NVICEnableVector(TIM2_IRQn,
CORTEX_PRIORITY_MASK(STM32_ICU_TIM2_IRQ_PRIORITY));
- clock = STM32_TIMCLK1;
+ icup->clock = STM32_TIMCLK1;
}
#endif
#if STM32_ICU_USE_TIM3
if (&ICUD3 == icup) {
- RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
- RCC->APB1RSTR = RCC_APB1RSTR_TIM3RST;
- RCC->APB1RSTR = 0;
+ rccEnableTIM3(FALSE);
+ rccResetTIM3();
NVICEnableVector(TIM3_IRQn,
CORTEX_PRIORITY_MASK(STM32_ICU_TIM3_IRQ_PRIORITY));
- clock = STM32_TIMCLK1;
+ icup->clock = STM32_TIMCLK1;
}
#endif
#if STM32_ICU_USE_TIM4
if (&ICUD4 == icup) {
- RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
- RCC->APB1RSTR = RCC_APB1RSTR_TIM4RST;
- RCC->APB1RSTR = 0;
+ rccEnableTIM4(FALSE);
+ rccResetTIM4();
NVICEnableVector(TIM4_IRQn,
CORTEX_PRIORITY_MASK(STM32_ICU_TIM4_IRQ_PRIORITY));
- clock = STM32_TIMCLK1;
+ icup->clock = STM32_TIMCLK1;
}
#endif
#if STM32_ICU_USE_TIM5
if (&ICUD5 == icup) {
- RCC->APB1ENR |= RCC_APB1ENR_TIM5EN;
- RCC->APB1RSTR = RCC_APB1RSTR_TIM5RST;
- RCC->APB1RSTR = 0;
+ rccEnableTIM5(FALSE);
+ rccResetTIM5();
NVICEnableVector(TIM5_IRQn,
CORTEX_PRIORITY_MASK(STM32_ICU_TIM5_IRQ_PRIORITY));
- clock = STM32_TIMCLK1;
+ icup->clock = STM32_TIMCLK1;
}
#endif
#if STM32_ICU_USE_TIM8
if (&ICUD8 == icup) {
- RCC->APB2ENR |= RCC_APB2ENR_TIM8EN;
- RCC->APB2RSTR = RCC_APB2RSTR_TIM8RST;
- RCC->APB2RSTR = 0;
+ rccEnableTIM5(FALSE);
+ rccResetTIM5();
NVICEnableVector(TIM8_CC_IRQn,
CORTEX_PRIORITY_MASK(STM32_ICU_TIM8_IRQ_PRIORITY));
- clock = STM32_TIMCLK2;
+ icup->clock = STM32_TIMCLK2;
}
#endif
}
else {
/* Driver re-configuration scenario, it must be stopped first.*/
- icup->tim->CR1 = 0; /* Timer disabled. */
- icup->tim->DIER = 0; /* All IRQs disabled. */
- icup->tim->SR = 0; /* Clear eventual pending IRQs. */
- icup->tim->CCR1 = 0; /* Comparator 1 disabled. */
- icup->tim->CCR2 = 0; /* Comparator 2 disabled. */
- icup->tim->CNT = 0; /* Counter reset to zero. */
+ icup->tim->CR1 = 0; /* Timer disabled. */
+ icup->tim->DIER = 0; /* All IRQs disabled. */
+ icup->tim->SR = 0; /* Clear eventual pending IRQs. */
+ icup->tim->CCR[0] = 0; /* Comparator 1 disabled. */
+ icup->tim->CCR[1] = 0; /* Comparator 2 disabled. */
+ icup->tim->CNT = 0; /* Counter reset to zero. */
}
/* Timer configuration.*/
- psc = (clock / icup->config->frequency) - 1;
+ psc = (icup->clock / icup->config->frequency) - 1;
chDbgAssert((psc <= 0xFFFF) &&
- ((psc + 1) * icup->config->frequency) == clock,
+ ((psc + 1) * icup->config->frequency) == icup->clock,
"icu_lld_start(), #1", "invalid frequency");
icup->tim->PSC = (uint16_t)psc;
icup->tim->ARR = 0xFFFF;
/* CCMR1_CC1S = 01 = CH1 Input on TI1.
- CCMR1_CC2S = 10 = CH2 Input on TI2.*/
+ CCMR1_CC2S = 10 = CH2 Input on TI1.*/
icup->tim->CCMR1 = TIM_CCMR1_CC1S_0 |
TIM_CCMR1_CC2S_1;
/* SMCR_TS = 101, input is TI1FP1.
@@ -402,38 +396,38 @@ void icu_lld_stop(ICUDriver *icup) {
#if STM32_ICU_USE_TIM1
if (&ICUD1 == icup) {
NVICDisableVector(TIM1_CC_IRQn);
- RCC->APB2ENR &= ~RCC_APB2ENR_TIM1EN;
+ rccDisableTIM1(FALSE);
}
#endif
#if STM32_ICU_USE_TIM2
if (&ICUD2 == icup) {
NVICDisableVector(TIM2_IRQn);
- RCC->APB1ENR &= ~RCC_APB1ENR_TIM2EN;
+ rccDisableTIM2(FALSE);
}
#endif
#if STM32_ICU_USE_TIM3
if (&ICUD3 == icup) {
NVICDisableVector(TIM3_IRQn);
- RCC->APB1ENR &= ~RCC_APB1ENR_TIM3EN;
+ rccDisableTIM3(FALSE);
}
#endif
#if STM32_ICU_USE_TIM4
if (&ICUD4 == icup) {
NVICDisableVector(TIM4_IRQn);
- RCC->APB1ENR &= ~RCC_APB1ENR_TIM4EN;
+ rccDisableTIM4(FALSE);
}
#endif
#if STM32_ICU_USE_TIM5
if (&ICUD5 == icup) {
NVICDisableVector(TIM5_IRQn);
- RCC->APB1ENR &= ~RCC_APB1ENR_TIM5EN;
+ rccDisableTIM5(FALSE);
}
#endif
}
#if STM32_ICU_USE_TIM8
if (&ICUD8 == icup) {
NVICDisableVector(TIM8_CC_IRQn);
- RCC->APB2ENR &= ~RCC_APB2ENR_TIM8EN;
+ rccDisableTIM8(FALSE);
}
#endif
}
diff --git a/os/hal/platforms/STM32/icu_lld.h b/os/hal/platforms/STM32/icu_lld.h
index e7321e794..f5b6bf695 100644
--- a/os/hal/platforms/STM32/icu_lld.h
+++ b/os/hal/platforms/STM32/icu_lld.h
@@ -40,6 +40,10 @@
/*===========================================================================*/
/**
+ * @name Configuration options
+ * @{
+ */
+/**
* @brief ICUD1 driver enable switch.
* @details If set to @p TRUE the support for ICUD1 is included.
* @note The default is @p TRUE.
@@ -134,6 +138,7 @@
#if !defined(STM32_ICU_TIM8_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_ICU_TIM8_IRQ_PRIORITY 7
#endif
+/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
@@ -234,9 +239,13 @@ struct ICUDriver {
#endif
/* End of the mandatory fields.*/
/**
+ * @brief Timer base clock.
+ */
+ uint32_t clock;
+ /**
* @brief Pointer to the TIMx registers block.
*/
- TIM_TypeDef *tim;
+ stm32_tim_t *tim;
};
/*===========================================================================*/
@@ -253,7 +262,7 @@ struct ICUDriver {
*
* @notapi
*/
-#define icu_lld_get_width(icup) ((icup)->tim->CCR2 + 1)
+#define icu_lld_get_width(icup) ((icup)->tim->CCR[1] + 1)
/**
* @brief Returns the width of the latest cycle.
@@ -265,7 +274,7 @@ struct ICUDriver {
*
* @notapi
*/
-#define icu_lld_get_period(icup) ((icup)->tim->CCR1 + 1)
+#define icu_lld_get_period(icup) ((icup)->tim->CCR[0] + 1)
/*===========================================================================*/
/* External declarations. */
diff --git a/os/hal/platforms/STM32/mac_lld.c b/os/hal/platforms/STM32/mac_lld.c
new file mode 100644
index 000000000..99fba21ff
--- /dev/null
+++ b/os/hal/platforms/STM32/mac_lld.c
@@ -0,0 +1,358 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file STM32/mac_lld.c
+ * @brief STM32 low level MAC driver code.
+ *
+ * @addtogroup MAC
+ * @{
+ */
+
+#include "ch.h"
+#include "hal.h"
+#include "mii.h"
+
+#if HAL_USE_MAC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define BUFFER_SLICE ((((MAC_BUFFERS_SIZE - 1) | 3) + 1) / 4)
+
+/* MII divider optimal value.*/
+#if (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. */
+/*===========================================================================*/
+
+static uint32_t phyaddr;
+
+static stm32_eth_rx_descriptor_t *rxptr;
+static stm32_eth_tx_descriptor_t *txptr;
+
+static stm32_eth_rx_descriptor_t rd[MAC_RECEIVE_BUFFERS];
+static stm32_eth_tx_descriptor_t td[MAC_TRANSMIT_BUFFERS];
+
+static uint32_t rb[MAC_RECEIVE_BUFFERS * BUFFER_SLICE];
+static uint32_t tb[MAC_TRANSMIT_BUFFERS * BUFFER_SLICE];
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Writes a PHY register.
+ *
+ * @param[in] reg register number
+ * @param[in] value new register value
+ */
+static void mii_write_phy(uint32_t reg, uint32_t value) {
+
+ ETH->MACMIIDR = value;
+ ETH->MACMIIAR = 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] reg register number
+ */
+static uint32_t mii_read_phy(uint32_t reg) {
+
+ ETH->MACMIIAR = phyaddr | (reg << 6) | MACMIIDR_CR |
+ ETH_MACMIIAR_MB;
+ while ((ETH->MACMIIAR & ETH_MACMIIAR_MB) != 0)
+ ;
+ return ETH->MACMIIDR;
+}
+
+
+/**
+ * @brief PHY address detection.
+ */
+static void mii_find_phy(void) {
+ uint32_t i;
+
+ for (i = 0; i < 31; i++) {
+ ETH->MACMIIDR = (i << 6) | MACMIIDR_CR;
+ if ((mii_read_phy(MII_PHYSID1) == (BOARD_PHY_ID >> 16)) &&
+ (mii_read_phy(MII_PHYSID2) == (BOARD_PHY_ID & 0xFFF0))) {
+ phyaddr = i << 11;
+ return;
+ }
+ }
+ /* Wrong or defective board.*/
+ chSysHalt();
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level MAC initialization.
+ *
+ * @notapi
+ */
+void mac_lld_init(void) {
+ unsigned i;
+
+ macObjectInit(&ETHD1);
+
+ /* Descriptor tables are initialized in linked mode, note that the first
+ word is not initialized here but in mac_lld_start().*/
+ for (i = 0; i < MAC_RECEIVE_BUFFERS; i++) {
+ rd[i].rdes1 = STM32_RDES1_RCH | MAC_BUFFERS_SIZE;
+ rd[i].rdes2 = (uint32_t)&rb[i * BUFFER_SLICE];
+ rd[i].rdes3 = (uint32_t)&rb[((i + 1) % MAC_RECEIVE_BUFFERS) *
+ BUFFER_SLICE];
+ }
+ for (i = 0; i < MAC_TRANSMIT_BUFFERS; i++) {
+ td[i].tdes1 = 0;
+ td[i].tdes2 = (uint32_t)&tb[i * BUFFER_SLICE];
+ td[i].tdes3 = (uint32_t)&tb[((i + 1) % MAC_TRANSMIT_BUFFERS) *
+ BUFFER_SLICE];
+ }
+
+ /* MAC clocks activation.*/
+ rccEnableETH(FALSE);
+
+ /* Reset of the MAC core.*/
+ rccResetETH();
+
+ /* Find PHY address.*/
+ mii_find_phy();
+
+#if defined(BOARD_PHY_RESET)
+ /* PHY board-specific reset procedure.*/
+ BOARD_PHY_RESET();
+#else
+ /* PHY soft reset procedure.*/
+ mii_write_phy(MII_BMCR, BMCR_RESET);
+ while (mii_read_phy(MII_BMCR) & BMCR_RESET)
+ ;
+#endif
+
+ /* PHY in power down mode until the driver will be started.*/
+ mii_write_phy(MII_BMCR, BMCR_PDOWN);
+
+ /* 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 < MAC_RECEIVE_BUFFERS; i++)
+ rd[i].rdes0 = STM32_RDES0_OWN;
+ rxptr = (stm32_eth_rx_descriptor_t *)rd;
+ for (i = 0; i < MAC_TRANSMIT_BUFFERS; i++)
+ td[i].tdes0 = STM32_TDES0_TCH;
+ txptr = (stm32_eth_tx_descriptor_t *)td;
+
+ /* MAC clocks activation.*/
+ rccEnableETH(FALSE);
+
+ /* Descriptor chains pointers.*/
+ ETH->DMARDLAR = (uint32_t)rd;
+ ETH->DMATDLAR = (uint32_t)rd;
+
+ /* MAC configuration:
+ ETH_MACCR_TE - Transmitter enable.
+ ETH_MACCR_RE - Receiver enable.
+ Note that the complete setup of the MAC is performed when the link
+ status is detected.*/
+ ETH->MACCR = ETH_MACCR_TE | ETH_MACCR_TE;
+
+ ETH->MACFFR = 0;
+ ETH->MACHTHR = 0;
+ ETH->MACHTLR = 0;
+ ETH->MACHTLR = 0;
+ ETH->MACFCR = 0;
+ ETH->MACVLANTR = 0;
+}
+
+/**
+ * @brief Deactivates the MAC peripheral.
+ *
+ * @param[in] macp pointer to the @p MACDriver object
+ *
+ * @notapi
+ */
+void mac_lld_stop(MACDriver *macp) {
+
+ /* MAC clocks stopped.*/
+ rccDisableETH(FALSE);
+}
+
+/**
+ * @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 RDY_OK the descriptor has been obtained.
+ * @retval RDY_TIMEOUT descriptor not available.
+ *
+ * @notapi
+ */
+msg_t max_lld_get_transmit_descriptor(MACDriver *macp,
+ MACTransmitDescriptor *tdp) {
+
+ return RDY_OK;
+}
+
+/**
+ * @brief Writes to a transmit descriptor's stream.
+ *
+ * @param[in] tdp pointer to a @p MACTransmitDescriptor structure
+ * @param[in] buf pointer to the buffer cointaining 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) {
+
+ return 0;
+}
+
+/**
+ * @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) {
+
+}
+
+/**
+ * @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 RDY_OK the descriptor has been obtained.
+ * @retval RDY_TIMEOUT descriptor not available.
+ *
+ * @notapi
+ */
+msg_t max_lld_get_receive_descriptor(MACDriver *macp,
+ MACReceiveDescriptor *rdp) {
+
+ return RDY_TIMEOUT;
+}
+
+/**
+ * @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) {
+
+ return 0;
+}
+
+/**
+ * @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) {
+
+}
+
+/**
+ * @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_t mac_lld_poll_link_status(MACDriver *macp) {
+
+}
+
+#endif /* HAL_USE_MAC */
+
+/** @} */
diff --git a/os/hal/platforms/STM32/mac_lld.h b/os/hal/platforms/STM32/mac_lld.h
new file mode 100644
index 000000000..d6eb4bfc4
--- /dev/null
+++ b/os/hal/platforms/STM32/mac_lld.h
@@ -0,0 +1,280 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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. */
+/*===========================================================================*/
+
+/**
+ * @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_CIC_MASK 0x00C00000
+#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(MAC_TRANSMIT_BUFFERS) || defined(__DOXYGEN__)
+#define MAC_TRANSMIT_BUFFERS 2
+#endif
+
+/**
+ * @brief Number of available receive buffers.
+ */
+#if !defined(MAC_RECEIVE_BUFFERS) || defined(__DOXYGEN__)
+#define MAC_RECEIVE_BUFFERS 2
+#endif
+
+/**
+ * @brief Maximum supported frame size.
+ */
+#if !defined(MAC_BUFFERS_SIZE) || defined(__DOXYGEN__)
+#define MAC_BUFFERS_SIZE 1518
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* 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.
+ */
+ Semaphore tdsem;
+ /**
+ * @brief Receive semaphore.
+ */
+ Semaphore rdsem;
+#if MAC_USE_EVENTS || defined(__DOXYGEN__)
+ /**
+ * @brief Receive event.
+ */
+ EventSource rdevent;
+#endif
+ /* End of the mandatory fields.*/
+};
+
+/**
+ * @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.*/
+} 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.*/
+} MACReceiveDescriptor;
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if !defined(__DOXYGEN__)
+extern MACDriver ETHD1;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void mac_lld_init(void);
+ void mac_lld_start(MACDriver *macp);
+ void mac_lld_stop(MACDriver *macp);
+ msg_t max_lld_get_transmit_descriptor(MACDriver *macp,
+ MACTransmitDescriptor *tdp);
+ size_t mac_lld_write_transmit_descriptor(MACTransmitDescriptor *tdp,
+ uint8_t *buf,
+ size_t size);
+ void mac_lld_release_transmit_descriptor(MACTransmitDescriptor *tdp);
+ msg_t max_lld_get_receive_descriptor(MACDriver *macp,
+ MACReceiveDescriptor *rdp);
+ size_t mac_lld_read_receive_descriptor(MACReceiveDescriptor *rdp,
+ uint8_t *buf,
+ size_t size);
+ void mac_lld_release_receive_descriptor(MACReceiveDescriptor *rdp);
+ bool_t mac_lld_poll_link_status(MACDriver *macp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_MAC */
+
+#endif /* _MAC_LLD_H_ */
+
+/** @} */
diff --git a/os/hal/platforms/STM32/pwm_lld.c b/os/hal/platforms/STM32/pwm_lld.c
index efe215458..4392d5db9 100644
--- a/os/hal/platforms/STM32/pwm_lld.c
+++ b/os/hal/platforms/STM32/pwm_lld.c
@@ -297,37 +297,37 @@ void pwm_lld_init(void) {
#if STM32_PWM_USE_TIM1
/* Driver initialization.*/
pwmObjectInit(&PWMD1);
- PWMD1.tim = TIM1;
+ PWMD1.tim = STM32_TIM1;
#endif
#if STM32_PWM_USE_TIM2
/* Driver initialization.*/
pwmObjectInit(&PWMD2);
- PWMD2.tim = TIM2;
+ PWMD2.tim = STM32_TIM2;
#endif
#if STM32_PWM_USE_TIM3
/* Driver initialization.*/
pwmObjectInit(&PWMD3);
- PWMD3.tim = TIM3;
+ PWMD3.tim = STM32_TIM3;
#endif
#if STM32_PWM_USE_TIM4
/* Driver initialization.*/
pwmObjectInit(&PWMD4);
- PWMD4.tim = TIM4;
+ PWMD4.tim = STM32_TIM4;
#endif
#if STM32_PWM_USE_TIM5
/* Driver initialization.*/
pwmObjectInit(&PWMD5);
- PWMD5.tim = TIM5;
+ PWMD5.tim = STM32_TIM5;
#endif
#if STM32_PWM_USE_TIM8
/* Driver initialization.*/
pwmObjectInit(&PWMD8);
- PWMD5.tim = TIM8;
+ PWMD8.tim = STM32_TIM8;
#endif
}
@@ -341,74 +341,68 @@ void pwm_lld_init(void) {
* @notapi
*/
void pwm_lld_start(PWMDriver *pwmp) {
- uint32_t clock, psc;
+ uint32_t psc;
uint16_t ccer;
if (pwmp->state == PWM_STOP) {
/* Clock activation and timer reset.*/
#if STM32_PWM_USE_TIM1
if (&PWMD1 == pwmp) {
- RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
- RCC->APB2RSTR = RCC_APB2RSTR_TIM1RST;
- RCC->APB2RSTR = 0;
+ rccEnableTIM1(FALSE);
+ rccResetTIM1();
NVICEnableVector(TIM1_UP_IRQn,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM1_IRQ_PRIORITY));
NVICEnableVector(TIM1_CC_IRQn,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM1_IRQ_PRIORITY));
- clock = STM32_TIMCLK2;
+ pwmp->clock = STM32_TIMCLK2;
}
#endif
#if STM32_PWM_USE_TIM2
if (&PWMD2 == pwmp) {
- RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
- RCC->APB1RSTR = RCC_APB1RSTR_TIM2RST;
- RCC->APB1RSTR = 0;
+ rccEnableTIM2(FALSE);
+ rccResetTIM2();
NVICEnableVector(TIM2_IRQn,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM2_IRQ_PRIORITY));
- clock = STM32_TIMCLK1;
+ pwmp->clock = STM32_TIMCLK1;
}
#endif
#if STM32_PWM_USE_TIM3
if (&PWMD3 == pwmp) {
- RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
- RCC->APB1RSTR = RCC_APB1RSTR_TIM3RST;
- RCC->APB1RSTR = 0;
+ rccEnableTIM3(FALSE);
+ rccResetTIM3();
NVICEnableVector(TIM3_IRQn,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM3_IRQ_PRIORITY));
- clock = STM32_TIMCLK1;
+ pwmp->clock = STM32_TIMCLK1;
}
#endif
#if STM32_PWM_USE_TIM4
if (&PWMD4 == pwmp) {
- RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
- RCC->APB1RSTR = RCC_APB1RSTR_TIM4RST;
- RCC->APB1RSTR = 0;
+ rccEnableTIM4(FALSE);
+ rccResetTIM4();
NVICEnableVector(TIM4_IRQn,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM4_IRQ_PRIORITY));
- clock = STM32_TIMCLK1;
+ pwmp->clock = STM32_TIMCLK1;
}
#endif
#if STM32_PWM_USE_TIM5
if (&PWMD5 == pwmp) {
- RCC->APB1ENR |= RCC_APB1ENR_TIM5EN;
- RCC->APB1RSTR = RCC_APB1RSTR_TIM5RST;
- RCC->APB1RSTR = 0;
+ rccEnableTIM5(FALSE);
+ rccResetTIM5();
NVICEnableVector(TIM5_IRQn,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM5_IRQ_PRIORITY));
- clock = STM32_TIMCLK1;
+ pwmp->clock = STM32_TIMCLK1;
}
#endif
#if STM32_PWM_USE_TIM8
if (&PWMD8 == pwmp) {
- RCC->APB2ENR |= RCC_APB2ENR_TIM8EN;
- RCC->APB2RSTR = RCC_APB2RSTR_TIM8RST;
- RCC->APB2RSTR = 0;
+ rccEnableTIM8(FALSE);
+ rccResetTIM8();
NVICEnableVector(TIM8_UP_IRQn,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM8_IRQ_PRIORITY));
NVICEnableVector(TIM8_CC_IRQn,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM8_IRQ_PRIORITY));
- clock = STM32_TIMCLK2;
+ pwmp->clock = STM32_TIMCLK2;
}
#endif
@@ -425,20 +419,20 @@ void pwm_lld_start(PWMDriver *pwmp) {
}
else {
/* Driver re-configuration scenario, it must be stopped first.*/
- pwmp->tim->CR1 = 0; /* Timer disabled. */
- pwmp->tim->DIER = 0; /* All IRQs disabled. */
- pwmp->tim->SR = 0; /* Clear eventual pending IRQs. */
- pwmp->tim->CCR1 = 0; /* Comparator 1 disabled. */
- pwmp->tim->CCR2 = 0; /* Comparator 2 disabled. */
- pwmp->tim->CCR3 = 0; /* Comparator 3 disabled. */
- pwmp->tim->CCR4 = 0; /* Comparator 4 disabled. */
+ pwmp->tim->CR1 = 0; /* Timer disabled. */
+ pwmp->tim->DIER = 0; /* All IRQs disabled. */
+ pwmp->tim->SR = 0; /* Clear eventual pending IRQs. */
+ pwmp->tim->CCR[0] = 0; /* Comparator 1 disabled. */
+ pwmp->tim->CCR[1] = 0; /* Comparator 2 disabled. */
+ pwmp->tim->CCR[2] = 0; /* Comparator 3 disabled. */
+ pwmp->tim->CCR[3] = 0; /* Comparator 4 disabled. */
pwmp->tim->CNT = 0; /* Counter reset to zero. */
}
/* Timer configuration.*/
- psc = (clock / pwmp->config->frequency) - 1;
+ psc = (pwmp->clock / pwmp->config->frequency) - 1;
chDbgAssert((psc <= 0xFFFF) &&
- ((psc + 1) * pwmp->config->frequency) == clock,
+ ((psc + 1) * pwmp->config->frequency) == pwmp->clock,
"pwm_lld_start(), #1", "invalid frequency");
pwmp->tim->PSC = (uint16_t)psc;
pwmp->tim->ARR = (uint16_t)(pwmp->period - 1);
@@ -552,38 +546,38 @@ void pwm_lld_stop(PWMDriver *pwmp) {
if (&PWMD1 == pwmp) {
NVICDisableVector(TIM1_UP_IRQn);
NVICDisableVector(TIM1_CC_IRQn);
- RCC->APB2ENR &= ~RCC_APB2ENR_TIM1EN;
+ rccDisableTIM1(FALSE);
}
#endif
#if STM32_PWM_USE_TIM2
if (&PWMD2 == pwmp) {
NVICDisableVector(TIM2_IRQn);
- RCC->APB1ENR &= ~RCC_APB1ENR_TIM2EN;
+ rccDisableTIM2(FALSE);
}
#endif
#if STM32_PWM_USE_TIM3
if (&PWMD3 == pwmp) {
NVICDisableVector(TIM3_IRQn);
- RCC->APB1ENR &= ~RCC_APB1ENR_TIM3EN;
+ rccDisableTIM3(FALSE);
}
#endif
#if STM32_PWM_USE_TIM4
if (&PWMD4 == pwmp) {
NVICDisableVector(TIM4_IRQn);
- RCC->APB1ENR &= ~RCC_APB1ENR_TIM4EN;
+ rccDisableTIM4(FALSE);
}
#endif
#if STM32_PWM_USE_TIM5
if (&PWMD5 == pwmp) {
NVICDisableVector(TIM5_IRQn);
- RCC->APB1ENR &= ~RCC_APB1ENR_TIM5EN;
+ rccDisableTIM5(FALSE);
}
#endif
#if STM32_PWM_USE_TIM8
if (&PWMD8 == pwmp) {
NVICDisableVector(TIM8_UP_IRQn);
NVICDisableVector(TIM8_CC_IRQn);
- RCC->APB2ENR &= ~RCC_APB2ENR_TIM8EN;
+ rccDisableTIM8(FALSE);
}
#endif
}
@@ -605,7 +599,7 @@ void pwm_lld_enable_channel(PWMDriver *pwmp,
pwmchannel_t channel,
pwmcnt_t width) {
- *(&pwmp->tim->CCR1 + (channel * 2)) = width; /* New duty cycle. */
+ pwmp->tim->CCR[channel] = width; /* New duty cycle. */
/* If there is a callback defined for the channel then the associated
interrupt must be enabled.*/
if (pwmp->config->channels[channel].callback != NULL) {
@@ -633,7 +627,7 @@ void pwm_lld_enable_channel(PWMDriver *pwmp,
*/
void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel) {
- *(&pwmp->tim->CCR1 + (channel * 2)) = 0;
+ pwmp->tim->CCR[channel] = 0;
pwmp->tim->DIER &= ~(2 << channel);
}
diff --git a/os/hal/platforms/STM32/pwm_lld.h b/os/hal/platforms/STM32/pwm_lld.h
index fb5a83790..ca890e8f0 100644
--- a/os/hal/platforms/STM32/pwm_lld.h
+++ b/os/hal/platforms/STM32/pwm_lld.h
@@ -75,6 +75,10 @@
/*===========================================================================*/
/**
+ * @name Configuration options
+ * @{
+ */
+/**
* @brief If advanced timer features switch.
* @details If set to @p TRUE the advanced features for TIM1 and TIM8 are
* enabled.
@@ -179,6 +183,7 @@
#if !defined(STM32_PWM_TIM8_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_PWM_TIM8_IRQ_PRIORITY 7
#endif
+/** @} */
/*===========================================================================*/
/* Configuration checks. */
@@ -316,9 +321,13 @@ struct PWMDriver {
#endif
/* End of the mandatory fields.*/
/**
+ * @brief Timer base clock.
+ */
+ uint32_t clock;
+ /**
* @brief Pointer to the TIMx registers block.
*/
- TIM_TypeDef *tim;
+ stm32_tim_t *tim;
};
/*===========================================================================*/
diff --git a/os/hal/platforms/STM32/rtc_lld.c b/os/hal/platforms/STM32/rtc_lld.c
deleted file mode 100644
index 1ddbc0903..000000000
--- a/os/hal/platforms/STM32/rtc_lld.c
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
- 2011 Giovanni Di Sirio.
-
- This file is part of ChibiOS/RT.
-
- ChibiOS/RT is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- ChibiOS/RT is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file STM32/rtc_lld.c
- * @brief STM32 RTC subsystem low level driver header.
- *
- * @addtogroup RTC
- * @{
- */
-
-#include "ch.h"
-#include "hal.h"
-
-
-#if HAL_USE_RTC || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Driver exported variables. */
-/*===========================================================================*/
-
-/** @brief RTC driver identifier.*/
-RTCDriver RTCD;
-
-
-/*===========================================================================*/
-/* Driver local variables. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver local functions. */
-/*===========================================================================*/
-
-/**
- * @brief Shared IRQ handler.
- *
- * @param[in] rtcp pointer to a @p RTCDriver object
- */
-#if RTC_SUPPORTS_CALLBACKS
-
-static void rtc_lld_serve_interrupt(RTCDriver *rtcp){
- chSysLockFromIsr();
-
- if ((RTC->CRH & RTC_CRH_SECIE) && \
- (RTC->CRL & RTC_CRL_SECF) && \
- (rtcp->config->second_cb != NULL)){
- rtcp->config->second_cb(rtcp);
- RTC->CRL &= ~RTC_CRL_SECF;
- }
- if ((RTC->CRH & RTC_CRH_ALRIE) && \
- (RTC->CRL & RTC_CRL_ALRF) && \
- (rtcp->config->alarm_cb != NULL)){
- rtcp->config->alarm_cb(rtcp);
- RTC->CRL &= ~RTC_CRL_ALRF;
- }
- if ((RTC->CRH & RTC_CRH_OWIE) && \
- (RTC->CRL & RTC_CRL_OWF) && \
- (rtcp->config->overflow_cb != NULL)){
- rtcp->config->overflow_cb(rtcp);
- RTC->CRL &= ~RTC_CRL_OWF;
- }
-
- chSysUnlockFromIsr();
-}
-#endif /* RTC_SUPPORTS_CALLBACKS */
-
-/*===========================================================================*/
-/* Driver interrupt handlers. */
-/*===========================================================================*/
-
-/**
- * @brief RTC interrupt handler.
- * @isr
- */
-#if RTC_SUPPORTS_CALLBACKS
-
-CH_IRQ_HANDLER(RTC_IRQHandler) {
- CH_IRQ_PROLOGUE();
- rtc_lld_serve_interrupt(&RTCD);
- CH_IRQ_EPILOGUE();
-}
-
-#endif /* RTC_SUPPORTS_CALLBACKS */
-
-/*===========================================================================*/
-/* Driver exported functions. */
-/*===========================================================================*/
-
-/**
- * @brief Enable access to registers and initialize RTC if BKP domain
- * was previously reseted.
- */
-void rtc_lld_init(void){
- RCC->APB1ENR |= (RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN); /* enable clocking */
- PWR->CR |= PWR_CR_DBP; /* enable access */
-
- if (!(RCC->BDCR & (RCC_BDCR_RTCEN | RCC_BDCR_LSEON))){ /* BKP domain was reseted */
- RCC->BDCR |= RTC_CLOCK_SOURCE; /* select clocking from LSE */
- RCC->BDCR |= RCC_BDCR_LSEON; /* switch LSE on */
- while(!(RCC->BDCR & RCC_BDCR_LSEON)) /* wait for stabilization */
- ;
- RCC->BDCR |= RCC_BDCR_RTCEN; /* run clock */
- }
-
- #if defined(RTC_CLOCK_SOURCE) == defined(RCC_BDCR_RTCSEL_LSE)
- uint32_t preload = STM32_LSECLK - 1UL;
- #elif defined(RTC_CLOCK_SOURCE) == defined(RCC_BDCR_RTCSEL_LSI)
- uint32_t preload = STM32_LSICLK - 1UL;
- #elif defined(RTC_CLOCK_SOURCE) == defined(RCC_BDCR_RTCSEL_HSE)
- uint32_t preload = (STM32_HSICLK / 128UL) - 1UL;
- #else
- #error "RTC clock source not selected"
- #endif /* RTC_CLOCK_SOURCE == RCC_BDCR_RTCSEL_LSE */
-
- /* Write preload register only if value changed */
- if (preload != (((uint32_t)(RTC->PRLH)) << 16) + RTC->PRLH){
- while(!(RTC->CRL & RTC_CRL_RTOFF))
- ;
-
- RTC->CRL |= RTC_CRL_CNF; /* switch on configure mode */
- RTC->PRLH = (uint16_t)((preload >> 16) & 0b1111); /* write preloader */
- RTC->PRLL = (uint16_t)(preload & 0xFFFF);
- RTC->CRL &= ~RTC_CRL_CNF; /* switch off configure mode */
-
- while(!(RTC->CRL & RTC_CRL_RTOFF)) /* wait for completion */
- ;
- }
-
- /* Ensure that RTC_CNT and RTC_DIV contain actual values after enabling
- * clocking on APB1, because these values only update when APB1 functioning.*/
- RTC->CRL &= ~(RTC_CRL_RSF);
- while (!(RTC->CRL & RTC_CRL_RSF))
- ;
-
- /* disable all interrupts and clear all even flags just to be safe */
- RTC->CRH &= ~(RTC_CRH_OWIE | RTC_CRH_ALRIE | RTC_CRH_SECIE);
- RTC->CRL &= ~(RTC_CRL_SECF | RTC_CRL_ALRF | RTC_CRL_OWF);
-
- RTCD.config = NULL;
-}
-
-/**
- * @brief Configure and start interrupt servicing routines.
- * This function do nothing if callbacks disabled.
- *
- * @param[in] rtcp pointer to a @p RTCDriver object
- * @param[in] rtccfgp pointer to a @p RTCDriver config object
- */
-void rtc_lld_start(RTCDriver *rtcp, const RTCConfig *rtccfgp){
- uint16_t isr_flags = 0;
-
- NVICEnableVector(RTC_IRQn, CORTEX_PRIORITY_MASK(STM32_RTC_IRQ_PRIORITY));
-
- rtcp->config = rtccfgp;
- if (rtcp->config->overflow_cb != NULL){
- isr_flags |= RTC_CRH_OWIE;
- }
- if (rtcp->config->alarm_cb != NULL){
- isr_flags |= RTC_CRH_ALRIE;
- }
- if (rtcp->config->second_cb != NULL){
- isr_flags |= RTC_CRH_SECIE;
- }
-
- /* clear all event flags just to be safe */
- RTC->CRL &= ~(RTC_CRL_SECF | RTC_CRL_ALRF | RTC_CRL_OWF);
- RTC->CRH |= isr_flags;
-}
-
-/**
- * @brief Disable interrupt servicing routines.
- */
-void rtc_lld_stop(void){
- NVICDisableVector(RTC_IRQn);
- RTC->CRH = 0;
-}
-
-
-/**
- * @brief Set current time.
- *
- * @param[in] tv_sec time value in UNIX notation.
- */
-void rtc_lld_set_time(uint32_t tv_sec){
-
- while(!(RTC->CRL & RTC_CRL_RTOFF))
- ;
-
- RTC->CRL |= RTC_CRL_CNF; /* switch on configure mode */
- RTC->CNTH = (uint16_t)((tv_sec >> 16) & 0xFFFF); /* write time */
- RTC->CNTL = (uint16_t)(tv_sec & 0xFFFF);
- RTC->CRL &= ~RTC_CRL_CNF; /* switch off configure mode */
-
- while(!(RTC->CRL & RTC_CRL_RTOFF)) /* wait for completion */
- ;
-}
-
-/**
- * @brief Return current time in UNIX notation.
- */
-inline uint32_t rtc_lld_get_sec(void){
- return ((RTC->CNTH << 16) + RTC->CNTL);
-}
-
-/**
- * @brief Return fractional part of current time (milliseconds).
- */
-inline uint16_t rtc_lld_get_msec(void){
- uint32_t time_frac = 0;
- time_frac = (((uint32_t)RTC->DIVH) << 16) + (RTC->DIVL);
- return(((STM32_LSECLK - time_frac) * 1000) / STM32_LSECLK);
-}
-
-/**
- * @brief Set alarm date in UNIX notation.
- */
-void rtc_lld_set_alarm(uint32_t tv_alarm){
-
- while(!(RTC->CRL & RTC_CRL_RTOFF))
- ;
-
- RTC->CRL |= RTC_CRL_CNF; /* switch on configure mode */
- RTC->ALRH = (uint16_t)((tv_alarm >> 16) & 0xFFFF); /* write time */
- RTC->ALRL = (uint16_t)(tv_alarm & 0xFFFF);
- RTC->CRL &= ~RTC_CRL_CNF; /* switch off configure mode */
-
-#if !(RTC_SUPPORTS_CALLBACKS)
- RTC->CRL &= ~RTC_CRL_ALRF;
- RTC->CRH |= RTC_CRH_ALRIE;
-#endif /* !(RTC_SUPPORTS_CALLBACKS) */
-
- while(!(RTC->CRL & RTC_CRL_RTOFF)) /* wait for completion */
- ;
-}
-
-/**
- * @brief Get current alarm date in UNIX notation.
- * @note Default value after reset is 0xFFFFFFFF
- */
-inline uint32_t rtc_lld_get_alarm(void){
- return ((RTC->ALRH << 16) + RTC->ALRL);
-}
-
-
-#endif /* HAL_USE_RTC */
-
-/** @} */
diff --git a/os/hal/platforms/STM32/DMAv1/sdc_lld.c b/os/hal/platforms/STM32/sdc_lld.c
index b9e02a815..2ce3cd0fb 100644
--- a/os/hal/platforms/STM32/DMAv1/sdc_lld.c
+++ b/os/hal/platforms/STM32/sdc_lld.c
@@ -443,7 +443,7 @@ void sdc_lld_start(SDCDriver *sdcp) {
dmaStreamSetPeripheral(STM32_DMA2_STREAM4, &SDIO->FIFO);
NVICEnableVector(SDIO_IRQn,
CORTEX_PRIORITY_MASK(STM32_SDC_SDIO_IRQ_PRIORITY));
- RCC->AHBENR |= RCC_AHBENR_SDIOEN;
+ rccEnableSDIO(FALSE);
}
/* Configuration, card clock is initially stopped.*/
SDIO->POWER = 0;
@@ -470,6 +470,7 @@ void sdc_lld_stop(SDCDriver *sdcp) {
/* Clock deactivation.*/
NVICDisableVector(SDIO_IRQn);
dmaStreamRelease(STM32_DMA2_STREAM4);
+ rccDisableSDIO(FALSE);
}
}
diff --git a/os/hal/platforms/STM32/DMAv1/sdc_lld.h b/os/hal/platforms/STM32/sdc_lld.h
index eea76dadd..f670e6bbe 100644
--- a/os/hal/platforms/STM32/DMAv1/sdc_lld.h
+++ b/os/hal/platforms/STM32/sdc_lld.h
@@ -41,6 +41,10 @@
/*===========================================================================*/
/**
+ * @name Configuration options
+ * @{
+ */
+/**
* @brief SDIO data timeout in SDIO clock cycles.
*/
#if !defined(STM32_SDC_DATATIMEOUT) || defined(__DOXYGEN__)
@@ -67,6 +71,7 @@
#if !defined(STM32_SDC_UNALIGNED_SUPPORT) || defined(__DOXYGEN__)
#define STM32_SDC_UNALIGNED_SUPPORT TRUE
#endif
+/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
diff --git a/os/hal/platforms/STM32/serial_lld.c b/os/hal/platforms/STM32/serial_lld.c
index 5aaa60de9..c5dda231b 100644
--- a/os/hal/platforms/STM32/serial_lld.c
+++ b/os/hal/platforms/STM32/serial_lld.c
@@ -60,6 +60,11 @@ SerialDriver SD4;
SerialDriver SD5;
#endif
+/** @brief USART6 serial driver identifier.*/
+#if STM32_SERIAL_USE_USART6 || defined(__DOXYGEN__)
+SerialDriver SD6;
+#endif
+
/*===========================================================================*/
/* Driver local variables. */
/*===========================================================================*/
@@ -90,7 +95,11 @@ static void usart_init(SerialDriver *sdp, const SerialConfig *config) {
/*
* Baud rate setting.
*/
+#if STM32_HAS_USART6
+ if ((sdp->usart == USART1) || (sdp->usart == USART6))
+#else
if (sdp->usart == USART1)
+#endif
u->BRR = STM32_PCLK2 / config->sc_speed;
else
u->BRR = STM32_PCLK1 / config->sc_speed;
@@ -123,7 +132,7 @@ static void usart_deinit(USART_TypeDef *u) {
#if STM32_SERIAL_USE_USART1 || STM32_SERIAL_USE_USART2 || \
STM32_SERIAL_USE_USART3 || STM32_SERIAL_USE_UART4 || \
- USE_STM32_USART5
+ STM32_SERIAL_USE_UART5 || STM32_SERIAL_USE_USART6
/**
* @brief Error handling routine.
*
@@ -237,6 +246,14 @@ static void notify5(GenericQueue *qp) {
}
#endif
+#if STM32_SERIAL_USE_USART6 || defined(__DOXYGEN__)
+static void notify6(GenericQueue *qp) {
+
+ (void)qp;
+ USART6->CR1 |= USART_CR1_TXEIE;
+}
+#endif
+
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
@@ -321,6 +338,22 @@ CH_IRQ_HANDLER(UART5_IRQHandler) {
}
#endif
+#if STM32_SERIAL_USE_USART6 || defined(__DOXYGEN__)
+/**
+ * @brief USART1 interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(USART6_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ serve_interrupt(&SD6);
+
+ CH_IRQ_EPILOGUE();
+}
+#endif
+
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
@@ -356,6 +389,11 @@ void sd_lld_init(void) {
sdObjectInit(&SD5, NULL, notify5);
SD5.usart = UART5;
#endif
+
+#if STM32_SERIAL_USE_USART6
+ sdObjectInit(&SD6, NULL, notify6);
+ SD6.usart = USART6;
+#endif
}
/**
@@ -376,39 +414,46 @@ void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
if (sdp->state == SD_STOP) {
#if STM32_SERIAL_USE_USART1
if (&SD1 == sdp) {
- RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
+ rccEnableUSART1(FALSE);
NVICEnableVector(USART1_IRQn,
CORTEX_PRIORITY_MASK(STM32_SERIAL_USART1_PRIORITY));
}
#endif
#if STM32_SERIAL_USE_USART2
if (&SD2 == sdp) {
- RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
+ rccEnableUSART2(FALSE);
NVICEnableVector(USART2_IRQn,
CORTEX_PRIORITY_MASK(STM32_SERIAL_USART2_PRIORITY));
}
#endif
#if STM32_SERIAL_USE_USART3
if (&SD3 == sdp) {
- RCC->APB1ENR |= RCC_APB1ENR_USART3EN;
+ rccEnableUSART3(FALSE);
NVICEnableVector(USART3_IRQn,
CORTEX_PRIORITY_MASK(STM32_SERIAL_USART3_PRIORITY));
}
#endif
#if STM32_SERIAL_USE_UART4
if (&SD4 == sdp) {
- RCC->APB1ENR |= RCC_APB1ENR_UART4EN;
+ rccEnableUART4(FALSE);
NVICEnableVector(UART4_IRQn,
CORTEX_PRIORITY_MASK(STM32_SERIAL_UART4_PRIORITY));
}
#endif
#if STM32_SERIAL_USE_UART5
if (&SD5 == sdp) {
- RCC->APB1ENR |= RCC_APB1ENR_UART5EN;
+ rccEnableUART5(FALSE);
NVICEnableVector(UART5_IRQn,
CORTEX_PRIORITY_MASK(STM32_SERIAL_UART5_PRIORITY));
}
#endif
+#if STM32_SERIAL_USE_USART6
+ if (&SD6 == sdp) {
+ rccEnableUSART6(FALSE);
+ NVICEnableVector(USART6_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_SERIAL_USART6_PRIORITY));
+ }
+#endif
}
usart_init(sdp, config);
}
@@ -428,39 +473,46 @@ void sd_lld_stop(SerialDriver *sdp) {
usart_deinit(sdp->usart);
#if STM32_SERIAL_USE_USART1
if (&SD1 == sdp) {
- RCC->APB2ENR &= ~RCC_APB2ENR_USART1EN;
+ rccDisableUSART1(FALSE);
NVICDisableVector(USART1_IRQn);
return;
}
#endif
#if STM32_SERIAL_USE_USART2
if (&SD2 == sdp) {
- RCC->APB1ENR &= ~RCC_APB1ENR_USART2EN;
+ rccDisableUSART2(FALSE);
NVICDisableVector(USART2_IRQn);
return;
}
#endif
#if STM32_SERIAL_USE_USART3
if (&SD3 == sdp) {
- RCC->APB1ENR &= ~RCC_APB1ENR_USART3EN;
+ rccDisableUSART3(FALSE);
NVICDisableVector(USART3_IRQn);
return;
}
#endif
#if STM32_SERIAL_USE_UART4
if (&SD4 == sdp) {
- RCC->APB1ENR &= ~RCC_APB1ENR_UART4EN;
+ rccDisableUART4(FALSE);
NVICDisableVector(UART4_IRQn);
return;
}
#endif
#if STM32_SERIAL_USE_UART5
if (&SD5 == sdp) {
- RCC->APB1ENR &= ~RCC_APB1ENR_UART5EN;
+ rccDisableUART5(FALSE);
NVICDisableVector(UART5_IRQn);
return;
}
#endif
+#if STM32_SERIAL_USE_USART6
+ if (&SD6 == sdp) {
+ rccDisableUSART6(FALSE);
+ NVICDisableVector(USART6_IRQn);
+ return;
+ }
+#endif
}
}
diff --git a/os/hal/platforms/STM32/serial_lld.h b/os/hal/platforms/STM32/serial_lld.h
index ceeccff67..ccafe736a 100644
--- a/os/hal/platforms/STM32/serial_lld.h
+++ b/os/hal/platforms/STM32/serial_lld.h
@@ -40,9 +40,13 @@
/*===========================================================================*/
/**
+ * @name Configuration options
+ * @{
+ */
+/**
* @brief USART1 driver enable switch.
* @details If set to @p TRUE the support for USART1 is included.
- * @note The default is @p FALSE.
+ * @note The default is @p TRUE.
*/
#if !defined(STM32_SERIAL_USE_USART1) || defined(__DOXYGEN__)
#define STM32_SERIAL_USE_USART1 TRUE
@@ -60,7 +64,7 @@
/**
* @brief USART3 driver enable switch.
* @details If set to @p TRUE the support for USART3 is included.
- * @note The default is @p FALSE.
+ * @note The default is @p TRUE.
*/
#if !defined(STM32_SERIAL_USE_USART3) || defined(__DOXYGEN__)
#define STM32_SERIAL_USE_USART3 TRUE
@@ -69,7 +73,7 @@
/**
* @brief UART4 driver enable switch.
* @details If set to @p TRUE the support for UART4 is included.
- * @note The default is @p FALSE.
+ * @note The default is @p TRUE.
*/
#if !defined(STM32_SERIAL_USE_UART4) || defined(__DOXYGEN__)
#define STM32_SERIAL_USE_UART4 TRUE
@@ -78,13 +82,22 @@
/**
* @brief UART5 driver enable switch.
* @details If set to @p TRUE the support for UART5 is included.
- * @note The default is @p FALSE.
+ * @note The default is @p TRUE.
*/
#if !defined(STM32_SERIAL_USE_UART5) || defined(__DOXYGEN__)
#define STM32_SERIAL_USE_UART5 TRUE
#endif
/**
+ * @brief USART6 driver enable switch.
+ * @details If set to @p TRUE the support for USART6 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_SERIAL_USE_USART6) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USE_USART6 TRUE
+#endif
+
+/**
* @brief USART1 interrupt priority level setting.
*/
#if !defined(STM32_SERIAL_USART1_PRIORITY) || defined(__DOXYGEN__)
@@ -119,6 +132,14 @@
#define STM32_SERIAL_UART5_PRIORITY 12
#endif
+/**
+ * @brief USART6 interrupt priority level setting.
+ */
+#if !defined(STM32_SERIAL_USART6_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SERIAL_USART6_PRIORITY 12
+#endif
+/** @} */
+
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
@@ -143,9 +164,13 @@
#error "UART5 not present in the selected device"
#endif
+#if STM32_SERIAL_USE_USART6 && !STM32_HAS_USART6
+#error "USART6 not present in the selected device"
+#endif
+
#if !STM32_SERIAL_USE_USART1 && !STM32_SERIAL_USE_USART2 && \
!STM32_SERIAL_USE_USART3 && !STM32_SERIAL_USE_UART4 && \
- !STM32_SERIAL_USE_UART5
+ !STM32_SERIAL_USE_UART5 && !STM32_SERIAL_USE_USART6
#error "SERIAL driver activated but no USART/UART peripheral assigned"
#endif
@@ -230,6 +255,9 @@ extern SerialDriver SD4;
#if STM32_SERIAL_USE_UART5 && !defined(__DOXYGEN__)
extern SerialDriver SD5;
#endif
+#if STM32_SERIAL_USE_USART6 && !defined(__DOXYGEN__)
+extern SerialDriver SD6;
+#endif
#ifdef __cplusplus
extern "C" {
diff --git a/os/hal/platforms/STM32/DMAv1/spi_lld.c b/os/hal/platforms/STM32/spi_lld.c
index 9302b0102..34a892d48 100644
--- a/os/hal/platforms/STM32/DMAv1/spi_lld.c
+++ b/os/hal/platforms/STM32/spi_lld.c
@@ -32,6 +32,34 @@
#if HAL_USE_SPI || defined(__DOXYGEN__)
/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define SPI1_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI1_RX_DMA_STREAM, \
+ STM32_SPI1_RX_DMA_CHN)
+
+#define SPI1_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI1_TX_DMA_STREAM, \
+ STM32_SPI1_TX_DMA_CHN)
+
+#define SPI2_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI2_RX_DMA_STREAM, \
+ STM32_SPI2_RX_DMA_CHN)
+
+#define SPI2_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI2_TX_DMA_STREAM, \
+ STM32_SPI2_TX_DMA_CHN)
+
+#define SPI3_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI3_RX_DMA_STREAM, \
+ STM32_SPI3_RX_DMA_CHN)
+
+#define SPI3_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_SPI_SPI3_TX_DMA_STREAM, \
+ STM32_SPI3_TX_DMA_CHN)
+
+/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
@@ -62,26 +90,6 @@ static uint16_t dummyrx;
/*===========================================================================*/
/**
- * @brief Stops the SPI DMA channels.
- *
- * @param[in] spip pointer to the @p SPIDriver object
- */
-#define dma_stop(spip) { \
- dmaStreamDisable(spip->dmatx); \
- dmaStreamDisable(spip->dmarx); \
-}
-
-/**
- * @brief Starts the SPI DMA channels.
- *
- * @param[in] spip pointer to the @p SPIDriver object
- */
-#define dma_start(spip) { \
- dmaChannelEnable((spip)->dmarx); \
- dmaChannelEnable((spip)->dmatx); \
-}
-
-/**
* @brief Shared end-of-rx service routine.
*
* @param[in] spip pointer to the @p SPIDriver object
@@ -91,15 +99,18 @@ static void spi_lld_serve_rx_interrupt(SPIDriver *spip, uint32_t flags) {
/* DMA errors handling.*/
#if defined(STM32_SPI_DMA_ERROR_HOOK)
- if ((flags & STM32_DMA_ISR_TEIF) != 0) {
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
STM32_SPI_DMA_ERROR_HOOK(spip);
}
#else
(void)flags;
#endif
- /* Stop everything.*/
- dma_stop(spip);
+ /* Stop everything. The status of the TX DMA is cleared here because its
+ handler is only invoked in case of error.*/
+ dmaStreamDisable(spip->dmatx);
+ dmaStreamDisable(spip->dmarx);
+ dmaStreamClearInterrupt(spip->dmatx);
/* Portable SPI ISR code defined in the high level driver, note, it is
a macro.*/
@@ -145,26 +156,56 @@ void spi_lld_init(void) {
#if STM32_SPI_USE_SPI1
spiObjectInit(&SPID1);
- SPID1.thread = NULL;
- SPID1.spi = SPI1;
- SPID1.dmarx = STM32_DMA1_STREAM2;
- SPID1.dmatx = STM32_DMA1_STREAM3;
+ SPID1.spi = SPI1;
+ SPID1.dmarx = STM32_DMA_STREAM(STM32_SPI_SPI1_RX_DMA_STREAM);
+ SPID1.dmatx = STM32_DMA_STREAM(STM32_SPI_SPI1_TX_DMA_STREAM);
+ SPID1.rxdmamode = STM32_DMA_CR_CHSEL(SPI1_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ SPID1.txdmamode = STM32_DMA_CR_CHSEL(SPI1_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
#endif
#if STM32_SPI_USE_SPI2
spiObjectInit(&SPID2);
- SPID2.thread = NULL;
- SPID2.spi = SPI2;
- SPID2.dmarx = STM32_DMA1_STREAM4;
- SPID2.dmatx = STM32_DMA1_STREAM5;
+ SPID2.spi = SPI2;
+ SPID2.dmarx = STM32_DMA_STREAM(STM32_SPI_SPI2_RX_DMA_STREAM);
+ SPID2.dmatx = STM32_DMA_STREAM(STM32_SPI_SPI2_TX_DMA_STREAM);
+ SPID2.rxdmamode = STM32_DMA_CR_CHSEL(SPI2_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI2_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ SPID2.txdmamode = STM32_DMA_CR_CHSEL(SPI2_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI2_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
#endif
#if STM32_SPI_USE_SPI3
spiObjectInit(&SPID3);
- SPID3.thread = NULL;
- SPID3.spi = SPI3;
- SPID3.dmarx = STM32_DMA2_STREAM1;
- SPID3.dmatx = STM32_DMA2_STREAM2;
+ SPID3.spi = SPI3;
+ SPID3.dmarx = STM32_DMA_STREAM(STM32_SPI_SPI3_RX_DMA_STREAM);
+ SPID3.dmatx = STM32_DMA_STREAM(STM32_SPI_SPI3_TX_DMA_STREAM);
+ SPID3.rxdmamode = STM32_DMA_CR_CHSEL(SPI3_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI3_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_P2M |
+ STM32_DMA_CR_TCIE |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
+ SPID3.txdmamode = STM32_DMA_CR_CHSEL(SPI3_TX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_SPI_SPI3_DMA_PRIORITY) |
+ STM32_DMA_CR_DIR_M2P |
+ STM32_DMA_CR_DMEIE |
+ STM32_DMA_CR_TEIE;
#endif
}
@@ -182,49 +223,49 @@ void spi_lld_start(SPIDriver *spip) {
#if STM32_SPI_USE_SPI1
if (&SPID1 == spip) {
bool_t b;
- b = dmaStreamAllocate(STM32_DMA1_STREAM2,
+ b = dmaStreamAllocate(spip->dmarx,
STM32_SPI_SPI1_IRQ_PRIORITY,
(stm32_dmaisr_t)spi_lld_serve_rx_interrupt,
(void *)spip);
chDbgAssert(!b, "spi_lld_start(), #1", "stream already allocated");
- b = dmaStreamAllocate(STM32_DMA1_STREAM3,
+ b = dmaStreamAllocate(spip->dmatx,
STM32_SPI_SPI1_IRQ_PRIORITY,
(stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
(void *)spip);
chDbgAssert(!b, "spi_lld_start(), #2", "stream already allocated");
- RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
+ rccEnableSPI1(FALSE);
}
#endif
#if STM32_SPI_USE_SPI2
if (&SPID2 == spip) {
bool_t b;
- b = dmaStreamAllocate(STM32_DMA1_STREAM4,
+ b = dmaStreamAllocate(spip->dmarx,
STM32_SPI_SPI2_IRQ_PRIORITY,
(stm32_dmaisr_t)spi_lld_serve_rx_interrupt,
(void *)spip);
chDbgAssert(!b, "spi_lld_start(), #3", "stream already allocated");
- b = dmaStreamAllocate(STM32_DMA1_STREAM5,
+ b = dmaStreamAllocate(spip->dmatx,
STM32_SPI_SPI2_IRQ_PRIORITY,
(stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
(void *)spip);
chDbgAssert(!b, "spi_lld_start(), #4", "stream already allocated");
- RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;
+ rccEnableSPI2(FALSE);
}
#endif
#if STM32_SPI_USE_SPI3
if (&SPID3 == spip) {
bool_t b;
- b = dmaStreamAllocate(STM32_DMA1_STREAM1,
+ b = dmaStreamAllocate(spip->dmarx,
STM32_SPI_SPI3_IRQ_PRIORITY,
(stm32_dmaisr_t)spi_lld_serve_rx_interrupt,
(void *)spip);
chDbgAssert(!b, "spi_lld_start(), #5", "stream already allocated");
- b = dmaStreamAllocate(STM32_DMA1_STREAM2,
+ b = dmaStreamAllocate(spip->dmatx,
STM32_SPI_SPI3_IRQ_PRIORITY,
(stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
(void *)spip);
chDbgAssert(!b, "spi_lld_start(), #6", "stream already allocated");
- RCC->APB1ENR |= RCC_APB1ENR_SPI3EN;
+ rccEnableSPI3(FALSE);
}
#endif
@@ -233,18 +274,19 @@ void spi_lld_start(SPIDriver *spip) {
dmaStreamSetPeripheral(spip->dmatx, &spip->spi->DR);
}
- /* More DMA setup.*/
- if ((spip->config->cr1 & SPI_CR1_DFF) == 0)
- spip->dmamode = STM32_DMA_CR_PL(STM32_SPI_SPI2_DMA_PRIORITY) |
- STM32_DMA_CR_TEIE |
- STM32_DMA_CR_PSIZE_BYTE |
- STM32_DMA_CR_MSIZE_BYTE; /* 8 bits transfers. */
- else
- spip->dmamode = STM32_DMA_CR_PL(STM32_SPI_SPI2_DMA_PRIORITY) |
- STM32_DMA_CR_TEIE |
- STM32_DMA_CR_PSIZE_HWORD |
- STM32_DMA_CR_MSIZE_HWORD; /* 16 bits transfers. */
-
+ /* Configuration-specific DMA setup.*/
+ if ((spip->config->cr1 & SPI_CR1_DFF) == 0) { /* 8 bits transfers. */
+ spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) |
+ STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE;
+ spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) |
+ STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE;
+ }
+ else { /* 16 bits transfers. */
+ spip->rxdmamode = (spip->rxdmamode & ~STM32_DMA_CR_SIZE_MASK) |
+ STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
+ spip->txdmamode = (spip->txdmamode & ~STM32_DMA_CR_SIZE_MASK) |
+ STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
+ }
/* SPI setup and enable.*/
spip->spi->CR1 = 0;
spip->spi->CR1 = spip->config->cr1 | SPI_CR1_MSTR | SPI_CR1_SSM |
@@ -267,27 +309,20 @@ void spi_lld_stop(SPIDriver *spip) {
/* SPI disable.*/
spip->spi->CR1 = 0;
+ dmaStreamRelease(spip->dmarx);
+ dmaStreamRelease(spip->dmatx);
#if STM32_SPI_USE_SPI1
- if (&SPID1 == spip) {
- dmaStreamRelease(STM32_DMA1_STREAM2);
- dmaStreamRelease(STM32_DMA1_STREAM3);
- RCC->APB2ENR &= ~RCC_APB2ENR_SPI1EN;
- }
+ if (&SPID1 == spip)
+ rccDisableSPI1(FALSE);
#endif
#if STM32_SPI_USE_SPI2
- if (&SPID2 == spip) {
- dmaStreamRelease(STM32_DMA1_STREAM4);
- dmaStreamRelease(STM32_DMA1_STREAM5);
- RCC->APB1ENR &= ~RCC_APB1ENR_SPI2EN;
- }
+ if (&SPID2 == spip)
+ rccDisableSPI2(FALSE);
#endif
#if STM32_SPI_USE_SPI3
- if (&SPID3 == spip) {
- dmaStreamRelease(STM32_DMA1_STREAM1);
- dmaStreamRelease(STM32_DMA1_STREAM2);
- RCC->APB1ENR &= ~RCC_APB1ENR_SPI3EN;
- }
+ if (&SPID3 == spip)
+ rccDisableSPI3(FALSE);
#endif
}
}
@@ -332,12 +367,11 @@ void spi_lld_ignore(SPIDriver *spip, size_t n) {
dmaStreamSetMemory0(spip->dmarx, &dummyrx);
dmaStreamSetTransactionSize(spip->dmarx, n);
- dmaStreamSetMode(spip->dmarx, spip->dmamode | STM32_DMA_CR_DIR_P2M |
- STM32_DMA_CR_TCIE | STM32_DMA_CR_EN);
+ dmaStreamSetMode(spip->dmarx, spip->rxdmamode | STM32_DMA_CR_EN);
+
dmaStreamSetMemory0(spip->dmatx, &dummytx);
dmaStreamSetTransactionSize(spip->dmatx, n);
- dmaStreamSetMode(spip->dmatx, spip->dmamode | STM32_DMA_CR_DIR_M2P |
- STM32_DMA_CR_EN);
+ dmaStreamSetMode(spip->dmatx, spip->txdmamode | STM32_DMA_CR_EN);
}
/**
@@ -360,13 +394,12 @@ void spi_lld_exchange(SPIDriver *spip, size_t n,
dmaStreamSetMemory0(spip->dmarx, rxbuf);
dmaStreamSetTransactionSize(spip->dmarx, n);
- dmaStreamSetMode(spip->dmarx, spip->dmamode | STM32_DMA_CR_DIR_P2M |
- STM32_DMA_CR_TCIE | STM32_DMA_CR_MINC |
- STM32_DMA_CR_EN);
+ dmaStreamSetMode(spip->dmarx, spip->rxdmamode| STM32_DMA_CR_MINC |
+ STM32_DMA_CR_EN);
dmaStreamSetMemory0(spip->dmatx, txbuf);
dmaStreamSetTransactionSize(spip->dmatx, n);
- dmaStreamSetMode(spip->dmatx, spip->dmamode | STM32_DMA_CR_DIR_M2P |
- STM32_DMA_CR_MINC | STM32_DMA_CR_EN);
+ dmaStreamSetMode(spip->dmatx, spip->txdmamode | STM32_DMA_CR_MINC |
+ STM32_DMA_CR_EN);
}
/**
@@ -386,12 +419,12 @@ void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
dmaStreamSetMemory0(spip->dmarx, &dummyrx);
dmaStreamSetTransactionSize(spip->dmarx, n);
- dmaStreamSetMode(spip->dmarx, spip->dmamode | STM32_DMA_CR_DIR_P2M |
- STM32_DMA_CR_TCIE | STM32_DMA_CR_EN);
+ dmaStreamSetMode(spip->dmarx, spip->rxdmamode | STM32_DMA_CR_EN);
+
dmaStreamSetMemory0(spip->dmatx, txbuf);
dmaStreamSetTransactionSize(spip->dmatx, n);
- dmaStreamSetMode(spip->dmatx, spip->dmamode | STM32_DMA_CR_DIR_M2P |
- STM32_DMA_CR_MINC | STM32_DMA_CR_EN);
+ dmaStreamSetMode(spip->dmatx, spip->txdmamode | STM32_DMA_CR_MINC |
+ STM32_DMA_CR_EN);
}
/**
@@ -411,13 +444,11 @@ void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
dmaStreamSetMemory0(spip->dmarx, rxbuf);
dmaStreamSetTransactionSize(spip->dmarx, n);
- dmaStreamSetMode(spip->dmarx, spip->dmamode | STM32_DMA_CR_DIR_P2M |
- STM32_DMA_CR_TCIE | STM32_DMA_CR_MINC |
- STM32_DMA_CR_EN);
+ dmaStreamSetMode(spip->dmarx, spip->rxdmamode | STM32_DMA_CR_MINC |
+ STM32_DMA_CR_EN);
dmaStreamSetMemory0(spip->dmatx, &dummytx);
dmaStreamSetTransactionSize(spip->dmatx, n);
- dmaStreamSetMode(spip->dmatx, spip->dmamode | STM32_DMA_CR_DIR_M2P |
- STM32_DMA_CR_EN);
+ dmaStreamSetMode(spip->dmatx, spip->txdmamode | STM32_DMA_CR_EN);
}
/**
diff --git a/os/hal/platforms/STM32/DMAv1/spi_lld.h b/os/hal/platforms/STM32/spi_lld.h
index c8c1e0661..ee2586ea1 100644
--- a/os/hal/platforms/STM32/DMAv1/spi_lld.h
+++ b/os/hal/platforms/STM32/spi_lld.h
@@ -40,6 +40,10 @@
/*===========================================================================*/
/**
+ * @name Configuration options
+ * @{
+ */
+/**
* @brief SPI1 driver enable switch.
* @details If set to @p TRUE the support for SPI1 is included.
* @note The default is @p TRUE.
@@ -67,10 +71,31 @@
#endif
/**
+ * @brief SPI1 interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI1_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief SPI2 interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI2_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief SPI3 interrupt priority level setting.
+ */
+#if !defined(STM32_SPI_SPI3_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI3_IRQ_PRIORITY 10
+#endif
+
+/**
* @brief SPI1 DMA priority (0..3|lowest..highest).
- * @note The priority level is used for both the TX and RX DMA channels but
- * because of the channels ordering the RX channel has always priority
- * over the TX channel.
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
*/
#if !defined(STM32_SPI_SPI1_DMA_PRIORITY) || defined(__DOXYGEN__)
#define STM32_SPI_SPI1_DMA_PRIORITY 1
@@ -78,9 +103,9 @@
/**
* @brief SPI2 DMA priority (0..3|lowest..highest).
- * @note The priority level is used for both the TX and RX DMA channels but
- * because of the channels ordering the RX channel has always priority
- * over the TX channel.
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
*/
#if !defined(STM32_SPI_SPI2_DMA_PRIORITY) || defined(__DOXYGEN__)
#define STM32_SPI_SPI2_DMA_PRIORITY 1
@@ -88,44 +113,85 @@
/**
* @brief SPI3 DMA priority (0..3|lowest..highest).
- * @note The priority level is used for both the TX and RX DMA channels but
- * because of the channels ordering the RX channel has always priority
- * over the TX channel.
+ * @note The priority level is used for both the TX and RX DMA streams but
+ * because of the streams ordering the RX stream has always priority
+ * over the TX stream.
*/
#if !defined(STM32_SPI_SPI3_DMA_PRIORITY) || defined(__DOXYGEN__)
#define STM32_SPI_SPI3_DMA_PRIORITY 1
#endif
/**
- * @brief SPI1 interrupt priority level setting.
+ * @brief SPI DMA error hook.
*/
-#if !defined(STM32_SPI_SPI1_IRQ_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_SPI_SPI1_IRQ_PRIORITY 10
+#if !defined(STM32_SPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define STM32_SPI_DMA_ERROR_HOOK(spip) chSysHalt()
#endif
+#if STM32_ADVANCED_DMA || defined(__DOXYGEN__)
+
/**
- * @brief SPI2 interrupt priority level setting.
+ * @brief DMA stream used for SPI1 RX operations.
+ * @note This option is only available on platforms with enhanced DMA.
*/
-#if !defined(STM32_SPI_SPI2_IRQ_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_SPI_SPI2_IRQ_PRIORITY 10
+#if !defined(STM32_SPI_SPI1_RX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 0)
#endif
/**
- * @brief SPI3 interrupt priority level setting.
+ * @brief DMA stream used for SPI1 TX operations.
+ * @note This option is only available on platforms with enhanced DMA.
*/
-#if !defined(STM32_SPI_SPI3_IRQ_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_SPI_SPI3_IRQ_PRIORITY 10
+#if !defined(STM32_SPI_SPI1_TX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 3)
#endif
/**
- * @brief SPI DMA error hook.
- * @note The default action for DMA errors is a system halt because DMA
- * error can only happen because programming errors.
+ * @brief DMA stream used for SPI2 RX operations.
+ * @note This option is only available on platforms with enhanced DMA.
*/
-#if !defined(STM32_SPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
-#define STM32_SPI_DMA_ERROR_HOOK(spip) chSysHalt()
+#if !defined(STM32_SPI_SPI2_RX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3)
+#endif
+
+/**
+ * @brief DMA stream used for SPI2 TX operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_SPI_SPI2_TX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
#endif
+/**
+ * @brief DMA stream used for SPI3 RX operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_SPI_SPI3_RX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0)
+#endif
+
+/**
+ * @brief DMA stream used for SPI3 TX operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_SPI_SPI3_TX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_SPI_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
+#endif
+
+#else /* !STM32_ADVANCED_DMA */
+
+/* Fixed streams for platforms using the old DMA peripheral, the values are
+ valid for both STM32F1xx and STM32L1xx.*/
+#define STM32_SPI_SPI1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
+#define STM32_SPI_SPI1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3)
+#define STM32_SPI_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
+#define STM32_SPI_SPI2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 5)
+#define STM32_SPI_SPI3_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 1)
+#define STM32_SPI_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2)
+
+#endif /* !STM32_ADVANCED_DMA*/
+/** @} */
+
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
@@ -146,6 +212,36 @@
#error "SPI driver activated but no SPI peripheral assigned"
#endif
+#if STM32_SPI_USE_SPI1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI1_RX_DMA_STREAM, STM32_SPI1_RX_DMA_MSK)
+#error "invalid DMA stream associated to SPI1 RX"
+#endif
+
+#if STM32_SPI_USE_SPI1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI1_TX_DMA_STREAM, STM32_SPI1_TX_DMA_MSK)
+#error "invalid DMA stream associated to SPI1 TX"
+#endif
+
+#if STM32_SPI_USE_SPI2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI2_RX_DMA_STREAM, STM32_SPI2_RX_DMA_MSK)
+#error "invalid DMA stream associated to SPI2 RX"
+#endif
+
+#if STM32_SPI_USE_SPI2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI2_TX_DMA_STREAM, STM32_SPI2_TX_DMA_MSK)
+#error "invalid DMA stream associated to SPI2 TX"
+#endif
+
+#if STM32_SPI_USE_SPI3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI3_RX_DMA_STREAM, STM32_SPI3_RX_DMA_MSK)
+#error "invalid DMA stream associated to SPI3 RX"
+#endif
+
+#if STM32_SPI_USE_SPI3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_SPI_SPI3_TX_DMA_STREAM, STM32_SPI3_TX_DMA_MSK)
+#error "invalid DMA stream associated to SPI3 TX"
+#endif
+
#if !defined(STM32_DMA_REQUIRED)
#define STM32_DMA_REQUIRED
#endif
@@ -227,17 +323,21 @@ struct SPIDriver{
*/
SPI_TypeDef *spi;
/**
- * @brief Receive DMA channel.
+ * @brief Receive DMA stream.
*/
const stm32_dma_stream_t *dmarx;
/**
- * @brief Transmit DMA channel.
+ * @brief Transmit DMA stream.
*/
const stm32_dma_stream_t *dmatx;
/**
- * @brief DMA mode bit mask.
+ * @brief RX DMA mode bit mask.
+ */
+ uint32_t rxdmamode;
+ /**
+ * @brief TX DMA mode bit mask.
*/
- uint32_t dmamode;
+ uint32_t txdmamode;
};
/*===========================================================================*/
diff --git a/os/hal/platforms/STM32/stm32.h b/os/hal/platforms/STM32/stm32.h
new file mode 100644
index 000000000..c051dafe0
--- /dev/null
+++ b/os/hal/platforms/STM32/stm32.h
@@ -0,0 +1,154 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file STM32/stm32.h
+ * @brief STM32 common header.
+ * @pre One of the following macros must be defined before including
+ * this header, the macro selects the inclusion of the appropriate
+ * vendor header:
+ * - STM32F10X_LD_VL for Value Line Low Density devices.
+ * - STM32F10X_MD_VL for Value Line Medium Density devices.
+ * - STM32F10X_LD for Performance Low Density devices.
+ * - STM32F10X_MD for Performance Medium Density devices.
+ * - STM32F10X_HD for Performance High Density devices.
+ * - STM32F10X_XL for Performance eXtra Density devices.
+ * - STM32F10X_CL for Connectivity Line devices.
+ * - STM32F2XX for High-performance STM32 F-2 devices.
+ * - STM32F4XX for High-performance STM32 F-4 devices.
+ * - STM32L1XX_MD for Ultra Low Power Medium-density devices.
+ * .
+ *
+ * @addtogroup HAL
+ * @{
+ */
+
+#ifndef _STM32_H_
+#define _STM32_H_
+
+#if defined(STM32F10X_LD_VL) || defined(STM32F10X_MD_VL) || \
+ defined(STM32F10X_HD_VL) || defined(STM32F10X_LD) || \
+ defined(STM32F10X_MD) || defined(STM32F10X_HD) || \
+ defined(STM32F10X_XL) || defined(STM32F10X_CL) || \
+ defined(__DOXYGEN__)
+#include "stm32f10x.h"
+#endif
+
+#if defined(STM32F2XX) || defined(__DOXYGEN__)
+#include "stm32f2xx.h"
+#endif
+
+#if defined(STM32F4XX) || defined(__DOXYGEN__)
+#include "stm32f4xx.h"
+#endif
+
+#if defined(STM32L1XX_MD) || defined(__DOXYGEN__)
+#include "stm32l1xx.h"
+#endif
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief STM32 TIM registers block.
+ * @note Redefined from the ST headers because the non uniform
+ * declaration of the CCR registers among the various
+ * sub-families.
+ */
+typedef struct {
+ volatile uint16_t CR1;
+ uint16_t _resvd0;
+ volatile uint16_t CR2;
+ uint16_t _resvd1;
+ volatile uint16_t SMCR;
+ uint16_t _resvd2;
+ volatile uint16_t DIER;
+ uint16_t _resvd3;
+ volatile uint16_t SR;
+ uint16_t _resvd4;
+ volatile uint16_t EGR;
+ uint16_t _resvd5;
+ volatile uint16_t CCMR1;
+ uint16_t _resvd6;
+ volatile uint16_t CCMR2;
+ uint16_t _resvd7;
+ volatile uint16_t CCER;
+ uint16_t _resvd8;
+ volatile uint32_t CNT;
+ volatile uint16_t PSC;
+ uint16_t _resvd9;
+ volatile uint32_t ARR;
+ volatile uint16_t RCR;
+ uint16_t _resvd10;
+ volatile uint32_t CCR[4];
+ volatile uint16_t BDTR;
+ uint16_t _resvd11;
+ volatile uint16_t DCR;
+ uint16_t _resvd12;
+ volatile uint16_t DMAR;
+ uint16_t _resvd13;
+ volatile uint16_t OR;
+ uint16_t _resvd14;
+} stm32_tim_t;
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @name TIM units references
+ * @{
+ */
+#define STM32_TIM1 ((stm32_tim_t *)TIM1_BASE)
+#define STM32_TIM2 ((stm32_tim_t *)TIM2_BASE)
+#define STM32_TIM3 ((stm32_tim_t *)TIM3_BASE)
+#define STM32_TIM4 ((stm32_tim_t *)TIM4_BASE)
+#define STM32_TIM5 ((stm32_tim_t *)TIM5_BASE)
+#define STM32_TIM6 ((stm32_tim_t *)TIM6_BASE)
+#define STM32_TIM7 ((stm32_tim_t *)TIM7_BASE)
+#define STM32_TIM8 ((stm32_tim_t *)TIM8_BASE)
+#define STM32_TIM9 ((stm32_tim_t *)TIM9_BASE)
+#define STM32_TIM10 ((stm32_tim_t *)TIM10_BASE)
+#define STM32_TIM11 ((stm32_tim_t *)TIM11_BASE)
+#define STM32_TIM12 ((stm32_tim_t *)TIM12_BASE)
+#define STM32_TIM13 ((stm32_tim_t *)TIM13_BASE)
+#define STM32_TIM14 ((stm32_tim_t *)TIM14_BASE)
+/** @} */
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#endif /* _STM32_H_ */
+
+/** @} */
diff --git a/os/hal/platforms/STM32/DMAv1/uart_lld.c b/os/hal/platforms/STM32/uart_lld.c
index a9303744d..be63fc695 100644
--- a/os/hal/platforms/STM32/DMAv1/uart_lld.c
+++ b/os/hal/platforms/STM32/uart_lld.c
@@ -32,6 +32,34 @@
#if HAL_USE_UART || defined(__DOXYGEN__)
/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+#define USART1_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART1_RX_DMA_STREAM, \
+ STM32_USART1_RX_DMA_CHN)
+
+#define USART1_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART1_TX_DMA_STREAM, \
+ STM32_USART1_TX_DMA_CHN)
+
+#define USART2_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART2_RX_DMA_STREAM, \
+ STM32_USART2_RX_DMA_CHN)
+
+#define USART2_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART2_TX_DMA_STREAM, \
+ STM32_USART2_TX_DMA_CHN)
+
+#define USART3_RX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART3_RX_DMA_STREAM, \
+ STM32_USART3_RX_DMA_CHN)
+
+#define USART3_TX_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_UART_USART3_TX_DMA_STREAM, \
+ STM32_USART3_TX_DMA_CHN)
+
+/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
@@ -92,10 +120,9 @@ static void set_rx_idle_loop(UARTDriver *uartp) {
/* RX DMA channel preparation, if the char callback is defined then the
TCIE interrupt is enabled too.*/
if (uartp->config->rxchar_cb == NULL)
- mode = STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_CIRC | STM32_DMA_CR_TEIE;
+ mode = STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_CIRC;
else
- mode = STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_CIRC | STM32_DMA_CR_TEIE |
- STM32_DMA_CR_TCIE;
+ mode = STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_CIRC | STM32_DMA_CR_TCIE;
dmaStreamSetMemory0(uartp->dmarx, &uartp->rxbuf);
dmaStreamSetTransactionSize(uartp->dmarx, 1);
dmaStreamSetMode(uartp->dmarx, uartp->dmamode | mode);
@@ -172,7 +199,7 @@ static void uart_lld_serve_rx_end_irq(UARTDriver *uartp, uint32_t flags) {
/* DMA errors handling.*/
#if defined(STM32_UART_DMA_ERROR_HOOK)
- if ((flags & STM32_DMA_ISR_TEIF) != 0) {
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
STM32_UART_DMA_ERROR_HOOK(uartp);
}
#else
@@ -192,6 +219,7 @@ static void uart_lld_serve_rx_end_irq(UARTDriver *uartp, uint32_t flags) {
uartp->rxstate = UART_RX_COMPLETE;
if (uartp->config->rxend_cb != NULL)
uartp->config->rxend_cb(uartp);
+
/* If the callback didn't explicitly change state then the receiver
automatically returns to the idle state.*/
if (uartp->rxstate == UART_RX_COMPLETE) {
@@ -211,7 +239,7 @@ static void uart_lld_serve_tx_end_irq(UARTDriver *uartp, uint32_t flags) {
/* DMA errors handling.*/
#if defined(STM32_UART_DMA_ERROR_HOOK)
- if ((flags & STM32_DMA_ISR_TEIF) != 0) {
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
STM32_UART_DMA_ERROR_HOOK(uartp);
}
#else
@@ -219,10 +247,12 @@ static void uart_lld_serve_tx_end_irq(UARTDriver *uartp, uint32_t flags) {
#endif
dmaStreamDisable(uartp->dmatx);
+
/* A callback is generated, if enabled, after a completed transfer.*/
uartp->txstate = UART_TX_COMPLETE;
if (uartp->config->txend1_cb != NULL)
uartp->config->txend1_cb(uartp);
+
/* If the callback didn't explicitly change state then the transmitter
automatically returns to the idle state.*/
if (uartp->txstate == UART_TX_COMPLETE)
@@ -248,6 +278,7 @@ static void serve_usart_irq(UARTDriver *uartp) {
}
if (sr & USART_SR_TC) {
u->SR = ~USART_SR_TC;
+
/* End of transmission, a callback is generated.*/
if (uartp->config->txend2_cb != NULL)
uartp->config->txend2_cb(uartp);
@@ -320,22 +351,22 @@ void uart_lld_init(void) {
#if STM32_UART_USE_USART1
uartObjectInit(&UARTD1);
UARTD1.usart = USART1;
- UARTD1.dmarx = STM32_DMA1_STREAM5;
- UARTD1.dmatx = STM32_DMA1_STREAM4;
+ UARTD1.dmarx = STM32_DMA_STREAM(STM32_UART_USART1_RX_DMA_STREAM);
+ UARTD1.dmatx = STM32_DMA_STREAM(STM32_UART_USART1_TX_DMA_STREAM);
#endif
#if STM32_UART_USE_USART2
uartObjectInit(&UARTD2);
UARTD2.usart = USART2;
- UARTD2.dmarx = STM32_DMA1_STREAM6;
- UARTD2.dmatx = STM32_DMA1_STREAM7;
+ UARTD2.dmarx = STM32_DMA_STREAM(STM32_UART_USART2_RX_DMA_STREAM);
+ UARTD2.dmatx = STM32_DMA_STREAM(STM32_UART_USART2_TX_DMA_STREAM);
#endif
#if STM32_UART_USE_USART3
uartObjectInit(&UARTD3);
UARTD3.usart = USART3;
- UARTD3.dmarx = STM32_DMA1_STREAM3;
- UARTD3.dmatx = STM32_DMA1_STREAM2;
+ UARTD3.dmarx = STM32_DMA_STREAM(STM32_UART_USART3_RX_DMA_STREAM);
+ UARTD3.dmatx = STM32_DMA_STREAM(STM32_UART_USART3_TX_DMA_STREAM);
#endif
}
@@ -348,67 +379,74 @@ void uart_lld_init(void) {
*/
void uart_lld_start(UARTDriver *uartp) {
+ uartp->dmamode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
+
if (uartp->state == UART_STOP) {
#if STM32_UART_USE_USART1
if (&UARTD1 == uartp) {
bool_t b;
- b = dmaStreamAllocate(STM32_DMA1_STREAM4,
+ b = dmaStreamAllocate(uartp->dmarx,
STM32_UART_USART1_IRQ_PRIORITY,
- (stm32_dmaisr_t)uart_lld_serve_tx_end_irq,
+ (stm32_dmaisr_t)uart_lld_serve_rx_end_irq,
(void *)uartp);
chDbgAssert(!b, "uart_lld_start(), #1", "stream already allocated");
- b = dmaStreamAllocate(STM32_DMA1_STREAM5,
+ b = dmaStreamAllocate(uartp->dmatx,
STM32_UART_USART1_IRQ_PRIORITY,
- (stm32_dmaisr_t)uart_lld_serve_rx_end_irq,
+ (stm32_dmaisr_t)uart_lld_serve_tx_end_irq,
(void *)uartp);
chDbgAssert(!b, "uart_lld_start(), #2", "stream already allocated");
- RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
+ rccEnableUSART1(FALSE);
NVICEnableVector(USART1_IRQn,
CORTEX_PRIORITY_MASK(STM32_UART_USART1_IRQ_PRIORITY));
+ uartp->dmamode |= STM32_DMA_CR_CHSEL(USART1_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_USART1_DMA_PRIORITY);
}
#endif
#if STM32_UART_USE_USART2
if (&UARTD2 == uartp) {
bool_t b;
- b = dmaStreamAllocate(STM32_DMA1_STREAM6,
+ b = dmaStreamAllocate(uartp->dmarx,
STM32_UART_USART2_IRQ_PRIORITY,
(stm32_dmaisr_t)uart_lld_serve_rx_end_irq,
(void *)uartp);
chDbgAssert(!b, "uart_lld_start(), #3", "stream already allocated");
- b = dmaStreamAllocate(STM32_DMA1_STREAM7,
+ b = dmaStreamAllocate(uartp->dmatx,
STM32_UART_USART2_IRQ_PRIORITY,
(stm32_dmaisr_t)uart_lld_serve_tx_end_irq,
(void *)uartp);
chDbgAssert(!b, "uart_lld_start(), #4", "stream already allocated");
- RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
+ rccEnableUSART2(FALSE);
NVICEnableVector(USART2_IRQn,
CORTEX_PRIORITY_MASK(STM32_UART_USART2_IRQ_PRIORITY));
+ uartp->dmamode |= STM32_DMA_CR_CHSEL(USART2_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_USART2_DMA_PRIORITY);
}
#endif
#if STM32_UART_USE_USART3
if (&UARTD3 == uartp) {
bool_t b;
- b = dmaStreamAllocate(STM32_DMA1_STREAM2,
+ b = dmaStreamAllocate(uartp->dmarx,
STM32_UART_USART3_IRQ_PRIORITY,
- (stm32_dmaisr_t)uart_lld_serve_tx_end_irq,
+ (stm32_dmaisr_t)uart_lld_serve_rx_end_irq,
(void *)uartp);
chDbgAssert(!b, "uart_lld_start(), #5", "stream already allocated");
- b = dmaStreamAllocate(STM32_DMA1_STREAM3,
+ b = dmaStreamAllocate(uartp->dmatx,
STM32_UART_USART3_IRQ_PRIORITY,
- (stm32_dmaisr_t)uart_lld_serve_rx_end_irq,
+ (stm32_dmaisr_t)uart_lld_serve_tx_end_irq,
(void *)uartp);
chDbgAssert(!b, "uart_lld_start(), #6", "stream already allocated");
- RCC->APB1ENR |= RCC_APB1ENR_USART3EN;
+ rccEnableUSART3(FALSE);
NVICEnableVector(USART3_IRQn,
CORTEX_PRIORITY_MASK(STM32_UART_USART3_IRQ_PRIORITY));
+ uartp->dmamode |= STM32_DMA_CR_CHSEL(USART3_RX_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_UART_USART3_DMA_PRIORITY);
}
#endif
/* Static DMA setup, the transfer size depends on the USART settings,
it is 16 bits if M=1 and PCE=0 else it is 8 bits.*/
- uartp->dmamode = STM32_DMA_CR_PL(STM32_UART_USART1_DMA_PRIORITY);
if ((uartp->config->cr1 & (USART_CR1_M | USART_CR1_PCE)) == USART_CR1_M)
uartp->dmamode |= STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
dmaStreamSetPeripheral(uartp->dmarx, &uartp->usart->DR);
@@ -432,33 +470,29 @@ void uart_lld_stop(UARTDriver *uartp) {
if (uartp->state == UART_READY) {
usart_stop(uartp);
+ dmaStreamRelease(uartp->dmarx);
+ dmaStreamRelease(uartp->dmatx);
#if STM32_UART_USE_USART1
if (&UARTD1 == uartp) {
- dmaStreamRelease(STM32_DMA1_STREAM4);
- dmaStreamRelease(STM32_DMA1_STREAM5);
NVICDisableVector(USART1_IRQn);
- RCC->APB2ENR &= ~RCC_APB2ENR_USART1EN;
+ rccDisableUSART1(FALSE);
return;
}
#endif
#if STM32_UART_USE_USART2
if (&UARTD2 == uartp) {
- dmaStreamRelease(STM32_DMA1_STREAM6);
- dmaStreamRelease(STM32_DMA1_STREAM7);
NVICDisableVector(USART2_IRQn);
- RCC->APB1ENR &= ~RCC_APB1ENR_USART2EN;
+ rccDisableUSART2(FALSE);
return;
}
#endif
#if STM32_UART_USE_USART3
if (&UARTD3 == uartp) {
- dmaStreamRelease(STM32_DMA1_STREAM2);
- dmaStreamRelease(STM32_DMA1_STREAM3);
NVICDisableVector(USART3_IRQn);
- RCC->APB1ENR &= ~RCC_APB1ENR_USART3EN;
+ rccDisableUSART3(FALSE);
return;
}
#endif
@@ -482,8 +516,7 @@ void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf) {
dmaStreamSetMemory0(uartp->dmatx, txbuf);
dmaStreamSetTransactionSize(uartp->dmatx, n);
dmaStreamSetMode(uartp->dmatx, uartp->dmamode | STM32_DMA_CR_DIR_M2P |
- STM32_DMA_CR_MINC | STM32_DMA_CR_TEIE |
- STM32_DMA_CR_TCIE);
+ STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE);
dmaStreamEnable(uartp->dmatx);
}
@@ -526,8 +559,7 @@ void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf) {
dmaStreamSetMemory0(uartp->dmarx, rxbuf);
dmaStreamSetTransactionSize(uartp->dmarx, n);
dmaStreamSetMode(uartp->dmarx, uartp->dmamode | STM32_DMA_CR_DIR_P2M |
- STM32_DMA_CR_MINC | STM32_DMA_CR_TEIE |
- STM32_DMA_CR_TCIE);
+ STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE);
dmaStreamEnable(uartp->dmarx);
}
diff --git a/os/hal/platforms/STM32/DMAv1/uart_lld.h b/os/hal/platforms/STM32/uart_lld.h
index aff7f52ba..742a8a37d 100644
--- a/os/hal/platforms/STM32/DMAv1/uart_lld.h
+++ b/os/hal/platforms/STM32/uart_lld.h
@@ -40,6 +40,10 @@
/*===========================================================================*/
/**
+ * @name Configuration options
+ * @{
+ */
+/**
* @brief UART driver on USART1 enable switch.
* @details If set to @p TRUE the support for USART1 is included.
* @note The default is @p FALSE.
@@ -106,6 +110,7 @@
#if !defined(STM32_UART_USART2_DMA_PRIORITY) || defined(__DOXYGEN__)
#define STM32_UART_USART2_DMA_PRIORITY 0
#endif
+
/**
* @brief USART3 DMA priority (0..3|lowest..highest).
* @note The priority level is used for both the TX and RX DMA channels but
@@ -125,6 +130,70 @@
#define STM32_UART_DMA_ERROR_HOOK(uartp) chSysHalt()
#endif
+#if STM32_ADVANCED_DMA || defined(__DOXYGEN__)
+
+/**
+ * @brief DMA stream used for USART1 RX operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_UART_USART1_RX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_UART_USART1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 5)
+#endif
+
+/**
+ * @brief DMA stream used for USART1 TX operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_UART_USART1_TX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_UART_USART1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
+#endif
+
+/**
+ * @brief DMA stream used for USART2 RX operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_UART_USART2_RX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_UART_USART2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 5)
+#endif
+
+/**
+ * @brief DMA stream used for USART2 TX operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_UART_USART2_TX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
+#endif
+
+/**
+ * @brief DMA stream used for USART3 RX operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_UART_USART3_RX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_UART_USART3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 1)
+#endif
+
+/**
+ * @brief DMA stream used for USART3 TX operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_UART_USART3_TX_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_UART_USART3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3)
+#endif
+
+#else /* !STM32_ADVANCED_DMA */
+
+/* Fixed streams for platforms using the old DMA peripheral, the values are
+ valid for both STM32F1xx and STM32L1xx.*/
+#define STM32_UART_USART1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 5)
+#define STM32_UART_USART1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4)
+#define STM32_UART_USART2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6)
+#define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7)
+#define STM32_UART_USART3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3)
+#define STM32_UART_USART3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2)
+
+#endif /* !STM32_ADVANCED_DMA*/
+/** @} */
+
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
@@ -146,6 +215,42 @@
#error "UART driver activated but no USART/UART peripheral assigned"
#endif
+#if STM32_UART_USE_USART1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART1_RX_DMA_STREAM, \
+ STM32_USART1_RX_DMA_MSK)
+#error "invalid DMA stream associated to USART1 RX"
+#endif
+
+#if STM32_UART_USE_USART1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART1_TX_DMA_STREAM, \
+ STM32_USART1_TX_DMA_MSK)
+#error "invalid DMA stream associated to USART1 TX"
+#endif
+
+#if STM32_UART_USE_USART2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART2_RX_DMA_STREAM, \
+ STM32_USART2_RX_DMA_MSK)
+#error "invalid DMA stream associated to USART2 RX"
+#endif
+
+#if STM32_UART_USE_USART2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART2_TX_DMA_STREAM, \
+ STM32_USART2_TX_DMA_MSK)
+#error "invalid DMA stream associated to USART2 TX"
+#endif
+
+#if STM32_UART_USE_USART3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART3_RX_DMA_STREAM, \
+ STM32_USART3_RX_DMA_MSK)
+#error "invalid DMA stream associated to USART3 RX"
+#endif
+
+#if STM32_UART_USE_USART3 && \
+ !STM32_DMA_IS_VALID_ID(STM32_UART_USART3_TX_DMA_STREAM, \
+ STM32_USART3_TX_DMA_MSK)
+#error "invalid DMA stream associated to USART3 TX"
+#endif
+
#if !defined(STM32_DMA_REQUIRED)
#define STM32_DMA_REQUIRED
#endif