I2C in the Arduino environment is probably one of the simplest things to get working. And frustrating... the behaviour of the write() command within the protocol doesn't even come close to following it's own conventions, let alone those of I2C (which are sloppy, at best).
Case in point: I was just debugging an I2C conversation between the Max32 as master (which uses receive() instead of read() - don't get me started...!) and the Leonardo as slave, with the objective of moving the code on the Leo to an AT Tiny 84 later on.
It wasn't working... I requested 5 bytes, and got 5 "ÿ" characters.... W.T.H.?
My terminal session on the Max32 wasn't line wrapping, so I decided to also send a "\n" which is a newline character. I was getting the occasional valid character, depending on how I structured the sender, but mostly it was a long string of "ÿ". Stunningly, that worked the first time, every time.
So I was getting invalid garbage, and a valid newline character. Weird.
I went looking for this mysterious looking lower-case-y character (it came out as either -1 or 255 if I displayed the ascii code for it) and found this post that had the answer: You can't do multiple writes from the onrequest slave to answer a single request.
So if you think you should be doing a beginTransmission, writes, and an endTransmission in the slave to send bytes as a response... nope.
Just one single write().
That little gem is actually buried on one of the first articles I read on I2C on the Arduino, so it shouldn't have been a surprise to me:
It's a bit of a long read, but I2C is a bit of a confusing mess, since there protocol is somewhat open-ended.