Skip to content

Commit 3d8637c

Browse files
committed
Fixes to serial_api:
* Allow pins to be configured as NC without failing or asserting * Fix putc() to not return before the entire character has been physically shifted out. * Use MBED_ASSERT * Fix baudrate calculation to avoid wrong configuration on startup for stdio
1 parent 6ab14fa commit 3d8637c

File tree

1 file changed

+98
-24
lines changed
  • libraries/mbed/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32

1 file changed

+98
-24
lines changed

libraries/mbed/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/serial_api.c

Lines changed: 98 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -477,12 +477,21 @@ static void serial_enable_pins(serial_t *obj, uint8_t enable)
477477
{
478478
if (enable) {
479479
/* Configure GPIO pins*/
480-
pin_mode(obj->serial.rx_pin, Input);
481-
/* 0x10 sets DOUT. Prevents false start. */
482-
pin_mode(obj->serial.tx_pin, PushPull | 0x10);
480+
if(obj->serial.rx_pin != NC) {
481+
pin_mode(obj->serial.rx_pin, Input);
482+
}
483+
/* Set DOUT first to prevent glitches */
484+
if(obj->serial.tx_pin != NC) {
485+
GPIO_PinOutSet((GPIO_Port_TypeDef)(obj->serial.tx_pin >> 4 & 0xF), obj->serial.tx_pin & 0xF);
486+
pin_mode(obj->serial.tx_pin, PushPull);
487+
}
483488
} else {
484-
pin_mode(obj->serial.rx_pin, Disabled);
485-
pin_mode(obj->serial.tx_pin, Disabled);
489+
if(obj->serial.rx_pin != NC) {
490+
pin_mode(obj->serial.rx_pin, Disabled);
491+
}
492+
if(obj->serial.tx_pin != NC) {
493+
pin_mode(obj->serial.tx_pin, Disabled);
494+
}
486495
}
487496
}
488497

@@ -513,7 +522,7 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
513522
CMU_ClockEnable(serial_get_clock(obj), true);
514523

