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;
        }
    }
}
  • Aryan, I'm massively relieved if it's not a GCC bug so no need to apologise for that.

    PS I don't know if you do this or not, you said that optimized gcc is hard to follow (and it is). I always compile optimised but still add full debug info, the code is still scrambled but at least it has source in it.

    I've been looking at that code for a while and don't see what's wrong. Wondered if it could be due to the write buffer on the Cortex M4 delaying the TASKS_STARTTX=1 write and the while loop exiting instantly but that doesn't seem very likely. Have you tried setting EVENTS_TXSTOPPED to 0 explicitly before starting the transmission?

  • RK, you can probably help me out here I have made this code simple

    #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_Baud115200 << UARTE_BAUDRATE_BAUDRATE_Pos);
    
        uint8_t str[] = "hello\n";
        uint32_t len = 6;
    
        while(true) 
        {
            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));
            register uint32_t delay asm ("r0") = 1;
        __ASM volatile (
              " NOP"
               : "+r" (delay));
        }
    }
    

    With flags -O3, If i remove the ASM in the last, then it writes some garbage. If i add that ASM it does not. The problem does not seem to be write buffer, looking into the generated ASM, it looks like GCC is optimizing away below when no asm is used

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

    I am attaching two assembly dump files with and without the ASM code in the last. With ASM, look that there are few extra instructions while assigning str = hello

  • If this ASM dump makes any sense, this has to be with GCC, Now the code i pasted works exactly like what Prithviraj sees.

  • I"ll look - possibly in the morning as it's getting a bit late here now and I've been staring at this for a while. Do you happen to have the two .elf files for those as well as the disassembly? They'll have even more information about where the strings are stored and I can stuff them through Hopper. If not, no problem, I really need to get my nrf52 environement properly set up so I can compile this stuff.

  • do not have ELF, i have been on this for long time. Take rest and we can help Prithvi tomorrow.

Related