Introduce a generic STM8 I2C Master API
TG9541 opened this issue · 8 comments
I2C has long been a mainstay of small-scale control system composition and integration. Even as most modern µCs provide I2C peripherals that are compliant with the "NXP I2C-bus specification and user manual", bit-banging I2C following the timing diagrams and command descriptions in a peripheral datasheet is still common (I can only speculate about the reason but not referring to the standard in the hope of avoiding IP property "discussions" might be one of them - and "a loved child has many names").
This issue introduces "STM8 eForth platform support" for the STM8 I2C peripheral for the "single master" use case (both the mandatory and the optional features in Table2 of the manual). The optional feature "10-bit slave address" will be implemented as a special case of "7-bit" addressing).
Both "Standard-" (100kbit) and "Fast-mode" (400kbit) will be supported (using the 16MHz HSI the limit for "Fast-mode" is 381kbit).
Error detection shall cover the cases detectable by the I2C peripheral (the NXP I2C manual lists some cases where a hard reset of I2C network nodes is recommended - these are out of scope).
See: https://www.i2cchip.com/pdfs/BL233_Datasheet.pdf
Section 19 I2C Bus Deadlock
Bit banging is still common because:
- The hardware often has either bugs or ill thought out gotchas rendering it worse than bit bashing. (Yes Atmel, looking at you)
- Bit bashing allows any pin, and multiple busses
- Many uses are pretty much blocking anyway, so your cpu has nothing better to do.
@sbridger I guess that there are many reasons for not using an I2C peripheral, and I also identified more than one rough edge in the design of the STM8 I2C peripheral. Having worked through it I still think that it's worth it since features like "clock stretching" are difficult to implement, and there are use cases where concurrent execution has advantages.
The "I2C Master" is only the first step. The real "prize" is the "I2C Slave" - using a Forth system as a peripheral in a larger system, especially an STM8L, is quite attractive.
Did you read the deadlock section? It is important that your master can escape this. It is probably added to the I2C_Stop routine.
Hardware SCL_Stretch is a plus. It is however very easy to implement in bit-bash as well (and should be). Hardware slaves will stretch at ACK - you don't need to be checking SCL before every clock edge, just the one that exits ACK. (Supporting low speed firmware slaves seems completely pointless to me).
SCLStretch is necessary if you want to support slaves that are micros - it is very hard to make them never stretch.
The other thing hardware can do is monitor that the bus is busy so that your master doesn't start if the bus is already open i.e. between Start and Stop. Apart from expected multi-master situations, some batteries with SMBUS were acting as masters every few seconds, as well as slaves - this caused one of my customers grief as the bus collisions were incredibly intermittent.
Which deadlock section are you referring to? (I'm sipping on my first cup of coffee)
The observation about ACK stretching is interesting. Regarding clock stretching in general: the I2C slave section in the STM8 I2C description assumes that the master supports it. I think that the STM8L can avoid the ADDR Event -> Load I2C_DR
delay by using DMA. Maybe pre-loading I2C_DR
works.
The experience with SMBus and inexpected multi-master is really valuable. It would be attractive to make an "I2C stress-tester slave" for master testing - this would help building reliable I2C applications.
Which deadlock section are you referring to? (I'm sipping on my first cup of coffee)
See: https://www.i2cchip.com/pdfs/BL233_Datasheet.pdf
Section 19 I2C Bus Deadlock
Thanks, that's a great resource!
I merged I2CMA
- please refer to the examples in this GitHub Gist.
Now tested with an STM8S207K6 (High density) chip.
Hint: OPT2 bit 6 needs to be set since I2C depends on "AFR6 Alternate function remapping option 6".