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.

Parents
  • I don't see anything wrong initially, but it is diffiucult to say without seeing your custom made sensor driver. Remember to not use the same pins for the SDA and SCL as any of the already connected sensor. An option is to connect the external sensor using the pins available due I/O expander, as Martin suggested in this post.

    Best regards,

    Simon

  • Hello Simon, thanks for your response and suggestion.
    to clarify i just assume that i2c bus can have multiple i2c sensors on
    same bus provided they have unique slave address. with that in mind i
    connected my sensor to TWI_SCL_EXT and TWI_SDA_EXT pin which is also
    share with LIS2DH12. let me know if this is OK.

    if i have to connect an exclusive i2c pin using IO expanded, please do
    let me know  which are the pins can be used from P4 connector.

    also  i do not have any interrupt pin on my sensor, hence i can not
    use io interrupt driven - event handler. let me know best possible
    example.

    By the way connecting my sensor to P5 ( TWI_SCL_EXT, TWI_SDA_EXT )
    connector and then running my i2c sensor code as a standalone
    application ( using ble peripheral example from Sdk 15.0)  i'm able to
    read sensor data and pass this data to a custom BLE characteristics.
    however i do not have any event handling in that standalone
    application.

    trouble mounts only when i combine this code with Thingy FW which is
    basically non blocking implementation.

    thanks for your time.

  • 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

Reply
  • 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

Children
Related