3

I'm doing a project that includes an Arduino Uno and custom hardware made by me. Everything is working perfectly independently, and I'm trying to implement a way for them (the Arduino and my hardware) to work together. In order to achieve that, I am using the Wire protocol (Arduino side) and I2C (custom hardware side). From now I can send data from my hardware to my Arduino in a master-slave relation, and I have no problem with that. Please take a look at my Arduino code for better understanding:

void setup(void) {
  Wire.begin(7);
  Wire.onReceive(receiveEvent);
}

void receiveEvent(int howMany) {
  int x = Wire.read(); // receive byte as an integer
  Serial.print(x);
  if (x==0) 
    state = 0;
}

So far so good. Now I want to send data from the Arduino to my custom hardware full duple, and for that I am adding this code:

void frame(void){
  Wire.write('x');
  Wire.write('\r');
}

void loop() {
  if (state == 0){
    frame();
    state = 1;
  }
}

In order to receive the 'x' char in my custom hardware I have switched the I2C protocol bit from Write to Read using I2C_FORMAT_7_BIT_ADDRESS(SlaveAddress, _address, I2C_WRITE); to I2C_FORMAT_7_BIT_ADDRESS(SlaveAddress, _address, I2C_READ); in my custom hardware code.

I don't know why, I am not receiving the data from the Arduino. Am I missing any configuration on the Arduino side?

  • Do I need any address in my custom hardware (I2C protocol) to receive data from the arduino side? – scuba Apr 4 '16 at 15:49
  • Who exactly is the master here? Who generates the clock? Full duplex means both devices can transmit simultaneously; this isnt possible with the I2C protocol. The Wire library is an Arduino implementation of the I2C protocol. – TisteAndii Apr 4 '16 at 21:49
  • The master is my custom hardware (pic32mx) and the slave is the Arduino. So the master gives the clock which is 5khz for this case. I know they can not simultaneously but i AM trying to find a way for them to work in a question-answer way. – scuba Apr 4 '16 at 21:58
1

I've not done events on an Arduino so this could be a bum steer, but shouldn't the state variable be volatile and protected with a semaphore? You are accessing it in the main program and in your event/ISR.

Secondly, no offence intended, could you replace your hardware with a bit of tried and trusted hardware to eliminate the remote possibility that your hardware is at fault.

  • No, you don't need to have a variable defined as volatile and protected to access it in the main program and in any other event/method. Let's not consider any possible problem with the hardware (which is a thing I don't believe because it's already a established product). What I really want to understand if it is possible to send and receive characters through Wire protocol as long as we have the Arduino defined as slave. I am receiving data with Wire.read and after that I am sending a chunk of chars using Wire.write but I am not getting that info in my hardware. – scuba Apr 4 '16 at 13:33
  • 2
    @scuba - in actuality, Matt's concern is probably correct. The Arduino documentation is notoriously incomplete, but arduino.stackexchange.com/questions/4477/… suggests that the event methods are called in interrupt context, which means that the state variables they share with the main thread of execution do need to be volatile. This is in contrast to something like SerialEvent() which occurs in the main thread of execution only between calls to loop(). – Chris Stratton Dec 31 '16 at 22:16
  • 1
    However it looks as if your more primary issue may be that your code would respond to the write address by sending data, when what it needs to be doing is sending data in response to the read address that triggers the request event. – Chris Stratton Dec 31 '16 at 22:19
1

You use the onReceive() and onRequest() methods of the Wire library to implement an Arduino slave. In your case, something like this:

void setup(void){
  Wire.begin(18);
  Wire.onReceive(receiveEvent);  # register receive handler
  Wire.onRequest(requestEvent);  #register request handler
  Serial.begin(9600);
}

void receiveEvent(int howMany){
  int x = Wire.read();    // receive byte as an integer
  Serial.print(x);
  if (x == 0) 
    state = 0;
}

void requestEvent(){
  Wire.write("x\r");
  state = 1;
}

See Slave Receiver and Slave Sender examples for more details.

  • How is the requestEvent is being called in this case? I already use the wire.write to send data to my hardware but I am not using the requestEvent at all. Is it really necessary? – scuba Apr 4 '16 at 23:18
  • requestEvent is called automatically whenever the master requests data from the slave. The Arduino is not in charge of the I2C bus; it must wait till the master begins driving the clock line and specifically asks for data. Only then should you use Wire.write() else nothing happens. – TisteAndii Apr 4 '16 at 23:24
  • So from my Pic side which function should I use to request data from the arduino? – scuba Apr 4 '16 at 23:41
  • The same function you would use to read data from any I2C slave; from the PIC32, you simply send the address of the Arduino slave (7, in this case) followed by a 1 to indicate a READ operation and you wait till this is sent. At this point, the Arduino receives this byte and interprets it as a READ, calls onRequest() and begins to place data on the bus. Your PIC32 reads the data byte by byte until it is satisfied and then sends the STOP condition. I assume you've worked with I2C on the PIC32 before? – TisteAndii Apr 5 '16 at 0:00
  • That's exactly what I am doing in the PIC32 side but it seems the READ operation is not taking effect in the arduino side and it's not calling the onRequest() arduino function automatically. – scuba Apr 5 '16 at 0:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.