Skip to main content
Associate III
November 12, 2024
Solved

Delay, multi milliseconds, on the STM32F0, again..

  • November 12, 2024
  • 12 replies
  • 9213 views

where I wrote it among the codes.. // Here I have to wait 500ms.
Can you help me to prevent the timers from being affected by this wait?
Can you give me the codes that I will add. Because I am very confused..

I tried many things but they all stopped the interrupts..

 

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{

	if(htim->Instance==TIM1)
	{
		
	if(input1==0) 
	{
		HAL_GPIO_WritePin(GPIOA, GPIO_Pin_1, GPIO_PIN_SET);
		// Here I have to wait 500ms.
		HAL_GPIO_WritePin(GPIOA, GPIO_Pin_1, GPIO_PIN_RESET);
	}

}

 

 

 

 

 

This topic has been closed for replies.
Best answer by Karl Yamashita

Let's assume you're only looking a 3 inputs and controlling 2 outputs. 

Create a data structure to represent the look-up table

typedef union
{
	struct
	{
		uint8_t data[2]; // byte 0 is current state, byte 1 is last state
	}Byte;
	struct
	{
		uint8_t pa1:1;
		uint8_t pa2:1;
		uint8_t pc13:1;
		uint8_t :5;
	}Status;
}InputStatus_t;

 

Using EXTI for the input pins, we can use the HAL GPIO callbacks to set the input pin states. I've tested on a Nucleo-G071RB which uses a Rising and Falling callback where some STM's use 1 callback, but concept is the same.  

/*
 * Description: Update pin status for specific input.
 * Input: pin data structure, pin to update, the pin state
 */
void GPIO_UpdatePinStatus(InputStatus_t *input, uint8_t pin, GPIO_PinState pinStatus)
{
	switch(pin)
	{
	case 0:
		input->Status.pa1 = pinStatus;
		break;
	case 1:
		input->Status.pa2 = pinStatus;
		break;
	case 2:
		input->Status.pc13 = pinStatus;
		break;
	default:
		// invalid pin
		break;
	}
}

/*
 * Description: Functions as a HAL GPIO callback.
 * Note: no sw debounce incorporated.
 * See YouTube video to learn how to debounce push buttons that use EXTI
 * https://www.youtube.com/watch?v=o0qhmXR5LD0
 */
void GPIO_Callback(uint16_t GPIO_Pin)
{
	if(GPIO_Pin == PA1_Pin)
	{
		GPIO_UpdatePinStatus(&inputs, 0, HAL_GPIO_ReadPin(PA1_GPIO_Port, PA1_Pin));
	}
	else if(GPIO_Pin == PA2_Pin)
	{
		GPIO_UpdatePinStatus(&inputs, 1, HAL_GPIO_ReadPin(PA2_GPIO_Port, PA2_Pin));
	}
	else if(GPIO_Pin == PC13_Pin)
	{
		GPIO_UpdatePinStatus(&inputs, 2, HAL_GPIO_ReadPin(PC13_GPIO_Port, PC13_Pin));
	}
}

/*
 * STM32G071 HAL driver uses Rising and Falling callbacks where other STM32's use 1 callback.
 */
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
	GPIO_Callback(GPIO_Pin);
}

void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
{
	GPIO_Callback(GPIO_Pin);
}

 

By using a data structure to represent the look-up table, we can use switch-case to determine what state the input pins are. By checking for current pin state versus the last pin state, you can avoid having case 0 being called again. For case 0, PB12 is low, and PA10 is high. A timer callback is started and after 500ms, it turns Off PA10.

void GPIO_Check(InputStatus_t *input)
{
	if(input->Byte.data[1] != input->Byte.data[0]) // check for change, else do nothing.
	{
		input->Byte.data[1] = input->Byte.data[0]; // copy current state to last state

		switch(input->Byte.data[0]) // index of truth table
		{
		case 0:
			PB12_Off(); // pin is low
			PA10_On(); // pin is high
			TimerCallbackTimerStart(&timerCallback, PA10_Off, 500, TIMER_NO_REPEAT); // start timer to turn off PA10
			break;
		case 1: // all other case, PA12 is On (high state)
		case 2:
		case 3:
		case 4:
		case 5:
		case 6:
		case 7:
		default:
			PB12_On(); // pin is high
			break;
		}
	}
}

 

And the code for the GPIO outputs

