From 014d180b1da90a5e23f2ebd4df3d00457bc5fb28 Mon Sep 17 00:00:00 2001 From: Anton Staaf Date: Tue, 28 Jul 2015 10:30:44 -0700 Subject: USART: Split RX driver between L and F families The USART peripheral in the L and F families is different enough to need different receive drivers. In particular, the L family USART perihperal has no way of disabling the overflow error bit. So for that family we check and clear the bit, and keep a count of overflows. Signed-off-by: Anton Staaf BRANCH=None BUG=None TEST=make buildall -j Change-Id: Iea26c242d5177afd552a3bd4d6ab1a9c7a65f90e Reviewed-on: https://chromium-review.googlesource.com/288978 Trybot-Ready: Anton Staaf Tested-by: Anton Staaf Reviewed-by: Randall Spangler Commit-Queue: Anton Staaf --- chip/stm32/build.mk | 3 +- chip/stm32/registers.h | 3 ++ chip/stm32/usart.c | 14 +++++--- chip/stm32/usart.h | 1 + chip/stm32/usart_rx_interrupt-stm32f0.c | 1 + chip/stm32/usart_rx_interrupt-stm32f3.c | 1 + chip/stm32/usart_rx_interrupt-stm32l.c | 64 +++++++++++++++++++++++++++++++++ chip/stm32/usart_rx_interrupt.c | 18 +++++----- 8 files changed, 91 insertions(+), 14 deletions(-) create mode 120000 chip/stm32/usart_rx_interrupt-stm32f0.c create mode 120000 chip/stm32/usart_rx_interrupt-stm32f3.c create mode 100644 chip/stm32/usart_rx_interrupt-stm32l.c diff --git a/chip/stm32/build.mk b/chip/stm32/build.mk index 72be7eb6d4..0cfd72b93f 100644 --- a/chip/stm32/build.mk +++ b/chip/stm32/build.mk @@ -35,7 +35,8 @@ chip-$(CONFIG_COMMON_GPIO)+=gpio.o gpio-$(CHIP_FAMILY).o chip-$(CONFIG_COMMON_TIMER)+=hwtimer$(TIMER_TYPE).o chip-$(CONFIG_I2C)+=i2c-$(CHIP_FAMILY).o chip-$(CONFIG_STREAM_USART)+=usart.o usart-$(CHIP_FAMILY).o -chip-$(CONFIG_STREAM_USART)+=usart_rx_interrupt.o usart_tx_interrupt.o +chip-$(CONFIG_STREAM_USART)+=usart_rx_interrupt-$(CHIP_FAMILY).o +chip-$(CONFIG_STREAM_USART)+=usart_tx_interrupt.o chip-$(CONFIG_STREAM_USART)+=usart_tx_dma.o chip-$(CONFIG_STREAM_USB)+=usb-stream.o chip-$(CONFIG_WATCHDOG)+=watchdog.o diff --git a/chip/stm32/registers.h b/chip/stm32/registers.h index f9f27f25f5..617abd98f9 100644 --- a/chip/stm32/registers.h +++ b/chip/stm32/registers.h @@ -189,16 +189,19 @@ #define STM32_USART_RQR(base) STM32_USART_REG(base, 0x18) #define STM32_USART_ISR(base) STM32_USART_REG(base, 0x1C) #define STM32_USART_ICR(base) STM32_USART_REG(base, 0x20) +#define STM32_USART_ICR_ORECF (1 << 3) #define STM32_USART_ICR_TCCF (1 << 6) #define STM32_USART_RDR(base) STM32_USART_REG(base, 0x24) #define STM32_USART_TDR(base) STM32_USART_REG(base, 0x28) /* register alias */ #define STM32_USART_SR(base) STM32_USART_ISR(base) +#define STM32_USART_SR_ORE (1 << 3) #define STM32_USART_SR_RXNE (1 << 5) #define STM32_USART_SR_TC (1 << 6) #define STM32_USART_SR_TXE (1 << 7) #else /* !CHIP_FAMILY_STM32F0 */ #define STM32_USART_SR(base) STM32_USART_REG(base, 0x00) +#define STM32_USART_SR_ORE (1 << 3) #define STM32_USART_SR_RXNE (1 << 5) #define STM32_USART_SR_TC (1 << 6) #define STM32_USART_SR_TXE (1 << 7) diff --git a/chip/stm32/usart.c b/chip/stm32/usart.c index 32dbeaf7d0..549769cb48 100644 --- a/chip/stm32/usart.c +++ b/chip/stm32/usart.c @@ -42,7 +42,7 @@ void usart_init(struct usart_config const *config) */ STM32_USART_CR1(base) = 0x0000; STM32_USART_CR2(base) = 0x0000; - STM32_USART_CR3(base) = STM32_USART_CR3_OVRDIS; + STM32_USART_CR3(base) = 0x0000; /* * Enable the RX, TX, and variant specific HW. @@ -51,6 +51,12 @@ void usart_init(struct usart_config const *config) config->tx->init(config); config->hw->ops->enable(config); + /* + * Clear error counts. + */ + config->state->rx_overrun = 0; + config->state->rx_dropped = 0; + /* * Enable the USART, this must be done last since most of the * configuration bits require that the USART be disabled for writes to @@ -98,6 +104,6 @@ void usart_set_baud_f(struct usart_config const *config, int frequency_hz) void usart_interrupt(struct usart_config const *config) { - config->tx->interrupt(config); - config->rx->interrupt(config); -} \ No newline at end of file + config->tx->interrupt(config); + config->rx->interrupt(config); +} diff --git a/chip/stm32/usart.h b/chip/stm32/usart.h index c0003c6cb9..a274aa8dce 100644 --- a/chip/stm32/usart.h +++ b/chip/stm32/usart.h @@ -24,6 +24,7 @@ struct usart_state { * in the RX queue. */ uint32_t rx_dropped; + uint32_t rx_overrun; }; struct usart_config; diff --git a/chip/stm32/usart_rx_interrupt-stm32f0.c b/chip/stm32/usart_rx_interrupt-stm32f0.c new file mode 120000 index 0000000000..a756455f9b --- /dev/null +++ b/chip/stm32/usart_rx_interrupt-stm32f0.c @@ -0,0 +1 @@ +usart_rx_interrupt.c \ No newline at end of file diff --git a/chip/stm32/usart_rx_interrupt-stm32f3.c b/chip/stm32/usart_rx_interrupt-stm32f3.c new file mode 120000 index 0000000000..a756455f9b --- /dev/null +++ b/chip/stm32/usart_rx_interrupt-stm32f3.c @@ -0,0 +1 @@ +usart_rx_interrupt.c \ No newline at end of file diff --git a/chip/stm32/usart_rx_interrupt-stm32l.c b/chip/stm32/usart_rx_interrupt-stm32l.c new file mode 100644 index 0000000000..e6222d1716 --- /dev/null +++ b/chip/stm32/usart_rx_interrupt-stm32l.c @@ -0,0 +1,64 @@ +/* Copyright (c) 2015 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Interrupt based USART RX driver for STM32L */ + +#include "usart.h" + +#include "atomic.h" +#include "common.h" +#include "queue.h" +#include "registers.h" + +static void usart_rx_init(struct usart_config const *config) +{ + intptr_t base = config->hw->base; + + STM32_USART_CR1(base) |= STM32_USART_CR1_RXNEIE; + STM32_USART_CR1(base) |= STM32_USART_CR1_RE; +} + +static void usart_rx_interrupt_handler(struct usart_config const *config) +{ + intptr_t base = config->hw->base; + int32_t status = STM32_USART_SR(base); + + /* + * We have to check and clear the overrun error flag on STM32L because + * we can't disable it. + */ + if (status & STM32_USART_SR_ORE) { + /* + * In the unlikely event that the overrun error bit was set but + * the RXNE bit was not (possibly because a read was done from + * RDR without first reading the status register) we do a read + * here to clear the overrun error bit. + */ + if (!(status & STM32_USART_SR_RXNE)) + (void)STM32_USART_RDR(config->hw->base); + + atomic_add(&config->state->rx_overrun, 1); + } + + if (status & STM32_USART_SR_RXNE) { + uint8_t byte = STM32_USART_RDR(base); + + if (!queue_add_unit(config->producer.queue, &byte)) + atomic_add(&config->state->rx_dropped, 1); + } +} + +struct usart_rx const usart_rx_interrupt = { + .producer_ops = { + /* + * Nothing to do here, we either had enough space in the queue + * when a character came in or we dropped it already. + */ + .read = NULL, + }, + + .init = usart_rx_init, + .interrupt = usart_rx_interrupt_handler, +}; diff --git a/chip/stm32/usart_rx_interrupt.c b/chip/stm32/usart_rx_interrupt.c index ea1b4a4c6a..d4fb48f5a0 100644 --- a/chip/stm32/usart_rx_interrupt.c +++ b/chip/stm32/usart_rx_interrupt.c @@ -3,7 +3,7 @@ * found in the LICENSE file. */ -/* Interrupt based USART RX driver for STM32 */ +/* Interrupt based USART RX driver for STM32F0 and STM32F3 */ #include "usart.h" @@ -18,20 +18,20 @@ static void usart_rx_init(struct usart_config const *config) STM32_USART_CR1(base) |= STM32_USART_CR1_RXNEIE; STM32_USART_CR1(base) |= STM32_USART_CR1_RE; + STM32_USART_CR3(base) |= STM32_USART_CR3_OVRDIS; } static void usart_rx_interrupt_handler(struct usart_config const *config) { - intptr_t base = config->hw->base; - uint8_t byte; - - if (!(STM32_USART_SR(base) & STM32_USART_SR_RXNE)) - return; + intptr_t base = config->hw->base; + int32_t status = STM32_USART_SR(base); - byte = STM32_USART_RDR(base); + if (status & STM32_USART_SR_RXNE) { + uint8_t byte = STM32_USART_RDR(base); - if (!queue_add_unit(config->producer.queue, &byte)) - atomic_add(&config->state->rx_dropped, 1); + if (!queue_add_unit(config->producer.queue, &byte)) + atomic_add(&config->state->rx_dropped, 1); + } } struct usart_rx const usart_rx_interrupt = { -- cgit v1.2.1