I was looking over the i2c functions in the documentation and couldn’t see a way to set up the daisy as an i2c follower, it seems permently set to leader. (side note, I would prefer we use leader/follower terminology than master/slave in this thread).
I would love to be able to control my daisySM via i2c from modules like Teletype or Crow, which send data or queries as leaders over i2c to other modules such as er-301, mannequins just friends or w/, and various expander modules.
Does this i2c follower functionality exist or would it need to be added?
There are a few missing pieces to get this mode to work though, i.e. you’d have to call HAL function to listen for master’s requests and add a callback that handles them. I had some POC code to get OWL firmware to exchange data with Teletype (on F4 MCU) before and I don’t see anything that would make it impossible to do the same with libDaisy.
IIRC, you can’t simply use DMA callbacks instead of listening for transaction end because ii protocol has commands of varying length, so you can’t tell how many bytes to expect.
It’s highly recommended to use a logic analyzer for troubleshooting I2C transactions. Don’t expect debugging to work as it won’t prevent master device from sending data, you’ll just get buffer overrun failures if you pause firmware.
At this point, I believe the I2C peripheral is fully realized in the sense that you can do transmit, and receive in either leader or follower modes.
However, there aren’t any examples of using the daisy in a follower mode, and the existing devices in the library all connect to daisy as followers (leddriver, oled, etc.).
Having an interface to be able to read controls from something like a Teletype, etc. would be very cool!
As @antisvin mentioned, you wouldn’t be able to take a pure-DMA approach since you wouldn’t know how much data to be expected. I’m not familiar with what those devices send out, but doing some sort of hybrid blocking/dma approach could work if the initial transaction can tell you what to expect in future transactions.
Starting with a blocking-only approach to verify the protocol would probably be the easiest path forward in anycase.
Also, I agree that a logic analyzer can be a huge time saver when working with i2c. Side note, it would be a cool project to make a little logic/i2c analyzer out of another daisy.
My only interaction with coding teletype i2c stuff so far has been with using it with wire.h in Arduino, for creating little teensy based expanders. Obviously Arduino makes a lot of this stuff quite approachable though so the process may be more involved than I expected on a daisy. Good to know it’s possible though.
Ok I’ve found my experiments, so actually I was using interrupt-based transfers, but the challenge was to figure out how to setup the whole I2C exchange as a state machine. In case if anyone would ever dare to touch this, it goes like this:
Init peripheral, set address, enable listen interrupt
HAL_I2C_AddrCallback calls HAL_I2C_Slave_Seq_Receive_IT or HAL_I2C_Slave_Seq_Transmit_IT depending on TransferDirection parameter
HAL_I2C_SlaveRxCpltCallback updates ringbuffer to mark amount of bytes read as hi2c->XferSize - __HAL_DMA_GET_COUNTER(hi2c->hdmarx)); , HAL_I2C_SlaveTxCpltCallback does the same with another handle/buffer
HAL_I2C_ListenCpltCallback fires last and you have to re-enable listen interrupt in it
Like I’ve said, I’m fairly sure that DMA transfer was not be firing until the requested buffer was filled, so it was not usable for RX. I suppose it’s still possible to use DMA TX as in this case we know the number of bytes to be sent. But Teletype typically sends very short messages, the overhead of setting up DMA transfers likely makes it not worth it.
this is also on my roadmap, i’ve got my thing talking to crow now, but would like to be using it as a follower. going to look into what @antisvin mentioned and if i get anywhere with teletype i will report back.