| Author |
Message |
|
|
Posted: Aug 19, 2012 - 11:55 PM |
|

Joined: Aug 19, 2012
Posts: 7
|
|
Hi guys!
I've spent more than three weeks trying to make Atmega8 able to "speak" I2C (I have to use a LM75 sensor) but I have no success at all... =(
Can someone help me with an example with two Atmega8 linked by I2C? A Proteus example would also be very good for me too, but, any help will be very useful for me.
I've already visited all foruns on Internet (including Peter Fleury) and nothing...  |
|
|
| |
|
|
|
|
|
Posted: Aug 20, 2012 - 12:27 AM |
|


Joined: Mar 28, 2001
Posts: 20387
Location: Sydney, Australia (Gum trees, Koalas and Kangaroos, No Edelweiss)
|
|
|
|
|
|
|
Posted: Aug 20, 2012 - 05:23 AM |
|


Joined: Mar 28, 2001
Posts: 20387
Location: Sydney, Australia (Gum trees, Koalas and Kangaroos, No Edelweiss)
|
|
|
|
|
|
|
Posted: Aug 20, 2012 - 02:09 PM |
|

Joined: Aug 19, 2012
Posts: 7
|
|
Thanks, JS.
The problem is that I already visited this page and they didn't solve the problem stated on the thread (which is the same as mine).
I'm already using LM74 (SPI) and I made it work perfectly (by the way, I want to share the code here, but I don't know how yet), but, using LM75 (I2C) had become a very hard problem... I made so many things trying to make I2C working on Atmega8 that AVRFreaks is my last hope... |
|
|
| |
|
|
|
|
|
Posted: Aug 20, 2012 - 03:05 PM |
|


Joined: Jul 18, 2005
Posts: 62349
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
| I'd start by considering what debug techniques you have available. A DSO or a logic analyser would be invaluable. Also, if this particular I2C device is complex then pick something real easy like an EEPROM or an RTC and get the basics of I2C working between the AVR and that (with proven library code such as Fleury). When you have the basics working it firstly rules out a lot of the low level, hardware "unknowns" and also will have given you experience you may put towards debugging what's happening with a more complex device. |
_________________
|
| |
|
|
|
|
|
Posted: Aug 20, 2012 - 05:02 PM |
|

Joined: Aug 07, 2007
Posts: 1477
Location: Czech
|
|
If I understand you have the sensor connected to Avr1 and want to send values from Avr1 to Avr2.
You can use uart, it is much easier in my opinion.
A one-way communication will do (from Avr1 to Avr2), so that you use 2 wires, same as I2c.
If hw uart is not available then use a software one.
Quote:
I've spent more than three weeks trying to make Atmega8 able to "speak" I2C
Ooh, I gave it up much sooner (Avr as i2c slave). |
Last edited by Visovian on Aug 21, 2012 - 02:55 PM; edited 1 time in total
|
| |
|
|
|
|
|
Posted: Aug 20, 2012 - 07:09 PM |
|

Joined: Aug 19, 2012
Posts: 7
|
|
|
Visovian wrote:
Ooh, I gave it up much sooner (Avr as i2c slave).
Yeah, but I can use almost everything on Atmega8 (LCD, USART, SPI) but no deal with I2C...
I spent all that time serching/testing and nothing...
After I make the code, I'll put it here because I don't want anybody facing the same boring problem...  |
|
|
| |
|
|
|
|
|
Posted: Aug 20, 2012 - 11:16 PM |
|


