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

Sending actual TWI sensor values through BLE

Hello! I am trying to modify the ble_app_hrs_freertos example to send actual heart rate sensor value to the nRF Toolbox app over BLE. I am able to read values from my sensor through TWI, and I am also able to run the ble_app_hrs_freertos example and send the simulated data through BLE. Now, I would like to combine the two, and send the actual reading from the sensor to the app through BLE.

I tried modifying the heart_rate_meas_timeout_handler function of the code to take value from the sensor instead of sensorsim_measure(). However when I do this, I am not able to the device anymore. After trying different things, I realized that the nrf_drv_twi_tx() and nrf_drv_twi_rx() function is the issue. My I wrong to call nrf_drv_twi_tx() and nrf_drv_twi_rx() in the handler? How then, can I get the sensor reading through TWI?

static void heart_rate_meas_timeout_handler(TimerHandle_t xTimer)
{
    static uint32_t cnt = 0;
    ret_code_t      err_code;
    uint8_t        heart_rate;

    UNUSED_PARAMETER(xTimer);

    //heart_rate = (uint16_t)sensorsim_measure(&m_heart_rate_sim_state, &m_heart_rate_sim_cfg);
    heart_rate = readHRS();
    
    cnt++;
    err_code = ble_hrs_heart_rate_measurement_send(&m_hrs, heart_rate);
    if ((err_code != NRF_SUCCESS) &&
        (err_code != NRF_ERROR_INVALID_STATE) &&
        (err_code != NRF_ERROR_RESOURCES) &&
        (err_code != NRF_ERROR_BUSY) &&
        (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING)
       )
    {
        APP_ERROR_HANDLER(err_code);
    }

    // Disable RR Interval recording every third heart rate measurement.
    // NOTE: An application will normally not do this. It is done here just for testing generation
    // of messages without RR Interval measurements.
    m_rr_interval_enabled = ((cnt % 3) != 0);
}


void readHRS(uint8_t * read_long_data){
    ret_code_t err_code;
    
    err_code = nrf_drv_twi_tx(&m_twi_nrf52, HRS_ADDR, (uint8_t *) HRS_FIFO_DATA, sizeof(HRS_FIFO_DATA), true);

    if (NRF_SUCCESS == err_code){
	    err_code = nrf_drv_twi_rx(&m_twi_nrf52, HRS_ADDR, (uint8_t *) read_long_data, 6);
    }
    APP_ERROR_CHECK(err_code);
    nrf_delay_ms(10);
}

THANK YOU!

