Install Rohm digital ambient light sensor IC BH1750 on SP7021 BPI-F2S board

The goal of this document is to illustrate how to install Rohm digital ambient light sensor IC BH1750 on SP7021 BPI-F2S board.

Refer to BH1750 ambient light sensor module (GY-302) below:

This is a compact module board. It consists of a light sensor IC BH1750, a 3.3V LDO regulator XC6206, two 10k pull-up resistors, two 1k resistors and four capacitors. BH1750 is the main IC. Size of BH1750 is very small. It's only 1.6x1.6x0.55mm.

BH1750 supports I2C interface operating at 400 kHz. I2C address is either 0x23 (ADR = LOW) or 0x5c (ADR = HIGH).

Please follow the following steps:

1. Install hardware

Refer to schematics of BH1750 ambient light sensor IC module:

XC6206 is a low drop-out regulator (LDO) which converters VCC (+5V) input power to +3.3V power. BH1750 is ambient light sensor which senses illuminance and converts to digital code. R3 and R4 are 10k pull-up resistors for I2C signals SCL and SDA, respectively. C1, C3 and C4 are bypass capacitors which stabilize +5V and 3.3V powers. R1 and C5 set R/C time for power-on reset. Pin ADR of BH1750 is used to select I2C address. Connecting ADR to GND results in I2C address to be 0x23 while connecting ADR to +3.3V results in I2C address to be 0x5C. I2C signals SDA, SCL, address selection signal ADDR, ground and VCC (+5 Volts) power are connected to J1 directly. One can use the connector to supply power and communicate with BH1750.

Refer to pin-assignment of Raspberry Pi compatible pin-header of SP7021 BPI-F2S board:

Connect BH1750 ambient light sensor module to SP7021 BPI-F2S board as shown in following table:

Pin # of J1 of BH1750 module

Pin name of J1 of BH1750 module

Pin # of 40-pin pin-header

Pin name of 40-pin pin-header

1

VCC

2

+5V_VDD

2

GND

9

GND

3

SCL

5

GPIO_P1_5/G_MX13 (SCL1)

4

SDA

3

GPIO_P1_4/G_MX12 (SDA1)

5

ADDR

-

-

Refer to photograph, BH1750 ambient light sensor module is connected to 40-pin pin-header of SP7021 BPI-F2S board.

2. Modify device-tree source file

Modify device-tree node i2cm0 in device-tree source file linux/kernel/arch/arm/boot/dts/sp7021-bpi-f2s.dts to setup channel 0 of I2C master for BH1750 as shown below:

