How to distinguish between Stop or Restart by selected slave ?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How to distinguish between Stop or Restart by selected slave ?

2,627 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Shoichi Kojima on Mon Sep 24 23:36:28 MST 2012
Hi, fellow developers;

I'm trying to implement I2C Master/Slave feature on several LPC serise devices.
Some of those will be connected together on the same I2C bus, a multi-master environment.

As a part of protocol implementation, I need to distinguish between STOPed or Restarted at the interrupt report with I2CSTAT value 0xA0;
i.e.
  When I2C transaction is terminated...
   by STOP condition:     Normal data sent to its slave-behaving part
   by RESTART condition:  data bytes sent before it should be treated as a kind of particular COMMANDs and expected that some more data bytes will be sent as OPERAND parameters to those COMMANDs with termination by STOP condition.

Is there any way to do it with I2C module implemented in LPC-serise MCUs ?
I'm going to do it onto LPC11xx, 1343, 1769 and 4350 etc...
Labels (1)
0 Kudos
11 Replies

2,273 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by bob_walker on Tue Jan 26 17:48:14 MST 2016
I think Soichi's method is the only workaround that I can see....checking the state of SDA.
This would work for any slave protocol (variable number of bytes during the write (slave_rx) phase.
Otherwise, one would have to rely on  i2c->rxSz to determine whether it is a read or write. There would have
to be a different number of bytes received to distinguish between the read and write functions.
0 Kudos

2,273 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by bob_walker on Mon Jan 25 09:39:50 MST 2016
My problem with the I2C block not being able to signal a STA vs. RSTA condition is as follows:

Let's say a slave operates in the following manner:
Write: STA-SLA-W --> reg, -->value,  -->STP
Read: STA-SLA-W,  --> reg,  -->operand,  -->RSTA-SLA-R,  -->data0,  -->data1,  -->data(n),  -->STP.

How does one know if the write portion (setup) of the Read command was intended for the Write command or the Read command- If the stop and restart conditions are the same, the logic has no way to determine this. One would have to monitor the I2C state to see if the bus was released (write condition). I believe that is what Shoichi is referring to ... at least that is my understanding.

Does anyone have a work around for this condition?


0 Kudos

2,273 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by noahk on Sat Nov 17 23:57:17 MST 2012
Hi Shoichi,

The newly released LPC800 family comes with a new I2C block that is capable of pseudo distinguishing between starts and restarts. The mechanism by which this is accomplished is by using the SLVSEL bit of the STATUS register. By checking whether that bit is already set (in the SLV_STATE = Address (0)), you can tell if this is a restart (it will already be set), or a start (it will be cleared). Note that it is possible for a restart to look like a start when the previous address was nacked or was to another slave as the SLVSEL bit will be clear.

It seems to me that this is sufficient for the use cases you have outlined.

You can also use the SLVDESEL bit in the STATUS register to detect a stop, or a repeated start to another slave.

http://www.nxp.com/documents/user_manual/UM10601.pdf
Chapter 16: LPC800 I2C-bus interface

Noah
0 Kudos

2,273 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Karl on Thu Sep 27 13:06:31 MST 2012
Hi Shoichi,

Thank you very much for this detailed explanation. It really helped to understand what difficulties you have to manage.
Your objection to the "two slave addresses" solutions is valid. This consumes twice as many addresses, and should only be considered if there is no other way out.

The problem is down to how the slave can correctly interpret these formats:
<code>
S SLA+W "Normal" P
S SLA+W "Command" Sr SLA+W "Operand" P
</code>

My interpretation of the I2C spec is this: These are three write transfers ("Normal", "Command", "Operand") which are all equivalent as far as the slave is concerned. The spec does not differentiate between transfers that start with S, and transfers that start with Sr. So I believe that what you do (exploit the Sr to treat the "Operand" transfer differently) is just no covered by the spec. Anyway, I'm sure that regardless of whether I'm right or wrong, none of us will be sued for misinterpreting the spec! :-)

