diff --git a/miosix/arch/common/drivers/serial_stm32.cpp b/miosix/arch/common/drivers/serial_stm32.cpp deleted file mode 100644 index f35c32d70937e682b04c70a94c2a32d7bbab4c89..0000000000000000000000000000000000000000 --- a/miosix/arch/common/drivers/serial_stm32.cpp +++ /dev/null @@ -1,1402 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2010-2018 by Terraneo Federico * - * * - * This program 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 2 of the License, or * - * (at your option) any later version. * - * * - * This program 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. * - * * - * As a special exception, if other files instantiate templates or use * - * macros or inline functions from this file, or you compile this file * - * and link it with other works to produce a work based on this file, * - * this file does not by itself cause the resulting work to be covered * - * by the GNU General Public License. However the source code for this * - * file must still be made available in accordance with the GNU General * - * Public License. This exception does not invalidate any other reasons * - * why a work based on this file might be covered by the GNU General * - * Public License. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, see <http://www.gnu.org/licenses/> * - ***************************************************************************/ - -#include <cstring> -#include <errno.h> -#include <termios.h> -#include "serial_stm32.h" -#include "kernel/sync.h" -#include "kernel/scheduler/scheduler.h" -#include "filesystem/ioctl.h" -#include "cache/cortexMx_cache.h" - -using namespace std; -using namespace miosix; - -//Work around ST renaming register fields for some STM32L4 -#if defined(USART_CR1_RXNEIE_RXFNEIE) && !defined(USART_CR1_RXNEIE) -#define USART_CR1_RXNEIE USART_CR1_RXNEIE_RXFNEIE -#endif -#if defined(USART_ISR_RXNE_RXFNE) && !defined(USART_ISR_RXNE) -#define USART_ISR_RXNE USART_ISR_RXNE_RXFNE -#endif -#if defined(USART_ISR_TXE_TXFNF) && !defined(USART_ISR_TXE) -#define USART_ISR_TXE USART_ISR_TXE_TXFNF -#endif - -#ifdef STM32F030x8 -// On this chip only USART1 exists -#define STM32_NO_SERIAL_2_3 -#endif - -static const int numPorts=3; //Supporting only USART1, USART2, USART3 - -//A nice feature of the stm32 is that the USART are connected to the same -//GPIOS in all families, stm32f1, f2, f4 and l1. Additionally, USART1 is -//always connected to the APB2, while USART2 and USART3 are always on APB1 -//Unfortunately, this does not hold with DMA. -typedef Gpio<GPIOA_BASE,9> u1tx; -typedef Gpio<GPIOA_BASE,10> u1rx; -typedef Gpio<GPIOA_BASE,11> u1cts; -typedef Gpio<GPIOA_BASE,12> u1rts; - -typedef Gpio<GPIOA_BASE,2> u2tx; -typedef Gpio<GPIOA_BASE,3> u2rx; -typedef Gpio<GPIOA_BASE,0> u2cts; -typedef Gpio<GPIOA_BASE,1> u2rts; - -typedef Gpio<GPIOB_BASE,10> u3tx; -typedef Gpio<GPIOB_BASE,11> u3rx; -typedef Gpio<GPIOB_BASE,13> u3cts; -typedef Gpio<GPIOB_BASE,14> u3rts; - -/// Pointer to serial port classes to let interrupts access the classes -static STM32Serial *ports[numPorts]={0}; - -/** - * \internal interrupt routine for usart1 actual implementation - */ -void __attribute__((noinline)) usart1irqImpl() -{ - if(ports[0]) ports[0]->IRQhandleInterrupt(); -} - -/** - * \internal interrupt routine for usart1 - */ -void __attribute__((naked)) USART1_IRQHandler() -{ - saveContext(); - asm volatile("bl _Z13usart1irqImplv"); - restoreContext(); -} - -#if !defined(STM32_NO_SERIAL_2_3) - -/** - * \internal interrupt routine for usart2 actual implementation - */ -void __attribute__((noinline)) usart2irqImpl() -{ - if(ports[1]) ports[1]->IRQhandleInterrupt(); -} - -/** - * \internal interrupt routine for usart2 - */ -void __attribute__((naked)) USART2_IRQHandler() -{ - saveContext(); - asm volatile("bl _Z13usart2irqImplv"); - restoreContext(); -} - -#if !defined(STM32F411xE) && !defined(STM32F401xE) && !defined(STM32F401xC) -/** - * \internal interrupt routine for usart3 actual implementation - */ -void __attribute__((noinline)) usart3irqImpl() -{ - if(ports[2]) ports[2]->IRQhandleInterrupt(); -} - -/** - * \internal interrupt routine for usart3 - */ -#if !defined(STM32F072xB) -void __attribute__((naked)) USART3_IRQHandler() -{ - saveContext(); - asm volatile("bl _Z13usart3irqImplv"); - restoreContext(); -} -#else //!defined(STM32F072xB) -void __attribute__((naked)) USART3_4_IRQHandler() -{ - saveContext(); - asm volatile("bl _Z13usart3irqImplv"); - restoreContext(); -} -#endif //!defined(STM32F072xB) -#endif //!defined(STM32F411xE) && !defined(STM32F401xE) && !defined(STM32F401xC) -#endif //!defined(STM32_NO_SERIAL_2_3) - -#ifdef SERIAL_1_DMA - -/** - * \internal USART1 DMA tx actual implementation - */ -void __attribute__((noinline)) usart1txDmaImpl() -{ - #if defined(_ARCH_CORTEXM3_STM32F1) || defined (_ARCH_CORTEXM4_STM32F3) \ - || defined(_ARCH_CORTEXM4_STM32L4) - DMA1->IFCR=DMA_IFCR_CGIF4; - DMA1_Channel4->CCR=0; //Disable DMA - #elif defined(_ARCH_CORTEXM7_STM32H7) //stm32f2 and f4 - DMA1->HIFCR = DMA_HIFCR_CTCIF7 - | DMA_HIFCR_CTEIF7 - | DMA_HIFCR_CDMEIF7 - | DMA_HIFCR_CFEIF7; - #else //stm32f2 and f4 - DMA2->HIFCR = DMA_HIFCR_CTCIF7 - | DMA_HIFCR_CTEIF7 - | DMA_HIFCR_CDMEIF7 - | DMA_HIFCR_CFEIF7; - #endif - if(ports[0]) ports[0]->IRQhandleDMAtx(); -} - -/** - * \internal USART1 DMA rx actual implementation - */ -void __attribute__((noinline)) usart1rxDmaImpl() -{ - if(ports[0]) ports[0]->IRQhandleDMArx(); -} - -#if defined(_ARCH_CORTEXM3_STM32F1) || defined (_ARCH_CORTEXM4_STM32F3) \ - || defined(_ARCH_CORTEXM4_STM32L4) -/** - * \internal DMA1 Channel 4 IRQ (configured as USART1 TX) - */ -void __attribute__((naked)) DMA1_Channel4_IRQHandler() -{ - saveContext(); - asm volatile("bl _Z15usart1txDmaImplv"); - restoreContext(); -} - -/** - * \internal DMA1 Channel 5 IRQ (configured as USART1 RX) - */ -void __attribute__((naked)) DMA1_Channel5_IRQHandler() -{ - saveContext(); - asm volatile("bl _Z15usart1rxDmaImplv"); - restoreContext(); -} - -#elif defined(_ARCH_CORTEXM7_STM32H7) - -/** - * \internal DMA1 stream 7 IRQ (configured as USART1 TX) - */ -void __attribute__((naked)) DMA1_Stream7_IRQHandler() -{ - saveContext(); - asm volatile("bl _Z15usart1txDmaImplv"); - restoreContext(); -} - -/** - * \internal DMA1 stream 5 IRQ (configured as USART1 RX) - */ -void __attribute__((naked)) DMA1_Stream5_IRQHandler() -{ - saveContext(); - asm volatile("bl _Z15usart1rxDmaImplv"); - restoreContext(); -} - -#else //stm32f2 and stm32f4 - -/** - * \internal DMA2 stream 7 IRQ (configured as USART1 TX) - */ -void __attribute__((naked)) DMA2_Stream7_IRQHandler() -{ - saveContext(); - asm volatile("bl _Z15usart1txDmaImplv"); - restoreContext(); -} - -/** - * \internal DMA2 stream 5 IRQ (configured as USART1 RX) - */ -void __attribute__((naked)) DMA2_Stream5_IRQHandler() -{ - saveContext(); - asm volatile("bl _Z15usart1rxDmaImplv"); - restoreContext(); -} -#endif -#endif //SERIAL_1_DMA - -#if defined(SERIAL_2_DMA) && !defined(STM32_NO_SERIAL_2_3) - -/** - * \internal USART2 DMA tx actual implementation - */ -void __attribute__((noinline)) usart2txDmaImpl() -{ - #if defined(_ARCH_CORTEXM3_STM32F1) || defined (_ARCH_CORTEXM4_STM32F3) \ - || defined(_ARCH_CORTEXM4_STM32L4) - DMA1->IFCR=DMA_IFCR_CGIF7; - DMA1_Channel7->CCR=0; //Disable DMA - #else //stm32f2 and f4 - DMA1->HIFCR = DMA_HIFCR_CTCIF6 - | DMA_HIFCR_CTEIF6 - | DMA_HIFCR_CDMEIF6 - | DMA_HIFCR_CFEIF6; - #endif - if(ports[1]) ports[1]->IRQhandleDMAtx(); -} - -/** - * \internal USART2 DMA rx actual implementation - */ -void __attribute__((noinline)) usart2rxDmaImpl() -{ - if(ports[1]) ports[1]->IRQhandleDMArx(); -} - -#if defined(_ARCH_CORTEXM3_STM32F1) || defined (_ARCH_CORTEXM4_STM32F3) \ - || defined(_ARCH_CORTEXM4_STM32L4) -/** - * \internal DMA1 Channel 7 IRQ (configured as USART2 TX) - */ -void __attribute__((naked)) DMA1_Channel7_IRQHandler() -{ - saveContext(); - asm volatile("bl _Z15usart2txDmaImplv"); - restoreContext(); -} - -/** - * \internal DMA1 Channel 6 IRQ (configured as USART2 RX) - */ -void __attribute__((naked)) DMA1_Channel6_IRQHandler() -{ - saveContext(); - asm volatile("bl _Z15usart2rxDmaImplv"); - restoreContext(); -} - -#elif defined(_ARCH_CORTEXM7_STM32H7) - -/** - * \internal DMA1 stream 6 IRQ (configured as USART2 TX) - */ -void __attribute__((naked)) DMA1_Stream6_IRQHandler() -{ - saveContext(); - asm volatile("bl _Z15usart2txDmaImplv"); - restoreContext(); -} - -/** - * \internal DMA1 stream 4 IRQ (configured as USART2 RX) - */ -void __attribute__((naked)) DMA1_Stream4_IRQHandler() -{ - saveContext(); - asm volatile("bl _Z15usart2rxDmaImplv"); - restoreContext(); -} - -#else //stm32f2 and stm32f4 - -/** - * \internal DMA1 stream 6 IRQ (configured as USART2 TX) - */ -void __attribute__((naked)) DMA1_Stream6_IRQHandler() -{ - saveContext(); - asm volatile("bl _Z15usart2txDmaImplv"); - restoreContext(); -} - -/** - * \internal DMA1 stream 5 IRQ (configured as USART2 RX) - */ -void __attribute__((naked)) DMA1_Stream5_IRQHandler() -{ - saveContext(); - asm volatile("bl _Z15usart2rxDmaImplv"); - restoreContext(); -} -#endif -#endif //SERIAL_2_DMA - -#if defined(SERIAL_3_DMA) && !defined(STM32_NO_SERIAL_2_3) - -/** - * \internal USART3 DMA tx actual implementation - */ -void __attribute__((noinline)) usart3txDmaImpl() -{ - #if defined(_ARCH_CORTEXM3_STM32F1) || defined (_ARCH_CORTEXM4_STM32F3) \ - || defined(_ARCH_CORTEXM4_STM32L4) - DMA1->IFCR=DMA_IFCR_CGIF2; - DMA1_Channel2->CCR=0; //Disable DMA - #else //stm32f2 and f4 - DMA1->LIFCR = DMA_LIFCR_CTCIF3 - | DMA_LIFCR_CTEIF3 - | DMA_LIFCR_CDMEIF3 - | DMA_LIFCR_CFEIF3; - #endif - if(ports[2]) ports[2]->IRQhandleDMAtx(); -} - -/** - * \internal USART3 DMA rx actual implementation - */ -void __attribute__((noinline)) usart3rxDmaImpl() -{ - if(ports[2]) ports[2]->IRQhandleDMArx(); -} - -#if defined(_ARCH_CORTEXM3_STM32F1) || defined (_ARCH_CORTEXM4_STM32F3) \ - || defined(_ARCH_CORTEXM4_STM32L4) -/** - * \internal DMA1 Channel 2 IRQ (configured as USART3 TX) - */ -void __attribute__((naked)) DMA1_Channel2_IRQHandler() -{ - saveContext(); - asm volatile("bl _Z15usart3txDmaImplv"); - restoreContext(); -} - -/** - * \internal DMA1 Channel 3 IRQ (configured as USART3 RX) - */ -void __attribute__((naked)) DMA1_Channel3_IRQHandler() -{ - saveContext(); - asm volatile("bl _Z15usart3rxDmaImplv"); - restoreContext(); -} - -#else //stm32f2 and stm32f4 - -/** - * \internal DMA1 stream 3 IRQ (configured as USART3 TX) - */ -void __attribute__((naked)) DMA1_Stream3_IRQHandler() -{ - saveContext(); - asm volatile("bl _Z15usart3txDmaImplv"); - restoreContext(); -} - -/** - * \internal DMA1 stream 1 IRQ (configured as USART3 RX) - */ -void __attribute__((naked)) DMA1_Stream1_IRQHandler() -{ - saveContext(); - asm volatile("bl _Z15usart3rxDmaImplv"); - restoreContext(); -} -#endif -#endif //SERIAL_3_DMA - -namespace miosix { - -#ifdef SERIAL_DMA -#if defined(_ARCH_CORTEXM4_STM32F4) || defined(_ARCH_CORTEXM4_STM32F3) \ - || defined(_ARCH_CORTEXM4_STM32L4) -/** - * The STM3F3, STM32F4 and STM32L4 have an ugly quirk of having 64KB RAM area - * called CCM that can only be accessed by the processor and not be the DMA. - * \param x pointer to check - * \return true if the pointer is inside the CCM, and thus it isn't possible - * to use it for DMA transfers - */ -static bool isInCCMarea(const void *x) -{ - unsigned int ptr=reinterpret_cast<const unsigned int>(x); - return (ptr>=0x10000000) && (ptr<(0x10000000+64*1024)); -} -#else //_ARCH_CORTEXM4_STM32F4 and _ARCH_CORTEXM4_STM32F3 -static inline bool isInCCMarea(const void *x) { return false; } -#endif // _ARCH_CORTEXM4_STM32F4 and _ARCH_CORTEXM4_STM32F3 -#endif //SERIAL_DMA - -// -// class STM32Serial -// - -// A note on the baudrate/500: the buffer is selected so as to withstand -// 20ms of full data rate. In the 8N1 format one char is made of 10 bits. -// So (baudrate/10)*0.02=baudrate/500 -STM32Serial::STM32Serial(int id, int baudrate, FlowCtrl flowControl) - : Device(Device::TTY), rxQueue(rxQueueMin+baudrate/500), - flowControl(flowControl==RTSCTS), portId(id) -{ - //stm32f1 alternate function mapping does not work like later stm32 chips, - //its only purpose is to change the GPIO pins allocated to a peripherals. - //There is no AF register per pin, but an AF register per peripheral - //with several mutually exclusive mapping options. - //Therefore we don't need to configure AF on stm32f1 for the serial to work - #if !defined(_ARCH_CORTEXM3_STM32F1) - //stm32f2, f4, l4, l1, f7, h7, l0 require alternate function mapping - //stm32f0/l0 family has different alternate function mapping - //with respect to the other families - #if defined(_ARCH_CORTEXM0_STM32F0) - int altFunc = 1; // F0 only - #elif defined(_ARCH_CORTEXM0PLUS_STM32L0) - int altFunc = 4; // L0 only - #else - int altFunc = 7; // everyone else - #endif - switch(id) - { - case 1: - u1tx::alternateFunction(altFunc); - u1rx::alternateFunction(altFunc); - if(flowControl) - { - u1rts::alternateFunction(altFunc); - u1cts::alternateFunction(altFunc); - } - break; - case 2: - u2tx::alternateFunction(altFunc); - u2rx::alternateFunction(altFunc); - if(flowControl) - { - u2rts::alternateFunction(altFunc); - u2cts::alternateFunction(altFunc); - } - break; - case 3: - u3tx::alternateFunction(altFunc); - u3rx::alternateFunction(altFunc); - if(flowControl) - { - u3rts::alternateFunction(altFunc); - u3cts::alternateFunction(altFunc); - } - break; - } - #endif - - switch(id) - { - case 1: - commonInit(id,baudrate,u1tx::getPin(),u1rx::getPin(), - u1rts::getPin(),u1cts::getPin()); - break; - case 2: - commonInit(id,baudrate,u2tx::getPin(),u2rx::getPin(), - u2rts::getPin(),u2cts::getPin()); - break; - case 3: - commonInit(id,baudrate,u3tx::getPin(),u3rx::getPin(), - u3rts::getPin(),u3cts::getPin()); - break; - } -} - -STM32Serial::STM32Serial(int id, int baudrate, GpioPin tx, GpioPin rx) - : Device(Device::TTY), rxQueue(rxQueueMin+baudrate/500), - flowControl(false), portId(id) -{ - commonInit(id,baudrate,tx,rx,tx,rx); //The last two args will be ignored -} - -STM32Serial::STM32Serial(int id, int baudrate, GpioPin tx, GpioPin rx, - miosix::GpioPin rts, miosix::GpioPin cts) - : Device(Device::TTY), rxQueue(rxQueueMin+baudrate/500), - flowControl(true), portId(id) -{ - commonInit(id,baudrate,tx,rx,rts,cts); -} - -void STM32Serial::commonInit(int id, int baudrate, GpioPin tx, GpioPin rx, - GpioPin rts, GpioPin cts) -{ - #ifdef SERIAL_DMA - dmaTx=0; - dmaRx=0; - txWaiting=0; - dmaTxInProgress=false; - #endif //SERIAL_DMA - InterruptDisableLock dLock; - if(id<1|| id>numPorts || ports[id-1]!=0) errorHandler(UNEXPECTED); - ports[id-1]=this; - unsigned int freq=SystemCoreClock; - switch(id) - { - case 1: - port=USART1; - RCC->APB2ENR |= RCC_APB2ENR_USART1EN; - RCC_SYNC(); - #ifdef SERIAL_1_DMA - #if defined(_ARCH_CORTEXM3_STM32F1) || defined(_ARCH_CORTEXM4_STM32F3) \ - || defined(_ARCH_CORTEXM4_STM32L4) - #ifdef _ARCH_CORTEXM4_STM32L4 - RCC->AHB1ENR |= RCC_AHBENR_DMA1EN; - DMA1_CSELR->CSELR |= (2 << DMA_CSELR_C4S_Pos) // Assign DMA1_CH4 to USART1_TX - | (2 << DMA_CSELR_C5S_Pos);// Assign DMA1_CH5 to USART1_RX - #else - RCC->AHBENR |= RCC_AHBENR_DMA1EN; - #endif - RCC_SYNC(); - NVIC_SetPriority(DMA1_Channel4_IRQn,15);//Lowest priority for serial - NVIC_EnableIRQ(DMA1_Channel4_IRQn); - dmaTx=DMA1_Channel4; - //Higher priority to ensure IRQhandleDMArx() is called before - //IRQhandleInterrupt(), so that idle is set correctly - NVIC_SetPriority(DMA1_Channel5_IRQn,14); - NVIC_EnableIRQ(DMA1_Channel5_IRQn); - dmaRx=DMA1_Channel5; - #elif defined(_ARCH_CORTEXM7_STM32H7) - RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN; // enabling DMA1 clock - RCC_SYNC(); - // enabling interrupts - dmaRx=DMA1_Stream5; - NVIC_EnableIRQ(DMA1_Stream5_IRQn); - NVIC_SetPriority(DMA1_Stream5_IRQn,14); - dmaTx=DMA1_Stream7; - NVIC_EnableIRQ(DMA1_Stream7_IRQn); - NVIC_SetPriority(DMA1_Stream7_IRQn,15); - // Configuring DMAMUX - DMAMUX1_Channel5->CCR &= ~DMAMUX_CxCR_DMAREQ_ID; - DMAMUX1_Channel5->CCR |= DMAMUX_CxCR_DMAREQ_ID_0 - | DMAMUX_CxCR_DMAREQ_ID_3 - | DMAMUX_CxCR_DMAREQ_ID_5; - DMAMUX1_Channel7->CCR &= ~DMAMUX_CxCR_DMAREQ_ID; - DMAMUX1_Channel7->CCR |= DMAMUX_CxCR_DMAREQ_ID_1 - | DMAMUX_CxCR_DMAREQ_ID_3 - | DMAMUX_CxCR_DMAREQ_ID_5; - #else //stm32f2, stm32f4 - RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; - RCC_SYNC(); - NVIC_SetPriority(DMA2_Stream7_IRQn,15);//Lowest priority for serial - NVIC_EnableIRQ(DMA2_Stream7_IRQn); - dmaTx=DMA2_Stream7; - //Higher priority to ensure IRQhandleDMArx() is called before - //IRQhandleInterrupt(), so that idle is set correctly - NVIC_SetPriority(DMA2_Stream5_IRQn,14); - NVIC_EnableIRQ(DMA2_Stream5_IRQn); - dmaRx=DMA2_Stream5; - #endif - port->CR3=USART_CR3_DMAT | USART_CR3_DMAR; - #endif //SERIAL_1_DMA - NVIC_SetPriority(USART1_IRQn,15);//Lowest priority for serial - NVIC_EnableIRQ(USART1_IRQn); - #if !defined(_ARCH_CORTEXM7_STM32H7) && !defined(_ARCH_CORTEXM0_STM32F0) - if(RCC->CFGR & RCC_CFGR_PPRE2_2) freq/=1<<(((RCC->CFGR>>RCC_CFGR_PPRE2_Pos) & 0x3)+1); - #elif defined(_ARCH_CORTEXM0_STM32F0) - // STM32F0 family has only PPRE2 register - if(RCC->CFGR & RCC_CFGR_PPRE_2) freq/=1<<(((RCC->CFGR>>RCC_CFGR_PPRE_Pos) & 0x3)+1); - #else - //rcc_hclk3 = SystemCoreClock / HPRE - //rcc_pclk2 = rcc_hclk1 / D2PPRE2 - //NOTE: are rcc_hclk3 and rcc_hclk1 the same signal? - //usart1 clock is rcc_pclk2 - if(RCC->D1CFGR & RCC_D1CFGR_HPRE_3) - freq/=1<<(((RCC->D1CFGR>>RCC_D1CFGR_HPRE_Pos) & 0x7)+1); - if(RCC->D2CFGR & RCC_D2CFGR_D2PPRE2_2) - freq/=1<<(((RCC->D2CFGR>>RCC_D2CFGR_D2PPRE2_Pos) & 0x3)+1); - #endif //_ARCH_CORTEXM7_STM32H7 - break; - - #if !defined(STM32_NO_SERIAL_2_3) - case 2: - port=USART2; - #ifndef _ARCH_CORTEXM7_STM32H7 - #ifndef _ARCH_CORTEXM4_STM32L4 - RCC->APB1ENR |= RCC_APB1ENR_USART2EN; - #else //_ARCH_CORTEXM4_STM32L4 - RCC->APB1ENR1 |= RCC_APB1ENR1_USART2EN; - #endif //_ARCH_CORTEXM4_STM32L4 - #else //_ARCH_CORTEXM7_STM32H7 - RCC->APB1LENR |= RCC_APB1LENR_USART2EN; - #endif //_ARCH_CORTEXM7_STM32H7 - RCC_SYNC(); - #ifdef SERIAL_2_DMA - #if defined(_ARCH_CORTEXM3_STM32F1) || defined(_ARCH_CORTEXM4_STM32F3) \ - || defined(_ARCH_CORTEXM4_STM32L4) - #ifdef _ARCH_CORTEXM4_STM32L4 - RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN; - DMA1_CSELR->CSELR |= (2 << DMA_CSELR_C7S_Pos) // Assign DMA1_CH7 to USART2_TX - | (2 << DMA_CSELR_C6S_Pos);// Assign DMA1_CH6 to USART2_RX - #else - RCC->AHBENR |= RCC_AHBENR_DMA1EN; - #endif - RCC_SYNC(); - NVIC_SetPriority(DMA1_Channel7_IRQn,15);//Lowest priority for serial - NVIC_EnableIRQ(DMA1_Channel7_IRQn); - dmaTx=DMA1_Channel7; - //Higher priority to ensure IRQhandleDMArx() is called before - //IRQhandleInterrupt(), so that idle is set correctly - NVIC_SetPriority(DMA1_Channel6_IRQn,14); - NVIC_EnableIRQ(DMA1_Channel6_IRQn); - dmaRx=DMA1_Channel6; - #elif defined(_ARCH_CORTEXM7_STM32H7) - RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN; // enabling DMA1 clock - RCC_SYNC(); - // enabling interrupts - dmaRx=DMA1_Stream4; - NVIC_EnableIRQ(DMA1_Stream4_IRQn); - NVIC_SetPriority(DMA1_Stream4_IRQn,14); - dmaTx=DMA1_Stream6; - NVIC_EnableIRQ(DMA1_Stream6_IRQn); - NVIC_SetPriority(DMA1_Stream6_IRQn,15); - // Configuring DMAMUX - DMAMUX1_Channel4->CCR &= ~DMAMUX_CxCR_DMAREQ_ID; - DMAMUX1_Channel4->CCR |= DMAMUX_CxCR_DMAREQ_ID_0 - | DMAMUX_CxCR_DMAREQ_ID_1 - | DMAMUX_CxCR_DMAREQ_ID_3 - | DMAMUX_CxCR_DMAREQ_ID_5; - DMAMUX1_Channel6->CCR &= ~DMAMUX_CxCR_DMAREQ_ID; - DMAMUX1_Channel6->CCR |= DMAMUX_CxCR_DMAREQ_ID_2 - | DMAMUX_CxCR_DMAREQ_ID_3 - | DMAMUX_CxCR_DMAREQ_ID_5; - #else //stm32f2, stm32f4 - RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN; - RCC_SYNC(); - NVIC_SetPriority(DMA1_Stream6_IRQn,15);//Lowest priority for serial - NVIC_EnableIRQ(DMA1_Stream6_IRQn); - dmaTx=DMA1_Stream6; - //Higher priority to ensure IRQhandleDMArx() is called before - //IRQhandleInterrupt(), so that idle is set correctly - NVIC_SetPriority(DMA1_Stream5_IRQn,14); - NVIC_EnableIRQ(DMA1_Stream5_IRQn); - dmaRx=DMA1_Stream5; - #endif - port->CR3=USART_CR3_DMAT | USART_CR3_DMAR; - #endif //SERIAL_2_DMA - NVIC_SetPriority(USART2_IRQn,15);//Lowest priority for serial - NVIC_EnableIRQ(USART2_IRQn); - #if !defined(_ARCH_CORTEXM7_STM32H7) && !defined(_ARCH_CORTEXM0_STM32F0) - if(RCC->CFGR & RCC_CFGR_PPRE1_2) freq/=1<<(((RCC->CFGR>>RCC_CFGR_PPRE1_Pos) & 0x3)+1); - #elif defined(_ARCH_CORTEXM0_STM32F0) - // STM32F0 family has only PPRE2 register - if(RCC->CFGR & RCC_CFGR_PPRE_2) freq/=1<<(((RCC->CFGR>>RCC_CFGR_PPRE_Pos) & 0x3)+1); - #else //_ARCH_CORTEXM7_STM32H7 - //rcc_hclk3 = SystemCoreClock / HPRE - //rcc_pclk1 = rcc_hclk1 / D2PPRE1 - //NOTE: are rcc_hclk3 and rcc_hclk1 the same signal? - //usart2 clock is rcc_pclk1 - if(RCC->D1CFGR & RCC_D1CFGR_HPRE_3) - freq/=1<<(((RCC->D1CFGR>>RCC_D1CFGR_HPRE_Pos) & 0x7)+1); - if(RCC->D2CFGR & RCC_D2CFGR_D2PPRE1_2) - freq/=1<<(((RCC->D2CFGR>>RCC_D2CFGR_D2PPRE1_Pos) & 0x3)+1); - #endif //_ARCH_CORTEXM7_STM32H7 - break; - #if !defined(STM32F411xE) && !defined(STM32F401xE) && !defined(STM32F401xC) && !defined(STM32L053xx) - case 3: - port=USART3; - #ifndef _ARCH_CORTEXM7_STM32H7 - #ifndef _ARCH_CORTEXM4_STM32L4 - RCC->APB1ENR |= RCC_APB1ENR_USART3EN; - #else //_ARCH_CORTEXM4_STM32L4 - RCC->APB1ENR1 |= RCC_APB1ENR1_USART3EN; - #endif //_ARCH_CORTEXM4_STM32L4 - #else - RCC->APB1LENR |= RCC_APB1LENR_USART3EN; - #endif //_ARCH_CORTEXM7_STM32H7 - RCC_SYNC(); - #ifdef SERIAL_3_DMA - #if defined(_ARCH_CORTEXM3_STM32F1) || defined(_ARCH_CORTEXM4_STM32F3) \ - || defined(_ARCH_CORTEXM4_STM32L4) - #ifdef _ARCH_CORTEXM4_STM32L4 - RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN; - DMA1_CSELR->CSELR |= (2 << DMA_CSELR_C2S_Pos) // Assign DMA1_CH2 to USART2_TX - | (2 << DMA_CSELR_C3S_Pos);// Assign DMA1_CH3 to USART2_RX - #else - RCC->AHBENR |= RCC_AHBENR_DMA1EN; - #endif - RCC_SYNC(); - NVIC_SetPriority(DMA1_Channel2_IRQn,15);//Lowest priority for serial - NVIC_EnableIRQ(DMA1_Channel2_IRQn); - dmaTx=DMA1_Channel2; - //Higher priority to ensure IRQhandleDMArx() is called before - //IRQhandleInterrupt(), so that idle is set correctly - NVIC_SetPriority(DMA1_Channel3_IRQn,14); - NVIC_EnableIRQ(DMA1_Channel3_IRQn); - dmaRx=DMA1_Channel3; - #elif defined(_ARCH_CORTEXM7_STM32H7) - RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN; // enabling DMA1 clock - RCC_SYNC(); - // enabling interrupts - dmaRx=DMA1_Stream1; - NVIC_EnableIRQ(DMA1_Stream1_IRQn); - NVIC_SetPriority(DMA1_Stream1_IRQn,14); - dmaTx=DMA1_Stream3; - NVIC_EnableIRQ(DMA1_Stream3_IRQn); - NVIC_SetPriority(DMA1_Stream3_IRQn,15); - // Configuring DMAMUX - DMAMUX1_Channel1->CCR &= ~DMAMUX_CxCR_DMAREQ_ID; - DMAMUX1_Channel1->CCR |= DMAMUX_CxCR_DMAREQ_ID_0 - | DMAMUX_CxCR_DMAREQ_ID_2 - | DMAMUX_CxCR_DMAREQ_ID_3 - | DMAMUX_CxCR_DMAREQ_ID_5; - DMAMUX1_Channel3->CCR &= ~DMAMUX_CxCR_DMAREQ_ID; - DMAMUX1_Channel3->CCR |= DMAMUX_CxCR_DMAREQ_ID_1 - | DMAMUX_CxCR_DMAREQ_ID_2 - | DMAMUX_CxCR_DMAREQ_ID_3 - | DMAMUX_CxCR_DMAREQ_ID_5; - #else //stm32f2, stm32f4 - RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN; - RCC_SYNC(); - NVIC_SetPriority(DMA1_Stream3_IRQn,15);//Lowest priority for serial - NVIC_EnableIRQ(DMA1_Stream3_IRQn); - dmaTx=DMA1_Stream3; - //Higher priority to ensure IRQhandleDMArx() is called before - //IRQhandleInterrupt(), so that idle is set correctly - NVIC_SetPriority(DMA1_Stream1_IRQn,14); - NVIC_EnableIRQ(DMA1_Stream1_IRQn); - dmaRx=DMA1_Stream1; - #endif - port->CR3=USART_CR3_DMAT | USART_CR3_DMAR; - #endif //SERIAL_3_DMA - #if !defined(STM32F072xB) && !defined(STM32L053xx) - NVIC_SetPriority(USART3_IRQn,15);//Lowest priority for serial - NVIC_EnableIRQ(USART3_IRQn); - #else //STM32F072xB - NVIC_SetPriority(USART3_4_IRQn,15); - NVIC_EnableIRQ(USART3_4_IRQn); - #endif //STM32F072xB - #if !defined(_ARCH_CORTEXM7_STM32H7) && !defined(_ARCH_CORTEXM0_STM32F0) - if(RCC->CFGR & RCC_CFGR_PPRE1_2) freq/=1<<(((RCC->CFGR>>RCC_CFGR_PPRE1_Pos) & 0x3)+1); - #elif defined(_ARCH_CORTEXM0_STM32F0) - // STM32F0 family has only PPRE2 register - if(RCC->CFGR & RCC_CFGR_PPRE_2) freq/=1<<(((RCC->CFGR>>RCC_CFGR_PPRE_Pos) & 0x3)+1); - #else //_ARCH_CORTEXM7_STM32H7 - //rcc_hclk3 = SystemCoreClock / HPRE - //rcc_pclk1 = rcc_hclk1 / D2PPRE1 - //NOTE: are rcc_hclk3 and rcc_hclk1 the same signal? - //usart2 clock is rcc_pclk1 - if(RCC->D1CFGR & RCC_D1CFGR_HPRE_3) - freq/=1<<(((RCC->D1CFGR>>RCC_D1CFGR_HPRE_Pos) & 0x7)+1); - if(RCC->D2CFGR & RCC_D2CFGR_D2PPRE1_2) - freq/=1<<(((RCC->D2CFGR>>RCC_D2CFGR_D2PPRE1_Pos) & 0x3)+1); - #endif //_ARCH_CORTEXM7_STM32H7 - break; - #endif //!defined(STM32F411xE) && !defined(STM32F401xE) && !defined(STM32F401xC) - #endif //!defined(STM32_NO_SERIAL_2_3) - } - //Quirk: stm32f1 rx pin has to be in input mode, while stm32f2 and up want - //it in ALTERNATE mode. Go figure... - #ifdef _ARCH_CORTEXM3_STM32F1 - Mode::Mode_ rxPinMode=Mode::INPUT; - #else //_ARCH_CORTEXM3_STM32F1 - Mode::Mode_ rxPinMode=Mode::ALTERNATE; - #endif //_ARCH_CORTEXM3_STM32F1 - tx.mode(Mode::ALTERNATE); - rx.mode(rxPinMode); - if(flowControl) - { - rts.mode(Mode::ALTERNATE); - cts.mode(rxPinMode); - } - const unsigned int quot=2*freq/baudrate; //2*freq for round to nearest - port->BRR=quot/2 + (quot & 1); //Round to nearest - //Quirk: some stm32 do not have onebit mode (stm32f101,f102,f103) - #ifdef USART_CR3_ONEBIT - if(flowControl==false) port->CR3 |= USART_CR3_ONEBIT; - else port->CR3 |= USART_CR3_ONEBIT | USART_CR3_RTSE | USART_CR3_CTSE; - #else - if(flowControl) port->CR3 |= USART_CR3_RTSE | USART_CR3_CTSE; - #endif - //Enabled, 8 data bit, no parity, interrupt on character rx - #ifdef SERIAL_DMA - if(dmaTx) - { - port->CR1 = USART_CR1_UE //Enable port - | USART_CR1_IDLEIE //Interrupt on idle line - | USART_CR1_TE //Transmission enbled - | USART_CR1_RE; //Reception enabled - IRQdmaReadStart(); - return; - } - #endif //SERIAL_DMA - port->CR1 = USART_CR1_UE //Enable port - | USART_CR1_RXNEIE //Interrupt on data received - | USART_CR1_IDLEIE //Interrupt on idle line - | USART_CR1_TE //Transmission enbled - | USART_CR1_RE; //Reception enabled -} - -ssize_t STM32Serial::readBlock(void *buffer, size_t size, off_t where) -{ - Lock<FastMutex> l(rxMutex); - char *buf=reinterpret_cast<char*>(buffer); - size_t result=0; - FastInterruptDisableLock dLock; - DeepSleepLock dpLock; - for(;;) - { - //Try to get data from the queue - for(;result<size;result++) - { - if(rxQueue.tryGet(buf[result])==false) break; - //This is here just not to keep IRQ disabled for the whole loop - FastInterruptEnableLock eLock(dLock); - } - if(idle && result>0) break; - if(result==size) break; - //Wait for data in the queue - do { - rxWaiting=Thread::IRQgetCurrentThread(); - Thread::IRQwait(); - { - FastInterruptEnableLock eLock(dLock); - Thread::yield(); - } - } while(rxWaiting); - } - return result; -} - -ssize_t STM32Serial::writeBlock(const void *buffer, size_t size, off_t where) -{ - Lock<FastMutex> l(txMutex); - DeepSleepLock dpLock; - const char *buf=reinterpret_cast<const char*>(buffer); - #ifdef SERIAL_DMA - if(dmaTx) - { - size_t remaining=size; - if(isInCCMarea(buf)==false) - { - //Use zero copy for all but the last txBufferSize bytes, if possible - while(remaining>txBufferSize) - { - //DMA is limited to 64K - size_t transferSize=min<size_t>(remaining-txBufferSize,65535); - waitDmaTxCompletion(); - writeDma(buf,transferSize); - buf+=transferSize; - remaining-=transferSize; - } - } - while(remaining>0) - { - size_t transferSize=min(remaining,static_cast<size_t>(txBufferSize)); - waitDmaTxCompletion(); - //Copy to txBuffer only after DMA xfer completed, as the previous - //xfer may be using the same buffer - memcpy(txBuffer,buf,transferSize); - writeDma(txBuffer,transferSize); - buf+=transferSize; - remaining-=transferSize; - } - #ifdef WITH_DEEP_SLEEP - //The serial driver by default can return even though the last part of - //the data is still being transmitted by the DMA. When using deep sleep - //however the DMA operation needs to be fully enclosed by a deep sleep - //lock to prevent the scheduler from stopping peripheral clocks. - waitDmaTxCompletion(); - waitSerialTxFifoEmpty(); //TODO: optimize by doing it only when entering deep sleep - #endif //WITH_DEEP_SLEEP - return size; - } - #endif //SERIAL_DMA - for(size_t i=0;i<size;i++) - { - #if !defined(_ARCH_CORTEXM7_STM32F7) && !defined(_ARCH_CORTEXM7_STM32H7) \ - && !defined(_ARCH_CORTEXM0_STM32F0) && !defined(_ARCH_CORTEXM4_STM32F3) \ - && !defined(_ARCH_CORTEXM4_STM32L4) && !defined(_ARCH_CORTEXM0PLUS_STM32L0) - while((port->SR & USART_SR_TXE)==0) ; - port->DR=*buf++; - #elif defined(_ARCH_CORTEXM7_STM32H7) - while((port->ISR & USART_ISR_TXE_TXFNF)==0) ; - port->TDR=*buf++; - #else //_ARCH_CORTEXM7_STM32F7/H7 - while((port->ISR & USART_ISR_TXE)==0) ; - port->TDR=*buf++; - #endif //_ARCH_CORTEXM7_STM32F7/H7 - } - return size; -} - -void STM32Serial::IRQwrite(const char *str) -{ - // We can reach here also with only kernel paused, so make sure - // interrupts are disabled. This is important for the DMA case - bool interrupts=areInterruptsEnabled(); - if(interrupts) fastDisableInterrupts(); - #ifdef SERIAL_DMA - if(dmaTx) - { - #if defined(_ARCH_CORTEXM3_STM32F1) || defined(_ARCH_CORTEXM4_STM32F3) \ - || defined(_ARCH_CORTEXM4_STM32L4) - //If no DMA transfer is in progress bit EN is zero. Otherwise wait until - //DMA xfer ends, by waiting for the TC (or TE) interrupt flag - static const unsigned int irqMask[]= - { - (DMA_ISR_TCIF4 | DMA_ISR_TEIF4), - (DMA_ISR_TCIF7 | DMA_ISR_TEIF7), - (DMA_ISR_TCIF2 | DMA_ISR_TEIF2) - }; - #if !defined(_ARCH_CORTEXM3_STM32L1) - // Workaround for ST messing up with flag definitions... - constexpr unsigned int DMA_CCR4_EN = DMA_CCR_EN; - #endif - while((dmaTx->CCR & DMA_CCR4_EN) && !(DMA1->ISR & irqMask[getId()-1])) ; - #else //_ARCH_CORTEXM3_STM32F1 - //Wait until DMA xfer ends. EN bit is cleared by hardware on transfer end - while(dmaTx->CR & DMA_SxCR_EN) ; - #endif //_ARCH_CORTEXM3_STM32F1 - } - #endif //SERIAL_DMA - while(*str) - { - #if !defined(_ARCH_CORTEXM7_STM32F7) && !defined(_ARCH_CORTEXM7_STM32H7) \ - && !defined(_ARCH_CORTEXM0_STM32F0) && !defined(_ARCH_CORTEXM4_STM32F3) \ - && !defined(_ARCH_CORTEXM4_STM32L4) && !defined(_ARCH_CORTEXM0PLUS_STM32L0) - while((port->SR & USART_SR_TXE)==0) ; - port->DR=*str++; - #elif defined(_ARCH_CORTEXM7_STM32H7) - while((port->ISR & USART_ISR_TXE_TXFNF)==0) ; - port->TDR=*str++; - #else //_ARCH_CORTEXM7_STM32F7/H7 - while((port->ISR & USART_ISR_TXE)==0) ; - port->TDR=*str++; - #endif //_ARCH_CORTEXM7_STM32F7/H7 - } - waitSerialTxFifoEmpty(); - if(interrupts) fastEnableInterrupts(); -} - -int STM32Serial::ioctl(int cmd, void* arg) -{ - if(reinterpret_cast<unsigned>(arg) & 0b11) return -EFAULT; //Unaligned - termios *t=reinterpret_cast<termios*>(arg); - switch(cmd) - { - case IOCTL_SYNC: - waitSerialTxFifoEmpty(); - return 0; - case IOCTL_TCGETATTR: - t->c_iflag=IGNBRK | IGNPAR; - t->c_oflag=0; - t->c_cflag=CS8 | (flowControl ? CRTSCTS : 0); - t->c_lflag=0; - return 0; - case IOCTL_TCSETATTR_NOW: - case IOCTL_TCSETATTR_DRAIN: - case IOCTL_TCSETATTR_FLUSH: - //Changing things at runtime unsupported, so do nothing, but don't - //return error as console_device.h implements some attribute changes - return 0; - default: - return -ENOTTY; //Means the operation does not apply to this descriptor - } -} - -void STM32Serial::IRQhandleInterrupt() -{ - #if !defined(_ARCH_CORTEXM7_STM32F7) && !defined(_ARCH_CORTEXM7_STM32H7) \ - && !defined(_ARCH_CORTEXM0_STM32F0) && !defined(_ARCH_CORTEXM4_STM32F3) \ - && !defined(_ARCH_CORTEXM4_STM32L4) && !defined(_ARCH_CORTEXM0PLUS_STM32L0) - unsigned int status=port->SR; - #elif defined(_ARCH_CORTEXM7_STM32H7) - unsigned int status=port->ISR; - constexpr unsigned int USART_SR_RXNE=USART_ISR_RXNE_RXFNE; - constexpr unsigned int USART_SR_IDLE=USART_ISR_IDLE; - constexpr unsigned int USART_SR_FE =USART_ISR_FE; - #else //_ARCH_CORTEXM7_STM32F7/H7 - unsigned int status=port->ISR; - constexpr unsigned int USART_SR_RXNE=USART_ISR_RXNE; - constexpr unsigned int USART_SR_IDLE=USART_ISR_IDLE; - constexpr unsigned int USART_SR_FE =USART_ISR_FE; - #endif //_ARCH_CORTEXM7_STM32F7/H7 - char c; - #ifdef SERIAL_DMA - if(dmaRx==0 && (status & USART_SR_RXNE)) - #else //SERIAL_DMA - if(status & USART_SR_RXNE) - #endif //SERIAL_DMA - { - //Always read data, since this clears interrupt flags - #if !defined(_ARCH_CORTEXM7_STM32F7) && !defined(_ARCH_CORTEXM7_STM32H7) \ - && !defined(_ARCH_CORTEXM0_STM32F0) && !defined(_ARCH_CORTEXM4_STM32F3) \ - && !defined(_ARCH_CORTEXM4_STM32L4) && !defined(_ARCH_CORTEXM0PLUS_STM32L0) - c=port->DR; - #else //_ARCH_CORTEXM7_STM32F7/H7 - c=port->RDR; - #endif //_ARCH_CORTEXM7_STM32F7/H7 - //If no error put data in buffer - if((status & USART_SR_FE)==0) - if(rxQueue.tryPut(c)==false) /*fifo overflow*/; - idle=false; - } - if(status & USART_SR_IDLE) - { - #if !defined(_ARCH_CORTEXM7_STM32F7) && !defined(_ARCH_CORTEXM7_STM32H7) \ - && !defined(_ARCH_CORTEXM0_STM32F0) && !defined(_ARCH_CORTEXM4_STM32F3) \ - && !defined(_ARCH_CORTEXM4_STM32L4) && !defined(_ARCH_CORTEXM0PLUS_STM32L0) - c=port->DR; //clears interrupt flags - #else //_ARCH_CORTEXM7_STM32F7/H7 - port->ICR=USART_ICR_IDLECF; //clears interrupt flags - #endif //_ARCH_CORTEXM7_STM32F7/H7 - #ifdef SERIAL_DMA - if(dmaRx) IRQreadDma(); - #endif //SERIAL_DMA - idle=true; - } - if((status & USART_SR_IDLE) || rxQueue.size()>=rxQueueMin) - { - //Enough data in buffer or idle line, awake thread - if(rxWaiting) - { - rxWaiting->IRQwakeup(); - if(rxWaiting->IRQgetPriority()> - Thread::IRQgetCurrentThread()->IRQgetPriority()) - Scheduler::IRQfindNextThread(); - rxWaiting=0; - } - } -} - -#ifdef SERIAL_DMA -void STM32Serial::IRQhandleDMAtx() -{ - dmaTxInProgress=false; - if(txWaiting==0) return; - txWaiting->IRQwakeup(); - if(txWaiting->IRQgetPriority()>Thread::IRQgetCurrentThread()->IRQgetPriority()) - Scheduler::IRQfindNextThread(); - txWaiting=0; -} - -void STM32Serial::IRQhandleDMArx() -{ - IRQreadDma(); - idle=false; - if(rxWaiting==0) return; - rxWaiting->IRQwakeup(); - if(rxWaiting->IRQgetPriority()>Thread::IRQgetCurrentThread()->IRQgetPriority()) - Scheduler::IRQfindNextThread(); - rxWaiting=0; -} -#endif //SERIAL_DMA - -STM32Serial::~STM32Serial() -{ - waitSerialTxFifoEmpty(); - { - InterruptDisableLock dLock; - port->CR1=0; - int id=getId(); - ports[id-1]=0; - switch(id) - { - case 1: - #ifdef SERIAL_1_DMA - IRQdmaReadStop(); - #if defined(_ARCH_CORTEXM3_STM32F1) || defined(_ARCH_CORTEXM4_STM32F3) \ - || defined(_ARCH_CORTEXM4_STM32L4) - NVIC_DisableIRQ(DMA1_Channel4_IRQn); - NVIC_ClearPendingIRQ(DMA1_Channel4_IRQn); - NVIC_DisableIRQ(DMA1_Channel5_IRQn); - NVIC_ClearPendingIRQ(DMA1_Channel5_IRQn); - #elif defined(_ARCH_CORTEXM7_STM32H7) - NVIC_DisableIRQ(DMA1_Stream7_IRQn); - NVIC_ClearPendingIRQ(DMA1_Stream7_IRQn); - NVIC_DisableIRQ(DMA1_Stream5_IRQn); - NVIC_ClearPendingIRQ(DMA1_Stream5_IRQn); - #else //stm32f2, stm32f4 - NVIC_DisableIRQ(DMA2_Stream7_IRQn); - NVIC_ClearPendingIRQ(DMA2_Stream7_IRQn); - NVIC_DisableIRQ(DMA2_Stream5_IRQn); - NVIC_ClearPendingIRQ(DMA2_Stream5_IRQn); - #endif - #endif //SERIAL_1_DMA - NVIC_DisableIRQ(USART1_IRQn); - NVIC_ClearPendingIRQ(USART1_IRQn); - RCC->APB2ENR &= ~RCC_APB2ENR_USART1EN; - break; - - #if !defined(STM32_NO_SERIAL_2_3) - case 2: - #ifdef SERIAL_2_DMA - IRQdmaReadStop(); - #if defined(_ARCH_CORTEXM3_STM32F1) || defined(_ARCH_CORTEXM4_STM32F3) \ - || defined(_ARCH_CORTEXM4_STM32L4) - NVIC_DisableIRQ(DMA1_Channel7_IRQn); - NVIC_ClearPendingIRQ(DMA1_Channel7_IRQn); - NVIC_DisableIRQ(DMA1_Channel6_IRQn); - NVIC_ClearPendingIRQ(DMA1_Channel6_IRQn); - #else //stm32f2, stm32f4 - NVIC_DisableIRQ(DMA1_Stream6_IRQn); - NVIC_ClearPendingIRQ(DMA1_Stream6_IRQn); - NVIC_DisableIRQ(DMA1_Stream5_IRQn); - NVIC_ClearPendingIRQ(DMA1_Stream5_IRQn); - #endif - #endif //SERIAL_2_DMA - NVIC_DisableIRQ(USART2_IRQn); - NVIC_ClearPendingIRQ(USART2_IRQn); - #ifndef _ARCH_CORTEXM7_STM32H7 - #ifdef _ARCH_CORTEXM4_STM32L4 - RCC->APB1ENR1 &= ~RCC_APB1ENR1_USART2EN; - #else - RCC->APB1ENR &= ~RCC_APB1ENR_USART2EN; - #endif - #else //_ARCH_CORTEXM7_STM32H7 - RCC->APB1LENR &= ~RCC_APB1LENR_USART2EN; - #endif //_ARCH_CORTEXM7_STM32H7 - break; - #if !defined(STM32F411xE) && !defined(STM32F401xE) && !defined(STM32F401xC) && !defined(STM32L053xx) - case 3: - #ifdef SERIAL_3_DMA - IRQdmaReadStop(); - #if defined(_ARCH_CORTEXM3_STM32F1) || defined(_ARCH_CORTEXM4_STM32F3) \ - || defined(_ARCH_CORTEXM4_STM32L4) - NVIC_DisableIRQ(DMA1_Channel2_IRQn); - NVIC_ClearPendingIRQ(DMA1_Channel2_IRQn); - NVIC_DisableIRQ(DMA1_Channel3_IRQn); - NVIC_ClearPendingIRQ(DMA1_Channel3_IRQn); - #else //stm32f2, stm32f4 - NVIC_DisableIRQ(DMA1_Stream3_IRQn); - NVIC_ClearPendingIRQ(DMA1_Stream3_IRQn); - NVIC_DisableIRQ(DMA1_Stream1_IRQn); - NVIC_ClearPendingIRQ(DMA1_Stream1_IRQn); - #endif - #endif //SERIAL_3_DMA - #if !defined(STM32F072xB) - NVIC_SetPriority(USART3_IRQn,15);//Lowest priority for serial - NVIC_EnableIRQ(USART3_IRQn); - #else //STM32F072xB - NVIC_SetPriority(USART3_4_IRQn,15); - NVIC_EnableIRQ(USART3_4_IRQn); - #endif //STM32F072xB - #ifndef _ARCH_CORTEXM7_STM32H7 - #ifdef _ARCH_CORTEXM4_STM32L4 - RCC->APB1ENR1 &= ~RCC_APB1ENR1_USART3EN; - #else - RCC->APB1ENR &= ~RCC_APB1ENR_USART3EN; - #endif - #else //_ARCH_CORTEXM7_STM32H7 - RCC->APB1LENR &= ~RCC_APB1LENR_USART3EN; - #endif //_ARCH_CORTEXM7_STM32H7 - break; - #endif //!defined(STM32F411xE) && !defined(STM32F401xE) && !defined(STM32F401xC) - #endif //!defined(STM32_NO_SERIAL_2_3) - } - } -} - -#ifdef SERIAL_DMA -void STM32Serial::waitDmaTxCompletion() -{ - FastInterruptDisableLock dLock; - // If a previous DMA xfer is in progress, wait - if(dmaTxInProgress) - { - txWaiting=Thread::IRQgetCurrentThread(); - do { - Thread::IRQwait(); - { - FastInterruptEnableLock eLock(dLock); - Thread::yield(); - } - } while(txWaiting); - } -} - -void STM32Serial::writeDma(const char *buffer, size_t size) -{ - markBufferBeforeDmaWrite(buffer,size); - //Quirk: DMA messes up the TC bit, and causes waitSerialTxFifoEmpty() to - //return prematurely, causing characters to be missed when rebooting - //immediately a write. You can just clear the bit manually, but doing that - //is dangerous, as if you clear the bit but for any reason the serial - //write doesn't start (think an invalid buffer, or another thread crashing), - //then TC will never be set and waitSerialTxFifoEmpty() deadlocks! - //The only way to clear it safely is to first read SR and then write to - //DR (thus the bit is cleared at the same time a transmission is started, - //and the race condition is eliminated). This is the purpose of this - //instruction, it reads SR. When we start the DMA, the DMA controller - //writes to DR and completes the TC clear sequence. - DeepSleepLock dpLock; - #if !defined(_ARCH_CORTEXM7_STM32F7) && !defined(_ARCH_CORTEXM7_STM32H7) \ - && !defined(_ARCH_CORTEXM0_STM32F0) && !defined(_ARCH_CORTEXM4_STM32F3) \ - && !defined(_ARCH_CORTEXM4_STM32L4) - while((port->SR & USART_SR_TXE)==0) ; - #elif defined(_ARCH_CORTEXM7_STM32H7) - while((port->ISR & USART_ISR_TXE_TXFNF)==0) ; - #else //_ARCH_CORTEXM7_STM32F7/H7 - while((port->ISR & USART_ISR_TXE)==0) ; - #endif //_ARCH_CORTEXM7_STM32F7/H7 - - dmaTxInProgress=true; - #if defined(_ARCH_CORTEXM3_STM32F1) || defined(_ARCH_CORTEXM4_STM32F3) || \ - defined(_ARCH_CORTEXM4_STM32L4) - #if defined(_ARCH_CORTEXM3_STM32F1) - dmaTx->CPAR=reinterpret_cast<unsigned int>(&port->DR); - #else - dmaTx->CPAR=reinterpret_cast<unsigned int>(&port->TDR); - #endif - dmaTx->CMAR=reinterpret_cast<unsigned int>(buffer); - dmaTx->CNDTR=size; - dmaTx->CCR = DMA_CCR_MINC //Increment RAM pointer - | DMA_CCR_DIR //Memory to peripheral - | DMA_CCR_TEIE //Interrupt on transfer error - | DMA_CCR_TCIE //Interrupt on transfer complete - | DMA_CCR_EN; //Start DMA - #else //_ARCH_CORTEXM4_STM32F3 - #if !defined(_ARCH_CORTEXM7_STM32F7) && !defined(_ARCH_CORTEXM7_STM32H7) \ - && !defined(_ARCH_CORTEXM0_STM32F0) - dmaTx->PAR=reinterpret_cast<unsigned int>(&port->DR); - #else //_ARCH_CORTEXM7_STM32F7/H7 - dmaTx->PAR=reinterpret_cast<unsigned int>(&port->TDR); - #endif //_ARCH_CORTEXM7_STM32F7/H7 - dmaTx->M0AR=reinterpret_cast<unsigned int>(buffer); - dmaTx->NDTR=size; - //Quirk: not enabling DMA_SxFCR_FEIE because the USART seems to - //generate a spurious fifo error. The code was tested and the - //transfer completes successfully even in the presence of this fifo - //error - dmaTx->FCR=DMA_SxFCR_DMDIS;//Enable fifo - #ifndef _ARCH_CORTEXM7_STM32H7 - dmaTx->CR = DMA_SxCR_CHSEL_2 //Select channel 4 (USART_TX) - | DMA_SxCR_MINC //Increment RAM pointer - | DMA_SxCR_DIR_0 //Memory to peripheral - | DMA_SxCR_TCIE //Interrupt on completion - | DMA_SxCR_TEIE //Interrupt on transfer error - | DMA_SxCR_DMEIE //Interrupt on direct mode error - | DMA_SxCR_EN; //Start the DMA - #else - dmaTx->CR = DMA_SxCR_MINC //Increment RAM pointer - | DMA_SxCR_DIR_0 //Memory to peripheral - | DMA_SxCR_TCIE //Interrupt on completion - | DMA_SxCR_TEIE //Interrupt on transfer error - | DMA_SxCR_DMEIE //Interrupt on direct mode error - | DMA_SxCR_EN; //Start the DMA - #endif //_ARCH_CORTEXM7_STM32H7 - #endif //_ARCH_CORTEXM4_STM32F3 -} - -void STM32Serial::IRQreadDma() -{ - int elem=IRQdmaReadStop(); - markBufferAfterDmaRead(rxBuffer,rxQueueMin); - for(int i=0;i<elem;i++) - if(rxQueue.tryPut(rxBuffer[i])==false) /*fifo overflow*/; - IRQdmaReadStart(); -} - -void STM32Serial::IRQdmaReadStart() -{ - #if defined(_ARCH_CORTEXM3_STM32F1) || defined(_ARCH_CORTEXM4_STM32F3) || \ - defined(_ARCH_CORTEXM4_STM32L4) - #if defined(_ARCH_CORTEXM3_STM32F1) - dmaRx->CPAR=reinterpret_cast<unsigned int>(&port->DR); - #else - dmaRx->CPAR=reinterpret_cast<unsigned int>(&port->RDR); - #endif - dmaRx->CMAR=reinterpret_cast<unsigned int>(rxBuffer); - dmaRx->CNDTR=rxQueueMin; - dmaRx->CCR = DMA_CCR_MINC //Increment RAM pointer - | 0 //Peripheral to memory - | DMA_CCR_TEIE //Interrupt on transfer error - | DMA_CCR_TCIE //Interrupt on transfer complete - | DMA_CCR_EN; //Start DMA - #else //_ARCH_CORTEXM4_STM32F3 - #if !defined(_ARCH_CORTEXM7_STM32F7) && !defined(_ARCH_CORTEXM7_STM32H7) \ - && !defined(_ARCH_CORTEXM0_STM32F0) - dmaRx->PAR=reinterpret_cast<unsigned int>(&port->DR); - #else //_ARCH_CORTEXM7_STM32F7/H7 - dmaRx->PAR=reinterpret_cast<unsigned int>(&port->RDR); - #endif //_ARCH_CORTEXM7_STM32F7/H7 - dmaRx->M0AR=reinterpret_cast<unsigned int>(rxBuffer); - dmaRx->NDTR=rxQueueMin; - #ifndef _ARCH_CORTEXM7_STM32H7 - dmaRx->CR = DMA_SxCR_CHSEL_2 //Select channel 2 (USART_RX) - | DMA_SxCR_MINC //Increment RAM pointer - | 0 //Peripheral to memory - | DMA_SxCR_HTIE //Interrupt on half transfer - | DMA_SxCR_TEIE //Interrupt on transfer error - | DMA_SxCR_DMEIE //Interrupt on direct mode error - | DMA_SxCR_EN; //Start the DMA - #else - dmaRx->CR = DMA_SxCR_MINC //Increment RAM pointer - | 0 //Peripheral to memory - | DMA_SxCR_HTIE //Interrupt on half transfer - | DMA_SxCR_TEIE //Interrupt on transfer error - | DMA_SxCR_DMEIE //Interrupt on direct mode error - | DMA_SxCR_EN; //Start the DMA - #endif // _ARCH_CORTEXM7_STM32H7 - #endif //_ARCH_CORTEXM4_STM32F3 -} - -int STM32Serial::IRQdmaReadStop() -{ - #if defined(_ARCH_CORTEXM3_STM32F1) || defined(_ARCH_CORTEXM4_STM32F3) \ - || defined(_ARCH_CORTEXM4_STM32L4) - dmaRx->CCR=0; - static const unsigned int irqMask[]= - { - DMA_IFCR_CGIF5, - DMA_IFCR_CGIF6, - DMA_IFCR_CGIF3 - }; - DMA1->IFCR=irqMask[getId()-1]; - return rxQueueMin-dmaRx->CNDTR; - #else //_ARCH_CORTEXM3_STM32F1 - //Stop DMA and wait for it to actually stop - dmaRx->CR &= ~DMA_SxCR_EN; - while(dmaRx->CR & DMA_SxCR_EN) ; - - - #ifdef _ARCH_CORTEXM7_STM32H7 - static const unsigned int irqMask[]= - { - (DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5), - (DMA_HIFCR_CTCIF4 | DMA_HIFCR_CHTIF4 | DMA_HIFCR_CTEIF4 | DMA_HIFCR_CDMEIF4 | DMA_HIFCR_CFEIF4), - (DMA_LIFCR_CTCIF1 | DMA_LIFCR_CHTIF1 | DMA_LIFCR_CTEIF1 | DMA_LIFCR_CDMEIF1 | DMA_LIFCR_CFEIF1) - }; - #else - static const unsigned int irqMask[]= - { - (DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5), - (DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5 | DMA_HIFCR_CTEIF5 | DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5), - (DMA_LIFCR_CTCIF1 | DMA_LIFCR_CHTIF1 | DMA_LIFCR_CTEIF1 | DMA_LIFCR_CDMEIF1 | DMA_LIFCR_CFEIF1) - }; - #endif - - #ifdef _ARCH_CORTEXM7_STM32H7 - static volatile unsigned long * const irqRegs[]= - { - &DMA1->HIFCR, - &DMA1->HIFCR, - &DMA1->LIFCR - }; - #else - static volatile unsigned long * const irqRegs[]= - { - &DMA2->HIFCR, - &DMA1->HIFCR, - &DMA1->LIFCR - }; - #endif - *irqRegs[getId()-1]=irqMask[getId()-1]; - return rxQueueMin-dmaRx->NDTR; - #endif //_ARCH_CORTEXM3_STM32F1 -} -#endif //SERIAL_DMA - -} //namespace miosix diff --git a/miosix/arch/common/drivers/serial_stm32.h b/miosix/arch/common/drivers/serial_stm32.h deleted file mode 100644 index 9b2ab44b15874f4245c7b63edd28a0e50c9ee121..0000000000000000000000000000000000000000 --- a/miosix/arch/common/drivers/serial_stm32.h +++ /dev/null @@ -1,296 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2010-2018 by Terraneo Federico * - * * - * This program 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 2 of the License, or * - * (at your option) any later version. * - * * - * This program 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. * - * * - * As a special exception, if other files instantiate templates or use * - * macros or inline functions from this file, or you compile this file * - * and link it with other works to produce a work based on this file, * - * this file does not by itself cause the resulting work to be covered * - * by the GNU General Public License. However the source code for this * - * file must still be made available in accordance with the GNU General * - * Public License. This exception does not invalidate any other reasons * - * why a work based on this file might be covered by the GNU General * - * Public License. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, see <http://www.gnu.org/licenses/> * - ***************************************************************************/ - -#ifndef SERIAL_STM32_H -#define SERIAL_STM32_H - -#include "filesystem/console/console_device.h" -#include "kernel/sync.h" -#include "kernel/queue.h" -#include "interfaces/gpio.h" -#include "board_settings.h" - -#if defined(_ARCH_CORTEXM3_STM32F1) && defined(__ENABLE_XRAM) -//Quirk: concurrent access to the FSMC from both core and DMA is broken in -//the stm32f1, so disable DMA mode if XRAM is enabled. -#undef SERIAL_1_DMA -#undef SERIAL_2_DMA -#undef SERIAL_3_DMA -#endif - -#if defined(SERIAL_1_DMA) || defined(SERIAL_2_DMA) || defined(SERIAL_3_DMA) -#define SERIAL_DMA -#endif - -#if defined(SERIAL_DMA) && defined(_ARCH_CORTEXM0_STM32F0) \ - && defined(_ARCH_CORTEXM0PLUS_STM32L0) -#undef SERIAL_1_DMA -#undef SERIAL_2_DMA -#undef SERIAL_3_DMA -#undef SERIAL_DMA -#warning "DMA not yet implemented for STM32F0/STM32L0 family" -#endif - -namespace miosix { - -/** - * Serial port class for stm32 microcontrollers. - * Only supports USART1, USART2 and USART3 - * Additionally, USARTx can use DMA if SERIAL_x_DMA is defined in - * board_settings.h, while the other serial use polling for transmission, - * and interrupt for reception. - * - * Classes of this type are reference counted, must be allocated on the heap - * and managed through intrusive_ref_ptr<FileBase> - */ -class STM32Serial : public Device -{ -public: - enum FlowCtrl - { - NOFLOWCTRL, ///< No hardware flow control - RTSCTS ///< RTS/CTS hardware flow control - }; - - /** - * Constructor, initializes the serial port using the default pins, which - * are: - * USART1: tx=PA9 rx=PA10 cts=PA11 rts=PA12 - * USART2: tx=PA2 rx=PA3 cts=PA0 rts=PA1 - * USART3: tx=PB10 rx=PB11 cts=PB13 rts=PB14 - * If you board has a different mapping, use one of the other constructors. - * - * Calls errorHandler(UNEXPECTED) if id is not in the correct range, or when - * attempting to construct multiple objects with the same id. That is, - * it is possible to instantiate only one instance of this class for each - * hardware USART. - * \param id a number 1 to 3 to select which USART - * \param baudrate serial port baudrate - * \param flowControl to enable hardware flow control on this port - */ - STM32Serial(int id, int baudrate, FlowCtrl flowControl=NOFLOWCTRL); - - /** - * Constructor, initializes the serial port using remapped pins and disables - * flow control. - * - * NOTE: for stm32f2, f4, f7 and h7 you have to set the correct alternate - * function to the pins in order to connect then to the USART peripheral - * before passing them to this class. - * - * Calls errorHandler(UNEXPECTED) if id is not in the correct range, or when - * attempting to construct multiple objects with the same id. That is, - * it is possible to instantiate only one instance of this class for each - * hardware USART. - * \param id a number 1 to 3 to select which USART - * \param baudrate serial port baudrate - * \param tx tx pin - * \param rx rx pin - */ - STM32Serial(int id, int baudrate, miosix::GpioPin tx, miosix::GpioPin rx); - - /** - * Constructor, initializes the serial port using remapped pins and enables - * flow control. - * - * NOTE: for stm32f2, f4, f7 and h7 you have to set the correct alternate - * function to the pins in order to connect then to the USART peripheral - * before passing them to this class. - * - * Calls errorHandler(UNEXPECTED) if id is not in the correct range, or when - * attempting to construct multiple objects with the same id. That is, - * it is possible to instantiate only one instance of this class for each - * hardware USART. - * \param id a number 1 to 3 to select which USART - * \param tx tx pin - * \param rx rx pin - * \param rts rts pin - * \param cts cts pin - */ - STM32Serial(int id, int baudrate, miosix::GpioPin tx, miosix::GpioPin rx, - miosix::GpioPin rts, miosix::GpioPin cts); - - /** - * Read a block of data - * \param buffer buffer where read data will be stored - * \param size buffer size - * \param where where to read from - * \return number of bytes read or a negative number on failure. Note that - * it is normal for this function to return less character than the amount - * asked - */ - ssize_t readBlock(void *buffer, size_t size, off_t where); - - /** - * Write a block of data - * \param buffer buffer where take data to write - * \param size buffer size - * \param where where to write to - * \return number of bytes written or a negative number on failure - */ - ssize_t writeBlock(const void *buffer, size_t size, off_t where); - - /** - * Write a string. - * An extension to the Device interface that adds a new member function, - * which is used by the kernel on console devices to write debug information - * before the kernel is started or in case of serious errors, right before - * rebooting. - * Can ONLY be called when the kernel is not yet started, paused or within - * an interrupt. This default implementation ignores writes. - * \param str the string to write. The string must be NUL terminated. - */ - void IRQwrite(const char *str); - - /** - * Performs device-specific operations - * \param cmd specifies the operation to perform - * \param arg optional argument that some operation require - * \return the exact return value depends on CMD, -1 is returned on error - */ - int ioctl(int cmd, void *arg); - - /** - * \internal the serial port interrupts call this member function. - * Never call this from user code. - */ - void IRQhandleInterrupt(); - - #ifdef SERIAL_DMA - /** - * \internal the serial port DMA tx interrupts call this member function. - * Never call this from user code. - */ - void IRQhandleDMAtx(); - - /** - * \internal the serial port DMA rx interrupts call this member function. - * Never call this from user code. - */ - void IRQhandleDMArx(); - #endif //SERIAL_DMA - - /** - * \return port id, 1 for USART1, 2 for USART2, ... - */ - int getId() const { return portId; } - - /** - * Destructor - */ - ~STM32Serial(); - -private: - /** - * Code common for all constructors - */ - void commonInit(int id, int baudrate, miosix::GpioPin tx, miosix::GpioPin rx, - miosix::GpioPin rts, miosix::GpioPin cts); - - #ifdef SERIAL_DMA - /** - * Wait until a pending DMA TX completes, if any - */ - void waitDmaTxCompletion(); - - /** - * Write to the serial port using DMA. When the function returns, the DMA - * transfer is still in progress. - * \param buffer buffer to write - * \param size size of buffer to write - */ - void writeDma(const char *buffer, size_t size); - - /** - * Read from DMA buffer and write data to queue - */ - void IRQreadDma(); - - /** - * Start DMA read - */ - void IRQdmaReadStart(); - - /** - * Stop DMA read - * \return the number of characters in rxBuffer - */ - int IRQdmaReadStop(); - #endif //SERIAL_DMA - - /** - * Wait until all characters have been written to the serial port. - * Needs to be callable from interrupts disabled (it is used in IRQwrite) - */ - void waitSerialTxFifoEmpty() - { - #if !defined(_ARCH_CORTEXM7_STM32F7) && !defined(_ARCH_CORTEXM7_STM32H7) \ - && !defined(_ARCH_CORTEXM0_STM32F0) && !defined(_ARCH_CORTEXM4_STM32F3) \ - && !defined(_ARCH_CORTEXM4_STM32L4) && !defined(_ARCH_CORTEXM0PLUS_STM32L0) - while((port->SR & USART_SR_TC)==0) ; - #else //_ARCH_CORTEXM7_STM32F7/H7 - while((port->ISR & USART_ISR_TC)==0) ; - #endif //_ARCH_CORTEXM7_STM32F7/H7 - } - - FastMutex txMutex; ///< Mutex locked during transmission - FastMutex rxMutex; ///< Mutex locked during reception - - DynUnsyncQueue<char> rxQueue; ///< Receiving queue - static const unsigned int rxQueueMin=16; ///< Minimum queue size - Thread *rxWaiting=0; ///< Thread waiting for rx, or 0 - - USART_TypeDef *port; ///< Pointer to USART peripheral - #ifdef SERIAL_DMA - #if defined(_ARCH_CORTEXM3_STM32F1) || defined(_ARCH_CORTEXM4_STM32F3) \ - || defined(_ARCH_CORTEXM4_STM32L4) - DMA_Channel_TypeDef *dmaTx; ///< Pointer to DMA TX peripheral - DMA_Channel_TypeDef *dmaRx; ///< Pointer to DMA RX peripheral - #else //_ARCH_CORTEXM3_STM32F1 and _ARCH_CORTEXM4_STM32F3 - DMA_Stream_TypeDef *dmaTx; ///< Pointer to DMA TX peripheral - DMA_Stream_TypeDef *dmaRx; ///< Pointer to DMA RX peripheral - #endif //_ARCH_CORTEXM3_STM32F1 and _ARCH_CORTEXM4_STM32F3 - Thread *txWaiting; ///< Thread waiting for tx, or 0 - static const unsigned int txBufferSize=16; ///< Size of tx buffer, for tx speedup - /// Tx buffer, for tx speedup. This buffer must not end up in the CCM of the - /// STM32F4, as it is used to perform DMA operations. This is guaranteed by - /// the fact that this class must be allocated on the heap as it derives - /// from Device, and the Miosix linker scripts never put the heap in CCM - char txBuffer[txBufferSize]; - /// This buffer emulates the behaviour of a 16550. It is filled using DMA - /// and an interrupt is fired as soon as it is half full - char rxBuffer[rxQueueMin]; - bool dmaTxInProgress; ///< True if a DMA tx is in progress - #endif //SERIAL_DMA - bool idle=true; ///< Receiver idle - const bool flowControl; ///< True if flow control GPIOs enabled - const unsigned char portId; ///< 1 for USART1, 2 for USART2, ... -}; - -} //namespace miosix - -#endif //SERIAL_STM32_H