Since my last post lead me to work with I2C, I am very curious to know about it’s limitations and have a couple questions/scenarios that I’d like to understand if anyone can shed some light on them I’d really appreciate it
I know that Wire.write can read a string, such as:
Wire.write("this works ");
But why doesn’t this work? :
'2. Does Wire.write() or Wire.read() have a limitation? Is there only so many bytes they can send or read?
For instance I had two Cores communicating through I2C the Master Core - Writer sending a 78 byte length char and the Slave Core - Reader was reading as such:
From the first Serial.print line I get that 32 bytes are available and in my second Serial.print line I only get the first 32 bytes of the 78 byte string? Make me lead to believe there can only be so many bytes read with Wire.read(); OR I am writing to the I2C bus before the Wire.read(); is finished?
Your first question about why Wire.write(“a string of chars”); works but it does not work with String objects is pretty easy.
First off, in Arduino land, print methods are for user-readable string data and write methods are for binary data that is not generally user-readable. This is important since char* strings use a zero byte to indicate the end of the string and therefore the print method could not easily send a zero but the write method can. They serve different purposes.
The Wire (TwoWire under the hood) class has a couple of write methods for numeric types (integers) and uses the Print class’s write method for const char* strings, so that is why the first one works. The Print class has a write method for this type of string that just finds the strlen() and calls write( (cast)str, len ); So this is what happens:
So the Print class has print methods for String objects but not a write method because the expectation is that user-readable strings should be “printed” and not “written” in the Arduino/Spark wiring language.
Since you can access the underlying char* string from String objects on Spark with the c_str() method, you can do this:
String dataString= "" ;
dataString += String ("Why not?");
// OR this which is exactly what is happening (assume string is not empty):
Wire.write((const uint8_t *)dataString.c_str(), strlen(dataString.c_str()));
I don’t know why you can’t transfer more than 32-bytes at a time. In theory i2c does not have a transfer size limit but SMBus does have 32-byte limit.
I am not sure why you would choose i2c for connecting two cores together, but you must have reason. Serial and SPI would be the obvious other choices.
As for the 32byte limit.
The reason for this might be that in spark_wiring_i2c.h the BUFFER_LENGTH is defined as 32.
So even if you request more than 32 bytes, the length will be clipped to 32 and Wire.read() will not actually request more bytes, since it doesn’t actually do any I2C communication but only gives you back the bytes that were read into the buffer by a previouse request or have been sent by the master, who’s buffer will also only be 32 byte in case of a Core as master.
Okay the reason for number one makes sense thanks for clearing that up!
I’m using I2C because it was a suggested alternate solution to a problem I had from a previous post:
I have an offline master core collecting data and writing to my slave core which reads the incoming data, and it all happens automatically without me needing to input commands like in Serial command (unless maybe there is a way without user intervention?) and SPI I would have to say I’m still foggy with but would gladly look into if it’s an alternate solution!
This was a major concern for me because I for sure will be sending more than 32 bytes at a time, so thank you for clarifying. Maybe I could do send the 72-80 bytes(max) over 32 bytes at a time and just assemble the string in chunks on the slave core side? OR is it possible to actually change BUFFER_LENGTH to a higher number?
@UST, if I recall in that other post, I suggested I2C or Serial. Using serial would give you a much more flexible solution for your data transfer since Serial is a stream and simple to work with. You wifi Core would send a request to your logging core and then listen for and assemble the data to send over wifi as required as long as data keeps coming from the logging core. It’s the least complicated way to do it. I2C is more suitable for short command/data messages designed for a multi-slave configuration.
and yes @peekay123 you did suggest both , sorry bout that! But I understood the Serial route as making user defined commands that you call through a Serial terminal? Okay I have some major digging to do, but glad that I learned I2C (to some extent) anyway!
Any good links I could look at to get me started? Thanks again
@UST, I agree, serial should be the way to go for you, but as I got the impression that you are still at the beginning of your journey with the Core and C and serial communication, I’d suggest you just do some very basic serial communication to get the grip on what’s going on at the basic level, before you’d try to plough your way through any library too sophisticated without the basics.
This said, @peekay123 's link in the post above will give you a nice and easy start before you decide to look at ArduinoSerialCommand.
You’re a champ @ScruffR thanks a lot for the message.
As I am new to all the things you said, I felt I had an understanding of Serial comm so I just tried shoving in what I thought would work into my current project and got 90% of the way there. Spent hours getting frustrated because things were not working as I had expected! But I went to the basics doing test apps so I can understand what is happening and why during Serial communication between two Cores.