I2C Master Write, stuck in while loop ( I2C_WAIT_BYTE_COMPLETE)

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
KevinE
Level 3
Level 3
10 sign-ins 10 replies posted 5 sign-ins

Hello, 

I have seen many others having a similar issue, but wanted to post in case my issue is slightly different. 

I am using PSOC5LP I2C Master Mode with a DS2484 I2C to 1-Wire Converter. 

Everything is working fine  - I2C writes and reads, but there are times where something happens (Not sure what is causing this) and the PSOC hangs up in the below infinite while loop

KevinE_0-1656023814455.png

 

I have implemented a simple watchdog using a 1ms timer interrupt - when the watchdog counter fails to reset, I attempt to reset the I2C peripheral using the following lines. This does not work, and the code continues to sit in the while loop. 

The only thing that actually works is calling for a SW reset....Not ideal at all. 

Perhaps I'm not calling the right API to actually reset the I2C peripheral, if this is the case, please advise on the proper way to reset the peripheral so that I can break from the while loop. 

KevinE_1-1656023980066.png

From a logic analyzer standpoint, when this occurs, SCL and SDA are both logic High and remain at logic High

Ideally we do not want to call a software reset for something as small as this. Can anyone provide any input on what can be done to get "unstuck" from this infinite while loop?

I could implement a timeout inside the while loop, but I fear that this will be an issue when regenerating code, is that correct?

Please let me know what the best course of action to take is. 

Thank you, 

 




0 Likes
1 Solution
KevinE
Level 3
Level 3
10 sign-ins 10 replies posted 5 sign-ins

Hello, 

I have made some progress on this over the weekend by modifying the I2C component API generation files. By modifying the component source, I can make it so that PSoC creator generates the fix into the auto generated API. 

In doing so, I was able to include a counter that breaks the infinite while loop in the PSoC creator generated API calls. 

KevinE_0-1656344732298.png



In doing so, this has solved my issue of being stuck in this while loop. 

I strongly suggest that cypress include this fix, or a better fix as I have seen a lot of others having this issue with PSoC I2C. 

Thank you for your time into this issue - If you don't mind, please look over the fix I included in the above snippet and let me know if you would do it a different way. 

Would it be acceptable to copy the original I2C component and create an entirely new component? I should be able to copy all the source from the I2C component, include my fix and create a new component correct?

What would I need to change so that PSoC creator recognizes this as a different component instead of a duplicate?

View solution in original post

0 Likes
7 Replies
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

KevinE,

Are you willing to share your project with the forum?

It appears you're not using the standard I2C API calls.  It is not required but advised.

You're calling various functions (or macros) that I have not idea what they do in detail. [I2C_CHECK_MASTER_MODE() and I2C_WAIT_BYTE_COMPLETE()].

Note:  Normally reading a status register clears status bits after reading.  This might account for the reason for the infinite wait loop.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

Hello, thank you for the reply, 

I can create a stripped down version, but will take some time - I can't share the entire project. 

While I'm doing that:

These API calls are generated from PSoC creator and strictly used from the code examples within the IDE (I2C_WAIT_BYTE_COMPLETE()].)

If these are not the standard API calls, can you share a link so that I can inform myself on the advised API calls? I would much rather be using the advised API calls. 

It appears that the API call I referenced above is doing some housekeeping, writing the data to the register and waiting for the hardware to finish transmitting the byte. 

