[milkv] 1. Light sensor bh1750 driver addition and testing


This chapter introduces adding the light sensor bh1750 to the milkv-duo development board and implementing application layer testing.

1. View circuit diagram

1.1 duo development board i2c pins


These are the pins that can be used as i2c

Note: gpio0 and 1 in the circuit diagram correspond to gpio28 and 29 on the chip, and they are also 28 and 29 when viewed in dtsi.

Search gpio0 and 1 in the circuit diagram to find the corresponding circuit.

As shown in the figure, the default functions of gpio0 and 1 of the small board are IIC_SCL and IIC_SDA.

What comes out of the leftmost border is the reusable function of this pin. Specifically, you need to open the corresponding node in dtsi.

1.2 Light sensor bh1750 pins

What I bought is Hezhou’s bh1750. It has been taken off the shelves. You can find something already on the market.

From left to right they are addr | sda | scl | gnd | vcc

Light sensor and duo board connection circuit

bh1750 | duo
vcc | 3.3v(out)
gnd | gnd
scl | gpio0(gpio28)
sda | gpio1(gpio29)
addr | gnd

2. dtsi added

Dts basics: https://blog.csdn.net/qq_53144843/article/details/123829747

dts file path: build\boards\cv180x\cv1800b_milkv_duo_sd\dts_riscv\cv1800b_milkv_duo_sd.dts

Add the following content to dts

 &i2c0 {
    status = "okay";
clock-frequency = <100000>;
    bh1750:bh1750@23 {
        compatible = "rohm,bh1750";
        reg = #;
        status = "okay";

Among them, 23 is the i2c address of the addr grounding of bh1750. For details, please refer to the documentation of the driver and sensor.

After adding it to Dtsi, compile img and flash the machine to check whether it is added under devicetree.

# cd /sys/firmware/devicetree/base/i2c@04000000/bh1750@23
# cat name


i2c0: i2c@04000000 {
compatible = "snps,designware-i2c";
clocks = < & amp;clk CV180X_CLK_I2C>;
reg = <0x0 0x04000000 0x0 0x1000>;
clock-frequency = <400000>;

#size-cells = <0x0>;
#address-cells = <0x1>;
resets = < & amp;rst RST_I2C0>;
reset-names = "i2c0";

The 4000000 here is the address of the i2c0 controller, and the corresponding device tree path is /sys/firmware/devicetree/base/i2c@04000000

3. bh1750 driver

Note that it needs to match the dtsi

ko basics: https://blog.csdn.net/li_man_man_man/article/details/126534271

There are two ways to add a driver, and I used the second one.

3.1 Write the driver and finally generate the ko file

Reference: https://blog.csdn.net/ZOROE123/article/details/117442036

Advantages: Can be added and uninstalled manually

Disadvantages: You need to implement the driver yourself. You can refer to the relevant code retrieved by “sensor name + linux” on git and csdn.

3.2 Open config and compile the existing driver into img (config=y)

Advantages: No need to implement the driver yourself

Disadvantages: It is suitable for SDKs that already have drivers and cannot be dynamically uninstalled.

bh1750 driver path:

The specific content analysis is put into the application layer introduction.

View the driver’s Config configuration process

obj-$(CONFIG_IIO) + = iio/

obj-y + = light/

obj-$(CONFIG_BH1750) + = bh1750.o

Configure config file



Add the following content


Check the compilation log

CC drivers/iio/light/bh1750.o

Indicates that the driver compilation of bh1750 has been completed.

After completion, flash to the tf card and boot.

Search bh1750 and find driver and device tree information

3.3 i2c0 error

Check if i2c is loaded

i2cdetect -y -r 0

Found that no i2c address is displayed

Report an error

[ 1.943778] i2c_designware 4000000.i2c: controller timed out
[ 1.949738] bh1750: probe of 0-0023 failed with error -110

Prompt i2c0 controller time out.

3.4 Solution

Method 1: Change the default pin configuration through the driver in uboot

View io default status


Original configuration


The default configuration will cause i2c0 to fail to load successfully and an error will be reported indicating that i2c has timed out.

Change to the following content, put it at the end.


Reason for change: In the reference circuit diagram, the pin name is IIC0_SDA, which can be reused as these pins on the left.

For example, if reuse is uart2, set


Method 2: Use tools provided by official technical support


4. Driver analysis

Basic knowledge points

Introduction to iio: https://blog.csdn.net/m0_74282605/article/details/128098034

bh1750 driver: https://blog.csdn.net/ZOROE123/article/details/117442036

misc introduction: https://blog.csdn.net/rj_ys/article/details/112791330

iio driver: https://blog.csdn.net/weixin_68294039/article/details/124931816

bh driver path:


The probe function defines the mode of the iio device as DIRECT, which means generating sysfs. We can obtain bh1750 data through the sysfs interface.

iio channel

where raw is the light sensing data we need


iio generates sysfs interface:

The application calls the sysfs interface of iio:

File interface:

Test the sysfs interface added by the driver

cat /sys/devices/platform/4000000.i2c/i2c-0/0-0023/iio:device0\in_illuminance_raw

Test Results:

Occlusion raw is 2

Unoccluded raw is 182

5. Application layer

5.1 Code



#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/ioctl.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include <poll.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>

static int file_data_read(char *filename, char *str)
    int ret = 0;
    FILE *data_stream;

    data_stream = fopen(filename, "r"); /* open for reading only */
    if(data_stream == NULL) {
        printf("can't open file %s\r\\
", filename);
        return -1;

    ret = fscanf(data_stream, "%s", str);
    if(!ret) {
        printf("file read error!\r\\
    } else if(ret == EOF) {
        /* Read the end of the file and readjust the file pointer to the beginning of the file */
        fseek(data_stream, 0, SEEK_SET);
    fclose(data_stream); /* Close the file */
    return 0;

int main(int argc, char *argv[])
    int fd;
    int light_value;
    int test_time = 50;

    char str[50];
    int ret = 0;
    // char* filename = "/dev/iio:device0";
    // sysfs interface generated by iio
    char* filename = "/sys/devices/platform/4000000.i2c/i2c-0/0-0023/iio:device0/in_illuminance_raw";

        file_data_read(filename, str);
        light_value = atof(str);
        printf("test_time %d :%d\r\\

    return 0;

5.2 Compilation

Compile the complete img first, because the dts has been changed.

Use balenaEtcher to flash the tf card, insert it into the board, and power on.

Compile application code and generate executable file

Compilation and transmission

riscv64-unknown-linux-musl-gcc -static -o test_bh1750 test_bh1750.c
scp test_bh1750 [email protected]:~/

Enter password: milkv

5.3 Run executable file

Log into device

ssh [email protected]

executable file


Test Results

6. Summary

This chapter starts with the circuit diagram and introduces the pin information, dts configuration, driver addition process, simple driver analysis, sysfs interface test, and test files that implement light sensing.

The main problem encountered during the trial process was that i2c0 could not be used. Later, it was discovered that the default function of the pin needs to be configured.

When developing the application layer, although the sysfs interface can be read through the cat command, the code implementation still needs to refer to some tutorials and implement it through interfaces such as fopen.

You can use this as an example to add other sensors later.