Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Not receiving BLE NUS data on the nRF Toolbox app; getting 0x04 error code from app_uart_put().

Hi,

I'm using the Nordic DK52 (52832) along with SDK 15.0 to prototype an application where I can send some data from a sensor attached via UART to an BLE-enabled application. I'm using nRF Toolbox with the Serial feature to test whether I'm getting any data sent from the sensor. I am using SESV4.22 for the development of the application.

I've started out with the ble_app_uart example and attempted to modify it to my needs. Below I'm providing code snippets where I changed the functions; everything else is unchanged:

//Send this to the sensor to initiate a measurement
static uint8_t const readLiveDataCmd[] = {0x16, 0x13, 0x2D, 0x10, 0x1F, 0x00, 0x7E};

//Don't care if data is sent to the board
static void nus_data_handler(ble_nus_evt_t * p_evt)
{

    /*if (p_evt->type == BLE_NUS_EVT_RX_DATA)
    {
        uint32_t err_code;

        NRF_LOG_DEBUG("Received data from BLE NUS. Writing data on UART.");
        NRF_LOG_HEXDUMP_DEBUG(p_evt->params.rx_data.p_data, p_evt->params.rx_data.length);

        for (uint32_t i = 0; i < p_evt->params.rx_data.length; i++)
        {
            do
            {
                err_code = app_uart_put(p_evt->params.rx_data.p_data[i]);
                if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_BUSY))
                {
                    NRF_LOG_ERROR("Failed receiving NUS message. Error 0x%x. ", err_code);
                    APP_ERROR_CHECK(err_code);
                }
            } while (err_code == NRF_ERROR_BUSY);
        }
        /*if (p_evt->params.rx_data.p_data[p_evt->params.rx_data.length - 1] == '\r')
        {
            while (app_uart_put('\n') == NRF_ERROR_BUSY);
        }*/
    //}
}

void uart_event_handle(app_uart_evt_t * p_event)
{
    static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
    static uint8_t index = 0;
    float          temperature = 0;
    float          pressure = 0;
    uint8_t        data[64];
    uint32_t       err_code;
    


    switch (p_event->evt_type)
    {
        case APP_UART_DATA_READY:
            UNUSED_VARIABLE(app_uart_get(&data_array[index]));
            index++;

            if ((data_array[index - 4] == (uint16_t) 0x10) && (data_array[index-3] == (uint16_t) 0x1F))
            {
                NRF_LOG_DEBUG("Got Sensor Readings");
                NRF_LOG_HEXDUMP_DEBUG(data_array, index);
                
                union {
                char c[4];
                float f;
                } u;
                
                u.c[0] = data_array[7];
                u.c[1] = data_array[8];
                u.c[2] = data_array[9];
                u.c[3] = data_array[10];

                pressure = u.f;

                u.c[0] = data_array[11];
                u.c[1] = data_array[12];
                u.c[2] = data_array[13];
                u.c[3] = data_array[14]; 

                temperature = u.f;
                
                
                /*Send the temp and pressure data to the BLE*/
                do
                { 
                    sprintf((char*) data,"Temperature: %f; Pressure: %f", temperature, pressure);
                    uint16_t length = (uint16_t)sizeof(data);
                    err_code = ble_nus_data_send(&m_nus, data, &length, m_conn_handle);
                    if ( (err_code != NRF_ERROR_INVALID_STATE) && (err_code != NRF_ERROR_BUSY) &&
                         (err_code != NRF_ERROR_NOT_FOUND) )
                    {
                        APP_ERROR_CHECK(err_code);
                    }
                } while (err_code == NRF_ERROR_BUSY);

                index = 0;
            }
            break;

        case APP_UART_COMMUNICATION_ERROR:
            APP_ERROR_HANDLER(p_event->data.error_communication);
            break;

        case APP_UART_FIFO_ERROR:
            APP_ERROR_HANDLER(p_event->data.error_code);
            break;

        default:
            break;
    }
}

//main
int main(void)
{
    bool erase_bonds;

    // Initialize.
    uart_init();
    log_init();
    timers_init();
    buttons_leds_init(&erase_bonds);
    power_management_init();
    ble_stack_init();
    gap_params_init();
    gatt_init();
    services_init();
    advertising_init();
    conn_params_init();

    // Start execution.
    //printf("\r\nUART started.\r\n");
    NRF_LOG_INFO("Debug logging for UART over RTT started.");
    advertising_start();

    // Enter main loop.
    for (;;)
    { 
        //idle_state_handle();
        uint32_t err_code;
        for(uint8_t i = 0; i < sizeof(readLiveDataCmd); i++)
        {
          do
          {
            err_code = app_uart_put(readLiveDataCmd[i]);
             if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_BUSY))
                  {
                      if(err_code == 0x04)
                      {
                        break;
                      }
                      else
                      {
                        APP_ERROR_CHECK(err_code);
                      }
                  }
          } while (err_code == NRF_ERROR_BUSY);
        }
    }
}


When I run the app as is, I can see the advertisement in the nRF Toolbox and I can connect to the board, but I get nothing transmitted from the sensor. When I try to debug the application, I get an error 0x04 returned a from the app_uart_put() function.

