1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

kinetis: Refactor UART driver

This commit is contained in:
Joakim Nohlgård 2017-04-05 11:48:34 +02:00
parent 1162f2beff
commit a107a416cf
10 changed files with 177 additions and 225 deletions

View File

@ -79,24 +79,19 @@ extern "C"
* @name UART configuration
* @{
*/
#define UART_NUMOF (1U)
#define UART_0_EN 1
#define UART_IRQ_PRIO 1
#define UART_CLK CLOCK_CORECLOCK
/* UART 0 device configuration */
#define KINETIS_UART UART_Type
#define UART_0_DEV UART0
#define UART_0_CLKEN() (SIM->SCGC4 |= (SIM_SCGC4_UART0_MASK))
#define UART_0_CLK UART_CLK
#define UART_0_IRQ_CHAN UART0_RX_TX_IRQn
#define UART_0_ISR isr_uart0_rx_tx
/* UART 0 pin configuration */
#define UART_0_PORT_CLKEN() (SIM->SCGC5 |= (SIM_SCGC5_PORTB_MASK))
#define UART_0_PORT PORTB
#define UART_0_RX_PIN 16
#define UART_0_TX_PIN 17
#define UART_0_AF 3
static const uart_conf_t uart_config[] = {
{
.dev = UART0,
.clken = (volatile uint32_t*)(BITBAND_REGADDR(SIM->SCGC4, SIM_SCGC4_UART0_SHIFT)),
.freq = CLOCK_CORECLOCK,
.pin_rx = GPIO_PIN(PORT_B, 16),
.pin_tx = GPIO_PIN(PORT_B, 17),
.pcr_rx = PORT_PCR_MUX(3),
.pcr_tx = PORT_PCR_MUX(3),
.irqn = UART0_RX_TX_IRQn,
},
};
#define UART_NUMOF (sizeof(uart_config) / sizeof(uart_config[0]))
/** @} */
/**

View File

@ -34,6 +34,11 @@
/** Disable hardware watchdog, for debugging purposes, don't use this on production builds. */
#define DISABLE_WDOG 1
/**
* @brief Use the UART1 for STDIO on this board
*/
#define UART_STDIO_DEV UART_DEV(1)
/**
* @brief xtimer configuration
* @{

View File

@ -96,49 +96,29 @@ extern "C"
* @name UART configuration
* @{
*/
#define UART_NUMOF (2U)
#define UART_0_EN 1
#define UART_1_EN 1
#define UART_2_EN 0
#define UART_3_EN 0
#define UART_4_EN 0
#define UART_IRQ_PRIO CPU_DEFAULT_IRQ_PRIO
/* UART 0 device configuration */
#define UART_0_DEV UART1
#define UART_0_CLKEN() (BITBAND_REG32(SIM->SCGC4, SIM_SCGC4_UART1_SHIFT) = 1)
#define UART_0_CLKDIS() (BITBAND_REG32(SIM->SCGC4, SIM_SCGC4_UART1_SHIFT) = 0)
#define UART_0_CLK (CLOCK_CORECLOCK)
#define UART_0_IRQ_CHAN UART1_RX_TX_IRQn
#define UART_0_ISR isr_uart1_status
/* UART 0 pin configuration */
#define UART_0_PORT_CLKEN() (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTC_SHIFT) = 1)
#define UART_0_PORT PORTC
#define UART_0_TX_PIN 4
#define UART_0_RX_PIN 3
/* Function number in pin multiplex, see K60 Sub-Family Reference Manual,
* section 10.3.1 K60 Signal Multiplexing and Pin Assignments */
#define UART_0_AF 3
#define UART_0_TX_PCR_MUX 3
#define UART_0_RX_PCR_MUX 3
/* UART 1 device configuration */
#define UART_1_DEV UART0
#define UART_1_CLKEN() (BITBAND_REG32(SIM->SCGC4, SIM_SCGC4_UART0_SHIFT) = 1)
#define UART_1_CLKDIS() (BITBAND_REG32(SIM->SCGC4, SIM_SCGC4_UART0_SHIFT) = 0)
#define UART_1_CLK (CLOCK_CORECLOCK)
#define UART_1_IRQ_CHAN UART0_RX_TX_IRQn
#define UART_1_ISR isr_uart0_status
/* UART 1 pin configuration */
#define UART_1_PORT_CLKEN() (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTA_SHIFT) = 1)
#define UART_1_PORT PORTA
#define UART_1_TX_PIN 14
#define UART_1_RX_PIN 15
/* Function number in pin multiplex, see K60 Sub-Family Reference Manual,
* section 10.3.1 K60 Signal Multiplexing and Pin Assignments */
#define UART_1_AF 3
#define UART_1_TX_PCR_MUX 3
#define UART_1_RX_PCR_MUX 3
static const uart_conf_t uart_config[] = {
{
.dev = UART0,
.clken = (volatile uint32_t*)(BITBAND_REGADDR(SIM->SCGC4, SIM_SCGC4_UART0_SHIFT)),
.freq = CLOCK_CORECLOCK,
.pin_rx = GPIO_PIN(PORT_A, 14),
.pin_tx = GPIO_PIN(PORT_A, 15),
.pcr_rx = PORT_PCR_MUX(3),
.pcr_tx = PORT_PCR_MUX(3),
.irqn = UART0_RX_TX_IRQn,
},
{
.dev = UART1,
.clken = (volatile uint32_t*)(BITBAND_REGADDR(SIM->SCGC4, SIM_SCGC4_UART1_SHIFT)),
.freq = CLOCK_CORECLOCK,
.pin_rx = GPIO_PIN(PORT_C, 3),
.pin_tx = GPIO_PIN(PORT_C, 4),
.pcr_rx = PORT_PCR_MUX(3),
.pcr_tx = PORT_PCR_MUX(3),
.irqn = UART1_RX_TX_IRQn,
},
};
#define UART_NUMOF (sizeof(uart_config) / sizeof(uart_config[0]))
/** @} */

View File

@ -30,6 +30,11 @@ extern "C"
{
#endif
/**
* @brief Use the UART2 for STDIO on this board
*/
#define UART_STDIO_DEV UART_DEV(2)
/**
* @name LED pin definitions and handlers
* @{

View File

@ -81,38 +81,39 @@ extern "C"
* @name UART configuration
* @{
*/
#define UART_NUMOF (1U)
#define UART_0_EN 1
#define UART_1_EN 0
#define UART_IRQ_PRIO 1
#define UART_CLK (48e6)
/* UART 0 device configuration */
#define KINETIS_UART UART_Type
#define UART_0_DEV UART2
#define UART_0_CLKEN() (SIM->SCGC4 |= (SIM_SCGC4_UART2_MASK))
#define UART_0_CLK UART_CLK
#define UART_0_IRQ_CHAN UART2_RX_TX_IRQn
#define UART_0_ISR isr_uart2_rx_tx
/* UART 0 pin configuration */
#define UART_0_PORT_CLKEN() (SIM->SCGC5 |= (SIM_SCGC5_PORTD_MASK))
#define UART_0_PORT PORTD
#define UART_0_RX_PIN 2
#define UART_0_TX_PIN 3
#define UART_0_AF 3
/* UART 1 device configuration */
#define UART_1_DEV UART0
#define UART_1_CLKEN() (SIM->SCGC4 |= (SIM_SCGC4_UART0_MASK))
#define UART_1_CLK UART_CLK
#define UART_1_IRQ_CHAN UART0_RX_TX_IRQn
#define UART_1_ISR isr_uart0_rx_tx
/* UART 1 pin configuration */
#define UART_1_PORT_CLKEN() (SIM->SCGC5 |= (SIM_SCGC5_PORTD_MASK))
#define UART_1_PORT PORTD
#define UART_1_RX_PIN 6
#define UART_1_TX_PIN 7
#define UART_1_AF 3
static const uart_conf_t uart_config[] = {
{
.dev = UART0,
.clken = (volatile uint32_t*)(BITBAND_REGADDR(SIM->SCGC4, SIM_SCGC4_UART0_SHIFT)),
.freq = CLOCK_CORECLOCK,
.pin_rx = GPIO_PIN(PORT_D, 6),
.pin_tx = GPIO_PIN(PORT_D, 7),
.pcr_rx = PORT_PCR_MUX(3),
.pcr_tx = PORT_PCR_MUX(3),
.irqn = UART0_RX_TX_IRQn,
},
{
.dev = UART1,
.clken = (volatile uint32_t*)(BITBAND_REGADDR(SIM->SCGC4, SIM_SCGC4_UART1_SHIFT)),
.freq = CLOCK_CORECLOCK,
.pin_rx = GPIO_UNDEF,
.pin_tx = GPIO_UNDEF,
.pcr_rx = PORT_PCR_MUX(3),
.pcr_tx = PORT_PCR_MUX(3),
.irqn = UART1_RX_TX_IRQn,
},
{
.dev = UART2,
.clken = (volatile uint32_t*)(BITBAND_REGADDR(SIM->SCGC4, SIM_SCGC4_UART2_SHIFT)),
.freq = CLOCK_BUSCLOCK,
.pin_rx = GPIO_PIN(PORT_D, 2),
.pin_tx = GPIO_PIN(PORT_D, 3),
.pcr_rx = PORT_PCR_MUX(3),
.pcr_tx = PORT_PCR_MUX(3),
.irqn = UART2_RX_TX_IRQn,
},
};
#define UART_NUMOF (sizeof(uart_config) / sizeof(uart_config[0]))
/** @} */
/**

View File

@ -77,14 +77,6 @@ extern "C"
#define PORTE_CLOCK_GATE (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTE_SHIFT))
/** @} */
/**
* @name UART driver settings
*/
/** @{ */
/** UART typedef from CPU header. */
#define KINETIS_UART UART_Type
/** @} */
/**
* @name Clock settings for the LPTMR0 timer
* @{

View File

@ -103,15 +103,15 @@ WEAK_DEFAULT void isr_can1_rx_warn(void);
WEAK_DEFAULT void isr_can1_wake_up(void);
/* void dummy_handler(void); */
WEAK_DEFAULT void isr_uart0_lon(void);
WEAK_DEFAULT void isr_uart0_status(void);
WEAK_DEFAULT void isr_uart0_rx_tx(void);
WEAK_DEFAULT void isr_uart0_error(void);
WEAK_DEFAULT void isr_uart1_status(void);
WEAK_DEFAULT void isr_uart1_rx_tx(void);
WEAK_DEFAULT void isr_uart1_error(void);
WEAK_DEFAULT void isr_uart2_status(void);
WEAK_DEFAULT void isr_uart2_rx_tx(void);
WEAK_DEFAULT void isr_uart2_error(void);
WEAK_DEFAULT void isr_uart3_status(void);
WEAK_DEFAULT void isr_uart3_rx_tx(void);
WEAK_DEFAULT void isr_uart3_error(void);
WEAK_DEFAULT void isr_uart4_status(void);
WEAK_DEFAULT void isr_uart4_rx_tx(void);
WEAK_DEFAULT void isr_uart4_error(void);
/* void dummy_handler(void); */
/* void dummy_handler(void); */
@ -224,15 +224,15 @@ ISR_VECTORS const void *interrupt_vector[] = {
(void*) isr_can1_wake_up,
(void*) dummy_handler,
(void*) isr_uart0_lon,
(void*) isr_uart0_status,
(void*) isr_uart0_rx_tx,
(void*) isr_uart0_error,
(void*) isr_uart1_status,
(void*) isr_uart1_rx_tx,
(void*) isr_uart1_error,
(void*) isr_uart2_status,
(void*) isr_uart2_rx_tx,
(void*) isr_uart2_error,
(void*) isr_uart3_status,
(void*) isr_uart3_rx_tx,
(void*) isr_uart3_error,
(void*) isr_uart4_status,
(void*) isr_uart4_rx_tx,
(void*) isr_uart4_error,
(void*) dummy_handler,
(void*) dummy_handler,

View File

@ -316,28 +316,33 @@
* The register UARTx_BDH to UARTx_C4 look almost the same.
* We distinguish the type of the UART
* using the BRFA field in the UART C4 register.
* Currently, only the base functionality is available.
* Currently, only the base TX/RX functionality is available.
*
* ### UART configuration Example (for periph_conf.h) ###
*
* #define UART_NUMOF (1U)
* #define UART_0_EN 1
* #define UART_IRQ_PRIO 1
* #define UART_CLK (48e6)
*
* // UART 0 device configuration
* #define KINETIS_UART UART0_Type
* #define UART_0_DEV UART0
* #define UART_0_CLKEN() (SIM->SCGC4 |= (SIM_SCGC4_UART0_MASK))
* #define UART_0_CLK UART_CLK
* #define UART_0_IRQ_CHAN UART0_IRQn
* #define UART_0_ISR isr_uart0
* // UART 0 pin configuration
* #define UART_0_PORT_CLKEN() (SIM->SCGC5 |= (SIM_SCGC5_PORTA_MASK))
* #define UART_0_PORT PORTA
* #define UART_0_RX_PIN 1
* #define UART_0_TX_PIN 2
* #define UART_0_AF 2
* static const uart_conf_t uart_config[] = {
* {
* .dev = UART0,
* .clken = (volatile uint32_t*)(BITBAND_REGADDR(SIM->SCGC4, SIM_SCGC4_UART0_SHIFT)),
* .freq = CLOCK_CORECLOCK,
* .pin_rx = GPIO_PIN(PORT_A, 14),
* .pin_tx = GPIO_PIN(PORT_A, 15),
* .pcr_rx = PORT_PCR_MUX(3),
* .pcr_tx = PORT_PCR_MUX(3),
* .irqn = UART0_RX_TX_IRQn,
* },
* {
* .dev = UART1,
* .clken = (volatile uint32_t*)(BITBAND_REGADDR(SIM->SCGC4, SIM_SCGC4_UART1_SHIFT)),
* .freq = CLOCK_CORECLOCK,
* .pin_rx = GPIO_PIN(PORT_C, 3),
* .pin_tx = GPIO_PIN(PORT_C, 4),
* .pcr_rx = PORT_PCR_MUX(3),
* .pcr_tx = PORT_PCR_MUX(3),
* .irqn = UART1_RX_TX_IRQn,
* },
* };
* #define UART_NUMOF (sizeof(uart_config) / sizeof(uart_config[0]))
*
* Optional settings:
*

View File

@ -298,6 +298,20 @@ enum {
#define TIMER_LPTMR_DEV(x) (TIMER_DEV(PIT_NUMOF + (x)))
/** @} */
/**
* @brief UART module configuration options
*/
typedef struct {
UART_Type *dev; /**< Pointer to module hardware registers */
volatile uint32_t *clken; /**< Clock enable bitband register address */
uint32_t freq; /**< Module clock frequency, usually CLOCK_CORECLOCK or CLOCK_BUSCLOCK */
gpio_t pin_rx; /**< RX pin, GPIO_UNDEF disables RX */
gpio_t pin_tx; /**< TX pin */
uint32_t pcr_rx; /**< Pin configuration register bits for RX */
uint32_t pcr_tx; /**< Pin configuration register bits for TX */
IRQn_Type irqn; /**< IRQ number for this module */
} uart_conf_t;
/**
* @brief CPU internal function for initializing PORTs
*

View File

@ -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
clk = uart_config[uart].freq;
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;
/* 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();
}
#if UART_0_EN
void UART_0_ISR(void)
void isr_uart0_rx_tx(void)
{
irq_handler(UART_0, UART_0_DEV);
irq_handler(UART_DEV(0));
}
#endif
#if UART_1_EN
void UART_1_ISR(void)
void isr_uart1_rx_tx(void)
{
irq_handler(UART_1, UART_1_DEV);
irq_handler(UART_DEV(1));
}
void isr_uart2_rx_tx(void)
{
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