This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nrf52832 uart tx works only with NRF_UARTE0 read after EndTx

FormerMember
FormerMember

Greetings, There is a bit of strange operation in UARTE peripheral in nrf52832 with the DK. In the simple code below, if both of the if statements with comments 'Check 1' and 'Check 2' are removed the 'hello' prints are not sent and I get some junk value. If either of the two reads to the UARTE registers is made in these if statement, then the 'hello' prints are sent out correctly. What's happening? I don't see any errata related to UARTE peripheral.

Thanks.

Toolchain: GCC 4.9.3q2 on Linux

#include <stdbool.h>
#include <stdint.h>
#include "nrf_delay.h"
#include "nrf52-gpio.h"
#include "nrf52-clock.h"
#include "board.h"
#include "nrf52-uart.h"

int main(void)
{
	nrf_gpio_cfg_output(LED1);
	nrf_gpio_cfg_output(LED2);
	nrf_gpio_cfg_output(LED3);
	nrf_gpio_cfg_output(LED4);

	/* Configure TX and RX pins from board.h */
	nrf_gpio_cfg_output(TX_PIN_NUMBER);
	nrf_gpio_cfg_input(RX_PIN_NUMBER, GPIO_PIN_CNF_PULL_Disabled);
	NRF_UARTE0->PSEL.TXD = TX_PIN_NUMBER;
	NRF_UARTE0->PSEL.RTS = RX_PIN_NUMBER;

	nrf_gpio_cfg_output(RTS_PIN_NUMBER);
	nrf_gpio_cfg_input(CTS_PIN_NUMBER, GPIO_PIN_CNF_PULL_Disabled);
	NRF_UARTE0->PSEL.RTS = RTS_PIN_NUMBER;
	NRF_UARTE0->PSEL.CTS = CTS_PIN_NUMBER;
	NRF_UARTE0->CONFIG = (UARTE_CONFIG_HWFC_Enabled << UARTE_CONFIG_HWFC_Pos);

	/* Configure other UART parameters, BAUD rate is defined in nrf52-uart.h	*/
	NRF_UARTE0->BAUDRATE = (UARTE_BAUDRATE << UARTE_BAUDRATE_BAUDRATE_Pos);
	NRF_UARTE0->ENABLE = (UARTE_ENABLE_ENABLE_Enabled << UARTE_ENABLE_ENABLE_Pos);

    // Toggle LEDs.
    while (true)
    {
    	uint32_t i;
        for (i = 0; i < 2; i++)
        {
        	if(i){
        		NRF_P0->OUTSET = (1<<LED1);
        	} else {
        		NRF_P0->OUTCLR = (1<<LED1);
        	}
        	nrf_delay_ms(500);

            uint8_t str[] = "hello\n";
            uint32_t len = 6;

            NRF_UARTE0->EVENTS_ENDTX = 0;
            NRF_UARTE0->TASKS_STOPTX = 0;

        	NRF_UARTE0->TXD.PTR = (uint32_t)((uint8_t *) str);
        	NRF_UARTE0->TXD.MAXCNT = (uint32_t) len;

        	NRF_UARTE0->TASKS_STARTTX = 1;

        	while((0 == NRF_UARTE0->EVENTS_ENDTX)&&(0 == NRF_UARTE0->EVENTS_TXSTOPPED)){}

            /*****Check 1*****/
        	if(NRF_UARTE0->EVENTS_ENDTX){
        		NRF_P0->OUTSET = (1<<LED3);
        	}

            /*****Check 2*****/    
        	if(6 == NRF_UARTE0->TXD.AMOUNT){
        		NRF_P0->OUTSET = (1<<LED2);
        	}

            NRF_UARTE0->EVENTS_ENDTX = 0;
            NRF_UARTE0->TASKS_STOPTX = 0;
        }
    }
}
  • FormerMember
    0 FormerMember in reply to RK

    So, I was testing the simplified code that Aryan posted, which I modified a little. Now 'hello' gets printed only when at least one of the #if statement is '1' when the optimization level is O1 or greater. With O0 or Og, it works in any case.

    It is strange that just adding a NOP before or after can change the way GCC initializes the string.

    #include <stdbool.h>
    #include <stdint.h>
    #include "nrf_delay.h"
    #include "nrf_gpio.h"
    #include "nrf_clock.h"
    #include "boards.h"
    #include "nrf_uart.h"
    
    int main(void)
    {
        /* Configure TX and RX pins from board.h */
        nrf_gpio_cfg_output(TX_PIN_NUMBER);
        nrf_gpio_cfg_input(RX_PIN_NUMBER, GPIO_PIN_CNF_PULL_Disabled);
        NRF_UARTE0->ENABLE = (UARTE_ENABLE_ENABLE_Enabled << UARTE_ENABLE_ENABLE_Pos);
        NRF_UARTE0->PSEL.TXD = TX_PIN_NUMBER;
        NRF_UARTE0->PSEL.RTS = RX_PIN_NUMBER;
    
        nrf_gpio_cfg_output(RTS_PIN_NUMBER);
        nrf_gpio_cfg_input(CTS_PIN_NUMBER, GPIO_PIN_CNF_PULL_Disabled);
        NRF_UARTE0->PSEL.RTS = RTS_PIN_NUMBER;
        NRF_UARTE0->PSEL.CTS = CTS_PIN_NUMBER;
        NRF_UARTE0->CONFIG = (UARTE_CONFIG_HWFC_Enabled << UARTE_CONFIG_HWFC_Pos);
    
        /* Configure other UART parameters, BAUD rate is defined in nrf52-uart.h    */
        NRF_UARTE0->BAUDRATE = (UARTE_BAUDRATE_BAUDRATE_Baud460800 << UARTE_BAUDRATE_BAUDRATE_Pos);
    
        while(true) 
        {
    
    	nrf_delay_ms(1000);
    
    #if 1
    	volatile
    #endif 
    	uint8_t str[] = "hello\n";
    	uint32_t len = 6;
    
    #if 0		//Pre NOP
            register uint32_t delay asm ("r0") = 1;
        __ASM volatile (
              " NOP"
               : "+r" (delay)); 
    #endif
            NRF_UARTE0->TXD.PTR = (uint32_t)((uint8_t *) str);
            NRF_UARTE0->TXD.MAXCNT = (uint32_t) len;
    
            NRF_UARTE0->TASKS_STARTTX = 1;
            NRF_UARTE0->EVENTS_ENDTX = 0;
            while((0 == NRF_UARTE0->EVENTS_ENDTX));
    
    #if 0		//Post NOP
            register uint32_t delay1 asm ("r0") = 1;
        __ASM volatile (
              " NOP"
               : "+r" (delay1)); 
    #endif
        }
    }
    
  • Thanks RK for filing bug in GCC, can you point us to that GCC bug you filed. In case someone is aiming at you, then we can support you :) I do not believe that GCC will change anything or to that matter do not think that they will agree that it is a GCC bug. But we need some explanation of why it works if we change [] to *, or adding some asm in the end. Because we want to know why GCC thinks these two are different. That explanation is the best outcome I expect from this

  • And the answer - which I have come around to believing, is the code falls into 'implementation dependent' and gcc is within its rights to decide that string isn't used and remove it.

    Since the code was a piece of test code and not something anyone would be likely to write for real, initialized string on the stack going to a register and then wait for it to clock out, I don't think it's going to be a huge problem. It was however an interesting intellectual exercise.

  • I agree, i do not think that it is going to be a big problem and it was good exercise. What is still unanswered is about the piece of assembly we add in end which makes compiler allocate space. I see that you have asked that question but still remain unexplained.

    I will ask this information to be very visible in the migration guide from nRF51 to nRF52

Related