The problem
An EV controller that hangs or browns out with the motor driver on or the relay closed is dangerous. Production ECUs use watchdogs, supply monitoring and a defined safe state at every reset. Students often add a watchdog without proving it catches real failures.
Objectives
- Define the safe state of every output on the kit.
- Implement IWDG and a task-health check that feeds it only when all functions are alive.
- Use the PVD to detect a falling supply and act before reset.
- Read, log and display the reset cause on every start-up.
- Inject faults and prove each one ends in the safe state.
What you need
From the EV Embedded Development Kit
- STM32F103C8T6 main controller
- General output relay (NO / COM / NC)
- Motor driver for PWM motor-control experiments
- RGB LEDs
- Buzzer
- 16×2 LCD
- 4×3 matrix keypad
- Serial UART interface
Software
- STM32CubeIDE with HAL drivers
- Embedded C
- A serial terminal or Python with pyserial
Extra parts
- Adjustable bench power supply (optional) — To lower the supply slowly and test the PVD warning, only if the kit's power port and regulator allow it; otherwise the PVD path is tested by software injection.
Key concepts
- Independent watchdog (IWDG)
- A counter clocked from the internal LSI oscillator (about 40 kHz, not precise) that resets the MCU unless refreshed in time. It keeps running even if the main clock fails.
- Task-health watchdog
- Each function sets a flag when it completes; the watchdog is refreshed only when all flags are set, so a single stuck function causes a reset.
- PVD
- The programmable voltage detector compares VDD with a selectable threshold and raises an interrupt, giving warning before the fixed power-down reset. The STM32F103 has no programmable brown-out reset, so the PVD fills that role.
- Reset cause
- RCC->CSR flags record whether a reset came from power-on, the reset pin, software, IWDG, WWDG or low-power management; they must be read and cleared at boot.
- Safe state
- The output condition that cannot cause harm: relay de-energised, motor PWM off, loads off, warning indicated.
Step-by-step guide
- 1
Define the safe state and failure modes
List every output and its safe value: relay coil off (state which contact, NO or NC, is safe for your demo load), motor driver PWM at 0 with enable off, buzzer and LEDs indicating fault. List failure modes to cover: infinite loop, stuck interrupt, HardFault, stack overflow, clock failure and supply dip. For each, say how it will be detected and what the system does.
Checkpoint: A failure-mode table with detection mechanism and expected end state for each row.
- 2
Make outputs safe from the first instruction
In CubeMX set initial GPIO levels for the relay and motor driver enable to their safe values, and make sure MX_GPIO_Init runs before anything else that could drive them. Check that pins float to a safe level during reset, before firmware runs, by measuring them while holding the reset button. Set the DIP switches for the relay, motor driver, LEDs, buzzer, LCD and keypad.
Checkpoint: During reset and after boot, the relay and motor driver are measured off.
- 3
Log the reset cause
At the start of main, read the flags with __HAL_RCC_GET_FLAG (RCC_FLAG_IWDGRST, RCC_FLAG_WWDGRST, RCC_FLAG_SFTRST, RCC_FLAG_PORRST, RCC_FLAG_PINRST, RCC_FLAG_LPWRRST), save them, then clear them with __HAL_RCC_CLEAR_RESET_FLAGS. Show the cause on the LCD and print it over UART. Count consecutive watchdog resets in an RTC backup register (enable backup domain access first) so they survive a reset. Keep a short history of the last few causes for diagnosis.
Checkpoint: Pressing reset shows 'PIN', power cycling shows 'POR', and a software reset with NVIC_SystemReset shows 'SFT'.
- 4
Configure the IWDG
Enable the IWDG with a prescaler and reload giving a timeout of about 500 ms, remembering the LSI tolerance means the real timeout can differ noticeably; design the refresh period with plenty of margin. Refresh with HAL_IWDG_Refresh. Note that once started the IWDG cannot be stopped except by reset, and decide whether it should keep running when the debugger halts the core (DBGMCU freeze bit).
Checkpoint: Removing the refresh call causes a reset, shown as 'IWDG' on the next boot, at a measured interval near the design value.
- 5
Build the task-health check
Give each function (sensor read, control loop, display, keypad, communications) a bit in a health word that it sets each time it completes. A supervisor running every 100 ms checks that all bits are set, refreshes the IWDG, then clears the word. If any bit is missing it does not refresh, so the watchdog resets. Add a timer-based check that the control loop period is within limits.
Checkpoint: Blocking any single function in a test build causes an IWDG reset within the expected time.
- 6
Handle HardFault and stack overflow
Write a HardFault handler that immediately forces the safe state on the relay and motor driver pins with direct register writes, stores fault information (stacked PC, LR and fault status registers SCB->CFSR and SCB->HFSR) in a backup register or reserved RAM, then waits for the watchdog or calls a system reset. Place a stack canary pattern at the stack bottom and check it in the supervisor.
Checkpoint: A deliberate null-pointer write ends in the safe state, and the next boot prints the faulting address.
- 7
Add supply monitoring with the PVD
Enable the PVD with HAL_PWR_ConfigPVD at a threshold above the power-down reset (for example 2.9 V) and HAL_PWR_EnablePVD, with its EXTI interrupt. In the handler, force the safe state, save a 'power dip' record and stop non-essential activity. If a bench supply can safely lower the board's supply through the power port, test it slowly; otherwise test the handler by triggering its code path from a debug command.
Checkpoint: The PVD handler forces the safe state and the dip is recorded and reported on the next boot.
- 8
Add a restart policy
After a watchdog or fault reset, start in a degraded mode: motor output disabled until the user acknowledges the fault on the keypad. After three consecutive watchdog resets, stay in a locked safe mode that needs a service action. Show the mode on the LCD and RGB LED. Reset the consecutive-reset counter only after the system has run normally for a set time, such as one minute. Log every mode change with the reset cause, so the history explains why the board is in locked mode.
Checkpoint: Three forced watchdog resets in a row leave the board in locked safe mode until the service key sequence is entered.
- 9
Run the fault-injection campaign
Using the keypad or UART, inject each failure mode from step 1 many times, including during motor PWM output with an add-on motor if available or with the driver output observed on an LED. Record detection time, end state and reported cause for each. Inject each fault at least twenty times at random moments, including during LCD updates and UART transmission, because faults that occur in the middle of an operation are the ones most likely to expose a gap. Measure detection time with GPIO toggles where possible.
Checkpoint: A completed fault-injection table with every injected failure ending in the defined safe state.
- 10
Document the design
Write up the failure-mode table, safe-state definition, watchdog timing calculation (including LSI tolerance), PVD threshold choice, restart policy and test results. Explain what extra measures a production ECU would add, such as an external watchdog and a window watchdog. Include the reset-cause handling code path, the health-word design and a timing diagram showing worst-case detection time for a stuck task. Describe how the design would be reviewed in a functional-safety process, without claiming certification.
Checkpoint: A report linking each failure mode to its test evidence.
Testing & validation
- Every failure mode in the table ends in the safe state in repeated tests.
- Watchdog timeout measured and within the design margin given LSI tolerance.
- Reset cause correctly reported for power-on, pin, software, IWDG and fault resets.
- Outputs are safe during reset as well as after boot.
Expected results
Firmware with a proven safe state: task-level watchdog supervision, fault and supply-dip handling, reset-cause logging and a restart policy, backed by a fault-injection test record.
Take it further
- Add the window watchdog (WWDG) to catch code that refreshes too early.
- Report reset causes and fault records over CAN to a diagnostic tool.
- Store a fault history in SPI flash with RTC timestamps.
Viva and review questions
Why feed the watchdog only when all tasks are healthy?
Feeding it from a timer interrupt would keep it happy even if the main logic were stuck; the health word proves every function is still running.
Why use the PVD on this chip?
The STM32F103 has a fixed power-down reset but no programmable brown-out reset, so the PVD gives an early warning to reach the safe state.
Why is the IWDG timeout not exact?
It is clocked from the LSI RC oscillator, whose frequency varies between parts and with temperature.
What is the safe state for the motor driver?
PWM duty zero and the driver disabled, set at the start of GPIO initialisation and forced again in every fault handler.