Does writeing to messageBuffer count as accessing outside the ISR? i cannot figure out why i cant declare it as volatile. Also i cannot declare the struct as volatile, is it okay to just declare each member of the struct as volatile instead of the whole struct. How do i declare all members of struct at once
The .readBytes() is from the stream class and it is not meant for I2C data. It can be used, but I would add a extra safety check.
The .readBytes() together with a memcpy() is a extra copy that is not needed.
Wire.beginTransmission(0x50);
Wire.write(0x01);
Wire.endTransmission(); // <-- a "false" as parameter is here often used
Wire.requestFrom(0x50, sizeof(sms1));
if (Wire.available() == sizeof(sms1)) // is all the data received ?
Wire.readBytes((byte *) &sms1 , sizeof(sms1));
The I2C bus is not a stream of data, it is packages of data.
The .readBytes() is from the Stream class and has a timeout with millis() because it is used for a stream. That timeout can get in the way when using the Wire library.
My solution is as shown, check the number of bytes that are available and then use .readBytes() to read those bytes. That avoids that the timeout kicks in. If you disagree, can we do that discussion somewhere else ? I don't want to confuse notsolowki.
I think i was definitely wrong about i2c sending 32byte packets. After checking again. I discovered they are 8 bit packets and each are followed by an ack.
In this case, technically no because Wire.requestFrom(0x50, sizeof(sms1)); is synchronous.
When you return from that call, the data is already in the Wire buffer so timeout won't be an issue there. You could actually just check the returned value of Wire.requestFrom() and if it's not 0 then assume all was right
By synchronous i think you mean "Wire" is going to wait for response so everything else will be blocked anyways?
I was under the impression that if you access a global variable outside/during the ISR at any point that it would need to be volatile. But it appears my logic is wrong. At what point would the members of the struct need to be declared volatile?
yes. if that was not the case you could not read the data with just one if (Wire.available()) you would need a while loop to extract all the expected data
volatile is the safe way to ensure the compiler does not do funny optimisations and keep the data in a register whilst you read it from memory elsewhere. ➜ all reads and writes actually go to memory and any cache is not assumed valid
volatile does not guarantee atomicity though, so when working with multi-byte variables and an ISR, you need a critical section where you copy or handle the data.
here you pass a buffer to the Wire library, which indeed uses interrupts to get the data back but your main code does not do anything until the data has been read, and once read the ISR has no chance to run and mess with the buffer (until you ask for it). So there's no need for volatile or critical section.
to your question, nothing in the code calls readSubModule() so the optimiser just gets rid of it
No. It is never used in an interrupt service routine.
In fact, most of your code is largely unused, and there is no code that is executed in an interrupt context.
The volatile here applies to the void return type, it has no effect on the readSubModule function itself. A return type of volatile void is meaningless.
Okay then im afraid i still have some confusion. i read what volatile does to the compiler and i understand that. But some how i dont see the logic of using it.
For example flow sensor code,
uint32_t flow2 () // Interrupt function
{
flow_frequency++;
}
the above function called by and interrupt. Then flow_frequency need to be volatile?