Added support for additional UARTs (up to six on the K64F).

Also moved some code that is duplicated per-UART into
local functions to reduce the amount of duplication.
This commit is contained in:
Wim Lewis 2017-12-08 19:42:13 -08:00
parent ec4b244c51
commit c4eb6b4901
2 changed files with 249 additions and 73 deletions

View File

@ -1,5 +1,6 @@
/* /*
ChibiOS - Copyright (C) 2013-2015 Fabio Utzig ChibiOS - Copyright (C) 2013-2015 Fabio Utzig
Copyright (C) 2017 Wim Lewis
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -50,6 +51,18 @@ SerialDriver SD2;
SerialDriver SD3; SerialDriver SD3;
#endif #endif
#if KINETIS_SERIAL_USE_UART3 || defined(__DOXYGEN__)
SerialDriver SD4;
#endif
#if KINETIS_SERIAL_USE_UART4 || defined(__DOXYGEN__)
SerialDriver SD5;
#endif
#if KINETIS_SERIAL_USE_UART5 || defined(__DOXYGEN__)
SerialDriver SD6;
#endif
/*===========================================================================*/ /*===========================================================================*/
/* Driver local variables and types. */ /* Driver local variables and types. */
/*===========================================================================*/ /*===========================================================================*/
@ -95,24 +108,9 @@ static void serve_error_interrupt(SerialDriver *sdp) {
UART_w_TypeDef *u = &(sdp->uart); UART_w_TypeDef *u = &(sdp->uart);
uint8_t s1 = *(u->s1_p); uint8_t s1 = *(u->s1_p);
/* S1 bits are write-1-to-clear for UART0 on KL2x. */ /* Clearing on K20x, K60x, and KL2x/UART>0 is done by reading S1 and
/* Clearing on K20x and KL2x/UART>0 is done by reading S1 and
* then reading D.*/ * 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_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;
}
#endif /* KL2x && KINETIS_SERIAL_USE_UART0 */
if(s1 & UARTx_S1_IDLE) { if(s1 & UARTx_S1_IDLE) {
(void)*(u->d_p); (void)*(u->d_p);
} }
@ -123,6 +121,25 @@ static void serve_error_interrupt(SerialDriver *sdp) {
} }
} }
#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) {
*(u->s1_p) |= UARTx_S1_IDLE;
}
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;
}
}
#endif /* KL2x && KINETIS_SERIAL_USE_UART0 */
/** /**
* @brief Common IRQ handler. * @brief Common IRQ handler.
* @note Tries hard to clear all the pending interrupt sources, we don't * @note Tries hard to clear all the pending interrupt sources, we don't
@ -161,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); serve_error_interrupt(sdp);
} }
@ -184,29 +207,28 @@ static void preload(SerialDriver *sdp) {
/** /**
* @brief Driver output notification. * @brief Driver output notification.
*/ */
#if KINETIS_SERIAL_USE_UART0 || defined(__DOXYGEN__) static void notify(io_queue_t *qp)
static void notify1(io_queue_t *qp)
{ {
(void)qp; preload(qp->q_link);
preload(&SD1);
} }
#endif
#if KINETIS_SERIAL_USE_UART1 || defined(__DOXYGEN__) /**
static void notify2(io_queue_t *qp) * @brief Common driver initialization, except LP.
{ */
(void)qp; static void sd_lld_init_driver(SerialDriver *SDn, UART_TypeDef *UARTn) {
preload(&SD2); /* 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. * @brief Common UART configuration.
@ -240,9 +262,9 @@ static void configure_uart(SerialDriver *sdp, const SerialConfig *config) {
} }
#endif /* KINETIS_SERIAL_USE_UART0 */ #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 KINETIS_SERIAL_USE_UART0
if(sdp == &SD1) if(sdp == &SD1)
divisor = KINETIS_SYSCLK_FREQUENCY; divisor = KINETIS_SYSCLK_FREQUENCY;
@ -260,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->bdh_p) = UARTx_BDH_SBR(divisor >> 13) | (*(uart->bdh_p) & ~UARTx_BDH_SBR_MASK);
*(uart->bdl_p) = UARTx_BDL_SBR(divisor >> 5); *(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); *(uart->c4_p) = UARTx_C4_BRFA(divisor) | (*(uart->c4_p) & ~UARTx_C4_BRFA_MASK);
#endif /* K20x */ #endif /* K20x, K60x */
/* Line settings. */ /* Line settings. */
*(uart->c1_p) = 0; *(uart->c1_p) = 0;
@ -300,12 +322,40 @@ OSAL_IRQ_HANDLER(KINETIS_SERIAL2_IRQ_VECTOR) {
} }
#endif #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_HAS_SERIAL_ERROR_IRQ
#if KINETIS_SERIAL_USE_UART0 || defined(__DOXYGEN__) #if KINETIS_SERIAL_USE_UART0 || defined(__DOXYGEN__)
OSAL_IRQ_HANDLER(KINETIS_SERIAL0_ERROR_IRQ_VECTOR) { OSAL_IRQ_HANDLER(KINETIS_SERIAL0_ERROR_IRQ_VECTOR) {
OSAL_IRQ_PROLOGUE(); OSAL_IRQ_PROLOGUE();
#if defined(KL2x)
serve_error_interrupt_uart0();
#else
serve_error_interrupt(&SD1); serve_error_interrupt(&SD1);
#endif
OSAL_IRQ_EPILOGUE(); OSAL_IRQ_EPILOGUE();
} }
#endif #endif
@ -326,6 +376,30 @@ OSAL_IRQ_HANDLER(KINETIS_SERIAL2_ERROR_IRQ_VECTOR) {
} }
#endif #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 */ #endif /* KINETIS_HAS_SERIAL_ERROR_IRQ */
/*===========================================================================*/ /*===========================================================================*/
@ -341,19 +415,11 @@ void sd_lld_init(void) {
#if KINETIS_SERIAL_USE_UART0 #if KINETIS_SERIAL_USE_UART0
/* Driver initialization.*/ /* Driver initialization.*/
sdObjectInit(&SD1, NULL, notify1);
#if ! KINETIS_SERIAL0_IS_LPUART #if ! KINETIS_SERIAL0_IS_LPUART
SD1.uart.bdh_p = &(UART0->BDH); sd_lld_init_driver(&SD1, UART0);
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);
#else /* ! KINETIS_SERIAL0_IS_LPUART */ #else /* ! KINETIS_SERIAL0_IS_LPUART */
/* little endian! */ /* little endian! */
sdObjectInit(&SD1, NULL, notify);
SD1.uart.bdh_p = ((uint8_t *)&(LPUART0->BAUD)) + 1; /* BDH: BAUD, byte 3 */ 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.bdl_p = ((uint8_t *)&(LPUART0->BAUD)) + 0; /* BDL: BAUD, byte 4 */
SD1.uart.c1_p = ((uint8_t *)&(LPUART0->CTRL)) + 0; /* C1: CTRL, byte 4 */ SD1.uart.c1_p = ((uint8_t *)&(LPUART0->CTRL)) + 0; /* C1: CTRL, byte 4 */
@ -377,20 +443,11 @@ void sd_lld_init(void) {
#if KINETIS_SERIAL_USE_UART1 #if KINETIS_SERIAL_USE_UART1
/* Driver initialization.*/ /* Driver initialization.*/
sdObjectInit(&SD2, NULL, notify2);
#if ! KINETIS_SERIAL1_IS_LPUART #if ! KINETIS_SERIAL1_IS_LPUART
SD2.uart.bdh_p = &(UART1->BDH); sd_lld_init_driver(&SD2, UART1);
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;
#else /* ! KINETIS_SERIAL1_IS_LPUART */ #else /* ! KINETIS_SERIAL1_IS_LPUART */
/* little endian! */ /* little endian! */
sdObjectInit(&SD2, NULL, notify);
SD2.uart.bdh_p = ((uint8_t *)&(LPUART1->BAUD)) + 1; /* BDH: BAUD, byte 3 */ 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.bdl_p = ((uint8_t *)&(LPUART1->BAUD)) + 0; /* BDL: BAUD, byte 4 */
SD2.uart.c1_p = ((uint8_t *)&(LPUART1->CTRL)) + 0; /* C1: CTRL, byte 4 */ SD2.uart.c1_p = ((uint8_t *)&(LPUART1->CTRL)) + 0; /* C1: CTRL, byte 4 */
@ -406,19 +463,20 @@ void sd_lld_init(void) {
#endif /* KINETIS_SERIAL_USE_UART1 */ #endif /* KINETIS_SERIAL_USE_UART1 */
#if KINETIS_SERIAL_USE_UART2 #if KINETIS_SERIAL_USE_UART2
/* Driver initialization.*/ sd_lld_init_driver(&SD3, UART2);
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;
#endif /* KINETIS_SERIAL_USE_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 */
} }
/** /**
@ -505,6 +563,33 @@ void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
} }
#endif /* KINETIS_SERIAL_USE_UART2 */ #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.*/ /* Configures the peripheral.*/
@ -575,6 +660,30 @@ void sd_lld_stop(SerialDriver *sdp) {
SIM->SCGC4 &= ~SIM_SCGC4_UART2; SIM->SCGC4 &= ~SIM_SCGC4_UART2;
} }
#endif #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
} }
} }