Parents
  • Hi,

    The heart_rate_meas_timeout_handler() is just an app_timer timeout handler function, so it should not be any problems starting a TWI transaction here.

    What do you mean by "when I do this, I am not able to the device anymore."? Have you done any debugging to find out what actually happens?

    Without knowing more, the one thing that stands out is your call to nrf_delay_ms(). Note that this is in an RTC interrupt routine (app_timer), so any same or lower interrupt priorities will be blocked. You should not use nrf_delay_ms or other forms of bussy waiting. Instead, it would make sense to start the TWI transfer and then wait for an event when the TWI transfer has completed. Then you can call ble_hrs_heart_rate_measurement_send() from the TWI event handler.

  • What do you mean by "when I do this, I am not able to the device anymore."? 

    Sorry, I meant that I wasn't able to connect to the device anymore when tried to modify the heart_rate_meas_timeout_handler function of the code to take value from the sensor instead of sensorsim_measure(). 

    Have you done any debugging to find out what actually happens?

    Yes, so I tried commenting out lines of code that are used in the readHRS() function and I was only able to connect to the device through BLE when I commented out nrf_drv_twi_tx() and nrf_drv_twi_rx().So I thought that was the issue.

    Then you can call ble_hrs_heart_rate_measurement_send() from the TWI event handler.

    Can you elaborate more on how I can do this? Right now I am calling the ble_hrs_heart_rate_measurement_send() in the heart_rate_meas_timeout_handler() and using the heart_rate_meas_timeout_handler() in timer_init()

    static void timers_init(void)
    {
        // Initialize timer module.
        ret_code_t err_code = app_timer_init();
        APP_ERROR_CHECK(err_code);
    
        // Create timers.
        m_battery_timer = xTimerCreate("BATT",
                                       BATTERY_LEVEL_MEAS_INTERVAL,
                                       pdTRUE,
                                       NULL,
                                       battery_level_meas_timeout_handler);
        m_heart_rate_timer = xTimerCreate("HRT",
                                          HEART_RATE_MEAS_INTERVAL,
                                          pdTRUE,
                                          NULL,
                                          heart_rate_meas_timeout_handler);
        m_rr_interval_timer = xTimerCreate("RRT",
                                           RR_INTERVAL_INTERVAL,
                                           pdTRUE,
                                           NULL,
                                           rr_interval_timeout_handler);
        m_sensor_contact_timer = xTimerCreate("SCT",
                                              SENSOR_CONTACT_DETECTED_INTERVAL,
                                              pdTRUE,
                                              NULL,
                                              sensor_contact_detected_timeout_handler);
    
        /* Error checking */
        if ( (NULL == m_battery_timer)
             || (NULL == m_heart_rate_timer)
             || (NULL == m_rr_interval_timer)
             || (NULL == m_sensor_contact_timer) )
        {
            APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
        }
    }
    
    
    static void heart_rate_meas_timeout_handler(TimerHandle_t xTimer)
    {
        static uint32_t cnt = 0;
        ret_code_t      err_code;
        uint8_t        heart_rate;
    
        UNUSED_PARAMETER(xTimer);
    
        //heart_rate = (uint16_t)sensorsim_measure(&m_heart_rate_sim_state, &m_heart_rate_sim_cfg);
        heart_rate = readHRS();
        
        cnt++;
        err_code = ble_hrs_heart_rate_measurement_send(&m_hrs, heart_rate);
        if ((err_code != NRF_SUCCESS) &&
            (err_code != NRF_ERROR_INVALID_STATE) &&
            (err_code != NRF_ERROR_RESOURCES) &&
            (err_code != NRF_ERROR_BUSY) &&
            (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING)
           )
        {
            APP_ERROR_HANDLER(err_code);
        }
    
        // Disable RR Interval recording every third heart rate measurement.
        // NOTE: An application will normally not do this. It is done here just for testing generation
        // of messages without RR Interval measurements.
        //m_rr_interval_enabled = ((cnt % 3) != 0);
    }
    
    
    void readHRS(uint8_t * read_long_data){
        ret_code_t err_code;
        
        err_code = nrf_drv_twi_tx(&m_twi_nrf52, HRS_ADDR, (uint8_t *) HRS_FIFO_DATA, sizeof(HRS_FIFO_DATA), true);
    
        if (NRF_SUCCESS == err_code){
    	    err_code = nrf_drv_twi_rx(&m_twi_nrf52, HRS_ADDR, (uint8_t *) read_long_data, 6);
        }
        APP_ERROR_CHECK(err_code);
    
    }

     

  • Hi,

    If you are using Segger Embedded Studio, you simply select the debug build configuration (usually by a drop-down in the upper left corner of the screen). If you are using another toolchain, just make sure you have a global define "DEBUG" and build without optimization.

    Then enable debug logging in sdk_config.h if it is not already enabled (UART logging is enabled by default in most examples). If you are using an example without logging, you could just use the debugger to inspect the info struct in the error handler to see the same information, but it is a bit more hassle.

    Unfortunately, there is no unified list of error codes in the SDK, but there is a hierarchy with error bases etc. If you use logging the error code will most of the time be spelled out with the name of the define, so you won't have to piece it together.

  • Hi, 

    Does the debugging mode shows error during the BLE transaction? I don't seem to be getting any error in the debugging mode. When I give dummy heart rate values in the code, the BLE transactions works fine, but once I make it read from the sensor, the BLE connection crashes. Could that be an issue with the timing? But shouldn't the timing issue be handled automatically, since it is in non-blocking mode?

  • Hi,

    It could be a timing issue or could be something else. The key is that you need to debug to understand what the connection is dropped. Without proper debugging you will just have to guess, and that is not a good way of approaching this. We have already seen from the screenshot of your call stack in a previous post that the nRF is in an error handler. So you need to debug to see what error occurred. Have you done that? You may find An introduction to error handling in nRF5 projects interesting, though it is not fully up to date.

  • Thank you for sending this link. I will go through it to debug. Meanwhile, I have a quick question.

    In the twi sensor example, the twi transaction "read_sensor_data()" is called in the main function, instead of in the data_handler, and I believe that the interrupt is controlled by the state of m_xfer_done. Is that an approach I can try too? Or does it not work in my case because I have to send the data through BLE?

    Thanks!

  • Hi,

    You can use this method. How you obtain data via WTI is independent from how you use it later (such as transferring over BLE).

Reply Children
No Data
Related