I2C Slave mode support?

ChibiOS public support forum for all topics not covered by a specific support forum.

Moderators: utzig, lbednarz, tfAteba, barthess, RoccoMarco

steved
Posts: 770
Joined: Fri Nov 09, 2012 2:22 pm
Has thanked: 10 times
Been thanked: 122 times

Re: I2C Slave mode support?

Postby steved » Thu Jun 13, 2019 2:56 pm

I'm not certain that 'read zero bytes from this address' is a valid call, although there's no specific test for it. Are you using i2cMasterReceiveTimeout()?

On the slave, IIRC it should always respond with data - the source depends on the call type. The slave has no knowledge of how much data has been requested; it just keeps sending until a STOP is received. So I suspect the problem is at the master end.

It's a while since I tested all modes of the driver, so its possible that something has become broken outside my normal use case. However nothing substantive has been changed.

eblot
Posts: 18
Joined: Fri Dec 08, 2017 5:33 pm
Been thanked: 1 time

Re: I2C Slave mode support?

Postby eblot » Thu Jun 13, 2019 3:32 pm

Hi steved,

I do not think this issue comes from your updated code, but is part of the not-yet-handled use cases.

The master cannot do anything in this case: as clock stretching has been left activated by default, the slave leaves the clock at the low level so the master is no longer able to communicate with the slave anyway - at least until the timer times out on the slave and release the SCL line so the master gets a chance to initiate a STOP.

I do not think an I2C request requires to have at least one data byte, whatever the direction.
The master is not running ChibiOS in my current setup.

Thanks for your help, I still need to dig further into the code.

It would be really nice the "slave" modes get an official API in ChibiOS - I'm also thinking about SPI here :-)

User avatar
Professor Tarantoga
Posts: 3
Joined: Thu Aug 20, 2020 1:30 pm

Re: I2C Slave mode support?

Postby Professor Tarantoga » Thu Aug 20, 2020 2:03 pm

Hi folks.
I am really happy, that there is code for i2c slave mode available (thanks for that), but i do have some little problem, getting it to work properly. Maybe someone can give me a hint?
I am using the NUCLEO-F767ZI, OS is 20.3.1 and code compiles without any error.
DMA disabled.
From the given examples i use following code to get slave mode up:

i2cStart(&slaveI2cPort, &slaveI2Cconfig);
slaveI2cPort.slaveTimeout = TIME_MS2I(500);
initialReply.size = strlen((char *)initialReply.body) + 1;
i2cSlaveConfigure(&slaveI2cPort, &echoRx, &initialReply);


In i2cSlaveConfigure function i2c_lld_slaveReceive is called and i2cStartReceive should be called in order to activate rx interrupt (I2C_CR1_RXIE). But i2cp->mode is set to idle and because of if (i2cp->mode == i2cLockedRxing && rxMsg->body && rxMsg->size) function i2cStartReceive is never called.

Am I missing something?
Thanks in advance

steved
Posts: 770
Joined: Fri Nov 09, 2012 2:22 pm
Has thanked: 10 times
Been thanked: 122 times

Re: I2C Slave mode support?

Postby steved » Thu Aug 20, 2020 5:50 pm

Long time since I looked at the code in detail, but I think you'll find that i2cStartReceive() is called (maybe via a convoluted route) once the device has received a correct I2C address.

Looking at my code, I have this sequence:

Code: Select all

#if HAL_USE_I2C_SLAVE
  slaveI2cPort.slaveTimeout = MS2ST(100);       // Time for complete message
#endif
  i2cMatchAddress(&slaveI2cPort, slaveI2Caddress/2);
  i2cSlaveConfigure(&slaveI2cPort, &echoRx, &initialReply);

You don't mention calling i2cMatchAddress(), so that could be the problem.
Note: I always regard I2C addresses as 8 bits, with bit 0 always zero; Chibi uses a 7-bit value.

If you look back in this thread, there should be some pointers to the test harnesses I used originally when making the code work. (I do have this feeling that the I2Cv2 code might be over-complicated, but have never had time to revisit it)

User avatar
Professor Tarantoga
Posts: 3
Joined: Thu Aug 20, 2020 1:30 pm

Re: I2C Slave mode support?

