UART problems on the nRF9160 DK (bare metal programming)

I am trying to get the UARTE0 on the nRF9160 DK to transmit some bytes through the Virtual COM port. I am not sure why it does not work. I have included my source code below.

I have done some debugging with an oscilloscope on the TXD pin (P0.29) and the Ozone Debugger. So far, I can observe that the TXD pin goes low as soon as I enable the UART (line 47), even though I have set it high at line 16.

Basically, the UART never transmits anything and the TXD pin stays low after enabling the UART. It goes into an infinite loop while waiting for EVENTS_ENDTX to get set (line 58).

I have tried to implement the workaround for errata 23 as well. However, using the debugger, I can see that the registers in question (addresses 0x50008564 and 0x50008568) are both zero at startup, so maybe this is not applicable to my revision of the nRF9160? The program never enters the "if" statements at line 33 and 36.

What I have not tried are the PUBLISH and SUBSCRIBE registers. Do I need to use DPPI channels for my single-threaded application?

By the way, I have tried UARTE1 as well. And different GPIOs for TXD. Same results. I also tried to use SPIM. Same story. As soon as the peripheral is enabled, the GPIOs go low, even though they should be high. And tasks and events appear to be not working.

I am using the linker script, startup code and system code from the nrfx library found at github.com/.../nrfx:

mdk/nrf9160_xxaa.ld
mdk/gcc_startup_nrf9160.S
mdk/system_nrf9160.c

Any ideas on what could be wrong are highly appreciated. Thanks in advance :-)

#include "nrfx.h"

int main()
{
    // Use the HFXO as the high frequency clock
    NRF_CLOCK->TASKS_HFCLKSTART = 1;
    while (! NRF_CLOCK->EVENTS_HFCLKSTARTED); // Wait for the clock to start
    NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;

    // The primary virtual COM port on nRF9160 DK is using the following pins:
    // P0.26 CTS, P0.27 RTS, P0.28 RXD and P0.29 TXD
    
    // Configure the GPIOs
    NRF_P0->DIRCLR = (1<<28) | (1<<26); // Set RXD and CTS pins as inputs
    NRF_P0->DIRSET = (1<<29) | (1<<27); // Set TXD and RTS pins as outputs
    NRF_P0->OUTSET = (1<<29) | (1<<29); // Set TXD and RTS pins high
    
    // Route the UARTE0 pins to the above GPIOs
    NRF_UARTE0->PSEL.CTS = 26;
    NRF_UARTE0->PSEL.RTS = 27;
    NRF_UARTE0->PSEL.RXD = 28;
    NRF_UARTE0->PSEL.TXD = 29;
    
    // Configure the UART with no hardware flow control, no parity bit, one
    // stop bit and a baud rate of 115200.
    NRF_UARTE0->CONFIG = 0;
    NRF_UARTE0->BAUDRATE = 0x01D60000ul;
    
    // -------- Errata [23] UART: TASKS_RESUME impacts UARTE ------------------
    volatile uint32_t* RXENABLE = (volatile uint32_t*)0x50008564ul;
    volatile uint32_t* TXENABLE = (volatile uint32_t*)0x50008568ul;
    
    if (*TXENABLE == 1)
        NRF_UARTE0->TASKS_STOPTX = 1;         // Trigger TASKS_STOPTX
    
    if (*RXENABLE == 1)
    {
        NRF_UARTE0->ENABLE = 1;               // Enable UARTE
        NRF_UARTE0->TASKS_STOPRX = 1;         // Trigger TASKS_STOPRX
        while (*RXENABLE != 0);               // Wait until RXENABLE reads '0'
        NRF_UARTE0->ERRORSRC = 0;             // Clear ERRORSRC register
    }
    
    // -----------------------------------------------------------------------
    
    // Enable the UART
    NRF_UARTE0->ENABLE = 1;
        
    // Set up the UART to transmit these bytes
    const uint8_t data[4] = { 0xDE, 0xAD, 0xBE, 0xEF };
    NRF_UARTE0->TXD.MAXCNT = 4;
    NRF_UARTE0->TXD.PTR = (uint32_t)data;
    
    // Main loop that repeatedly transmits the above data
    while (1)
    {
        NRF_UARTE0->TASKS_STARTTX = 1;      // Start the transmission
        while (! NRF_UARTE0->EVENTS_ENDTX); // Wait for transmission to finish
        NRF_UARTE0->EVENTS_ENDTX = 0;       // Clear the ENDTX event
    }
    
}

