Enable Bluetooth on BeagleBone Black

Have you bought a Bluetooth adapter for your BeagleBone Black but can’t get it to work? If so, this article is for you.

If you are having trouble getting your computer or other device to pair with the Bluetooth dongle you have attached to your BeagleBone Black, the fix may be as simple as this two step procedure. By default, the Bluetooth drivers are not fully enabled; I will show you how to fix this.

Quick Version

If you don’t care about learning what is going on, just copy and paste this command into your BeagleBone Black. I don’t really recommend doing this in general, if you get into the habit of just copying and pasting code from random websites on the internet, you could easily give someone fairly unrestricted access to your system. But if you can look at the commands below and understand what is going on, go for it.

echo –e “\n[Bluetooth]\nEnable=true” >> /var/lib/connman/settings && \ 
systemctl enable bluetooth.service && \
systemctl start bluetooth.service

If you would like to learn a little bit more about what you are doing and why, continue reading.

Step 1: Enable Bluetooth Capability

The first step in enabling Bluetooth is to inform your BeagleBone Black that you would like to be able to use this feature. To do this you will just need to make a quick edit to a configuration file.

If you perform:

cat /var/lib/connman/settings

You should see something like:

[global]
OfflineMode=false

[Wired]
Enable=true

[WiFi]
Enable=true

What this file is essentially telling you is that the BeagleBone Black connection manager is only aware of Wired Ethernet connections, or WiFi connections enabled through a USB module.

What you want to do is add the Bluetooth module. To add this just type the following command:

echo –e “\n[Bluetooth]\nEnable=true” >> /var/lib/connman/settings

Now if you look at your configuration file again by using

cat /var/lib/connman/settings

You should see something like this:

[global]
OfflineMode=false

[Wired]
Enable=true

[WiFi]
Enable=true

[Bluetooth]
Enable=true

Step 2: Enable the Bluetooth System Service

Your next and final step is to enable and start the system service that monitors Bluetooth. This allows you to pair with the BeagleBone Black, as well as some other core functionality. To enable the service type:

systemctl enable bluetooth.service

You may see a few messages but should not get any errors, if that is the case then this step worked as expected and your BeagleBone Black is almost ready to use Bluetooth. All you need to do now is start this service using the following command.

systemctl start bluetooth.service

Congratulations! You should now have a working Bluetooth dongle.

Cross-Compile and Remote Deploy for BeagleBone Black using Eclipse

This article explains in detail how to cross-compile for BeagleBone Black then easily run your program from within Eclipse.

Note: This article is fairly old at this point, Linux and Eclipse have had a few updates in that time, this article has not. Perhaps the instructions below will be of assistance to you but if not, check the comments.

Since I began developing the SensorCape for BeagleBone Black I have been doing more and more work in the BeagleBone environment. One of the first things I learned is that it is possible to develop and build your applications directly on the BBB, but it is certainly not an efficient use of time.

As your projects grow larger you will find yourself wanting to move away from the command line and be able to use an IDE. Additionally, the processor on the BBB will eventually begin to act as a limit on how quickly you can compile.

To fix this problem, we would like to be able to develop and build our projects on another machine and then easily transfer to the BeagleBone Black. This doesn’t sound so difficult, after-all why can’t we just build on our local machine and then transfer the binary to the BeagleBone Black?

The reason we can’t do this is because your development platform most likely has a different processor architecture than the BeagleBone Black.

Most modern computers use the Intel x86 instruction set, but many embedded systems use an ARM architecture. This essentially means that at the lowest level the two computers don’t speak the same language. To get your processors speaking the same language we need to cross-compile for BeagleBone Black by using a compiler that is targeted at the ARM architecture. So let’s get started!

Install a Virtual Machine on Non-Linux Systems

When I first started writing this article I wanted to be able to cover all operating systems, since it is generally a PITA to install a VM if you don’t have to. Then I realized it was much worse trying to hack together a toolchain for other operating systems. In addition to this, after I started getting deeper into development I realized that it wouldn’t even be practical to develop for the BeagleBone Black on a non-Linux system since it would be so difficult to obtain certain libraries and other useful programs.