Postby Professor Tarantoga » Wed Aug 26, 2020 8:22 am

Hej steved,
thanks for answering.

Indeed I overlooked i2cMatchAddress(). Beside that I was struggeling with some inconveniences in my test setup. Meanwhile I managed to get something working.
As I don't have any experience with DMA, I disabled DMA. i2c should now run in interrupt mode.
I can see the received data in the provided rx-buffer but data is not further handled in any way.
i2cp->slaveBytes is always 0
I found a function i2cEndSlaveRxDMA, but no end-function for interrupt driven mode.
Could it be that your code is only working with DMA?

I will try DMA-mode and see, although it would be nice if you can give me a short feedback on interrupt driven mode.

Thanks and best regards
PT

steved
Posts: 770
Joined: Fri Nov 09, 2012 2:22 pm
Has thanked: 10 times
Been thanked: 122 times

Re: I2C Slave mode support?

Postby steved » Tue Sep 01, 2020 1:40 pm

Does look as if my 'real' code was using the I2C in DMA driven mode, although the driver was tested with both DMA and interrupts for a range of message sizes up to 563 bytes.
My applications send a message to the device, and always expect a reply.

Last thing I do in initialisation is:

Code: Select all

  i2cSlaveConfigure(&slaveI2cPort, &echoRx, &initialReply);


The key data block is:

Code: Select all

const I2CSlaveMsg echoRx =
{
  sizeof(rxBody),       /* max sizeof received msg body */
  rxBody,               /* body of received msg */
  NULL,                 /* do nothing on address match */
  messageProcessor,     /* Routine to process received messages */
  catchError            /* Error hook */
};

Then the key parts of my message processor are:

Code: Select all

void messageProcessor(I2CDriver *i2cp)
{
  size_t len = i2cSlaveBytes(i2cp);         // Number of bytes received
  if (len >= sizeof(rxBody))
      len = sizeof(rxBody)-1;
  rxBody[len]=0;
  /* Process received message, generate response */
  uint8_t rxLen = checkRxMessage(rxBody);
  if (rxLen == 0)
  {
    strcpy((char *)txBody, errorReplyBody);
    echoReply.size = strlen(errorReplyBody);
  }
  else
  {
    uint8_t txLen = processMessage(&rxBody, rxLen, &txBody);
    txBody[1 + txLen] = '\0';       // Null terminate for simplicity
    echoReply.size = txLen;
  }
  i2cSlaveReplyI(i2cp, &echoReply);
}


Hope that helps

User avatar
Professor Tarantoga
Posts: 3
Joined: Thu Aug 20, 2020 1:30 pm

Re: I2C Slave mode support?

Postby Professor Tarantoga » Thu Sep 03, 2020 1:56 pm

I am now running DMA-mode. The data is received correctly and put into the rx-buffer.
Unfortunately the messageProcessor is never called so I cannot handle the data.

debugging codes are: 0x82, 0x80, | : 0x04, 0x13, 0x14, 0x05 : |

I understand:
82&80 init transfer
04 address match
13 address match receive
14 receive
05 stop

But where is the data handled?

Maybe I am stuck on outdated code od still missing something?

Thanks
best regards
PT

steved
Posts: 770
Joined: Fri Nov 09, 2012 2:22 pm
Has thanked: 10 times
Been thanked: 122 times

Re: I2C Slave mode support?

Postby steved » Tue Dec 15, 2020 8:39 pm

Professor Tarantoga wrote:But where is the data handled?

Maybe I am stuck on outdated code od still missing something?
PT

I've just started using I2C slave mode in a different way to previously, and found exactly the same as you. It's when the master just sends, without requiring a reply - as you say, the data isn't handled.

Did you ever fix the problem?

steved
Posts: 770
Joined: Fri Nov 09, 2012 2:22 pm
Has thanked: 10 times
Been thanked: 122 times

Re: I2C Slave mode support?

Postby steved » Fri Dec 18, 2020 4:58 pm

Well, this is how I fixed it for I2Cv2 - just update the LLD.
Works with and without DMA.
Code could still do with a serious tidy up, but at least it works.
Attachments
I2Cv2.7z
(16.35 KiB) Downloaded 35 times


Return to “General Support”

Who is online

Users browsing this forum: No registered users and 7 guests