aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal/ports/KINETIS/LLD/hal_serial_lld.c
diff options
context:
space:
mode:
Diffstat (limited to 'os/hal/ports/KINETIS/LLD/hal_serial_lld.c')
-rw-r--r--os/hal/ports/KINETIS/LLD/hal_serial_lld.c239
1 files changed, 168 insertions, 71 deletions
diff --git a/os/hal/ports/KINETIS/LLD/hal_serial_lld.c b/os/hal/ports/KINETIS/LLD/hal_serial_lld.c
index c75d41a..c92fa5c 100644
--- a/os/hal/ports/KINETIS/LLD/hal_serial_lld.c
+++ b/os/hal/ports/KINETIS/LLD/hal_serial_lld.c
@@ -1,5 +1,6 @@
/*
ChibiOS - Copyright (C) 2013-2015 Fabio Utzig
+ Copyright (C) 2017 Wim Lewis
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -107,33 +108,37 @@ static void serve_error_interrupt(SerialDriver *sdp) {
UART_w_TypeDef *u = &(sdp->uart);
uint8_t s1 = *(u->s1_p);
- /* S1 bits are write-1-to-clear for UART0 on KL2x. */
- /* Clearing on K20x and KL2x/UART>0 is done by reading S1 and
+ /* Clearing on K20x, K60x, and KL2x/UART>0 is done by reading S1 and
* then reading D.*/
-#if defined(KL2x) && KINETIS_SERIAL_USE_UART0
- if(sdp == &SD1) {
- if(s1 & UARTx_S1_IDLE) {
- *(u->s1_p) |= UARTx_S1_IDLE;
- }
+ if(s1 & UARTx_S1_IDLE) {
+ (void)*(u->d_p);
+ }
- if(s1 & (UARTx_S1_OR | UARTx_S1_NF | UARTx_S1_FE | UARTx_S1_PF)) {
- set_error(sdp, s1);
- *(u->s1_p) |= UARTx_S1_OR | UARTx_S1_NF | UARTx_S1_FE | UARTx_S1_PF;
- }
- return;
+ if(s1 & (UARTx_S1_OR | UARTx_S1_NF | UARTx_S1_FE | UARTx_S1_PF)) {
+ set_error(sdp, s1);
+ (void)*(u->d_p);
}
-#endif /* KL2x && KINETIS_SERIAL_USE_UART0 */
+}
+
+#if defined(KL2x) && KINETIS_SERIAL_USE_UART0
+static void serve_error_interrupt_uart0(void) {
+ SerialDriver *sdp = &SD1;
+ UART_w_TypeDef *u = &(sdp->uart);
+ uint8_t s1 = *(u->s1_p);
+
+ /* S1 bits are write-1-to-clear for UART0 on KL2x. */
if(s1 & UARTx_S1_IDLE) {
- (void)*(u->d_p);
+ *(u->s1_p) |= UARTx_S1_IDLE;
}
if(s1 & (UARTx_S1_OR | UARTx_S1_NF | UARTx_S1_FE | UARTx_S1_PF)) {
set_error(sdp, s1);
- (void)*(u->d_p);
+ *(u->s1_p) |= UARTx_S1_OR | UARTx_S1_NF | UARTx_S1_FE | UARTx_S1_PF;
}
}
+#endif /* KL2x && KINETIS_SERIAL_USE_UART0 */
/**
* @brief Common IRQ handler.
@@ -173,6 +178,12 @@ static void serve_interrupt(SerialDriver *sdp) {
}
}
+#if defined(KL2x) && KINETIS_SERIAL_USE_UART0
+ if (sdp == &SD1) {
+ serve_error_interrupt_uart0();
+ return;
+ }
+#endif
serve_error_interrupt(sdp);
}
@@ -196,29 +207,28 @@ static void preload(SerialDriver *sdp) {
/**
* @brief Driver output notification.
*/
-#if KINETIS_SERIAL_USE_UART0 || defined(__DOXYGEN__)
-static void notify1(io_queue_t *qp)
+static void notify(io_queue_t *qp)
{
- (void)qp;
- preload(&SD1);
+ preload(qp->q_link);
}
-#endif
-#if KINETIS_SERIAL_USE_UART1 || defined(__DOXYGEN__)
-static void notify2(io_queue_t *qp)
-{
- (void)qp;
- preload(&SD2);
+/**
+ * @brief Common driver initialization, except LP.
+ */
+static void sd_lld_init_driver(SerialDriver *SDn, UART_TypeDef *UARTn) {
+ /* Driver initialization.*/
+ sdObjectInit(SDn, NULL, notify);
+ SDn->uart.bdh_p = &(UARTn->BDH);
+ SDn->uart.bdl_p = &(UARTn->BDL);
+ SDn->uart.c1_p = &(UARTn->C1);
+ SDn->uart.c2_p = &(UARTn->C2);
+ SDn->uart.c3_p = &(UARTn->C3);
+ SDn->uart.c4_p = &(UARTn->C4);
+ SDn->uart.s1_p = (volatile uint8_t *)&(UARTn->S1);
+ SDn->uart.s2_p = &(UARTn->S2);
+ SDn->uart.d_p = &(UARTn->D);
+ SDn->uart.uart_p = UARTn;
}
-#endif
-
-#if KINETIS_SERIAL_USE_UART2 || defined(__DOXYGEN__)
-static void notify3(io_queue_t *qp)
-{
- (void)qp;
- preload(&SD3);
-}
-#endif
/**
* @brief Common UART configuration.
@@ -252,9 +262,9 @@ static void configure_uart(SerialDriver *sdp, const SerialConfig *config) {
}
#endif /* KINETIS_SERIAL_USE_UART0 */
-#elif defined(K20x) /* KL2x */
+#elif defined(K20x) || defined(K60x) /* KL2x */
- /* UARTs 0 and 1 are clocked from SYSCLK, others from BUSCLK on K20x. */
+ /* UARTs 0 and 1 are clocked from SYSCLK, others from BUSCLK on K20x and K60x. */
#if KINETIS_SERIAL_USE_UART0
if(sdp == &SD1)
divisor = KINETIS_SYSCLK_FREQUENCY;
@@ -272,9 +282,9 @@ static void configure_uart(SerialDriver *sdp, const SerialConfig *config) {
*(uart->bdh_p) = UARTx_BDH_SBR(divisor >> 13) | (*(uart->bdh_p) & ~UARTx_BDH_SBR_MASK);
*(uart->bdl_p) = UARTx_BDL_SBR(divisor >> 5);
-#if defined(K20x)
+#if defined(K20x) || defined(K60x)
*(uart->c4_p) = UARTx_C4_BRFA(divisor) | (*(uart->c4_p) & ~UARTx_C4_BRFA_MASK);
-#endif /* K20x */
+#endif /* K20x, K60x */
/* Line settings. */
*(uart->c1_p) = 0;
@@ -312,12 +322,40 @@ OSAL_IRQ_HANDLER(KINETIS_SERIAL2_IRQ_VECTOR) {
}
#endif
+#if KINETIS_SERIAL_USE_UART3 || defined(__DOXYGEN__)
+OSAL_IRQ_HANDLER(KINETIS_SERIAL3_IRQ_VECTOR) {
+ OSAL_IRQ_PROLOGUE();
+ serve_interrupt(&SD4);
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if KINETIS_SERIAL_USE_UART4 || defined(__DOXYGEN__)
+OSAL_IRQ_HANDLER(KINETIS_SERIAL4_IRQ_VECTOR) {
+ OSAL_IRQ_PROLOGUE();
+ serve_interrupt(&SD5);
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if KINETIS_SERIAL_USE_UART5 || defined(__DOXYGEN__)
+OSAL_IRQ_HANDLER(KINETIS_SERIAL5_IRQ_VECTOR) {
+ OSAL_IRQ_PROLOGUE();
+ serve_interrupt(&SD6);
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
#if KINETIS_HAS_SERIAL_ERROR_IRQ
#if KINETIS_SERIAL_USE_UART0 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(KINETIS_SERIAL0_ERROR_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE();
+#if defined(KL2x)
+ serve_error_interrupt_uart0();
+#else
serve_error_interrupt(&SD1);
+#endif
OSAL_IRQ_EPILOGUE();
}
#endif
@@ -338,6 +376,30 @@ OSAL_IRQ_HANDLER(KINETIS_SERIAL2_ERROR_IRQ_VECTOR) {
}
#endif
+#if KINETIS_SERIAL_USE_UART3 || defined(__DOXYGEN__)
+OSAL_IRQ_HANDLER(KINETIS_SERIAL3_ERROR_IRQ_VECTOR) {
+ OSAL_IRQ_PROLOGUE();
+ serve_error_interrupt(&SD4);
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if KINETIS_SERIAL_USE_UART4 || defined(__DOXYGEN__)
+OSAL_IRQ_HANDLER(KINETIS_SERIAL4_ERROR_IRQ_VECTOR) {
+ OSAL_IRQ_PROLOGUE();
+ serve_error_interrupt(&SD5);
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if KINETIS_SERIAL_USE_UART5 || defined(__DOXYGEN__)
+OSAL_IRQ_HANDLER(KINETIS_SERIAL5_ERROR_IRQ_VECTOR) {
+ OSAL_IRQ_PROLOGUE();
+ serve_error_interrupt(&SD6);
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
#endif /* KINETIS_HAS_SERIAL_ERROR_IRQ */
/*===========================================================================*/
@@ -353,19 +415,11 @@ void sd_lld_init(void) {
#if KINETIS_SERIAL_USE_UART0
/* Driver initialization.*/
- sdObjectInit(&SD1, NULL, notify1);
#if ! KINETIS_SERIAL0_IS_LPUART
- SD1.uart.bdh_p = &(UART0->BDH);
- SD1.uart.bdl_p = &(UART0->BDL);
- SD1.uart.c1_p = &(UART0->C1);
- SD1.uart.c2_p = &(UART0->C2);
- SD1.uart.c3_p = &(UART0->C3);
- SD1.uart.c4_p = &(UART0->C4);
- SD1.uart.s1_p = (volatile uint8_t *)&(UART0->S1);
- SD1.uart.s2_p = &(UART0->S2);
- SD1.uart.d_p = &(UART0->D);
+ sd_lld_init_driver(&SD1, UART0);
#else /* ! KINETIS_SERIAL0_IS_LPUART */
/* little endian! */
+ sdObjectInit(&SD1, NULL, notify);
SD1.uart.bdh_p = ((uint8_t *)&(LPUART0->BAUD)) + 1; /* BDH: BAUD, byte 3 */
SD1.uart.bdl_p = ((uint8_t *)&(LPUART0->BAUD)) + 0; /* BDL: BAUD, byte 4 */
SD1.uart.c1_p = ((uint8_t *)&(LPUART0->CTRL)) + 0; /* C1: CTRL, byte 4 */
@@ -389,20 +443,11 @@ void sd_lld_init(void) {
#if KINETIS_SERIAL_USE_UART1
/* Driver initialization.*/
- sdObjectInit(&SD2, NULL, notify2);
#if ! KINETIS_SERIAL1_IS_LPUART
- SD2.uart.bdh_p = &(UART1->BDH);
- SD2.uart.bdl_p = &(UART1->BDL);
- SD2.uart.c1_p = &(UART1->C1);
- SD2.uart.c2_p = &(UART1->C2);
- SD2.uart.c3_p = &(UART1->C3);
- SD2.uart.c4_p = &(UART1->C4);
- SD2.uart.s1_p = (volatile uint8_t *)&(UART1->S1);
- SD2.uart.s2_p = &(UART1->S2);
- SD2.uart.d_p = &(UART1->D);
- SD2.uart.uart_p = UART1;
+ sd_lld_init_driver(&SD2, UART1);
#else /* ! KINETIS_SERIAL1_IS_LPUART */
/* little endian! */
+ sdObjectInit(&SD2, NULL, notify);
SD2.uart.bdh_p = ((uint8_t *)&(LPUART1->BAUD)) + 1; /* BDH: BAUD, byte 3 */
SD2.uart.bdl_p = ((uint8_t *)&(LPUART1->BAUD)) + 0; /* BDL: BAUD, byte 4 */
SD2.uart.c1_p = ((uint8_t *)&(LPUART1->CTRL)) + 0; /* C1: CTRL, byte 4 */
@@ -418,19 +463,20 @@ void sd_lld_init(void) {
#endif /* KINETIS_SERIAL_USE_UART1 */
#if KINETIS_SERIAL_USE_UART2
- /* Driver initialization.*/
- sdObjectInit(&SD3, NULL, notify3);
- SD3.uart.bdh_p = &(UART2->BDH);
- SD3.uart.bdl_p = &(UART2->BDL);
- SD3.uart.c1_p = &(UART2->C1);
- SD3.uart.c2_p = &(UART2->C2);
- SD3.uart.c3_p = &(UART2->C3);
- SD3.uart.c4_p = &(UART2->C4);
- SD3.uart.s1_p = (volatile uint8_t *)&(UART2->S1);
- SD3.uart.s2_p = &(UART2->S2);
- SD3.uart.d_p = &(UART2->D);
- SD3.uart.uart_p = UART2;
+ sd_lld_init_driver(&SD3, UART2);
#endif /* KINETIS_SERIAL_USE_UART2 */
+
+#if KINETIS_SERIAL_USE_UART3
+ sd_lld_init_driver(&SD4, UART3);
+#endif /* KINETIS_SERIAL_USE_UART3 */
+
+#if KINETIS_SERIAL_USE_UART4
+ sd_lld_init_driver(&SD5, UART4);
+#endif /* KINETIS_SERIAL_USE_UART4 */
+
+#if KINETIS_SERIAL_USE_UART5
+ sd_lld_init_driver(&SD6, UART5);
+#endif /* KINETIS_SERIAL_USE_UART5 */
}
/**
@@ -517,6 +563,33 @@ void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
}
#endif /* KINETIS_SERIAL_USE_UART2 */
+#if KINETIS_SERIAL_USE_UART3
+ if (sdp == &SD4) {
+ SIM->SCGC4 |= SIM_SCGC4_UART3;
+ configure_uart(sdp, config);
+ nvicEnableVector(UART3Status_IRQn, KINETIS_SERIAL_UART3_PRIORITY);
+ nvicEnableVector(UART3Error_IRQn, KINETIS_SERIAL_UART3_PRIORITY);
+ }
+#endif /* KINETIS_SERIAL_USE_UART3 */
+
+#if KINETIS_SERIAL_USE_UART4
+ if (sdp == &SD5) {
+ SIM->SCGC1 |= SIM_SCGC1_UART4;
+ configure_uart(sdp, config);
+ nvicEnableVector(UART4Status_IRQn, KINETIS_SERIAL_UART4_PRIORITY);
+ nvicEnableVector(UART4Error_IRQn, KINETIS_SERIAL_UART4_PRIORITY);
+ }
+#endif /* KINETIS_SERIAL_USE_UART4 */
+
+#if KINETIS_SERIAL_USE_UART5
+ if (sdp == &SD6) {
+ SIM->SCGC1 |= SIM_SCGC1_UART5;
+ configure_uart(sdp, config);
+ nvicEnableVector(UART5Status_IRQn, KINETIS_SERIAL_UART5_PRIORITY);
+ nvicEnableVector(UART5Error_IRQn, KINETIS_SERIAL_UART5_PRIORITY);
+ }
+#endif /* KINETIS_SERIAL_USE_UART5 */
+
}
/* Configures the peripheral.*/
@@ -587,6 +660,30 @@ void sd_lld_stop(SerialDriver *sdp) {
SIM->SCGC4 &= ~SIM_SCGC4_UART2;
}
#endif
+
+#if KINETIS_SERIAL_USE_UART3
+ if (sdp == &SD4) {
+ nvicDisableVector(UART3Status_IRQn);
+ nvicDisableVector(UART3Error_IRQn);
+ SIM->SCGC4 &= ~SIM_SCGC4_UART3;
+ }
+#endif
+
+#if KINETIS_SERIAL_USE_UART4
+ if (sdp == &SD5) {
+ nvicDisableVector(UART4Status_IRQn);
+ nvicDisableVector(UART4Error_IRQn);
+ SIM->SCGC1 &= ~SIM_SCGC1_UART4;
+ }
+#endif
+
+#if KINETIS_SERIAL_USE_UART5
+ if (sdp == &SD6) {
+ nvicDisableVector(UART5Status_IRQn);
+ nvicDisableVector(UART5Error_IRQn);
+ SIM->SCGC1 &= ~SIM_SCGC1_UART5;
+ }
+#endif
}
}