/* 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, .info = NULL, };