|
|
|
@ -1,4 +1,5 @@
|
|
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2017 Eistec AB |
|
|
|
|
* Copyright (C) 2014 PHYTEC Messtechnik GmbH |
|
|
|
|
* Copyright (C) 2014 Freie Universität Berlin |
|
|
|
|
* |
|
|
|
@ -17,6 +18,7 @@
|
|
|
|
|
* |
|
|
|
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de> |
|
|
|
|
* @author Johann Fischer <j.fischer@phytec.de> |
|
|
|
|
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se> |
|
|
|
|
* |
|
|
|
|
* @} |
|
|
|
|
*/ |
|
|
|
@ -42,7 +44,7 @@
|
|
|
|
|
*/ |
|
|
|
|
static uart_isr_ctx_t config[UART_NUMOF]; |
|
|
|
|
|
|
|
|
|
static inline void kinetis_set_brfa(KINETIS_UART *dev, uint32_t baudrate, uint32_t clk) |
|
|
|
|
static inline void kinetis_set_brfa(UART_Type *dev, uint32_t baudrate, uint32_t clk) |
|
|
|
|
{ |
|
|
|
|
#if KINETIS_UART_ADVANCED |
|
|
|
|
/* set baudrate fine adjust (brfa) */ |
|
|
|
@ -55,87 +57,43 @@ static int init_base(uart_t uart, uint32_t baudrate);
|
|
|
|
|
|
|
|
|
|
int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) |
|
|
|
|
{ |
|
|
|
|
assert(uart < UART_NUMOF); |
|
|
|
|
/* do basic initialization */ |
|
|
|
|
int res = init_base(uart, baudrate); |
|
|
|
|
if (res != UART_OK) { |
|
|
|
|
return res; |
|
|
|
|
} |
|
|
|
|
UART_Type *dev = uart_config[uart].dev; |
|
|
|
|
|
|
|
|
|
/* remember callback addresses */ |
|
|
|
|
config[uart].rx_cb = rx_cb; |
|
|
|
|
config[uart].arg = arg; |
|
|
|
|
|
|
|
|
|
/* enable receive interrupt */ |
|
|
|
|
switch (uart) { |
|
|
|
|
#if UART_0_EN |
|
|
|
|
|
|
|
|
|
case UART_0: |
|
|
|
|
NVIC_SetPriority(UART_0_IRQ_CHAN, UART_IRQ_PRIO); |
|
|
|
|
NVIC_EnableIRQ(UART_0_IRQ_CHAN); |
|
|
|
|
UART_0_DEV->C2 |= (1 << UART_C2_RIE_SHIFT); |
|
|
|
|
break; |
|
|
|
|
#endif |
|
|
|
|
#if UART_1_EN |
|
|
|
|
|
|
|
|
|
case UART_1: |
|
|
|
|
NVIC_SetPriority(UART_1_IRQ_CHAN, UART_IRQ_PRIO); |
|
|
|
|
NVIC_EnableIRQ(UART_1_IRQ_CHAN); |
|
|
|
|
UART_1_DEV->C2 |= (1 << UART_C2_RIE_SHIFT); |
|
|
|
|
break; |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
return UART_NODEV; |
|
|
|
|
} |
|
|
|
|
NVIC_EnableIRQ(uart_config[uart].irqn); |
|
|
|
|
dev->C2 |= (1 << UART_C2_RIE_SHIFT); |
|
|
|
|
|
|
|
|
|
return UART_OK; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int init_base(uart_t uart, uint32_t baudrate) |
|
|
|
|
{ |
|
|
|
|
KINETIS_UART *dev; |
|
|
|
|
PORT_Type *port; |
|
|
|
|
UART_Type *dev = uart_config[uart].dev; |
|
|
|
|
uint32_t clk; |
|
|
|
|
uint16_t ubd; |
|
|
|
|
uint8_t tx_pin = 0; |
|
|
|
|
uint8_t rx_pin = 0; |
|
|
|
|
uint8_t af; |
|
|
|
|
|
|
|
|
|
switch (uart) { |
|
|
|
|
#if UART_0_EN |
|
|
|
|
|
|
|
|
|
case UART_0: |
|
|
|
|
dev = UART_0_DEV; |
|
|
|
|
port = UART_0_PORT; |
|
|
|
|
clk = UART_0_CLK; |
|
|
|
|
tx_pin = UART_0_TX_PIN; |
|
|
|
|
rx_pin = UART_0_RX_PIN; |
|
|
|
|
af = UART_0_AF; |
|
|
|
|
UART_0_PORT_CLKEN(); |
|
|
|
|
UART_0_CLKEN(); |
|
|
|
|
break; |
|
|
|
|
#endif |
|
|
|
|
#if UART_1_EN |
|
|
|
|
|
|
|
|
|
case UART_1: |
|
|
|
|
dev = UART_1_DEV; |
|
|
|
|
port = UART_1_PORT; |
|
|
|
|
clk = UART_1_CLK; |
|
|
|
|
tx_pin = UART_1_TX_PIN; |
|
|
|
|
rx_pin = UART_1_RX_PIN; |
|
|
|
|
af = UART_1_AF; |
|
|
|
|
UART_1_PORT_CLKEN(); |
|
|
|
|
UART_1_CLKEN(); |
|
|
|
|
break; |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
return UART_NODEV; |
|
|
|
|
clk = uart_config[uart].freq; |
|
|
|
|
|
|
|
|
|
/* initialize pins */ |
|
|
|
|
if (uart_config[uart].pin_rx != GPIO_UNDEF) { |
|
|
|
|
gpio_init_port(uart_config[uart].pin_rx, uart_config[uart].pcr_rx); |
|
|
|
|
} |
|
|
|
|
if (uart_config[uart].pin_tx != GPIO_UNDEF) { |
|
|
|
|
gpio_init_port(uart_config[uart].pin_tx, uart_config[uart].pcr_tx); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* configure RX and TX pins, set pin to use alternative function mode */ |
|
|
|
|
port->PCR[rx_pin] = PORT_PCR_MUX(af); |
|
|
|
|
port->PCR[tx_pin] = PORT_PCR_MUX(af); |
|
|
|
|
/* Turn on module clock gate */ |
|
|
|
|
*(uart_config[uart].clken) = 1; |
|
|
|
|
|
|
|
|
|
/* disable transmitter and receiver */ |
|
|
|
|
dev->C2 &= ~(UART_C2_TE_MASK | UART_C2_RE_MASK); |
|
|
|
@ -180,46 +138,33 @@ static int init_base(uart_t uart, uint32_t baudrate)
|
|
|
|
|
|
|
|
|
|
void uart_write(uart_t uart, const uint8_t *data, size_t len) |
|
|
|
|
{ |
|
|
|
|
KINETIS_UART *dev; |
|
|
|
|
|
|
|
|
|
switch (uart) { |
|
|
|
|
#if UART_0_EN |
|
|
|
|
case UART_0: |
|
|
|
|
dev = UART_0_DEV; |
|
|
|
|
break; |
|
|
|
|
#endif |
|
|
|
|
#if UART_1_EN |
|
|
|
|
case UART_1: |
|
|
|
|
dev = UART_1_DEV; |
|
|
|
|
break; |
|
|
|
|
#endif |
|
|
|
|
default: |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
UART_Type *dev = uart_config[uart].dev; |
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < len; i++) { |
|
|
|
|
while (!(dev->S1 & UART_S1_TDRE_MASK)); |
|
|
|
|
while (!(dev->S1 & UART_S1_TDRE_MASK)) {} |
|
|
|
|
dev->D = data[i]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static inline void irq_handler(uart_t uartnum, KINETIS_UART *dev) |
|
|
|
|
static inline void irq_handler(uart_t uart) |
|
|
|
|
{ |
|
|
|
|
UART_Type *dev = uart_config[uart].dev; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* On Cortex-M0, it happens that S1 is read with LDR |
|
|
|
|
* instruction instead of LDRB. This will read the data register |
|
|
|
|
* at the same time and arrived byte will be lost. Maybe it's a GCC bug. |
|
|
|
|
* |
|
|
|
|
* Observed with: arm-none-eabi-gcc (4.8.3-8+..) |
|
|
|
|
* It does not happen with: arm-none-eabi-gcc (4.8.3-9+11) |
|
|
|
|
*/ |
|
|
|
|
* On Cortex-M0, it happens that S1 is read with LDR |
|
|
|
|
* instruction instead of LDRB. This will read the data register |
|
|
|
|
* at the same time and arrived byte will be lost. Maybe it's a GCC bug. |
|
|
|
|
* |
|
|
|
|
* Observed with: arm-none-eabi-gcc (4.8.3-8+..) |
|
|
|
|
* It does not happen with: arm-none-eabi-gcc (4.8.3-9+11) |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
if (dev->S1 & UART_S1_RDRF_MASK) { |
|
|
|
|
/* RDRF flag will be cleared when dev-D was read */ |
|
|
|
|
uint8_t data = dev->D; |
|
|
|
|
|
|
|
|
|
if (config[uartnum].rx_cb != NULL) { |
|
|
|
|
config[uartnum].rx_cb(config[uartnum].arg, data); |
|
|
|
|
if (config[uart].rx_cb != NULL) { |
|
|
|
|
config[uart].rx_cb(config[uart].arg, data); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -231,19 +176,29 @@ static inline void irq_handler(uart_t uartnum, KINETIS_UART *dev)
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
cortexm_isr_end(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void isr_uart0_rx_tx(void) |
|
|
|
|
{ |
|
|
|
|
irq_handler(UART_DEV(0)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#if UART_0_EN |
|
|
|
|
void UART_0_ISR(void) |
|
|
|
|
void isr_uart1_rx_tx(void) |
|
|
|
|
{ |
|
|
|
|
irq_handler(UART_0, UART_0_DEV); |
|
|
|
|
irq_handler(UART_DEV(1)); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#if UART_1_EN |
|
|
|
|
void UART_1_ISR(void) |
|
|
|
|
void isr_uart2_rx_tx(void) |
|
|
|
|
{ |
|
|
|
|
irq_handler(UART_1, UART_1_DEV); |
|
|
|
|
irq_handler(UART_DEV(2)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void isr_uart3_rx_tx(void) |
|
|
|
|
{ |
|
|
|
|
irq_handler(UART_DEV(3)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void isr_uart4_rx_tx(void) |
|
|
|
|
{ |
|
|
|
|
irq_handler(UART_DEV(4)); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|