TWI / I2C Not Working (Solved)

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello!

I'm programming an I2C communications for the first time and I just can't seem to get it to work.

Communications are between an Arduino Uno R3 and an Atmega1280 (external crystal 8MHz).

Pullup Resistors are 4.7kohm to a 5V line.

Arduino acting as Master, Atmega as Slave.

 

I'm trying to get the Arduino to send data to the uC and have it send it back, however it doesn't seem get into the states I expect it to.

 

Arduino Code:

// Code to test whether I2C of uC is working
// Description: Send data, receive data sent, display

#include <Wire.h>

void setup() {
  // put your setup code here, to run once:
  Wire.begin();
  Serial.begin(9600);
  uint8_t uC_Address = 0x1C;
  uint8_t sending = 3;
  uint8_t SendBuffer[sending];
  uint8_t txsending;

  //command to let uC know to store
  SendBuffer[0] = 0x1;
  //data to send
  SendBuffer[1] = 0x17;
  SendBuffer[2] = 0x64;

  // Testing begin
  // Send test data
  Wire.beginTransmission(uC_Address);
  Wire.write(SendBuffer , sending);
  txsending = Wire.endTransmission();

  if (txsending == 0){
      Serial.println("Sending Success");
  } else {
      Serial.println("Sending Failed. Bytes left to send:");
      Serial.println(txsending);
  }

  //Receive test data
  Wire.requestFrom(uC_Address, uint8_t (sending-1));

  Serial.println("Request complete");

  while(Wire.available())
  {
    Serial.println("Available confirmed");
    uint8_t x = Wire.read();
    Serial.println(x);
  }

  Serial.println("Receiving complete");

}

void loop() {
  // put your main code here, to run repeatedly:

}

 

Atmega1280 Code:

/**
 * Test code for receiving I2C
 * uC acting as Slave
 */

/*
 * Include header files for all drivers that have been imported from
 * Atmel Software Framework (ASF).
 */
/*
 * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
 */
#define F_CPU 8000000UL

#include <asf.h>
#include <util/twi.h>

uint8_t SlaveAddress = 0x1C;
volatile uint8_t TWI_Command = 0;
volatile uint8_t TWI_txbuffer[0xFF];			//buffer to store data being sent
volatile uint8_t TWI_datacount = 0;				//tracks how much data needs to be sent
volatile uint8_t TWI_datatrack = 0;				//tracks how much data has been sent

ISR(TWI_vect){
	// set pin to low if interrupt is called
	ioport_set_port_level(IOPORT_PORTD, (1<<PD6), IOPORT_PIN_LEVEL_LOW);
	// dummy variable to store data
	uint8_t data;

	if (TW_STATUS == TW_SR_SLA_ACK){			// if slave address comes up with write command (slave is receiver), New command

		TWCR |= (1<<TWINT)|(0<<TWSTO)|(1<<TWEA)|(1<<TWEN);

	} else if (TW_STATUS == TW_SR_DATA_ACK) {	// if Data byte has been received in slave receive mode

		data = TWDR;
			if (TWI_Command == 0){
			if ((data & 0x1) == 0x1) {			// Communications test command, send ack and prepare to receive data to send back

				TWI_Command = 1;
				TWCR |= (1<<TWINT)|(1<<TWEA)|(1<<TWEN);

			}
			} else if (TWI_Command == 1) {		// Data received is test data meant to be sent back, 0xFF total data bytes can be sent for test

			TWI_txbuffer[TWI_datacount] = data;
			TWI_datacount++;

			if (TWI_datacount == 0xFF){			// if too much data is set to be sent (overflow), reset the count, most recent data only data to be sent
				TWI_txbuffer[0] = data;
				TWI_datacount = 1;
			}

			TWI_datatrack = 0;					// counter used to track data being sent, reset to 0 for new sending

			TWCR |= (1<<TWINT)|(1<<TWEA)|(1<<TWEN);		//clear flag, send ack and prepare to receive more data

		}

	} else if (TW_STATUS == TW_SR_STOP){		// stop command or repeated start, set slave to prepare to be addressed. if repeated start likely going to be addressed again but as transmitter

		TWCR |= (1<<TWINT)|(1<<TWEA)|(1<<TWEN);

	} else if (TW_STATUS == TW_ST_SLA_ACK) {	// if slave address comes up with read command (slave is transmitter)

		if (TWI_Command == 1){					// commands 1 (currently) are the commands that require transmission

			TWDR = TWI_txbuffer[TWI_datatrack];
			TWI_datatrack++;

			TWCR = (1<<TWINT)|(0<<TWSTO)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE);

		} else {								// if not one of these commands then the system has been commanded incorrectly, set to send 0xFF and receive nack

			TWDR = 0xFF;
			TWCR = (1<<TWINT)|(0<<TWSTO)|(0<<TWEA)|(1<<TWEN)|(1<<TWIE);

		}

	} else if (TW_STATUS == TW_ST_DATA_ACK){	// if there is still more transmitting to do

		TWDR = TWI_txbuffer[TWI_datatrack];
		TWI_datatrack++;

		if (TWI_datatrack == TWI_datacount) {// is this data byte the last one to be sent?, if yes prepare to receive nack
			TWI_datacount = 0;
			TWI_datatrack = 0;
			TWCR = (1<<TWINT)|(0<<TWSTO)|(0<<TWEA)|(1<<TWEN)|(1<<TWIE);

		} else {

			TWCR = (1<<TWINT)|(0<<TWSTO)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE);
		}

	} else if (TW_STATUS == TW_ST_LAST_DATA) { // if last data has been sent and ack received when it shouldn't have, switch to not addressed

		TWCR = (1<<TWINT)|(0<<TWSTA)|(0<<TWSTO)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE);

	} else {									// (command not recognized, state not accounted for), clear flag, set to prepare for next addressing

		TWCR |= (1<<TWINT)|(1<<TWEA)|(1<<TWEN);
	}

}