Joined: Mar 28, 2001
Posts: 20387
Location: Sydney, Australia (Gum trees, Koalas and Kangaroos, No Edelweiss)
|
|
So is the problem the I2C/TWI or the LM75? You have a I2C/TWI library which works (I have never used that one but others) so all you need to do is to figure out what the LM75 wants.
And of course the first thing we want to know is if you have the I2C pullup resistors mounted on the board, without them nothing will work.
Also you many want to start with something for which you have working examples like a DS1307 or a I2C memory chip.
winAvr has a demo project
Quote:
/*
* Simple demo program that talks to a 24Cxx I²C EEPROM using the
* builtin TWI interface of an ATmega device.
*/
Are you using winAvr or the newfangled AS6? Either way I'm sure you have working examples of how to communicate using thw I2C. |
_________________ John Samperi
Ampertronics Pty. Ltd.
www.ampertronics.com.au
* Electronic Design * Custom Products * Contract Assembly
|
| |
|
|
|
|
|
Posted: Aug 20, 2012 - 11:31 PM |
|

Joined: Aug 19, 2012
Posts: 7
|
|
Hi, John.
I'm first using Proteus to simulate the codes. I'm using Atmega8 and TC74 (which is a clone of LM75) on it with pull-ups and everything. I made a code (which I'm organizing right now to put here on AVR Freaks) for reading a LM74 (SPI) and the conversion routine will be the same, but I'm having problems with I2C and Atmega8. I already read Atmega8 datasheet but I can't make them work. I tried different libraries (TWI/I2C is kind of complex for making my own) , clocks but no success at all...
The best result was some random waves (on virtual scope) on SDA... =( |
|
|
| |
|
|
|
|
|
Posted: Aug 21, 2012 - 12:13 AM |
|


Joined: Mar 28, 2001
Posts: 20387
Location: Sydney, Australia (Gum trees, Koalas and Kangaroos, No Edelweiss)
|
|
| Sorry I'm out, you are using simulation and a virtual scope and not the real hardware. |
_________________ John Samperi
Ampertronics Pty. Ltd.
www.ampertronics.com.au
* Electronic Design * Custom Products * Contract Assembly
|
| |
|
|
|
|
|
Posted: Aug 21, 2012 - 12:17 AM |
|

Joined: Aug 19, 2012
Posts: 7
|
|
| For the first test, yes. Testing everything on real world as a first step would take waaaay more time. |
|
|
| |
|
|
|
|
|
Posted: Aug 21, 2012 - 12:23 AM |
|


Joined: Mar 28, 2001
Posts: 20387
Location: Sydney, Australia (Gum trees, Koalas and Kangaroos, No Edelweiss)
|
|
Not for me as I have the real world at my disposal ie real hardware, real debugger (JTAG or DW) and real oscilloscope.  |
_________________ John Samperi
Ampertronics Pty. Ltd.
www.ampertronics.com.au
* Electronic Design * Custom Products * Contract Assembly
|
| |
|
|
|
|
|
Posted: Aug 21, 2012 - 01:48 AM |
|


Joined: Apr 20, 2007
Posts: 6072
Location: Long Island New York
|
|
From what I just read on the datasheet you have two registers to deal with and an address.
The address is 1001101b
The two registers are:
Config where only two bits are looked at, the STANDBY bit which you can read or write to, and by default is set to '0' or normal operation. And the DATA READY which tells you if there is valid data in the other register you have access to
The TEMP register which is read only.
If you look at Figure 3-1 on page 7 it shows the formats for a write operation and a read operation along with the data format the sensor outputs when a read command is sent.
All in all this is a relatively simple device to interface to. I do remember having some difficulty my first go around with I2C and js's help along with David's got things moving quite quickly.
Since you are using Proteus, I assume 'C' is the language so I am not much help there.
Post the code as you have noted. I am sure it's something simple. Usually is.
EdIT: In Proteus, can you put a logic analyzer on the SCK and SDA lines and see what the lines do? |
_________________ Jim
I have decided that I am no longer going to plan anything in advance. In a court of law this is called Pre-Meditated, and does not look good for the defense.....
Timer function not working properly? Check CLKDIV8 Fuse first
|
| |
|
|
|
|
|
Posted: Aug 21, 2012 - 03:32 AM |
|

Joined: Apr 20, 2011
Posts: 8
Location: Singapore
|
|
Look like he do not understand the I2C communication way, as the data pin can be input (receive data) then output (send data). The Atmel processor should be master as LM75 is not a controller so is a slave.
I2C is not as simple as SPI. |
|
|
| |
|
|
|
|
|
Posted: Aug 21, 2012 - 09:37 AM |
|


Joined: Dec 22, 2006
Posts: 300
Location: Odense, Denmark
|
|
Soo... A schematic would help!
And it would also be nice to have a look at your code that you can't get working! |
_________________ - Brian
|
| |
|
|
|
|
|
Posted: Aug 21, 2012 - 10:35 AM |
|


Joined: Jan 07, 2012
Posts: 1210
Location: North of France
|
|
Perhaps one would need two schematics and two codes, as there are two circuits (one temperature sensor + AVR as an I2C slave, another AVR being the I2C master)...
There is something which worries me : is there a cheap way to test only one circuit at the time with a PC (it already exists) which would function as a master (if one tests the slave part) , then as a slave (to test the master part). As PCs already preexist, this could be cheaper than a DSO or a logic analyser (and I feel/fear they test both circuits at the same time, which is complicated)....
Edited : if the structure temperature sensor + AVR is a slave, the AVR should be at the same time a master (to silently "speak" to the other AVR) and a slave (to "listen" to the LM75). But perhaps I guessed wrongly... |
|
|
| |
|
|
|
|
|
Posted: Aug 21, 2012 - 01:07 PM |
|


Joined: Dec 22, 2006
Posts: 300
Location: Odense, Denmark
|
|
|
dbrion0606 wrote:
Perhaps one would need two schematics and two codes, as there are two circuits (one temperature sensor + AVR as an I2C slave, another AVR being the I2C master)...
Right, I didn't get that from the original post!
First he speaks about connecting a LM75 to the mega and I thought that was it, but then about connecting to megas together!
To Felipe: While it can certainly be done, it will complicate things slightly, why don't you just start by getting the mega to run as a master connecting it to your LM75. Once you have the master part running start working on the slave part! |
|
|
| |
|
|
|
|
|
Posted: Aug 24, 2012 - 02:56 AM |
|

Joined: Aug 19, 2012
Posts: 7
|
|
It worked!
I adapted Peter Fleury's library in order to put it in just a file. First I used TC74 (which is almost same thing as LM75) and it worked perfectly (I don't have any TC74, I tested it on Proteus, if anyone can test it on real world, please share with us!). Here is the code:
Code:
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include <avr/interrupt.h>
#include <compat/twi.h>
#define TC74 0b1001101 // device address of TC74
/*uC Clock*/
#define uC_Clock 8000000L
/** defines the data direction (reading from I2C device) in i2c_start(),i2c_rep_start() */
#define I2C_READ 1
/** defines the data direction (writing to I2C device) in i2c_start(),i2c_rep_start() */
#define I2C_WRITE 0
/* I2C clock in Hz */
#define SCL_CLOCK 100000L
/*************************************************************************
Initialization of the I2C bus interface. Need to be called only once
*************************************************************************/
void i2c_init(void)
{
/* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */
TWSR = 0; /* no prescaler */
TWBR = ((uC_Clock/SCL_CLOCK)-16)/2; /* must be > 10 for stable operation */
}/* i2c_init */
/*************************************************************************
Issues a start condition and sends address and transfer direction.
return 0 = device accessible, 1= failed to access device
*************************************************************************/
unsigned char i2c_start(unsigned char address)
{
uint8_t twst;
// send START condition
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
// wait until transmission completed
while(!(TWCR & (1<<TWINT)));
// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8;
if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;
// send device address
TWDR = address;
TWCR = (1<<TWINT) | (1<<TWEN);
// wail until transmission completed and ACK/NACK has been received
while(!(TWCR & (1<<TWINT)));
// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8;
if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;
return 0;
}/* i2c_start */
/*************************************************************************
Issues a start condition and sends address and transfer direction.
If device is busy, use ack polling to wait until device is ready
Input: address and transfer direction of I2C device
*************************************************************************/
void i2c_start_wait(unsigned char address)
{
uint8_t twst;
while ( 1 )
{
// send START condition
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
// wait until transmission completed
while(!(TWCR & (1<<TWINT)));
// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8;
if ( (twst != TW_START) && (twst != TW_REP_START)) continue;
// send device address
TWDR = address;
TWCR = (1<<TWINT) | (1<<TWEN);
// wail until transmission completed
while(!(TWCR & (1<<TWINT)));
// check value of TWI Status Register. Mask prescaler bits.
twst = TW_STATUS & 0xF8;
if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) )
{
/* device busy, send stop condition to terminate write operation */
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
// wait until stop condition is executed and bus released
while(TWCR & (1<<TWSTO));
continue;
}
//if( twst != TW_MT_SLA_ACK) return 1;
break;
}
}/* i2c_start_wait */
/*************************************************************************
Issues a repeated start condition and sends address and transfer direction
Input: address and transfer direction of I2C device
Return: 0 device accessible
1 failed to access device
*************************************************************************/
unsigned char i2c_rep_start(unsigned char address)
{
return i2c_start( address );
}/* i2c_rep_start */
/*************************************************************************
Terminates the data transfer and releases the I2C bus
*************************************************************************/
void i2c_stop(void)
{
/* send stop condition */
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
// wait until stop condition is executed and bus released
while(TWCR & (1<<TWSTO));
}/* i2c_stop */
/*************************************************************************
Send one byte to I2C device
Input: byte to be transfered
Return: 0 write successful
1 write failed
*************************************************************************/
unsigned char i2c_write( unsigned char data )
{
uint8_t twst;
// send data to the previously addressed device
TWDR = data;
TWCR = (1<<TWINT) | (1<<TWEN);
// wait until transmission completed
while(!(TWCR & (1<<TWINT)));
// check value of TWI Status Register. Mask prescaler bits
twst = TW_STATUS & 0xF8;
if( twst != TW_MT_DATA_ACK) return 1;
return 0;
}/* i2c_write */
/*************************************************************************
Read one byte from the I2C device, request more data from device
Return: byte read from I2C device
*************************************************************************/
unsigned char i2c_readAck(void)
{
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
while(!(TWCR & (1<<TWINT)));
return TWDR;
}/* i2c_readAck */
/*************************************************************************
Read one byte from the I2C device, read is followed by a stop condition
Return: byte read from I2C device
*************************************************************************/
unsigned char i2c_readNak(void)
{
TWCR = (1<<TWINT) | (1<<TWEN);
while(!(TWCR & (1<<TWINT)));
return TWDR;
}/* i2c_readNak */
int main(void)
{
unsigned char ret;
DDRB = 0xff; // use all pins on port B for output
PORTB = 0xff; // (active low LED's )
_delay_ms(1000);
i2c_init(); // init I2C interface
i2c_start(0x9A); // set device address and write mode
i2c_write(0x00);
i2c_rep_start(0x9B); // set device address and read mode
PORTB = i2c_readNak();
i2c_stop();
for(;;)
{
i2c_start(0x9A); // set device address and write mode
i2c_write(0x00);
i2c_rep_start(0x9B); // set device address and read mode
PORTB = i2c_readNak(); //Temperature can be read on PORTB pins
i2c_stop();
_delay_ms(1000);
}
}
The only thing that didn't work was:
Code:
i2c_start(TC74+I2C_WRITE);
so I had to put TC74's address + "0" on LSB (0x9A).
By the way, anyone knows if Atmega8 can use 100 khz TWI with its internal 1 Mhz osc? |
|
|
| |
|
|
|
|
|