diff --git a/os/hal/platforms/STM32/uart_lld.c b/os/hal/platforms/STM32/uart_lld.c index 4ecce9a69..7974f74fa 100644 --- a/os/hal/platforms/STM32/uart_lld.c +++ b/os/hal/platforms/STM32/uart_lld.c @@ -243,19 +243,19 @@ static void serve_usart_irq(UARTDriver *uartp) { #if STM32_UART_USE_USART1 || defined(__DOXYGEN__) /** - * @brief USART1 RX DMA interrupt handler (channel 4). + * @brief USART1 RX DMA interrupt handler (channel 5). */ -CH_IRQ_HANDLER(DMA1_Ch4_IRQHandler) { +CH_IRQ_HANDLER(DMA1_Ch5_IRQHandler) { UARTDriver *uartp; CH_IRQ_PROLOGUE(); uartp = &UARTD1; - if ((STM32_DMA1->ISR & DMA_ISR_TEIF4) != 0) { + if ((STM32_DMA1->ISR & DMA_ISR_TEIF5) != 0) { STM32_UART_USART1_DMA_ERROR_HOOK(); } - dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_4); if (uartp->ud_rxstate == UART_RX_IDLE) { + dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_5); /* Fast IRQ path, this is why it is not centralized in serve_rx_end_irq().*/ /* Receiver in idle state, a callback is generated, if enabled, for each received character and then the driver stays in the same state.*/ @@ -265,7 +265,8 @@ CH_IRQ_HANDLER(DMA1_Ch4_IRQHandler) { else { /* Receiver in active state, a callback is generated, if enabled, after a completed transfer.*/ - dmaDisableChannel(STM32_DMA1, STM32_DMA_CHANNEL_4); + dmaDisableChannel(STM32_DMA1, STM32_DMA_CHANNEL_5); + dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_5); serve_rx_end_irq(uartp); } @@ -273,17 +274,17 @@ CH_IRQ_HANDLER(DMA1_Ch4_IRQHandler) { } /** - * @brief USART1 TX DMA interrupt handler (channel 5). + * @brief USART1 TX DMA interrupt handler (channel 4). */ -CH_IRQ_HANDLER(DMA1_Ch5_IRQHandler) { +CH_IRQ_HANDLER(DMA1_Ch4_IRQHandler) { CH_IRQ_PROLOGUE(); - if ((STM32_DMA1->ISR & DMA_ISR_TEIF5) != 0) { + if ((STM32_DMA1->ISR & DMA_ISR_TEIF4) != 0) { STM32_UART_USART1_DMA_ERROR_HOOK(); } - dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_5); - dmaDisableChannel(STM32_DMA1, STM32_DMA_CHANNEL_5); + dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_4); + dmaDisableChannel(STM32_DMA1, STM32_DMA_CHANNEL_4); serve_tx_end_irq(&UARTD1); CH_IRQ_EPILOGUE(); @@ -315,8 +316,8 @@ CH_IRQ_HANDLER(DMA1_Ch6_IRQHandler) { if ((STM32_DMA1->ISR & DMA_ISR_TEIF6) != 0) { STM32_UART_USART2_DMA_ERROR_HOOK(); } - dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_6); if (uartp->ud_rxstate == UART_RX_IDLE) { + dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_6); /* Fast IRQ path, this is why it is not centralized in serve_rx_end_irq().*/ /* Receiver in idle state, a callback is generated, if enabled, for each received character and then the driver stays in the same state.*/ @@ -327,6 +328,7 @@ CH_IRQ_HANDLER(DMA1_Ch6_IRQHandler) { /* Receiver in active state, a callback is generated, if enabled, after a completed transfer.*/ dmaDisableChannel(STM32_DMA1, STM32_DMA_CHANNEL_6); + dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_6); serve_rx_end_irq(uartp); } @@ -363,6 +365,68 @@ CH_IRQ_HANDLER(USART2_IRQHandler) { } #endif /* STM32_UART_USE_USART2 */ +#if STM32_UART_USE_USART3 || defined(__DOXYGEN__) +/** + * @brief USART3 RX DMA interrupt handler (channel 3). + */ +CH_IRQ_HANDLER(DMA1_Ch3_IRQHandler) { + UARTDriver *uartp; + + CH_IRQ_PROLOGUE(); + + uartp = &UARTD3; + if ((STM32_DMA1->ISR & DMA_ISR_TEIF3) != 0) { + STM32_UART_USART1_DMA_ERROR_HOOK(); + } + if (uartp->ud_rxstate == UART_RX_IDLE) { + dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_3); + /* Fast IRQ path, this is why it is not centralized in serve_rx_end_irq().*/ + /* Receiver in idle state, a callback is generated, if enabled, for each + received character and then the driver stays in the same state.*/ + if (uartp->ud_config->uc_rxchar != NULL) + uartp->ud_config->uc_rxchar(uartp->ud_rxbuf); + } + else { + /* Receiver in active state, a callback is generated, if enabled, after + a completed transfer.*/ + dmaDisableChannel(STM32_DMA1, STM32_DMA_CHANNEL_3); + dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_3); + serve_rx_end_irq(uartp); + } + + CH_IRQ_EPILOGUE(); +} + +/** + * @brief USART3 TX DMA interrupt handler (channel 2). + */ +CH_IRQ_HANDLER(DMA1_Ch2_IRQHandler) { + + CH_IRQ_PROLOGUE(); + + if ((STM32_DMA1->ISR & DMA_ISR_TEIF2) != 0) { + STM32_UART_USART1_DMA_ERROR_HOOK(); + } + dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_2); + dmaDisableChannel(STM32_DMA1, STM32_DMA_CHANNEL_2); + serve_tx_end_irq(&UARTD3); + + CH_IRQ_EPILOGUE(); +} + +/** + * @brief USART3 IRQ handler. + */ +CH_IRQ_HANDLER(USART3_IRQHandler) { + + CH_IRQ_PROLOGUE(); + + serve_usart_irq(&UARTD3); + + CH_IRQ_EPILOGUE(); +} +#endif /* STM32_UART_USE_USART3 */ + /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ @@ -378,8 +442,8 @@ void uart_lld_init(void) { uartObjectInit(&UARTD1); UARTD1.ud_usart = USART1; UARTD1.ud_dmap = STM32_DMA1; - UARTD1.ud_dmarx = STM32_DMA_CHANNEL_4; - UARTD1.ud_dmatx = STM32_DMA_CHANNEL_5; + UARTD1.ud_dmarx = STM32_DMA_CHANNEL_5; + UARTD1.ud_dmatx = STM32_DMA_CHANNEL_4; UARTD1.ud_dmaccr = 0; #endif @@ -393,6 +457,17 @@ void uart_lld_init(void) { UARTD2.ud_dmatx = STM32_DMA_CHANNEL_7; UARTD2.ud_dmaccr = 0; #endif + +#if STM32_UART_USE_USART3 + RCC->APB1RSTR = RCC_APB1RSTR_USART3RST; + RCC->APB1RSTR = 0; + uartObjectInit(&UARTD3); + UARTD2.ud_usart = USART3; + UARTD2.ud_dmap = STM32_DMA1; + UARTD2.ud_dmarx = STM32_DMA_CHANNEL_3; + UARTD2.ud_dmatx = STM32_DMA_CHANNEL_2; + UARTD2.ud_dmaccr = 0; +#endif } /** @@ -429,6 +504,19 @@ void uart_lld_start(UARTDriver *uartp) { } #endif +#if STM32_UART_USE_USART3 + if (&UARTD3 == uartp) { + dmaEnable(DMA1_ID); /* NOTE: Must be enabled before the IRQs.*/ + NVICEnableVector(USART3_IRQn, + CORTEX_PRIORITY_MASK(STM32_UART_USART3_IRQ_PRIORITY)); + NVICEnableVector(DMA1_Channel2_IRQn, + CORTEX_PRIORITY_MASK(STM32_UART_USART3_IRQ_PRIORITY)); + NVICEnableVector(DMA1_Channel3_IRQn, + CORTEX_PRIORITY_MASK(STM32_UART_USART3_IRQ_PRIORITY)); + RCC->APB1ENR |= RCC_APB1ENR_USART3EN; + } +#endif + /* Static DMA setup, the transfer size depends on the USART settings, it is 16 bits if M=1 and PCE=0 else it is 8 bits.*/ uartp->ud_dmaccr = STM32_UART_USART1_DMA_PRIORITY << 12; @@ -475,6 +563,17 @@ void uart_lld_stop(UARTDriver *uartp) { return; } #endif + +#if STM32_UART_USE_USART3 + if (&UARTD3 == uartp) { + NVICDisableVector(USART3_IRQn); + NVICDisableVector(DMA1_Channel2_IRQn); + NVICDisableVector(DMA1_Channel3_IRQn); + dmaDisable(DMA1_ID); + RCC->APB1ENR &= ~RCC_APB1ENR_USART3EN; + return; + } +#endif } } @@ -519,9 +618,15 @@ void uart_lld_stop_send(UARTDriver *uartp) { */ void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf) { - (void)uartp; - (void)n; - (void)rxbuf; + /* Stopping previous activity (idle state).*/ + dmaDisableChannel(uartp->ud_dmap, uartp->ud_dmarx); + dmaClearChannel(uartp->ud_dmap, uartp->ud_dmarx); + + /* RX DMA channel preparation and start.*/ + dmaSetupChannel(uartp->ud_dmap, uartp->ud_dmarx, n, rxbuf, + uartp->ud_dmaccr | DMA_CCR1_MINC | + DMA_CCR1_TEIE | DMA_CCR1_TCIE); + dmaEnableChannel(uartp->ud_dmap, uartp->ud_dmarx); } /** @@ -532,7 +637,9 @@ void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf) { */ void uart_lld_stop_receive(UARTDriver *uartp) { - (void)uartp; + dmaDisableChannel(uartp->ud_dmap, uartp->ud_dmarx); + dmaClearChannel(uartp->ud_dmap, uartp->ud_dmarx); + set_rx_idle_loop(uartp); } #endif /* CH_HAL_USE_UART */ diff --git a/readme.txt b/readme.txt index 36aa0ef95..ab278c071 100644 --- a/readme.txt +++ b/readme.txt @@ -79,6 +79,8 @@ - NEW: Centralized DMA macros in the STM32 HAL. - NEW: New UART device driver model, this device driver allows unbuffered, callback driven access to UART-type devices. +- NEW: UART device driver for STM32 and UART demo application under + ./testhal/STM32/UART. - NEW: Added friendly interrupt vectors names to the STM32 HAL (change request 3023944). - NEW: Added support for SPI3 in the STM32 HAL. diff --git a/testhal/STM32/UART/main.c b/testhal/STM32/UART/main.c index 214cf35db..e111935d7 100644 --- a/testhal/STM32/UART/main.c +++ b/testhal/STM32/UART/main.c @@ -20,7 +20,7 @@ #include "ch.h" #include "hal.h" -static VirtualTimer vt; +static VirtualTimer vt1, vt2; static void restart(void *p) { @@ -28,31 +28,66 @@ static void restart(void *p) { uartStartSend(&UARTD2, 14, "Hello World!\r\n"); } -static void txend1(void) { +static void ledoff(void *p) { + (void)p; + palSetPad(IOPORT3, GPIOC_LED); } +/* + * This callback is invoked when a transmission buffer has been completely + * read by the driver. + */ +static void txend1(void) { + + palClearPad(IOPORT3, GPIOC_LED); +} + +/* + * This callback is invoked when a transmission has phisically completed. + */ static void txend2(void) { + palSetPad(IOPORT3, GPIOC_LED); chSysLockFromIsr(); - chVTSetI(&vt, MS2ST(1000), restart, NULL); + chVTSetI(&vt1, MS2ST(5000), restart, NULL); chSysUnlockFromIsr(); } +/* + * This callback is invoked on a receive error, the errors mask is passed + * as parameter. + */ static void rxerr(uartflags_t e) { (void)e; } +/* + * This callback is invoked when a character is received but the application + * was not ready to receive it, the character is passed as parameter. + */ static void rxchar(uint16_t c) { (void)c; + /* Flashing the LED each time a character is received.*/ + palClearPad(IOPORT3, GPIOC_LED); + chSysLockFromIsr(); + if (!chVTIsArmedI(&vt2)) + chVTSetI(&vt2, MS2ST(200), ledoff, NULL); + chSysUnlockFromIsr(); } +/* + * This callback is invoked when a receive buffer has been completely written. + */ static void rxend(void) { } +/* + * UART driver configuration structure. + */ static UARTConfig uart_cfg_1 = { txend1, txend2, @@ -65,22 +100,6 @@ static UARTConfig uart_cfg_1 = { 0 }; -/* - * Red LEDs blinker thread, times are in milliseconds. - */ -static WORKING_AREA(waThread1, 128); -static msg_t Thread1(void *arg) { - - (void)arg; - while (TRUE) { - palClearPad(IOPORT3, GPIOC_LED); - chThdSleepMilliseconds(500); - palSetPad(IOPORT3, GPIOC_LED); - chThdSleepMilliseconds(500); - } - return 0; -} - /* * Entry point, note, the main() function is already a thread in the system * on entry. @@ -95,11 +114,6 @@ int main(int argc, char **argv) { */ uartStart(&UARTD2, &uart_cfg_1); - /* - * Creates the blinker thread. - */ - chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL); - /* * Starts the transmission, it will be handled entirely in background. */