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.

CC1352R: Only I2C Start interrupt but no data interrupt

Part Number: CC1352R

I'm writing a customized bootloader based on I2C communication. My bootloader code is sitting in the last flash page and erases all other flash pages. As a lot of TI driver function uses also some part from flash I can't use them. But I can use ROM functions and register access which I do to erase for example the flash pages.

FlashSectorErasePonter_t FuncPointer = (uint32_t (*)(uint32_t))(ROM_API_FLASH_TABLE[5]);
uint32_t result = FuncPointer(PageAddress);

I realized that when I call this function the next I2C frame leads only to a Start Interrupt. The then expected Data and Stop Interrupts are not received. When not calling the ROM function, even replacing with a delay, doesn't lead to problems. As the bootloader hasen't anything else to do instead of doing the I2C communication after one command was executed, I don't use interrupt routines. I poll the status register:

    uint32_t IntReg = HWREG(I2C0_BASE + I2C_O_SMIS);

    if (IntReg != 0)
    {
        uint32_t StatusReg = HWREG(I2C0_BASE + I2C_O_SSTAT);
        HWREG(I2C0_BASE + I2C_O_SICR) = I2C_SRIS_STOPRIS  + I2C_SRIS_STARTRIS + I2C_SRIS_DATARIS;

        if (IntReg & I2C_SMIS_STARTMIS)
        {
            //Start Interrupt received. So enabled Data and Stop Interrupts
            HWREG(I2C0_BASE + I2C_O_SIMR) |= I2C_SIMR_STOPIM + I2C_SIMR_DATAIM;
        }
        else if (IntReg & I2C_SMIS_STOPMIS)
        {
            //Stop Interrupt received. Data- und Stop-Interrupts are not used anymore
            HWREG(I2C0_BASE + I2C_O_SIMR) = I2C_SIMR_STARTIM;
        }
        else if (IntReg & I2C_SMIS_DATAMIS)
        {
            //Data interrupt receivef
            if (StatusReg & I2C_SSTAT_TREQ)
            {
                //Master want to read data. Send a byte
                HWREG(I2C0_BASE + I2C_O_SDR) = 0xFF;
            }
            else if (StatusReg & I2C_SSTAT_RREQ)
            {
                //Master has written data. Read it
                uint8_t aByte = HWREG(I2C0_BASE + I2C_O_SDR);
            }
        }
    }

I should have mentioned that CC1352 is the I2C slave. Also all my trace logic and the working with my data is removed from the source code listing above. From the trace I see (as said) that the data interrupt is not comming. I'm quite sure that the Master really wants to make a correct frame. But then it cannot happen, that I detect only the start condition but no data condition. Or am I wrong?

Regards
Erwin

  • Hi Erwin, 

    Thanks for your question. 

    I'll look into your issue and provide an update as soon as possible. 

    Thanks, 
    Elin

  • Hi Elin,

    I guess I have at least a workaround.

    First I organized a I2C sniffer and then observed the I2C bus in detail. From there I got the impression that there was a (up to a timeout in the sniffer) stretching of the code for the acknowledge bit.

    Putting then some extra logic into my I2C driver I saw, that the TREQ Bit in I2C0:SSTAT register was set even there was no DATAIM bit in I2C0:SRIS Register set. To me this would mean the HW has received the read request, which was shown by the STARTIM interrupt (bit), but the DATAIM interrupt is somehow lost. Therefore I don't put the data byte into the SDR data register. As a result the clock was stretched without end.

    Now I use the SRIS interrupt register only to detect the start and stop condition, which I need to setup my internal frame buffer correctly.

    Writing or reading of the SDR data register is solely based on the TREQ and RREQ bits in SSTAT. So this is totally independently from the DATAIM interrupt.

    With this implementation I haven't seen any error until now.

    I would be interested into the details when which interrupt is fired in detail. My expectation for an I2C slave is:

    • When the HW has detected a start condition and a matching address value it fires the STARTIM interrupt.
      In principle this could be done even before the R/W bit is received from HW.
    • If the received R/W bit indicates that the external master wants to read a byte from me (the slave) it fires the DATAIM interrupt.
      The HW stretches the clock of the ACK bit until I have written SDR as a result from the DATAIM interrupt. After that the master can read my given byte.
    • If the received R/W bit indicates that the external master want to write a byte to me no interrupt is fired.
      The address/RwBit is acknowledge from the HW without my intervention. The master writes then the first byte which my HW receives.
      When the last bit of this byte is received the DATAIM interrupt is fired and the HW stretches the clock until I have read SDR.
    • When the HW detects a stop condition the STOPIM interrupt is fired.

    As far as I know it's from I2C protocol point of view when a slave doesn't ACK one data byte. How can this be done with CC1352?

    Is there a document about all these details I would like to know?

    BR
    Erwin

  • Sorry, it was my mistake. As even shared I use an "else if" construct in the register bit checking. As a consequence I found the start interrupt but didn't check for data interrupt. But all interrupts are reset. Therefore the data interrupt is gone when I check the register only after start and data interrupts where received.

    Now it works also with checking SRIS register for data interrupts.

    But I would still be interested into an explanation when which interrupt comes in detail.

    BR
    Erwin

  • Hi Erwin,

    Glad to see you figuring out the issue on your own, as for the follow up point: "when which interrupt comes in detail", you mean when exactly the interrupt will fire in more detail then what is given in the Technical Reference Manual?

  • Hi M-W,

    yes I would like to have more details. Even I would say the information in the Technical Reference Manual is not very detailed. But to be fair the information is sufficient to use the I2C module.But it tells e.g. for the same data interrupt only that it is fired when data "is received or requested". the Command Sequence Flow Charts even don't talk about interrupts at all. I guess my understanding mentioned in my post before is correct, but would be good to get this somehow confirmed. Even a person that's haven't delt in such detail with I2C would be glad to get this information somewhere.

    According my current understanding it's even not possible to NACK some bytes as each ACK is generated automatically from the HW module. If for example I'm as a slave not ready to deliver the requested bytes I have to disable the module at all? So in that case the HW will not ACK the read request from the master for my slave address? Or is there a way to ack for example only the first two bytes to the master but later read attempts (of more bytes) will be NACKed?

    BR
    Erwin

  • Hi Erwin,

    I can't give you much more detail then this as of now. The flow charts typically does not include interrupt examples but the flow would be similar just that instead of polling a flag, you configure the interrupt. As you say, I think your understanding is already good and I could not really elaborate further into the "exact moment" the interrupt flag other then the TRM right now.

    As for the NACK/ACK case, it is my understanding that you have no option here really, the slave module will ACK properly received data/commands. In the case that you are not ready to receive it will stretch the clock signal until you have read/written the data to the buffer so you should not need to disable the module, just don't read out the data until ready.  I admit that this gives you less flexibility as you for example can't use the NACK as a "end of operation" indication but the I2C slave module in this case is more focused on being "simple". You would likely need to design the master side to be aware of how many bytes to read before sending the stop signal.