3 Simple Ways to
Share What You Make

With Instructables you can share what you make with the world — and tap into an ever-growing community of creative experts.

PhotosPhotos

Share one or more photos of a project, recipe, or whatever you've made, quickly and easily.

Step by StepStep-By-Step

Share your step-by-step photos with text instructions of what you made so others can do it too!

VideoVideo

Share your how-to video. You'll need your embed code from a video site such as YouTube.

I2C Bus for ATtiny and ATmega

Step 3I2C Drivers

Here are the descriptions of the driver functions for the I2C bus. These were developed using the Atmel Apps Notes for starters. I couldn't have done this without them as a base to build on. Development was done using WinAVR and the gcc C compiler.

Clock rate restrictions are described below for each processor. Since I am not able to test all the processor flavor / clock rate combinations possible, I'll just stick to what I actually can test and try to indicate the restrictions and limitations.

Here are the driver functions and how to use them. Please look at the examples for more details and to see the functions in use in complete programs.

For the ATtiny2313:
Clock Requirement:
The drivers are designed for a clock rate of 1MHz (the default rate) for ATtiny2313. If you want to run at other rates, then you'll have to adjust constants in the drivers. Email me if you need help doing this. You can also get some hints from the Atmel apps notes in the links in the Resources Step.

USI_TWI_Master_Initialise()
This function initializes the USI hardware for I2C mode operation. Call it once at the start of your program. It returns void and there are no arguments.

USI_TWI_Get_State_Info()
This function returns I2C error information and is used if an error occurred during an I2C transaction. Since this function only returns an error code, I use the function TWI_Act_On_Failure_In_Last_Transmission(TWIerrorMsg) to flash an error LED. The error codes are defined in USI_TWI_Master.h. Here's how to call it:
TWI_Act_On_Failure_In_Last_Transmission( USI_TWI_Get_State_Info())

USI_TWI_Start_Read_Write()
This function is used to read and write single bytes to I2C devices. It is also used to write multiple bytes. There are 6 steps to using this function.
1)Declare a message buffer in your program to hold the slave address and the data byte to be sent or received.
unsigned char messageBuf (MESSAGEBUF_SIZE);
2)Put the Slave Address as the first byte in the buffer. Shift it one bit left and OR in the Read/Write bit. Note the Read/Write bit will be 1 for a Read and 0 for a Write. This example is for a Read.
messageBuf(0) = (TWI_targetSlaveAddress<<TWI_ADR_BITS) | (TRUE<<TWI_READ_BIT);
3)When doing a Write, put the byte to be written into the next location in the buffer.
4)Call the USI_TWI_Start_Read_Write function with the message buffer and the message size as arguments.
temp = USI_TWI_Start_Read_Write( messageBuf, 2 );
5)The returned value (temp in this case) can be tested to see if an error occurred. If so, it is handled as discussed above. See examples in the programs.
6)If a Read was requested, the byte read will be in the second location in the buffer.
If multiple bytes are to be written (such as to a memory device), this same routine can be used. Setting up the buffer and calling the routine are slightly different. The second byte in the buffer will be the starting memory address to which to write. The data to be written will be in subsequent bytes. The message size will be the size including all the valid data. So if 6 bytes are to be written, then the message size will be 8 (slave address + memory address + 6 bytes of data).

USI_TWI_Start_Random_Read()
This function is used to read multiple bytes from an I2C device, typically it's only meaningful for a memory of some sort. Using this routine is very similar to the previous routine, with two exceptions.
The setting of the Read/Write bit doesn't matter. Calling this routine will always cause a Read operation.
The messageSize should be 2 plus the number of bytes to be read.
If no errors occurred, the data will be in the buffer beginning at the second location.

For the ATmega168:
Clock Requirement:
The drivers are designed for a clock rate of 4MHz for ATmega168. The example code shows how to set this clock rate. If you want to run at other rates, then you'll have to adjust constants in the drivers. Email me if you need to do this.

TWI_Master_Initialise()
This function initializes the TWI hardware for I2C mode operation. Call it once at the start of your program. It returns void and there are no arguments. Be sure to enable interrupts by calling swi() after initializing.

TWI_Get_State_Info()
This function returns I2C error information and is used if an error occurred during an I2C transaction. Since this function only returns an error code, I use the function TWI_Act_On_Failure_In_Last_Transmission(TWIerrorMsg) to flash an error LED. The error codes are defined in TWI_Master.h, but are modified for signaling on an error LED. See the example code for details. Here's how to call it:
TWI_Act_On_Failure_In_Last_Transmission(TWI_Get_State_Info())
Note that error checking is done by making sure that the I2C transaction is complete (function described below) and then testing a bit in the global status word.

TWI_Start_Read_Write()
TWI_Start_Random_Read()
These two functions work the same as the corresponding functions described above but with a few exceptions.
They don't return any error values.
Data read is not transferred into the buffer. Doing this will be done with the function described next.
When calling TWI_Start_Random_Read, the messageSize should be the number of data bytes requested plus one, not two.
The I2C driver for the ATmega168 is interrupt driven. That is, the I2C transactions are started and then execute independently while the main routine continues to run. When the main routine wants data from an I2C transaction that it started, it must check to see if the data is available. The situation is the same for error checking. The main routine must be sure that the I2C transaction is complete before checking for errors. The next two functions are used for these purposes.

TWI_Transceiver_Busy()
Call this function to see if an I2C transaction is complete before checking for errors. The example programs show how to use this.

TWI_Read_Data_From_Buffer()
Call this function to transfer data from the I2C driver's receive buffer into the message buffer. This function will make sure the I2C transaction is complete before transferring the data. While a value is returned by this function, I find checking the error bit directly to be more reliable. Here's how to call it. The message Size should be one greater than the number of data bits desired. The data will be in messageBuf starting at the second location.
temp = TWI_Read_Data_From_Buffer( messageBuf, messageSize );
« Previous StepDownload PDFView All StepsNext Step »

Pro

Get More Out of Instructables

Already have an Account?

close

All Steps Viewing
View all steps of an Instructable on the same page when you're a Pro Member.

Upgrade to Pro today!
41
Followers
8
Author:doctek