SiLabs Pearl: Minimize line glitches when doing LEUART-USART switch

Switch caused a phantom 0xFF frame to appear on the line when we switched
from LEUART to USART due to a baud rate was increase. This was short
enough that it was only visible at high (~115kbps) speeds.

As a fix, skip disabling the GPIO pins (as their configuration does not
change), and defer disabling the LEUART routing until at the very last
moment. Additionally, do not call serial_format, but immediately
initialize the UART to correct params.
pull/1501/head
Mikko Polojarvi 2015-12-14 20:43:38 +02:00 committed by Steven Cooreman
parent 2961d4cc33
commit 96ff20491c
1 changed files with 68 additions and 39 deletions

View File

@ -149,16 +149,34 @@ static void leuart1_irq()
*
* @param obj pointer to serial object
*/
static void uart_init(serial_t *obj, uint32_t baudrate)
static void uart_init(serial_t *obj, uint32_t baudrate, SerialParity parity, int stop_bits)
{
if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
LEUART_Init_TypeDef init = LEUART_INIT_DEFAULT;
if (stop_bits == 2) {
init.stopbits = leuartStopbits2;
} else {
init.stopbits = leuartStopbits1;
}
switch (parity) {
case ParityOdd:
case ParityForced0:
init.parity = leuartOddParity;
break;
case ParityEven:
case ParityForced1:
init.parity = leuartEvenParity;
break;
default: /* ParityNone */
init.parity = leuartNoParity;
break;
}
init.enable = leuartDisable;
init.baudrate = baudrate;
init.databits = leuartDatabits8;
init.parity = leuartNoParity;
init.stopbits = leuartStopbits1;
#ifdef LEUART_USING_LFXO
init.refFreq = LEUART_LF_REF_FREQ;
#else
@ -168,12 +186,29 @@ static void uart_init(serial_t *obj, uint32_t baudrate)
} else {
USART_InitAsync_TypeDef init = USART_INITASYNC_DEFAULT;
if (stop_bits == 2) {
init.stopbits = usartStopbits2;
} else {
init.stopbits = usartStopbits1;
}
switch (parity) {
case ParityOdd:
case ParityForced0:
init.parity = usartOddParity;
break;
case ParityEven:
case ParityForced1:
init.parity = usartEvenParity;
break;
default: /* ParityNone */
init.parity = usartNoParity;
break;
}
init.enable = usartDisable;
init.baudrate = baudrate;
init.oversampling = usartOVS16;
init.databits = usartDatabits8;
init.parity = usartNoParity;
init.stopbits = usartStopbits1;
init.refFreq = 0; /* Emlib will read HFPER clock to figure out the divider */
USART_InitAsync(obj->serial.periph.uart, &init);
@ -496,6 +531,7 @@ static void serial_enable_pins(serial_t *obj, uint8_t enable)
}
}
void serial_init(serial_t *obj, PinName tx, PinName rx)
{
uint32_t baudrate;
@ -537,7 +573,7 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
}
/* Configure UART for async operation */
uart_init(obj, baudrate);
uart_init(obj, baudrate, ParityNone, 1);
/* Enable pins for UART at correct location */
if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
@ -570,7 +606,6 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
serial_enable_pins(obj, true);
serial_enable(obj, true);
obj->serial.dmaOptionsTX.dmaChannel = -1;
obj->serial.dmaOptionsTX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
@ -700,10 +735,6 @@ static void serial_switch_to_usart(serial_t *obj, int baudrate)
/* Disable LEUART */
serial_enable(obj, false);
/* Disable GPIO pins and routing */
serial_enable_pins(obj, false);
leuart->ROUTEPEN = 0;
/* Remove IRQ callback */
serial_irq_ids[serial_get_index(obj)] = 0;
@ -719,35 +750,8 @@ static void serial_switch_to_usart(serial_t *obj, int baudrate)
obj->serial.dmaOptionsRX.dmaChannel = -1;
obj->serial.dmaOptionsRX.dmaUsageState = DMA_USAGE_OPPORTUNISTIC;
serial_uart_free(leuart);
/* TODO: disable clocks? */
/* Replace LEUART with USART */
serial_preinit(obj, obj->serial.tx_pin, obj->serial.rx_pin, false);
CMU_ClockEnable(serial_get_clock(obj), true);
uart_init(obj, baudrate);
USART_TypeDef *usart = obj->serial.periph.uart;
usart->ROUTELOC0 = (obj->serial.location_tx << _USART_ROUTELOC0_TXLOC_SHIFT) |
(obj->serial.location_rx << _USART_ROUTELOC0_RXLOC_SHIFT);
usart->ROUTEPEN = USART_ROUTEPEN_RXPEN | USART_ROUTEPEN_TXPEN;
usart->IFC = USART_IFC_TXC;
serial_enable_pins(obj, true);
serial_enable(obj, true);
/* Restore interrupts */
serial_irq_ids[serial_get_index(obj)] = irq_id;
if( ien_rxd ) serial_irq_set(obj, RxIrq, 1);
if( ien_txc ) serial_irq_set(obj, TxIrq, 1);
if( ien_ferr ) usart->IEN |= USART_IEN_FERR;
if( ien_perr ) usart->IEN |= USART_IEN_PERR;
if( ien_rxof ) usart->IEN |= USART_IEN_RXOF;
SerialParity par = ParityNone;
switch( parity ) {
case LEUART_CTRL_PARITY_NONE: par = ParityNone; break;
@ -767,7 +771,32 @@ static void serial_switch_to_usart(serial_t *obj, int baudrate)
break;
}
serial_format(obj, 8, par, stopb);
/* Replace LEUART with USART */
serial_preinit(obj, obj->serial.tx_pin, obj->serial.rx_pin, false);
CMU_ClockEnable(serial_get_clock(obj), true);
uart_init(obj, baudrate, par, stopb);
USART_TypeDef *usart = obj->serial.periph.uart;
/* Disable/enable routing */
usart->ROUTELOC0 = (obj->serial.location_tx << _USART_ROUTELOC0_TXLOC_SHIFT) |
(obj->serial.location_rx << _USART_ROUTELOC0_RXLOC_SHIFT);
leuart->ROUTEPEN = 0;
usart->ROUTEPEN = USART_ROUTEPEN_RXPEN | USART_ROUTEPEN_TXPEN;
usart->IFC = USART_IFC_TXC;
serial_uart_free(leuart);
serial_enable(obj, true);
/* Restore interrupts */
serial_irq_ids[serial_get_index(obj)] = irq_id;
if( ien_rxd ) serial_irq_set(obj, RxIrq, 1);
if( ien_txc ) serial_irq_set(obj, TxIrq, 1);
if( ien_ferr ) usart->IEN |= USART_IEN_FERR;
if( ien_perr ) usart->IEN |= USART_IEN_PERR;
if( ien_rxof ) usart->IEN |= USART_IEN_RXOF;
}
#endif /* _SILICON_LABS_32B_PLATFORM_2 */