&i2cm0 { clock-frequency = <100000>; pinctrl-names = "default"; pinctrl-0 = <&i2cm0_pins>; #address-cells = <1>; #size-cells = <0>; bh1750@23 { compatible = "rohm,bh1750"; reg = <0x23>; status = "okay"; }; };

Note that i2cm0 is a label to node i2c@9c004600. Address of I2C of BH1750 is 0x23 (ADDR = LOW). Frequency of clock of I2C is set to 100,000 Hz.

Also, modify dts node pinmux_i2cm0-pins to setup pins for channel 0 of I2C master as shown below:

i2cm0_pins: pinmux_i2cm0-pins { sunplus,pins = < SPPCTL_IOPAD(13, SPPCTL_PCTL_G_PMUX, MUXF_I2CM0_CLK, 0) SPPCTL_IOPAD(12, SPPCTL_PCTL_G_PMUX, MUXF_I2CM0_DAT, 0) >; };

Note that node pinmux_i2cm0-pins is sub-node of node pctl. G_MX13 and G_MX12 are set as CLK and DAT signals of channel 0 of I2C master, respectively.

Please note that to comply with Linux rules, after version 5.10.59, 4 property-names of pin node of SP7021 are changed as shown in table below:

5.4.35

5.10.59

5.4.35

5.10.59

sppctl,function

function

sppctl,groups

groups

sppctl,pins

sunplus,pins

sppctl,zero_func

sunplus,zerofunc

3. Enable Linux device drivers

Run make kconfig in project top directory. When “Linux/arm Kernel Configuration” menu pops up, move cursor to go to “Device Drivers” → “I2C support” → “I2C Hardware Bus support” sub-menu. Move cursor to “SP I2C support” and enable it. Refer to screenshot below:

Move cursor to go to “Device Drivers” → “Industrial I/O support” and press <Y> to enable it. Refer to screenshot below:

 

Press <Enter> key to enter “Industrial I/O support” sub-menu. Move cursor to go to “Light sensors” → “ROHM BH1750 ambient light sensor” and enable it. Refer to screenshot below:

Finally, save configuration.

4. Build Linux image

Go to top folder. Run make all to build Linux image.

5. Boot Linux

Boot Linux with the built image.

6. Read illuminance

After Linux boots up successfully, run ls /sys/bus/iio/devices/iio:device0 to list sysfs of device iio:device0 (bh1750). Refer to screenshot below:

Please run cat command to show information of device iio:device0. Refer to screenshot below:

Current device name is bh1750 and its device number 252:0. Integration time of measurement is 0.120060 second (120 mS). Scaling factor is 0.833333.

Run cat /sys/bus/iio/devices/iio:device0/in_illuminance_raw to read raw data of illuminance. Refer to screenshot below:

Raw data of illuminance is 891. The real illuminance is:

in_illuminance_raw * in_illuminance_scale = 891 * 0.83333 = 473 (lx)

Unit of illuminance is lux (lx).

7. User-space device

If you want to use user-space applications to access I2C device file, instead of IIO interface via sysfs, please run make menuconfig and move cursor to go to “Device Drivers” → “I2C support” → “I2C device interface” and enable it. Refer to screenshot below:

When I2C interface driver probes successfully, it creates character device, /dev/i2c-X, where X is the channel number of I2C bus. Refer to screenshot, I2C device, /dev/i2c-0, is shown:

8. Example C code of using user-space device

Refer to the following C code for reading illuminance from BH1750 via Linux device file, /dev/i2c-0.

#include <stdio.h> #include <linux/types.h> #include <ctype.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <sys/ioctl.h> #include <errno.h> #include <string.h> #define I2C_RETRIES 0x0701 #define I2C_TIMEOUT 0x0702 #define I2C_RDWR 0x0707 #define I2C_DEV "/dev/i2c-0" /* i2c device */ #define I2C_ADDR 0x23 /* slave device address */ struct i2c_msg { unsigned short addr; unsigned short flags; unsigned short len; unsigned char *buf; }; struct i2c_rdwr_ioctl_data { struct i2c_msg *msgs; int nmsgs; }; struct i2c_rdwr_ioctl_data storage_data; struct i2c_msg storage_msg[2]; int i2c_write(int fd, unsigned char slvAddr, unsigned char* const data, unsigned short len) { storage_data.nmsgs = 1; storage_data.msgs[0].len = len; // data length storage_data.msgs[0].addr = slvAddr; // device address storage_data.msgs[0].flags = 0; // write storage_data.msgs[0].buf = data; // data if (ioctl(fd, I2C_RDWR, &storage_data) < 0) { perror("ioctl write error"); return -1; } return 0; } int i2c_read(int fd, unsigned char slvAddr, unsigned char *data, unsigned short len) { storage_data.nmsgs = 1; storage_data.msgs[0].len = len; // data length storage_data.msgs[0].addr = slvAddr; // device address storage_data.msgs[0].flags = 1; // read storage_data.msgs[0].buf = data; // data if (ioctl(fd,I2C_RDWR, &storage_data) < 0) { perror("ioctl read error"); return -1; } return 0; } int main(int argc, char **argv) { int fd = 0; unsigned char read_buf[16]; unsigned char write_buf[16]; short adc_I; storage_data.nmsgs = 2; storage_data.msgs = storage_msg; fd = open(I2C_DEV,O_RDWR); if (fd < 0) { printf("Cannot open \'%s\'!\n", I2C_DEV); exit(1); } printf("Opened \'%s\' successfully!\n", I2C_DEV); ioctl(fd, I2C_TIMEOUT, 1); /*set timeout value*/ ioctl(fd, I2C_RETRIES, 2); /*set retry times*/ // Set power-down. write_buf[0] = 0x00; if (i2c_write(fd, I2C_ADDR, write_buf, 1) != 0) goto error; // Set power-on. write_buf[0] = 0x01; if (i2c_write(fd, I2C_ADDR, write_buf, 1) != 0) goto error; // Set measurement time, MT = 0x45 (120 mS). write_buf[0] = 0x42; if (i2c_write(fd, I2C_ADDR, write_buf, 1) != 0) goto error; write_buf[0] = 0x65; if (i2c_write(fd, I2C_ADDR, write_buf, 1) != 0) goto error; // Set continuously H-resolution mode (1 lx). write_buf[0] = 0x10; if (i2c_write(fd, I2C_ADDR, write_buf, 1) != 0) goto error; usleep(200000); // 200 mS // Read illuminance data: (MSB, LSB) if (i2c_read(fd, I2C_ADDR, read_buf, 2) != 0) goto error; adc_I = (read_buf[0]<<8) | read_buf[1]; printf("adc_I = %5d (0x%04x)\n", adc_I, (adc_I & 0xffff)); // MT = 69 (0x45) // lx/count = 1/1.2*69/MT = 0.833333 printf("Illuminance = %5d (lx)\n", (int)(adc_I*0.8333333)); if (fd) { close(fd); } return 0; error: fprintf(stderr, "Failed to access i2c device \'%s\'!\n", I2C_DEV); exit(1); }

Refer to screenshot captured when executable bh1750 was running:

The current illuminance is 743 lx.