If you are having issues with the exercises, please create a ticket on DevZone:
Click or drag files to this area to upload. You can upload up to 2 files.

Exercise 2

Connecting to the BH1749 Ambient Light Sensor on the Thingy:91 and Thingy:53

Instead of the usual development kits, we have used to run samples and exercises throughout this course, this exercise uses a special type of Nordic Semiconductors’ prototyping boards called the Thingy. This exercise can be run on either a Thingy:53 or a Thingy:91.


The Thingy is an easy-to-use battery-operated prototyping board that allows the user to build a proof-of-concept in minimal time as it contains onboard a variety of sensors and interfaces. For this exercise, to illustrate how to use the I2C interface, we will be using either the Thingy:53 or the Thingy:91 and make use of the BH1749: Ambient Light Sensor they have onboard.

Thingy:53 PCB, Front view, Light sensor location
Thingy:91 PCB, Back view, Light sensor location

The BH1749NUC is a color sensor which uses I2C for its interface. The Integrated Circuit (IC) onboard the sensor senses Red, Green, Blue (RGB), and infrared colors, then represents their intensities as digital values stored in 2 bytes for each value.

In this exercise, we will read the RGB value from the sensor and print it on a serial terminal.

Registers’ table as found in BH1749NUC color sensor datasheet

The above table shows the registers of the color sensor and their corresponding addresses. For our exercise, the relevant registers are the 4 registers in the red box. The 4 registers are, the basic SYSTEM_CONTROL register, the 2 MODE_CONTROL registers, used to set specific modes of the sensor, and lastly the RED_DATA register and more specifically the lower byte [7-0] in it, located at address 0x50.

To read color data (RGB without the IR value) from the sensor, you need to first set up the sensor mode, by writing to the MODE_CONTROL1 register. After that, you will need to enable measurements by writing to the MODE_CONTROL2 register. Lastly, you will need to do the actual reading from the data registers of RED_DATA, GREEN_DATA, and _BLUE_DATA. We will do a burst read starting from the first byte of the RED_DATA register.

Note that you can use the sensor’s driver (found here <nRF Connect SDK Installation Path>\nrf\drivers\sensor\bh1749>) to enable other features as well, such as reading infrared (IR) light intensity and utilizing interrupts. However, this exercise focuses only on the I2C aspect of interfacing the sensor, hence extra features are not within the scope of this exercise.

Exercise steps


To run this exercise using a Thingy:53, the nRF Connect SDK version used must be v2.3 or higher.

1. In the GitHub repository for this course, open the base code for this exercise, found in lesson6/fund_less6_exer2 of whichever version directory you are using (v2.x.x or v1.6.0-v1.9.1).

2. Enable the I2C driver by adding the following line to the prj.conf file.


If you are building with TF-M (thingyxx_nrfxxxx_ns), you will need to disable logging for TF-M. The UART peripheral used for TF-M shares the same base address as the TWIM peripheral used in this exercise, and it’s enabled by default in nRF Connect SDK 2.6.0 and above. To disable it, simply add these two Kconfig symbols in prj.conf.



3. In main.c , include the header file of the I2C API.

#include <zephyr/drivers/i2c.h>

4. To display the sensor readings on the console, we will use a simple printk().

4.1 Include the header file <sys/printk.h> to use printk()

#include <zephyr/sys/printk.h>

4.2 Enable floating point format specifiers in prj.conf by adding the symbol

5. (No action needed) In the previous exercise, we were using an external expansion board. Since the sensor was on that expansion board, and not built-in on a Nordic Semiconductor board, we needed a step to specify that the sensor is connected to an I2C controller and provide its address in an overlay file.

In this exercise, the sensor is built-in on the Thingy board and is already specified in the devicetree file. You can verify this by checking the devicetree file and searching for the BH1749 sensor as shown below.

6. Get the node identifier of the sensor. This was explained in detail in step 4 of the I2C Driver section.

#define I2C_NODE DT_NODELABEL(bh1749)

7. Retrieve the API-specific device structure, make sure that the device is ready to use, and print an error message if the I2C device is not ready to use:

