How to get data of BH1750 (light sensor) via on I2C interface using i2c-tools

1.6k Views Asked by At

I am trying to use BH170FVI sensor via on I²C interface on Ubuntu-16.04. My board is UpSquared not Raspberry.

To be able to use i2c interface, I installed i2c-tools. I also controlled BMI160 sensor with this tool before without meeting a problem.

When I tried to detect my sensor via on terminal with the command:

i2cdetect -r -y 5

This command detects my sensor correctly as shown below:

enter image description here

As it seems my device adress is 0x23.

After this when I tried to read all the register map data by the command:

i2cdump -y -f 5 0x23

The result is:

enter image description here

The problem is all map adresses are zero. At least one of them should read light amount. I thought the sensor power may off but I tried to use command i2cset for power-on but still nothing change.

Note: My sensor has no problem because I tried it with Arduino and also with below code:

#!/usr/bin/python
import smbus
import time
 
# Define some constants from the datasheet
DEVICE     = 0x23 # Default device I2C address
POWER_DOWN = 0x00 # No active state
POWER_ON   = 0x01 # Power on
RESET      = 0x07 # Reset data register value
ONE_TIME_HIGH_RES_MODE = 0x20
 
bus = smbus.SMBus(1)  # Rev 2 Pi uses 1
 
def convertToNumber(data):
  # Simple function to convert 2 bytes of data
  # into a decimal number
  return ((data[1] + (256 * data[0])) / 1.2)
 
def readLight(addr=DEVICE):
  data = bus.read_i2c_block_data(addr,ONE_TIME_HIGH_RES_MODE)
  return convertToNumber(data)
 
def main():
 
  while True:
    print "Light Level : " + str(readLight()) + " lux"
    time.sleep(0.5)
 
if __name__=="__main__":
   main()

My question is that why I cant control my sensor via on i2c-tools.

2

There are 2 best solutions below

0
On

To my knowledge it is not possible doing that with i2c-tools. The problem is the way you need to read the measurement results from BH1750. See datasheet:

S Adr Rd (A) (Data) A (Data) NA P

You cannot create such a sequence with i2c-tools:

  • either one byte without register address
  • n bytes, but you have to provide a register address

Both will result in I2C command sequences which are not what the chip wants.

It worked for me in C from userspace. See my question here:

Read a word (2 byte) without providing a register address from userspace

1
On

I think @0andriy is right. You need a driver, a library to interface it (more details in the "official" user documentation for libiio), with python bindings in your case and some configuration. In user space you could use mraa/upm, but it's not in your Ubuntu so you would need to build that.

The suggested answer is to use the driver in the kernel, create a small ACPI table that tells the kernel which device to find on address 0x23 on bus 5. And then you use python-libiio or libiio C++ bindings to access the device. Examples of ACPI tables that can be loaded into the kernel (hint: through ConfigFS) are here https://github.com/westeri/meta-acpi/tree/master/recipes-bsp/acpi-tables/samples.

In your case it will be something like:

DefinitionBlock ("bh1750.aml", "SSDT", 5, "", "BH1750", 1)
{
    External (_SB_.PCI0.I2C5, DeviceObj) // Define Correct I2C controller
    Scope (\_SB.PCI0.I2C5)
    {
        Device (ALS0)
        {
            Name (_HID, "PRP0001")
            Name (_DDN, "ROHM BH1750FVI ambient light sensor")
            Name (_CRS, ResourceTemplate () {
                    I2cSerialBus (
                            0x23,                   // I2C Address
                            ControllerInitiated, 
                            400000,                 // Bus Speed
                            AddressingMode7Bit,     
                            "\\_SB.PCI0.I2C5",
                            0x00,
                            ResourceConsumer,,)
            }
            Name (_DSD, Package () {
                ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                Package () {
                    Package () {"compatible", "rohm,bh1750"},
                }
            })
        }
    }
}

...assuming the path to the controller is \\_SB_.PCI0.I2C5 (you may find it in DSDT).

The links @0andriy gave in comments, i.e. adding i2c client devices on x86_64, Building a i2c device controller and spidev Linux driver on Intel Atom board have additional information how to compile and attach the above table to your system.