2014. szeptember 1., hétfő

BeagleBone Black and the BH1750 Light Sensor

In this post I'll show you how to attach a BH1750 light sensor via I2C to your favorite BeagleBone Black running Debian. I've purchased this nice little breakout board from eBay for almost nothing.
This is how it looks like.

The pinout of the board is pretty straightforward, it has two pins for power, two pins for the I2C bus (SDA, SCL), and address pin for bus address selection. 


Wiring:
This is a fairly easy part, you don't have many wires to connect. I've used a breadboard, and some jumper cables, to do it. First, you have to connect the VCC (3.3V!!) and GND to their respective pin headers on the BeagleBone. 

Be careful to plug them in the right holes ;)

Next on, you have to connect the I2C Data, and Clock pins to the spots shown on the diagram. The ADDR pin can be left unconnected, so our address will be 0x23.

Mounted on a breadboard, ready to use


Communicating with the device:

After wiring it up, we can start communicating with the sensor. I will not go into the basics and the fundamentals of the I2C communication, I assume you have a basic knowledge of it: ) (or if not, Derek Molloy has a great tutorial on it: http://derekmolloy.ie/beaglebone/beaglebone-an-i2c-tutorial-interfacing-to-a-bma180-accelerometer/

After SSH-ing into your board, you will have to grab the i2c-tools, if not installed.

sudo apt-get install i2c-tools
After you have it, this package provides us with some nice tools for using the I2C bus.  So, now that we have everything, we'll see, if the device is present on the bus. For this, type the following:

sudo i2cdetect -r 1
After pressing enter it prompts you with a warning, but just say yes.


So, what did we do now? The i2cdetect polls every address on the bus in the argument, and detects if there are devices present and reachable. And as you can see, at 0x23 - we have a device, which is our BH1750 sensor. That was easy :)

So, now we can communicate with the device, knowing its's address. Next up, we'd like to read something out of it, so lets i2cdump it!

sudo i2cdump -y 1 0x23
This command reads every register of the specified I2C device on bus one, so we can see what's inside the sensor.

Oh, that's all zeroes. That's not what we would expect, there's something that should be in the device's memory. If we try to write to the device with i2cset, it always fails.

After tinkering days with it, and assuming that I'm stupid, or my sensor is faulty, I've read the datasheet, and concluded, that IT'S NOT A STANDARD I2C DEVICE. The tools in the i2c-tools package assumes that the device is a standard I2C device, therefore we will fail in reading, or writing it. i2cdetect is good for discovering it on the bus, but we have to use different tools to get the sensor working. 
So why is it not standard? When communicating with normal I2C devices, we need an address when reading, and an address plus a data when writing. This device only uses "opecodes" defined in the datasheet when writing it. No data part, just 8 bit opcodes.

Code:

After a heavy Googling, I found a way to make it work. SMBus. It's a bus similar to I2C, and with the python libraries of SMBus, we can write single bytes to the bus, and read back without hitting an error. So, let's do it! To use SMBus in Python, you need to install the SMBus libraries, as well as python itself, if you dont't have it.

sudo apt-get install python-smbus
Now we have the libs, so let's see the code! I've found a few templates around the 17th page of Google,  and I wrote this little code for reading the BH1750. Fire up you favorite command line text editor  - nano, and copy this code:

#!/usr/bin/python

import time
import smbus
import decimal
bus = smbus.SMBus(1)
addr = 0x23
data = bus.read_i2c_block_data(addr,0x11)
lux2 = str((data[1] + (256 * data[0])) / 1.2)
lux = decimal.Decimal(lux2).quantize(decimal.Decimal('.01'), rounding=decimal.ROUND_UP)
outlux = str(lux)
print outlux
This little piece of code addresses the device with a read command at 0x11, which actually clocks in the opcode for a high resolution read. After it's done, we get the light intensity, round it up, and print it out.
Save it as light.py, and execute it!

Isn't it beautiful? :)

Hell yes! Our sensor is working, we can read the light intensity! You can experiment with it, put some light source near it, and you can see the number going up :)

I hope, I could help in getting it working! If you have any questions, I'm happy to answer them in the comments!

(in the future I'm planning on writing a C code for the sensor, which I will publish here)

A short intro

So, hey!

A few weeks ago I've decided, that I'll start blogging about my BeagleBone Black, and Linux hacking experiences and stuff. Back in January I've purchased the BeagleBone Black SBC, and started getting accommodated to the hardware as well as the Linux environment. Previously I've had experience with Linux on a PC, and microcontrollers, but it seemed like quite a challenge, and the next step in my software/hardware skill development. My main aim with the BeagleBone is to make an advanced home automation system, which can do the following:
 - Temperature monitoring
 - Light measurement
 - Lighting automation
 - Media player remote control
 - Accessible from mobile app, or web

So far I have most of the features implemented and working, but I will cover all the parts in tutorials, as most of them are not available (or hard to find) on the internet. My BeagleBone is running the Debian distro from a 4GB SD card, with peripherals on an unpowered USB hub. The board is powered by a 7.2A (a bit of an overkill) MeanWell PSU.
So, that's all for now, have a good night, and be prepared for upcoming post!