EDIT (5/19/2015): If you’d like to give it a shot on a Windows machine without installing a VM try this tutorial.

So to sum it up, I know it’s non-optimal but just trust me, you don’t want to deal with the headache of developing on a different platform than you deploy for. Linux distros are all basically the same under the hood, so if you develop from a Linux platform, it should be able to run on any embedded Linux system.

There are quite a few virtualization options for both Windows and Mac but by far the two most popular are VirtualBox and VMWare Player. These two programs are the leader of the pack for good reasons. First they are free! Second, they both offer all of the features necessary for a casual user to fully emulate whatever environment they need.

For some unknown reason, I have always used VMWare Player on my Windows machines and VirtualBox for my Mac machines. I can’t say I have a particular preference for either one really, my Windows box is much better at virtualization, but that is because it is about 2.5x the computer my MacBook Air is. In the interest of covering all the bases I will show you how to install a Linux VM using VMWare Player on Windows and I will show you how to install a Linux VM using VirtualBox on a Mac.

If you are already running a Linux system then you don’t need to worry about a VM and can skip to the “For Linux” section. However, my instructions are for a Debian based system, so while you will definitely still be able to get this to work on other systems it will be easiest if you too are on a Debian system, that is up to you.

Choosing a Linux Distribution

There are a seemingly endless amount of Linux distributions (distros) which you could choose from. For our purposes you will want to choose a Debian distribution such as Ubuntu or Linux Mint. Ubuntu is easily the most popular distro but I think that they have gone too far in simplifying things and have made it more difficult for developers to use. Linux Mint, on the other hand, is based off of Ubuntu but does not attempt to hide the gritty technical details either.

For these reasons, I will be using Linux Mint during this tutorial but you can easily use Ubuntu without changing anything. You can download these distros from the following locations:

When choosing a download, you do not want any special installers. After your download finishes and you have uncompressed the download you should end up with a .iso or similar disk image file once this has been verified you are ready to move on to installing your virtual machine.

Windows VM Installation Mac VM Installation
On Windows I recommend using VMWare and following this “Getting Started” guide. On macOS I recommend using VirtualBox and following this very well written general guide from Lifehacker on installing a VM using VirtualBox.

For Linux

Install Eclipse, C/C++ Tools, and Remote Tools (Debian)

Open up the Terminal and enter:

sudo apt-get install eclipse eclipse-cdt g++ gcc

This command installs the main Eclipse package, the Eclipse C/C++ development tools (CDT), the GNU C++ Compiler/Linker (G++), and the GNU Compiler Collection (GCC). You most likely already have G++ and GCC installed, and they aren’t even really necessary for this example, but it never hurts to verify.

After this installation finishes you need to open up Eclipse and install the “Remote System Explorer” (RSE) plugin. It is possible that RSE is included in the default Eclipse installation. To check this, go to:

Window -> Open Perspective -> Other… 

and choose “Remote System Explorer” from the Open Perspective dialog to open the RSE perspective. If it is not installed, navigate to:

Help -> Install New Software…

Where the label says “Work with:” click on the down arrow to show a dropdown box. Select the update site for your version of Eclipse. For example my version of Eclipse is Indigo, so I chose the Indigo Update Site.

Selecting the Indigo Update Site

Then move your cursor to the search box below and enter “remote”. After a short wait you will be presented with a list of packages, one of which will be the “Remote System Explorer End-User Runtime” select this box.

You will also want to scroll a bit further down under the “Mobile and Device Development” section and select the “C/C++ Remote Launch” plugin. After you have selected these packages, proceed with the wizard to finish the install. So again, be sure to install:

  • Remote System Explorer End-User Runtime
  • C/C++ Remote Launch
Installing Remote System Explorer

Now that your basic Eclipse environment is set-up, we can move on to installing the BeagleBone Specific functionality.

