You are here: Home Documentation Tutorials Using I2C on the Make Contoller Board
Document Actions

Using I2C on the Make Contoller Board

Note: Return to tutorial view.

Hardware and Software for I2C on the Make Controller Board.

Hardware

Hardware modifications for accessing I2C on the Make Controller Board
The Atmel ATMSAM7X CPU on the Make Controller board has a wealth of built-in peripherals. One of those is I2C, which can be used to connect many peripherals to the Make Controller board such as LCD displays, GPS's, or compasses, leaving the RS232 port free for other uses such as the X-Bee controller board.

To access the I2C (AKA TWI) pins on the CPU, traces must be cut, and two wires must be soldered. Although the ATMSAM7X pins appear to be used for USB, I2C is usable concurrently with USB.

Caveats

None of this has been thoroughly tested, and if you need to be certain your system will function properly and won't be damaged by any of this, you should consult with an EE. This isn't my day job!

The traces are tiny, and this modification should only be attempted by a skilled user of a high quality soldering iron.

Cutting The Traces

See the attached photograph of the underside of the Make Controller Board to see where to cut the traces (please, no laughing).

Pin 18 is TWD, and connected through R19 to USB 5V. Although this hardware is present to detect USB connections, the software does not use it, and we can cut the trace from pin 18 to R19 and R18. Cut this trace on the underside of the board so the via is available as a solder pad for the TWD wire.

Pin 19 is TWCK, and is connected to Q1 and R20 and this output is used to enable USB. Cut the trace on the underside of the board between the via from pin 19, and Q1 and R20. Q1 still must connect to R20, otherwise USB will not work. In my case, I accidentally cut the trace between Q1 and R20 and had to add a small wire between Q1 and R20. As was the case for pin 18, pin 19 now has a free via to be used as a solder pad.

This is a good point to re-connect your controller board and re-test your system to make sure the USB is still functional. If it is not, most likely there is no connection between Q1 and R20.

Making the I2C connection header

See the attached photograph of the completed I2C header. The I2C connection header will have 4 pins defined as follows: +5V, Ground, TWD, and TWCK.

Cut a small proto board and drill holes in it so it can later be mounted to the controller board using 4-40 nylon screws. Install a 4-pin header (Dig-key 277-1647-NDD, or the make controller connector pack: http://www.makingthings.com/products/ACC-MAKE-CONN) onto the proto board.

Solder a wire between one pin of the I2C header and the ground pin 4 of connector J4 on the controller board. Mark a pin on the I2C header as +5V

Wire TWD and TWCK each to their own pins on the connector, then attach two 3.3Kohm pull-up resisters between those pins and the 5V pin marked on the I2C header.

Attach the nifty green screw connector to the I2C header pins.

Power

The Make Controller Board does not have 5V, although it is 5V tolerant. I re-used an old sound board connector and wire to get 5V power from a free 5V power pin on the Make Application Board. This wire was attached to the 5V pin marked on the I2C header.

When using USB to power the system, the "5V" power is actually around 4.3V because of a diode to protect the system. My I2C display seems to work fine with this. By powering the system with an external supply connected to V+ for power instead of USB, a true 5V is obtained. My I2C display works fine with this as well.

Software

Software for the I2C Interface
After spending plenty of time experimenting with the Atmel TWI interface and eventually getting my own transmit routine to function, I gained an appreciation of the software Atmel has already written for their TWI interface. Below I describe where to get this software and how to integrate it into the Make Controller software environment. I've also included some wrapper functions that provide a simple I2C API to make things easier to use.

Atmel Software

Atmel has a large set of useful software for the ATM91SAM and other processors. Go to the Atmel AT91SAM software tools web site and downlaod version 1.3 of their AT91SAM7X-EK Software Package. It's available at http://www.atmel.com/dyn/resources/prod_documents/softpack-1.3-at91sam7se-ek-web.zip

Unzip the file to a local directory, then open up the file "index.html" in your browser, which will display a web page with links to various software packages. Under the Software Resources header, click on "examples". Next click on the CD icon for the GNU version of the "Basic Twi EEPROM Project". Files of interest are under the at91lib\utility, at91lib\drivers, and at91lib\peripherals subdirectories. The files to use are: async.c, async.h, math.c, math.h, trace.h, twi.c, twi.h, twid.c, twid.h.

Putting the Atmel Software Into the Make Environment

I copied each of the above files into my "heavy" directory and added the "c" files to my Makefile. It would have been nicer to put them in a subdirectory.

Atmel has a nice tracing facility built into their software which is comparable to the nice Debug OSC facility in the Make software. I modified Atmel's "trace.h" function so the trace statements in Atmels code are automagically converted to their corresponding OSC Debug statements. Their trace log levels go from 0-4, whereas Debug uses 3-0. The Atmel code has a unique trace_LEVEL defined at compile time for each file with tracing. In "trace.h", define trace_LOG as follows:

#define trace_LOG(level, ...) { \
   if ((level)>=trace_LEVEL) { \
      Debug((3-((level)*3/4)), __VA_ARGS__); \
   } \
}

I wrote a new ASSERT macro that doesn't waste as much code space. It is in assert.h and assert.c in the attached zip file.

When working on something like this, its hard to remember everything that needed to be changed. Please comment if I've missed anything!

Simple I2C API Functions

The TWI driver API functions of the Atmel code are flexible, but cause excessive driver-specific clutter to appear in application code. I wrote a few functions to simplify things, and placed them in twiapi.c and twiapi.h. They are bundled in the attached zip file. The functions are:

// Two Wire Interface Initialization
void twiInit(void);
// Two Wire Interface Write
// Parameters:
// buf - Pointer to data to send
// length - Number of bytes to send
// addr - 7-bit I2C address of target device.
// LSB is part of the addr (not r/w bit!)
// delayTilNext - Maximum time this operation will take to
// complete. Used to pause the next
// future operation so the device is ready.
void twiWrite(char * buf, int length, int addr, int delayTilNext);
// Two Wire Interface Read
// Parameters:
// buf - Pointer to caller-supplied data buffer
// num - Number of bytes to read
// addr - 7-bit I2C address of target device.
int twiRead(char * buf, int num, int addr);

The twiWrite function has a parameter "delayTilNext" which can be used to enforce a delay after operations that take a long time to complete. When a write is done, the delayTilNext is added to the current time to calculate the time the next operation may begin. Later when the next read or write is done, the current time is compared with the timeForNextOperation and a Sleep is done if sufficient time has not already elapsed.

Note: I've not tested multi-byte reads nor I2C device internal addressing, as my LCD display does not have these features.

Future Enhancements

Right now, this TWI software works just fine when it is used from within one task. However, you'll run into trouble if you attempt to use it from multiple tasks. In the future, I'd like to add semaphore protection of key resources so it can be used by multiple tasks concurrently.

Busy waits. This code has them. I hate them. I'd like to enhance this software to use Atmel's asynchronous mode of operation, which uses interrupts to indicate when operations are completed instead of spin loops waiting on a completion bit to be set in a register. In the meantime, run your I2C code at a lower priority, and add some taskYIELDs or Sleeps to let other tasks run when needed.