515524
/* Limitations of board controller: CDC port only supports 115kbaud */
516-
if((tx == STDIO_UART_TX) && (rx == STDIO_UART_RX)
525+
if(((tx == STDIO_UART_TX) || (rx == STDIO_UART_RX))
517526
&& (obj->serial.periph.uart == (USART_TypeDef*)STDIO_UART )
518527
) {
519528
baudrate = 115200;
@@ -528,21 +537,53 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
528537
/* Enable pins for UART at correct location */
529538
if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
530539
#ifdef _LEUART_ROUTE_LOCATION_SHIFT
531-
obj->serial.periph.leuart->ROUTE = LEUART_ROUTE_RXPEN | LEUART_ROUTE_TXPEN | (obj->serial.location << _LEUART_ROUTE_LOCATION_SHIFT);
540+
obj->serial.periph.leuart->ROUTE = (obj->serial.location << _LEUART_ROUTE_LOCATION_SHIFT);
541+
if(tx != (uint32_t)NC) {
542+
obj->serial.periph.leuart->ROUTE |= LEUART_ROUTE_TXPEN;
543+
}
544+
if(rx != (uint32_t)NC) {
545+
obj->serial.periph.leuart->ROUTE |= LEUART_ROUTE_RXPEN;
546+
}
532547
#else
533-
obj->serial.periph.leuart->ROUTELOC0 = (obj->serial.location_tx << _LEUART_ROUTELOC0_TXLOC_SHIFT) |
534-
(obj->serial.location_rx << _LEUART_ROUTELOC0_RXLOC_SHIFT);
535-
obj->serial.periph.leuart->ROUTEPEN = LEUART_ROUTEPEN_RXPEN | LEUART_ROUTEPEN_TXPEN;
548+
if(obj->serial.location_tx != NC) {
549+
obj->serial.periph.leuart->ROUTELOC0 = (obj->serial.periph.leuart->ROUTELOC0 & (~_LEUART_ROUTELOC0_TXLOC_MASK)) | (obj->serial.location_tx << _LEUART_ROUTELOC0_TXLOC_SHIFT);
550+
obj->serial.periph.leuart->ROUTEPEN = (obj->serial.periph.leuart->ROUTEPEN & (~_LEUART_ROUTEPEN_TXPEN_MASK)) | LEUART_ROUTEPEN_TXPEN;
551+
} else {
552+
obj->serial.periph.leuart->ROUTEPEN = (obj->serial.periph.leuart->ROUTEPEN & (~_LEUART_ROUTEPEN_TXPEN_MASK));
553+
}
554+
if(obj->serial.location_rx != NC) {
555+
obj->serial.periph.leuart->ROUTELOC0 = (obj->serial.periph.leuart->ROUTELOC0 & (~_LEUART_ROUTELOC0_RXLOC_MASK)) | (obj->serial.location_rx << _LEUART_ROUTELOC0_RXLOC_SHIFT);
556+
obj->serial.periph.leuart->ROUTEPEN = (obj->serial.periph.leuart->ROUTEPEN & (~_LEUART_ROUTEPEN_RXPEN_MASK)) | LEUART_ROUTEPEN_RXPEN;
557+
} else {
558+
obj->serial.periph.leuart->CMD = LEUART_CMD_RXBLOCKEN;
559+
obj->serial.periph.leuart->ROUTEPEN = (obj->serial.periph.leuart->ROUTEPEN & (~_LEUART_ROUTEPEN_RXPEN_MASK));
560+
}
536561
#endif
537562
obj->serial.periph.leuart->IFC = LEUART_IFC_TXC;
538563
obj->serial.periph.leuart->CTRL |= LEUART_CTRL_RXDMAWU | LEUART_CTRL_TXDMAWU;
539564
} else {
540565
#ifdef _USART_ROUTE_LOCATION_SHIFT
541-
obj->serial.periph.uart->ROUTE = USART_ROUTE_RXPEN | USART_ROUTE_TXPEN | (obj->serial.location << _USART_ROUTE_LOCATION_SHIFT);
566+
obj->serial.periph.uart->ROUTE = (obj->serial.location << _USART_ROUTE_LOCATION_SHIFT);
567+
if(tx != (uint32_t)NC) {
568+
obj->serial.periph.uart->ROUTE |= USART_ROUTE_TXPEN;
569+
}
570+
if(rx != (uint32_t)NC) {
571+
obj->serial.periph.uart->ROUTE |= USART_ROUTE_RXPEN;
572+
}
542573
#else
543-
obj->serial.periph.uart->ROUTELOC0 = (obj->serial.location_tx << _USART_ROUTELOC0_TXLOC_SHIFT) |
544-
(obj->serial.location_rx << _USART_ROUTELOC0_RXLOC_SHIFT);
545-
obj->serial.periph.uart->ROUTEPEN = USART_ROUTEPEN_RXPEN | USART_ROUTEPEN_TXPEN;
574+
if(obj->serial.location_tx != NC) {
575+
obj->serial.periph.uart->ROUTELOC0 = (obj->serial.periph.uart->ROUTELOC0 & (~_USART_ROUTELOC0_TXLOC_MASK)) | (obj->serial.location_tx << _USART_ROUTELOC0_TXLOC_SHIFT);
576+
obj->serial.periph.uart->ROUTEPEN = (obj->serial.periph.uart->ROUTEPEN & (~_USART_ROUTEPEN_TXPEN_MASK)) | USART_ROUTEPEN_TXPEN;
577+
} else {
578+
obj->serial.periph.uart->ROUTEPEN = (obj->serial.periph.uart->ROUTEPEN & (~_USART_ROUTEPEN_TXPEN_MASK));
579+
}
580+
if(obj->serial.location_rx != NC) {
581+
obj->serial.periph.uart->ROUTELOC0 = (obj->serial.periph.uart->ROUTELOC0 & (~_USART_ROUTELOC0_RXLOC_MASK)) | (obj->serial.location_rx << _USART_ROUTELOC0_RXLOC_SHIFT);
582+
obj->serial.periph.uart->ROUTEPEN = (obj->serial.periph.uart->ROUTEPEN & (~_USART_ROUTEPEN_RXPEN_MASK)) | USART_ROUTEPEN_RXPEN;
583+
} else {
584+
obj->serial.periph.uart->CMD = USART_CMD_RXBLOCKEN;
585+
obj->serial.periph.uart->ROUTEPEN = (obj->serial.periph.uart->ROUTEPEN & (~_USART_ROUTEPEN_RXPEN_MASK));
586+
}
546587
#endif
547588
obj->serial.periph.uart->IFC = USART_IFC_TXC;
548589
}
@@ -571,6 +612,7 @@ void serial_free(serial_t *obj)
571612
} else {
572613
USART_Enable(obj->serial.periph.uart, usartDisable);
573614
}
615+
serial_enable_pins(obj, false);
574616
}
575617