Install Toolchain for BeagleBone Black

Plug your BeagleBone Black into your computer using the provided Mini-USB cable. If you are developing from a virtual machine make sure that the BeagleBone Black is mounted on your virtual machine and not on your host machine.

After the BeagleBone Black is mounted it should appear on your desktop as a removable drive. Navigate to this drive and double-click on “START.htm”. This will run the install scripts and verify that the BeagleBone Black is operating as expected. After a few seconds you should see the boxes for Step 1 and Step 2 turn green and earn a check-mark. This means that you are ready to move on to installation.

To install the proper toolchain for the BeagleBone Black we will pull the gcc-arm-linux-gnueabi package from the apt repository. This is included in the default Debian repositories so you can simply type…

sudo apt-get install gcc-arm-linux-gnueabi

After a short wait the ARM toolchain should install successfully and you are well on your way to being able to cross-compile for BeagleBone Black. The next step is to set up your Eclipse environment to make this process as automated as possible.

Note (5/11/2015): It looks like some newer versions of Linux have separated the GCC and G++ toolchains and you will likely need both. Install G++ with:

sudo apt-get install g++-arm-linux-gnueabi

Create and Configure a Project to Build Using this Toolchain

This is where the magic happens, once we complete this section you should be able to create your own project that will compile on your local computer and then run on your BeagleBone Black with the push of a single button. Let’s begin with something simple, a classic “Hello, World” application.

Creating a C++ Project

Navigate your cursor to the “Project Explorer” view. This is usually the left side-panel but if it isn’t there then you can go to:

Window -> Show View -> Project Explorer.

With your cursor positioned inside this view, right click and select:

New -> C++ Project.

A window will appear asking you to name your project and choose some project settings. You can name your project whatever you like, I will be naming mine “Test”.

Then select Executable -> Hello World C++ Project. If you have multiple Toolchain options just choose one, it doesn’t matter since we will be changing this later.

At the next screen you will be asked to set up some of the template options, you can leave them as-is or change them to your liking. I will be changing the Hello World message to Hello BeagleBone. After you are done with this screen you can go to the next and skip that one, then select the “Finish” button.

After a moment Eclipse will finish preparing the project and you will be presented with the familiar “Hello World” program. Just to make sure there are no weird errors, go ahead and click the build button in the toolbar (it looks like a hammer). In your console at the bottom you should see a few compiler commands and it should end with a build summary.

If you get errors at this point then there is most likely something wrong with your Eclipse installation, I recommend doing a few Google searches for help, then re-installing Eclipse if you can’t find a solution. If all went well then you can move on to the next step.

Configure the ARM Toolchain

If you took a good look through your last build log you will notice that Eclipse used GCC and G++ to compile your program. This is normally fine, but in our case we want to deploy to an ARM architecture so we need to reconfigure our project to build using the toolchain we downloaded earlier.

To do this you can right click on your project name in the “Project Explorer” and select “Properties” from the menu. This will bring up a new window where you can modify the build settings of your project.

On the left sidebar of the properties window expand the “C/C++ Build” category and select “Settings”. This is where you can change your compilers, linker, and assembler, otherwise known as your toolchain. Make sure your active tab is “Tool Settings”, we will begin by changing your GCC Compiler. For my current set-up I change my compiler to:

arm-linux-gnueabi-gcc-4.7

But this could be different for you, I recommend opening up a terminal window and typing arm-linux then hitting tab a few times to get a list of suggestions. This will show you what options you have available. To avoid messing up, I would just copy and paste from this list. This is what it looks like on my system.

Showing available ARM compilers

You will now go through all four options and change them to their appropriate ARM equivalents. My GCC compiler command looks like this after changing it:

ARM GCC Compiler Command

Now you will need to go ahead and update the commands for the G++ compiler, G++ linker, and the GCC assembler. Since this is fairly repetitive I won’t show each step, but note that (at the time of writing) the assembler is the only command that does not have a 4.7 after it.

