EFM32 Giant Gecko USART Problems

richdinoso wrote on Wednesday, April 05, 2017:

I have the development board mentioned in this website: https://eewiki.net/display/microcontroller/Getting+Started+with+EFM32+Giant+Gecko+ARM+Cortex-M3. I copied the UART example from there and integrated it with a FreeRTOS demo included in Simplicity Studio. What I have is a single task running that outputs bytes on USART1. Everything works fine until I add a call to vTaskDelay(). The last two bytes of my output string gets lost or corrupted, not in memory, but on the output line.

I have tried different baudrates, different strings, different delay values, and the results are all similar.

Here is the task:

static void UartTest(void *pParameters) {

	int i, j;
	const char introString[] = "\n\rEFM32 GG Benchmark test started!\n\r\n\r";
	const char testString[40] = "abcdefghij\n\r";
	const portTickType delay = pdMS_TO_TICKS(1000);

	// Print intro string
	for(i=0; i<strlen(introString); i++) {
		while( !(USART1->STATUS & (1 << 6)) ); // wait for TX buffer to empty
		USART1->TXDATA = introString[i];       // print each character of the test string
	}

	for(j=0; j<20; j++) {

		// Print test string
		for(i=0; i<strlen(testString); i++) {
			while( !(USART1->STATUS & (1 << 6)) ); // wait for TX buffer to empty
			USART1->TXDATA = testString[i];       // print each character of the test string
		}

		//vTaskDelay(delay);   // This is the line of code that corrupts the output.
	}
}

Here is how I initialize the UART

void SetupUart(void)
{

	CMU_ClockDivSet(cmuClock_HF, cmuClkDiv_1);       // Set HF clock divider to /2 to keep core frequency < 32MHz
	CMU_OscillatorEnable(cmuOsc_HFXO, true, true);   // Enable XTAL Osc and wait to stabilize
	CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFXO); // Select HF XTAL osc as system clock source. 48MHz XTAL, but we divided the system clock by 2, therefore our HF clock will be 24MHz

	CMU_ClockEnable(cmuClock_HFPER, true);
	CMU_ClockEnable(cmuClock_GPIO, true);            // Enable GPIO peripheral clock
	CMU_ClockEnable(cmuClock_USART1, true);          // Enable USART1 peripheral clock

	GPIO_PinModeSet(UART_TXPORT, UART_TXPIN, gpioModePushPull, 1); // Configure UART TX pin as digital output, initialize high since UART TX idles high (otherwise glitches can occur)
	GPIO_PinModeSet(UART_RXPORT, UART_RXPIN, gpioModeInput, 0);    // Configure UART RX pin as input (no filter)

	USART_InitAsync_TypeDef uartInit =
	{
		.enable       = usartDisable,   // Wait to enable the transmitter and receiver
		.refFreq      = 0,              // Setting refFreq to 0 will invoke the CMU_ClockFreqGet() function and measure the HFPER clock
		.baudrate     = 115200,          // Desired baud rate
		.oversampling = usartOVS16,     // Set oversampling value to x16
		.databits     = usartDatabits8, // 8 data bits
		.parity       = usartNoParity,  // No parity bits
		.stopbits     = usartStopbits1, // 1 stop bit
		.mvdis        = false,          // Use majority voting
		.prsRxEnable  = false,          // Not using PRS input
		.prsRxCh      = usartPrsRxCh0,  // Doesn't matter which channel we select
	};

	USART_InitAsync(USART1, &uartInit);                                              // Apply configuration struct to USART1
	USART1->ROUTE = UART_ROUTE_RXPEN | UART_ROUTE_TXPEN | UART_ROUTE_LOCATION_LOC1; // Clear RX/TX buffers and shift regs, enable transmitter and receiver pins

	USART_IntClear(USART1, _UART_IF_MASK); // Clear any USART interrupt flags
	NVIC_ClearPendingIRQ(UART1_RX_IRQn);   // Clear pending RX interrupt flag in NVIC
	NVIC_ClearPendingIRQ(UART1_TX_IRQn);   // Clear pending TX interrupt flag in NVIC

	USART_Enable(USART1, usartEnable);     // Enable transmitter and receiver
}

