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

NRFX_UARTE nrf52832 not receiving all bytes

Dear Nordic fellows,

I have a Rigado BMD-350 that can transmit correctly bytes to another device via UARTE, but who cannot receive data correctly.

I'm using SDK15.3.0, softdevice 6.1.1.

For debugging,  I disabled all the bluetooth stack, and I initialized only the UART module like this

void my_uarte_init()
{
  nrfx_uarte_config_t uart_conf;
  memset(&uart_conf,0,sizeof(uart_conf));
  uart_conf.baudrate           = NRF_UARTE_BAUDRATE_115200;//p_init->serial.baud;
  uart_conf.hwfc               = NRF_UARTE_HWFC_DISABLED;//p_init->serial.hwfc;
  uart_conf.interrupt_priority = APP_TIMER_CONFIG_IRQ_PRIORITY; // 7 
  uart_conf.p_context          = 0 ; //initialized by the nrfx init function
  uart_conf.parity             = NRF_UARTE_PARITY_EXCLUDED;//p_init->serial.parity;
  uart_conf.pselcts            = PIN_NOT_CONNECTED; //NOT_CONNECTED
  uart_conf.pselrts            = PIN_NOT_CONNECTED;
  uart_conf.pselrxd            = RX_PIN_NUMBER; //8
  uart_conf.pseltxd            = TX_PIN_NUMBER; //6

  m_uart_instance = (nrfx_uarte_t)NRFX_UARTE_INSTANCE(0); //initialize UARTE0. the cast is safe to do
  err_code = nrfx_uarte_init(&m_uart_instance,&uart_conf,handle_nrfx_event);

  memset(m_tmp_buffer,0,UART_RX_BUF_SIZE);
  memset(debug_buffer,0,UART_RX_BUF_SIZE);
  debug_buffer_idx=0;
  m_tmp_buf_idx=0;
  m_tmp_buffer[0]=0;
  nrfx_uarte_rx(&m_uart_instance,m_tmp_buffer,1);
}

Buffer are 250bytes long each.

For the debugging purposes, I receive only one byte per NRFX_UARTE_EVT_ENDRX event.

There are two problems:

  • the number of bytes received is not correct
  • Some messages are not received

This is the event handling function:

static void handle_nrfx_event(nrfx_uarte_event_t const *p_event ,void* p_context)
{
  my_uart_evt_t event;// set the status to "Processing command"
  switch(p_event->type)
  {
    case NRFX_UARTE_EVT_ERROR:
      event.type = UART_EVT_UART_ERROR;
      event.data.uart_err.err_code = p_event->data.error.error_mask;
      event.data.uart_err.data     = p_event->data.error.rxtx.p_data;
      event.data.uart_err.length    = p_event->data.error.rxtx.bytes;
      handler(&event);
      break;
    case NRFX_UARTE_EVT_TX_DONE://NRFX_UARTE_EVT_TX_DONE:
      event.type   = UART_EVT_CMD_SENT;
      handler(&event);  
      break;
    case NRFX_UARTE_EVT_RX_DONE://NRFX_UARTE_EVT_RX_DONE:
      //DEBUG
      memcpy(&(debug_buffer[debug_buffer_idx]),p_event->data.rxtx.p_data,p_event->data.rxtx.bytes);
      debug_buffer_idx += p_event->data.rxtx.bytes;
      nrfx_uarte_rx(&m_uart_instance,m_tmp_buffer,1);
      return;
  }
}

When I test the function, sending 11 bytes ({0xb0,0xb0,0x0b,0x87,0x02,0x54,0x45,0x53,0x54,0x30,0x34}) at 115200 baud, 8N1 the debug_buffer, which only stores received data, is as follows: (I bolded the changes on the debug_buffer)

0B 87 02 54 45 53 54 30 ...

After the second transmission of the same 11 bytes, the debug_buffer becomes:

0B 87 02 54 45 53 54 30 34 B0 B0 ...

After the third:

0B 87 02 54 45 53 54 30 34 B0 B0 0B 87 02 54 45 53 54 30 ...

If, instead, I use nrfx_uarte_rx(&m_uart_instance, m_tmp_buffer,11) the device won't display the first reception of data, but at the second transfer the debug_buffer will be

0B 87 02 54 45 53 54 30 34 B0 B0 ...

which is all the data, but with the first two bytes at the end

I think I initialized the nrfx_uarte module correctly, and I think the minimal receiving procedure is correct.

Does anyone have a suggestion on what the problem could be?

