viewtopic.php?f=2&t=1502&start=10&hilit=i2c+slave
is now largely compete.
This makes it possible to network ChiBiOS microcontrollers via their I2C bus controllers.
The API of the existing Master Mode has not been changed.
The enhanced I2C driver API supports:
I2C Slave Mode
Multiple I2C Masters sharing the same bus
SMBus style "quick" messages (e.g. 0 byte writes and reads)
Ability to "lock" the bus for any arbitrary sequence of messages
Ability of slaves to detect whether or not the previous write received was ended with a STOP conditon (or repeated START)
The I2C driver still does not support:
10-bit addressing mode
SMBus CRC checking
The first implementation is for the STM32 MCUs that employ the STM32/I2Cv1 driver.
Testing has been carried out between STM32L1xx Discovery boards and older I2C controllers based on a (non-ChiBiOS) MSP430169 microcontroller.
Templates and headers are in place to facilitate enhancement of other I2C drivers in ChiBiOS.
The code is available at:
https://github.com/brentr/ChibiOS-RT
Anyone interested may clone the repo with:
Code: Select all
git clone git@github.com:brentr/ChibiOS-RT.git
cd ChiBiOS-RT
git checkout i2cslave
This is all based on the 2.6x stable series.
Most of the changes are in i2cslave.h (new file) and i2c_lld.*
Note that there is no i2cslave.c, as the slave mode support is integrated into the existing i2c driver when, in halconf.h:
Code: Select all
#define HAL_USE_I2C_SLAVE TRUE
To enable the optional i2cLock() function in the master mode API, allowing arbitrary sequences of "repeated starts" for atomic messaging, add:
Code: Select all
#define HAL_USE_I2C_LOCK TRUE
The only change I made outside the driver was to add a macro to initialize virtual timers allocated in automatic storage.
I called this chVTInit(). If there's a better/more standard way to get this done, please let me know.
When slave messages arrive, the driver invokes callbacks in interrupt context to process them.
This is very efficient and appropriate for simple cases.
However, a small, hardware independent library (os/various/i2c_event.[c.h]) can convert these interrupt context callbacks into events that are typically serviced in a dedicated message processing thread.
Others have complained that the STM32's I2C controller is buggy. I have not found it to be especially so. The only hardware problems I see are:
1) Slaves do not get interrupted when repeated start event end the current message they are processing. As a result, slaves cannot process such messages until after the address for the next message is sent. This results in having one interrupt both end the previous message and start a new one and is why event queuing is absolutely required to interface with any sort of message processing thread.
2) Zero length writes do not provide any opportunity for slaves to stretch the I2C clock. They work fine to spite this. The queue size can be configured to store the longest rapid sequence of uninterrupted zero length writes to be expected. (usually, a queue depth of 4 events suffices)
3) Zero length reads are problematic. They can only work if the MSB of the first response byte from the receiving slave is 1. Otherwise, the STM32 will drive the SDA line low before the master has a chance to end the transaction by signalling a STOP condition.
The existing, still admittedly basic, tests are in the projects i2cmaster and i2cslave.
To run these without change, connect the PB8 and PB9 pins of two boards together and pull each up to VDD through approximately 4Kohm.
Run the i2cmaster project on one board and i2cslave on the other.
If you have the latest version of OpenOCD and are interfacing via STLINKv2, progress messages will appear in the debugger via DCC.
Otherwise, you'll need to modify the test code to output text to the serial port of your choosing.