int main (void)
{
	/* Insert application code here, after the board has been initialized. */
	ioport_set_port_dir(IOPORT_PORTD, (1<<PD6), IOPORT_DIR_OUTPUT);
	ioport_set_port_level(IOPORT_PORTD, (1<<PD6), IOPORT_PIN_LEVEL_HIGH);

	sei();

	TWAR = (SlaveAddress<<1);

	// Enable TWI and TWI interrupt flag
	TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWEA)|(1<<TWINT);

	while(1){}
}

 

The Pin that I set to go low if the Atmega1280 ISR is entered properly goes low.

However No data is successfully sent (Arduino wire.endTransmission() state also reflects this, giving a value of 2), I can't seem to figure out why this is.

This topic has a solution.

SO

Last Edited: Thu. Sep 28, 2017 - 01:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

At the beginning of your ISR, there is:

ioport_set_port_level(IOPORT_PORTD, (1<<PD6), IOPORT_PIN_LEVEL_LOW);
 

For ATmega8, which I have and use, this instruction is done automatically by hardware when TWINT is set. Then, by clearing TWINT (by setting it to 1) PD6 becomes high, also by hardware.

 

I am not sure about Atmega1280.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

KerimF wrote:

At the beginning of your ISR, there is:

ioport_set_port_level(IOPORT_PORTD, (1<<PD6), IOPORT_PIN_LEVEL_LOW);
 

For ATmega8, which I have and use, this instruction is done automatically by hardware when TWINT is set. Then, by clearing TWINT (by setting it to 1) PD6 becomes high, also by hardware.

 

I am not sure about Atmega1280.

 

 

That's something I added after as a check to see if the Atmega is even registering being addressed or if it was just completely ignoring the Arduino. When it wasn't in the same problems happened.

SO

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

 

I suggest that you instead try Petery Fleury's i2c lib. Which works great!

And I think you need to re read the TWI section in the datasheet if you want to DIY.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Fleury is only Master.   Your problems are with the Slave.    The Master runs on an Arduino and it looks fine (to me).

 

I suggest that you write both Master and Slave with the Arduino.    The ATmega1280 is an official Arduino chip.

Get it running 100% on Arduino.    Post the finished sketch for the Slave.

 

Then re-write the Slave for straight C if that is what you want.   We can help you at that stage.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

canbeany1 wrote:

Hi,

 

I suggest that you instead try Petery Fleury's i2c lib. Which works great!

And I think you need to re read the TWI section in the datasheet if you want to DIY.

 

That seems to be a Master I2C Library, do you know any good ones for slave?

 

