Pages: [1]   Go Down
Author Topic: I2C RequestFrom isn't working between arduinos.  (Read 1313 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 21
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

For a start I had several I2C devices already connected to including DS1307 RTC. I wished to add an arduino as a slave device to existing I2C bus. On master side I didn't change any code, as it was already working perfectly, regarding I2C protocol. On slave I tried to make it behave similar to other slave devices which have addresses and 16bit registers inside I could read and write.
The result is somewhat confusing. Sending data from Master to Slave just works perfectly. But when Request comes from Master, Slave receives first byte which is register pointer and sending fails. No matter what slave sends, Master receives 2 bytes - one is 0 and other is 255. Meanwhile the same routine is working perfectly with other I2C devices.

I2C bus works ok, as other devices are unaffected and sending data from slave to master works.
Code on Master side should be ok as well, as other devices use the same code and work.

code on the slave side looks like this:
Code:
#include <MemoryFree.h>
#include <avr/wdt.h>
#include <Wire.h>   // include Wire library for I2C

/*
  Blink
  Turns on an LED on for one second, then off for one second, repeatedly.
 
  This example code is in the public domain.
 */
  //Global variables defined here
  byte datain[9] = {};
  long unsigned int lastmillis = 0;
  long unsigned int millisnow = 0;
  int x = 0;
  int blinktime = 200;
  byte dataOut = 210;
  //Registers for I2C
  int I2C_register[8] ={72,9400,20202,-17432,44,-8433,18,777};
  boolean dataready = false; // data is not ready for sending
  boolean receiveddata = false;
  boolean senddata = false;
  boolean address_data = false; //if false it means address if true it means data
  byte bytes_count = 0;  // how many bytes are available?
  byte reg_pointer = 0; //register pointer - which register to use for read or write
  byte bytes_requested = 0;

void setup() {
  wdt_disable(); 
  Wire.begin(9);                // Start I2C Bus as a Slave (Device Number 9)
  Wire.onRequest(sendRequest); // this is interrupt - code must be extremely small Data must be sent
  Wire.onReceive(receiveEvent); // Data must be received.
  // initialize the digital pin as an output.
  // Pin 13 has an LED connected on most Arduino boards:
  pinMode(13, OUTPUT);   
  Serial.begin(9600);
  wdt_enable(WDTO_8S);   // set the wdt on 8 sec
  Serial.print("freeMemory()=");
  Serial.println(freeMemory());
}

void loop() {
  ledblink();
  data_receive(); //check if there is any data to receive
  data_send();    //check if there is any data to send
  wdt_reset(); // reset the wdt
}

// There is data received. Interrupt handler
void receiveEvent(int howMany) {
  bytes_count = howMany;
  receiveddata = true;
}

// There is a request to send data - interrupt handler
void sendRequest()
{
//  bytes_requested = howMany;
  senddata = true;
}


void ledblink() {
  millisnow = millis();
  if ((millisnow - lastmillis) > blinktime) {
    if (digitalRead(13) == LOW) {
       digitalWrite(13, HIGH);   // set the LED on
    }
    else {
      digitalWrite(13, LOW);    // set the LED off
    }
    lastmillis = millisnow; //start a new cycle of one second
  }
}

void data_send(){
  if ((senddata == true) && (address_data == true)) {
  uint8_t dataOut[6] = {22,33,44,55,66,77};               
  dataOut[0] = highByte(I2C_register[reg_pointer]);
  dataOut[1] = lowByte(I2C_register[reg_pointer]);
  //byte* datapointer = &(dataOut[0]);
  Wire.send(dataOut,2);
    Serial.print("Bytes requested: ");
    Serial.println(int(bytes_requested));
    Serial.print("from register: ");
    Serial.println(int(reg_pointer));
    Serial.print("data sent: ");
    Serial.println(I2C_register[reg_pointer]);
    Serial.println(int(dataOut[0]));
    Serial.println(int(dataOut[1]));
  address_data = false; 
  reg_pointer = 0;
  senddata = false;
  bytes_requested = 0;
  }
}

void data_receive () {
if (receiveddata == true) {
  Serial.print("How many: ");
  Serial.println(int(bytes_count));
  byte i = 0;
  while(Wire.available())   //read until buffer is empty
  {
    datain[i] = Wire.receive(); // write received data to array
    i ++;
  }

  // if one byte is received then it is a address of register, if 3 bytes, then data after first byte
  // must be combined into word and written to register pointed to in the first byte
  reg_pointer = datain[0];  //write received register pointer
   Serial.print("Register chosen: ");
   Serial.println(int(reg_pointer)); //show register number
  if (bytes_count == 1) {  //if incoming data is address, it is written to register pointer
    address_data = true;  // next byte is data either incoming or outgoing.
  }
  if (bytes_count == 3) {
    I2C_register[reg_pointer] = word(datain[1],datain[2]);
    Serial.print(" received and written data: ");
    Serial.println(I2C_register[reg_pointer]); //show data received and written to register
    reg_pointer = 0; // set register pointer to default after receive is finished
  }
  bytes_count=0;
  receiveddata = false;
 
  }
}

Any suggestions?
Could there be some timing problem on master side?
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 485
Posts: 18806
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I got I2C working between two Arduinos as described here:

http://www.gammon.com.au/forum/?id=10896

The difference between what you did is that I responded in the interrupt routine (the Wire.onRequest function). I suspect that deferring the response as you did results in either the chip (or library) switching to a different mode, or it just being too slow.
Logged


0
Offline Offline
Newbie
*
Karma: 0
Posts: 21
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Placing sendrequest code into interrupt routne didn't help.

Will check other possibilities.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 485
Posts: 18806
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Well, the code I posted in the link works. So you must be doing something somewhat differently. Can you post your amended code? Hopefully you took out the Serial.print stuff from the interrupt routine, that would seriously slow it down.
Logged


0
Offline Offline
Newbie
*
Karma: 0
Posts: 21
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

yes, I removed serial.prints from interrupt routine. Tried to request single byte and 5 bytes, neither worked. Wire library has poor explanation. Some tricks I had to find out from forum.
So far I haven't found any example sketches that use Wire.RequestFrom()

On the master side code looks like this:

Code:
unsigned int I2Cread(byte chipadress, byte dataadress) {
    unsigned int data;
    Wire.beginTransmission(chipadress);
    //Writing a starting address to DS1307
    Wire.send(dataadress);
    Wire.endTransmission();
    // request of data from addresses given
    byte bytes = 5;
    Wire.requestFrom(chipadress, bytes);
    Serial.print("bytes available ");
    Serial.println(int(Wire.available()));
    byte highbyte;
    byte lowbyte;
        highbyte = (Wire.receive());
        lowbyte = (Wire.receive());
    data = word(highbyte, lowbyte);
  return data;
}
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 485
Posts: 18806
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

So far I haven't found any example sketches that use Wire.RequestFrom()

Apart from the ones I gave in my link, right?

Can you post the slave code now please?
Logged


Denver
Offline Offline
God Member
*****
Karma: 20
Posts: 779
Inactive - PM
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
So far I haven't found any example sketches that use Wire.RequestFrom()
There are 4-5 examples already loaded in your IDE under your wire library. Slave Receive, Slave Transmit, etc.

I believe that the slaves response is in the same "session" as the master's request.  Therefore you must respond quickly (or do "pulse stretching" to make the master wait longer.
Logged

"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll

Pages: [1]   Go Up
Jump to: