Emergency Stop Procedure for RF Power Amplifier Protection in PLFM-RADAR

The PLFM-RADAR firmware implements a three-layer emergency stop routine that immediately disables RF power amplifier rails and enters a safe-hold loop when critical faults are detected. This protection mechanism prevents catastrophic damage to the GaN PA during over-current, over-temperature, or watchdog timeout conditions.

This guide explains how the emergency stop procedure works in the open-source PLFM-RADAR project, walking through the fault detection logic, shutdown sequence, and verification test suite. All implementations are found in the microcontroller firmware under 9_Firmware/9_1_Microcontroller/9_1_3_C_Cpp_Code/main.cpp.

Three-Layer Protection Architecture

The RF power amplifier protection system operates through coordinated hardware and software layers:

Layer Purpose Key Component
Fault detection Identify PA-damaging conditions SystemError_t enum in main.cpp (lines 808-826)
Decision logic Classify critical vs. recoverable faults handleSystemError() function (lines 1088-1095)
Shutdown execution Safely de-energize all PA rails Emergency_Stop() function (lines 820-858)

Fault Detection and Error Classification

Hardware faults that threaten the RF power amplifier are enumerated in the SystemError_t type definition. Located at 9_Firmware/9_1_Microcontroller/9_1_3_C_Cpp_Code/main.cpp lines 808-826, this enum includes:

  • ERROR_RF_PA_OVERCURRENT — PA drain current exceeds safe threshold
  • ERROR_RF_PA_BIAS_FAULT — GaN gate bias regulation failure
  • ERROR_TEMPERATURE_HIGH — Thermal runaway condition
  • ERROR_POWER_SUPPLY — Bulk rail collapse or sequencing error
  • ERROR_WATCHDOG_TIMEOUT — Control loop deadlock detected

These values represent conditions where continued operation risks permanent PA damage or fire hazard.

Critical Error Handling Logic

The handleSystemError() function serves as the central dispatcher for all fault conditions. Implemented in main.cpp lines 1088-1095, it performs three essential operations before deciding on recovery or shutdown:

  1. State tracking — increments error_count and stores last_error for diagnostic logging
  2. Error logging — outputs diagnostic message via debug console
  3. Severity classification — checks if error falls within critical range

For critical errors, the function sets system_emergency_state = true before invoking Emergency_Stop(). This ordering—documented as GAP-3 FIX 5 in the source—ensures external systems receive immediate notification that an emergency stop is in progress.

// Critical error range check triggers emergency stop
if (error >= ERROR_RF_PA_OVERCURRENT && 
    error <= ERROR_WATCHDOG_TIMEOUT) {
    system_emergency_state = true;  // Notify external systems FIRST
    Emergency_Stop();                // Enter infinite safe-hold loop
}

Non-critical errors route to attemptErrorRecovery() for transient fault handling.

Emergency Stop Shutdown Sequence

The Emergency_Stop() function at main.cpp lines 820-858 implements a deterministic, fast-to-slow rail shutdown protocol. This sequencing prevents dangerous operating modes in GaN PAs, which can self-bias or oscillate if control voltages persist while drain supplies collapse.

The ordered actions are:

  1. Clear all DAC outputs via DAC5578_ActivateClearPin — removes bias voltages immediately
  2. Disable TX mixers — deasserts GPIOD pin 11 to stop RF drive
  3. Cut PA 5V auxiliary supplies — disables EN_P_5V0_PA1, EN_P_5V0_PA2, EN_P_5V0_PA3
  4. Cut PA 5.5V bulk supply — disables EN_P_5V5_PA
  5. Disable RF-PA VDD — deasserts EN_DIS_RFPA_VDD (main drain supply)
  6. Enter infinite hold loop — refreshes independent watchdog (IWDG) every 100ms to prevent reset
void Emergency_Stop(void) {
    // 1. Clear DAC outputs immediately
    DAC5578_ActivateClearPin();
    
    // 2. Disable TX mixers
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_11, GPIO_PIN_RESET);
    
    // 3-5. Cut PA power rails in sequence
    HAL_GPIO_WritePin(GPIOA, EN_P_5V0_PA1 | EN_P_5V0_PA2 | EN_P_5V0_PA3, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOA, EN_P_5V5_PA, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB, EN_DIS_RFPA_VDD, GPIO_PIN_RESET);
    
    // 6. Infinite safe-hold with watchdog servicing
    while (1) {
        HAL_IWDG_Refresh(&hiwdg);
        HAL_Delay(100);
    }
}

The IWDG refresh is critical: without it, the watchdog would timeout and reset the MCU, potentially re-enabling power rails during boot before fault conditions are cleared.

System State Exposure

The global system_emergency_state flag propagates emergency status to external systems. The getSystemStatusForGUI() function reports "EMERGENCY_STOP" when this flag is set, allowing the operator interface to display appropriate alarms and block further operation attempts.

// Query system state for GUI display
char status_buffer[256];
getSystemStatusForGUI(status_buffer, sizeof(status_buffer));
// Returns: "System Status: EMERGENCY_STOP" when flag is set

Unit Test Verification

The PLFM-RADAR repository includes comprehensive unit tests validating emergency stop behavior under 9_Firmware/9_1_Microcontroller/tests/:

These tests ensure deterministic, repeatable protection behavior across firmware builds.

Summary

  • Fault detection uses the SystemError_t enum to classify PA-threatening conditions
  • handleSystemError() routes critical faults to emergency stop while allowing recovery attempts for transient errors
  • Emergency_Stop() executes a sequenced shutdown: DAC clear → mixer disable → rail cut-off → infinite IWDG-serviced hold
  • The state flag ordering ensures external notification precedes the non-returning stop routine
  • Unit tests verify correct implementation of all protection paths

Frequently Asked Questions

What triggers the emergency stop in PLFM-RADAR?

Critical faults in the ERROR_RF_PA_OVERCURRENT through ERROR_WATCHDOG_TIMEOUT range trigger the emergency stop procedure. These include PA over-current, bias faults, over-temperature conditions, power supply failures, and watchdog timeouts detected in main.cpp lines 808-826.

Why does the emergency stop enter an infinite loop instead of resetting?

The infinite loop with IWDG refresh prevents the MCU from resetting and potentially re-enabling PA power rails before fault conditions are cleared. This safe-hold state maintains all rails de-energized until manual intervention or power cycle occurs, eliminating the risk of automatic restart into a damaged or hazardous condition.

How can I manually trigger an emergency stop for testing?

Call Emergency_Stop() directly from diagnostic code. This function never returns, placing the system into the same safe state as fault-triggered stops:

extern void Emergency_Stop(void);

void run_manual_estop_test(void) {
    Emergency_Stop();  // Enters infinite loop, requires power cycle
}

Where is the emergency stop sequence verified in the codebase?

Three unit test files validate the implementation: test_gap3_overtemp_emergency_stop.c tests thermal and watchdog triggers; test_gap3_emergency_stop_rails.c verifies GPIO rail sequencing; and test_gap3_emergency_state_ordering.c confirms state flag timing.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →