How does I2C_Start() affect flash?

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

cross mob
PrMa_264311
Level 3
Level 3
First like received

I have a piece of code that is continuously calculating a program CRC by scanning the PSoC4 program space. The initial CRC is calculated on the first POR. A 16-bit CRC is then stored in the last 2-bytes of the last row of the FLASH space and referenced for comparison. So, I scan from 0x0 to 0x00008000-sizeof(CRC). If the program memory ever changes during operation (i.e. the running CRC does not match the program CRC) the program is instructed to produce a fault code and discontinue normal operation. 

   

I have been testing my project extensively. Everything works great. When I intentionally corrupt a random location in flash, as is typically done during verification and validation testing, the CRC checking catches the fault as expected. 

   

Now here's the gotcha I'm hoping someone has an answer to. I have an I2C peripheral in the system, which is optionally enabled depending upon the device connected to a group of shared pins. During testing, I enable the I2C SCB by calling I2C_Start(). It is similarly disabled by calling I2C_Stop(). Within moments of calling I2C_Start() (and nothing else), the CRC checking process registers a change in the program memory and throws an error. I am surprised by this because the registers the processor and SCB blocks utilize are outside of my scanning area (0x40000000 – 0x4000FFFF and 0x40060000- -0x4006FFFF respectively).

   

I can only conclude that something in flash is changing but can find very little in the TRM to suggest what that might be. This behavior is the same whether interrupts are enabled or not during I2C_Start(). 

   

Does anyone know what in Flash is changing, where it is changing, or what other side effect starting I2C might have that ismaking the program think something is changing?

   

Thanks.

0 Likes
15 Replies
Anonymous
Not applicable
        1. If you don't start/enable the I2C, the CRC check is correct? 2. Can you set it up so that the i2C is enable/disable by an input pin. ie high to enable i2C and low to disable CRC run the program with pin high and low and see if that still fail. 3. If it only fail every time the pin is high. If it is possible, set and clear another output pin when ever you call the write to flash function call. Use a CRO to see if it was being called.   
0 Likes
Anonymous
Not applicable
        I got the small text box again 😞   
0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

Curious, after the first CRC generate/store cycle, w/o starting I2C, you

   

do another CRC check that passes ? Thought is your scan ptr is one

   

byte off (or something like this) and picking up the change in flash due

   

to CRC write into last 2 rows of flash. The pointer of course would be

   

declared volatile if used in an ISR.

   

 

   

Regards, Dana.

0 Likes
PrMa_264311
Level 3
Level 3
First like received

 Here are a few more interesting clues. I tried making the CRC checking process atomic. That didn't fix anything. CRC still fails. The original idea behind the CRC check is that if the program CRC fails even once, it is forever failed. So this time I just allow that flag to be re-set to OK if the CRC passes in a subsequent run. That worked...but is only a bandaid to the problem. It does give some clues about where the problem lies.

   

So there are a couple other possibilities. The running CRC value could become corrupt, though it is a static variable declared within a function and inaccessable (in theory) to the outside world. The error flag could become corrupt, but that is also a static variable. Or the stack could become corrupt.

   

The evidence seems to point to the flag becoming corrupted. But I am not manipulating the stack in any way besides calling API functions. So something may be growing into it somehow. I tried growing the stack in CYDWR, but that didn't help either.

   

My next step is to look into the assembly and see where things are located. I will have to get back to you on that though.

   

In any case, the problem only occurs when I2C_Start() is called.

0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

Evidence as you point out sure seems to indicate ISR related.

   

 

   

If you use a pointer for next byte access in CRC computation, thats

   

what needs to be declared volatile to insure immunity from ISR

   

related corruption.

   

 

   

Regards, Dana.

0 Likes
Anonymous
Not applicable
        If may, Does I2C_Start routine using same CRC generator hardware?   
0 Likes
Anonymous
Not applicable

1. You mentioned that you make the CRC check atomic, I assume you have all interrupt disabled during the CRC check process.

   

2. If you just start but disable the i2C at start up only once, see if that makes any difference?

0 Likes
PrMa_264311
Level 3
Level 3
First like received

 I appreciate all the thoughts. I will try answering some questions.

   

1. If you don't start/enable the I2C, the CRC check is correct? 2. Can you set it up so that the i2C is enable/disable by an input pin. ie high to enable i2C and low to disable CRC run the program with pin high and low and see if that still fail. 3. If it only fail every time the pin is high. If it is possible, set and clear another output pin when ever you call the write to flash function call. Use a CRO to see if it was being called. 

   

1. If I don't start the I2C peripheral, CRC checking always works. I've neve seen it fail unless I intentionally corrupt the program space for purposes of verification and validation. 

   

2. I am unable to use another pin. The chip is in a system and I don't have easy access to pins. I can send commands to the chip to enable and disable I2C on the fly, which is where I see the problem.

   

