I2C Slave Test routines for STM32F4 (and others using 'V1' I2C)

Addresses are 7-bit


Test Program operation
----------------------
Test platform: Olimex E407 using I2C2 on PF0, PF1

There are two modes:
a) Callback (Asynchronous) (#define CallBackAPI  TRUE)

Structures of type I2CSlaveMsg are hooked into the slave transmit and slave receive; these
define the receive buffer/reply message and other callbacks.

A simple read returns a fixed identification message
On a write then read (repeated start):
    empty write message returns current time
    non-empty write message is echoed 



b) Thread-based (Synchronous) (#define CallBackAPI  FALSE)
- uses additional files i2c_event.c, i2c_event.h, found in the 'various' subdirectory.

THIS MODE NOT YET TESTED - some file discrepancies to resolve.


Description from i2cslave.h
---------------------------
  An event service thread based API library called i2cevent supports processing
  slave messages on a dedicated thread.  This facility is built upon the
  low-level driver's asynchronous callback functions described below:

  Each callback function may alter the processing of subsequent I2C
  messages and read requests by calling i2cSlaveReceive() and
  i2cSlaveReply(), respectively.  Further, callbacks may alter their
  i2cSlaveMsg structs in RAM, but only those for their own channel.
  Such changes take immediate affect.  This facility can be used to
  avoid copying message buffers.

  If receive buffers become full or a reply to a read request cannot be
  generated immediately, the relevant I2CSlaveMsg struct may be substituted
  for another whose body pointer is NULL or whose body size is zero.
  Note that, I2CSlaveMsg structs may be modified
  in place within a channel's callbacks to the same effect.

  A NULL body pointer or zero size causes the slave to signal the master node
  to wait by holding the I2C clock signal low, "stretching it", during the next
  transaction to which that I2CSlaveMsg applies.
  The I2C clock resumes only after a i2cSlaveSetReceive() or SetReply() is
  called with an I2CSlaveMsg containing a non-NULL body,
  or after the transaction timeout expires.

  Therefore, if a NULL body pointer is replaced with a non-NULL one or
  a zero length is replaced with a non-zero one, i2cSlaveReceive() or
  i2cSlaveReply() MUST be called -- even if with the same pointer values --
  to inform the i2c driver that the transaction may resume.

  Note that Receive and Reply processing is initially "locked".

  
  
  Notes from forum thread (not necessarily accurate)
  -----------------------
  IDLE = No message transaction in progress
MATCHED_READ = Address Matched for Master Read (query to be answered)
READING = transferring reply from slave to master
MATCHED_WRITE = Address Matched for Master Write (data to be stored)
WRITING = transferring message body from mater to slave

Transitions:
IDLE --> MATCHED_READ --> READING --> IDLE
IDLE --> MATCHED_WRITE --> WRITING --> IDLE

Once the address matching criteria are established, I think the three functions I described in my previous message would be sufficient for this state machine to run in the event handling loop of a single (dedicated) thread.

i2cAwaitAddressMatch() blocks until the driven enters the MATCH_READ or MATCH_WRITE states (indicating which was entered).
i2cSlaveAccept() handles the MATCH_WRITE state.
i2cSalveAnswer() handles the MATCH_READ state
Both block until the driver reenters the IDLE state.
I could perhaps define the act of calling i2CAwaitAddressMatch() while in either MATCHED_READ or MATCHED_WRITE
as aborting the transaction in progress, sending a NAK if possible. However, I don't think the I2C protocol allows the slave to NAK in some cases. I'll look into this.
  
  