Parents
  • Hi,

     

    I would recommend that you use defines in the nrf9160_bitfields.h for writing/reading registers.

    I got it working on my side, but there's 3 things needed to be done:

    1. Configure your pins as input/output in the NRF_P0->PIN_CNF[] registers.

    	NRF_P0->PIN_CNF[26] |= GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos;
    	NRF_P0->PIN_CNF[27] |= GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos;
    	NRF_P0->PIN_CNF[28] |= GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos;
    	NRF_P0->PIN_CNF[29] |= GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos;
    

    2. EasyDMA cannot read from flash. Change the "data" array to a static uint8_t, ie. not a const.

    3. The .ENABLE register value for UARTE is '8'.

        // Enable the UART
        NRF_UARTE0->ENABLE = UARTE_ENABLE_ENABLE_Enabled << UARTE_ENABLE_ENABLE_Pos;

     

    Could you try this and see if it works?

     

    Kind regards,

    Håkon

  • Thank you very much, Håkon - it works now :-)

    1. I did not have to use the PIN_CNF registers. But, I guess it might give more control over the GPIOs, although the registers are marked as "retained" in the datasheet?

    2. Yes... I forgot. Thank you for pointing that out.

    3. Well, this is embarrassing - I just assumed it was enabled by a "1" :-) I guess this is how the device knows if the peripheral should be enabled as UART, SPI, TWI, etc.?

    I have included my working code below and a scope screenshot:

    #include "nrfx.h"
    
    int main()
    {
        // Use the HFXO as the high frequency clock
        NRF_CLOCK->TASKS_HFCLKSTART = 1;
        while (! NRF_CLOCK->EVENTS_HFCLKSTARTED); // Wait for the clock to start
        NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
    
        // The primary virtual COM port on nRF9160 DK is using the following pins:
        // P0.26 CTS, P0.27 RTS, P0.28 RXD and P0.29 TXD
        
        // Configure the GPIOs
        NRF_P0->DIRCLR = (1<<28) | (1<<26); // Set RXD and CTS pins as inputs
        NRF_P0->DIRSET = (1<<29) | (1<<27); // Set TXD and RTS pins as outputs
        NRF_P0->OUTSET = (1<<29) | (1<<29); // Set TXD and RTS pins high
        
        // Route the UARTE0 pins to the above GPIOs
        NRF_UARTE0->PSEL.CTS = 26;
        NRF_UARTE0->PSEL.RTS = 27;
        NRF_UARTE0->PSEL.RXD = 28;
        NRF_UARTE0->PSEL.TXD = 29;
        
        // Configure the UART with no hardware flow control, no parity bit, one
        // stop bit and a baud rate of 115200.
        NRF_UARTE0->CONFIG = 0;
        NRF_UARTE0->BAUDRATE = 0x01D60000ul;
    
        // Enable the UART
        NRF_UARTE0->ENABLE = UARTE_ENABLE_ENABLE_Enabled << UARTE_ENABLE_ENABLE_Pos;
            
        // Set up the UART to transmit these bytes
        static uint8_t data[] = { 0xDE, 0xAD, 0xBE, 0xEF };
        NRF_UARTE0->TXD.MAXCNT = 4;
        NRF_UARTE0->TXD.PTR = (uint32_t)data;
        
        // Main loop that repeatedly transmits the above data
        while (1)
        {
            NRF_UARTE0->TASKS_STARTTX = 1;      // Start the transmission
            while (! NRF_UARTE0->EVENTS_ENDTX); // Wait for transmission to finish
            NRF_UARTE0->EVENTS_ENDTX = 0;       // Clear the ENDTX event
        }
        
    }

  • Hi,

     

    Glad to hear its working on your side as well!

    1. I did not have to use the PIN_CNF registers. But, I guess it might give more control over the GPIOs, although the registers are marked as "retained" in the datasheet?

    It isn't strictly needed, as the hardware peripheral itself will claim the pins.

    in cases where you need to disable the uart (for sleep purposes, lowers the current), you'd want to set the pin itself as idle, ie. high for serial communication. Then it is usually good to ensure that this is already set in the GPIO registers when the UARTE peripheral releases said pins.

    Well, this is embarrassing - I just assumed it was enabled by a "1" :-)

    Don't worry, I have done the same mistake many times.

    I guess this is how the device knows if the peripheral should be enabled as UART, SPI, TWI, etc.?

    Very good catch! Yes, this sets the hardware peripheral in "the wanted serial mode" state.

    '8' for UARTE, '9' for TWIS etc.

     

    Kind regards,

    Håkon

  • Thanks a lot for the very useful information, Håkon Slight smile

Reply Children
No Data
Related