576618
static void serial_enable(serial_t *obj, uint8_t enable)
@@ -599,7 +641,7 @@ void serial_baud(serial_t *obj, int baudrate)
599641
if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
600642
serial_leuart_baud(obj, baudrate);
601643
} else {
602-
USART_BaudrateAsyncSet(obj->serial.periph.uart, 0, (uint32_t)baudrate, usartOVS16);
644+
USART_BaudrateAsyncSet(obj->serial.periph.uart, REFERENCE_FREQUENCY, (uint32_t)baudrate, usartOVS16);
603645
}
604646
}
605647

@@ -720,11 +762,26 @@ void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_b
720762

721763
/* Re-enable pins for UART at correct location */
722764
#ifdef _LEUART_ROUTE_LOCATION_SHIFT
723-
obj->serial.periph.leuart->ROUTE = LEUART_ROUTE_RXPEN | LEUART_ROUTE_TXPEN | (obj->serial.location << _LEUART_ROUTE_LOCATION_SHIFT);
765+
obj->serial.periph.leuart->ROUTE = (obj->serial.location << _LEUART_ROUTE_LOCATION_SHIFT);
766+
if(obj->serial.tx_pin != (uint32_t)NC) {
767+
obj->serial.periph.leuart->ROUTE |= LEUART_ROUTE_TXPEN;
768+
}
769+
if(obj->serial.rx_pin != (uint32_t)NC) {
770+
obj->serial.periph.leuart->ROUTE |= LEUART_ROUTE_RXPEN;
771+
}
724772
#else
725-
obj->serial.periph.leuart->ROUTELOC0 = (obj->serial.location_tx << _LEUART_ROUTELOC0_TXLOC_SHIFT) |
726-
(obj->serial.location_rx << _LEUART_ROUTELOC0_RXLOC_SHIFT);
727-
obj->serial.periph.leuart->ROUTEPEN = LEUART_ROUTEPEN_RXPEN | LEUART_ROUTEPEN_TXPEN;
773+
if(obj->serial.location_tx != NC) {
774+
obj->serial.periph.leuart->ROUTELOC0 = (obj->serial.periph.leuart->ROUTELOC0 & (~_LEUART_ROUTELOC0_TXLOC_MASK)) | (obj->serial.location_tx << _LEUART_ROUTELOC0_TXLOC_SHIFT);
775+
obj->serial.periph.leuart->ROUTEPEN = (obj->serial.periph.leuart->ROUTEPEN & (~_LEUART_ROUTEPEN_TXPEN_MASK)) | LEUART_ROUTEPEN_TXPEN;
776+
} else {
777+
obj->serial.periph.leuart->ROUTEPEN = (obj->serial.periph.leuart->ROUTEPEN & (~_LEUART_ROUTEPEN_TXPEN_MASK));
778+
}
779+
if(obj->serial.location_rx != NC) {
780+
obj->serial.periph.leuart->ROUTELOC0 = (obj->serial.periph.leuart->ROUTELOC0 & (~_LEUART_ROUTELOC0_RXLOC_MASK)) | (obj->serial.location_rx << _LEUART_ROUTELOC0_RXLOC_SHIFT);
781+
obj->serial.periph.leuart->ROUTEPEN = (obj->serial.periph.leuart->ROUTEPEN & (~_LEUART_ROUTEPEN_RXPEN_MASK)) | LEUART_ROUTEPEN_RXPEN;
782+
} else {
783+
obj->serial.periph.leuart->ROUTEPEN = (obj->serial.periph.leuart->ROUTEPEN & (~_LEUART_ROUTEPEN_RXPEN_MASK));
784+
}
728785
#endif
729786

