I had a problem communicating an nodeMCU with an Arduino Pro Mini with I2C.
To find the culprit, I finally wrote an Echo Server in Arduino: it receives a byte and responds the same byte. In the nodeMCU I wrote a test program: it sends bytes to the Echo Server and verifies the response, in addition to any error conditions in the Wire
methods.
Both processors are connected GND-GND, VCC-VCC, SDA-SDA and SCL-SCL. SDA and SCL have 10K pull-up resistors. Both are connected via USB to my PC, and I have two serial monitors to trace the execution.
In the tester program line 38 there is a delay(1)
. If you comment it out, some requestFrom()
fails randomly with return value != 1, but the Echo Server still received the byte.
As ATmega328 included TWI in the silicon, I can't understand what is failing here and why delay(1)
seems to solve the problem. What I'm missing here?
The tester program
/*
* Echo Server Test
* Send one byte to the Echo Server and read it back.
* Do it for bytes from 0x01 to 0xDD
*/
#include <Wire.h>
#define SLAVE_ADDRESS 42
byte car = 1; // car to be send to the Echo Server.
void setup() {
Serial.begin(9600);
// We have a nodeMCU con I2C on pins D5 and D6.
Wire.begin(D5, D6);
delay(1000);
Serial.println("");
Serial.println(" Echo Server Tester");
Serial.println("---------------------");
Serial.println("### Sent Received");
delay(1000);
}
/*
* Send one byte in each loop().
*/
void loop() {
byte status;
if(car > 0) {
do {
Wire.beginTransmission(SLAVE_ADDRESS);
int written = Wire.write(car);
status = Wire.endTransmission();
switch(status) {
case 0:
delay(1); // Comment this out and watch requestFrom() fails.
if(Wire.requestFrom(SLAVE_ADDRESS, 1) == 1) {
byte r = Wire.read();
printChar(car, r);
car++;
} else {
Serial.println("error in return");
status = 4;
}
break;
case 1:
Serial.println("Data too long");
break;
case 2:
Serial.println("NACK on address");
break;
case 3:
Serial.println("NACK on data");
break;
case 4:
Serial.println("Some error");
break;
}
}
while(status != 0);
}
}
/*
* Utility: print in bytes sent and received
*/
void printChar(byte s, byte r) {
Serial.print(s);
Serial.print(" ");
printBits(s);
Serial.print(' ');
printBits(r);
if(r != s) {
// Mark invalid responses.
Serial.print(" *");
}
Serial.println();
}
/*
* Print a simple byte in binary
*/
void printBits(int car) {
byte bit = 0x80;
for(int i = 0; i < 8; i++) {
int digit = car & bit;
Serial.print(digit ? '1' : '0');
bit >>= 1;
}
}
The Echo Server program
/*
* I2C Echo Server
* Receive one byte from Master, echo the same byte to Master.
*/
#define MY_ADDRESS 42
#include <Wire.h>
volatile byte received;
volatile int count = 0;
void setup() {
Serial.begin(9600);
Wire.begin(MY_ADDRESS);
Serial.println("--- Echo Server ---");
Wire.onReceive(receiveCommand);
Wire.onRequest(sendAnswer);
}
void loop() {
static int lastCount = 0;
if (count != lastCount) {
Serial.print(lastCount + 1); Serial.print(" ");
printChar(received);
lastCount++;
}
}
/*
* Receive a byte from Master
*/
void receiveCommand(int howMany) {
received = Wire.read();
count++;
}
/*
* Send a byte to Master
*/
void sendAnswer() {
Wire.write(received);
}
/*
* Utility print byte received/sent
*/
void printChar(byte car) {
Serial.print("Char ");
byte bit = 0x80;
for (int i = 0; i < 8; i++) {
byte digit = car & bit;
Serial.print(digit ? '1' : '0');
bit >>= 1;
}
Serial.println();
}