INTRODUCTION
This project demonstrates concurrency through hardware timers and interrupts: TIM2 and TIM3 run independent background tasks at 1Hz and 2Hz, while a button press triggers an immediate foreground response, all coordinated through a foreground/background cyclic executive.
HARDWARE SETUP
- Board: RT-Thread RT-Spark (STM32F407ZGT6)
- LED_RED: PF11
- LED_BLUE: PF12
- DEBUG_PIN: PE0 (used for ISR timing measurements)
- User Button: PA0 (configured as external interrupt, rising edge, pull-down)
SOFTWARE SETUP
The system follows a foreground/background design:
- Background tasks (ISRs): TIM2 fires every 1 second (highest priority), TIM3 fires every 0.5 seconds (lower priority). Both simply toggle their LED and set a flag for the foreground to process.
- Foreground tasks (main loop): continuously checks the flags set by the ISRs and runs the corresponding task (Task A for TIM2, Task B for TIM3, Task C for periodic background monitoring).
- Event-triggered task: a button press on PA0 triggers an EXTI interrupt that directly toggles both LEDs immediately, independent of the main loop — demonstrating fast, asynchronous event handling.
- TIM2: Prescaler = 8399, ARR = 9999 → 1 Hz interrupt (with PLL configured for 84 MHz APB1 timer clock)
- TIM3: Prescaler = 8399, ARR = 4999 → 2 Hz interrupt
- NVIC priorities: TIM2 = 0 (highest), TIM3 = 1, EXTI0 = 2 (lowest)
HOW IT WORKS:
- At startup,
main()initializes TIM2 and TIM3 and starts both with interrupts enabled. - TIM2 counts up and overflows every 1 second, firing its ISR — this toggles the RED LED, sets the
task_adc_readyflag, and incrementstick_count. - TIM3 counts up and overflows every 0.5 seconds, firing its ISR — this toggles the BLUE LED and sets the
task_display_readyflag. - Back in the main loop, the foreground code continuously checks these flags:
- If
task_adc_readyis set → runs Task A (simulated ADC processing, 50ms) - If
task_display_readyis set → runs Task B (simulated display update, 20ms) - If
tick_count >= 10→ runs Task C (10-second periodic check) and resets the count - Meanwhile, the button (PA0) is wired as an external interrupt. Pressing it fires the EXTI ISR, which immediately toggles both LEDs, bypassing the main loop entirely, so the response is instant regardless of what the foreground tasks are doing.
- This combination of two independent timers driving background flags, a foreground loop consuming them, and an asynchronous button interrupt, demonstrates a complete foreground/background (cyclic executive) scheduling model.
Using the STM32CubeIDE debugger with the DWT cycle counter (84 MHz clock):
Observations:
RED LED (TIM2) blinks every 1 second, BLUE LED (TIM3) blinks every 0.5 second — since TIM3 has the shorter period, BLUE toggles first and twice as often as RED. Pressing the button toggles both LEDs immediately, regardless of where the main loop is in its cycle, confirming that hardware interrupts can preempt the foreground tasks at any time.
ANALYSIS
The ISR execution time itself is negligible (~0.65 µs), confirming that the actual response time is dominated by the task processing time (e.g., 50ms for Task A), not by interrupt overhead. In the worst case, Task A's latency can reach ~20ms if it has to wait for Task B (HAL_Delay(20)) to finish in the non-preemptive main loop, giving a worst-case response time of ~70ms. A preemptive scheduler would reduce this to near-idle latency (~5µs) by allowing higher-priority tasks to interrupt lower-priority ones immediately — at the cost of added complexity and potential priority inversion issues.
GitHub Link:https://github.com/bertaldearias/Arias-Timer-ISR-Lab1





_IhUWeM3aQA.png)

_3u05Tpwasz.png?auto=compress%2Cformat&w=40&h=40&fit=fillmax&bg=fff&dpr=2)

Comments