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

Nordic Thingy 52 - external I2C sensor device driver implementation

Hello everyone,

i'm trying to hook up an external i2C sensor to P5 connector (TWI_SCL_EXT, TWI_SDA_EXT) and created a device driver template ( from drv_gas_sensor.c example) .

to start with  i have created this function in m_environment.c:

/**@brief Function for initializing the MY sensor
 */
static uint32_t my_sensor_init(const nrf_drv_twi_t * p_twi_instance)
{
    uint32_t       err_code;
    drv_my_init_t init_params;

    static const nrf_drv_twi_config_t twi_config =
    {
        .scl                = TWI_SCL_EXT,
        .sda                = TWI_SDA_EXT,
        .frequency          = NRF_TWI_FREQ_400K,
        .interrupt_priority = APP_IRQ_PRIORITY_LOW
    };

    init_params.p_twi_instance = p_twi_instance;
    init_params.p_twi_cfg      = &twi_config;
    init_params.twi_addr       = MY_ADDR;
    init_params.data_handler   = drv_my_data_handler;

    err_code = drv_my_init(&init_params);
    RETURN_IF_ERROR(err_code);

    return NRF_SUCCESS;

}

//and calling this function in  m_environment_init() function as below

     err_code = my_sensor_init(p_params->p_twi_instance);
    APP_ERROR_CHECK(err_code);

let me know if this is right.

  • Hello Simon,

    Thank you very much for your detailed explanation.

    Do you have any sensor on Thingy that does not have an INTERRUPT pin , curious to know how do you handle such situation?. Just use another timer based interrupt ? Basically my sensor does not have an interrupt pin and  i just want to send a start measurement command(similar to drv_humidity_sample(..) function ) and then wait for 1 second or so before reading the sensor data(similar to drv_humidity_temp_get(..)). and then i have created a custom characteristics on m_environment.c  which will take this value and pass it to ble_tes_mysensor_set(..) in ble_tes.c file.

    Thanks

  • I am not too familiar with the hts221 sensor, but I think you can read the temperature output registers without using the interrupt. If you look at the image below, you can see that HTS_INT (P0.24) is connected to DRDY, and according to the hts221 datasheet the DRDY signal will go high after new data is available, and goes low after the registers are read. 

    However, I don't think there is anything stopping you from reading the output register without checking the DRDY line, you just risk reading the same data over again. If there is a small delay between the call to drv_humidity_sample(..) and  drv_humidity_temp_get(..) I think this should be fine.

    Be aware that I might be wrong. Test it out, and give me an update of the result.

    Best regards,

    Simon

  • Hello Simon,

    sorry for the confusion, i'm not using hts221 sensor.  i have a sensor which does not have DRDY/INT pin. it has only i2c interface and i'm able to read/write registers  through i2c.  i was thinking some kind of event scheduler will mimic DRDY/INT functionality and hence i can use rest of the API's similar to hts221 sensor.

    Thanks

  • Hello Simon,

    here is what i'm attempting to do.

    //i have written a drv_mysensor.c and created following event scheduler.

    APP_TIMER_DEF(m_idle_timer_id);

    void reset_idle_timer(void)
    {
        uint32_t err_code;

        // Stop timer
        err_code = app_timer_stop(m_idle_timer_id);
        APP_ERROR_CHECK(err_code);

        // Start timer
           err_code = app_timer_start(m_idle_timer_id,APP_TIMER_TICKS(1000),NULL);
        APP_ERROR_CHECK(err_code);
    }

    /**@brief event handler
     */
    void reset_idle_timer_event(void * p_event_data, uint16_t event_size)
    {
        reset_idle_timer();
        // Data ready
        m_drv_pm.evt_handler(DRV_MYSENSOR_EVT_DATA);
    }


    /**@brief event scheduler
     */
    static void idle_timer_evt_scheduler()
    {
        uint32_t err_code;

        // Reset idle timer
            err_code = app_sched_event_put(NULL, NULL, reset_idle_timer_event);
            APP_ERROR_CHECK(err_code);

    }

    // and  i'm expecting following function to be called from m_environment.c file every 1 second

    /**@brief My sensor event handler.
     */
    static void drv_mysensor_evt_handler(drv_mysensor_evt_t event)
    {
        uint32_t err_code;



        if (event == DRV_MYSENSOR_EVT_DATA)
        {
            ble_tes_mysensor_t dat;
     
            float value = drv_mysensor_get();
        
            if (m_get_mysensor== true)
            {
                err_code = ble_tes_mysensor_set(&m_tes, &value);
                APP_ERROR_CHECK(err_code);
                m_get_mysensor = false;
            }
        }
        else
        {
            APP_ERROR_CHECK_BOOL(false);
        }
    }

    // but my problem is i'm not hitting following case statement which i have added in  m_environment.c file, because of which idle_timer_evt_scheduler() function is not started.

            case BLE_TES_EVT_NOTIF_MYSENSOR:
                NRF_LOG_DEBUG("tes_evt_handler: BLE_TES_EVT_NOTIF_MYSENSOR: %d\r\n", p_tes->is_mysensor_notif_enabled);
                if (p_tes->is_mysensor_notif_enabled)
                {
                    err_code = mysensor_start();
                    APP_ERROR_CHECK(err_code);
                }
                else
                {
                    err_code = mysensor_stop(p_tes->is_mysensor_notif_enabled == false);
                    APP_ERROR_CHECK(err_code);
                }
                break;

  • Why are you starting and stopping the timer? Isn't it possible to create a repeated timer that fires every 1 second?

    I have not tested this myself, and I am not sure if this is the best way to go about it, but here I will present an approach that might work

    In drv_mysensor.c

    • Create an enable function ( similar to drv_humidity_enable(..) where you create and start a repeated timer that triggers idle_timer_evt_scheduler()
    • Inside idle_timer_evt_scheduler() run app_sched_event_put(NULL, NULL, reset_idle_timer_event)
    • In the function reset_idle_timer_event() only run m_drv_pm.evt_handler(DRV_MYSENSOR_EVT_DATA);
    • Create in init function (similar to drv_humidity_init(..) )
      • Here you can create the repeated timer (not start it)
      • In addition you set your event handler m_drv_pm.evt_handler here

    In m_environment.c

    • Create the event handler (similar to humidity_timeout_handler() )
    • Run the init and enable function that you created in drv_mysensor.c

    Best regards,

    Simon

Related