I spent a couple of days writing code to use an Arduino Nano & Arduino Mini as an I2C slave (5V, 16MHz devices), in order to learn about the IDEs, debugging tools, logic analyser, etc.
In case my findings are useful to anyone, I put them in a pdf (attached).
Note - the use case I was coding for isn't well suited to the Wire library (e.g. I didn't need to copy data between buffers, but Wire does that anyway).
Wire might be a much better fit for your use case.
Also - this is my first attempt at coding using the Wire library, or using Assembler on the ATMega, etc. So take my code with a large pinch of salt!
I wrote an I2C master on an Arduino Nano to create a standard test-bed, and then wrote 3 sets of I2C Slave code:
1. Using C and the WIre library, programming using Arduino IDE
2. Hand-coding the C interrupt routines, using Arduino IDE
3. Writing the whole thing in assembler, using Atmel Studio 7 (so bare metal - no Arduino background code).
I analysed the timing of the results using a simple logic analyser. They are interesting:
a. To quantify the timing advantage/disadvantage of each approach
b. Particularly for the Wire library - to see it actually working.
Below is the trace of the I2C slave using the Wire library.
The 'Main Code' pin toggles when the ATMega is executing the main code loop.
The 'Interrupt' pin is high when the ATMega is executing my callback routines to process the I2C requests.
You can see where the Wire library is handling the I2C communications invisibly (via interrupts), and where it is hitting the callback routines.
(Ignore the break in main-loop around 530us. I assume this is a background Arduino interrupt, such as a Timer).
I hope it might be useful / informative.
Any feedback on code, timings, etc. is welcome.