730787
/* Re-enable interrupts */
@@ -771,11 +828,26 @@ void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_b
771828

772829
/* Re-enable pins for UART at correct location */
773830
#ifdef _USART_ROUTE_LOCATION_SHIFT
774-
obj->serial.periph.uart->ROUTE = USART_ROUTE_RXPEN | USART_ROUTE_TXPEN | (obj->serial.location << _USART_ROUTE_LOCATION_SHIFT);
831+
obj->serial.periph.uart->ROUTE = (obj->serial.location << _USART_ROUTE_LOCATION_SHIFT);
832+
if(obj->serial.tx_pin != (uint32_t)NC) {
833+
obj->serial.periph.uart->ROUTE |= USART_ROUTE_TXPEN;
834+
}
835+
if(obj->serial.rx_pin != (uint32_t)NC) {
836+
obj->serial.periph.uart->ROUTE |= USART_ROUTE_RXPEN;
837+
}
775838
#else
776-
obj->serial.periph.uart->ROUTELOC0 = (obj->serial.location_tx << _USART_ROUTELOC0_TXLOC_SHIFT) |
777-
(obj->serial.location_rx << _USART_ROUTELOC0_RXLOC_SHIFT);
778-
obj->serial.periph.uart->ROUTEPEN = USART_ROUTEPEN_RXPEN | USART_ROUTEPEN_TXPEN;
839+
if(obj->serial.location_tx != NC) {
840+
obj->serial.periph.uart->ROUTELOC0 = (obj->serial.periph.uart->ROUTELOC0 & (~_USART_ROUTELOC0_TXLOC_MASK)) | (obj->serial.location_tx << _USART_ROUTELOC0_TXLOC_SHIFT);
841+
obj->serial.periph.uart->ROUTEPEN = (obj->serial.periph.uart->ROUTEPEN & (~_USART_ROUTEPEN_TXPEN_MASK)) | USART_ROUTEPEN_TXPEN;
842+
} else {
843+
obj->serial.periph.uart->ROUTEPEN = (obj->serial.periph.uart->ROUTEPEN & (~_USART_ROUTEPEN_TXPEN_MASK));
844+
}
845+
if(obj->serial.location_rx != NC) {
846+
obj->serial.periph.uart->ROUTELOC0 = (obj->serial.periph.uart->ROUTELOC0 & (~_USART_ROUTELOC0_RXLOC_MASK)) | (obj->serial.location_rx << _USART_ROUTELOC0_RXLOC_SHIFT);
847+
obj->serial.periph.uart->ROUTEPEN = (obj->serial.periph.uart->ROUTEPEN & (~_USART_ROUTEPEN_RXPEN_MASK)) | USART_ROUTEPEN_RXPEN;
848+
} else {
849+
obj->serial.periph.uart->ROUTEPEN = (obj->serial.periph.uart->ROUTEPEN & (~_USART_ROUTEPEN_RXPEN_MASK));
850+
}
779851
#endif
780852

781853
/* Re-enable interrupts */
@@ -997,8 +1069,10 @@ void serial_putc(serial_t *obj, int c)
9971069
* need to use serial_writable(). */
9981070
if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
9991071
LEUART_Tx(obj->serial.periph.leuart, (uint8_t)(c));
1072+
while (!(obj->serial.periph.leuart->STATUS & LEUART_STATUS_TXC));
10001073
} else {
10011074
USART_Tx(obj->serial.periph.uart, (uint8_t)(c));
1075+
while (!(obj->serial.periph.uart->STATUS & USART_STATUS_TXC));
10021076
}
10031077
}
10041078

@@ -1418,7 +1492,7 @@ static void serial_dmaActivate(serial_t *obj, void* cb, void* buffer, int length
14181492
break;
14191493
#endif
14201494
default:
1421-
EFM_ASSERT(0);
1495+
MBED_ASSERT(0);
14221496
while(1);
14231497
break;
14241498
}

0 commit comments

Comments
 (0)