static const struct i2c_dt_spec dev_i2c = I2C_DT_SPEC_GET(I2C_NODE);
if (!device_is_ready(dev_i2c.bus)) {
	printk("I2C bus %s is not ready!\n\r",dev_i2c.bus->name);

8. Define the addresses of the relevant registers, which can be found in the sensor datasheet. This information typically goes into a separate header file (.h). However, for the sake of keeping this demonstration simple, we will add them in main.c.

#define BH1749_SYSTEM_CONTROL                           0x40
#define BH1749_MODE_CONTROL1                            0x41
#define BH1749_MODE_CONTROL2                            0x42
#define BH1749_RED_DATA_LSB                             0x50
#define BH1749_MODE_CONTROL2_RGB_EN_ENABLE              BIT(4)
#define BH1749_MODE_CONTROL1_DEFAULTS                   0x2A

9. Setup the sensor by writing the value 0x2A to the MODE_CONTROL1 register.

As evident by the MODE_CONTROL1 register map below, 0x2A (0 01 01 010 in binary) would mean:

  • IR Gain: x1,
  • RGB Gain: x1
  • Measurement mode: 120ms
char buff1[] = {BH1749_MODE_CONTROL1,BH1749_MODE_CONTROL1_DEFAULTS};
ret = i2c_write_dt(&dev_i2c,buff1,sizeof(buff1));
if(ret != 0){
	printk("Failed to write to I2C device address 0x%c at Reg. 0x%c\n",dev_i2c.addr,BH1749_MODE_CONTROL1);

10. To read the RGB values from the sensor we need to enable measurement by writing 1 to bit 4 of the MODE_CONTROL2 register. We will use the i2c_write_dt() API as shown below

ret = i2c_write_dt(&dev_i2c,buff2,sizeof(buff2));
if(ret != 0){
	printk("Failed to write to I2C device address 0x%c at Reg. 0x%c\n",dev_i2c.addr,BH1749_MODE_CONTROL2);

11. Read the RGB values from the RED_DATA, GREEN_DATA, and BLUE_DATA registers.

Since these registers are sequential, we will do a burst read starting from the first byte of the RED_DATA which is at address 0x50 (BH1749_RED_DATA_LSB). Notice that we are reading six bytes (as the size of rgb_value the buffer is 6 bytes) so the register would store the values of RGB as: (most significant bit)BBGGRR(least significant bit)

uint8_t rgb_value[6]= {0};
//Do a burst read of 6 bytes as each color channel is 2 bytes
ret = i2c_burst_read_dt(&dev_i2c, BH1749_RED_DATA_LSB,rgb_value,sizeof(rgb_value));
if(ret != 0){
   printk("Failed to read to I2C device address 0x%c at Reg. 0x%c\n",dev_i2c.addr,BH1749_RED_DATA_LSB);
//Print reading to console  
printk("Red Value:\t %d\n", (rgb_value[0] | rgb_value[1] << 8));
printk("Green Value:\t %d\n", (rgb_value[2] | rgb_value[3] << 8));
printk("Blue Value:\t %d\n", (rgb_value[4] | rgb_value[5] << 8));

12. Build the application.

To build for a Thingy:91, use the same building procedure as used in the previous exercises and choose thingy91_nrf9160_ns as the target board in the Add Build Configuration window as shown below.

To build for the Thingy:53, use thingy53_nrf5340_cpuapp_ns as the target board instead.

13. Flash the application to your device.

To read more about flashing applications for the Thingy, click here for instructions regarding the Thingy:53 or click here for instructions regarding the Thingy:91. You should see an output similar to the one below.

To verify that the color values respond to ambient light changes, you can try for example covering the light sensor on the board (remember the location of the light sensor varies according to the Thingy version you are using, please refer to the board pictures at the top of this page) and observe how the values drastically decrease. You can also subject the board to a certain light color and observe how this value in the output increases.

The solution for this exercise can be found in the GitHub repository, lesson6/fund_less6_exer2_solution of whichever version directory you are using (v2.x.x or v1.6.0-v1.9.1).

Register an account
Already have an account? Log in
(All fields are required unless specified optional)

  • 8 or more characters
  • Upper and lower case letters
  • At least one number or special character

Forgot your password?
Enter the email associated with your account, and we will send you a link to reset your password.