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

Software

Software for the I2C Interface
Hardware and Software for I2C on the Make Controller Board.
Page 2 of 2.
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.

 



 

Software file changes

Posted by Ross Wakelin at 2008-04-15 05:47
Hi Bob

I'm trying this right now, and so far have found:
you need to remember to edit the files from Atmel and
remove the paths to the include files.
I can't get twiapi.c to compile, it keeps barfing when trying
to include the
#include "ioat91sam7x256.h"
#include "lib_AT91SAM7X256.h"
files. Did you make any changes to these files in your
build? I'm getting hundreds of compile errors from these files, mainly what looks like double definitions and assembly errors.
I'm using the latest Yagarto toolset:
yagarto-bu-2.18)gcc-4.2.2-c-c++_nl-1.16.0_gi-6.8.59_20080408. Maybe thats the issue?

Software file changes

Posted by Bob Faulk at 2008-04-16 01:09
It turns out I did change those two files. In ioat91sam7x256.h, I moved the else from line 2744 to the line before the end of the file so the assembly EQU's fell within the #if 0.
In lib_AT91SAM7X256.h, I changed the void parameter on some function prototypes. I don't believe this change was required; I was probably experimenting with compiler warnings. Here is the diff output. Hopefully this will work for you, as I will not be able to check the forum for a few days.
Regards,
Bob

[bobf@www ARM7_AT91SAM7S]$ diff lib_AT91SAM7X256.h ~/fw131/heavy/controller/freertos/portable/GCC/ARM7_AT91SAM7S/lib_AT91SAM7X256.h
60c60
< void (*newHandler)() ) // \arg address of the interrupt handler
---
> void (*newHandler) (void) ) // \arg address of the interrupt handler
135c135
< void (*Handler) (void) ) // \arg Interrupt Handler
---
> void (*Handler) () ) // \arg Interrupt Handler


[bobf@www ARM7_AT91SAM7S]$ diff ioat91sam7x256.h ~/fw131/heavy/controller/freertos/portable/GCC/ARM7_AT91SAM7S/ioat91sam7x256.h
2744c2744
<
---
> #endif
4697c4697
< #endif
---
>