diff --git a/radio/src/hal/serial_driver.h b/radio/src/hal/serial_driver.h index 98119f6b6..e3d19672a 100644 --- a/radio/src/hal/serial_driver.h +++ b/radio/src/hal/serial_driver.h @@ -51,7 +51,14 @@ struct etx_serial_init { void (*on_error)(); // = nullptr; }; +struct etx_serial_callbacks_t { + bool (*on_send)(uint8_t& data); + void (*on_receive)(uint8_t data); + void (*on_error)(); +}; + struct etx_serial_driver_t { + // Init module communication void (*init)(const etx_serial_init* params); diff --git a/radio/src/targets/common/arm/stm32/extmodule_serial_driver.cpp b/radio/src/targets/common/arm/stm32/extmodule_serial_driver.cpp index 30a83e712..8453aba48 100644 --- a/radio/src/targets/common/arm/stm32/extmodule_serial_driver.cpp +++ b/radio/src/targets/common/arm/stm32/extmodule_serial_driver.cpp @@ -29,13 +29,10 @@ #include "io/frsky_pxx2.h" ModuleFifo extmoduleFifo; -struct etx_serial_callbacks_t { - void (*on_receive)(uint8_t data); - void (*on_error)(); +static etx_serial_callbacks_t extmodule_driver = { + nullptr, nullptr, nullptr }; -static etx_serial_callbacks_t extmodule_driver = { nullptr, nullptr }; - void extmoduleFifoReceive(uint8_t data) { extmoduleFifo.push(data); @@ -56,6 +53,25 @@ static const etx_serial_init extmoduleSerialParams = { .on_error = extmoduleFifoError, }; +static const LL_GPIO_InitTypeDef extmoduleUSART_PinDef = { + .Pin = EXTMODULE_TX_GPIO_PIN | EXTMODULE_RX_GPIO_PIN, + .Mode = LL_GPIO_MODE_ALTERNATE, + .Speed = LL_GPIO_SPEED_FREQ_LOW, + .OutputType = LL_GPIO_OUTPUT_PUSHPULL, + .Pull = LL_GPIO_PULL_UP, + .Alternate = EXTMODULE_USART_GPIO_AF_LL, +}; + +static const stm32_usart_t extmoduleUSART = { + .USARTx = EXTMODULE_USART, + .GPIOx = EXTMODULE_TX_GPIO, + .pinInit = &extmoduleUSART_PinDef, + .IRQn = EXTMODULE_USART_IRQn, + .DMAx = EXTMODULE_USART_TX_DMA, + .DMA_Stream = EXTMODULE_USART_TX_DMA_STREAM_LL, + .DMA_Channel = EXTMODULE_USART_TX_DMA_CHANNEL, +}; + static void extmoduleSerialStart(const etx_serial_init* params) { if (!params) return; @@ -63,27 +79,9 @@ static void extmoduleSerialStart(const etx_serial_init* params) extmodule_driver.on_receive = params->on_receive; extmodule_driver.on_error = params->on_error; - // TX + RX Pins - LL_GPIO_InitTypeDef pinInit; - LL_GPIO_StructInit(&pinInit); - pinInit.Pin = EXTMODULE_TX_GPIO_PIN | EXTMODULE_RX_GPIO_PIN; - pinInit.Mode = LL_GPIO_MODE_ALTERNATE; - pinInit.Pull = LL_GPIO_PULL_UP; - pinInit.Alternate = EXTMODULE_USART_GPIO_AF_LL; - LL_GPIO_Init(EXTMODULE_USART_GPIO, &pinInit); - // UART config - stm32_usart_init(EXTMODULE_USART, params); + stm32_usart_init(&extmoduleUSART, params); extmoduleFifo.clear(); - - // Enable TX DMA request - LL_USART_EnableDMAReq_TX(EXTMODULE_USART); - - // Enable RX IRQ - LL_USART_EnableIT_RXNE(EXTMODULE_USART); - - NVIC_SetPriority(EXTMODULE_USART_IRQn, 6); - NVIC_EnableIRQ(EXTMODULE_USART_IRQn); } void extmoduleInvertedSerialStart(uint32_t baudrate) @@ -106,20 +104,7 @@ void extmodulePxx1SerialStart() void extmoduleSerialStop() { - DMA_DeInit(EXTMODULE_USART_TX_DMA_STREAM); - - // Reconfigure pin as output - LL_GPIO_InitTypeDef pinInit; - LL_GPIO_StructInit(&pinInit); - - pinInit.Pin = EXTMODULE_TX_GPIO_PIN | EXTMODULE_RX_GPIO_PIN; - pinInit.Mode = LL_GPIO_MODE_OUTPUT; - pinInit.Pull = LL_GPIO_PULL_DOWN; - LL_GPIO_Init(EXTMODULE_TX_GPIO, &pinInit); - - LL_USART_DeInit(EXTMODULE_USART); - LL_GPIO_ResetOutputPin(EXTMODULE_USART_GPIO, - EXTMODULE_TX_GPIO_PIN | EXTMODULE_RX_GPIO_PIN); + stm32_usart_deinit(&extmoduleUSART); // reset callbacks extmodule_driver.on_receive = nullptr; @@ -128,76 +113,18 @@ void extmoduleSerialStop() static void extmoduleSendByte(uint8_t byte) { - while (!LL_USART_IsActiveFlag_TXE(EXTMODULE_USART)); - LL_USART_TransmitData8(EXTMODULE_USART, byte); + stm32_usart_send_byte(&extmoduleUSART, byte); } static void extmoduleSendBuffer(const uint8_t * data, uint8_t size) { if (size == 0) return; - LL_DMA_DeInit(EXTMODULE_USART_TX_DMA, EXTMODULE_USART_TX_DMA_STREAM_LL); - - LL_DMA_InitTypeDef dmaInit; - LL_DMA_StructInit(&dmaInit); - dmaInit.Channel = EXTMODULE_USART_TX_DMA_CHANNEL; - dmaInit.PeriphOrM2MSrcAddress = CONVERT_PTR_UINT(&EXTMODULE_USART->DR); - dmaInit.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; - dmaInit.MemoryOrM2MDstAddress = CONVERT_PTR_UINT(data); - dmaInit.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; - dmaInit.NbData = size; - dmaInit.Priority = LL_DMA_PRIORITY_VERYHIGH; - - LL_DMA_Init(EXTMODULE_USART_TX_DMA, EXTMODULE_USART_TX_DMA_STREAM_LL, &dmaInit); - LL_DMA_EnableStream(EXTMODULE_USART_TX_DMA, EXTMODULE_USART_TX_DMA_STREAM_LL); -} - -#define USART_FLAG_ERRORS (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE | USART_FLAG_PE) -extern "C" void EXTMODULE_USART_IRQHandler(void) -{ - // No ISR based send loop: DMA only - - // Receive - uint32_t status = LL_USART_ReadReg(EXTMODULE_USART, SR); - while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) { - uint8_t data = LL_USART_ReceiveData8(EXTMODULE_USART); - if (status & USART_FLAG_ERRORS) { - if (extmodule_driver.on_error) - extmodule_driver.on_error(); - } - else { - if (extmodule_driver.on_receive) - extmodule_driver.on_receive(data); - } - status = LL_USART_ReadReg(EXTMODULE_USART, SR); - } + stm32_usart_send_buffer(&extmoduleUSART, data, size); } static void extmoduleWaitForTxCompleted() { - // TODO: check if everything is properly initialised, this seems to block when - // the port has been initialised with a zero baudrate - if (LL_DMA_IsEnabledStream(EXTMODULE_USART_TX_DMA, - EXTMODULE_USART_TX_DMA_STREAM_LL)) { - - static_assert(EXTMODULE_USART_TX_DMA_STREAM_LL == LL_DMA_STREAM_3 || - EXTMODULE_USART_TX_DMA_STREAM_LL == LL_DMA_STREAM_6 || - EXTMODULE_USART_TX_DMA_STREAM_LL == LL_DMA_STREAM_7, ""); - - switch(EXTMODULE_USART_TX_DMA_STREAM_LL) { - case LL_DMA_STREAM_3: - while (LL_DMA_IsActiveFlag_TC3(EXTMODULE_USART_TX_DMA)); - LL_DMA_ClearFlag_TC3(EXTMODULE_USART_TX_DMA); - break; - case LL_DMA_STREAM_6: - while (LL_DMA_IsActiveFlag_TC6(EXTMODULE_USART_TX_DMA)); - LL_DMA_ClearFlag_TC6(EXTMODULE_USART_TX_DMA); - break; - case LL_DMA_STREAM_7: - while (LL_DMA_IsActiveFlag_TC7(EXTMODULE_USART_TX_DMA)); - LL_DMA_ClearFlag_TC7(EXTMODULE_USART_TX_DMA); - break; - } - } + stm32_usart_wait_for_tx_dma(&extmoduleUSART); } const etx_serial_driver_t ExtmoduleSerialDriver = { @@ -208,4 +135,9 @@ const etx_serial_driver_t ExtmoduleSerialDriver = { .waitForTxCompleted = extmoduleWaitForTxCompleted, }; +extern "C" void EXTMODULE_USART_IRQHandler(void) +{ + stm32_usart_isr(&extmoduleUSART, &extmodule_driver); +} + #endif // defined(EXTMODULE_USART) diff --git a/radio/src/targets/common/arm/stm32/f2/CMakeLists.txt b/radio/src/targets/common/arm/stm32/f2/CMakeLists.txt index 53f0c458b..380a426cf 100644 --- a/radio/src/targets/common/arm/stm32/f2/CMakeLists.txt +++ b/radio/src/targets/common/arm/stm32/f2/CMakeLists.txt @@ -10,6 +10,7 @@ add_library(stm32cube_ll OBJECT ${STM32CUBE_DIR}/Src/stm32f2xx_ll_tim.c ${STM32CUBE_DIR}/Src/stm32f2xx_ll_dma.c ${STM32CUBE_DIR}/Src/stm32f2xx_ll_usart.c + ${STM32CUBE_DIR}/Src/stm32f2xx_ll_rcc.c ) target_compile_options(stm32cube_ll PRIVATE -DUSE_FULL_LL_DRIVER) diff --git a/radio/src/targets/common/arm/stm32/f2/system_stm32f2xx.c b/radio/src/targets/common/arm/stm32/f2/system_stm32f2xx.c index 992d3b676..31c9f43a6 100644 --- a/radio/src/targets/common/arm/stm32/f2/system_stm32f2xx.c +++ b/radio/src/targets/common/arm/stm32/f2/system_stm32f2xx.c @@ -88,6 +88,7 @@ uint32_t SystemCoreClock = 120000000; __I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; + __I uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; /** * @} diff --git a/radio/src/targets/common/arm/stm32/f4/CMakeLists.txt b/radio/src/targets/common/arm/stm32/f4/CMakeLists.txt index 4324ed96a..9b7c61bb0 100644 --- a/radio/src/targets/common/arm/stm32/f4/CMakeLists.txt +++ b/radio/src/targets/common/arm/stm32/f4/CMakeLists.txt @@ -10,6 +10,7 @@ add_library(stm32cube_ll OBJECT ${STM32CUBE_DIR}/Src/stm32f4xx_ll_tim.c ${STM32CUBE_DIR}/Src/stm32f4xx_ll_dma.c ${STM32CUBE_DIR}/Src/stm32f4xx_ll_usart.c + ${STM32CUBE_DIR}/Src/stm32f4xx_ll_rcc.c ) target_compile_options(stm32cube_ll PRIVATE -DUSE_FULL_LL_DRIVER) diff --git a/radio/src/targets/common/arm/stm32/f4/system_stm32f4xx.c b/radio/src/targets/common/arm/stm32/f4/system_stm32f4xx.c index dba520562..10805d908 100644 --- a/radio/src/targets/common/arm/stm32/f4/system_stm32f4xx.c +++ b/radio/src/targets/common/arm/stm32/f4/system_stm32f4xx.c @@ -182,6 +182,7 @@ uint32_t SystemCoreClock = 168000000; __I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; + __I uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; /** * @} diff --git a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp b/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp index 42759e4c5..ca4373bc9 100755 --- a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp +++ b/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp @@ -19,24 +19,40 @@ * GNU General Public License for more details. */ -#include "opentx.h" +#include "stm32_hal_ll.h" #include "intmodule_serial_driver.h" #include "stm32_usart_driver.h" +#include "board.h" +#include "io/frsky_pxx2.h" ModuleFifo intmoduleFifo; #if !defined(INTMODULE_DMA_STREAM) uint8_t * intmoduleTxBufferData; volatile uint8_t intmoduleTxBufferRemaining; + +bool intmoduleTxBufferSend(uint8_t& data) +{ + if (intmoduleTxBufferRemaining) { + data = *(intmoduleTxBufferData++); + intmoduleTxBufferRemaining--; + return true; + } + + // buffer is empty + return false; +} #endif -struct etx_serial_callbacks_t { - void (*on_receive)(uint8_t data); - void (*on_error)(); +static etx_serial_callbacks_t intmodule_driver = { +#if !defined(INTMODULE_DMA_STREAM) + intmoduleTxBufferSend, +#else + nullptr, +#endif + nullptr, nullptr }; -static etx_serial_callbacks_t intmodule_driver = { nullptr, nullptr }; - // TODO: move this somewhere else void intmoduleFifoReceive(uint8_t data) { @@ -48,23 +64,28 @@ void intmoduleFifoError() intmoduleFifo.errors++; } +static const LL_GPIO_InitTypeDef intmoduleUSART_PinDef = { + .Pin = INTMODULE_TX_GPIO_PIN | INTMODULE_RX_GPIO_PIN, + .Mode = LL_GPIO_MODE_ALTERNATE, + .Speed = LL_GPIO_SPEED_FREQ_LOW, + .OutputType = LL_GPIO_OUTPUT_PUSHPULL, + .Pull = LL_GPIO_PULL_UP, + .Alternate = INTMODULE_GPIO_AF_LL, +}; + +static const stm32_usart_t intmoduleUSART = { + .USARTx = INTMODULE_USART, + .GPIOx = INTMODULE_GPIO, + .pinInit = &intmoduleUSART_PinDef, + .IRQn = INTMODULE_USART_IRQn, + .DMAx = INTMODULE_DMA, + .DMA_Stream = INTMODULE_DMA_STREAM_LL, + .DMA_Channel = INTMODULE_DMA_CHANNEL, +}; + void intmoduleStop() { -#if defined(INTMODULE_DMA_STREAM) - INTMODULE_DMA_STREAM->CR &= ~DMA_SxCR_EN; // Disable DMA -#endif - - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.GPIO_Pin = INTMODULE_TX_GPIO_PIN | INTMODULE_RX_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - GPIO_Init(INTMODULE_GPIO, &GPIO_InitStructure); - - USART_DeInit(INTMODULE_USART); - - GPIO_ResetBits(INTMODULE_GPIO, INTMODULE_TX_GPIO_PIN | INTMODULE_RX_GPIO_PIN); + stm32_usart_deinit(&intmoduleUSART); // reset callbacks intmodule_driver.on_receive = nullptr; @@ -78,89 +99,22 @@ void intmoduleSerialStart(const etx_serial_init* params) // TODO: sanity check parameters // - the UART seems to block when initialised with baudrate = 0 - // TODO: remove this!!! - INTERNAL_MODULE_ON(); - // init callbacks intmodule_driver.on_receive = params->on_receive; intmodule_driver.on_error = params->on_error; - uint32_t baudrate = params->baudrate; - -#if !defined(INTMODULE_DMA_STREAM) - // IRQ based TX - NVIC_InitTypeDef NVIC_InitStructure; - NVIC_InitStructure.NVIC_IRQChannel = INTMODULE_USART_IRQn; - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; - NVIC_Init(&NVIC_InitStructure); - - // rco: workaround for high baudrate not supported with - // IRQ based TX. - if (baudrate > 1870000) { - TRACE("limiting baudrate to 1.87 MBit/s"); - baudrate = 1870000; - } -#endif - - GPIO_PinAFConfig(INTMODULE_GPIO, INTMODULE_GPIO_PinSource_TX, INTMODULE_GPIO_AF); - GPIO_PinAFConfig(INTMODULE_GPIO, INTMODULE_GPIO_PinSource_RX, INTMODULE_GPIO_AF); - - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.GPIO_Pin = INTMODULE_TX_GPIO_PIN | INTMODULE_RX_GPIO_PIN; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; - GPIO_Init(INTMODULE_GPIO, &GPIO_InitStructure); - - stm32_usart_init(INTMODULE_USART, params); - - if (params->rx_enable) { - USART_ITConfig(INTMODULE_USART, USART_IT_RXNE, ENABLE); - NVIC_SetPriority(INTMODULE_USART_IRQn, 6); - NVIC_EnableIRQ(INTMODULE_USART_IRQn); - } + stm32_usart_init(&intmoduleUSART, params); } #define USART_FLAG_ERRORS (USART_FLAG_ORE | USART_FLAG_NE | USART_FLAG_FE | USART_FLAG_PE) extern "C" void INTMODULE_USART_IRQHandler(void) { -#if !defined(INTMODULE_DMA_STREAM) - // Send - if (USART_GetITStatus(INTMODULE_USART, USART_IT_TXE) != RESET) { - if (intmoduleTxBufferRemaining) { - USART_SendData(INTMODULE_USART, intmoduleTxBufferData[0]); - intmoduleTxBufferData++; - intmoduleTxBufferRemaining--; - } - else { - USART_ITConfig(INTMODULE_USART, USART_IT_TXE, DISABLE); - } - } -#endif - - // Receive - uint32_t status = INTMODULE_USART->SR; - while (status & (USART_FLAG_RXNE | USART_FLAG_ERRORS)) { - uint8_t data = INTMODULE_USART->DR; - if (status & USART_FLAG_ERRORS) { - if (intmodule_driver.on_error) - intmodule_driver.on_error(); - } - else { - if (intmodule_driver.on_receive) - intmodule_driver.on_receive(data); - } - status = INTMODULE_USART->SR; - } + stm32_usart_isr(&intmoduleUSART, &intmodule_driver); } void intmoduleSendByte(uint8_t byte) { - while (!(INTMODULE_USART->SR & USART_SR_TXE)); - USART_SendData(INTMODULE_USART, byte); + stm32_usart_send_byte(&intmoduleUSART, byte); } void intmoduleSendBuffer(const uint8_t * data, uint8_t size) @@ -168,48 +122,20 @@ void intmoduleSendBuffer(const uint8_t * data, uint8_t size) if (size == 0) return; -#if defined(INTMODULE_DMA_STREAM) - DMA_InitTypeDef DMA_InitStructure; - DMA_DeInit(INTMODULE_DMA_STREAM); - DMA_InitStructure.DMA_Channel = INTMODULE_DMA_CHANNEL; - DMA_InitStructure.DMA_PeripheralBaseAddr = CONVERT_PTR_UINT(&INTMODULE_USART->DR); - DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; - DMA_InitStructure.DMA_Memory0BaseAddr = CONVERT_PTR_UINT(data); - DMA_InitStructure.DMA_BufferSize = size; - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; - DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; - DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; - DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; - DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; - DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; - DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; - DMA_Init(INTMODULE_DMA_STREAM, &DMA_InitStructure); - DMA_Cmd(INTMODULE_DMA_STREAM, ENABLE); - USART_DMACmd(INTMODULE_USART, USART_DMAReq_Tx, ENABLE); -#else +#if !defined(INTMODULE_DMA_STREAM) intmoduleTxBufferData = (uint8_t *)data; intmoduleTxBufferRemaining = size; - USART_ITConfig(INTMODULE_USART, USART_IT_TXE, ENABLE); #endif + stm32_usart_send_buffer(&intmoduleUSART, data, size); } void intmoduleWaitForTxCompleted() { -#if !defined(SIMU) #if defined(INTMODULE_DMA_STREAM) - // TODO: check if everything is properly initialised, this seems to block when - // the port has been initialised with a zero baudrate - if (DMA_GetCmdStatus(INTMODULE_DMA_STREAM) == ENABLE) { - while(DMA_GetFlagStatus(INTMODULE_DMA_STREAM, INTMODULE_DMA_FLAG_TC) == RESET); - DMA_ClearFlag(INTMODULE_DMA_STREAM, INTMODULE_DMA_FLAG_TC); - } + stm32_usart_wait_for_tx_dma(&intmoduleUSART); #else while (intmoduleTxBufferRemaining > 0); #endif -#endif } const etx_serial_driver_t IntmoduleSerialDriver = { diff --git a/radio/src/targets/common/arm/stm32/stm32_usart_driver.cpp b/radio/src/targets/common/arm/stm32/stm32_usart_driver.cpp index 8f366e3fc..9f8809a9b 100644 --- a/radio/src/targets/common/arm/stm32/stm32_usart_driver.cpp +++ b/radio/src/targets/common/arm/stm32/stm32_usart_driver.cpp @@ -20,51 +20,193 @@ */ #include "stm32_usart_driver.h" +#include -void stm32_usart_init(USART_TypeDef *USARTx, const etx_serial_init* params) +void stm32_usart_init(const stm32_usart_t* usart, const etx_serial_init* params) { - USART_DeInit(USARTx); + LL_USART_DeInit(usart->USARTx); + LL_GPIO_Init(usart->GPIOx, (LL_GPIO_InitTypeDef*)usart->pinInit); + + LL_USART_InitTypeDef usartInit; + usartInit.BaudRate = params->baudrate; - USART_InitTypeDef USART_InitStructure; - - USART_InitStructure.USART_BaudRate = params->baudrate; - - uint16_t parity = USART_Parity_No; + uint32_t parity = LL_USART_PARITY_NONE; switch(params->parity){ case ETX_Parity_None: - parity = USART_Parity_No; + parity = LL_USART_PARITY_NONE; break; case ETX_Parity_Even: - parity = USART_Parity_Even; + parity = LL_USART_PARITY_EVEN; break; case ETX_Parity_Odd: - parity = USART_Parity_Odd; + parity = LL_USART_PARITY_ODD; break; } - USART_InitStructure.USART_Parity = parity; + usartInit.Parity = parity; - uint16_t stop_bits = USART_StopBits_1; + uint16_t stop_bits = LL_USART_STOPBITS_1; switch(params->stop_bits) { case ETX_StopBits_One: - stop_bits = USART_StopBits_1; + stop_bits = LL_USART_STOPBITS_1; break; case ETX_StopBits_OneAndHalf: - stop_bits = USART_StopBits_1_5; + stop_bits = LL_USART_STOPBITS_1_5; break; case ETX_StopBits_Two: - stop_bits = USART_StopBits_2; + stop_bits = LL_USART_STOPBITS_2; break; } - USART_InitStructure.USART_StopBits = stop_bits; + usartInit.StopBits = stop_bits; if (params->word_length == ETX_WordLength_9) { - USART_InitStructure.USART_WordLength = USART_WordLength_9b; + usartInit.DataWidth = LL_USART_DATAWIDTH_9B; } else { - USART_InitStructure.USART_WordLength = USART_WordLength_8b; + usartInit.DataWidth = LL_USART_DATAWIDTH_8B; } - USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; - USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; - USART_Init(USARTx, &USART_InitStructure); - USART_Cmd(USARTx, ENABLE); + usartInit.HardwareFlowControl = LL_USART_HWCONTROL_NONE; + usartInit.TransferDirection = LL_USART_DIRECTION_TX_RX; + + LL_USART_Init(usart->USARTx, &usartInit); + LL_USART_Enable(usart->USARTx); + + // Enable TX DMA request + if (usart->DMAx) { + LL_USART_EnableDMAReq_TX(usart->USARTx); + } + + // Enable RX IRQ + if (params->rx_enable) { + LL_USART_EnableIT_RXNE(usart->USARTx); + } + + if (!usart->DMAx || params->rx_enable) { + // TODO: configurable priority ??? + NVIC_SetPriority(usart->IRQn, 6); + NVIC_EnableIRQ(usart->IRQn); + } +} + +void stm32_usart_deinit(const stm32_usart_t* usart) +{ + if (usart->DMAx) { + LL_DMA_DeInit(usart->DMAx, usart->DMA_Stream); + } + NVIC_DisableIRQ(usart->IRQn); + LL_USART_DeInit(usart->USARTx); + + // Reconfigure pin as output + LL_GPIO_InitTypeDef pinInit; + memcpy(&pinInit, usart->pinInit, sizeof(LL_GPIO_InitTypeDef)); + pinInit.Mode = LL_GPIO_MODE_OUTPUT; + pinInit.Pull = LL_GPIO_PULL_NO; + pinInit.Alternate = LL_GPIO_AF_0; + LL_GPIO_Init(usart->GPIOx, &pinInit); + LL_GPIO_ResetOutputPin(usart->GPIOx, pinInit.Pin); +} + +void stm32_usart_send_byte(const stm32_usart_t* usart, uint8_t byte) +{ + while (!LL_USART_IsActiveFlag_TXE(usart->USARTx)); + LL_USART_TransmitData8(usart->USARTx, byte); +} + +void stm32_usart_send_buffer(const stm32_usart_t* usart, const uint8_t * data, uint32_t size) +{ + if (usart->DMAx) { + LL_DMA_DeInit(usart->DMAx, usart->DMA_Stream); + + LL_DMA_InitTypeDef dmaInit; + LL_DMA_StructInit(&dmaInit); + + dmaInit.Channel = usart->DMA_Channel; + dmaInit.PeriphOrM2MSrcAddress = (uint32_t)&usart->USARTx->DR; + dmaInit.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; + dmaInit.MemoryOrM2MDstAddress = (uint32_t)data; + dmaInit.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; + dmaInit.NbData = size; + dmaInit.Priority = LL_DMA_PRIORITY_VERYHIGH; + + LL_DMA_Init(usart->DMAx, usart->DMA_Stream, &dmaInit); + LL_DMA_EnableStream(usart->DMAx, usart->DMA_Stream); + + return; + } else { + // Please note that we don't use the buffer: + // it should set internally by the driver user + // and each byte is returned individually by on_send() + LL_USART_EnableIT_TXE(usart->USARTx); + } +} + +void stm32_usart_wait_for_tx_dma(const stm32_usart_t* usart) +{ + // TODO: check if everything is properly initialised, this seems to block when + // the port has been initialised with a zero baudrate + if (LL_DMA_IsEnabledStream(usart->DMAx, usart->DMA_Stream)) { + + switch(usart->DMA_Stream) { + case LL_DMA_STREAM_1: + while (LL_DMA_IsActiveFlag_TC1(usart->DMAx)); + LL_DMA_ClearFlag_TC1(usart->DMAx); + break; + case LL_DMA_STREAM_3: + while (LL_DMA_IsActiveFlag_TC3(usart->DMAx)); + LL_DMA_ClearFlag_TC3(usart->DMAx); + break; + case LL_DMA_STREAM_5: + while (LL_DMA_IsActiveFlag_TC5(usart->DMAx)); + LL_DMA_ClearFlag_TC5(usart->DMAx); + break; + case LL_DMA_STREAM_6: + while (LL_DMA_IsActiveFlag_TC6(usart->DMAx)); + LL_DMA_ClearFlag_TC6(usart->DMAx); + break; + case LL_DMA_STREAM_7: + while (LL_DMA_IsActiveFlag_TC7(usart->DMAx)); + LL_DMA_ClearFlag_TC7(usart->DMAx); + break; + } + } +} + +#define USART_FLAG_ERRORS \ + (LL_USART_SR_ORE | LL_USART_SR_NE | LL_USART_SR_FE | LL_USART_SR_PE) + +void stm32_usart_isr(const stm32_usart_t* usart, etx_serial_callbacks_t* cb) +{ + uint32_t status = LL_USART_ReadReg(usart->USARTx, SR); + + // IRQ based send: TXE IRQ is enabled only during transfer + if (LL_USART_IsEnabledIT_TXE(usart->USARTx) && (status & LL_USART_SR_TXE)) { + + uint8_t data; + if (cb->on_send && cb->on_send(data)) { + LL_USART_TransmitData8(usart->USARTx, data); + } else { + LL_USART_DisableIT_TXE(usart->USARTx); + } + } + + // Receive + if (LL_USART_IsEnabledIT_TXE(usart->USARTx)) { + + // Drain RX + while (status & (LL_USART_SR_RXNE | USART_FLAG_ERRORS)) { + + // This will clear the RXNE bit in USART_DR register + uint8_t data = LL_USART_ReadReg(usart->USARTx, DR); + + if (status & USART_FLAG_ERRORS) { + if (cb->on_error) + cb->on_error(); + } + else { + if (cb->on_receive) + cb->on_receive(data); + } + + status = LL_USART_ReadReg(usart->USARTx, SR); + } + } } diff --git a/radio/src/targets/common/arm/stm32/stm32_usart_driver.h b/radio/src/targets/common/arm/stm32/stm32_usart_driver.h index 9ac402886..58b6a5d7d 100644 --- a/radio/src/targets/common/arm/stm32/stm32_usart_driver.h +++ b/radio/src/targets/common/arm/stm32/stm32_usart_driver.h @@ -23,13 +23,27 @@ #include #include "hal/serial_driver.h" +#include "stm32_hal_ll.h" + +struct stm32_usart_t { + + // USART defs + USART_TypeDef* USARTx; + GPIO_TypeDef* GPIOx; + const LL_GPIO_InitTypeDef* pinInit; + IRQn_Type IRQn; + + // TX DMA defs + DMA_TypeDef* DMAx; + uint32_t DMA_Stream; + uint32_t DMA_Channel; +}; + +void stm32_usart_init(const stm32_usart_t* usart, const etx_serial_init* params); +void stm32_usart_deinit(const stm32_usart_t* usart); +void stm32_usart_send_byte(const stm32_usart_t* usart, uint8_t byte); +void stm32_usart_send_buffer(const stm32_usart_t* usart, const uint8_t * data, uint32_t size); +void stm32_usart_wait_for_tx_dma(const stm32_usart_t* usart); +void stm32_usart_isr(const stm32_usart_t* usart, etx_serial_callbacks_t* cb); -#if defined(STM32F4) -// #include "stm32f4xx.h" - #include "stm32f4xx_usart.h" -#else -// #include "stm32f2xx.h" - #include "stm32f2xx_usart.h" -#endif -void stm32_usart_init(USART_TypeDef *USARTx, const etx_serial_init* params); diff --git a/radio/src/targets/horus/hal.h b/radio/src/targets/horus/hal.h index 6c86f2153..56fbf0292 100644 --- a/radio/src/targets/horus/hal.h +++ b/radio/src/targets/horus/hal.h @@ -812,9 +812,12 @@ #define INTMODULE_GPIO_PinSource_RX GPIO_PinSource7 #define INTMODULE_USART USART1 #define INTMODULE_GPIO_AF GPIO_AF_USART1 +#define INTMODULE_GPIO_AF_LL LL_GPIO_AF_7 #define INTMODULE_USART_IRQn USART1_IRQn #define INTMODULE_USART_IRQHandler USART1_IRQHandler +#define INTMODULE_DMA DMA2 #define INTMODULE_DMA_STREAM DMA2_Stream7 +#define INTMODULE_DMA_STREAM_LL LL_DMA_STREAM_7 #define INTMODULE_DMA_STREAM_IRQ DMA2_Stream7_IRQn #define INTMODULE_DMA_STREAM_IRQHandler DMA2_Stream7_IRQHandler #define INTMODULE_DMA_FLAG_TC DMA_FLAG_TCIF7 diff --git a/radio/src/targets/nv14/hal.h b/radio/src/targets/nv14/hal.h index e7c540082..f37e26f8a 100644 --- a/radio/src/targets/nv14/hal.h +++ b/radio/src/targets/nv14/hal.h @@ -388,9 +388,12 @@ #define INTMODULE_GPIO_PinSource_RX GPIO_PinSource6 #define INTMODULE_USART UART7 #define INTMODULE_GPIO_AF GPIO_AF_UART7 +#define INTMODULE_GPIO_AF_LL LL_GPIO_AF_8 #define INTMODULE_USART_IRQn UART7_IRQn #define INTMODULE_USART_IRQHandler UART7_IRQHandler +#define INTMODULE_DMA DMA1 #define INTMODULE_DMA_STREAM DMA1_Stream1 +#define INTMODULE_DMA_STREAM_LL LL_DMA_STREAM_1 #define INTMODULE_DMA_STREAM_IRQ DMA1_Stream1_IRQn #define INTMODULE_DMA_FLAG_TC DMA_IT_TCIF1 #define INTMODULE_DMA_CHANNEL DMA_Channel_5 diff --git a/radio/src/targets/taranis/hal.h b/radio/src/targets/taranis/hal.h index e92f82da3..2a45f78b5 100644 --- a/radio/src/targets/taranis/hal.h +++ b/radio/src/targets/taranis/hal.h @@ -1353,9 +1353,12 @@ #define INTMODULE_GPIO_PinSource_RX GPIO_PinSource7 #define INTMODULE_USART USART1 #define INTMODULE_GPIO_AF GPIO_AF_USART1 + #define INTMODULE_GPIO_AF_LL LL_GPIO_AF_7 #define INTMODULE_USART_IRQHandler USART1_IRQHandler #define INTMODULE_USART_IRQn USART1_IRQn + #define INTMODULE_DMA DMA2 #define INTMODULE_DMA_STREAM DMA2_Stream7 + #define INTMODULE_DMA_STREAM_LL LL_DMA_STREAM_7 #define INTMODULE_DMA_STREAM_IRQ DMA2_Stream7_IRQn #define INTMODULE_DMA_STREAM_IRQHandler DMA2_Stream7_IRQHandler #define INTMODULE_DMA_FLAG_TC DMA_IT_TCIF7 @@ -1378,9 +1381,12 @@ #define INTMODULE_GPIO_PinSource_RX GPIO_PinSource7 #define INTMODULE_USART USART1 #define INTMODULE_GPIO_AF GPIO_AF_USART1 + #define INTMODULE_GPIO_AF_LL LL_GPIO_AF_7 #define INTMODULE_USART_IRQHandler USART1_IRQHandler #define INTMODULE_USART_IRQn USART1_IRQn + #define INTMODULE_DMA DMA2 #define INTMODULE_DMA_STREAM DMA2_Stream7 + #define INTMODULE_DMA_STREAM_LL LL_DMA_STREAM_7 #define INTMODULE_DMA_STREAM_IRQ DMA2_Stream7_IRQn #define INTMODULE_DMA_STREAM_IRQHandler DMA2_Stream7_IRQHandler #define INTMODULE_DMA_FLAG_TC DMA_IT_TCIF7 @@ -1398,9 +1404,12 @@ #define INTMODULE_GPIO_PinSource_RX GPIO_PinSource7 #define INTMODULE_USART USART1 #define INTMODULE_GPIO_AF GPIO_AF_USART1 + #define INTMODULE_GPIO_AF_LL LL_GPIO_AF_7 #define INTMODULE_USART_IRQHandler USART1_IRQHandler #define INTMODULE_USART_IRQn USART1_IRQn + #define INTMODULE_DMA DMA2 #define INTMODULE_DMA_STREAM DMA2_Stream7 + #define INTMODULE_DMA_STREAM_LL LL_DMA_STREAM_7 #define INTMODULE_DMA_STREAM_IRQ DMA2_Stream7_IRQn #define INTMODULE_DMA_STREAM_IRQHandler DMA2_Stream7_IRQHandler #define INTMODULE_DMA_FLAG_TC DMA_IT_TCIF7 @@ -1442,8 +1451,10 @@ #define INTMODULE_TIMER_CC_IRQn TIM1_CC_IRQn #define INTMODULE_TIMER_CC_IRQHandler TIM1_CC_IRQHandler #define INTMODULE_TX_GPIO_AF GPIO_AF_TIM1 + #define INTMODULE_DMA DMA2 #define INTMODULE_DMA_CHANNEL DMA_Channel_6 #define INTMODULE_DMA_STREAM DMA2_Stream5 + #define INTMODULE_DMA_STREAM_LL LL_DMA_STREAM_5 #define INTMODULE_DMA_STREAM_IRQn DMA2_Stream5_IRQn #define INTMODULE_DMA_STREAM_IRQHandler DMA2_Stream5_IRQHandler #define INTMODULE_DMA_FLAG_TC DMA_IT_TCIF5 @@ -1461,19 +1472,18 @@ #define INTMODULE_GPIO_PinSource_RX GPIO_PinSource11 #define INTMODULE_USART USART3 #define INTMODULE_GPIO_AF GPIO_AF_USART3 + #define INTMODULE_GPIO_AF_LL LL_GPIO_AF_7 #define INTMODULE_USART_IRQn USART3_IRQn #define INTMODULE_USART_IRQHandler USART3_IRQHandler - #define INTMODULE_TIMER TIM2 - #define INTMODULE_TIMER_IRQn TIM2_IRQn - #define INTMODULE_TIMER_IRQHandler TIM2_IRQHandler - #define INTMODULE_TIMER_CC_IRQn TIM2_CC_IRQn - #define INTMODULE_TIMER_CC_IRQHandler TIM2_CC_IRQHandler - #define INTMODULE_TIMER_FREQ (PERI2_FREQUENCY * TIMER_MULT_APB2) - #if defined(RADIO_TPRO) - #define INTMODULE_BOOTCMD_GPIO GPIOF - #define INTMODULE_BOOTCMD_GPIO_PIN GPIO_Pin_11 // PF.11 - #define INIT_INTMODULE_BOOTCMD_PIN() GPIO_ResetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN); - #endif + #define INTMODULE_DMA NULL + #define INTMODULE_DMA_CHANNEL 0 + #define INTMODULE_DMA_STREAM_LL 0 + // #define INTMODULE_TIMER TIM2 + // #define INTMODULE_TIMER_IRQn TIM2_IRQn + // #define INTMODULE_TIMER_IRQHandler TIM2_IRQHandler + // #define INTMODULE_TIMER_CC_IRQn TIM2_CC_IRQn + // #define INTMODULE_TIMER_CC_IRQHandler TIM2_CC_IRQHandler + // #define INTMODULE_TIMER_FREQ (PERI2_FREQUENCY * TIMER_MULT_APB2) #else #define INTMODULE_PULSES #define INTMODULE_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_DMA2) @@ -1488,6 +1498,7 @@ #define INTMODULE_TIMER_CC_IRQn TIM1_CC_IRQn #define INTMODULE_TIMER_CC_IRQHandler TIM1_CC_IRQHandler #define INTMODULE_TX_GPIO_AF GPIO_AF_TIM1 + #define INTMODULE_DMA DMA2 #define INTMODULE_DMA_CHANNEL DMA_Channel_6 #define INTMODULE_DMA_STREAM DMA2_Stream5 #define INTMODULE_DMA_STREAM_IRQn DMA2_Stream5_IRQn