diff options
-rw-r--r-- | os/hal/platforms/STM32/uart_lld.c | 141 | ||||
-rw-r--r-- | readme.txt | 2 | ||||
-rw-r--r-- | testhal/STM32/UART/main.c | 60 |
3 files changed, 163 insertions, 40 deletions
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 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,
@@ -66,22 +101,6 @@ static UARTConfig uart_cfg_1 = { };
/*
- * 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.
*/
@@ -96,11 +115,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. */
uartStartSend(&UARTD2, 13, "Starting...\r\n");
|