NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » TWI questions.

March 23, 2013
by jmuthe
jmuthe's Avatar

Right now, I am in the process of reading the Atmega168 datasheet and I am trying to understand the TWI section of it on Chapter 21. I was trying to look for some source code on this forum that gives a good example of how to use TWI with the SDA and SCL pins. I found a few examples that other people made but the code was just too long and complicated for me to understand. I wanted to create the simplest code possible to demonstrate how to use TWI and I tried but my program failed. I created two pieces of code for the slave and master. All I wanted to do was take a random number (in this case 23) and transfer it from the master microcontroller to the slave microcontroller. Then I wanted the slave to output the number onto the LCD. I first connected pins SDA and SCL of the master microcontroller to SDA and SCL of the slave microcontroller. I then connected pins SDA and SCL of the master microcontroller to resistors and the other side of those resistors went to the 5 Volts. The slave microcontroller went to the LCD. Here is the master code:

#include <avr/io.h>
#include <inttypes.h>

int main()
   {
    DDRC |= (1<<PC4)|(1<<PC5);////SDA and SCL outputs
    while(1)
        {
                    TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
                    while (!(TWCR & (1<<TWINT)))
                    {}
                    TWDR= 23;//number to transmit
                    TWCR = (1<<TWINT) |(1<<TWEN);// transmit
                    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);

        }

  return 0;
}

and here is the slave:

#include <avr/io.h>
#include <inttypes.h>
#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"

int main()
   {
     DDRC |= (0<<PC4)|(0<<PC5);//SDA and SCL inputs
     lcd_init();
     int i;
     while(1)
        {
           i = TWDR;
           lcd_line_one();
           lcd_write_int16(i);

        }

  return 0;
}

I wanted the code to print out the number 23 since that is what I put into TWDR but it printed out 255, so it didn’t work. First, I want to ask if I am even close to doing what I tried to do. If so, could you tell me what I have to do to get my code to work using TWI.

March 23, 2013
by esoderberg
esoderberg's Avatar

jmuthe,

Peter Fleury has a popular TWI utility. It's about as simple as you can get and still function.

Fleury_code

March 24, 2013
by Ralphxyz
Ralphxyz's Avatar

jmuthe, what TWI/I2C examples did you find on the forum??

With my very limited knowledge and abilities I have successfully ran every I2C/twi project so they cannot be that complicated.

Did you look for I2C beside looking for TWI? I2C is the original term TWI is ATmels copped out method of avoiding royalties on using the term "I2C".

Noter has a simple I2C Master/Slave.

Rick's I2C Nunchuck project is a lot of fun.

Eric also has a couple of I2C articles in the Nerdkits Community Library.

Ralph

March 24, 2013
by BStory
BStory's Avatar

In your slave code:

DDRC |= (0<<PC4)|(0<<PC5);

This line doesn't do anything, it ORs a 0 with whatever is currently in the PC4 and PC5 slots. The bits will just stay as they are.

A better method for setting a bit to 0 would be an AND NOT.

DDRC &= ~(1<<PC4)&(1<<PC5);

It's something like that.

April 03, 2013
by jmuthe
jmuthe's Avatar

I appreciate the links to other projects but I still haven’t found a good one for me. I just have two microcontrollers with me right now so I can’t do the projects with an eeprom or a nunchuck. Noters program looked promising at first but I have difficulty understanding what is going on in the program. It seems that there is a lot of code written for a simple program. I want to avoid using header files and just write code for a master and a slave microcontroller.

I reread chapter 21 and I realized something about TWI. The TWI doesn’t just transmit data serially from one device to another. It allows you to write to up to 128 devices using one master. Each device is given an address using TWAR so that data could be written from the master to that specific slave only. The master transmits to the slave by first writing the address value on TWDR followed by the data on TWDR that it wishes to send. I modified my master and slave code to do this. My goal was to assign the slave device a random address (48) and transmit random data value to it (57).The slave is still connected to the LCD. I want the slave to output the address and then output the data onto the LCD so I expect the LCD to print out the number 48 and then the number 57. The LCD prints out the address number 48 twice instead. I had some success because I was able to transmit the address and print it to the LCD but I want to know how can I print out the data as well? Here is the master code:

#include <avr/io.h>
#include <inttypes.h>

int main()
   {
    int address=48;//address + write
    int data = 57; //data
    DDRC |= (1<<PC4)|(1<<PC5);////SDA and SCL outputs
    while(1)
        {
                    TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
                    while (!(TWCR & (1<<TWINT)))
                    {};
                    TWDR= address;
                    TWCR = (1<<TWINT) |(1<<TWEN);// transmitting address
                    while (!(TWCR & (1<<TWINT)))
                    {};

                    TWDR = data;
                    TWCR = (1<<TWINT) |(1<<TWEN);//transmitting data
                    while (!(TWCR & (1<<TWINT)))
                    {};
                    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);

        }

  return 0;
}

Here is the slave.

#define F_CPU 14745600
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>
#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"

int main()
   { 
     DDRC &= ~(1<<PC4);
     DDRC &= (1<<PC5);
     int address=48;
     int i;
     int p;
     lcd_init();
     while(1)
        {
              TWAR=address;
              TWCR = (1<<TWEA)|(1<<TWEN);
           lcd_write_string(PSTR("  "));
           i = TWDR; //this value should be the address
           while (TWSR!=0x60)//wait for acknowledgement
           { };
           p=TWDR;//this value should be the data
           lcd_write_string(PSTR("  "));
           lcd_write_int16(i);//print address
           lcd_write_string(PSTR("  "));
           lcd_line_one();
           lcd_write_string(PSTR("  "));
           lcd_write_int16(p);//print data
           lcd_write_string(PSTR("  "));
        }

  return 0; 
}
April 03, 2013
by pcbolt
pcbolt's Avatar

jmuthe -

On line 24;

 while (TWSR!=0x60)//wait for acknowledgement

Does this state (0x60) indicate address sent or data sent? You might need to wait for state 0x80.

April 03, 2013
by Noter
Noter's Avatar

It's a complex interface. The slave must ACK the master SLA+W before any data is transmitted. Fleury's code is the easiest to follow. Continue to study chapter 21 and analyze/learn Fleury's I2c functions along with it. Then if you still want to write your own you can.

April 07, 2013
by jmuthe
jmuthe's Avatar

I was looking at the Fleury code and there is something that I don't understand. Fleury's download consists of several code which include a library "twimaster.c", "i2cmaster.h" and a test code "test_i2cmaster.c". In the library (twimaster.c) there are several variables in them such as TW_STATUS(line 52), TW_MT_SLA_ACK(line 64), and TW_MR_SLA_ACK (line 64). I can't find anywhere in the files ("twimaster.c", "i2cmaster.h" and "test_i2cmaster.c") where these variables are defined and given a value. What exactly is there inital value and where are they defined?

April 07, 2013
by Noter
Noter's Avatar

Chase the includes to find the definitions of these items. Look at <compat/twi.h> and you will see it includes <util/twi.h> and when you look at it you will find the definitions you seek. Both of these .h files are found in subdirectories of the AVR toolchain distribution directory. In my world these are found in "/home/paul/Atmel-AVR-Toolchain-3.4.1/avr8-gnu-toolchain-linux_x86_64/avr/include" but you'll have to find the toolchain include directory on your own computer.

April 08, 2013
by jmuthe
jmuthe's Avatar

Okay, thanks Noter. I found the file.

Post a Reply

Please log in to post a reply.

Did you know that you need to think about wires differently when you're transmitting signals more than a few inches? Learn more...