3. I'm not writing flash during this process. I only read the flash. The 16-bit program CRC is written only once during the life of the chip. During the very first power up of the chip, a complete system CRC is calculated. This value is stored at the end of the program flash and never written again. It is assumed that this value represents a valid program. Runtime CRC calculations simply compare a calculated result with that stored in flash.

   

 

   

Curious, after the first CRC generate/store cycle, w/o starting I2C, you
do another CRC check that passes ? Thought is your scan ptr is one
byte off (or something like this) and picking up the change in flash due
to CRC write into last 2 rows of flash. The pointer of course would be
declared volatile if used in an ISR.

   

Yes. Complete program CRCs are calculated repeatedly approximately every 2 seconds. They are always correct without starting I2C. The CRC function is not in an ISR. It is called from main during idle cycles. My program is a non-blocking super-loop.

   

Simplified super loop execution looks like this:

   

while(1)
{

   

if regularly occuring event asserts
{

   

take care of it

   

}

   

else // now in idle time

   

{

   

run incremental crc check

   

}

   

}

   

I have tried halting interrupts while the "run incremental crc check" code executes by using "CyGlobalIntEnable" and "CyGlobalIntDisable" commands around it. That doesn't help.

   

 

   

Evidence as you point out sure seems to indicate ISR related.

If you use a pointer for next byte access in CRC computation, thats
what needs to be declared volatile to insure immunity from ISR
related corruption.

   

I have tried declaring the CRC variables as volatile (again, these are not within an ISR). It doesn't help.

   

If may, Does I2C_Start routine using same CRC generator hardware?

   

My CRC function is sofware and unrelated to I2C functionality.

   

1. You mentioned that you make the CRC check atomic, I assume you have all interrupt disabled during the CRC check process.
2. If you just start but disable the i2C at start up only once, see if that makes any difference?

   

1. Yes, as mentioned above, I have tried disabling interrupts during CRC computation. This, however, is unnecessary given how the program is written, assuming ISRs execute and return properly. The result was the same; CRC failed.

   

2. How would you propose disableing the I2C? There is of course no I2C_Disable() function.

0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

You might consider posting a case at -

   

 

   

    

   

          

   

www.cypress.com

   

“Support”

   

“Technical Support”

   

“Create a Case”

   

 

   

This should take care of disable -

   

 

   

0 Likes
HeLi_263931
Level 8
Level 8
100 solutions authored 50 solutions authored 25 solutions authored

Can you post the code for calculating the CRC?

   

If have an idea I would need to verify:

   
        
  • according to the PSoC4 TRM the executable memory is from 0x00000000 up to 0x1fffffff
  •     
  • out of that range, 0x00000000 up to 0x00007fff is flash memory
  •     
  • but an "exception vector table" is located at 0x00000000
         
            
    • it is used as interrupt table too (see TRM page 38)
    •      
  •     
  • so it might be that starting the I2C component just sets a new interrupt vector, and therefore changes this location
  •    
   

So you can test this by just excluding that region. Or by checking whether the exception handlers 26 or 27 change - these are the ones for the SCB blocks. If you are advantageous, you can trace the call sequence for the I2C_Start() function down to what it really does, probably down to the assembler level...

0 Likes
PrMa_264311
Level 3
Level 3
First like received

 That is exactly how I stop I2C. That's not the problem.

   

With regard to the vector table, I checked both locations and could not find any changes to those memory locations.

0 Likes
PrMa_264311
Level 3
Level 3
First like received

 Hi danaaknight and hli,

   

I think I missunderstood your comments. I tried what you suggested. I executed the following 

   


I2C_Start();
I2C_Stop();
CRC_Init(); // initialize program CRC if it hasn't been

   


And guess what? It works. I can start and stop the I2C peripheral after that and the system calculation CRC remains correct.

   


If you swap them:

   

CRC_Init(); // initialize program CRC if it hasn't been
I2C_Start();
I2C_Stop();

   

it fails. So, you both are on to something. I'm not sure what yet though. Perhaps a new interrupt vector was created, as suggested by hli. I'm just not seeing it during the debugging session with memory watch. I've tried skipping the first few bytes of program memory, but haven't had success yet.

0 Likes
Anonymous
Not applicable

Is the function  "CRC_Init()" perform the CRC calcution and write the value to the flash if it is the first time being called?

   

if it is, how do you determine if it is the first time or not? Would that flag/byte used for checking corrupted so it didn't write the CRC and the next time it failed as the CRC value was not written

0 Likes
Anonymous
Not applicable

I need an edit function.

   

 

   

Press post too quickly

   

 

   

You have a function to perforn the CRC calcution and write the value to the flash if it is the first time being called?

   

if it is, how do you determine if it is the first time or not? Would that flag/byte used for checking corrupted so it didn't write the CRC and the next time it failed as the CRC value was not written

0 Likes
PrMa_264311
Level 3
Level 3
First like received

The programming process by default will clear all flash contents. That is, all flash is written to 0x00. You can specify otherwise, but I choose to leave it that way. CRC_Init checks the CRC location. If it is 0x0000, the system CRC must be calculated and written for the first time.

0 Likes