Why is my function static variable never different, despite the increase?

I am writing a callback function in C. It is intended to initialize the I2C sensor, and it is called at the end of each configuration step (split phase); after the 9th call, the device is almost ready for use.

The main idea of โ€‹โ€‹the function is as follows:

void callback(void) { static uint8_t calls = 0; if (++calls == 9) { // Finalise device setup (literally a single line of code) } } 

My problem is that the above if statement is never entered, even though the function is called 9 times.

The summary code (dis) for my function seems reasonable (except for the subi . 0xFF trick for incrementing, despite the inclusion of the inc statement):

 00000a4c <callback>: a4c: 80 91 9e 02 lds r24, 0x029E a50: 8f 5f subi r24, 0xFF ; 255 a52: 80 93 9e 02 sts 0x029E, r24 a56: 89 30 cpi r24, 0x09 ; 9 a58: 09 f0 breq .+2 ; 0xa5c <callback+0x10> a5a: 08 95 ret a5c: 2e e1 ldi r18, 0x1E ; 30 a5e: 35 e0 ldi r19, 0x05 ; 5 a60: 41 e0 ldi r20, 0x01 ; 1 a62: 60 e0 ldi r22, 0x00 ; 0 a64: 84 e7 ldi r24, 0x74 ; 116 a66: 0c 94 c7 02 jmp 0x58e ; 0x58e <twi_set_register> 

I am writing code for the Atmel AVR chip and thus compiling with avr-gcc. I donโ€™t have significant features for debugging code (I donโ€™t have access to the JTAG programmer, and the function is in any case an asynchronous / split phase, USART printing is too slow).

However, I do have access to a logical analyzer, and I was able to determine several things by placing while (1) ; in the code while (1) ; :

  • the function is called - if I put an infinite loop at the beginning of the function, the microcontroller hangs
  • the function must be called 9 times - the trigger for the function is the I2C exchange, and in the previous step it hangs immediately after the first message; I can observe 9 complete and reliable I2C messages
  • calls increase within the function - if I add if (calls == 0) { while (1) ; } if (calls == 0) { while (1) ; } after the increment, it does not hang
  • calls are never non-zero at the beginning of the function - if I add if (calls) { while(1) ; } if (calls) { while(1) ; } before the increment, it does not hang

I completely lose ideas.

Does anyone have any suggestions as to what might cause this, or even for new debugging steps that I could take?

+4
source share
2 answers

For what you are saying, I can only think of three possibilities: 1) your assumption that the function is called on every I2C message is incorrect, 2) your program has an error (possibly a memory leak) in some unrelated function, which causes damage to the call variable. or 3) two or more threads simultaneously call your function, and calls increase in a different way than you expect, use instead of == , if this solves the problem, then you are working in an environment with milti-threaded, and you do not know.

You need an exact method to determine the exact value of calls if you do not have a debugger and you do not have the means to display the text. The only thing you left is playing time. I donโ€™t know that you are a compiler, but Iโ€™m sure that it contains some useful synchronization functions, so I would loop before incrementing for 10+ seconds calls, and after incrementing again 10+ calls seconds, for example:

 sleep(1000*(10+calls)); ++calls; sleep(1000*(10+calls)); if(calls>8){ // your actual code } 

I would (chronometer in hand) expect a delay (10 + 0 plus 10 + 1) = 21 seconds on the first call, 23 seconds on the second call, 25 in the third and so on. Thus, I could be sure that the value of the calls started from 0, and then it gradually increased to 9.

In addition, you should check what you expect from what you don't expect, so instead:

 ++calls; if (calls==0) while (1); 

do the following:

 ++calls; if (calls==1) while (1); 

Thus, if your program freezes, you can be sure that the call value is exactly 1, and not regardless of zero. If you count one valid I2C relationship and your program freezes, the transition from 0 to 1 was performed correctly, so change the hang operator accordingly:

 ++calls; if (calls==2) while (1); 

Again, if you count 2 valid I2C messages before your program freezes, it means the transition from 1 to 2 was correct, etc.

Another suggestion, try the following:

 uint8_t Times(void){ static uint8_t calls = 0; return ++calls; } void callback(void){ if (Times()>8) { // Your actual code } } 

And this:

 void callback(void){ static uint8_t calls = 0; if (calls++>7) { // some code. } } 

Hope this helps.

+2
source

As a result, I discovered the cause of the error; another subsystem broke down as a side effect of the first callback function call, which meant that no other calls were successful.

This explains the behavior I saw:

  • he hung for the first time because he was actually called
  • he did not hang a second time (or any future) because he was called only once
  • I2C transactions occurred that I observed, but their callback mechanism did not work correctly, due to a violation of the subsystem (tasks)

I managed to do this using several GPIO pins as debug switches and thus tracking how the call evolves through the TWI interface.

Thanks for helping the guys. This is actually not the answer to the original question, but it has been resolved, so something :)

+4
source

Source: https://habr.com/ru/post/1500531/


All Articles