After you have updated your toolchain commands press “OK” and you will return to the main Eclipse view. To verify that everything worked as you hoped go ahead and build your project again. If it compiles without errors then congratulations, the hardest part is over and you have a binary that can run on your BeagleBone Black.

This next step is just to make everything a bit easier. When we are done, you will be able to hit the run button and Eclipse will automagically compile your program, transfer it to the BeagleBone Black, and run it on the BeagleBone Black.

Set Up Remote Deployment

Now that we have a project set up and know that it compiles, let’s set it up to run on the BeagleBone Black. You will start by clicking on the down facing arrow next to the run button, as shown below.

When you click on this arrow you will be presented with a dropdown menu, choose the “Run configurations…” option and you will see a new window that looks something like this.

You can see in the left sidebar that there is an option for “C/C++ Remote Application” if you do not see this on your system then you did not install all of the necessary plugins. Specifically, you forgot the C/C++ Remote Launch” plugin, return to the Eclipse marketplace and install this plugin. If you do see this option, then you are ready to move on to setting up your connection.

To create a new run configuration just double-click on the “C/C++ Remote Application” item, after a moment Eclipse will have created a new run configuration and you should see a window that looks something like this.

You now have the skeleton of a remote run configuration but need to inform Eclipse of which device you would like to deploy to. In order to do this you can click on the “New…” button to create a new connection which will present you with the new connection window.

You will first be asked to define the remote system type, for the BeagleBone Black you will choose “Linux” but as you can see there are many other methods of connected to devices.

On the next screen you will tell Eclipse what IP address to connect to as well as what SSH profile to use. Setting up the SSH profile is outside of the scope of this tutorial, but Eclipse should be able to handle that for you.

For my BeagleBone Black (and I believe all of them) connected by USB the IP address is 192.168.7.2. Enter this number in the “Host Name” section. If you BeagleBone Black has a different IP you will want to use that instead.

Finally, you can give the connection an easy to remember name and description, or you can leave these fields blank, that’s up to you. My completed connection information is as follows.

Click the next button and proceed to defining your connection protocols. These next four prompts allow you to define what protocols eclipse should use to communicate with your BeagleBone Black’s subsystem. You will choose the following options:

  1. ssh.files
  2. processes.shell.linux
  3. ssh.shells
  4. ssh.terminals

To verify that your connection settings are correct, go to the Remote System Explorer view and right click on your new connection. In the dropdown menu and select “Connect…” after this you will be prompted for a user name and password.

This should be the user name and password for the account you want to log-in to the BeagleBone Black with. If you haven’t set up any non-default accounts or know that you will need root access you should just log in with the default root account by using the following credentials.

Hit OK and you now have a working connection to the BeagleBone Black through Eclipse, you can even use Eclipse as a remote terminal now, but we won’t get in to that right now.

The next and final step is to configure your remote paths and to give your program execute permissions. If you don’t understand what that means, don’t worry, I am about to walk you through it.

Return to the “Run Configurations” window you need to begin by setting the remote path of your executable. Since you haven’t yet uploaded an executable to the BBB you need to define this as the program name in your root directory. So for example, in my case the program is called “Test” and my root directory is /home/root/ this means that my remote path will be:

/home/root/Test

In general you will define this as:

/home/root/{ProjectName}

Finally, you will need to grant your program execute permissions. This is essentially just a flag that tells the BeagleBone Black that it’s okay to run the file through the processor. You can do this by using the chmod command with the +x flag. For my project it looks like this:

chmod +x /home/root/Test

The final run configuration is:

Apply your configuration using the “Apply” button, then run your project and check your console, you should see an output that looks something like this…

root@beaglebone:~# echo $PWD'>'
/home/root>
root@beaglebone:~# chmod +x /home/root/Test;/home/root/Test;exit
Hello BeagleBone
logout

This shows the commands Eclipse used to run the application and shows a successful “Hello BeagleBone” message.

References

This was a complex article and took quite a bit of research. I came across several other articles that would cover a part of the process but not the whole flow, so I decided to combine all these articles as well as my own personal experiences into a unified place.

Hopefully this article has been useful, but if not feel free to tweet at me or check out these articles I read along the way.

Choosing a PCB Manufacturer

Definitions: A “mil” refers to a thousandth of an inch. While most engineering processes have standardized on the far more understandable metric system, physical products still rely on imperial units. “Clearance” refers to the separation from the edge of one trace to the nearest edge of another.

While one manufacturer may be able to produce 6 mil traces with 6 mil clearances (3/3) another manufacturer may be limited to a (8/8) setup. You do not want to design your board and route all of your traces at a very small width only to find that your manufacturer cannot produce the board at that specification. This could leave you resorting to much more expensive manufacturing options, or receiving a non-working PCB when the manufacturing house attempts to manufacture your design anyways.

If you thought there were a lot of CAD packages to choose from, then you would be truly overwhelmed by the number of different manufacturers and assembly houses there are. Rather than compiling a huge list of all of the PCB manufacturers and assemblers, I am just going to post a short list of those that I either have personal experience with or that have made a strong impression on me.

  • OSH Park (Low cost fabrication, U.S. based company) - If you just need to do a small order of PCBs, don't need assembly, and your design fits within their limitations, I fully recommend OSH Park. The turnaround time isn't stellar, but in the 2 weeks you may end up waiting for a board, you can always start working on other projects.
  • Advanced Circuits (Incredible flexibility and turnaround time, also offer assembly, U.S. based operations) - I have never used their services personally but I have to say I am impressed with what they offer and others seem to be happy with their results. Their prices for short run fabrication are much higher than OSH Park, but their medium run prices (50+ boards) are perfectly reasonable and they offer a wide range of fabrication options. They also offer a "Barebones" option that is excellent for prototyping.
  • Gold Phoenix (Cheap higher quantity orders, non U.S. based) - I have also never used Gold Phoenix but they are apparently often used by SparkFun and offer good prices on larger orders. Their services are based out of China and their boards are not as high of quality as Advanced Circuits, but they are worth a shot for medium run production.
  • ExpressPCB (Software integrated solution, reasonable pricing) - ExpressPCB is the only one on this list that also showed up on the CAD list as well. From what I can tell, their quality seems to be about on par with Gold Phoenix with a similar pricing structure to Advanced Circuits.
  • Seeed Studio (Reasonable pricing, not as many options as Advanced Circuits, but more freedom than OSH Park) - Seeed studio has made a point to focus on hobbyist work and their dedication is clear. You can get a 2-layer 5cm x 5cm board starting at $9.99, and they include free testing which is a great deal.
  • SFCircuits (Not as low budget as others, better suited for large or complex boards, including assembly) – I've also never used their services personally but have heard good things. They offer a couple U.S. made hobbyist specials but it's not their core service. They are a good place to start for larger production runs and more complex layouts.

These are just some of my recommendations, but as I noted earlier, there are many, many more out there. Suggest your own favorites in the comments below.

Understanding I2C

Note: This post originated from Robot Electronics, I have reposted it here with some edits for clarity and as a personal reference.

As I continue to refine this document and it no longer closely resembles the original I will remove this note and replace it with a reference link at the bottom of this post.

If anyone at Robot Electronics takes issue with this then please contact me and I will be happy to remove the article.

I2C is clearly very confusing for the newcomer. I know that I personally avoided I2C devices for my first few projects but now that I have learned the ins-and-outs of I2C I thought I would share these lessons with everyone. This page attempts to de-mystify the I2C bus, lets hope I can do that!

The Physical I2C Bus

This is just two wires, called SCL and SDA. SCL is the clock line. It is used to synchronize all data transfers over the I2C bus. SDA is the data line. The SCL and SDA lines are connected to all devices on the I2C bus. There needs to be a third wire which is just the ground or 0 volts. There may also be a 5 V wire if power is being distributed to the devices.

Both SCL and SDA lines are “open drain” drivers. What this means is that the chip can drive its output low, but it cannot drive it high. For the line to be able to go high you must provide pull-up resistors to the 5 V supply. There should be a resistor from the SCL line to the 5 V line and another from the SDA line to the 5 V line. You only need one set of pull-up resistors for the whole I2C bus, not for each device, as illustrated below:

Using pull-up resistors on the I2C Bus

The value of the resistors is not critical. I have seen anything from 1k8 (1800 ohms) to 47k (47000 ohms) used. 1k8, 4k7 and 10k are common values, but anything in this range should work OK. I recommend 1k8 as this gives you the best performance. If the resistors are missing, the SCL and SDA lines will always be low - nearly 0 V - and the I2C bus will not work.

Masters and Slaves

The devices on the I2C bus are either masters or slaves. The master is always the device that drives the SCL clock line. The slaves are the devices that respond to the master. A slave cannot initiate a transfer over the I2C bus, only a master can do that. There can be, and usually are, multiple slaves on the I2C bus, however there is normally only one master. It is possible to have multiple masters, but it is unusual and not covered here.

On your robot, the master will be your controller and the slaves will be our modules such as the SRF08 or CMPS03. Slaves will never initiate a transfer. Both master and slave can transfer data over the I2C bus, but that transfer is always controlled by the master.

The I2C Physical Protocol

When the master (your controller) wishes to talk to a slave (our CMPS03 for example) it begins by issuing a start sequence on the I2C bus. A start sequence is one of two special sequences defined for the I2C bus, the other being the stop sequence.

The start sequence and stop sequence are special in that these are the only places where the SDA (data line) is allowed to change while the SCL (clock line) is high. When data is being transferred, SDA must remain stable and not change whilst SCL is high. The start and stop sequences mark the beginning and end of a transaction with the slave device.

Data is transferred in sequences of 8 bits. The bits are placed on the SDA line starting with the MSB (Most Significant Bit). The SCL line is then pulsed high, then low.

Remember that the chip cannot really drive the line high, it simply “lets go” of it and the resistor actually pulls it high.

For every 8 bits transferred, the device receiving the data sends back an acknowledge bit, so there are actually 9 SCL clock pulses to transfer each 8 bit byte of data. If the receiving device sends back a low ACK bit, then it has received the data and is ready to accept another byte. If it sends back a high then it is indicating it cannot accept any further data and the master should terminate the transfer by sending a stop sequence.

How Fast is it?

The standard clock speed for I2C up to 100 kHz. Philips defines faster speeds:

  • Fast mode, which is up to 400 kHz
  • High Speed mode which is up to 3.4 MHz

All of our modules are designed to work at up to 100 kHz. We have tested our modules up to 1 MHz but this needs a small delay of a few uS between each byte transferred. In practical robots, we have never had any need to use high SCL speeds. Keep SCL at or below 100 kHz and then forget about it.

I2C Device Addressing

All I2C addresses are either 7 bits or 10 bits. The use of 10 bit addresses is rare and is not covered here. All of our modules and the common chips you will use will have 7 bit addresses. This means that you can have up to 128 devices on the I2C bus, since a 7 bit number can be from 0 to 127.

When sending out the 7 bit address, we still always send 8 bits. The extra bit is used to inform the slave if the master is writing to it or reading from it. If the bit is zero the master is writing to the slave. If the bit is 1 the master is reading from the slave. The 7 bit address is placed in the upper 7 bits of the byte and the Read/Write (R/W) bit is in the LSB (Least Significant Bit).

The placement of the 7 bit address in the upper 7 bits of the byte is a source of confusion for the newcomer. It means that to write to address 21, you must actually send out 42 which is 21 moved over by 1 bit. It is probably easier to think of the I2C bus addresses as 8 bit addresses, with even addresses as write only, and the odd addresses as the read address for the same device. To take our CMPS03 for example, this is at address 0xC0 ($C0). You would uses 0xC0 to write to the CMPS03 and 0xC1 to read from it. So the read/write bit just makes it an odd/even address.

The I2C Software Protocol

The first thing that will happen is that the master will send out a start sequence. This will alert all the slave devices on the bus that a transaction is starting and they should listen in incase it is for them. Next the master will send out the device address. The slave that matches this address will continue with the transaction, any others will ignore the rest of this transaction and wait for the next.

Having addressed the slave device the master must now send out the internal location or register number inside the slave that it wishes to write to or read from. This number is obviously dependant on what the slave actually is and how many internal registers it has. Some very simple devices do not have any, but most do, including all of our modules.

Our CMPS03 has 16 locations numbered 0-15. The SRF08 has 36. Having sent the I2C address and the internal register address the master can now send the data byte (or bytes, it doesn’t have to be just one). The master can continue to send data bytes to the slave and these will normally be placed in the following registers because the slave will automatically increment the internal register address after each byte. When the master has finished writing all data to the slave, it sends a stop sequence which completes the transaction. So to write to a slave device:

  • Send a start sequence
  • Send the I2C address of the slave with the R/W bit low (even address)
  • Send the internal register number you want to write to
  • Send the data byte
  • [Optionally, send any further data bytes]
  • Send the stop sequence.

As an example, you have an SRF08 at the factory default address of 0xE0. To start the SRF08 ranging you would write 0x51 to the command register at 0x00 like this:

  • Send a start sequence
  • Send 0xE0 ( I2C address of the SRF08 with the R/W bit low (even address)
  • Send 0x00 (Internal address of the command register)
  • Send 0x51 (The command to start the SRF08 ranging)
  • Send the stop sequence.

Reading from the Slave

This is a little more complicated - but not too much more. Before reading data from the slave device, you must tell it which of its internal addresses you want to read. So a read of the slave actually starts off by writing to it. This is the same as when you want to write to it:

You send the start sequence, the I2C address of the slave with the R/W bit low (even address) and the internal register number you want to write to. Now you send another start sequence (sometimes called a restart) and the I2C address again - this time with the read bit set. You then read as many data bytes as you wish and terminate the transaction with a stop sequence. So to read the compass bearing as a byte from the CMPS03 module:

  • Send a start sequence
  • Send 0xC0 ( I2C address of the CMPS03 with the R/W bit low (even address)
  • Send 0x01 (Internal address of the bearing register)
  • Send a start sequence again (repeated start)
  • Send 0xC1 ( I2C address of the CMPS03 with the R/W bit high (odd address)
  • Read data byte from CMPS03
  • Send the stop sequence.

The bit sequence will look like this:

Wait a Moment

That’s almost it for simple I2C communications, but there is one more complication. When the master is reading from the slave, its the slave that places the data on the SDA line, but its the master that controls the clock. What if the slave is not ready to send the data!

With devices such as EEPROMs this is not a problem, but when the slave device is actually a microprocessor with other things to do, it can be a problem. The microprocessor on the slave device will need to go to an interrupt routine, save its working registers, find out what address the master wants to read from, get the data and place it in its transmission register. This can take many uS to happen, meanwhile the master is blissfully sending out clock pulses on the SCL line that the slave cannot respond to.

The I2C protocol provides a solution to this:

The slave is allowed to hold the SCL line low! This is called clock stretching.

When the slave gets the read command from the master it holds the clock line low. The microprocessor then gets the requested data, places it in the transmission register and releases the clock line allowing the pull-up resistor to finally pull it high.

From the master’s point of view, it will issue the first clock pulse of the read by making SCL high and then check to see if it really has gone high. If its still low then its the slave that holding it low and the master should wait until it goes high before continuing. Luckily the hardware I2C ports on most microprocessors will handle this automatically.

Sometimes however, the master I2C is just a collection of subroutines and there are a few implementations out there that completely ignore clock stretching. They work with things like EEPROM’s but not with microprocessor slaves that use clock stretching. The result is that erroneous data is read from the slave. Beware!

Example Master Code using the PIC Processor

This example shows how to implement a software I2C master, including clock stretching. It is written in C for the PIC processor, but should be applicable to most processors with minor changes to the I/O pin definitions.

It is suitable for controlling all of our I2C based robot modules. Since the SCL and SDA lines are open drain type, we use the tristate control register to control the output, keeping the output register low. The port pins still need to be read though, so they’re defined as SCL_IN and SDA_IN. This definition and the initialization is probably all you’ll need to change for a different processor.

#define SCL     TRISB4  // I2C bus 
#define SDA     TRISB1  // 
#define SCL_IN  RB4     //
#define SDA_IN  RB1     //

To initialize the ports, set the output resistors to 0 and the tristate registers to 1 which disables the outputs and allows them to be pulled high by the resistors.

SDA = SCL = 1;
SCL_IN = SDA_IN = 0;

We use a small delay routine between SDA and SCL changes to give a clear sequence on the I2C bus. This is nothing more than a subroutine call and return.

void i2c_dly(void) {}

The following 4 functions provide the primitive start, stop, read and write sequences. All I2C transactions can be built up from these.

void i2c_start(void)
{
    SDA = 1; //I2C start bit sequence
    i2c_dly();
    SCL = 1;
    i2c_dly();
    SDA = 0;
    i2c_dly();
    SCL = 0;
    i2c_dly();
}
void i2c_stop(void)
{ 
    SDA = 0; // I2C stop bit sequence 
    i2c_dly(); 
    SCL = 1; 
    i2c_dly(); 
    SDA = 1; 
    i2c_dly();
}
unsigned char i2c_rx(char ack)
{
    char x, d = 0;
    SDA = 1;  

    for (x = 0; x < 8; x++)
    { 
        d <<= 1;

        // wait for any SCL clock stretching 
        do { SCL = 1; }
        while (SCL_IN == 0);
            i2c_dly();

        if (SDA_IN) d |= 1; 
        SCL = 0; 
    }

    if (ack) SDA = 0; 
    else SDA = 1;
    SCL = 1;

    // send (N)ACK bit 
    i2c_dly();
    SCL = 0;
    SDA = 1;

    return d; 
}
bit i2c_tx(unsigned char d)
{ 
    char x; 
    static bit b;

    for (x = 8; x; x--)
    { 
        if(d & 0x80) SDA = 1; 
        else SDA = 0;

        SCL = 1; 
        d <<= 1;
        SCL = 0;
    }

    SDA = 1; 
    SCL = 1; 
    i2c_dly(); 
    b = SDA_IN; // possible ACK bit SCL = 0;

    return b; 
}

The 4 primitive functions above can easily be put together to form complete I2C transactions. Here’s an example to start an SRF08 ranging in cm:

i2c_start();  // send start sequence 
i2c_tx(0xE0); // SRF08 I2C address with R/W bit clear
i2c_tx(0x00); // SRF08 command register address
i2c_tx(0x51); // command to start ranging in cm
i2c_stop();   // send stop sequence

Now after waiting 65mS for the ranging to complete (I’ve left that to you) the following example shows how to read the light sensor value from register 1 and the range result from registers 2 and 3.

i2c_start();  // send start sequence 
i2c_tx(0xE0); // SRF08 I2C address with R/W bit clear
i2c_tx(0x01); // SRF08 light sensor register address
i2c_start();  // send a restart sequence 
i2c_tx(0xE1); // SRF08 I2C address with R/W bit set

// get light sensor and send acknowledge
// internal register address will increment automatically
lightsensor = i2c_rx(1);

// get the high byte of the range and send acknowledge. 
rangehigh = i2c_rx(1);

// get low byte of the range 
// note we don't acknowledge the last byte
rangelow = i2c_rx(0);

i2c_stop(); // send stop sequence

External References

The definitive specs on the I2C bus can be found on the NXP website. It is currently here but if it has moved you’ll find it easily by searching for “I2C bus specification”. I also found these references useful when compiling this tutorial so if I missed something here, perhaps you will find what you need at one of these links.