You mentioned reading a status register and clearing the status bits - does this mean that I could use my watchdog to clear the register (Bolded) therefore allowing the infinite while loop to break? (I2C_WAIT_BYTE_COMPLETE(I2C_CSR_REG). Can you give an example of how to properly do this?

I will upload the project when I finish stripping it, thank you

0 Likes

KevinE,

There is a I2C Master example project called "DegSig_I2CM".

On the TopDesign, there is placed a I2CM (I2C Master component).

Len_CONSULTRON_0-1656085543839.png

Selecting the I2CM component and right-clicking on "Open Datasheet ..." opens the  component datasheet.

In the datasheet there is a Chapter called "Application Programming Interface".  It is a multi-section with different API calls depending on the modes of operation selected for the I2C Master component.

There are API calls to transfer an entire packet of data [I2C_MasterWriteBuf()] or a single byte [I2C_MasterWriteByte()[].  

I2C_MasterWriteBuf() is a non-blocking function and will return from the function after starting the transfer.   Packet data will be pushed into the I2C transmit buffer using an internal Tx ISR routine.   The I2C_MasterStatus() is used to determine if the packet is complete or in-process.

I2C_MasterWriteByte() is a blocking function and will not return from the function until the byte is pushed into the I2C transmit buffer.

It is possible to use the registers directly in your code.  However, you need to make sure you fully understand how these registers operate to get correct operation.  

In theory, the API calls by the author of the component are intended to be the "well thought out" execution of the register usage to provide reliable operation.   Occasionally an operational issue is found after the component is published.  Sometimes, this requires recoding the component API internals.   That is why it is usually wiser to use the API calls and to update the component if available.

This is particularly true if the component is implemented in UDB blocks.  The UDB blocks are custom programmed with special register rules designed by the author of the component.   Using these UDB registers directly can be confusing and are generally not advised without full understanding of the internally operation of the component.


You mentioned reading a status register and clearing the status bits - does this mean that I could use my watchdog to clear the register (Bolded) therefore allowing the infinite while loop to break? 

The PSoC watchdog I'm used to automatically resets the CPU if triggered.


(I2C_WAIT_BYTE_COMPLETE(I2C_CSR_REG). Can you give an example of how to properly do this?

Since I don't know the function or macro of 

I2C_WAIT_BYTE_COMPLETE(I2C_CSR_REG)

I cannot answer that question.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
lock attach
Attachments are accessible only for community members.

I'm definitely going to try using the interrupt based approach rather than the blocking approach. Thank you. 

In the meantime, please find attached the project. 

this project is designed to be programmed into two differently configured hardware systems. The code will self identify and set the PSoC as an I2C master or slave. 

In one case, the PSoC will be an I2C master and communicate to a DS2484 I2C to 1Wire master, as well as an MCP9902 temp sensor. 

In the other case, the PSoC will be an I2C slave and communicate to a DS28e17 1Wire Slave to I2C Master. In this case, the PSoC needs to be configured as a slave, but also must switch to Master mode to communicate to another MCP9902 temp sensor. 

For the role switch, the only thing that has worked for me is to call I2C_Stop() / I2C_Start(). Please advise if there is something I'm missing to be able to switch roles. 

0 Likes
KevinE
Level 3
Level 3
10 sign-ins 10 replies posted 5 sign-ins

Hello, 

I have made some progress on this over the weekend by modifying the I2C component API generation files. By modifying the component source, I can make it so that PSoC creator generates the fix into the auto generated API. 

In doing so, I was able to include a counter that breaks the infinite while loop in the PSoC creator generated API calls. 

KevinE_0-1656344732298.png



In doing so, this has solved my issue of being stuck in this while loop. 

I strongly suggest that cypress include this fix, or a better fix as I have seen a lot of others having this issue with PSoC I2C. 

Thank you for your time into this issue - If you don't mind, please look over the fix I included in the above snippet and let me know if you would do it a different way. 

Would it be acceptable to copy the original I2C component and create an entirely new component? I should be able to copy all the source from the I2C component, include my fix and create a new component correct?

What would I need to change so that PSoC creator recognizes this as a different component instead of a duplicate?

0 Likes

KevinE,

I'm glad to hear you have 'solved' your issue.

Sorry for the delay in responding after you provided your project.  It takes a little longer to perform a code review since I don't have your same configuration to actually run.


...
I strongly suggest that cypress include this fix, or a better fix as I have seen a lot of others having this issue with PSoC I2C. 
...

In the review of your code, I found no reason for Cypress/Infineon to provide a 'fix'.  the code for the component is NOT in error.

I believe I've determined the issue you exhibited with the 'infinite loop'.  It is that in the "Master" mode, the I2C_CHECK_BYTE_COMPLETE() is tested for you and if the byte is complete, it will send the next byte in the buffer.

Here is the flow of code in I2C_INT.c lines 120 thru 307.

    if(I2C_CHECK_SM_MASTER)
    {
    #if(I2C_MODE_MASTER_ENABLED)
        if(I2C_CHECK_BYTE_COMPLETE(tmpCsr))
        {
...
 /* Many tests performed to determine if the next byte in the Tx buffer is to be sent */
...
        }
    }

When you try to read I2C_CSR with the I2C_WAIT_BYTE_COMPLETE() macro, the status of the 'byte complete' may be not correct and could be 'hijacked' by the I2C_INT.c code trying to do its job.

If you're willing to use the I2C_MasterWriteByte() function it is a blocking function and will not return from the function until the byte is pushed into the I2C transmit buffer.

If you'd prefer not to block your own main() task code then use I2C_MasterWriteBuf().  It is a non-blocking function and will return from the function after starting the transfer.   Packet data will be pushed into the I2C transmit buffer using an internal Tx ISR routine.   The I2C_MasterStatus() is used to determine if the packet is complete or in-process.

 

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

Thank you for the meaningful responses, I will keep this in mind moving forward.  

I understand that Infineon/Cypress may not want to 'fix' this issue. If this HiJacking phenomenon occurs, I would rather have some kind of Fix in place to safeguard against this. I have built in persistency on my I2C communication that will allow for re-transmissions of this occurs. 

The code only seems to get stuck in this while loop on occasion. I believe it to be an issue with the slave device - which I need to treat as a black box unfortunately. 

So perhaps this is a case study in my scenario. 

 

Again, thank you for your time!

0 Likes