david.prentice wrote:

Fleury is only Master.   Your problems are with the Slave.    The Master runs on an Arduino and it looks fine (to me).

 

I suggest that you write both Master and Slave with the Arduino.    The ATmega1280 is an official Arduino chip.

Get it running 100% on Arduino.    Post the finished sketch for the Slave.

 

Then re-write the Slave for straight C if that is what you want.   We can help you at that stage.

 

David.

 

The Atmega1280 is already on a PCB, it only has  a JTAG connection for programming. Can I load Arduino onto it with a JTAG?

 

Could I perhaps write out what the slave code would be and then get help translating it to C?

SO

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can program an Arduino binary with JTAG or any external programmer.
You could program the Arduino bootloader into your 1280. Note that the default "Burn bootloader" will disable JTAG.
.
Either way, you need to make some adjustments to the Arduino environment. e.g. adding a JTAG programmer to programmers.txt
.
Yes, I would be happy to help translating Arduino Slave to C.
.
There are app notes for I2C Slave in C. The biggest problem is to decide how you want the Slave to behave. I find it easiest to emulate a known hardware chip.
.
David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
You can program an Arduino binary with JTAG or any external programmer. You could program the Arduino bootloader into your 1280. Note that the default "Burn bootloader" will disable JTAG. . Either way, you need to make some adjustments to the Arduino environment. e.g. adding a JTAG programmer to programmers.txt . Yes, I would be happy to help translating Arduino Slave to C. . There are app notes for I2C Slave in C. The biggest problem is to decide how you want the Slave to behave. I find it easiest to emulate a known hardware chip. . David.

 

Does that mean once I program the 1280 with arduino I will no longer be able to program it? theres no other connection but jtag to the 1280 on the board.

 

Right now i just want to know if it can properly communicate using I2C (sending and receiving), so no complicated behavior yet.

 

Here's some code I wrote in arduino to give an idea of what I want the 1280 to do as a test. Receive and store, and then send what is stored once requested.

 

//Test Code for Slave in Arduino to be converted to C

#include <Wire.h>

uint8_t SlaveAddress = 0x1C;
volatile uint8_t Storage[0xFF];
volatile uint8_t DataTrack = 0;

void setup() {
  // put your setup code here, to run once:
  Wire.begin(SlaveAddress);
  Wire.onReceive(ReceiveEvent);
  Wire.onRequest(RequestEvent);

}

void loop() {
  // put your main code here, to run repeatedly:
  delay(10);

}

void ReceiveEvent(){
  while (Wire.available()>0){
    Storage[DataTrack] = Wire.read();
    DataTrack++;
  }

  if (DataTrack == 0xFF){
    Storage[0] = Storage[DataTrack-1];
    DataTrack = 1;
  }
}

void RequestEvent(){
  Wire.write(Storage, DataTrack);
  DataTrack = 0;
}

 

SO

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The obvious thing to do is use a pair of Arduinos. Develop your project. Then translate to your actual target.
Arduinos are excellent for testing ideas.
.
Be sensible. Your "Slave" does not do anything. You don't even check what it is receiving. Or even have a protocol or safety net.
What happens if the Master sends 123 bytes or 4567 bytes?
.
David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

SleepyOak wrote:

That seems to be a Master I2C Library, do you know any good ones for slave?

 

Sorry, I had some beers too many yesterday.

 

I haven't tried it, but the code is pretty readable and should be easy to adapt if it doesn't work.

https://github.com/thegouger/avr...

 

I need a master/slave setup for a project, so I will test the code later today.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Okay everyone this is very embarrassing but it turns out the reason it wasn't working was because I had the pins connected wrong.

When I was looking at the pcb doc to find the pins for I2C I accidentally mixed up the positions of SDA and SCL, everything is working now that they're where they should be.

Sorry for the trouble.

SO

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Please mark the problem as solved. In this case it would be most appropriate to mark you own last post the solution. Click the "Mark Solved" button beneath your post. Thank you!

"He used to carry his guitar in a gunny sack, or sit beneath the tree by the railroad track. Oh the engineers would see him sitting in the shade, Strumming with the rhythm that the drivers made. People passing by, they would stop and say, "Oh, my, what that little country boy could play!" [Chuck Berry]

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]