The main function:

int main(void)
{
  /* Chip errata */
  CHIP_Init();

  // If first word of user data page is non-zero, enable eA Profiler trace
  BSP_TraceProfilerSetup();

  // Initialize LED driver
  BSP_LedsInit();
  // Setting state of leds
  BSP_LedSet(0);
  BSP_LedSet(1);

  SetupUart();

  // Initialize SLEEP driver, no calbacks are used
  SLEEP_Init(NULL, NULL);
#if (configSLEEP_MODE < 3)
  // do not let to sleep deeper than define
  SLEEP_SleepBlockBegin((SLEEP_EnergyMode_t)(configSLEEP_MODE+1));
#endif

  // Parameters for tasks.
  static TaskParams_t parametersToTask1 = { pdMS_TO_TICKS(1000), 0 };
  static TaskParams_t parametersToTask2 = { pdMS_TO_TICKS(1000), 1 };

  // Create two task for blinking leds.
  //xTaskCreate( LedBlink, (const char *) "LedBlink1", STACK_SIZE_FOR_TASK, &parametersToTask1, TASK_PRIORITY, NULL);
  //xTaskCreate( LedBlink, (const char *) "LedBlink2", STACK_SIZE_FOR_TASK, &parametersToTask2, TASK_PRIORITY, NULL);

  // Create task for USART1 test.
  xTaskCreate( UartTest, (const char *) "UartTest", STACK_SIZE_FOR_TASK, NULL, TASK_PRIORITY, NULL);

  // Start FreeRTOS Scheduler
  vTaskStartScheduler();

  return 0;
}

Here is the configuration options from FreeRTOSConfig.h:

/* Implement FreeRTOS configASSERT as emlib assert */
#define configASSERT( x )       EFM_ASSERT( x ) 

/* Modes of operations of operation system*/
#define configUSE_PREEMPTION       ( 1 )

/* Energy saving modes */
#define configUSE_TICKLESS_IDLE    ( 0 )
/* Available options when configUSE_TICKLESS_IDLE set to 1 
 * or configUSE_SLEEP_MODE_IN_IDLE set to 1 :
 * 1 - EM1, 2 - EM2, 3 - EM3, timer in EM3 is not very accurate*/
#define configSLEEP_MODE           ( 2 )
/* Definition used only if configUSE_TICKLESS_IDLE == 0 */
#define configUSE_SLEEP_MODE_IN_IDLE       ( 1 )

rtel wrote on Wednesday, April 05, 2017:

I see you have configUSE_TICKLESS_IDLE set to 0, but as you got the
project from simplicity studio it is possible that it is entering a low
power mode regardless of the configUSE_TICKLESS_IDLE setting (perhaps
even just entering a low power mode from the idle task).

Try waiting for the characters to actually have been transmitted before
calling vTaskDelay() - as you are doing before writing the next
character to the output:

while( !(USART1->STATUS & (1 << 6)) );
vTaskDelay( … );

As an aside, it will be much more efficient to use interrupt driven
output or ideally just use a DMA to send all the characters at once (if
the chip has the ability) with no software overhead.

richdinoso wrote on Wednesday, April 05, 2017:

Thank you. I will try waiting for the characters to be transmitted. I plan to use the DMA, but right now, I’m just making a quick demo to see characters out of the UART, and this seemed to be the simplest example.

richdinoso wrote on Wednesday, April 05, 2017:

Your hunch was correct. It was a low power mode that was causing the problem. Apparently, I have to stick with power mode EM1 to use the USART properly, even at low baud rates. I am used to the MSP430 where the UART worked at lower power modes as long as the baud rate wasn’t too high.

Hi,
The issue is actually in Energy Mode. By default BLE stack use tickless mode and EM2 settings. So, UART doesn’t work in EM2 at all, exclusive LEUART with a max speed of 9600.
In practice I have used GPIO RTS/CTS to switch the maximum EM modes using: sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM1);
sl_power_manager_remove_em_requirement(SL_POWER_MANAGER_EM1);
And it solves the issue. Another way is never using a mode less than EM1.