Go Down

Topic: I2C Repeated Start (Read 11010 times) previous topic - next topic

cdan

Hi,
the last release of the Wire library has added support for an extra parameter to the Wire.endTransmission and Wire.requestFrom, to specify if a STOP should be sent or not. Nevertheless, it seems it is not working for Due. I have inspected the source code for the two aforementioned methods and they ignore the boolean parameter altogether. I have also inspected the SCL and SDA lines with an oscilloscope   and I could clearly see the STOP condition being sent.

Am I missing something? or is this not supported on Due yet?

Best regards,
Dan.

P.S.
See the attached files.

Dan,

I'm about to start an I2C project that may require I2C repeated starts.

Have you learned anything about this issue?

-Chris

cdan

Hello,
what board are you going to use ? What are the specific I2C transactions that you'll need?

With the Due board, I was able to read/write from/to an internal register of a I2C slave device (MLX90614), using the API in the libsam library. You can find the source in
arduino-1.5.1r2\hardware\arduino\sam\system\libsam\source. Look for twi.c and twi.h
The functions of interest are void TWI_StartRead and void TWI_StartWrite. They both have a parameter called uint32_t iaddress where you can put the internal address/register you want to access. If you specify it, then the controller will automatically  send a REPEATED START condition after writing the address of the slave device and of the internal register on the bus and before reading/writing the data bytes.

Best regards,
Dan.


Dan,

I'm about to start an I2C project that may require I2C repeated starts.

Have you learned anything about this issue?

-Chris

#3
Dec 21, 2012, 03:43 pm Last Edit: Feb 04, 2013, 10:50 pm by chriskner Reason: 1
Hi Dan,

On the Due.

I have some pcb's with both a PCA9539 (from NXP) and LTC2489 (Linear Tech), perhaps others.

Protocols:
LTC2489_I2C.png (12kB)
PCA9539_I2C.png (22kB)

There's a bit of history with these boards (struggling to get other external uC's to issue an I2C repeated start without stop), so your post caught my attention.

I appreciate the pointers, and any other suggestions you may have.

Regards,

Chris

cdan

Hello,
I had a quick look over the LTC2489's specs and I think it would be very easy to interface it with the Due board.

  • You WRITE to the device's input register to select the input channels for the next selection. Input register is 8bit long.

  • You READ from the device's output register the value of the last conversion. The output register is 24bit long

  • The device starts a new conversion after the output register is READ and the master has generated a STOP CONDITION

  • If you want to select a different channel and read the previously converted value, in a single transaction, then you use a REPEATED START condition



Check out the attachment.
I'll have a look to the PCA9539, later this evening.

Thanks Dan,

I'm on the road right now.  I'll check it all out in one week.

-Chris

Hi Dan,
(DUE, 1.5.1r2)

I also have confirmed that a 'Stop' is always sent regardless of including true/false in endTransmission().

I can supply logic traces if anyone's interested.

Now, perhaps this neophyte could have a bit more help? 

How does one invoke 'TWI_Startread' in code?  Specifically, what would I include for the first parameter:
    TWI_StartRead(???, i2c_addr, i2c_register, 8 );

Thanks,

Chris

cdan

#7
Jan 24, 2013, 04:59 pm Last Edit: Jan 24, 2013, 05:01 pm by cdan Reason: 1
The first param is a pointer to a Twi structure denoting the I2C bus that you want to use.
In the case of arduino due there are 2 I2C buses, therefore you can use WIRE_INTERFACE_ID or WIRE1_INTERFACE_ID. Both of them are defined in hardware\arduino\sam\variants\arduino_due_x\variant.h

Dan,

Please forgive my ignorance on this matter.

However:
Code: [Select]
TWI_StartRead(WIRE_INTERFACE_ID, i2c_addr, i2c_register, 8 );
results in:
error: invalid conversion from 'int' to 'Twi*'
error: initializing argument 1 of 'void TWI_StartRead(Twi*, uint8_t, uint32_t, uint8_t)'


I have this uncomfortable feeling of not knowing the right questions to ask, and where to look to figure things out...

Regards,

Chris

cdan

It's my mistake. Use  WIRE_INTERFACE or  WIRE1_INTERFACE
You can find both defined in variant.h


After some turmoil, I have retreated to the state where only 1 byte at a time may be read from a slave.

Figure 34-20. "TWI Read Operation with Multiple Data Bytes with or without Internal Address" in the SAM3X8E datasheet seems out of reach. (Page 729, of the 28-May-12 revision)

I have found that a NACK is always generated after the 1st read by some unidentified mechanism, making multiple byte reads impossible.
For the desired protocol, see Figure 34-10. "Master Read with Multiple Data Bytes" (Page 721).

It seems that the Arduino community has been driving in circles over this problem for years.  For a sample:
http://code.google.com/p/arduino/issues/detail?id=28

I haven't been able to find a way to specify how the master (the Due) should respond for multiple sequential reads.

I have resorted to supporting only 1 byte reads for the foreseeable future.  This, of course, is a hack in my 50+ device I2C network.

Any ideas/suggestions?

Code: [Select]

    TWI_StartRead(WIRE_INTERFACE, i2c_addr, i2c_register, 1);
    Embiic_WaitByteXferComplete();
    for(i = 0; i < numOfBytes; i++) {
      //Need to set STOP condition WHILE reading the last byte...
      if ((i+1) == numOfBytes) {
        TWI_SendSTOPCondition(WIRE_INTERFACE);
        //DBG_PRINT("Sending last-byte STOP.");
      }
      Embiic_WaitByteReceived();
      //DBG_PRINTLN("Read_I2C_Values: Byte Ready");
      params[i] = TWI_ReadByte(WIRE_INTERFACE);
    }
    if (Embiic_WaitByteXferComplete()) {
      DBG_PRINTLN("Read_I2C_Values: Transaction completed successfully.");
    } else {
      DBG_PRINTLN("Read_I2C_Values: Transaction nottacompleted.");
    }

cdan

Can you please post a screenshot of the output from running your algorithm with numOfBytes=2 ?

The traces above are the same with any numOfBytes value.  That one was generated with nOB=3.

However, I get the same result for nOB= 1.

Of course, as you know, we expect the NACK on only the last read, and ACK's on all 1..n-1 reads.

The way that it is now, all reads beyond the first byte result in a timeout. (code below)

I suspect that there's a state machine somewhere (that I can't find), that I would like to look over.

I did find this:
/arduino-1.5.1r2/hardware/arduino/sam/system/CMSIS/Device/ATMEL/sam3xa/html/TWI0.html
which lists the TW registers in a nice format.  However, there isn't much to play with there.

Code: [Select]

boolean Embiic_WaitByteReceived() {
  unsigned long start, now;
  start = millis();
  while (!TWI_ByteReceived(WIRE_INTERFACE)) {
    //if (WIRE_INTERFACE->TWI_SR & TWI_SR_NACK) { // Failed ACK
    //  DBG_PRINTLN("Embiic_WaitByteReceived: Failed ACK.");
    //  Error_Code = 9010;
    //  return false;
    //}
    now = millis();
    if (now < start) {  // cheap! handle overflow, at at the expense of a longer timeout
      start = now;
      now++;
    } else {
      now = now - start;
    }
    if (now > I2C_READ_TIMEOUTmS){
      DBG_PRINTLN("Embiic_WaitByteReceived: Timeout.");
      Error_Code = 9011;
      return false;
    }
  }
  return true;
}

cdan

I have just order a Bus Pirate from a retailer in RO. I'll have it tomorrow and I'll give it a try too.
I have to look closer to this issue.

Go Up