What did I miss in my program?

  • Hello,

    So it is when you are receiving data over BLE and try to print it on the UART that you receive the 0x04 return value (NRF_ERROR_NO_MEM)?

    How did you initialize your uart? Have you set the tx buffer? What size is your tx buffer? Are you able to see any output on the UART at all? 

    Please note that app_uart_put is used to print on the physical UART, and not to send data to the connected phone. Is this your intention? To print on the physical UART?

    Best regards,

    Edvin

  • Hi Edvin,

    The purpose of my program is to read a value from the sensor and then send it via BLE to the app.

    No, I'm not sending any data over BLE. I get the 0x04 return value when I send the data to the sensor that is attached to the DK.

    My uart initialization is as follows:

    #define UART_TX_BUF_SIZE                256                                         /**< UART TX buffer size. */
    #define UART_RX_BUF_SIZE                256     
    
    /**@snippet [UART Initialization] */
    static void uart_init(void)
    {
        uint32_t                     err_code;
        app_uart_comm_params_t const comm_params =
        {
            .rx_pin_no    = RX_PIN_NUMBER,
            .tx_pin_no    = TX_PIN_NUMBER,
            .rts_pin_no   = RTS_PIN_NUMBER,
            .cts_pin_no   = CTS_PIN_NUMBER,
            .flow_control = APP_UART_FLOW_CONTROL_DISABLED,
            .use_parity   = false,
    #if defined (UART_PRESENT)
            .baud_rate    = NRF_UART_BAUDRATE_38400
    #else
            .baud_rate    = NRF_UARTE_BAUDRATE_115200
    #endif
        };
    
        APP_UART_FIFO_INIT(&comm_params,
                           UART_RX_BUF_SIZE,
                           UART_TX_BUF_SIZE,
                           uart_event_handle,
                           APP_IRQ_PRIORITY_LOWEST,
                           err_code);
        APP_ERROR_CHECK(err_code);
    }


    I have not connected the board to an oscilloscope/LA, but when I debug I can see that the app_put_uart() function is transmitting bytes to the sensor. I have not verified that the sensor responds.

    No, I'm sending data using the ble_nus_data() function in the nus_data_handler() function.

    Thank you so much!

  • Is your sensor connected via UART on the nRF?

    So you want to transfer data:
    Sensor -> UART -> nRF (peripheral) -> BLE -> Phone (central)?

    If so, what is the reason you are calling app_uart_put()?

    Either way, it shouldn't return 0x04 unless you have sent a lot of data too fast, filling up the buffer before you are able to process it. Can you double check that there is app_fifo_put inside app_uart_put that returns 0x04?

    Since this is in your main loop, I suspect that you are calling this too fast. Is it the intention to continuously print readLiveDataCmd[] on the UART? Perhaps you can try to use a timer (app_timer) to do this once a second instead of doing it as fast as the CPU can manage?

  • Edvin,

    Is your sensor connected via UART on the nRF?

    Yes, via pins 6 and 8.

    So you want to transfer data:
    Sensor -> UART -> nRF (peripheral) -> BLE -> Phone (central)?

    Yes. The reason I'm calling app_uart_put() so I can send a measure command to the sensor. So I guess a modified diagram can look something like this:

    nRF (peripheral) -> UART -> Sensor
    Sensor -> UART -> nRF (peripheral) -> BLE -> Phone

    Either way, it shouldn't return 0x04 unless you have sent a lot of data too fast, filling up the buffer before you are able to process it. Can you double check that there is app_fifo_put inside app_uart_put that returns 0x04?

    Just double checked and I'm not seeing that app_fifo_put returns 0x04.

    Since this is in your main loop, I suspect that you are calling this too fast. Is it the intention to continuously print readLiveDataCmd[] on the UART? Perhaps you can try to use a timer (app_timer) to do this once a second instead of doing it as fast as the CPU can manage?

    I was going to ask about that! Alright, I can try that. Would that interact with the interrupts raised by UART at all?

  • nikostpn said:
    Just double checked and I'm not seeing that app_fifo_put returns 0x04.

    So where does the 0x04 come from? Unless it is a softdevice call (sd_...) it should be possible to debug down to where it decides to return 0x04.

     

    nikostpn said:
    Would that interact with the interrupts raised by UART at all?

     What do you mean by interact? It is possible to queue writes to the uart from the timer callbacks, yes. Depending on priority settings it may or may not be processed until you release the timer interrupt. One way is to set a flag in the timeout, and then handle that from main(). Something like this (pseudo code):

    //near top of main:
    volatile bool m_request_sensor_data = false;
    
    void my_timer_timeout_handler()
    {
        m_request_sensor_data = true;
    }
    
    void request_data_from_sensor()
    {
        send_request_packet_over_uart();
    }
    
    int main()
    {
        initialize_my_timers();
        start_my_timer();
        ...
        
        while(true)
        {
            //main_loop
            if (m_request_sensor_data == true)
            {
                m_request_sensor_data = false;
                request_data_from_sensor();
            }
            sd_app_evt_wait();
        }
    }

Related