View File

@ -60,6 +60,27 @@
#if !defined(KINETIS_SERIAL_USE_UART2) || defined(__DOXYGEN__) #if !defined(KINETIS_SERIAL_USE_UART2) || defined(__DOXYGEN__)
#define KINETIS_SERIAL_USE_UART2 FALSE #define KINETIS_SERIAL_USE_UART2 FALSE
#endif #endif
/**
* @brief SD4 driver enable switch.
* @details If set to @p TRUE the support for SD4 is included.
*/
#if !defined(KINETIS_SERIAL_USE_UART3) || defined(__DOXYGEN__)
#define KINETIS_SERIAL_USE_UART3 FALSE
#endif
/**
* @brief SD5 driver enable switch.
* @details If set to @p TRUE the support for SD5 is included.
*/
#if !defined(KINETIS_SERIAL_USE_UART4) || defined(__DOXYGEN__)
#define KINETIS_SERIAL_USE_UART4 FALSE
#endif
/**
* @brief SD6 driver enable switch.
* @details If set to @p TRUE the support for SD6 is included.
*/
#if !defined(KINETIS_SERIAL_USE_UART5) || defined(__DOXYGEN__)
#define KINETIS_SERIAL_USE_UART5 FALSE
#endif
/** /**
* @brief UART0 interrupt priority level setting. * @brief UART0 interrupt priority level setting.
@ -82,6 +103,27 @@
#define KINETIS_SERIAL_UART2_PRIORITY 12 #define KINETIS_SERIAL_UART2_PRIORITY 12
#endif #endif
/**
* @brief UART3 interrupt priority level setting.
*/
#if !defined(KINETIS_SERIAL_UART3_PRIORITY) || defined(__DOXYGEN__)
#define KINETIS_SERIAL_UART3_PRIORITY 12
#endif
/**
* @brief UART4 interrupt priority level setting.
*/
#if !defined(KINETIS_SERIAL_UART4_PRIORITY) || defined(__DOXYGEN__)
#define KINETIS_SERIAL_UART4_PRIORITY 12
#endif
/**
* @brief UART5 interrupt priority level setting.
*/
#if !defined(KINETIS_SERIAL_UART5_PRIORITY) || defined(__DOXYGEN__)
#define KINETIS_SERIAL_UART5_PRIORITY 12
#endif
/** /**
* @brief UART0 clock source. * @brief UART0 clock source.
*/ */
@ -115,8 +157,21 @@
#error "UART2 not present in the selected device" #error "UART2 not present in the selected device"
#endif #endif
#if KINETIS_SERIAL_USE_UART3 && !KINETIS_HAS_SERIAL3
#error "UART3 not present in the selected device"
#endif
#if KINETIS_SERIAL_USE_UART4 && !KINETIS_HAS_SERIAL4
#error "UART4 not present in the selected device"
#endif
#if KINETIS_SERIAL_USE_UART5 && !KINETIS_HAS_SERIAL5
#error "UART5 not present in the selected device"
#endif
#if !(KINETIS_SERIAL_USE_UART0 || KINETIS_SERIAL_USE_UART1 || \ #if !(KINETIS_SERIAL_USE_UART0 || KINETIS_SERIAL_USE_UART1 || \
KINETIS_SERIAL_USE_UART2) KINETIS_SERIAL_USE_UART2 || KINETIS_SERIAL_USE_UART3 || \
KINETIS_SERIAL_USE_UART4 || KINETIS_SERIAL_USE_UART5)
#error "Serial driver activated but no UART peripheral assigned" #error "Serial driver activated but no UART peripheral assigned"
#endif #endif
@ -203,6 +258,18 @@ extern SerialDriver SD2;
extern SerialDriver SD3; extern SerialDriver SD3;
#endif #endif
#if KINETIS_SERIAL_USE_UART3 && !defined(__DOXYGEN__)
extern SerialDriver SD4;
#endif
#if KINETIS_SERIAL_USE_UART4 && !defined(__DOXYGEN__)
extern SerialDriver SD5;
#endif
#if KINETIS_SERIAL_USE_UART5 && !defined(__DOXYGEN__)
extern SerialDriver SD6;
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif