I am working on a general purpose command interpreter over I2C. For robustness reasons, I want the commands to be checksummed, and the slave should NACK any command with mismatched checksum. Is there a arduino I2C library suited for checksum calculation and ACK/NACK handling before the message ends, or do I have to take an existing library and modify it to suit these requests?
You could do it manually. After sending the command with a Wire.write(x), do a Wire.requestFrom(x) asking for the checksum. If they don't agree then try again. The slave would receive the command with Wire.onReceive() and return it's calculated checksum with Wire.onRequest().
PS
The slave could compare the checksums and return a single byte true, 0x0f, or false, 0xf0. Using several bits in the returned value help solve the problem of that byte being corrupted on return.
guenter_n, you mention a number of things, and they conflict with each other. I will try to explain.
Suppose the Wire library can be changed (I think it can), but then both the AVR and the SAM version have to be changed. And also the TinyWire and other compatible libraries. With every new version of Arduino, you would have to check if the modified library is still compatible. Then your library would no longer be "general purpose".
The same happens when you use a library by someone else who added a checksum. That library might work for the ATmega328P and for nothing else.
The I2C bus is not a RS-232 serial bus. It is the I2C bus. Suppose one in a million commands can go wrong, then the I2C bus is bad and the hardware has to be fixed.
What if the i2c address goes wrong due to a glitch ? or the NACK by the Slave goes wrong, or the Slave sends a ACK and it is received as a NACK.
The Wire library has been recently updated, it should be capable to detect a collision from multiple Masters. However, the I2C hardware must still work 100%.
If it makes you feel better, you may add a checksum. If the Slave has a mismatch, just ignore that command, or return the checksum with a new I2C transmission as Arctic_Eddie wrote.
To be sure that data is transmitted, you must check the return value of every Wire.endTransmission() and every Wire.requestFrom(). Did you do that already ? That is the best way to check if the I2C transmission was okay and was ended in a proper way.
Thank you for the answers.
I was hoping for an existing alternative to Wire, which already can do what I want, but probably there is no such thing.
I already have a plan how to modify the Wire library to do what I want. The checksum verification will, of course, not be in the library, but in the callback on the slave receiver. I just have to make the library call this callback after each byte, not as it is now after the message is finished. And I need a way to signal the library, from the callback, that the received data is not OK. Then the modified Wire library will send a NACK, just as it does now when the received data does not fit into the buffer.
Of course the master has to check the result of endTransmission to know if something went wrong, but that's already done
Could you think this over once more ?
The I2C bus not like the Serial bus as I wrote. A checksum does not solve all the communication errors. Maybe only 50% of the errors (the more I think about it, the smaller the percentage is getting). There should be no errors in the first place.
If you use a modified Wire library, your "general purpose" library will become a "it will work for one or two year for just a one specific microcontroller" library and almost no one will use it.
I2C, SPI, I2S, etc... are all designed for internal communication between chips in a device. They do not need checksums, because they are supposed to be used in "disturbance free" environment.
To make an easy comparison : there is no checksum mechanism on parallel busses of microprocessors. You get the data you read on the bus, you assume it's not corrupted.
If you think that data can be corrupted on the I2C, then you have a two explanations:
your electronic design is not clean enough (EMI compliance). Then not only I2C will be disturbed, but also everything else in your device. Avoiding errors on I2C will not solve anything. Note that I do not mean to be rude here, I just want to explain why you shall have no error on the I2C
you are using I2C outside of its nominal scope (like communication outside of a device). Then the I2C bus is exposed to external EMI, and it is simply not designed for that. You have two possibilities then: either you "enhance" your I2C design (like using shielded cable, or bus extender chips) to make it "harder", or you use a communication bus which has been specifically designed for this (like CAN), but then it's no more I2C
Thank you for the answers. Well, the intended use is for interconnecting a few arduino or ardunino-like boards inside a box, which are a few cm apart, so this should be adequate for I2C. But it will be used in an industrial environment, so noise is not really avoidable.
For now I will add the checksum, and if there will really be problems, I am thinking about RS485.