Is this you decision flow in the slave?
a) SLA+W ends with P: "Normal" if started with S, "Operand if started with "Sr"
b) SLA+W ends with Sr: "Command"

If you a free to design a new protocol, this is in my opinion the best way to do it:
<code>
S SLA+W <TAG_NORMAL> "Normal" P
S SLA+W <TAG_COMMAND> "Command" "Operand" P
S SLA+W <TAG_COMMAND> "Command" Sr SLA+R "DataFromSlave" P
</code>
That uses tags to distinguish "Normal" from "Command". Could be an extra byte, or one bit in the payload, or...
If you want to write to the slave, combine "Command" and "Operand" in one transfer. Only use Sr if you must change transfer direction.
If you cannot change that due to compatibility issues, maybe adding a third tag to the "Operand" works:
<code>
S SLA+W <TAG_COMMAND> "Command" Sr SLA+W <TAG_OPERAND> "Operand" P
</code>

I hope you can find a way to use the LPC's even if they are lacking the 27th status code :-)

Regards,
Rolf
0 Kudos

2,273 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Shoichi Kojima on Thu Sep 27 00:36:24 MST 2012
Hi Karl,

Thank you so much again.
It is a very dense and meaningful suggestion and review comment that I've ever had.

Maybe, the point is ownership, responsibility and utility to S,Sr,P.
In this perspective, in my implementation those are shared by both Master and Slaves. (you may say a not fully I2C-compatible implementation ^^;)

You are asking about my implementation more exactly.
So, let me describe some more.
Basically, I want to implement two kinds of communication.
One is "normal message" and the other is "Command with Operand".
Some commands may require data from the slave (similar to well-known EEPROM read access.)
Not like EEPROM read access, I will not use lonesome
"S SLA+R .... P" style communication (because of multi-master bus configuration to avoid problems.)

Regularly "Normal message" is used.
"Command + Operand" is used only in particular cases, such as initialization, parameter changes, some other house-keeping kind of controls etc... Only one "Operand" payload can follow the "Command". If several bytes of operand-meaning bytes are required, they are to be in one payload.
"Normal message" transfer occurs more often than the other.
Short and simple structure is expected.
So, in summary, follwing two types are used.

  S SLA+W "normal message" P
  S SLA+W "Command" Sr SLA+R/W "Operand" P

At the end of data payload sequence, P or Sr is treated as a kind of delimiter which determines the category of the data byte sequence made just before them.


Your new proposal
S SLA+W "Command" Sr SLA2+W "Operand" P

Without P in the middle, no other masters can interrupt.
It is good.
Problem to me about this are:
  Required plural I2C slave addresses per one physical
  slave device.
  Still difficult to implement "normal message" type at
  the same time.

Regarding former promlem, some I2C-capable MCUs does NOT always have suitable slave-address-match logic to detect plural slave address, and essentially I2C slave address space will be consumed more...

Anyway, I understand your new proposal is worth considering for one of my newer developments with NXP MCU which can handle several slave addresses.
Thank you for your good suggestion.


Finally, I would like to have a hint.
You wrote mine is not fully I2C-compatible.
It may be so... But, at this opportunity, I would like to study I2C spec again to know the reason why you fell so.
Could you tell me where and what description in I2C spec explains so.

Regards,
0 Kudos

2,273 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Karl on Wed Sep 26 02:50:31 MST 2012
Hi Shoichi,

The ability of a slave device to distinguish between STOP (P) and repeated START (Sr) is not an I2C requirement. The difference between the two is for the master only. A slave shouldn't care.
As you mention, the Sr ties two or more transfers closely together. All other bus masters will consider the bus busy until they detect the next STOP.

<blockquote>
I've done several implementations previously in that way I mentioned.
So, with LPC-serise, I might not make a new implementation that works together with those already-developed ones in the completely same protocol manners...
</blockquote>
So what exactly is your implementation? My understanding is:

<code>
S SLA+W "Command" Sr SLA+W "Operand" P
</code>
With the Sr you ensure that an operand is always associated with the command sent previously by the same master.

