Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob

How to Initialize and Read From an I2C Sensor

lock attach
Attachments are accessible only for community members.

How to Initialize and Read From an I2C Sensor

250 replies posted 100 replies posted 50 replies posted

Back to main page: Leveraging TAG4 to better understand the WICED Smart Programming Environment

    We won’t get into the fine details of the I2C protocol. Here, we will show how to execute I2C reads and writes using the WICED Smart platform and API. Keep in mind that what’s contained in this blog only applies to other chips at an abstract level. The specific API and drivers we have are for WICED Devices.

    What is a driver? Without an understanding of I2C you may look at an I2C driver in wonder. The driver is a set of functions that calls on the I2C API (the API is what is actually executing the I2C protocol at a hardware level) in a device-specific manner to make the sensor serve its purpose. Every sensor has its own driver and therefore requires that a different sequence/different register addresses/different I2C addresses be used. When creating your own apps you will never interact with the I2C API, but rather the driver for the specific sensor with which you wish to interact.

    The drivers necessary for the Tag4 are attached to this post. But let’s consider the other case: you get your hands on an I2C sensor that isn’t attached to your Tag4 device and you want to attach it. That’s for a separate, future project entirely, but we will, indeed, enter the realm of writing our own drivers for I2C devices.

    There are basic principles to understand before attempting to use an I2C device. It’s highly advised that you gain a general understanding of the protocol before proceeding (understand the use of addresses versus hardware chip select lines like on SPI, a different serial protocol).

    In all the research you’ve done at this point, you likely understand what a read and write sequence looks like. Conceptually, however, how do we interact with a sensor?

    • Writing to an I2C Register
      • In the sensor’s data sheet you will find a series of command registers. These command registers are to be written to in order to change the characteristics of the sensor. This is what your initialization will consist of (see below).

    • Reading Data from an I2C Device
      • In order to gather data from an I2C sensor, there are generally multiple steps taken. In order to read sensor data, the device must be written to, told to fill its data register with data, then that register must be read from. Sometimes, a third step is necessary: you may need to check the status of the data prior to reading (by reading a status register) and not perform the reading until the data is available. This is sometimes necessary because prematurely reading data will destroy it.

Fortunately, prewritten drivers do most of the tough work for you. Nonetheless, it’s necessary to understand for future I2C projects and debugging.

-------------------------------------------------STEP-BY-STEP GUIDE TO SAMPLE FIRMWARE-----------------------------------------------

With all that said, there are four steps that you will see in the attached test code that are necessary to accomplish the task at hand:

      1. We must apply power to the sensor.
      2. Then, we must initialize the sensor.
      3. Third, we tell the sensor to fill its data registers with the information we need.
      4. Lastly, we read the data register.

1.  On the Tag4 board the sensors are powered by a BJT that that is controlled by GPIO 2. In order to apply power to the sensors, in our create function we put GPIO 2 low (PNP BJT) in order to apply power to the sensors. Additionally, the sensor switch block must be physically switched on (SW 9).

gpio_configurePin(0, 2, GPIO_OUTPUT_ENABLE | GPIO_INPUT_DISABLE, 0);
gpio_setPinOutput(0, 2, 0);

2.  To initialize the sensor, we have a prewritten function in the test code that initializes the sensors that will suit most of your needs. In this function we activate the sensor, set the ODR rate (sample rate, linearly related to power consumption), set average values, and finally, we enable the BDU feature. Without ever looking into the driver, however, we can alter these characteristics in order to fit app-specific needs.


                        void init_hts221(void){

                if(HTS221_Activate() == HTS221_OK)

                    ble_trace0("HTS221_Activate Successful");


                    ble_trace0("HTS221_Activate Failed.");

                if(HTS221_Set_Odr(HTS221_ODR_7HZ) == HTS221_OK)

                    ble_trace0("HTS221_Set_Odr Successful");


                    ble_trace0("HTS221_Set_Odr Failed.");

                if(HTS221_Set_AvgHT(HTS221_AVGH_8, HTS221_AVGT_4) == HTS221_OK)

                    ble_trace0("HTS221_Set_AvgHT Successful");


                    ble_trace0("HTS221_Set_AvgHT failed");

                if(HTS221_Set_BduMode(HTS221_ENABLE) == HTS221_OK)

                    ble_trace0("HTS221_Set_BduMode Successful");


                    ble_trace0("HTS221_Set_BduMode failed");


3.  Given that we’re working with one stop measurements it is necessary to tell the sensor to start its one stop measurement. This is compared to instantiating a FIFO which will constantly stream data. The code for starting the measurement is paired with that of step 4..

4.  Lastly we read the data register. This is a call to a function in the driver, into which we pass two pointers for the data to be inserted. We'll then use this variable as the buffer of our data to accomplish anything we want: printing their value, transmitting it, etc.

                          if(HTS221_StartOneShotMeasurement() == HTS221_OK){

                  if(HTS221_Get_Measurement(&humidity, &temperature) == HTS221_OK)

                      ble_trace2("Humi*10=%6d, Temp*10=%6d", humidity, temperature);


Steps 1 and 2 are to be executed once in your create function. Steps 3 and 4 will be done continuously, in a loop (in our test app). When we work with interrupts we will be able to trigger a read on an interrupt. Alternatively, we may consider the case of power saving. In the test app, we start the sensor and never stop it. But if every micro-amp counts for your application, you may de-initialize the sensor and put P2 high, then reinitialize when you need the sensor again.

              void hts221_deinitialize ( void ) {

            if(HTS221_DeActivate() == HTS221_OK)

                ble_trace0("HTS221_DeActivate Successful");


                ble_trace0("HTS221_DeActivate Failed.");


Run traces on the attached test code. The values will stream across your terminal. Breathe on your board and watch the values for humidity and temperature rise.

Jacob W Torres

Back to main page: Leveraging TAG4 to better understand the WICED Smart Programming Environment