Skip to main content
Benjamin Brammer
Senior II
January 21, 2019
Solved

MCU runs different in free running than in manual stepping in debug mode

  • January 21, 2019
  • 8 replies
  • 3368 views

Hey guys,

I have expereinced a very strange behaviour of my STM32F429ZIT6 custom board:

When I execute the following code the processor behaves differently in free running then in manual stepped mode or my oscilloscope seems to be completely broken - which I doubt.

			_5_PLUS_COIL_HIGH;
			delay_TIM10(50);
			STANDARD_COIL_LOW;
			_5_MINUS_COIL_LOW;

the macros behinde _5_PLUS_COIL_HIGH , STANDARD_COIL_LOW and _5_MINUS_COIL_LOW are simply GPIO output state settings:

#define STANDARD_COIL_HIGH										STANDARD_COIL_GPIO_Port->BSRR = STANDARD_COIL_Pin
#define STANDARD_COIL_LOW										STANDARD_COIL_GPIO_Port->BSRR = (STANDARD_COIL_Pin	<< 16U)
#define _5_PLUS_COIL_HIGH										_5_PLUS_COIL_GPIO_Port->BSRR = _5_PLUS_COIL_Pin
#define _5_PLUS_COIL_LOW										_5_PLUS_COIL_GPIO_Port->BSRR = (_5_PLUS_COIL_Pin << 16U)

and the function delay_TIM10(50) is a msec delay function:

#pragma GCC push_options
#pragma GCC optimize ("O3")
 
void delay_TIM7(uint32_t ucnt)		// IMPORTANT!! always check with clock speed for correct delays in STM32CubeMX
{
	uint32_t start = TIM7->CNT;
	while(tim7_tick() - start < ucnt);
}
 
 
void delay_TIM10(uint32_t mcnt)		// IMPORTANT!! always check with clock speed for correct delays in STM32CubeMX
{
	uint32_t start = TIM10->CNT;
	while(tim10_tick() - start < mcnt);
}
 
#pragma GCC pop_options
 
#define tim7_tick()												(TIM7->CNT)
#define tim10_tick()											(TIM10->CNT)

I halt the program per breakpoint at _5_PLUS_COIL_HIGH and trigger my oscilloscope on that pin to check for a rising edge, as the pin is LOW prior. Normally I would just hit run and the socilloscope would get triggered. But for a reason I don't know, the oscilloscope gets not triggered. When I maually step from the breakpoint the oscilloscope gets triggered.

Has anybody a clue why this is the case?

My processor runs only at 68MHz.

best regards

Benjamin

This topic has been closed for replies.
Best answer by Benjamin Brammer

I finally found the problem:

I used open-drain outputs. Now I switched them to push-pull and everything works fine (the delays and the GPIO switching). I must admit that I not really understand why this was the reason.. I am having a logic buffer connected to these GPIOs, but as far as I thought the buffer just needs a clear HIGH or LOW state as it is a high impedance input. I will look deeper int this.

Anyhow thanks for all the help and effort from different people!

P.S. Off course this could not work, as a logic "1" on an open-drain output is a high impedance state, so floating.

8 replies

Tesla DeLorean
Guru
January 21, 2019

Aren't those 16-bit TIM?​

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
Benjamin Brammer
Senior II
January 21, 2019

yes, they are, why?

Tesla DeLorean
Guru
January 21, 2019

Apt to make your delay routines malfunction as coded.​

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
Benjamin Brammer
Senior II
January 21, 2019

Could you please point this out to me as I don't understand why. I use these delay functions on different places in my code and so far they have worked right. But this still doesn't explain why stepped debugging behaves differently than free running, does it?

Piranha
Principal III
January 21, 2019

The delay functions will fail on timer overflow. Correct code for 16-bit timers is:

void delay_TIM10(uint16_t mcnt)
{
	uint16_t start = tim10_tick();
	while((uint16_t)(tim10_tick() - start) < mcnt);
}

Type cast is necessary because of integer promotion.

https://en.cppreference.com/w/c/language/conversion

What are the tick frequencies and are these delay functions executed somehow in parallel? Debugging changes timing and that can expose/hide problems with delay functions failing on overflow.

Benjamin Brammer
Senior II
January 21, 2019

Ok..please correct me if I misunderstand this, as I try to understand and learn:

my TIM-CNT register depth is 16bit. The variable start was defined by me with uint32_t so the variable gets filled up with zeros. The problem now occurs when I have a wrap around from the timer i.e. lets say the timer should count until value 2600 and I have a start value of 2400 but mcnt is 300. So the timer will wrap around after 200 counts and start from zero but now the while equation is a negative value as 0 -2400 = -2400 in this case the expression tim10_tick() - start would be an int32_t, right? and the while loop would break because -2400 < 300, correct?

but I am not sure what happens with the explicit conversion. Does the processor just treat the -2400 as an unsigend integer? bit this would be much higher than a starting value of 2600 after wrap around. I am a bit confused, I think.

After Forever
Senior III
January 21, 2019

uint32_t is an unsigned type, it can never be negative. 0 - 2400 wraps around and becomes 4294964896 instead of -2400.

Benjamin Brammer
Senior II
January 21, 2019

Ok, thanks for all the answers and clearification!

I now corrected the code and my oscillsocope gets triggered.. :D

but what is strange is that my scope shows me something different in free running than in stepped mode. in stepped mode I can see that pin _5_PLUS_COIL gets HIGH and after I step through until the end STANDARD_COIL and _5_MINUS_COIL become LOW, as expected with the program code. But in free running mode STANDARD_COIL and _5_MINUS_COIL become LOW prior to _5_PLUS_COIL becomming HIGH. And this takes about 300ms...really strange. Since I have interrupts active that could interrupt this process these might be the problem, but wouldn't I then be stepped to the appropriate ISR with manual stepping?

I was happy too early. When I am in free running mode inside a debug session the oscilloscope again gets not triggered. This is so strange..

Can anyone tell me why the processor is behaving like this? Since I have corrected the delay function, this should not be the cause of this problem, right?

I now seperatily measure the voltage on the pin with a multimeter..it does not become HIGH. so this means for reason I don't know yet the program code gets not executed under free run... I must say I quite don't understand this. since in debugging mode it works and the breakpoint gets triggered, so my software is running inside the apropriate ISR.

OK I will now examine the problem more in detail.

Benjamin Brammer
Senior II
January 21, 2019

I have now done a lot of different experiments and checking and I can surely tell that sometimes my oscilloscope does not trigger a rising edge. I have contacted the manufacturer and hope to find the answer..

Piranha
Principal III
January 21, 2019

I should add, that my example is correct only when using full scale of uint16_t - rolling over after 0xFFFF. That's because for uint16_t math the following is true: 1 - 65534 == 3. Do You use other rollover value? Is there a reason for it? Of course code can be made for other rollover values also, but using full unsigned integer scale is the most simple and efficient way.

Benjamin Brammer
Senior II
January 21, 2019

Hey Piranha,

I use 65535 as a roll over Value, so to my beliefs, the max value.

Benjamin Brammer
Senior II
January 22, 2019

I have now checked the program run with a different oscilloscope and the errors are the same. After I have replaced the delay_TIM10(50) function with a while(!HAL_GPIO_ReadPin(_5_PLUS_COIL_GPIO_Port, _5_PLUS_COIL_Pin)); the oscilloscope's diagram looks correct except of the timings: 0690X000006DBZOQA4.png

Approx. 117ms between just two simple register writes seems an awful lot to me. But in manual stepping this program code get's not interrupted by something else.

What Do you guys think could take so long? The HAL function?? I doubt that. The HAL routine looks clean and fast to me.

Benjamin Brammer
Senior II
January 22, 2019

I think I found the error: My delay function seems not to work properly. I tried to put a 500ms delay with delay_TIM10(500). I get an approx. 175ms delay.

I put the defines here again. Maybe I have still done something wrong. Btw my prescaler value is 64000 as for 1ms tick with a APB1/2 timer clock of 64MHz.

void delay_TIM10(uint16_t mcnt)		// IMPORTANT!! always check with clock speed for correct delays in STM32CubeMX
{
	uint16_t start = TIM10->CNT;
	while((uint16_t)(tim10_tick() - start) < mcnt);
}
 
#define tim10_tick()											(uint16_t)(TIM10->CNT)

After Forever
Senior III
January 22, 2019

If your SysTick is configured to tick every millisecond then just use its counter for millisecond delays:

void ms_delay(uint32_t ms)
{
 volatile uint32_t discard32 = SysTick->CTRL;
 
 (void) discard32;
 
 while (ms) {
 if (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) {
 ms--;
 }
 }
}

Or if you must use general purpose timers then use their interrupts. I.e. declare a global volatile uint32_t variable, in the timer overflow interrupt check if it's not zero then decrease it. When you want a delay just set the variable to some value and wait until it becomes zero.