So far, so good. You might have combined this into one single transfer, as this is how it's typically done with I2C:
<code>
S SLA+W "Command" "Operand" P
</code>

The problem I see is that you are relying on the detection of Sr to distinguish between command and operand. So you're saying "this is an operand" just by its position in a transaction, not by its content. If by looking at the payload of a command and an operand transfer you cannot tell one from the other, then you're in trouble.
I'm not the author of the I2C spec :-), but for me it clearly says that a slave is not supposed to exploit the difference between Sr and P.

<blockquote>
You suggested two-slave-addresses-in-one-device implementation.
It may work.
But, in my application situation of multi-master bus structure, your idea may cause a new problem, I'm afraid.
Because, every I2C device with master-capability is watching the I2C bus becomes FREE and they will immediate try to issue HIS Start condition to get bus.
In the middle of Command-meaning transfer and following Operand-meaning transfer might be interrupted by some other master device which is willing to talk to my slave device.
</blockquote>

You're right with the multi-master setup. As described above, it takes a STOP to detect that the bus is available again. An Sr terminates a transfer for a slave, but the master may continue to use the bus.

My proposal with the two slave addresses should work:
<code>
S SLA1+W "Command" Sr SLA2+W "Operand" P
</code>

This allows to distinguish between Command and Operand based on the address.

However, if you already have a bunch of devices in the field (with what I consider a not fully I2C-compatible implementation), then only some nasty workaround may help...

Regards,
Karl
0 Kudos

2,273 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Shoichi Kojima on Wed Sep 26 02:27:08 MST 2012
Hi Karl,

Thank you again for your suggestion.

Your code seems to have very good balance between ease-of-understanding and help guide for compiler to generate smarter code for Cortex-M.
Not only to MY particular application case, but generally and commonly to every LPC user who is handling I2C, it is a very good reference code.


But, anyway, I still think I should code peeking pin level before switch-case like below.
Because, even if "switch-case" code is smarter, it will be worse than nothing to catch the physical signal level on the pin.
---------
void I2C_Handler(void){
uint32_t pin_level;
uint32_t status;

  pin_level = GPIO0 /* ####  ASAP, get physical pin level */
  status = (i2c->STAT & 0xF8) >> 3;

  switch (status) {
      ....

    case I2C_STATUS_0xA0:
      /* SDA pin. masking depends on each MCU model */
      if(pin_level & 0x????){ // maybe STOPped
            :
      }else{ // maybe ReSTARTed
            :
      }
      ......
}
---------

Anyway, somebody wrote somewhere in related forum, I2C logic block is not seem to be well-optimized for Cortex-M.
Related documents and materials as well....  sigh.

Regards,
0 Kudos

2,273 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Karl on Wed Sep 26 01:51:23 MST 2012
Hi Shoichi,

To me that approach doesn't really seem the way to go...

So let me just comment on the compiler efficiency. The status codes are in steps of eight only if you look at the status register as a byte. The status code field is only five bits wide. Make the compiler aware that you will only operate on this bit field:

<code>
/* Define possible I2C status code */
enum {
    ...

    I2C_STATUS_0x98 = 19,                   /**< SR: Sent NAK after data in (global call) */
    I2C_STATUS_0xA0 = 20,                   /**< SR: Received STOP or repeated START */
    I2C_STATUS_0xA8 = 21,                   /**< ST: Addressed as slave transmitter */

    ....
};


/* Read status register and extract status code */
status = (i2c->STAT & 0xF8) >> 3;

switch (status) {
    ....

    case I2C_STATUS_0xA0:
        ;
        ;
        break;

    ....
}
</code>

Almost certainly the compiler will now use the table branch instruction of the Cortex-M3, and produce compact and fast code.

Regards,
Karl

0 Kudos

2,273 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Shoichi Kojima on Wed Sep 26 00:02:25 MST 2012
Hi fellow developers,

I wrote:
>Anyway, I will continue to do some work-arounds.

One idea I have now is peeking physical signal level directly thru GPIO input as soon as any kinds of interrupt from I2C block is invoked.
Switch-case branch for I2CSTAT will be made as usual later.
Only in case that the I2CSTAT is reported as 0xA0, I'm going to check physical signal level which has been already peeked at the very beginning of I2C interrupt handler.

If STOP occured, signal level of SDA corresponding pin should be read as "H" and in case of ReSTART that signal level would be read as "L".

But, this work-around algorithm would be very critical in time. I think that my I2C interrupt handler should read the pin signal level within 1.3us (as defined as "tBUF" in I2C specification).
With Cortex-M-equipped LPC MCUs may help, because their NVIC architecture is desinged with great cares about "determinism", fully-preemptive in "priority" perspective. (still I think I need to locate I2C interrupt handler in some of higher priority levels)


Firstly, I checked interrupt handler code generated by Keil MDK-ARM (ARMCC). Switch-case made for I2CSTAT(which is NOT in dense order but in step of eight) seems tough for Cortex-M's ARMv7 instruction set ( or compiler?).
Step of eight is not reasonable for each handler branch-ends....Some library code portion (prepared with ARMCC)is employed just to do multiple branch by supplied code.
If I attempt to read physical pin only in case of the I2CSTAT is read as 0xA0, it might be too late.
Several CPU cycles have been consumed from the time of original event that I2C block detects STOP or ReSTART and new signaling will be made by master that prevents distinguishing STOP/ReSTART properly.
So, now I think to do "read pin level first then swicth-case".



Any other suggestions are still welcome.

Regards,
0 Kudos

2,273 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Shoichi Kojima on Tue Sep 25 17:06:01 MST 2012
Hi Karl,

Thank you for your reply and suggestions.

>You can't distinguish between the two situations.

Frankly, this is my first experience that the target/candidate MCU device does not have this capability....

I've done several implementations previously in that way I mentioned.
So, with LPC-serise, I might not make a new implementation that works together with those already-developed ones in the completely same protocol manners...
I do belive that the some portion of the logic circuitry of NXP's I2C block knows the difference of "STOPed" and "ReSTARTed" at the termination situation as a selected slave.
I strongly hope that at the opportunity of I2C IP block improvement, as new 27th Status code, termination by ReSTART should be reported in distinguish-able code.

Anyway, I will continue to do some work-arounds.

You suggested two-slave-addresses-in-one-device implementation.
It may work.
But, in my application situation of multi-master bus structure, your idea may cause a new problem, I'm afraid.
Because, every I2C device with master-capability is watching the I2C bus becomes FREE and they will immediate try to issue HIS Start condition to get bus.
In the middle of Command-meaning transfer and following Operand-meaning transfer might be interrupted by some other master device which is willing to talk to my slave device.

In my understanding, to every master-capable device "bus free" can be detected by the fact that STOP condition is observed on the bus, and ReSTART condition can not be interpreted and bus free, so until issuing STOP condition, the current winning-master can go on without disturbance by any other master-capable devices.
Do I misunderstand ? --> to: I2C expert people

Regards,

0 Kudos

2,273 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Karl on Tue Sep 25 03:16:06 MST 2012
Hi Shoichi,

You can't distinguish between the two situations. As far as the slave is concerned, they are identical in that both terminate the transfer.

The difference with repeated START (Sr) is for the master. Sr allows it to concatenate related transfers without releasing the bus. No arbitration takes place for a Sr, and no other master can claim the bus before the transaction (=multiple read or write transfers) is completed.

The I2C protocol demands that you send the slave address again after Sr. You cannot immediately start with your "operand" data! An I2C (slave) module in the LPC devices resets its hardware upon receiving Sr, and will only react again when addressed by one of its slave addresses. Wouldn't it be the easiest way to send both command and operand in the same transfer, and avoid the problem with two write transfers altogether?

If you really have to break command+operand into two transfers, my proposal is to assign two slave addresses to each slave device. Send the command data with the first address, then the operand data with the second address, separated by Sr. The slave can interpret the data based on address, and the integrity of the transaction (command and operand belonging together) is guaranteed by the Sr.

Regards,
Karl

0 Kudos