Edit: added SDK

Parents
  • Hi,

    I see that with 11-byte configuration, everything works as one could expect. Device doesn't know where is the start of your packet, so it breaks a stream into 11-byte chunks in random places... and there are bad news - you have no way to know how many bytes are already in the buffer until RX_DONE event is received. The solution depends on your case. If you can define a points in time when to start reception, for example as a response on transmitted command, you're lucky. If your messages can arrive at any time, a simplest solution is to set a timeout that will restart a reception... but sometimes you will lose data during restart procedure.

    I suggest a most reliable way - to configure UARTE in double-buffered mode: set ENDRX-STARTRX shortcut and switch buffers on RXSTARTED event, then configure a timer in counter mode that will increment on RXDRDY event, so your application will know how many bytes are in current buffer. In this case your logic will decide where is the start of a message - by unique header byte, by time difference between received bytes, or come up with your method.

Reply
  • Hi,

    I see that with 11-byte configuration, everything works as one could expect. Device doesn't know where is the start of your packet, so it breaks a stream into 11-byte chunks in random places... and there are bad news - you have no way to know how many bytes are already in the buffer until RX_DONE event is received. The solution depends on your case. If you can define a points in time when to start reception, for example as a response on transmitted command, you're lucky. If your messages can arrive at any time, a simplest solution is to set a timeout that will restart a reception... but sometimes you will lose data during restart procedure.

    I suggest a most reliable way - to configure UARTE in double-buffered mode: set ENDRX-STARTRX shortcut and switch buffers on RXSTARTED event, then configure a timer in counter mode that will increment on RXDRDY event, so your application will know how many bytes are in current buffer. In this case your logic will decide where is the start of a message - by unique header byte, by time difference between received bytes, or come up with your method.

Children
  • Hi Dmitry, thanks

    I tried your first solution, but it didn't work and I will explain myself right now.

    I added some variables

    #define UART_RX_BUF_SIZE 250
    static uint8_t          m_uart_rx_buffer[UART_RX_BUF_SIZE];
    static uint8_t          m_uart_rx_buffer_index;
    static uint8_t          m_tmp_buffer[UART_RX_BUF_SIZE];
    static uint8_t          m_tmp_buffer1[UART_RX_BUF_SIZE];
    
    static uint8_t*         m_primary_buf   = m_tmp_buffer;
    static uint8_t*         m_secondary_buf = m_tmp_buffer1;
    static bool             is_currently_primary_buffer_m_tmp_buffer = true;
    

    And a function that starts the reception

    static void start_rx(uint8_t len)
    {
      //start rx
      nrfx_uarte_rx(&m_uart_instance,m_primary_buf,len);
      nrfx_uarte_rx(&m_uart_instance,m_secondary_buf,len);
    
      //invert primary buffer with secondary buffer for next round
      if(is_currently_primary_buffer_m_tmp_buffer)
      {
        //invert the boolean
        is_currently_primary_buffer_m_tmp_buffer = !is_currently_primary_buffer_m_tmp_buffer;
        //switch the pointer of primary buffer with secondary buffer
        m_primary_buf   = m_tmp_buffer1;
        m_secondary_buf = m_tmp_buffer;
      }
      else // currently m_primary_buf = m_tmp_buffer_1
      {
        //invert the boolean
        is_currently_primary_buffer_m_tmp_buffer = !is_currently_primary_buffer_m_tmp_buffer;
        //switch the pointer of primary buffer with secondary buffer
        m_primary_buf   = m_tmp_buffer;
        m_secondary_buf = m_tmp_buffer1;
      }
    }

    the function reset_uart() became

    void reset_uart()
    {
      m_uart_rx_buffer_index=0;
      m_uart_rx_buffer[0]=0;
      start_rx(11);
    }
    

    The debugging function that handles the NRFX_UARTE_EVT_RX_DONE event.

    static void handle_nrfx_event(nrfx_uarte_event_t const *p_event ,void* p_context)
    {
      // handle events. all are listed, it shouldn't go to the default case
      switch(p_event->type)
      {
        case NRFX_UARTE_EVT_ERROR:
          break;
        case NRFX_UARTE_EVT_TX_DONE://NRFX_UARTE_EVT_TX_DONE:
          break;
        case NRFX_UARTE_EVT_RX_DONE://NRFX_UARTE_EVT_RX_DONE:
          //DEBUG
          memcpy(&(debug_buffer[debug_buffer_idx]),p_event->data.rxtx.p_data,p_event->data.rxtx.bytes);
          debug_buffer_idx += p_event->data.rxtx.bytes;
          start_rx(11);
          return;
      }
    }

    The result is always:

    • First sending of 11 bytes is not received
    • Second sending of the 11 bytes results in 0B 87 02 54 45 53 54 30 34 B0 B0  (last 2 bytes should be the first ones)
    • All odd sendings result in a non-event
    • All even sendings result in a adding of the debug_buffer of the sequence 0B 87 02 54 45 53 54 30 34 B0 B0  
  • //start rx
    nrfx_uarte_rx(&m_uart_instance,m_primary_buf,len);
    nrfx_uarte_rx(&m_uart_instance,m_secondary_buf,len);

    This won't work. For double-buffered scheme, you need to switch buffers on RXSTARTED event. I don't know whether SDK libraries support this mode, I have implemented it with direct programming of UARTE.

    void GNSS_UART_IRQHandler(void)
    {
    	if (COMM_UART->EVENTS_RXSTARTED)
    	{
    		COMM_UART->EVENTS_RXSTARTED = 0;
    		rxptr = (rxptr == uart_rx_buffer) ? uart_rx_buffer+UART_RX_BUFFER_SIZE/2 : uart_rx_buffer;
    		COMM_UART->RXD.PTR = (u32) rxptr;
    		COMM_UART->RXD.MAXCNT = UART_RX_BUFFER_SIZE / 2;
    	}
    	...
    }
    
    void gnss_uart_init(int baudrate, gnss_rx_callback rxcb)
    {
        ...
        rxptr = uart_rx_buffer;
    	COMM_UART->RXD.MAXCNT = UART_RX_BUFFER_SIZE / 2;
    	COMM_UART->RXD.PTR = (u32) rxptr;
    	COMM_UART->SHORTS = (1 << 5); // endrx-startrx
    	COMM_UART->ENABLE = 0x08; // enable
    	COMM_UART->EVENTS_RXSTARTED = 0;	
    	COMM_UART->TASKS_STARTRX = 1;
    	...
    }

  • Hi Dmitry, I tried your solution and the problem persists.

    The code I used is

    void UARTE0_UART0_IRQHandler(void)
    {
      if (m_uart_instance.p_reg->EVENTS_RXSTARTED)
      {
        m_uart_instance.p_reg->EVENTS_RXSTARTED = 0; // clear register
        m_uart_instance.p_reg->RXD.PTR = (uint32_t) m_secondary_buf;
        m_uart_instance.p_reg->RXD.MAXCNT = UART_RX_BUF_SIZE;
          //invert primary buffer with secondary buffer for next round
        if(is_currently_primary_buffer_m_tmp_buffer)
        {
          //invert the boolean
          is_currently_primary_buffer_m_tmp_buffer = !is_currently_primary_buffer_m_tmp_buffer;
          //switch the pointer of primary buffer with secondary buffer
          m_primary_buf   = m_tmp_buffer1;
          m_secondary_buf = m_tmp_buffer;
        }
        else // currently m_primary_buf = m_tmp_buffer_1
        {
          //invert the boolean
          is_currently_primary_buffer_m_tmp_buffer = !is_currently_primary_buffer_m_tmp_buffer;
          //switch the pointer of primary buffer with secondary buffer
          m_primary_buf   = m_tmp_buffer;
          m_secondary_buf = m_tmp_buffer1;
        }
      }
      if(m_uart_instance.p_reg->EVENTS_RXDRDY)
      {
        m_uart_instance.p_reg->EVENTS_RXDRDY=0; //clear register
        m_bytes_received++;
        uint32_t amount = m_uart_instance.p_reg->RXD.AMOUNT;
      }
      if(m_uart_instance.p_reg->EVENTS_ENDRX)
      {
        m_uart_instance.p_reg->EVENTS_ENDRX=0; //clear register
        nrfx_uarte_event_t evt;
        evt.type = NRFX_UARTE_EVT_RX_DONE;
        evt.data.rxtx.bytes  = m_uart_instance.p_reg->RXD.AMOUNT;
        evt.data.rxtx.p_data = m_secondary_buf;
        handle_nrfx_event(&evt,NULL);
        //m_bytes_received++;
        uint32_t amount = m_uart_instance.p_reg->RXD.AMOUNT;
      }
    
      if(m_uart_instance.p_reg->EVENTS_ERROR)
      {
        err_code = m_uart_instance.p_reg->ERRORSRC;
        m_uart_instance.p_reg->ERRORSRC = err_code;
        m_uart_instance.p_reg->EVENTS_ERROR=0; //clear register
        uint32_t amount = m_uart_instance.p_reg->RXD.AMOUNT;
        nrfx_uarte_event_t evt;
        evt.type = NRFX_UARTE_EVT_ERROR;
        evt.data.error.error_mask = err_code;
        evt.data.error.rxtx.bytes=amount;
        evt.data.error.rxtx.p_data = m_secondary_buf;
        handle_nrfx_event(&evt,NULL);
      }
      if(m_uart_instance.p_reg->EVENTS_ENDTX)
      {
        nrfx_uarte_event_t event;
        event.type = NRFX_UARTE_EVT_TX_DONE;
        handle_nrfx_event(&event,NULL);
      }
    }

    And I'm just counting the bytes I received, by looking at the variable m_bytes_received

    The init function is

    void uart_msg_init(uart_msg_init_t *p_init)
    {
      if(p_init->handler==0)
      {
        APP_ERROR_CHECK(NRF_ERROR_INVALID_DATA);
      }
      handler = p_init->handler;
      //CONFIG uarte 
      m_uart_instance = (nrfx_uarte_t)NRFX_UARTE_INSTANCE(0); //initialize UARTE0. the cast is safe to do
     /** APPLY CONFIG in nrfx_uarte.c*/
      //set tx pin as output pin
      nrf_gpio_pin_set(TX_PIN_NUMBER);
      nrf_gpio_cfg_output(TX_PIN_NUMBER);
      //set rx pin as input pin
      nrf_gpio_cfg_input(RX_PIN_NUMBER, NRF_GPIO_PIN_NOPULL);
      m_uart_instance.p_reg->BAUDRATE = NRF_UARTE_BAUDRATE_115200;
      m_uart_instance.p_reg->PSEL.CTS = NRF_UARTE_PSEL_DISCONNECTED;
      m_uart_instance.p_reg->PSEL.RTS = NRF_UARTE_PSEL_DISCONNECTED;
      m_uart_instance.p_reg->CONFIG   = (uint32_t)NRF_UARTE_PARITY_EXCLUDED | (uint32_t)NRF_UARTE_HWFC_DISABLED;
      m_uart_instance.p_reg->PSEL.RXD = RX_PIN_NUMBER;
      m_uart_instance.p_reg->PSEL.TXD = TX_PIN_NUMBER;
    /** END APPLY CONFIG*/
    
      /** INTERRUPT ENABLE */
      m_uart_instance.p_reg->EVENTS_ENDRX     = 0;
      m_uart_instance.p_reg->EVENTS_ENDTX     = 0;
      m_uart_instance.p_reg->EVENTS_ERROR     = 0;
      m_uart_instance.p_reg->EVENTS_RXTO      = 0;
      m_uart_instance.p_reg->EVENTS_RXSTARTED = 0;
      m_uart_instance.p_reg->SHORTS           = (1<<5);//NRF_UARTE_SHORT_ENDRX_STARTRX;
      m_uart_instance.p_reg->TASKS_STARTRX    = 1; 
      m_uart_instance.p_reg->INTENSET         = (NRF_UARTE_INT_ENDRX_MASK |NRF_UARTE_INT_ENDTX_MASK | NRF_UARTE_INT_RXDRDY_MASK|
                                               NRF_UARTE_INT_RXSTARTED_MASK | NRF_UARTE_INT_ERROR_MASK | NRF_UARTE_INT_RXTO_MASK);
     
      /** INTERRUPT ENABLE */
      NVIC_SetPriority(UARTE0_UART0_IRQn,APP_TIMER_CONFIG_IRQ_PRIORITY);
      NVIC_EnableIRQ(UARTE0_UART0_IRQn);
      m_uart_instance.p_reg->ENABLE = UARTE_ENABLE_ENABLE_Enabled; // ENABLE UARTE
      //END of INIT
      memset(m_tmp_buffer,0,UART_RX_BUF_SIZE);
      m_bytes_received=0;
      reset_uart();
      debug_buffer_idx=0;
    }

    The number of bytes is always less than 9 per packet.

    Did I make some mistake enabling the interrupts?

  • Ok, I solved.

    In the end, the error was on the other side. Even though I was transmitting bytes, and the oscilloscope decoded them correctly, the NRF52832 didn't manage to decode them, and did not raise any error in the UARTE registers

Related