diff --git a/os/hal/platforms/STM32/USARTv1/uart_lld.c b/os/hal/platforms/STM32/USARTv1/uart_lld.c index c1e624918..b965655aa 100644 --- a/os/hal/platforms/STM32/USARTv1/uart_lld.c +++ b/os/hal/platforms/STM32/USARTv1/uart_lld.c @@ -55,6 +55,22 @@ STM32_DMA_GETCHANNEL(STM32_UART_USART3_TX_DMA_STREAM, \ STM32_USART3_TX_DMA_CHN) +#define UART4_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_UART4_RX_DMA_STREAM, \ + STM32_UART4_RX_DMA_CHN) + +#define USART4_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_USART4_TX_DMA_STREAM, \ + STM32_UART4_TX_DMA_CHN) + +#define UART5_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_UART5_RX_DMA_STREAM, \ + STM32_UART5_RX_DMA_CHN) + +#define USART5_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_USART5_TX_DMA_STREAM, \ + STM32_UART5_TX_DMA_CHN) + #define USART6_RX_DMA_CHANNEL \ STM32_DMA_GETCHANNEL(STM32_UART_USART6_RX_DMA_STREAM, \ STM32_USART6_RX_DMA_CHN) @@ -63,6 +79,14 @@ STM32_DMA_GETCHANNEL(STM32_UART_USART6_TX_DMA_STREAM, \ STM32_USART6_TX_DMA_CHN) +#if (STM32_UART_USE_UART4 || STM32_UART_USE_UART5) + #define STM32_UART45_CR2_CHECK_MASK (USART_CR2_STOP_0 | USART_CR2_CLKEN | \ + USART_CR2_CPOL | USART_CR2_CPHA | USART_CR2_LBCL) + + #define STM32_UART45_CR3_CHECK_MASK (USART_CR3_CTSIE | USART_CR3_CTSE | \ + USART_CR3_RTSE | USART_CR3_SCEN | USART_CR3_NACK) +#endif + /*===========================================================================*/ /* Driver exported variables. */ /*===========================================================================*/ @@ -82,6 +106,15 @@ UARTDriver UARTD2; UARTDriver UARTD3; #endif +/** @brief UART4 UART driver identifier.*/ +#if STM32_UART_USE_UART4 || defined(__DOXYGEN__) +UARTDriver UARTD4; +#endif + +/** @brief UART5 UART driver identifier.*/ +#if STM32_UART_USE_UART5 || defined(__DOXYGEN__) +UARTDriver UARTD5; +#endif /** @brief USART6 UART driver identifier.*/ #if STM32_UART_USE_USART6 || defined(__DOXYGEN__) @@ -358,6 +391,44 @@ CH_IRQ_HANDLER(STM32_USART3_HANDLER) { } #endif /* STM32_UART_USE_USART3 */ +#if STM32_UART_USE_UART4 || defined(__DOXYGEN__) +#if !defined(STM32_UART4_HANDLER) +#error "STM32_USART4_HANDLER not defined" +#endif +/** + * @brief UART4 IRQ handler. + * + * @isr + */ +CH_IRQ_HANDLER(STM32_UART4_HANDLER) { + + CH_IRQ_PROLOGUE(); + + serve_usart_irq(&UARTD4); + + CH_IRQ_EPILOGUE(); +} +#endif /* STM32_UART_USE_UART4 */ + +#if STM32_UART_USE_UART5 || defined(__DOXYGEN__) +#if !defined(STM32_UART5_HANDLER) +#error "STM32_USART5_HANDLER not defined" +#endif +/** + * @brief UART5 IRQ handler. + * + * @isr + */ +CH_IRQ_HANDLER(STM32_UART5_HANDLER) { + + CH_IRQ_PROLOGUE(); + + serve_usart_irq(&UARTD5); + + CH_IRQ_EPILOGUE(); +} +#endif /* STM32_UART_USE_UART5 */ + #if STM32_UART_USE_USART6 || defined(__DOXYGEN__) #if !defined(STM32_USART6_HANDLER) #error "STM32_USART6_HANDLER not defined" @@ -412,6 +483,22 @@ void uart_lld_init(void) { UARTD3.dmatx = STM32_DMA_STREAM(STM32_UART_USART3_TX_DMA_STREAM); #endif +#if STM32_UART_USE_UART4 + uartObjectInit(&UARTD4); + UARTD4.usart = UART4; + UARTD4.dmamode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD4.dmarx = STM32_DMA_STREAM(STM32_UART_UART4_RX_DMA_STREAM); + UARTD4.dmatx = STM32_DMA_STREAM(STM32_UART_UART4_TX_DMA_STREAM); +#endif + +#if STM32_UART_USE_UART5 + uartObjectInit(&UARTD5); + UARTD5.usart = UART5; + UARTD5.dmamode = STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE; + UARTD5.dmarx = STM32_DMA_STREAM(STM32_UART_UART5_RX_DMA_STREAM); + UARTD5.dmatx = STM32_DMA_STREAM(STM32_UART_UART5_TX_DMA_STREAM); +#endif + #if STM32_UART_USE_USART6 uartObjectInit(&UARTD6); UARTD6.usart = USART6; @@ -420,6 +507,28 @@ void uart_lld_init(void) { #endif } +/** + * @brief Check CR2 and CR3 values for compatibility with UART4, UART5. + * + * @param[in] uartp pointer to the @p UARTDriver object + * + * @notapi + */ +#if (STM32_UART_USE_UART4 || STM32_UART_USE_UART5) +static void uart_check_config(const UARTDriver *uartp) { + + uint16_t cr; + + cr = uartp->config->cr2; + chDbgCheck((cr & STM32_UART45_CR2_CHECK_MASK) == 0, + "Some flags from CR2 unavailable for this UART"); + + cr = uartp->config->cr3; + chDbgCheck((cr & STM32_UART45_CR3_CHECK_MASK) == 0, + "Some flags from CR3 unavailable for this UART"); +} +#endif /* (STM32_UART_USE_USART4 || STM32_UART_USE_USART5) */ + /** * @brief Configures and activates the UART peripheral. * @@ -429,6 +538,14 @@ void uart_lld_init(void) { */ void uart_lld_start(UARTDriver *uartp) { +#if STM32_UART_USE_UART4 + if (uartp == &UARTD4) + uart_check_config(uartp); +#elif STM32_UART_USE_UART5 + else if (uartp == &UARTD5) + uart_check_config(uartp); +#endif + if (uartp->state == UART_STOP) { #if STM32_UART_USE_USART1 if (&UARTD1 == uartp) { @@ -493,6 +610,48 @@ void uart_lld_start(UARTDriver *uartp) { } #endif +#if STM32_UART_USE_UART4 + if (&UARTD4 == uartp) { + bool_t b; + b = dmaStreamAllocate(uartp->dmarx, + STM32_UART_UART4_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, + (void *)uartp); + chDbgAssert(!b, "uart_lld_start(), #7", "stream already allocated"); + b = dmaStreamAllocate(uartp->dmatx, + STM32_UART_UART4_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, + (void *)uartp); + chDbgAssert(!b, "uart_lld_start(), #8", "stream already allocated"); + rccEnableUART4(FALSE); + nvicEnableVector(STM32_UART4_NUMBER, + CORTEX_PRIORITY_MASK(STM32_UART_UART4_IRQ_PRIORITY)); + uartp->dmamode |= STM32_DMA_CR_CHSEL(UART4_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_UART4_DMA_PRIORITY); + } +#endif + +#if STM32_UART_USE_UART5 + if (&UARTD5 == uartp) { + bool_t b; + b = dmaStreamAllocate(uartp->dmarx, + STM32_UART_UART5_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, + (void *)uartp); + chDbgAssert(!b, "uart_lld_start(), #9", "stream already allocated"); + b = dmaStreamAllocate(uartp->dmatx, + STM32_UART_UART5_IRQ_PRIORITY, + (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, + (void *)uartp); + chDbgAssert(!b, "uart_lld_start(), #10", "stream already allocated"); + rccEnableUART5(FALSE); + nvicEnableVector(STM32_UART5_NUMBER, + CORTEX_PRIORITY_MASK(STM32_UART_UART5_IRQ_PRIORITY)); + uartp->dmamode |= STM32_DMA_CR_CHSEL(UART5_RX_DMA_CHANNEL) | + STM32_DMA_CR_PL(STM32_UART_UART5_DMA_PRIORITY); + } +#endif + #if STM32_UART_USE_USART6 if (&UARTD6 == uartp) { bool_t b; @@ -500,12 +659,12 @@ void uart_lld_start(UARTDriver *uartp) { STM32_UART_USART6_IRQ_PRIORITY, (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, (void *)uartp); - chDbgAssert(!b, "uart_lld_start(), #5", "stream already allocated"); + chDbgAssert(!b, "uart_lld_start(), #11", "stream already allocated"); b = dmaStreamAllocate(uartp->dmatx, STM32_UART_USART6_IRQ_PRIORITY, (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, (void *)uartp); - chDbgAssert(!b, "uart_lld_start(), #6", "stream already allocated"); + chDbgAssert(!b, "uart_lld_start(), #12", "stream already allocated"); rccEnableUSART6(FALSE); nvicEnableVector(STM32_USART6_NUMBER, CORTEX_PRIORITY_MASK(STM32_UART_USART6_IRQ_PRIORITY)); @@ -566,6 +725,22 @@ void uart_lld_stop(UARTDriver *uartp) { } #endif +#if STM32_UART_USE_UART4 + if (&UARTD4 == uartp) { + nvicDisableVector(STM32_UART4_NUMBER); + rccDisableUART4(FALSE); + return; + } +#endif + +#if STM32_UART_USE_UART5 + if (&UARTD5 == uartp) { + nvicDisableVector(STM32_UART5_NUMBER); + rccDisableUART5(FALSE); + return; + } +#endif + #if STM32_UART_USE_USART6 if (&UARTD6 == uartp) { nvicDisableVector(STM32_USART6_NUMBER); diff --git a/os/hal/platforms/STM32/USARTv1/uart_lld.h b/os/hal/platforms/STM32/USARTv1/uart_lld.h index ffaed007e..ba8f00f1e 100644 --- a/os/hal/platforms/STM32/USARTv1/uart_lld.h +++ b/os/hal/platforms/STM32/USARTv1/uart_lld.h @@ -66,6 +66,24 @@ #define STM32_UART_USE_USART3 FALSE #endif +/** + * @brief UART driver on UART4 enable switch. + * @details If set to @p TRUE the support for UART4 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_UART_USE_UART4) || defined(__DOXYGEN__) +#define STM32_UART_USE_UART4 FALSE +#endif + +/** + * @brief UART driver on UART5 enable switch. + * @details If set to @p TRUE the support for UART5 is included. + * @note The default is @p FALSE. + */ +#if !defined(STM32_UART_USE_UART4) || defined(__DOXYGEN__) +#define STM32_UART_USE_UART5 FALSE +#endif + /** * @brief UART driver on USART6 enable switch. * @details If set to @p TRUE the support for USART6 is included. @@ -96,6 +114,20 @@ #define STM32_UART_USART3_IRQ_PRIORITY 12 #endif +/** + * @brief UART4 interrupt priority level setting. + */ +#if !defined(STM32_UART_UART4_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_UART4_IRQ_PRIORITY 12 +#endif + +/** + * @brief UART5 interrupt priority level setting. + */ +#if !defined(STM32_UART_UART5_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_UART5_IRQ_PRIORITY 12 +#endif + /** * @brief USART6 interrupt priority level setting. */ @@ -133,6 +165,26 @@ #define STM32_UART_USART3_DMA_PRIORITY 0 #endif +/** + * @brief UART4 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. + */ +#if !defined(STM32_UART_UART4_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_UART4_DMA_PRIORITY 0 +#endif + +/** + * @brief UART5 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. + */ +#if !defined(STM32_UART_UART5_DMA_PRIORITY) || defined(__DOXYGEN__) +#define STM32_UART_UART5_DMA_PRIORITY 0 +#endif + /** * @brief USART6 DMA priority (0..3|lowest..highest). * @note The priority level is used for both the TX and RX DMA channels but @@ -144,7 +196,7 @@ #endif /** - * @brief USART1 DMA error hook. + * @brief USART DMA error hook. * @note The default action for DMA errors is a system halt because DMA * error can only happen because programming errors. */ @@ -202,6 +254,38 @@ #define STM32_UART_USART3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) #endif +/** + * @brief DMA stream used for UART4 RX operations. + * @note This option is only available on platforms with enhanced DMA. + */ +#if !defined(STM32_UART_UART4_RX_DMA_STREAM) || defined(__DOXYGEN__) +#define STM32_UART_UART4_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) +#endif + +/** + * @brief DMA stream used for UART4 TX operations. + * @note This option is only available on platforms with enhanced DMA. + */ +#if !defined(STM32_UART_UART4_TX_DMA_STREAM) || defined(__DOXYGEN__) +#define STM32_UART_UART4_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) +#endif + +/** + * @brief DMA stream used for UART5 RX operations. + * @note This option is only available on platforms with enhanced DMA. + */ +#if !defined(STM32_UART_UART5_RX_DMA_STREAM) || defined(__DOXYGEN__) +#define STM32_UART_UART5_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0) +#endif + +/** + * @brief DMA stream used for UART5 TX operations. + * @note This option is only available on platforms with enhanced DMA. + */ +#if !defined(STM32_UART_UART5_TX_DMA_STREAM) || defined(__DOXYGEN__) +#define STM32_UART_UART5_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) +#endif + /** * @brief DMA stream used for USART6 RX operations. * @note This option is only available on platforms with enhanced DMA. @@ -228,6 +312,8 @@ #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) +#define STM32_UART_UART4_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 3) +#define STM32_UART_UART4_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 5) #endif /* !STM32_ADVANCED_DMA*/ /** @} */ @@ -248,12 +334,33 @@ #error "USART3 not present in the selected device" #endif +#if STM32_UART_USE_UART4 + #if !STM32_HAS_UART4 + #error "UART4 not present in the selected device" + #endif + + #if !defined(STM32F4XX) || !defined(STM32F4XX) + #error "UART4 DMA access not supported in this platform" + #endif +#endif + +#if STM32_UART_USE_UART5 + #if !STM32_HAS_UART5 + #error "UART5 not present in the selected device" + #endif + + #if !defined(STM32F4XX) || !defined(STM32F4XX) + #error "UART5 DMA access not supported in this platform" + #endif +#endif + #if STM32_UART_USE_USART6 && !STM32_HAS_USART6 #error "USART6 not present in the selected device" #endif #if !STM32_UART_USE_USART1 && !STM32_UART_USE_USART2 && \ - !STM32_UART_USE_USART3 && !STM32_UART_USE_USART6 + !STM32_UART_USE_USART3 && !STM32_UART_USE_UART4 && \ + !STM32_UART_USE_UART5 && !STM32_UART_USE_USART6 #error "UART driver activated but no USART/UART peripheral assigned" #endif @@ -272,6 +379,16 @@ #error "Invalid IRQ priority assigned to USART3" #endif +#if STM32_UART_USE_UART4 && \ + !CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_UART_UART4_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to UART4" +#endif + +#if STM32_UART_USE_UART5 && \ + !CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_UART_UART5_IRQ_PRIORITY) +#error "Invalid IRQ priority assigned to UART5" +#endif + #if STM32_UART_USE_USART6 && \ !CORTEX_IS_VALID_KERNEL_PRIORITY(STM32_UART_USART6_IRQ_PRIORITY) #error "Invalid IRQ priority assigned to USART6" @@ -292,6 +409,16 @@ #error "Invalid DMA priority assigned to USART3" #endif +#if STM32_UART_USE_UART4 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_UART4_DMA_PRIORITY) +#error "Invalid DMA priority assigned to UART4" +#endif + +#if STM32_UART_USE_UART5 && \ + !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_UART5_DMA_PRIORITY) +#error "Invalid DMA priority assigned to UART5" +#endif + #if STM32_UART_USE_USART6 && \ !STM32_DMA_IS_VALID_PRIORITY(STM32_UART_USART6_DMA_PRIORITY) #error "Invalid DMA priority assigned to USART6" @@ -333,6 +460,30 @@ #error "invalid DMA stream associated to USART3 TX" #endif +#if STM32_UART_USE_UART4 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_UART4_RX_DMA_STREAM, \ + STM32_UART4_RX_DMA_MSK) +#error "invalid DMA stream associated to UART4 RX" +#endif + +#if STM32_UART_USE_UART4 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_UART4_TX_DMA_STREAM, \ + STM32_UART4_TX_DMA_MSK) +#error "invalid DMA stream associated to UART4 TX" +#endif + +#if STM32_UART_USE_UART5 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_UART5_RX_DMA_STREAM, \ + STM32_UART5_RX_DMA_MSK) +#error "invalid DMA stream associated to UART5 RX" +#endif + +#if STM32_UART_USE_UART5 && \ + !STM32_DMA_IS_VALID_ID(STM32_UART_UART5_TX_DMA_STREAM, \ + STM32_UART5_TX_DMA_MSK) +#error "invalid DMA stream associated to UART5 TX" +#endif + #if STM32_UART_USE_USART6 && \ !STM32_DMA_IS_VALID_ID(STM32_UART_USART6_RX_DMA_STREAM, \ STM32_USART6_RX_DMA_MSK) @@ -496,6 +647,14 @@ extern UARTDriver UARTD2; extern UARTDriver UARTD3; #endif +#if STM32_UART_USE_UART4 && !defined(__DOXYGEN__) +extern UARTDriver UARTD4; +#endif + +#if STM32_UART_USE_UART5 && !defined(__DOXYGEN__) +extern UARTDriver UARTD5; +#endif + #if STM32_UART_USE_USART6 && !defined(__DOXYGEN__) extern UARTDriver UARTD6; #endif diff --git a/readme.txt b/readme.txt index 7a853273f..8043a3dd5 100644 --- a/readme.txt +++ b/readme.txt @@ -89,6 +89,8 @@ ***************************************************************************** *** 2.7.0 *** +- NEW: Added support of UART4 and UART5 (STM32F4x and STM32F2x platforms). + Feature request #28. - FIX: Fixed missing casts in time-conversion macros (bug #418)(backported to 2.6.1, 2.4.4 and 2.2.10). - FIX: Fixed STM32 Serial (v2) driver invalid CR registers size (bug #416)