refactor(mcu): remove redundant ADAR1000 T/R SPI paths (FPGA-owned)
Per-chirp T/R switching is owned by the FPGA plfm_chirp_controller
driving adar_tr_x pins (TR_SOURCE=1 in REG_SW_CONTROL, already set by
initializeSingleDevice). The MCU's SPI RMW path via fastTXMode/
fastRXMode/pulseTXMode/pulseRXMode/setADTR1107Control was:
(a) architecturally redundant — raced the FPGA-driven TR line,
(b) toggled the wrong bit (TR_SOURCE instead of TR_SPI),
(c) in setFastSwitchMode(true) bundled a datasheet-violating
PA+LNA-simultaneously-biased side effect.
Removed methods and their backing state (fast_switch_mode_,
switch_settling_time_us_). Call sites in executeChirpSequence /
runRadarPulseSequence updated to rely on the FPGA chirp FSM (GPIOD_8
new_chirp trigger unchanged).
Tests: adds CMSIS-Core DWT/CoreDebug/SystemCoreClock stubs to
stm32_hal_mock so F-4.7's DWT-based delayUs() compiles under the host
mock build. SystemCoreClock=0 makes the busy-wait exit immediately.
This commit is contained in:
@@ -163,8 +163,10 @@ void ADAR1000Manager::switchToTXMode() {
|
||||
DIAG("BF", "Step 3: PA bias ON");
|
||||
setPABias(true);
|
||||
delayUs(50);
|
||||
DIAG("BF", "Step 4: ADTR1107 -> TX");
|
||||
setADTR1107Control(true);
|
||||
// Step 4 (former setADTR1107Control(true)) removed: TR pin is FPGA-owned.
|
||||
// Chip follows adar_tr_x; TX path is asserted by the FPGA chirp FSM, not
|
||||
// by SPI here. Write per-channel TX enables so the FPGA TR override has
|
||||
// something to gate.
|
||||
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
adarWrite(dev, REG_RX_ENABLES, 0x00, BROADCAST_OFF);
|
||||
@@ -185,8 +187,7 @@ void ADAR1000Manager::switchToRXMode() {
|
||||
DIAG("BF", "Step 2: Disable PA supplies");
|
||||
disablePASupplies();
|
||||
delayUs(10);
|
||||
DIAG("BF", "Step 3: ADTR1107 -> RX");
|
||||
setADTR1107Control(false);
|
||||
// Step 3 (former setADTR1107Control(false)) removed: FPGA owns TR pin.
|
||||
DIAG("BF", "Step 4: Enable LNA supplies");
|
||||
enableLNASupplies();
|
||||
delayUs(50);
|
||||
@@ -204,39 +205,11 @@ void ADAR1000Manager::switchToRXMode() {
|
||||
DIAG("BF", "switchToRXMode() complete");
|
||||
}
|
||||
|
||||
void ADAR1000Manager::fastTXMode() {
|
||||
DIAG("BF", "fastTXMode(): ADTR1107 -> TX (no bias sequencing)");
|
||||
setADTR1107Control(true);
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
adarWrite(dev, REG_RX_ENABLES, 0x00, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_TX_ENABLES, 0x0F, BROADCAST_OFF);
|
||||
devices_[dev]->current_mode = BeamDirection::TX;
|
||||
}
|
||||
current_mode_ = BeamDirection::TX;
|
||||
}
|
||||
|
||||
void ADAR1000Manager::fastRXMode() {
|
||||
DIAG("BF", "fastRXMode(): ADTR1107 -> RX (no bias sequencing)");
|
||||
setADTR1107Control(false);
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
adarWrite(dev, REG_TX_ENABLES, 0x00, BROADCAST_OFF);
|
||||
adarWrite(dev, REG_RX_ENABLES, 0x0F, BROADCAST_OFF);
|
||||
devices_[dev]->current_mode = BeamDirection::RX;
|
||||
}
|
||||
current_mode_ = BeamDirection::RX;
|
||||
}
|
||||
|
||||
void ADAR1000Manager::pulseTXMode() {
|
||||
DIAG("BF", "pulseTXMode(): TR switch only");
|
||||
setADTR1107Control(true);
|
||||
last_switch_time_us_ = HAL_GetTick() * 1000;
|
||||
}
|
||||
|
||||
void ADAR1000Manager::pulseRXMode() {
|
||||
DIAG("BF", "pulseRXMode(): TR switch only");
|
||||
setADTR1107Control(false);
|
||||
last_switch_time_us_ = HAL_GetTick() * 1000;
|
||||
}
|
||||
// fastTXMode, fastRXMode, pulseTXMode, pulseRXMode: REMOVED.
|
||||
// The chirp hot path owns T/R switching via the FPGA adar_tr_x pins
|
||||
// (see 9_Firmware/9_2_FPGA/plfm_chirp_controller.v). The old SPI-RMW per
|
||||
// chirp was architecturally redundant, raced the FPGA, and toggled the
|
||||
// wrong bit of REG_SW_CONTROL (TR_SOURCE instead of TR_SPI).
|
||||
|
||||
// Beam Steering
|
||||
bool ADAR1000Manager::setBeamAngle(float angle_degrees, BeamDirection direction) {
|
||||
@@ -368,25 +341,10 @@ void ADAR1000Manager::writeRegister(uint8_t deviceIndex, uint32_t address, uint8
|
||||
}
|
||||
|
||||
// Configuration
|
||||
void ADAR1000Manager::setSwitchSettlingTime(uint32_t us) {
|
||||
switch_settling_time_us_ = us;
|
||||
}
|
||||
|
||||
void ADAR1000Manager::setFastSwitchMode(bool enable) {
|
||||
DIAG("BF", "setFastSwitchMode(%s)", enable ? "ON" : "OFF");
|
||||
fast_switch_mode_ = enable;
|
||||
if (enable) {
|
||||
switch_settling_time_us_ = 10;
|
||||
DIAG("BF", " settling time = 10 us, enabling PA+LNA supplies and bias simultaneously");
|
||||
enablePASupplies();
|
||||
enableLNASupplies();
|
||||
setPABias(true);
|
||||
setLNABias(true);
|
||||
} else {
|
||||
switch_settling_time_us_ = 50;
|
||||
DIAG("BF", " settling time = 50 us");
|
||||
}
|
||||
}
|
||||
// setSwitchSettlingTime, setFastSwitchMode: REMOVED.
|
||||
// Their only reader was the deleted setADTR1107Control; setFastSwitchMode(true)
|
||||
// also violated the ADTR1107 datasheet bias sequence (PA + LNA biased to
|
||||
// operational simultaneously). Per-chirp T/R is FPGA-owned now.
|
||||
|
||||
void ADAR1000Manager::setBeamDwellTime(uint32_t ms) {
|
||||
beam_dwell_time_ms_ = ms;
|
||||
@@ -428,6 +386,16 @@ bool ADAR1000Manager::initializeSingleDevice(uint8_t deviceIndex) {
|
||||
DIAG("BF", " dev[%u] set RAM bypass (bias+beam)", deviceIndex);
|
||||
adarSetRamBypass(deviceIndex, BROADCAST_OFF);
|
||||
|
||||
// Hand per-chirp T/R switching to the FPGA.
|
||||
// Set TR_SOURCE (REG_SW_CONTROL bit 2) = 1 so the chip's internal
|
||||
// RX_EN_OVERRIDE / TX_EN_OVERRIDE follow the external TR pin (driven by
|
||||
// plfm_chirp_controller's adar_tr_x output). See ADAR1000 datasheet
|
||||
// "Theory of Operation" -- SPI Control vs TR Pin Control.
|
||||
// Without this write, the FPGA's TR pin is ignored and the chip stays
|
||||
// in RX state (TR_SPI POR default).
|
||||
DIAG("BF", " dev[%u] SW_CONTROL: TR_SOURCE=1 (FPGA owns TR pin)", deviceIndex);
|
||||
adarWrite(deviceIndex, REG_SW_CONTROL, (1 << 2), BROADCAST_OFF);
|
||||
|
||||
// Initialize ADC
|
||||
DIAG("BF", " dev[%u] enable ADC (2MHz clk)", deviceIndex);
|
||||
adarWrite(deviceIndex, REG_ADC_CONTROL, ADAR1000_ADC_2MHZ_CLK | ADAR1000_ADC_EN, BROADCAST_OFF);
|
||||
@@ -469,9 +437,11 @@ bool ADAR1000Manager::initializeADTR1107Sequence() {
|
||||
HAL_GPIO_WritePin(EN_P_3V3_SW_GPIO_Port, EN_P_3V3_SW_Pin, GPIO_PIN_SET);
|
||||
HAL_Delay(1);
|
||||
|
||||
// Step 4: Set CTRL_SW to RX mode initially via GPIO
|
||||
DIAG("BF", "Step 4: CTRL_SW -> RX (initial safe mode)");
|
||||
setADTR1107Control(false); // RX mode
|
||||
// Step 4: CTRL_SW safe-default is RX.
|
||||
// FPGA-owned path: with TR_SOURCE=1 (set in initializeSingleDevice) the
|
||||
// chip follows adar_tr_x, which is 0 in the FPGA FSM's IDLE state = RX.
|
||||
// No SPI write needed here.
|
||||
DIAG("BF", "Step 4: CTRL_SW -> RX (FPGA adar_tr_x idle-low == RX)");
|
||||
HAL_Delay(1);
|
||||
|
||||
// Step 5: Set VGG_LNA to 0
|
||||
@@ -573,7 +543,7 @@ bool ADAR1000Manager::setAllDevicesRXMode() {
|
||||
void ADAR1000Manager::setADTR1107Mode(BeamDirection direction) {
|
||||
if (direction == BeamDirection::TX) {
|
||||
DIAG_SECTION("ADTR1107 -> TX MODE");
|
||||
setADTR1107Control(true); // TX mode
|
||||
// setADTR1107Control(true) removed: TR pin is FPGA-driven.
|
||||
|
||||
// Step 1: Disable LNA power first
|
||||
DIAG("BF", " Disable LNA supplies");
|
||||
@@ -603,10 +573,11 @@ void ADAR1000Manager::setADTR1107Mode(BeamDirection direction) {
|
||||
}
|
||||
HAL_Delay(5);
|
||||
|
||||
// Step 5: Set TR switch to TX mode
|
||||
DIAG("BF", " TR switch -> TX (TR_SOURCE=1, BIAS_EN)");
|
||||
// Step 5: TR switch state is FPGA-driven. TR_SOURCE=1 is set once in
|
||||
// initializeSingleDevice, so the chip already follows adar_tr_x.
|
||||
// Only BIAS_EN needs to be asserted here.
|
||||
DIAG("BF", " BIAS_EN (TR source still = FPGA adar_tr_x)");
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
adarSetBit(dev, REG_SW_CONTROL, 2, BROADCAST_OFF); // TR_SOURCE = 1 (TX)
|
||||
adarSetBit(dev, REG_MISC_ENABLES, 5, BROADCAST_OFF); // BIAS_EN
|
||||
}
|
||||
DIAG("BF", " ADTR1107 TX mode complete");
|
||||
@@ -614,7 +585,7 @@ void ADAR1000Manager::setADTR1107Mode(BeamDirection direction) {
|
||||
} else {
|
||||
// RECEIVE MODE: Enable LNA, Disable PA
|
||||
DIAG_SECTION("ADTR1107 -> RX MODE");
|
||||
setADTR1107Control(false); // RX mode
|
||||
// setADTR1107Control(false) removed: TR pin is FPGA-driven.
|
||||
|
||||
// Step 1: Disable PA power first
|
||||
DIAG("BF", " Disable PA supplies");
|
||||
@@ -645,34 +616,21 @@ void ADAR1000Manager::setADTR1107Mode(BeamDirection direction) {
|
||||
}
|
||||
HAL_Delay(5);
|
||||
|
||||
// Step 5: Set TR switch to RX mode
|
||||
DIAG("BF", " TR switch -> RX (TR_SOURCE=0, LNA_BIAS_OUT_EN)");
|
||||
// Step 5: TR switch state is FPGA-driven (TR_SOURCE left at 1).
|
||||
// Only LNA_BIAS_OUT_EN needs to be asserted here.
|
||||
DIAG("BF", " LNA_BIAS_OUT_EN (TR source still = FPGA adar_tr_x)");
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
adarResetBit(dev, REG_SW_CONTROL, 2, BROADCAST_OFF); // TR_SOURCE = 0 (RX)
|
||||
adarSetBit(dev, REG_MISC_ENABLES, 4, BROADCAST_OFF); // LNA_BIAS_OUT_EN
|
||||
}
|
||||
DIAG("BF", " ADTR1107 RX mode complete");
|
||||
}
|
||||
}
|
||||
|
||||
void ADAR1000Manager::setADTR1107Control(bool tx_mode) {
|
||||
DIAG("BF", "setADTR1107Control(%s): setting TR switch on all %u devices, settling %lu us",
|
||||
tx_mode ? "TX" : "RX", (unsigned)devices_.size(), (unsigned long)switch_settling_time_us_);
|
||||
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
|
||||
setTRSwitchPosition(dev, tx_mode);
|
||||
}
|
||||
delayUs(switch_settling_time_us_);
|
||||
}
|
||||
|
||||
void ADAR1000Manager::setTRSwitchPosition(uint8_t deviceIndex, bool tx_mode) {
|
||||
if (tx_mode) {
|
||||
// TX mode: Set TR_SOURCE = 1
|
||||
adarSetBit(deviceIndex, REG_SW_CONTROL, 2, BROADCAST_OFF);
|
||||
} else {
|
||||
// RX mode: Set TR_SOURCE = 0
|
||||
adarResetBit(deviceIndex, REG_SW_CONTROL, 2, BROADCAST_OFF);
|
||||
}
|
||||
}
|
||||
// setADTR1107Control, setTRSwitchPosition: REMOVED.
|
||||
// The per-device SPI RMW of REG_SW_CONTROL bit 2 (TR_SOURCE) was both wrong
|
||||
// (it toggled the *control source*, not the TX/RX state -- TR_SPI is bit 1)
|
||||
// and redundant with the FPGA's plfm_chirp_controller adar_tr_x output.
|
||||
// TR_SOURCE is now set to 1 exactly once in initializeSingleDevice.
|
||||
|
||||
// Add the new public method
|
||||
bool ADAR1000Manager::setCustomBeamPattern16(const uint8_t phase_pattern[16], BeamDirection direction) {
|
||||
|
||||
@@ -48,10 +48,11 @@ public:
|
||||
// Mode Switching
|
||||
void switchToTXMode();
|
||||
void switchToRXMode();
|
||||
void fastTXMode();
|
||||
void fastRXMode();
|
||||
void pulseTXMode();
|
||||
void pulseRXMode();
|
||||
// fastTXMode/fastRXMode/pulseTXMode/pulseRXMode were removed: per-chirp T/R
|
||||
// switching is owned by the FPGA (plfm_chirp_controller -> adar_tr_x pins,
|
||||
// requires TR_SOURCE=1 in REG_SW_CONTROL, set in initializeSingleDevice).
|
||||
// The old SPI RMW path was architecturally redundant and also toggled the
|
||||
// wrong bit (TR_SOURCE instead of TR_SPI). See PR for details.
|
||||
|
||||
// Beam Steering
|
||||
bool setBeamAngle(float angle_degrees, BeamDirection direction);
|
||||
@@ -69,7 +70,8 @@ public:
|
||||
bool setAllDevicesTXMode();
|
||||
bool setAllDevicesRXMode();
|
||||
void setADTR1107Mode(BeamDirection direction);
|
||||
void setADTR1107Control(bool tx_mode);
|
||||
// setADTR1107Control removed -- it only wrapped the now-deleted
|
||||
// setTRSwitchPosition SPI path. FPGA drives the TR pin directly.
|
||||
|
||||
// Monitoring and Diagnostics
|
||||
float readTemperature(uint8_t deviceIndex);
|
||||
@@ -78,8 +80,11 @@ public:
|
||||
void writeRegister(uint8_t deviceIndex, uint32_t address, uint8_t value);
|
||||
|
||||
// Configuration
|
||||
void setSwitchSettlingTime(uint32_t us);
|
||||
void setFastSwitchMode(bool enable);
|
||||
// setSwitchSettlingTime / setFastSwitchMode removed: their only reader was
|
||||
// the deleted setADTR1107Control SPI path, and setFastSwitchMode(true)
|
||||
// also bundled a datasheet-violating PA+LNA-biased-simultaneously side
|
||||
// effect. Per-chirp settling is now FPGA-owned. Callers that need a
|
||||
// warm-up bias state should use switchToTXMode / switchToRXMode instead.
|
||||
void setBeamDwellTime(uint32_t ms);
|
||||
|
||||
// Getters
|
||||
@@ -100,8 +105,8 @@ public:
|
||||
};
|
||||
|
||||
// Configuration
|
||||
bool fast_switch_mode_ = false;
|
||||
uint32_t switch_settling_time_us_ = 50;
|
||||
// fast_switch_mode_ / switch_settling_time_us_ removed: both had no
|
||||
// readers after the FPGA-owned TR refactor.
|
||||
uint32_t beam_dwell_time_ms_ = 100;
|
||||
uint32_t last_switch_time_us_ = 0;
|
||||
|
||||
@@ -121,22 +126,22 @@ public:
|
||||
// No VM_GAIN[] table exists: VM magnitude is bits [4:0] of the I/Q bytes
|
||||
// themselves; per-channel VGA gain uses a separate register.
|
||||
static const uint8_t VM_I[128];
|
||||
static const uint8_t VM_Q[128];
|
||||
|
||||
// Named defaults for the ADTR1107 and ADAR1000 power sequence.
|
||||
static constexpr uint8_t kDefaultTxVgaGain = 0x7F;
|
||||
static constexpr uint8_t kDefaultRxVgaGain = 30;
|
||||
static constexpr uint8_t kLnaBiasOff = 0x00;
|
||||
static constexpr uint8_t kLnaBiasOperational = 0x30;
|
||||
static constexpr uint8_t kPaBiasTxSafe = 0x5D;
|
||||
static constexpr uint8_t kPaBiasIdqCalibration = 0x0D;
|
||||
static constexpr uint8_t kPaBiasOperational = 0x7F;
|
||||
static constexpr uint8_t kPaBiasRxSafe = 0x20;
|
||||
static constexpr uint8_t kTxBiasCurrent = 0x2D;
|
||||
static constexpr uint8_t kTxDriverBiasCurrent = 0x06;
|
||||
|
||||
// Private Methods
|
||||
bool initializeSingleDevice(uint8_t deviceIndex);
|
||||
static const uint8_t VM_Q[128];
|
||||
|
||||
// Named defaults for the ADTR1107 and ADAR1000 power sequence.
|
||||
static constexpr uint8_t kDefaultTxVgaGain = 0x7F;
|
||||
static constexpr uint8_t kDefaultRxVgaGain = 30;
|
||||
static constexpr uint8_t kLnaBiasOff = 0x00;
|
||||
static constexpr uint8_t kLnaBiasOperational = 0x30;
|
||||
static constexpr uint8_t kPaBiasTxSafe = 0x5D;
|
||||
static constexpr uint8_t kPaBiasIdqCalibration = 0x0D;
|
||||
static constexpr uint8_t kPaBiasOperational = 0x7F;
|
||||
static constexpr uint8_t kPaBiasRxSafe = 0x20;
|
||||
static constexpr uint8_t kTxBiasCurrent = 0x2D;
|
||||
static constexpr uint8_t kTxDriverBiasCurrent = 0x06;
|
||||
|
||||
// Private Methods
|
||||
bool initializeSingleDevice(uint8_t deviceIndex);
|
||||
bool initializeADTR1107Sequence();
|
||||
void calculatePhaseSettings(float angle_degrees, uint8_t phase_settings[4]);
|
||||
void delayUs(uint32_t microseconds);
|
||||
@@ -167,7 +172,7 @@ public:
|
||||
void adarSetTxVgaGain(uint8_t deviceIndex, uint8_t channel, uint8_t gain, uint8_t broadcast);
|
||||
void adarSetTxBias(uint8_t deviceIndex, uint8_t broadcast);
|
||||
uint8_t adarAdcRead(uint8_t deviceIndex, uint8_t broadcast);
|
||||
void setTRSwitchPosition(uint8_t deviceIndex, bool tx_mode);
|
||||
// setTRSwitchPosition removed -- FPGA owns TR pin. See PR.
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -483,11 +483,14 @@ void executeChirpSequence(int num_chirps, float T1, float PRI1, float T2, float
|
||||
DIAG("SYS", "executeChirpSequence: num_chirps=%d T1=%.2f PRI1=%.2f T2=%.2f PRI2=%.2f",
|
||||
num_chirps, T1, PRI1, T2, PRI2);
|
||||
// First chirp sequence (microsecond timing)
|
||||
// T/R switching is owned by the FPGA plfm_chirp_controller: its chirp
|
||||
// FSM drives adar_tr_x high during LONG_CHIRP/SHORT_CHIRP and low during
|
||||
// listen/guard. new_chirp (GPIOD_8) triggers the FSM out of IDLE.
|
||||
// The MCU's old pulseTXMode/pulseRXMode SPI path was redundant and raced
|
||||
// the FPGA -- removed.
|
||||
for(int i = 0; i < num_chirps; i++) {
|
||||
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_8); // New chirp signal to FPGA
|
||||
adarManager.pulseTXMode();
|
||||
delay_us((uint32_t)T1);
|
||||
adarManager.pulseRXMode();
|
||||
delay_us((uint32_t)(PRI1 - T1));
|
||||
}
|
||||
|
||||
@@ -496,11 +499,8 @@ void executeChirpSequence(int num_chirps, float T1, float PRI1, float T2, float
|
||||
// Second chirp sequence (nanosecond timing)
|
||||
for(int i = 0; i < num_chirps; i++) {
|
||||
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_8); // New chirp signal to FPGA
|
||||
adarManager.pulseTXMode();
|
||||
delay_ns((uint32_t)(T2 * 1000));
|
||||
adarManager.pulseRXMode();
|
||||
delay_ns((uint32_t)((PRI2 - T2) * 1000));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -513,9 +513,9 @@ void runRadarPulseSequence() {
|
||||
DIAG("SYS", "runRadarPulseSequence #%d: m_max=%d n_max=%d y_max=%d",
|
||||
sequence_count, m_max, n_max, y_max);
|
||||
|
||||
// Configure for fast switching
|
||||
DIAG("BF", "Enabling fast-switch mode for beam sweep");
|
||||
adarManager.setFastSwitchMode(true);
|
||||
// Fast per-chirp switching is now FPGA-owned (plfm_chirp_controller
|
||||
// adar_tr_x), not MCU-driven. setFastSwitchMode(true) call removed.
|
||||
DIAG("BF", "Beam sweep start (FPGA owns per-chirp T/R switching)");
|
||||
|
||||
int m = 1; // Chirp counter
|
||||
int n = 1; // Beam Elevation position counter
|
||||
@@ -656,18 +656,18 @@ SystemError_t checkSystemHealth(void) {
|
||||
|
||||
// 1. Check AD9523 Clock Generator
|
||||
static uint32_t last_clock_check = 0;
|
||||
if (HAL_GetTick() - last_clock_check > 5000) {
|
||||
GPIO_PinState s0 = HAL_GPIO_ReadPin(AD9523_STATUS0_GPIO_Port, AD9523_STATUS0_Pin);
|
||||
GPIO_PinState s1 = HAL_GPIO_ReadPin(AD9523_STATUS1_GPIO_Port, AD9523_STATUS1_Pin);
|
||||
DIAG_GPIO("CLK", "AD9523 STATUS0", s0);
|
||||
DIAG_GPIO("CLK", "AD9523 STATUS1", s1);
|
||||
if (s0 == GPIO_PIN_RESET || s1 == GPIO_PIN_RESET) {
|
||||
current_error = ERROR_AD9523_CLOCK;
|
||||
DIAG_ERR("CLK", "AD9523 clock health check FAILED (STATUS0=%d STATUS1=%d)", s0, s1);
|
||||
return current_error;
|
||||
}
|
||||
last_clock_check = HAL_GetTick();
|
||||
}
|
||||
if (HAL_GetTick() - last_clock_check > 5000) {
|
||||
GPIO_PinState s0 = HAL_GPIO_ReadPin(AD9523_STATUS0_GPIO_Port, AD9523_STATUS0_Pin);
|
||||
GPIO_PinState s1 = HAL_GPIO_ReadPin(AD9523_STATUS1_GPIO_Port, AD9523_STATUS1_Pin);
|
||||
DIAG_GPIO("CLK", "AD9523 STATUS0", s0);
|
||||
DIAG_GPIO("CLK", "AD9523 STATUS1", s1);
|
||||
if (s0 == GPIO_PIN_RESET || s1 == GPIO_PIN_RESET) {
|
||||
current_error = ERROR_AD9523_CLOCK;
|
||||
DIAG_ERR("CLK", "AD9523 clock health check FAILED (STATUS0=%d STATUS1=%d)", s0, s1);
|
||||
return current_error;
|
||||
}
|
||||
last_clock_check = HAL_GetTick();
|
||||
}
|
||||
|
||||
// 2. Check ADF4382 Lock Status
|
||||
bool tx_locked, rx_locked;
|
||||
@@ -702,34 +702,34 @@ SystemError_t checkSystemHealth(void) {
|
||||
|
||||
// 4. Check IMU Communication
|
||||
static uint32_t last_imu_check = 0;
|
||||
if (HAL_GetTick() - last_imu_check > 10000) {
|
||||
if (!GY85_Update(&imu)) {
|
||||
current_error = ERROR_IMU_COMM;
|
||||
DIAG_ERR("IMU", "Health check: GY85_Update() FAILED");
|
||||
return current_error;
|
||||
}
|
||||
last_imu_check = HAL_GetTick();
|
||||
}
|
||||
if (HAL_GetTick() - last_imu_check > 10000) {
|
||||
if (!GY85_Update(&imu)) {
|
||||
current_error = ERROR_IMU_COMM;
|
||||
DIAG_ERR("IMU", "Health check: GY85_Update() FAILED");
|
||||
return current_error;
|
||||
}
|
||||
last_imu_check = HAL_GetTick();
|
||||
}
|
||||
|
||||
// 5. Check BMP180 Communication
|
||||
static uint32_t last_bmp_check = 0;
|
||||
if (HAL_GetTick() - last_bmp_check > 15000) {
|
||||
double pressure = myBMP.getPressure();
|
||||
if (pressure < 30000.0 || pressure > 110000.0 || isnan(pressure)) {
|
||||
current_error = ERROR_BMP180_COMM;
|
||||
DIAG_ERR("SYS", "Health check: BMP180 pressure out of range: %.0f", pressure);
|
||||
return current_error;
|
||||
}
|
||||
last_bmp_check = HAL_GetTick();
|
||||
}
|
||||
if (HAL_GetTick() - last_bmp_check > 15000) {
|
||||
double pressure = myBMP.getPressure();
|
||||
if (pressure < 30000.0 || pressure > 110000.0 || isnan(pressure)) {
|
||||
current_error = ERROR_BMP180_COMM;
|
||||
DIAG_ERR("SYS", "Health check: BMP180 pressure out of range: %.0f", pressure);
|
||||
return current_error;
|
||||
}
|
||||
last_bmp_check = HAL_GetTick();
|
||||
}
|
||||
|
||||
// 6. Check GPS Communication (30s grace period from boot / last valid fix)
|
||||
uint32_t gps_fix_age = um982_position_age(&um982);
|
||||
if (gps_fix_age > 30000) {
|
||||
current_error = ERROR_GPS_COMM;
|
||||
DIAG_WARN("SYS", "Health check: GPS no fix for >30s (age=%lu ms)", (unsigned long)gps_fix_age);
|
||||
return current_error;
|
||||
}
|
||||
// 6. Check GPS Communication (30s grace period from boot / last valid fix)
|
||||
uint32_t gps_fix_age = um982_position_age(&um982);
|
||||
if (gps_fix_age > 30000) {
|
||||
current_error = ERROR_GPS_COMM;
|
||||
DIAG_WARN("SYS", "Health check: GPS no fix for >30s (age=%lu ms)", (unsigned long)gps_fix_age);
|
||||
return current_error;
|
||||
}
|
||||
|
||||
// 7. Check RF Power Amplifier Current
|
||||
if (PowerAmplifier) {
|
||||
@@ -760,7 +760,7 @@ SystemError_t checkSystemHealth(void) {
|
||||
DIAG_ERR("SYS", "checkSystemHealth returning error code %d", current_error);
|
||||
}
|
||||
return current_error;
|
||||
}
|
||||
}
|
||||
|
||||
// Error recovery function
|
||||
void attemptErrorRecovery(SystemError_t error) {
|
||||
@@ -905,22 +905,22 @@ void handleSystemError(SystemError_t error) {
|
||||
HAL_Delay(200);
|
||||
}
|
||||
|
||||
// Critical errors trigger emergency shutdown.
|
||||
//
|
||||
// Safety-critical range: any fault that can damage the PAs or leave the
|
||||
// system in an undefined state must cut the RF rails via Emergency_Stop().
|
||||
// This covers:
|
||||
// ERROR_RF_PA_OVERCURRENT .. ERROR_POWER_SUPPLY (9..13) -- PA/supply faults
|
||||
// ERROR_TEMPERATURE_HIGH (14) -- >75 C on the PA thermal sensors;
|
||||
// without cutting bias + 5V/5V5/RFPA rails
|
||||
// the GaN QPA2962 stage can thermal-runaway.
|
||||
// ERROR_WATCHDOG_TIMEOUT (16) -- health-check loop has stalled (>60 s);
|
||||
// transmitter state is unknown, safest to
|
||||
// latch Emergency_Stop rather than rely on
|
||||
// IWDG reset (which re-energises the rails).
|
||||
if ((error >= ERROR_RF_PA_OVERCURRENT && error <= ERROR_POWER_SUPPLY) ||
|
||||
error == ERROR_TEMPERATURE_HIGH ||
|
||||
error == ERROR_WATCHDOG_TIMEOUT) {
|
||||
// Critical errors trigger emergency shutdown.
|
||||
//
|
||||
// Safety-critical range: any fault that can damage the PAs or leave the
|
||||
// system in an undefined state must cut the RF rails via Emergency_Stop().
|
||||
// This covers:
|
||||
// ERROR_RF_PA_OVERCURRENT .. ERROR_POWER_SUPPLY (9..13) -- PA/supply faults
|
||||
// ERROR_TEMPERATURE_HIGH (14) -- >75 C on the PA thermal sensors;
|
||||
// without cutting bias + 5V/5V5/RFPA rails
|
||||
// the GaN QPA2962 stage can thermal-runaway.
|
||||
// ERROR_WATCHDOG_TIMEOUT (16) -- health-check loop has stalled (>60 s);
|
||||
// transmitter state is unknown, safest to
|
||||
// latch Emergency_Stop rather than rely on
|
||||
// IWDG reset (which re-energises the rails).
|
||||
if ((error >= ERROR_RF_PA_OVERCURRENT && error <= ERROR_POWER_SUPPLY) ||
|
||||
error == ERROR_TEMPERATURE_HIGH ||
|
||||
error == ERROR_WATCHDOG_TIMEOUT) {
|
||||
DIAG_ERR("SYS", "CRITICAL ERROR (code %d: %s) -- initiating Emergency_Stop()", error, err_name);
|
||||
snprintf(error_msg, sizeof(error_msg),
|
||||
"CRITICAL ERROR! Initiating emergency shutdown.\r\n");
|
||||
@@ -1483,8 +1483,8 @@ int main(void)
|
||||
HAL_GPIO_WritePin(EN_P_3V3_FPGA_GPIO_Port,EN_P_3V3_FPGA_Pin,GPIO_PIN_SET);
|
||||
HAL_Delay(100);
|
||||
DIAG("PWR", "FPGA power sequencing complete -- 1.0V -> 1.8V -> 3.3V");
|
||||
|
||||
|
||||
|
||||
|
||||
// Initialize module IMU
|
||||
DIAG_SECTION("IMU INIT (GY-85)");
|
||||
DIAG("IMU", "Initializing GY-85 IMU...");
|
||||
@@ -1493,12 +1493,12 @@ int main(void)
|
||||
Error_Handler();
|
||||
}
|
||||
DIAG("IMU", "GY-85 initialized OK, running 10 calibration samples");
|
||||
for(int i=0; i<10;i++){
|
||||
if (!GY85_Update(&imu)) {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
ax = imu.ax;
|
||||
for(int i=0; i<10;i++){
|
||||
if (!GY85_Update(&imu)) {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
ax = imu.ax;
|
||||
ay = imu.ay;
|
||||
az = imu.az;
|
||||
gx = -imu.gx;
|
||||
@@ -1793,20 +1793,20 @@ int main(void)
|
||||
HAL_Delay(10);
|
||||
}
|
||||
}
|
||||
RADAR_Longitude = um982_get_longitude(&um982);
|
||||
RADAR_Latitude = um982_get_latitude(&um982);
|
||||
DIAG("GPS", "Initial position: lat=%.6f lon=%.6f fix=%d sats=%d",
|
||||
RADAR_Latitude, RADAR_Longitude,
|
||||
um982_get_fix_quality(&um982), um982_get_num_sats(&um982));
|
||||
|
||||
// Re-apply heading after GPS init so the north-alignment stepper move uses
|
||||
// UM982 dual-antenna heading when available.
|
||||
if (um982_is_heading_valid(&um982)) {
|
||||
Yaw_Sensor = um982_get_heading(&um982);
|
||||
}
|
||||
|
||||
//move Stepper to position 1 = 0°
|
||||
HAL_GPIO_WritePin(STEPPER_CW_P_GPIO_Port, STEPPER_CW_P_Pin, GPIO_PIN_RESET);//Set stepper motor spinning direction to CCW
|
||||
RADAR_Longitude = um982_get_longitude(&um982);
|
||||
RADAR_Latitude = um982_get_latitude(&um982);
|
||||
DIAG("GPS", "Initial position: lat=%.6f lon=%.6f fix=%d sats=%d",
|
||||
RADAR_Latitude, RADAR_Longitude,
|
||||
um982_get_fix_quality(&um982), um982_get_num_sats(&um982));
|
||||
|
||||
// Re-apply heading after GPS init so the north-alignment stepper move uses
|
||||
// UM982 dual-antenna heading when available.
|
||||
if (um982_is_heading_valid(&um982)) {
|
||||
Yaw_Sensor = um982_get_heading(&um982);
|
||||
}
|
||||
|
||||
//move Stepper to position 1 = 0°
|
||||
HAL_GPIO_WritePin(STEPPER_CW_P_GPIO_Port, STEPPER_CW_P_Pin, GPIO_PIN_RESET);//Set stepper motor spinning direction to CCW
|
||||
//Point Stepper to North
|
||||
for(int i= 0;i<(int)(Yaw_Sensor*Stepper_steps/360);i++){
|
||||
HAL_GPIO_WritePin(STEPPER_CLK_P_GPIO_Port, STEPPER_CLK_P_Pin, GPIO_PIN_SET);
|
||||
@@ -1819,14 +1819,14 @@ int main(void)
|
||||
/**********wait for GUI start flag and Send Lat/Long/alt********/
|
||||
/***************************************************************/
|
||||
|
||||
GPS_Data_t gps_data;
|
||||
// Binary packet structure:
|
||||
// [Header 4 bytes][Latitude 8 bytes][Longitude 8 bytes][Altitude 4 bytes][Pitch 4 bytes][CRC 2 bytes]
|
||||
gps_data = {RADAR_Latitude, RADAR_Longitude, RADAR_Altitude, Pitch_Sensor, HAL_GetTick()};
|
||||
if (!GPS_SendBinaryToGUI(&gps_data)) {
|
||||
const uint8_t gps_send_error[] = "GPS binary send failed\r\n";
|
||||
HAL_UART_Transmit(&huart3, (uint8_t*)gps_send_error, sizeof(gps_send_error) - 1, 1000);
|
||||
}
|
||||
GPS_Data_t gps_data;
|
||||
// Binary packet structure:
|
||||
// [Header 4 bytes][Latitude 8 bytes][Longitude 8 bytes][Altitude 4 bytes][Pitch 4 bytes][CRC 2 bytes]
|
||||
gps_data = {RADAR_Latitude, RADAR_Longitude, RADAR_Altitude, Pitch_Sensor, HAL_GetTick()};
|
||||
if (!GPS_SendBinaryToGUI(&gps_data)) {
|
||||
const uint8_t gps_send_error[] = "GPS binary send failed\r\n";
|
||||
HAL_UART_Transmit(&huart3, (uint8_t*)gps_send_error, sizeof(gps_send_error) - 1, 1000);
|
||||
}
|
||||
|
||||
/* [STM32-006 FIXED] Removed blocking do-while loop that waited for
|
||||
* usbHandler.isStartFlagReceived(). The production V7 PyQt GUI does not
|
||||
|
||||
@@ -406,3 +406,11 @@ static int mock_spi_init_stub(void) { return 0; }
|
||||
const struct no_os_spi_platform_ops stm32_spi_ops = {
|
||||
.init = mock_spi_init_stub,
|
||||
};
|
||||
|
||||
/* ========================= CMSIS-Core stub storage ======================= */
|
||||
/* See stm32_hal_mock.h for rationale. SystemCoreClock = 0 forces delayUs() to
|
||||
* return immediately under host test builds. DWT->CTRL pre-enabled so the
|
||||
* one-time-init branch is skipped deterministically. */
|
||||
struct _DWT_Mock_Type _dwt_mock = { .CTRL = DWT_CTRL_CYCCNTENA_Msk, .CYCCNT = 0 };
|
||||
struct _CoreDebug_Mock_Type _coredebug_mock = { .DEMCR = 0 };
|
||||
uint32_t SystemCoreClock = 0U;
|
||||
|
||||
@@ -242,6 +242,26 @@ uint8_t ADS7830_Measure_SingleEnded(ADC_HandleTypeDef *hadc, uint8_t channel);
|
||||
* if desired via a global flag. */
|
||||
extern int mock_printf_enabled;
|
||||
|
||||
/* ========================= CMSIS-Core stubs ======================= */
|
||||
/* Minimum surface to let F-4.7's DWT-based delayUs() in ADAR1000_Manager.cpp
|
||||
* compile under the host mock build. SystemCoreClock is intentionally 0 so
|
||||
* target = microseconds * (SystemCoreClock / 1000000) is also 0, making the
|
||||
* busy-wait loop exit immediately regardless of argument. Pre-setting
|
||||
* DWT->CTRL with CYCCNTENA also skips the one-time init branch. */
|
||||
|
||||
#define DWT_CTRL_CYCCNTENA_Msk (1UL << 0)
|
||||
#define CoreDebug_DEMCR_TRCENA_Msk (1UL << 24)
|
||||
|
||||
struct _DWT_Mock_Type { uint32_t CTRL; uint32_t CYCCNT; };
|
||||
struct _CoreDebug_Mock_Type { uint32_t DEMCR; };
|
||||
|
||||
extern struct _DWT_Mock_Type _dwt_mock;
|
||||
extern struct _CoreDebug_Mock_Type _coredebug_mock;
|
||||
extern uint32_t SystemCoreClock;
|
||||
|
||||
#define DWT (&_dwt_mock)
|
||||
#define CoreDebug (&_coredebug_mock)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user