void PA10_On(void)
{
	HAL_GPIO_WritePin(PA10_GPIO_Port, PA10_Pin, GPIO_PIN_SET);
}

void PA10_Off(void)
{
	HAL_GPIO_WritePin(PA10_GPIO_Port, PA10_Pin, GPIO_PIN_RESET);
}

void PB12_On(void)
{
	HAL_GPIO_WritePin(PB12_GPIO_Port, PB12_Pin, GPIO_PIN_SET);
}

void PB12_Off(void)
{
	HAL_GPIO_WritePin(PB12_GPIO_Port, PB12_Pin, GPIO_PIN_RESET);
}

 

The working code is on Github https://github.com/karlyamashita/Nucleo-G071RB_GPIO_Delay500/wiki

 

 

 

 

12 replies

waclawek.jan
Super User
November 12, 2024

It's a bad idea to wait in the interrupt (and the callback is part of the interrupt).

The proper way to solve this is to set a flag (marked volatile) in the interrupt/callback, and in the main loop then perform the pin writes and delay upon that flag.

JW

MM..1
Chief III
November 12, 2024
HAL_TIM_PeriodElapsedCallback

or any other ISR callbacks is executed in ISR context and can be interrupted only with ISR with higher priority.

Then if you place 500ms here any other same or lower ISR is not executed and blocked and main code too.

Are you sure for this?

KnarfB
Super User
November 12, 2024

HAL_Delay would work here if you set the priority of the timer interrupt lower than SysTick. As @waclawek.jan pointed out, spending long time in an interrupt handler is often considered bad style. Alternatives, besides the already suggested shifting to the main loop, could be: using another hardware timer in one pulse mode for firing a precise pulse in a timely manner or even using a RTOS with software timers for placing events in the scheduler time line.

In the end, it all depends on the overall design of your code/system.

hth

KnarfB

Andrew Neil
Super User
November 12, 2024

@KnarfB wrote:

HAL_Delay would work here if you set the priority of the timer interrupt lower than SysTick.


But could still block other interrupts - depending on their priority.

@XooM - As the others have said, it is generally a Bad Idea to have blocking delays (especially long blocking delays) in an interrupt handler.

Here is a better way:

https://community.st.com/t5/stm32-mcus-embedded-software/how-to-use-hal-gettick/m-p/741355/highlight/true#M56827

https://community.st.com/t5/stm32-mcus-embedded-software/how-to-use-hal-gettick/m-p/741449/highlight/true#M56836

 

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
Karl Yamashita
Principal
November 12, 2024

Looks like your just want to toggle a GPIO? You can use the Systick to accomplish this. Mix the Systick with a timer callback and you can do many cool things. See this video https://www.youtube.com/watch?v=o0qhmXR5LD0

 

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.CAN Jammer an open source CAN bus hacking toolCANableV3 Open Source
Tesla DeLorean
Guru
November 12, 2024

As was explained/suggested to you yesterday, in one of your multiple threads on materially the same topic, perhaps just flag that you SET the pin, and have a structure/queue which can down count from 500 in the SysTick / 1 KHz / 1ms task that it needs to RESET the pin when 500ms have elapsed.

You REALLY need to break this one-dimensional thinking where every thing needs to occur in sequential code execution.

The CALLBACK is done under INTERRUPT CONTEXT, you shouldn't be dwelling here for 1/2 SECOND.

If the SysTick has a pre-emption level above this it can continue to count, but like I said doing it this way is just bad thinking.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
Tesla DeLorean
Guru
November 12, 2024
volatile uint32_t Tick_PA1_On; // Time it was turned ON
volatile int PA1_On = 0; // Flag that is is ON

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
 if(htim->Instance==TIM1)
 {
 if(input1==0)
 {
 HAL_GPIO_WritePin(GPIOA, GPIO_Pin_1, GPIO_PIN_SET); // Turn ON PA1
 Tick_PA1_On = HAL_GetTick();
 PA1_On = 1;
 }
 }
}

...
in main loop, or SysTick Handler ??

 if (PA1_On)
 {
 if ((HAL_GetTick() - Tick_PA1_On) >= 500) // On for 500ms, turn it off now
 {
 HAL_GPIO_WritePin(GPIOA, GPIO_Pin_1, GPIO_PIN_RESET); // Turn OFF PA1
 PA1_On = 0;
 }
 }
Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
XooMAuthor
Associate III
November 13, 2024

