There are many peripherals that can be added to a microprocessor over the I2C and SPI serial interfaces. These include atmospheric sensors, EEPROMS, and several types of display.
The Pi Wedge helps access the I2C and SPI signals.
This tutorial will walk you through getting the I2C and SPI interfaces of your Raspberry Pi working. These interfaces aren’t enabled by default, and need some extra configuration before you can use them.
Recommended Reading
Before we get started, you might want to review some related background material.
Background & Software Setup
The Raspberry Pi has three types of serial interface on the GPIO header. You’re probably already familiar with the UART serial port, which allows you to open a login session from a serial terminal application, such as PuTTY.
The other two serial interfaces are the Serial Peripheral Interface (SPI) and Inter-Integrated-Circuit bus (I2C). SPI on the Pi allows for up to two attached devices, while I2C potentially allows for many devices, as long as their addresses don’t conflict.
Software Details
The software landscape for the Raspberry Pi has evolved considerably since the introduction of the Pi. Many different operating systems have been ported to the Pi, and the device driver infrastructure has also changed quite a bit.
For this tutorial, we’ll be using a recent version of Raspbian (installed via NOOBS), and the wiringPi I/O library.
With the implementation of device tree overlays in Raspbian, some of the specific interface enablement details have changed. If you’re working with an older install, it might be worth backing up your SD card, and starting with a fresh install.
OS and Library Install
If you’re starting from scratch, with a blank SD card, you’ll want to install Raspbian. If you’ve already got a working Raspbian system, skip ahead to step 3.
- Download the NOOBS image. As of this writing, it’s at version 1.4.2.
- Follow the official installation instructions.
- Follow the Wiring Pi Instructions to get git, update and upgrade your Rasbpian packages, then install WwiringPi.
Be patient – each of these steps takes a while.
Once you’ve got wiringPi installed, run the gpio
commands shown below.
>gpio -v
>gpio readall
It should respond with some information about the wiringPi version and the Pi that its running on, then draw a table illustrating the configuration for the pins in the 40-pin connector.
The I2C and SPI interfaces each require some additional configuration and initialization, which we’ll cover in later sections.
Connecting To The Ports
Before we get into the configuration and software examples, lets locate the pins used by each of these interfaces.
If you’re directly connecting to the pins on the Pi, they’re a little disorganized. I2C.1 is near one end, while SPI and I2C.0 are in the middle of the header. If you’re connecting to these pins, be sure to count carefully.
Pi Serial Bus Pins
The Pi Wedge adapter PCB rearranges the pins, and labels them clearly. We’ll be using the Wedge for the following examples.
Wedge Serial Bus Pins
SPI on Pi
Configuration
The SPI peripheral is not turned on by default. To enable it, do the following.
- Run
sudo raspi-config
. - Use the down arrow to select
9 Advanced Options
- Arrow down to
A6 SPI
. - Select
yes
when it asks you to enable SPI, - Also select
yes
when it asks about automatically loading the kernel module. - Use the right arrow to select the
<Finish>
button. - Select
yes
when it asks to reboot.
Raspi-config for SPI
The system will reboot. When it comes back up, log in and enter the following command
>ls /dev/*spi*
The Pi should respond with
/dev/spidev0.0 /dev/spidev0.1
These represent SPI devices on chip enable pins 0 and 1, respectively. These pins are hardwired within the Pi. Ordinarily, this means the interface supports at most two peripherals, but there are cases where multiple devices can be daisy-chained, sharing a single chip enable signal.
Programming Example
Required Materials
- The 40-pin Pi Wedge.
- A Raspberry Pi B+ or Pi 2 Model B single board computer.
- A SolderlessBreadboard.
- Some jumper wires.
- A Serial 7-Segment display.
The Serial 7-Segment display is particularly useful for testing serial interfaces, because it can accept command from a UART, SPI, or I2C.
Connections
The display was connected to the Pi, via the Pi Wedge, as follows.
Rabpberry Pi Signal | Serial 7-seg Signal |
GND | GND |
3.3V | VCC |
CE1 | SS (Shift Select) |
SCK | SCK |
MOSI | SDI |
MISO | SDO |
The test hardware looked like this.
Serial 7-Segment connections for SPI
/****************************************************************************** i2ctest.cpp Raspberry Pi I2C interface demo Byron Jacquot @ SparkFun Electronics> 4/2/2014 http://bit.ly/1r9FY7L A brief demonstration of the Raspberry Pi I2C interface, using the SparkFun Pi Wedge breakout board. Resources: This example makes use of the Wiring Pi library, which streamlines the interface to the the I/O pins on the Raspberry Pi, providing an API that is similar to the Arduino. You can learn about installing Wiring Pi here: http://bit.ly/1r9FWNg The wiringPi SPI API is documented here: http://bit.ly/24g3J02 The init call returns a standard file descriptor. More detailed configuration of the interface can be performed using ioctl calls on that descriptor. See the wiringPi SPI implementation (wiringPi/wiringPiSPI.c) for some examples. Parameters configurable with ioctl are documented here: http://bit.ly/1r9FY7O Hardware connections: This file interfaces with the SparkFun Serial 7 Segment display: http://bit.ly/24g3J04 The board was connected as follows: (Raspberry Pi)(Serial 7 Segment) GND -> GND 3.3V -> Vcc CE1 -> SS (Shift Select) SCK -> SCK MOSI -> SDI MISO -> SDO To build this file, I use the command: > g++ spitest.cpp -lwiringPi Then to run it, first the spi kernel module needs to be loaded. This can be done using the GPIO utility. > gpio load spi > ./a.out This test uses the single-segment mode of the 7 segment display. It shifts a bit through the display characters, lighting a single character of each at a time. Development environment specifics: Tested on Raspberry Pi V2 hardware, running Raspbian. Building with GCC 4.6.3 (Debian 4.6.3-14+rpi1) This code is beerware; if you see me (or any other SparkFun employee) at the local, and you've found our code helpful, please buy us a round! Distributed as-is; no warranty is given. ******************************************************************************/ #include <iostream> #include <errno.h> #include <wiringPiSPI.h> #include <unistd.h> using namespace std; // channel is the wiringPi name for the chip select (or chip enable) pin. // Set this to 0 or 1, depending on how it's connected. static const int CHANNEL = 1; int main() { int fd, result; unsigned char buffer[100]; cout << "Initializing" << endl ; // Configure the interface. // CHANNEL insicates chip select, // 500000 indicates bus speed. fd = wiringPiSPISetup(CHANNEL, 500000); cout << "Init result: " << fd << endl; // clear display buffer[0] = 0x76; wiringPiSPIDataRW(CHANNEL, buffer, 1); sleep(5); // Do a one-hot bit selection for each field of the display // It displays gibberish, but tells us that we're correctly addressing all // of the segments. for(int i = 1; i <= 0x7f; i <<= 1) { // the decimals, colon and apostrophe dots buffer[0] = 0x77; buffer[1] = i; result = wiringPiSPIDataRW(CHANNEL, buffer, 2); // The first character buffer[0] = 0x7b; buffer[1] = i; result = wiringPiSPIDataRW(CHANNEL, buffer, 2); // The second character buffer[0] = 0x7c; buffer[1] = i; result = wiringPiSPIDataRW(CHANNEL, buffer, 2); // The third character buffer[0] = 0x7d; buffer[1] = i; result = wiringPiSPIDataRW(CHANNEL, buffer, 2); // The last character buffer[0] = 0x7e; buffer[1] = i; result = wiringPiSPIDataRW(CHANNEL, buffer, 2); // Pause so we can see them sleep(5); } // clear display again buffer[0] = 0x76; wiringPiSPIDataRW(CHANNEL, buffer, 1); }
When you built wiringPi, you might have noticed the statement about how to compile applications against it.
NOTE: To compile programs with wiringPi, you need to add: -lwiringPi to your compile line(s) To use the Gertboard, MaxDetect, etc. code (the devLib), you need to also add: -lwiringPiDev to your compile line(s).
Thus, we compile using the command.
>g++ spitest.cpp -lwiringPi -o spitest
Which generates an executable spitest
. When we run ./spitest
, it will exercise each of the segments of the display. It illuminates a segment in each digit for 5 seconds, before moving to the next segment. It takes about 40 seconds overall.
I2C on Pi
Configuration
Like the SPI peripheral, I2C is not turned on by default. Again, we can use raspi-config
to enable it.
- Run
sudo raspi-config
. - Use the down arrow to select
9 Advanced Options
- Arrow down to
A7 I2C
. - Select
yes
when it asks you to enable I2C - Also select
yes
when it tasks about automatically loading the kernel module. - Use the right arrow to select the
<Finish>
button. - Select
yes
when it asks to reboot.
Raspi-config for I2C
The system will reboot. when it comes back up, log in and enter the following command
>ls /dev/*i2c*
The Pi should respond with
/dev/i2c-1
Which represents the user-mode I2C interface.
Utilities
There is a set of command-line utility programs that can help get an I2C interface working. You can get them with the apt package manager.
sudo apt-get install -y i2c-tools
In particular, the i2cdetect
program will probe all the addresses on a bus, and report whether any devices are present.
pi@raspberrypi:~/$ i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: 60 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
This map indicates that there is a preipheral at address 0x60. We can try to read and write its registers using the i2cget
, i2cset
and i2cdump
commands.
Programming Example
Required Materials
- The 40-pin Pi Wedge.
- A Raspberry Pi B+ or Pi 2 Model B single board computer.
- A Solderless Breadboard.
- Some jumper wires.
- An MCP4725 digital-to-analog converter.
Connections
The display was connected to the Pi, via the Pi Wedge, as follows.
Rabpberry Pi Signal | MCP4725 |
GND | GND |
3.3V | VCC |
SCL | SCL |
SDA | SDA |
The test hardware looked like this.
ADC on a Breadboard
Example Program
The following code writes successive values to the DAC, producing an sawtooth wave at its output pin.
/******************************************************************************
i2ctest.cpp
Raspberry Pi I2C interface demo
Byron Jacquot @ SparkFun Electronics>
4/2/2014
http://bit.ly/1r9FY7L
A brief demonstration of the Raspberry Pi I2C interface, using the SparkFun
Pi Wedge breakout board.
Resources:
This example makes use of the Wiring Pi library, which streamlines the interface
the the I/O pins on the Raspberry Pi, providing an API that is similar to the
Arduino. You can learn about installing Wiring Pi here:
http://bit.ly/1r9FWNg
The I2C API is documented here:
http://bit.ly/24g3J06
The init call returns a standard file descriptor. More detailed configuration
of the interface can be performed using ioctl calls on that descriptor.
See the wiringPi I2C implementation (wiringPi/wiringPiI2C.c) for some examples.
Parameters configurable with ioctl are documented here:
http://bit.ly/1r9FX3P
Hardware connections:
This file interfaces with the SparkFun MCP4725 breakout board:
http://bit.ly/24g3Jgl
The board was connected as follows:
(Raspberry Pi)(MCP4725)
GND -> GND
3.3V -> Vcc
SCL -> SCL
SDA -> SDA
An oscilloscope probe was connected to the analog output pin of the MCP4725.
To build this file, I use the command:
> g++ i2ctest.cpp -lwiringPi
Then to run it, first the I2C kernel module needs to be loaded. This can be
done using the GPIO utility.
> gpio load i2c 400
> ./a.out
This will run the MCP through its output range several times. A rising
sawtooth will be seen on the analog output.
Development environment specifics:
Tested on Raspberry Pi V2 hardware, running Raspbian.
Building with GCC 4.6.3 (Debian 4.6.3-14+rpi1)
This code is beerware; if you see me (or any other SparkFun employee) at the
local, and you've found our code helpful, please buy us a round!
Distributed as-is; no warranty is given.
******************************************************************************/
#include <iostream>
#include <errno.h>
#include <wiringPiI2C.h>
using namespace std;
int main()
{
int fd, result;
// Initialize the interface by giving it an external device ID.
// The MCP4725 defaults to address 0x60.
//
// It returns a standard file descriptor.
//
fd = wiringPiI2CSetup(0x60);
cout << "Init result: "<< fd << endl;
for(int i = 0; i < 0x0000ffff; i++)
{
// I tried using the "fast write" command, but couldn't get it to work.
// It's not entirely obvious what's happening behind the scenes as
// regards to endianness or length of data sent. I think it's only
// sending one byte, when we really need two.
//
// So instead I'm doing a 16 bit register access. It appears to
// properly handle the endianness, and the length is specified by the
// call. The only question was the register address, which is the
// concatenation of the command (010x = write DAC output)
// and power down (x00x = power up) bits.
result = wiringPiI2CWriteReg16(fd, 0x40, (i & 0xfff) );
if(result == -1)
{
cout << "Error. Errno is: " << errno << endl;
}
}
}
Build it and link it to wiringPi using the following command.
g++ i2ctest.cpp -lwiringPi -o i2ctest
When you run i2ctest
, the DAC will produce an analog sawtooth wave for a few seconds.
Waveform as measured at the OUT
pin
I2C-0 on 40-pin Pi Boards
An Extra I2C bus?
As part of the B+ improvemets, the Raspberry Pi Foundation has standardized the interface to add-on boards, in what they call the “Hardware Added On Top” (HAT) specification. It standardizes the physical form factor for add-on boards, and includes a provision for the B+ to automatically identify and initialize HATs at startup. It uses an I2C bus to read a description from an EEPROM on the HAT, similar to cape identification on the Beagle Bone Black.
This capability has been carried forward on the A+ and Pi 2 Model B as well. This I2C bus is found on the ID_SC and ID_SD pins (pins 27 and 28 of the 40-pin connector) – but before you get too excited about adding peripherals on that bus, observe the note in the schematic for that port.
Schematic snippet for 40-Pin GPIO connector (J8).
This is further clarified in the HAT design guide
On a Model B+, GPIO0 (ID_SD) and GPIO1 (ID_SC) will be switched to ALT0 (I2C-0) mode and probed for an EEPROM. These pins will revert to inputs once the probe sequence has completed.
The only allowed connections to the ID_ pins are an ID EEPROM plus 3.9K pull up resistors. Do not connect anything else to these pins!
It’s only there to talk to EEPROMs at addresses 0x50 during boot time. User access at runtime is problematic. If you want a general purpose I2C bus on the B+, you’ll need to use I2C-1, on pins 3 and 5 of the 40-pin connector, marked SDA and SCL on the Pi Wedge.
Enabling I2C-0
I2C-0 is disabled by default. To enable it, you’ll need to manually edit the configuration file.
Edit /boot/config.txt, and add the following line. If you previously used raspi-config
to enable I2C-1 and SPI, you’ll see similar entries near the bottom of the vile.
dtparam=i2c_vc=on
With that enabled, restart your Pi (sudo reboot
). When it’s back up, you’ll know it’s been activated is you’ve got a filesystem node at /dev/i2c-0
.
EEPROM Diagnostic Tools
Alongside the HAT design guide, there is a directory with some software tools for working with HAT EEPROMs. To use them, download them then make
them from the command line.
We’ll explore how they’re used below.
Testing I2C-0
With the information above, we grabbed a 24LC256 EEPROM chip, and wired it to our Pi. We strapped all of the address pins to ground, which puts it at address 0x50, which we were able to confirm with i2cdetect
.
EEPROM on breadboard
Pull the EEPROM utilities mentioned above. The file test_settings.txt
is a human-readable example of an EEPROM file. For testing purposes, we edited this file, changing the vendor and product fields to relevant information.
The text file itself needs to be processed into a binary format before it can be written to the EEPROM. The eepmake
utility handles this conversion.
./eepmake test_settings.txt test.eep
With the binary test.eep
in hand, it can be programmed using the eepflash.sh
script. It takes a number of parameters, which are explained if you run it with the -h
flag. When writing the EEPROM, you’ll also have to approve of the operation by typing the full word yes
when it prompts (a simple y
is not acceptable). eepflash.sh will print out the status of the write – the 118 bytes written matches the length of the test.eep file we generated above.
sudo sh ./eepflash.sh -w -f=test.eep -t=24c256
This will disable the camera so you will need to REBOOT after this process completes.
This will attempt to write to i2c address 0x50. Make sure there is an eeprom at this address.
This script comes with ABSOLUTELY no warranty. Continue only if you know what you are doing.
Do you wish to continue? (yes/no): yes
Writing...
0+1 records in
0+1 records out
118 bytes (118 B) copied, 2.33811 s, 0.1 kB/s
Done.
As advised by that output, it is time to reboot.
When the system comes back up, you should have some new filesystem nodes at /proc/device-tree/hat
pi@raspberrypi /proc/device-tree/hat $ ls -al
total 0
drwxr-xr-x 2 root root 0 Oct 27 20:16 .
drwxr-xr-x 15 root root 0 Oct 27 20:16 ..
-r--r--r-- 1 root root 4 Oct 27 20:16 name
-r--r--r-- 1 root root 21 Oct 27 20:16 product
-r--r--r-- 1 root root 7 Oct 27 20:16 product_id
-r--r--r-- 1 root root 7 Oct 27 20:16 product_ver
-r--r--r-- 1 root root 37 Oct 27 20:16 uuid
-r--r--r-- 1 root root 24 Oct 27 20:16 vendor
If we inspect the contents of those notes, we see the values that we put in the test_settings.txt file:
pi@raspberrypi/proc/device-tree/hat $ cat vendor
SparkFun Electronics
pi@raspberrypi /proc/device-tree/hat $ cat product
EEPROM Testing
Troubleshooting
If you’ve gone through raspi-config and enabled the SPI/I2c from ‘Advanced Options’, yet the devices are not in the device tree, don’t lose hope. There are two files that should be examined. We found that somtimes the raspi-config utility doesn’t solve the problem, depending on what version of Pi, where raspbian was sourced from, and when the last update has occurred.
Check /boot/config.txt
Sometimes the raspi-config tool will incorrectly edit /boot/config.txt while selecting the advanced settings. What happens is an erroneous control-char is placed in the file.
hdmi_force_hotplug=1
config_hdmi_boost=4
overscan_left=24
overscan_right=24
overscan_top=16
overscan_bottom=16
disable_overscan=0^Mdtparam=spi=on
dtparam=i2c_arm=on
After configuration with raspi-config, /boot/config.txt contains a strange ^M
character
Fix the line breaking in the file so it looks something like this:
hdmi_force_hotplug=1
config_hdmi_boost=4
overscan_left=24
overscan_right=24
overscan_top=16
overscan_bottom=16
disable_overscan=0
dtparam=spi=on
dtparam=i2c_arm=on
Check /etc/modules
If they are not present, add the following to the end of /etc/modules
i2c-dev
Reboot the system
After checking the files, reboot by issuing sudo reboot
or sudo shutdown -r now
.
Resources & Going Further
Resources
- If you’re really curious about the nitty-gritty internal details of I2C and SPI, you might want to read the source code of Wiring Pi, which you can clone from here.
- Additionally, you can learn about the Linux underpinnings of these interfaces documented at kernel.org. The SPIdocumentation seems to be more complete than its I2C sibling.
- If the example code here isn’t working, you should check for updated versions on the 40-pin Pi Wedge GitHub Repository.
- The way that I2C and SPI devices are enabled in Raspbian has changed significantly in recent revisions. This forum post explains how to re-enable the interfaces if they disappeared in an upgrade.
- The HAT specifications and related information are hosted on GitHub. If you’re designing a HAT, you’ll want to start by reading the HAT Design Guide, and possibly perusing the B+ addons forum.
- Filezilla is a convenient FTP & SFTP client, which is useful for getting files to and from a Pi.
- PuTTY is a terminal program that has serial, telnet and SSH modes.
Going Further
- The Pi gPIo tutorial explains how to use the digital I/O pins on your Pi.
- The Pi Wedge gives you a convenient way to access the SPI and I2C interfaces on your Pi.
For more information about the Raspberry Pi and the software described here, please visit their sites.
- The Raspberry Pi Foundation
- The Pi Foundation’s B+ Addons forum.
- The Pi Foundation’s GitHub repository for the Raspberry Pi B+ HATs.
- The eLinux.org Raspberry Pi peripherals guide
- WiringPi
- RPi.GPIO module
- Some notes about increasing the available current from the B+ USB ports.
If you have any problems or questions, our technical support department can help. Please don’t hesitate to contact us. We also love to hear about your projects!
View more at: http://bit.ly/1XReQFr
Post a Comment