diff options
Diffstat (limited to 'os/hal/platforms/STM32')
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(ÐD1);
+
+ /* 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
|