cancel
Showing results for 
Search instead for 
Did you mean: 

[STM32g0] Multiple I2C target transmitters transmitting data in the same I2C transfer

zajil
Associate II

Hello, this will be a rather advanced problem that I'll be presenting so please bear with me until the end.

I'm currently working on I2C communication, with a configuration where I have a controller that initialize 4 STM32g0 on custom PCBs.

TL;DR : I want to combine data transmitted from target transmitters by broadcast, using the fact that I2C bus lines are driven low but it doesn't work.

Context

----------------------------------------

At initialization, the I2C controller (on SoC) will individually set each STM32g0 boards (targets) with a custom ID and two address : a broadcast address, and an individual address (which depends on the ID). This is done with the help of a mux and after this initialization, the mux is always set so that all STM32g0 are connected to the I2C bus.

Presently, the controller sends a command to say it will request to read some specific data to each target (STM32g0) individually then reads the data after a repeated start condition.

I2C communication presently looks like this :

(S)(ADDR_X)(W)(A)(CMD)(A)(P)(Sr)(ADDR_X)(R)(A)(DATA_0)(A)..(DATA_N)(N)(P)

(S) : start condition

(Sr) : repeated start condition

(ADDR_X) : ADDR of the device with its ID = X ( 1 <= X <= 4)

(R)/(W) : transfer direction bit

(A)/(N) : ACK and NACK

(CMD) : command (defined by custom protocol)

(DATA_0)...(DATA_N) : the data payload requested by the controller

(P) : stop condition

This communication will be repeated 4 times for each device.

I2C communication is handled by DMA, with stretching enabled.

What I would like to do

-------------------------------------------------------

I would like to instead request data with the broadcast address and get a payload like this :

(S)(ADDR_BR)(W)(A)(CMD)(A)(Sr)(ADDR_BR)(R)(A)(1_DATA_0)(A)..(1_DATA_N)(A)....(4_DATA_0)..(4_DATA_N)(N)(P)

(ADDR_BR) : broadcast address

So the controller will have one transfer of N*4 instead of 4 times a transfer of N bytes. The idea is to take advantage of the fact that I2C lines are active low, meaning that sending 0XFF bytes should be equivalent to letting the line free.

So I thought that an individual payload (different for each STM32) like this would work :

(for example, for the device with ID = 3)

[NOTMY_DATA][NOTMY_DATA][MY_DATA][NOTMY_DATA]

Here all NOTMY_DATA bytes are 0xFF bytes (only ones), which I think should translate to something like "I'm not driving the SDA line" as in I2C the SDA line is active low.                  

So when it's not the target turn to send its data, it doesn't drive the SDA line as it outputs only 'ones' such that the target that should drive the SDA line has the hand on the SDA line and can send its data (i.e. pull down when needed).

The problem 

--------------------------------------------------

In practice, it doesn't work at all. I'm actually trying with 2 target devices and the controller on the bus, but observing the SCK and SDA lines for both target shows that the overall payload seen on the bus is the payload of the first target transmitting data different than 0xFF. There's actually no "merging" of the payloads.

I've checked that it's not a HW problem (mux or PCB) because I modified the code such that the target STM32 device that I expect to not be able to communicate breaks the SDA line by driving the line low in the middle of the data payload transfer. And I did observe the expected communication breaking on the oscilloscope.

I'm kinda at loss here.

My best guess is that STM32 I2C HW implements some kind of error checking, monitoring what it sends and what is seen on the bus and then aborts the I2C transfer when the two don't match.

Does anyone have any insight on this ? I know this usage case isn't specified by the I2C specification, but there's nothing saying it shouldn't or doesn't work.

Thank to all of you that took the time to read this, and thank in you in advance for your help.

Z.

1 ACCEPTED SOLUTION

Accepted Solutions

This is how the I2C module in 'G0 works:

0693W00000Nrus7QAB.png 

While arbitration is a matter of masters indeed, using multiple slaves answering to the same address on the same bus is I2C protocol violation too.

JW

View solution in original post

3 REPLIES 3
zajil
Associate II

So I've been digging on this problem and here's what's new :

Communication from the DMA point of view is incomplete. I have 32 bytes to transmits, but for the target device that failed transmission the DMA CNTDR (counter register) value is 22, meaning it has managed to transmit 10 bytes to the I2C peripheral and the I2C has sent at least 9 of these bytes before stopping transmission. This 10 bytes value is not random, it's precisely the index of the first byte sent on the bus that is not 0xFF for the other target transmitter, so it strengthens the hypothesis made earlier.

I've tried to understand better why it stops the communication so I've looked into I2C ISR before and after a transmission failure.

Before the failure the arbitration lost flag is clear but this same flag is raised after the transmission. I suspect that it's this flag being raised that stops the communication in I2C HW block.

What I fail to understand is why is this flag relevant here, given that arbitration should occur only in a multi-master bus configuration.

This is how the I2C module in 'G0 works:

0693W00000Nrus7QAB.png 

While arbitration is a matter of masters indeed, using multiple slaves answering to the same address on the same bus is I2C protocol violation too.

JW

Oh okay, I feel kinda embarrassed for not having noticed this valuable piece of information earlier.

Thanks a lot !