This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS570LS3137: I2C repeated start condition using interrupts

Part Number: TMS570LS3137
Other Parts Discussed in Thread: HALCOGEN

I've been struggling to get the i2c device to actually create a restart condition using interrupts exclusively. My application is such that a busy-wait would be problematic.

Here is my code using a busy wait to generate a repeated start:

    ((Tms570I2cHandle_t*)master)->i2c->MDR &= ~(I2C_STP_BIT);
    i2cSetSlaveAdd(((Tms570I2cHandle_t*)master)->i2c, device_address);
    i2cSetDirection(((Tms570I2cHandle_t*)master)->i2c, I2C_TRANSMITTER);
    i2cSetMode(((Tms570I2cHandle_t*)master)->i2c, I2C_MASTER);
    i2cSetCount(((Tms570I2cHandle_t*)master)->i2c, num_sub_address_bytes);
    i2cSetStart(((Tms570I2cHandle_t*)master)->i2c);

    //Send subaddress
    i2cSend(((Tms570I2cHandle_t*)master)->i2c, num_sub_address_bytes, (uint8_t*)(&sub_address) + (4-num_sub_address_bytes));

    //wait for tx ready, indicating that we've sent the subaddress successfully
    while(!i2cIsTxReady(((Tms570I2cHandle_t*)master)->i2c));

    i2cSetSlaveAdd(((Tms570I2cHandle_t*)master)->i2c, device_address);
    i2cSetDirection(((Tms570I2cHandle_t*)master)->i2c, I2C_RECEIVER);
    i2cSetCount(((Tms570I2cHandle_t*)master)->i2c, transfer_size);
    i2cSetMode(((Tms570I2cHandle_t*)master)->i2c, I2C_MASTER);
    i2cSetStop(((Tms570I2cHandle_t*)master)->i2c);
    i2cSetStart(((Tms570I2cHandle_t*)master)->i2c);
    i2cReceive(((Tms570I2cHandle_t*)master)->i2c, transfer_size, data);

I would like to be able to remove the busy-wait after the i2cSend, and instead wait for a txrdy interrupt. I've modified the halcogen code so that it should generate the tx notification after every byte, but it does not seem to help. I don't seem to be actually getting a tx notification when the send is done. I've noticed that the i2csend notification is broken, since it sends the notification *before* the last byte has been shifted out, which is not useful in this case. I want to know when the device can be put into a receive mode.

I've looked into the ARDY bit, but I don't fully understand what exactly it indicates, as the documentation is fairly vague. How does ARDY work? What interrupt will let me know when I can start receiving after sending the subaddress?

Thank you.

  • So shortly after posting this I resolved this issue. I ended up ripping out the halcogen calls in my code and relying on direct register banging for this. Here's what got it to work for me:

    Read at subaddress with repeated start procedure:

    • Set CNT to the number of subaddress bytes (usually 1)
    • Set slave address
    • Set MDR to master | transmitter | start | nIRS. Note: make sure the stop bit is *not* set.
    • Enable txrdy interrupt and send the first byte to kick off the transfer
    • You will get a txrdy after each subaddress byte EXCEPT the last one (when CNT = 0). With this knowledge, you can clock out all the subaddress bytes.
    • You will receive an ARDY interrupt once CNT = 0 after the last byte is clocked out. This is your cue to switch to receive mode, reset CNT to the number of bytes to receive (unless using freerunning mode)
    • Receive like normal, reading a byte after each rxrdy interrupt.

    This is the interrupt behavior:

    • TXRDY: emitted after each byte is sent *except* when CNT == 0. I assume the logic here is that you use txrdy interrupt to send bytes out, so once CNT == 0, there should be no more bytes to send and no reason to wait on this interrupt. This is where ARDY is used.
    • I think ARDY is emitted when CNT is zero, after transmitting the last byte. There may be other times ARDY is emitted, but this is what I use it for. Use it as a queue to switch from TX mode to RX mode. Note: the ARDY bit in the STR register must be cleared manually in the ardy interupt handler by writing a 1 to that bit. If you don't do this, you will get slammed with an ARDY interrupt hammer and your device will hang until you power cycle it.

    Recommendations:

    • Don't use the halcogen driver if you plan on using an interrupt driven approach. It's far simpler to just implement the register accesses yourself.
    • If you do use halcogen, *don't* rely on the notification function to tell you when you can send data again. The tx notification is sent before the last byte of the transfer is sent, because there is no tx notification after it. (see above for explanation). Thus, if you try to chain write transfers together, this notification will be useless here. Instead, use ARDY.
    • The ARDY description in the datasheet is pretty vague an unhelpful. Experimenting with it is very useful here. See the above section for what I think ARDY actually does.

  • Hello,

    Thanks for the feedback!

    Best regards,

    Miro