Since my English is not very good, sometimes I can't understand what you say very well. I translate but it is not very accurate either. Short code outputs like the ones you gave me now speed up my understanding. Thank you very much. I will turn on my computer and try this in a moment. Now my way of thinking has changed a little.

XooMAuthor
Associate III
November 15, 2024

I tried to upload it here. I hope you can see it. 
The file is attached. How do I fix the errors?

Karl Yamashita
Principal
November 15, 2024

@XooM wrote:

I tried to upload it here. I hope you can see it. 
The file is attached. How do I fix the errors?


Look at my main.h file. It has an extern for the timercallback and some includes

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.CAN Jammer an open source CAN bus hacking toolCANableV3 Open Source
Karl Yamashita
Principal
November 17, 2024

You must not have read the last sentence in the Wiki? It says you need to add a call to TimerCallbacktick. You should have a file stm32fxxx_it.c in the src folder that has the SysTick_Handler

void SysTick_Handler(void)
{
 /* USER CODE BEGIN SysTick_IRQn 0 */

 /* USER CODE END SysTick_IRQn 0 */
 HAL_IncTick();
 /* USER CODE BEGIN SysTick_IRQn 1 */
 TimerCallbackTick(&timerCallback);
 /* USER CODE END SysTick_IRQn 1 */
}

Yes, the Timercallback.c/h can be used for any microcontroller. You're not limited to the Systick at 1ms.

You could also create a Timer interrupt for 100us and use both Timercallback instances, one for 1ms, and the other 100us.  

 

 

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.CAN Jammer an open source CAN bus hacking toolCANableV3 Open Source
XooMAuthor
Associate III
November 17, 2024

I guess I'm really ***. No matter what I do, it doesn't work.

TimerCallbackTimerStart(&timerCallback, PA10_Off, 500, TIMER_NO_REPEAT);
doesn't work..
PA10_off function doesn't work.

Karl Yamashita
Principal
November 17, 2024

Does PA10 turn on?

Attach your project

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.CAN Jammer an open source CAN bus hacking toolCANableV3 Open Source
XooMAuthor
Associate III
November 17, 2024

I couldn't do it with TimerCallback either
It didn't work like this either..
If PA2 is 0, PB14 should be 1 and PB14 should be 0 again for 500ms.

Karl Yamashita
Principal
November 17, 2024

You uploaded the wrong project. It doesn't have the TimerCallback files.

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.CAN Jammer an open source CAN bus hacking toolCANableV3 Open Source
Karl Yamashita
Principal
November 17, 2024

If you removed the files then how am i supposed to see what errors occurred? 

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.CAN Jammer an open source CAN bus hacking toolCANableV3 Open Source
XooMAuthor
Associate III
November 17, 2024

I added it in the message above and uploaded it again

Karl Yamashita
Principal
November 18, 2024

Your project still looks the same. Your while loop is empty so not much is going to work.

 

KarlYamashita_0-1731887068373.png

Your project tree should look like this

KarlYamashita_2-1731888214248.png

 

You don't have GPIO set up correctly for the ones that use EXTI. Only the pins that you are polling use Input mode.

I highlighted from my IOC what it should be like.

KarlYamashita_1-1731887940217.png

 

The TimerCallback.c/h and PollingRoutine.c/h just drop in your project. The only thing you need to do is change the GPIO names i've used to the name you used.

 

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.CAN Jammer an open source CAN bus hacking toolCANableV3 Open Source
XooMAuthor
Associate III
November 18, 2024

I did everything you said, but the errors are not decreasing.
Can you look at my project file? Please, I'm stuck and can't continue.

note1: I recreated the project. I added the file, but I can't solve the errors.

note2: I enabled NVICs and added the project again.

Karl Yamashita
Principal
November 18, 2024

@XooM wrote:

I don't have a program in the while loop. My program is in timer1 and timer16. When I do what you said, it gives an error, so I added the file.

I did everything you said but the errors are not decreasing.
Could you please look at my project file? Please I am stuck and cannot proceed.


What error? Added what file? Explain in more detail.

If you're talking about the latest project you've uploaded, did you even look at my main.h file? 

extern and #include are needed just like i have in my main.h which you need to add to your main.h

 

.

If a reply has proven helpful, click on Accept as Solution so that it'll show at top of the post.CAN Jammer an open source CAN bus hacking toolCANableV3 Open Source