Casting Variables for I2C

And what about the odd LED behavior?

That might be a side effect of either having 5V from the Arduinos pull-ups connected via the your 10k resistors to 3v3 or some issue with the “floating” GND rail - or something else that may only be found after the other issues are gone.

It’s also of interest what kind of blinking red there is (e.g. SOS + x slow blinks where x is of interest).

If I remember right … you can pull the I2C to 3v3 and the UNO should still deal with it ok, There must be a common gnd or there will be all sorts of odd issues!

What I was trying to get across was: If the Arduino side does pull the I2C lines up to 5V it might be problematic to feed that 5V (or what's "left" of that after the serial resistors) into the 3v3 pin.

Like this?

We are also back to value 1 = 0.00000, but still not the value desired… my LED status light is now continuously blinking green, tried getting it into safe mode but never found the cloud where it is in a good physical location to find it. Sometimes it oscillates fast cyan and fast green. Thoughts?

Im also thinking my ground wire is not connected properly… trying not to get too frustrated…

Hi guys I am still having issues and am hoping you can help. I rewired my breadboard, with a common ground going to the arduino. First question, is this ground correct? Here is an updated picture of my set up:


Second question, and hopefully this isn’t a double edged sword. Sometimes my electron will boot up, breathe cyan, and then turn solid cyan. I’ve read this is due to errors, but I’m not sure why this is happening?
Third set of questions. I am noticing my electron status change sometimes when I power on my arduino. This is fairly odd since I can’t reliably replicate this. On a couple of occasions, I noticed my arduino code is also getting hung up on Wire.requestFrom(0x8, 16); I’ve tried changing the decimal address to hex, different number of bytes requested, as well as including and excluding the optional arguments. Any help would be greatly appreciated! My arduino hangs after printing out “Br”.

Updated Arduino Master Code:

#include <Console.h> // to communicate over wifi
#include <Bridge.h>
#include <Process.h> //for gettime function
#include <Wire.h>
//int rxpin = 0;
float data =1.321;
String val_1str = "";
/*
On the Photon, Electron, P1 and Core, the I2C interface (Wire) is on D0 and D1:

DO: SDA
D1: SCL
*/
byte incomingb =100;
byte incomingc =200;
void setup() {
   // Initialize the Bridge and the Serial
  //Bridge.begin();
  //Console.begin();
  Serial.begin(9600);
  Wire.begin();  // join i2c bus (address optional for master)

  Serial.println("setup complete.*>>");

}

void loop() {
  // variables
//  incomingb= digitalRead(A4);
//  Serial.println(incomingb);
//  incomingc = analogRead(A4);
//  Serial.println(incomingc);
  int packet_size = 4; //sizeof(float);

  Serial.print("packetsz is ");  //mtp feedback
  Serial.println(packet_size);  // mtp feedback
  // send READ request to slave
  Serial.println("Br");
  delay(1);
  Wire.requestFrom(0x8, 16);  // request 6 bytes from slave device #8 , third arg is true
  //Wire.requestFrom(8, packet_size);  // request 6 bytes from slave device #8Serial.println("ARRRRR");
  Serial.println("AFTERRRR");
  int i = 0;
  char msg[32];
  float val_1 = 0.0;
  float val_2 = 0.0;
  //char* status_msg = NULL;
  
  // JOSH: Added this in b/c maybe it's not getting all the data we need.
  unsigned long t_request = millis();
//  while (i < packet_size) {
//    Serial.print(i);
//    // timeout will be performed if slave takes too long to transmit data
//    if ((millis() - t_request) > 1000) {
//      Serial.println("TIMEOUT OCCURED!!!");
//      break;
//    }
  
    // collect all data from slave (note: this may fail if master reads faster than slave writes)
    while (Wire.available()) { // slave may send less than requested
      msg[i] = Wire.read(); // read msg packet byte by byte
      Serial.println(msg[i]);  //mtp feedback
      i++;
      Serial.println(i);
      //if (i >= packet_size) {
      //  break;
      //}
    }
//  }
    
  // another print to figure out how long it took to get all the data
  Serial.print("Time taken to receive data from slave: ");
  Serial.print((millis() - t_request)/1000.0, 2);
  Serial.println(" seconds");
  
  // more prints
  Serial.print("Number of bytes read from last transmission: "); // checking if this is less than 4.
  Serial.println(i, DEC);
  
  // JOSH: Realizing that this is a messy way to convert byte array to a float :P
    // typecast the apppropiate sections on the packet
    //val_1 = (float*)(&msg[0]);          // extract first float
    //val_2 = (float*)(&msg[4]);          // extract second float
    //status_msg = (char*)(&msg[8]);      // extract string of text at the end
    
  // JOSH: This should also work
    memcpy(&val_1, &msg[0], sizeof(float));
    //memcpy(&val_2, &msg[4], sizeof(float));
    //memcpy(status_msg, &msg[8], 4);
  
  // perform all printouts
  Serial.print("value 1 is ");
  Serial.print(val_1,5);    //testing 4/27/19     
  Serial.print(", ");
  //Serial.println(val_2,5);  //testing 4/27/19    
  val_1str = String(data);
  Serial.println("val1str is "+val_1str);
  //Serial.print(", ");
  //Serial.print(status_msg);
  //Serial.print("\n");

  delay(2500);
}

This still doesn't look like the two grounds are connected. Even when both share the same USB host/supply I'd not consider this common GND.

Usually that's a sign for some deadlock situation where the device OS and the application block eachother for some reason (I2C is one of the usual suspects).

In most of your pics you have no LiPo connected. I'd suggest to always have one connected when the Electron should go online as the cellular module may require demand current in bursts that might be too much for your USB supply.

That doesn't make any differenc - just as the number eight wouldn't be any different whether you had 8 apples or 8 pears or 8 matchsticks - 8 == 0008 == 0x0008 == 0b1000 == (1+1+1+1+1+1+1+1)

@mstanley is it possible I have a combination of issues?

This GND for the breadboard should be going to the GND of the Arduino or to the Electron?

Does my Wire.requestFrom() call look correct?

Not "or". It should go to the Arduino and the Electron to be common GND for both.

2 Likes

Following up from the Safe Mode thread, I 've read that the i2C doesn't transmit the data until the Wire.endTransmission is called. Is this true? I cannot get the breathing cyan with it called.

I'm implementing the GND with a jumper wire now...

1 Like

Implemented. Current setup is below.


I've been able to get my Mode issue resolved. Took out Wire.endTransmission(), and the Arduino is still getting hung up on the Master side. I think I will still need to use wire.endTransmission() but will change my mode.
Slave Code update:

void setup() {
    Serial.begin(9600);
    Wire.begin(8); // i2c bus #8
    Wire.onRequest(requestEvent);  // register event
    Serial.println("setup complete.");
}

void loop() {
    delay(500);
    requestEvent();
}

void requestEvent() {
   
  // generate some simulated data
  //float val_1 = 11.08765; //dummy values - do not change   (random(200000) - 1000) / 100000.0;
  //float val_2 =-66.01234; //dummy values - do not change   (random(200000) - 1000) / 100000.0;
  float val_1 = +42.409671;
  float val_2 = -71.097330;
  char* val_3 = NULL;

  
  // transmit the simulated data
  //Wire.write((char*)&val_1); // respond with message of 6 bytes, SENDS CRAP DATA
  //Wire.write((uint8_t*)&val_1, 9); //TESTING // WORKS TO END OF -11.087654/113 NEED 1 MORE DIGIT
  Serial.println("val_1 is: ");Serial.println(val_1,5);
  if (val_1>1) {
    //Wire.begin(8);
    Serial.println("val_1 is ok.");
  }

  String sendstring1 = String(val_1);
  Serial.println("VAR is: "+sendstring1);
  Serial.println(sizeof(sendstring1)); // sizeof(sendstring1) is 16. verified.
  //Wire.write((uint8_t*)&val_1, 5);  // currently trying to send as data. 4/28/19
//  Wire.beginTransmission(0x8);
  Wire.write(sendstring1);  //testing sending as a string 4/28/19
  //Wire.write((uint8_t*)&val_2, sizeof(val_2));// testing 4/27/19 commented to isolate
  //Wire.write((char*)&val_1, sizeof(float)); //THIS ERRORED FROM JOSH
//  Wire.endTransmission();

//*/
}

@ScruffR what would you suggest?

I fear I have to rebuild your setup to see what’s happening first hand :blush:

BTW, why are you calling requestEvent() form loop().
This function is supposed to be triggered by the master. The slave has no business just chatting away without being asked.


I’ve tested communication between two Photons with this code and it works both directions

//#define MASTER
#define SLAVE

const byte addr = 4;
SerialLogHandler Logger(LOG_LEVEL_ALL);
char msg[32] = "dummy";

#ifdef MASTER
void setup() {
  Wire.begin();                     // join i2c bus as master
  Particle.function("send", fnSend);
  Particle.function("recv", fnRecv);
}

int fnSend(const char *arg) {
  strcpy(msg, arg);
  
  Wire.beginTransmission(addr);         // transmit to slave
  Wire.print(msg);                      // buffer data
  Wire.endTransmission();               // stop transmitting (=initiate transfer)

  return strlen(msg);
}

int fnRecv(const char *arg) {
  Wire.requestFrom(addr, strlen(msg));  // request as many bytes as we had sent before
  Wire.readBytes(msg, strlen(msg));
  Serial.print(msg);                    // print the character

  return strlen(msg);
}
#endif

// ----------------------------------------------------------------------------------------------


#ifdef SLAVE
void setup() {
  Wire.begin(addr);                     // join i2c bus with address #4
  Wire.onReceive(receiveEvent);         // register event
  Wire.onRequest(requestEvent);         // register event
  Serial.begin(115200);                 // start serial for output
}

void receiveEvent(int howMany) {
  int i = 0;
  
  Serial.printf("%d: ", howMany);       // we are expecting x bytes
  Wire.readBytes(msg, howMany);         // read them
  msg[howMany] = '\0';                  // terminate the string
  Serial.println(msg);                  // print the string
}

void requestEvent() {
  Wire.print(msg);                      // respond with message we got sent last
}
#endif

I have yet to dig up an Arduino UNO and try with an Electron.


Update:
I’ve now tested that code with Electron and Arduino UNO and it works too
This is the Arduino Master code

#include <Wire.h>

const int addr = 0x04;
char      msg[32] = "test\r\n";

void setup() {
  Wire.begin();                         // join i2c bus (address optional for master)
  Serial.begin(115200);                 // start serial for output
  
  // by this time the Electron should already be breathing cyan to receive the data
  Wire.beginTransmission(addr);         // start transmission to intended slave
  Wire.print(msg);                      // send to slave what we want to be sent back later
  Wire.endTransmission();               // finish transmission (=initiate transfer)
}

void loop() {
  int count = strlen(msg);
  memset(msg, 0x00, sizeof(msg));       // clear buffer to be sure we actually receive data
  Wire.requestFrom(addr, count);        // request back as many bytes we prevsiously sent to slave
  Wire.readBytes(msg, count);           // read all the requested bytes into buffer again
  Serial.println(msg);
  delay(500);
}

As it turns out, pull-up resistors are not needed. The Arduino’s own on-board pull-ups suffice.

Wiring:

UNO    -  Electron
 5V    -   Vin
GND    -   GND
A4/SDA - D0/SDA
A5/SCL - D1/SCL

@ScruffR,
So we are still not getting any output from the master arduino. My first troubleshooting step was to unplug and replug in the 5v-Vin wire, with no luck. I am also not getting any output from my Electron -

I call this since I am requesting the message from the Arduino and need to send from Electron to arduino. Ideally Id want to see the output from the electron but don't see it since we dont call it, or have a loop function. ( I am also using your second program directly above) ..... Why is a loop function not present on the electron?
Also, for these statements,
#define
#ifdef MASTER
#endif
I always thought of those as preprocessor commands, why are there two sets relating to #if/endif?

For kicks, I also tried your first set of code for the master, it wouldn't even compile, and threw an error on 'serialloghandler', was this defined in a library that wasn't included?

Thanks,

That's not how it's done.
As I said, the slave has no business requesting things from his master or bothering him without explicitly being told so.

The way how it's done is that the master requests the data and the slave responds and that's what the Wire.onRequest() call is for: It hooks up a handler function that will automatically be called when the request has been noticed.

That's also the answer to this question

No loop() is needed as the SLAVE doesn't do anything else but wait for the request.
And for the MASTER I have setup particle functions that will either send or request data and these are handled by the system and not by loop().
I could have added a void loop() { } but for what? So I just left it out.

Since my code above runs just fine between my Uno and my Electron I don't know what's wrong on your side.
Test my code and see (you obviously need to undefine the MASTER setting and define SLAVE in my Electron code - see below).

These are preprocessor commands. My code contains both the MASTER and the SLAVE code and depending on which of the two #define statements you have active, the respective code will be built. If you'd happen to have both active (which wouldn't be as intended) then you'd run into troubles - so keep them mutually exclusive.

That suggests that you are targeting a really old device OS version (pre 0.6.0).

1 Like

In regards to the serialloghandler, I was trying to run it on an arduino hence the error. When he uses the preprocessor commands, are those lines of code updoaded on both devices? I'm somewhat confused on that. is undefining the same thing as commenting out code?

This should be included in the slave and master correct?

Would I only adjust the line of code from
#define SLAVE
to
#define MASTER?

UPDATE I was able to get output: first upload, then subsequent up loads:
Arduino:
image
image

subsequent uploads:
(same thing for the Arduino)
image
Shouldn't I be getting the same output for the subsequent uploads? I also did not power cycle the other board when making changes to the other, does this play a factor? Why can I not get the same output as the first time I uploaded?

Thx
MP

Actually Wire.h is not needed for Particle devices - it's part of the system Particle.h which is auto-included in .ino files.

You have this in the combined code

//#define MASTER
#define SLAVE

This mean that the first line is not active so MASTER is not defined but the second line is active, so the code will build for the SLAVE

These AT command logs look like the output of the serial log handler that also prints out system. If you don't want them just comment the SerialLogHandler line.

image

In my first iteration, the count variable is 6 and then goes to zero. Why is this on the Arduino Side?

On the Particle side, I now can’t get any output to the Putty terminal. I have print statements in receiveEvent(int howMany) which are not getting invoked. Do these last two questions have to do with each other?

I also cant get the AT Serialprintlogger output to replicate that output, nor can I get it to replicate the " 6: test " in the post on May 31st. Is there a reason for this?

I can’t say anymore than that communication works for me as expected.
Sure, there can be plenty of problems, but when done correctly it just works without fail.

I have tested with an ARGON and a Arduino Leonardo

Argon APP :

#define MASTER
// #define SLAVE

const byte addr = 4;
SerialLogHandler Logger(LOG_LEVEL_WARN);
char msg[32] = "dummy";
const int testLoopDelay = 5000;
int loopCount;

#ifdef MASTER
void setup() {
  Wire.begin();                     // join i2c bus as master
  Particle.function("send", fnSend);
  Particle.function("recv", fnRecv);
}

int fnSend(const char *arg) {
  strcpy(msg, arg);
  
  Wire.beginTransmission(addr);         // transmit to slave
  Wire.print(msg);                      // buffer data
  Wire.endTransmission();               // stop transmitting (=initiate transfer)

  return strlen(msg);
}

int fnRecv(const char *arg) {
  Wire.requestFrom(addr, strlen(msg));  // request as many bytes as we had sent before
  Wire.readBytes(msg, strlen(msg));
  Serial.println(msg);                    // print the character

  return strlen(msg);
}
#endif

void loop() {
    unsigned long prevMillis;
    char buf[32];
    
    delay(testLoopDelay);
    
    sprintf(buf, "Loop count = %d", loopCount++);
    fnSend(buf);
    fnRecv(buf);

    
    
}

// ----------------------------------------------------------------------------------------------


#ifdef SLAVE
void setup() {
  Wire.begin(addr);                     // join i2c bus with address #4
  Wire.onReceive(receiveEvent);         // register event
  Wire.onRequest(requestEvent);         // register event
  Serial.begin(115200);                 // start serial for output
}

void receiveEvent(int howMany) {
  int i = 0;
  
  Serial.printf("%d: ", howMany);       // we are expecting x bytes
  Wire.readBytes(msg, howMany);         // read them
  msg[howMany] = '\0';                  // terminate the string
  Serial.println(msg);                  // print the string
}

void requestEvent() {
  Wire.print(msg);                      // respond with message we got sent last
}
#endif

Leonardo Sketch:

#include <Wire.h>

//#define MASTER
#define SLAVE

const byte addr = 4;
//SerialLogHandler Logger(LOG_LEVEL_ALL);
char msg[32] = "dummy";

#ifdef MASTER
void setup() {
  Wire.begin();                     // join i2c bus as master
  Particle.function("send", fnSend);
  Particle.function("recv", fnRecv);
}

int fnSend(const char *arg) {
  strcpy(msg, arg);
  
  Wire.beginTransmission(addr);         // transmit to slave
  Wire.print(msg);                      // buffer data
  Wire.endTransmission();               // stop transmitting (=initiate transfer)

  return strlen(msg);
}

int fnRecv(const char *arg) {
  Wire.requestFrom(addr, strlen(msg));  // request as many bytes as we had sent before
  Wire.readBytes(msg, strlen(msg));
  Serial.print(msg);                    // print the character

  return strlen(msg);
}
#endif

// ----------------------------------------------------------------------------------------------


#ifdef SLAVE
void setup() {
  Serial.begin(115200);
  while(!Serial);
  Serial.print("\nSetup....");
  Wire.begin(addr);                     // join i2c bus with address #4
  Wire.onReceive(receiveEvent);         // register event
  Wire.onRequest(requestEvent);         // register event
  Serial.begin(115200);                 // start serial for output
}

void receiveEvent(int howMany) {
  int i = 0;
  Serial.print("\nReceive data ");
  Serial.print(howMany);                // we are expecting x bytes
  Serial.print(" bytes [");
  Wire.readBytes(msg, howMany);         // read them
  msg[howMany] = '\0';                  // terminate the string
  Serial.print(msg);                  // print the string
  Serial.print("]");
}

void requestEvent() {
  Serial.print("\nSend reply to request....");
  Wire.print(msg);                      // respond with message we got sent last
}
#endif

void loop() {
  
}

Screen shot of both serial monitors (Argon on top, Leonardo below)

Connections

ARGON SDA/SCL through 3v3-5v level shifter to Leonardo and GND to GND

All working as expected. so the issue is not in @ScruffR sample code - perhaps post your code and we can review?

1 Like