I encountered a strange behavior while running 2 way transmission tests between 2 Arduino Zero (ATSAMD21G), one master and one slave. Wrong data is being continuously transferred both ways. The expected data is also being transferred in between. I have to filter out the received data to catch it (line 41 in Master's code and 33 in slave).

I'm using the stock wire libraries (being different for the 2 boards), along with Nick Gammon's "I2C_readAnything".

Master's code

Slave's code

I think this continuous flow doesn't allow the bus to be released. It might be what's making it impossible to communicate with a second master (and maybe causing my previous problem)

I also tried my code between a Mega 2560 (slave) and a Zero (master). Fake data is, this time, only being sent one way (from the Zero to the Mega only).

Is there some specific code to add to send data properly from ATSAMD boards? Is it a bug in the SAMD Wire library?

I also had to add a 1ms delay after sending data from the Master. It wouldn't go through otherwise. Shouldn't it be handled by the ATSAMD or the Wire library?

2 Answers 2


The code had several issues.

receiveEvent, on the slave side, contained a millis if condition timer that made it time out. I moved the timer to the master side before calling Wire.requestFrom.

receiveEvent, on the slave side, was also confusing real data with incoming requestEvent. I added an if statement to compare the receiveEvent data size with the expected size. Half of the data was wrong without this filter (this should ideally be handled in the Wire library)

I set the global variables used in events as volatile. The code is working too without this tho.

fixed Master code

fixed Slave code

  • The Slave I2C clock is 100kHz, the Master has 800kHz. Start with the most normal settings, that means also the Master at 100kHz. The return values are not tested in the Master. I think in this situation you should test them. In the Slave you could test the howMany and increment an error counter if it is not right. The I2C bus is not fault tolerant, that means it should always work 100%. If it is unreliable, you should fix it. How long are the wires ? When you connect a 3.3V board via I2C to a 5V board, did you use a level shifter ? Did you connect the GND's of both boards ?
    – Jot
    Commented Feb 26, 2017 at 16:06
  • Do you mean the remaining wrong data I'm filtering out with by testing howMany shouldn't be there? When I test it like you advise, I see it's half of the receiveEvent (not a continuous flow anymore, so it's good enough, the bus gets released after each transaction so multimaster is working too now). That's why I think it's confusing requestEvent with data. I'll understand more once I get my logic analyzer.
    – kb_
    Commented Feb 26, 2017 at 23:35
  • The Master sets I2C bus speed. The slave's code doesn't contain speed setting. 800 kHz works fine between 48 MHz Nano but too much with the Mega. The wires are less than 1 m long. I'm using a level shifter between the Nano and the Mega. All on same GND. I'll add a test on the data content in my final application for extra safety.
    – kb_
    Commented Feb 26, 2017 at 23:35
  • I don't care if 800kHz worked in the past. You have to fix a number of problems, therefor returning to 100kHz would be wise. If everything works fine, you could try higher clocks speeds. But you are not there yet. The I2C communication should work 100%, not 99%. When the howMany is only half of the receiveEvent okay, then your I2C communication is working 50%. You have to fix the problems to make it 100%. Start by using the default I2C clock speed of 100kHz en test the return values in the Master. Maybe you could also store the howMany in a variable when it was wrong and print that variable.
    – Jot
    Commented Feb 28, 2017 at 0:30
  • Same @100kHz. howMany = 0 for half of the receiveEvent. For these, Wire.read returns -1, meaning no data.
    – kb_
    Commented Feb 28, 2017 at 20:06

Start with a single byte, with a very small sketch, with both the Master and the Slave at 100kHz. When that is working 100% reliable, then you can try to transfer a struct.

The Slave RequestEvent function should always return valid data, not once every two seconds. The global variables that are used in receiveEvent or requestEvent and in the loop() should be made 'volatile'. Disable the interrupts in the loop() when reading or writing the global volatile struct.

With your sketch, you have to open the serial monitor for both the Master and Slave.

You could add more tests, for example testing the return value of Wire.endTransmissing, testing the 'howMany' parameter, testing the actual number that Wire.request returns.

  • I simplified the code to test with a single byte 2 way transfer @100 kHz, using volatiles in events like you advised. I'm still seeing the same behavior (after opening monitor on both of course). Transferring one way only is working properly. Adding more tests sounds to me that it would only hide that fake data is flowing between the devices (like the filtering I did in my initial code). I have to avoid disabling interrups because my final application relies on them (PID motor control and encoder reading...)
    – kb_
    Commented Feb 25, 2017 at 13:41
  • Result on slave: "Arduino connected ... ÿ ÿ m ÿ ÿ ÿ ..." (should get "m" only; same behavior on master side) Master / Slave / One way only Master
    – kb_
    Commented Feb 25, 2017 at 13:42
  • I figured out what didn't work in the simplified test. The millis delay in requestEvent was causing it to timeout. I put this delay before requestFrom in the master instead. I have to test the "howMany" parameter in the receiveEvent so it doesn't confuse incoming data with a requestEvent. This should be handled by the wire library in my opinion. Fixed code
    – kb_
    Commented Feb 25, 2017 at 14:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.