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

326 lines
7.5 KiB
C

/*
* Copyright (C) 2015-2017 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_efm32
* @ingroup drivers_periph_uart
* @{
*
* @file
* @brief Low-level UART driver implementation.
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Ryan Kurte <ryankurte@gmail.com>
* @author Bas Stottelaar <basstottelaar@gmail.com>
* @}
*/
#include "cpu.h"
#include "periph/uart.h"
#include "periph/gpio.h"
#include "em_usart.h"
#include "em_usart_utils.h"
/**
* @brief Defines whether LEUART is enabled and supported
*/
#if EFM32_LEUART_ENABLED && defined(LEUART_COUNT) && LEUART_COUNT > 0
#define USE_LEUART
#endif
#ifdef USE_LEUART
#include "em_leuart.h"
#include "em_leuart_utils.h"
#endif
/**
* @brief Allocate memory to store the callback functions
*/
static uart_isr_ctx_t isr_ctx[UART_NUMOF];
#ifdef USE_LEUART
/**
* @brief Check if device is a U(S)ART device.
*/
static inline bool _is_usart(uart_t dev)
{
return ((uint32_t) uart_config[dev].dev) < LEUART0_BASE;
}
#endif
int uart_init(uart_t dev, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
{
/* check if device is valid */
if (dev >= UART_NUMOF) {
return -1;
}
/* save interrupt callback context */
isr_ctx[dev].rx_cb = rx_cb;
isr_ctx[dev].arg = arg;
/* initialize the pins */
gpio_init(uart_config[dev].rx_pin, GPIO_IN_PU);
gpio_init(uart_config[dev].tx_pin, GPIO_OUT | 1); /* 1 for high */
/* initialize the UART/USART/LEUART device */
#ifdef USE_LEUART
if (_is_usart(dev)) {
#endif
USART_TypeDef *uart = (USART_TypeDef *) uart_config[dev].dev;
/* enable clocks */
CMU_ClockEnable(cmuClock_HFPER, true);
CMU_ClockEnable(uart_config[dev].cmu, true);
/* reset and initialize peripheral */
USART_InitAsync_TypeDef init = USART_INITASYNC_DEFAULT;
init.enable = usartDisable;
init.baudrate = baudrate;
USART_InitAsync(uart, &init);
/* configure pin functions */
#if defined(_SILICON_LABS_32B_SERIES_0)
uart->ROUTE = (uart_config[dev].loc |
USART_ROUTE_RXPEN |
USART_ROUTE_TXPEN);
#elif defined(_SILICON_LABS_32B_SERIES_1)
uart->ROUTELOC0 = uart_config[dev].loc;
uart->ROUTEPEN = USART_ROUTEPEN_RXPEN | USART_ROUTEPEN_TXPEN;
#endif
/* enable receive interrupt */
USART_IntEnable(uart, USART_IEN_RXDATAV);
#ifdef USE_LEUART
} else {
LEUART_TypeDef *leuart = (LEUART_TypeDef *) uart_config[dev].dev;
/* enable clocks */
CMU_ClockEnable(cmuClock_CORELE, true);
CMU_ClockEnable(uart_config[dev].cmu, true);
/* reset and initialize peripheral */
LEUART_Init_TypeDef init = LEUART_INIT_DEFAULT;
init.enable = leuartDisable;
init.baudrate = baudrate;
LEUART_Init(leuart, &init);
/* configure pin functions */
#if defined(_SILICON_LABS_32B_SERIES_0)
leuart->ROUTE = (uart_config[dev].loc |
LEUART_ROUTE_RXPEN |
LEUART_ROUTE_TXPEN);
#elif defined(_SILICON_LABS_32B_SERIES_1)
leuart->ROUTELOC0 = uart_config[dev].loc;
leuart->ROUTEPEN = LEUART_ROUTEPEN_RXPEN | LEUART_ROUTEPEN_TXPEN;
#endif
/* enable receive interrupt */
LEUART_IntEnable(leuart, LEUART_IEN_RXDATAV);
}
#endif
/* enable the interrupt */
if (rx_cb) {
NVIC_ClearPendingIRQ(uart_config[dev].irq);
NVIC_EnableIRQ(uart_config[dev].irq);
}
uart_poweron(dev);
return 0;
}
#ifdef MODULE_PERIPH_UART_MODECFG
int uart_mode(uart_t dev, uart_data_bits_t data_bits, uart_parity_t parity,
uart_stop_bits_t stop_bits)
{
if (parity == UART_PARITY_MARK || parity == UART_PARITY_SPACE) {
return UART_NOMODE;
}
#ifdef USE_LEUART
if (_is_usart(dev)) {
#endif
USART_TypeDef *uart = (USART_TypeDef *) uart_config[dev].dev;
USART_FrameSet(uart,
USART_DataBits2Def(data_bits),
USART_StopBits2Def(stop_bits),
USART_Parity2Def(parity));
#ifdef USE_LEUART
} else {
if (data_bits != UART_DATA_BITS_8) {
return UART_NOMODE;
}
LEUART_TypeDef *leuart = (LEUART_TypeDef *) uart_config[dev].dev;
LEUART_FrameSet(leuart,
LEUART_DataBits2Def(data_bits),
LEUART_StopBits2Def(stop_bits),
LEUART_Parity2Def(parity));
}
#endif
return UART_OK;
}
#endif
void uart_write(uart_t dev, const uint8_t *data, size_t len)
{
#ifdef USE_LEUART
if (_is_usart(dev)) {
#endif
USART_TypeDef *usart = uart_config[dev].dev;
while (len--) {
USART_Tx(usart, *(data++));
}
/* spin until transmission is complete */
while (!(usart->STATUS & USART_STATUS_TXC)) {}
#ifdef USE_LEUART
} else {
LEUART_TypeDef *leuart = uart_config[dev].dev;
while (len--) {
LEUART_Tx(leuart, *(data++));
}
/* spin until transmission is complete */
while (!(leuart->STATUS & LEUART_STATUS_TXC)) {}
}
#endif
}
void uart_poweron(uart_t dev)
{
CMU_ClockEnable(uart_config[dev].cmu, true);
#ifdef USE_LEUART
if (_is_usart(dev)) {
#endif
USART_TypeDef *usart = uart_config[dev].dev;
/* enable tx */
USART_Enable_TypeDef enable = usartEnableTx;
/* enable rx if needed */
if (isr_ctx[dev].rx_cb) {
enable |= usartEnableRx;
}
USART_Enable(usart, enable);
#ifdef USE_LEUART
}
else {
LEUART_TypeDef *leuart = uart_config[dev].dev;
/* enable tx */
LEUART_Enable_TypeDef enable = leuartEnableTx;
/* enable rx if needed */
if (isr_ctx[dev].rx_cb) {
enable |= leuartEnableRx;
}
LEUART_Enable(leuart, enable);
}
#endif
}
void uart_poweroff(uart_t dev)
{
#ifdef USE_LEUART
if (_is_usart(dev)) {
#endif
USART_TypeDef *usart = uart_config[dev].dev;
/* disable tx and rx */
USART_Enable(usart, usartDisable);
#ifdef USE_LEUART
}
else {
LEUART_TypeDef *leuart = uart_config[dev].dev;
/* disable tx and rx */
LEUART_Enable(leuart, leuartDisable);
}
#endif
CMU_ClockEnable(uart_config[dev].cmu, false);
}
static void rx_irq(uart_t dev)
{
#ifdef USE_LEUART
if (_is_usart(dev)) {
#endif
if (USART_IntGet(uart_config[dev].dev) & USART_IF_RXDATAV) {
uint8_t c = USART_RxDataGet(uart_config[dev].dev);
if (isr_ctx[dev].rx_cb) {
isr_ctx[dev].rx_cb(isr_ctx[dev].arg, c);
}
}
#ifdef USE_LEUART
} else {
if (LEUART_IntGet(uart_config[dev].dev) & LEUART_IF_RXDATAV) {
uint8_t c = LEUART_RxDataGet(uart_config[dev].dev);
if (isr_ctx[dev].rx_cb) {
isr_ctx[dev].rx_cb(isr_ctx[dev].arg, c);
}
}
}
#endif
cortexm_isr_end();
}
#ifdef UART_0_ISR_RX
void UART_0_ISR_RX(void)
{
rx_irq(0);
}
#endif
#ifdef UART_1_ISR_RX
void UART_1_ISR_RX(void)
{
rx_irq(1);
}
#endif
#ifdef UART_2_ISR_RX
void UART_2_ISR_RX(void)
{
rx_irq(2);
}
#endif
#ifdef UART_3_ISR_RX
void UART_3_ISR_RX(void)
{
rx_irq(3);
}
#endif
#ifdef UART_4_ISR_RX
void UART_4_ISR_RX(void)
{
rx_irq(4);
}
#endif