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.