2024-11-12 10:51 AM - last edited on 2024-11-12 02:04 PM by Tesla DeLorean
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);
}
}
Solved! Go to Solution.
2024-11-14 01:41 PM
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
2024-11-12 10:57 AM
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
2024-11-12 11:04 AM
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?
2024-11-12 12:08 PM
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
2024-11-12 01:26 PM
@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:
2024-11-12 01:40 PM
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
2024-11-12 02:03 PM
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.
2024-11-12 02:12 PM
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;
}
}
2024-11-12 09:45 PM
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.
2024-11-13 12:18 AM
PA1_On
isnt required , can be check on ODR register. But example code is ok. Better for you is start with normal explain, what your design need. For example:
Every checked input must react and light up LED ... reaction is important without delay or delay is allowed ? In your example pool is 1ms , then delay average to this, but you dont show where and how input1 is get/set.
When you go more advanced , then here some example idea how your 24 LEDS work complete offload MCU :
1. Create DMA buffer circular for 3x16bit SPI. Prepare values 0001 0002 0004 or by connection bits
2. Connect your 4094 to MOSI and CLK and SS on one free SPI peripheral setup it right and start DMA TX buffer from point 1. Set SPI speed to good refresh on LEDs... or based on timer
Now you have autonomous LED offload MCU and show data in buffer on all LEDs.
In your code for light up simple set bit in buffer ...