SiLabs Pearl: Free(er), dynamic allocation of UARTs

UARTs are no longer fixed to certain pins on Pearl, so
we need to allocate them as needed, and allow for free
pin selection.

TX and RX pin locations in the main serial struct have been
separated, and pin routing modified accordingly.

serial_api_HAL.h interface keeps track of which UARTS are
currently in use, and provides alloc/free functions. Serial
and SPI components modified to use the new API.

TODO: Magic to support LEUART. This code will also need to
be able to dynamically switch from LEUART to standard USART
if the user later sets params (baud rate or format) that can
not be supported on LEUART.
pull/1501/head
Mikko Polojarvi 2015-11-16 17:58:02 +02:00 committed by Steven Cooreman
parent 87aee51f52
commit 763ce3dbbc
6 changed files with 163 additions and 23 deletions

View File

@ -494,9 +494,9 @@ const PinMap PinMap_SPI_CS[] = {
/************UART**************/
const PinMap PinMap_UART_TX[] = {
// Pearl ok
/* USART0, USART1, LEUART0. Pinmaps are identical
so peripheral selection is dynamic */
/* USART0 */
{PA0, USART_0, 0},
{PA1, USART_0, 1},
{PA2, USART_0, 2},
@ -530,18 +530,14 @@ const PinMap PinMap_UART_TX[] = {
{PF6, USART_0, 30},
{PF7, USART_0, 31},
/* USART1, LEUART0, LEUART1 excluded as they can not
be selected through the Mbed API since their
pin maps completely overlap each other - FIXME */
{NC , NC , NC}
};
const PinMap PinMap_UART_RX[] = {
// Pearl ok
/* USART0, USART1, LEUART0. Pinmaps are identical
so peripheral selection is dynamic */
/* USART0 */
{PA1, USART_0, 0},
{PA2, USART_0, 1},
{PA3, USART_0, 2},
@ -575,9 +571,5 @@ const PinMap PinMap_UART_RX[] = {
{PF7, USART_0, 30},
{PA0, USART_0, 31},
/* USART1, LEUART0, LEUART1 excluded as they can not
be selected through the Mbed API since their
pin maps completely overlap each other - FIXME */
{NC , NC , NC}
};

View File

@ -124,6 +124,9 @@ int dma_channel_allocate(uint32_t capabilities)
int dma_channel_free(int channelid)
{
channels &= ~(1 << channelid);
if( channelid >= 0 ) {
channels &= ~(1 << channelid);
}
return 0;
}

View File

@ -114,7 +114,12 @@ struct serial_s {
USART_TypeDef *uart;
LEUART_TypeDef *leuart;
} periph;
#ifndef _SILICON_LABS_32B_PLATFORM_2
uint32_t location;
#else
uint32_t location_tx;
uint32_t location_rx;
#endif
PinName rx_pin;
PinName tx_pin;
#if DEVICE_SERIAL_ASYNCH

View File

@ -34,6 +34,7 @@
#include "mbed_assert.h"
#include "serial_api.h"
#include "serial_api_HAL.h"
#include <string.h>
#include <stdbool.h>
@ -67,6 +68,12 @@
#error Undefined number of low energy UARTs (LEUART).
#endif
#ifdef _SILICON_LABS_32B_PLATFORM_2
static uint8_t leuart0_reserved = 0;
static uint8_t usart_reserved[USART_COUNT] = { 0, 0 };
static USART_TypeDef * const usart_map[USART_COUNT] = { USART0, USART1 };
#endif
/* Store IRQ id for each UART */
static uint32_t serial_irq_ids[SERIAL_NUM_UARTS] = { 0 };
/* Interrupt handler from mbed common */
@ -334,8 +341,55 @@ inline CMU_Clock_TypeDef serial_get_clock(serial_t *obj)
}
}
#ifdef _SILICON_LABS_32B_PLATFORM_2
void *serial_uart_allocate(unsigned int uart_type)
{
int i;
if( uart_type & UART_TYPE_LEUART ) {
if( !leuart0_reserved ) {
leuart0_reserved = 1;
return LEUART0;
}
}
if( uart_type & UART_TYPE_USART ) {
for( i=0 ; i<USART_COUNT ; i++ ) {
if( !usart_reserved[i] ) {
usart_reserved[i] = 1;
return usart_map[i];
}
}
}
return NULL;
}
void serial_uart_free(void *uart)
{
int i;
for( i=0 ; i<USART_COUNT ; i++ ) {
if( usart_map[i] == uart ) {
usart_reserved[i] = 0;
return;
}
}
if( uart == LEUART0 ) {
leuart0_reserved = 0;
return;
}
MBED_ASSERT(0);
}
#endif /* _SILICON_LABS_32B_PLATFORM_2 */
void serial_preinit(serial_t *obj, PinName tx, PinName rx)
{
#ifndef _SILICON_LABS_32B_PLATFORM_2
/* Older platforms with fixed pin mappings per UART */
/* Get UART object connected to the given pins */
UARTName uart_tx = (UARTName) pinmap_peripheral(tx, PinMap_UART_TX);
UARTName uart_rx = (UARTName) pinmap_peripheral(rx, PinMap_UART_RX);
@ -352,6 +406,22 @@ void serial_preinit(serial_t *obj, PinName tx, PinName rx)
obj->serial.location = pinmap_merge(uart_tx_loc, uart_rx_loc);
MBED_ASSERT(obj->serial.location != (uint32_t)NC);
#else
/* New platforms with free pin mapping */
obj->serial.periph.uart = serial_uart_allocate(UART_TYPE_USART);
MBED_ASSERT(obj->serial.periph.uart);
uint32_t uart_tx_loc = pin_location(tx, PinMap_UART_TX);
uint32_t uart_rx_loc = pin_location(rx, PinMap_UART_RX);
MBED_ASSERT((uart_tx_loc != NC) && (uart_rx_loc != NC));
MBED_ASSERT(uart_tx_loc != uart_rx_loc);
obj->serial.location_tx = uart_tx_loc;
obj->serial.location_rx = uart_rx_loc;
#endif
/* Store pins in object for easy disabling in serial_free() */
obj->serial.rx_pin = rx;
obj->serial.tx_pin = tx;
@ -450,8 +520,8 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
#ifdef _LEUART_ROUTE_LOCATION_SHIFT
obj->serial.periph.leuart->ROUTE = LEUART_ROUTE_RXPEN | LEUART_ROUTE_TXPEN | (obj->serial.location << _LEUART_ROUTE_LOCATION_SHIFT);
#else
obj->serial.periph.leuart->ROUTELOC0 = (obj->serial.location << _LEUART_ROUTELOC0_TXLOC_SHIFT) |
(obj->serial.location << _LEUART_ROUTELOC0_RXLOC_SHIFT);
obj->serial.periph.leuart->ROUTELOC0 = (obj->serial.location_tx << _LEUART_ROUTELOC0_TXLOC_SHIFT) |
(obj->serial.location_rx << _LEUART_ROUTELOC0_RXLOC_SHIFT);
obj->serial.periph.leuart->ROUTEPEN = LEUART_ROUTEPEN_RXPEN | LEUART_ROUTEPEN_TXPEN;
#endif
obj->serial.periph.leuart->IFC = LEUART_IFC_TXC;
@ -460,8 +530,8 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
#ifdef _USART_ROUTE_LOCATION_SHIFT
obj->serial.periph.uart->ROUTE = USART_ROUTE_RXPEN | USART_ROUTE_TXPEN | (obj->serial.location << _USART_ROUTE_LOCATION_SHIFT);
#else
obj->serial.periph.uart->ROUTELOC0 = (obj->serial.location << _USART_ROUTELOC0_TXLOC_SHIFT) |
(obj->serial.location << _USART_ROUTELOC0_RXLOC_SHIFT);
obj->serial.periph.uart->ROUTELOC0 = (obj->serial.location_tx << _USART_ROUTELOC0_TXLOC_SHIFT) |
(obj->serial.location_rx << _USART_ROUTELOC0_RXLOC_SHIFT);
obj->serial.periph.uart->ROUTEPEN = USART_ROUTEPEN_RXPEN | USART_ROUTEPEN_TXPEN;
#endif
obj->serial.periph.uart->IFC = USART_IFC_TXC;
@ -485,6 +555,19 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
}
void serial_free(serial_t *obj)
{
if( LEUART_REF_VALID(obj->serial.periph.leuart) ) {
LEUART_Enable(obj->serial.periph.leuart, leuartDisable);
} else {
USART_Enable(obj->serial.periph.uart, usartDisable);
}
#ifdef _SILICON_LABS_32B_PLATFORM_2
serial_uart_free(obj->serial.periph.uart);
#endif
}
void serial_enable(serial_t *obj, uint8_t enable)
{
if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
@ -601,8 +684,8 @@ void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_b
#ifdef _LEUART_ROUTE_LOCATION_SHIFT
obj->serial.periph.leuart->ROUTE = LEUART_ROUTE_RXPEN | LEUART_ROUTE_TXPEN | (obj->serial.location << _LEUART_ROUTE_LOCATION_SHIFT);
#else
obj->serial.periph.leuart->ROUTELOC0 = (obj->serial.location << _LEUART_ROUTELOC0_TXLOC_SHIFT) |
(obj->serial.location << _LEUART_ROUTELOC0_RXLOC_SHIFT);
obj->serial.periph.leuart->ROUTELOC0 = (obj->serial.location_tx << _LEUART_ROUTELOC0_TXLOC_SHIFT) |
(obj->serial.location_rx << _LEUART_ROUTELOC0_RXLOC_SHIFT);
obj->serial.periph.leuart->ROUTEPEN = LEUART_ROUTEPEN_RXPEN | LEUART_ROUTEPEN_TXPEN;
#endif
@ -652,8 +735,8 @@ void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_b
#ifdef _USART_ROUTE_LOCATION_SHIFT
obj->serial.periph.uart->ROUTE = USART_ROUTE_RXPEN | USART_ROUTE_TXPEN | (obj->serial.location << _USART_ROUTE_LOCATION_SHIFT);
#else
obj->serial.periph.uart->ROUTELOC0 = (obj->serial.location << _USART_ROUTELOC0_TXLOC_SHIFT) |
(obj->serial.location << _USART_ROUTELOC0_RXLOC_SHIFT);
obj->serial.periph.uart->ROUTELOC0 = (obj->serial.location_tx << _USART_ROUTELOC0_TXLOC_SHIFT) |
(obj->serial.location_rx << _USART_ROUTELOC0_RXLOC_SHIFT);
obj->serial.periph.uart->ROUTEPEN = USART_ROUTEPEN_RXPEN | USART_ROUTEPEN_TXPEN;
#endif

View File

@ -0,0 +1,55 @@
/***************************************************************************//**
* @file serial_api_HAL.h
*******************************************************************************
* @section License
* <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
*******************************************************************************
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
* obligation to support this Software. Silicon Labs is providing the
* Software "AS IS", with no express or implied warranties of any kind,
* including, but not limited to, any implied warranties of merchantability
* or fitness for any particular purpose or warranties against infringement
* of any proprietary rights of a third party.
*
* Silicon Labs will not be liable for any consequential, incidental, or
* special damages, or any other relief, or for any claim by any third party,
* arising from your use of this Software.
*
******************************************************************************/
#ifndef MBED_SERIAL_API_HAL_H
#define MBED_SERIAL_API_HAL_H
#include "em_device.h"
#ifdef _SILICON_LABS_32B_PLATFORM_2
#define UART_TYPE_USART 0x01
#define UART_TYPE_LEUART 0x02
#ifdef __cplusplus
extern "C" {
#endif
void *serial_uart_allocate(unsigned int uart_type);
void serial_uart_free(void *uart);
#ifdef __cplusplus
}
#endif
#endif
#endif

View File

@ -40,6 +40,7 @@
#include "dma_api.h"
#include "dma_api_HAL.h"
#include "serial_api_HAL.h"
#include "spi_api.h"
#include "em_usart.h"
#include "em_cmu.h"
@ -117,10 +118,11 @@ static void usart_init(spi_t *obj, uint32_t baudrate, USART_Databits_TypeDef dat
USART_InitSync(obj->spi.spi, &init);
}
#ifdef LDMA_PRESENT
#ifdef _SILICON_LABS_32B_PLATFORM_2
void spi_preinit(spi_t *obj, PinName mosi, PinName miso, PinName clk, PinName cs)
{
obj->spi.spi = (USART_TypeDef *) pinmap_peripheral(mosi, PinMap_SPI_MOSI);
obj->spi.spi = serial_uart_allocate(UART_TYPE_USART);
MBED_ASSERT(obj->spi.spi);
SPIName spi_cs = (SPIName) pinmap_peripheral(cs, PinMap_SPI_CS);
if (cs != NC) { /* Slave mode */
obj->spi.master = false;