main.cpp
   1  /* USER CODE BEGIN Header */
   2  /**
   3    ******************************************************************************
   4    * @file           : main.c
   5    * @brief          : Main program body
   6    ******************************************************************************
   7    * @attention
   8    *
   9    * Copyright (c) 2025 STMicroelectronics.
  10    * All rights reserved.
  11    *
  12    * This software is licensed under terms that can be found in the LICENSE file
  13    * in the root directory of this software component.
  14    * If no LICENSE file comes with this software, it is provided AS-IS.
  15    *
  16    ******************************************************************************
  17    */
  18  /* USER CODE END Header */
  19  /* Includes ------------------------------------------------------------------*/
  20  #include "main.h"
  21  #include "usb_device.h"
  22  #include "USBHandler.h"
  23  #include "usbd_cdc_if.h"
  24  #include "adar1000.h"
  25  #include "ADAR1000_Manager.h"
  26  extern "C" {
  27  #include "ad9523.h"
  28  }
  29  #include "no_os_delay.h"
  30  #include "no_os_alloc.h"
  31  #include "no_os_print_log.h"
  32  #include "no_os_error.h"
  33  #include "no_os_units.h"
  34  #include "no_os_dma.h"
  35  #include "no_os_spi.h"
  36  #include "no_os_uart.h"
  37  #include "no_os_util.h"
  38  #include <stdint.h>
  39  #include <errno.h>
  40  #include <math.h>
  41  #include <stdio.h>
  42  #include <string.h>
  43  #include <inttypes.h>
  44  #include <iostream>
  45  #include <vector>
  46  #include "stm32_spi.h"
  47  #include "stm32_delay.h"
  48  #include "TinyGPSPlus.h"
  49  extern "C" {
  50  #include "GY_85_HAL.h"
  51  }
  52  #include "BMP180.h"
  53  extern "C" {
  54  #include "platform_noos_stm32.h"
  55  }
  56  extern "C" {
  57  
  58  #include "adf4382a_manager.h"
  59  #include "adf4382.h"
  60  #include "no_os_delay.h"
  61  #include "no_os_error.h"
  62  #include "diag_log.h"
  63  }
  64  #include <cmath>
  65  #include "DAC5578.h"
  66  #include "ADS7830.h"
  67  #include "gps_handler.h"
  68  
  69  #include "stm32f7xx_hal.h"
  70  
  71  
  72  
  73  
  74  /* Private includes ----------------------------------------------------------*/
  75  /* USER CODE BEGIN Includes */
  76  
  77  /* USER CODE END Includes */
  78  
  79  /* Private typedef -----------------------------------------------------------*/
  80  /* USER CODE BEGIN PTD */
  81  
  82  
  83  /* USER CODE END PTD */
  84  
  85  /* Private define ------------------------------------------------------------*/
  86  /* USER CODE BEGIN PD */
  87  
  88  
  89  /* -------- GPIO index mapping for no-OS interface -------- */
  90  #define GPIO_IDX_TX_CS       0
  91  #define GPIO_IDX_RX_CS       1
  92  #define GPIO_IDX_TX_DELSTR   2
  93  #define GPIO_IDX_TX_DELADJ   3
  94  #define GPIO_IDX_RX_DELSTR   4
  95  #define GPIO_IDX_RX_DELADJ   5
  96  #define GPIO_IDX_TX_CE       6
  97  #define GPIO_IDX_RX_CE       7
  98  #define GPIO_IDX_SW_SYNC     8
  99  
 100  /* USER CODE END PD */
 101  
 102  /* Private macro -------------------------------------------------------------*/
 103  /* USER CODE BEGIN PM */
 104  
 105  /* USER CODE END PM */
 106  
 107  /* Private variables ---------------------------------------------------------*/
 108  
 109  I2C_HandleTypeDef hi2c1;
 110  I2C_HandleTypeDef hi2c2;
 111  I2C_HandleTypeDef hi2c3;
 112  
 113  SPI_HandleTypeDef hspi1;
 114  SPI_HandleTypeDef hspi4;
 115  
 116  TIM_HandleTypeDef htim1;
 117  TIM_HandleTypeDef htim3;  // B15 fix: DELADJ PWM timer (CH2=TX, CH3=RX)
 118  
 119  UART_HandleTypeDef huart5;
 120  UART_HandleTypeDef huart3;
 121  
 122  /* USER CODE BEGIN PV */
 123  // The TinyGPSPlus object
 124  TinyGPSPlus gps;
 125  
 126  // Global data structures
 127  GPS_Data_t current_gps_data = {0};
 128  
 129  // Global USB handler
 130  USBHandler usbHandler;
 131  extern USBD_HandleTypeDef hUsbDeviceFS;
 132  
 133  // Buffer for USB reception
 134  uint8_t usb_rx_buffer[64];
 135  
 136  //IMU variable
 137  GY85_t imu;
 138  
 139  float Pitch_Sensor, Yaw_Sensor, Roll_Sensor;
 140  
 141  float abias[3] = {-0.108, -0.038, -0.006}, gbias[3] = {-10, 6, -12}, mbias[3]={0.0,0.0,0.0};
 142  float M11=1.0,  M12=-0.0,  M13=0.0,
 143        M21=0.0,  M22=1.0,   M23=0.0,
 144        M31=0.0,  M32=-0.0,  M33=1.0;
 145  float ax, ay, az, gx, gy, gz, mx, my, mz,mxc,myc,mzc; // variables to hold latest sensor data values
 146  float q[4] = {1.0f, 0.0f, 0.0f, 0.0f};    // vector to hold quaternion
 147  float temperature;
 148  float Mag_Declination = -0.61; //0°
 149  
 150  float RxAcc,RyAcc,RzAcc;
 151  float Rate_Ayz_1,Rate_Axz_1,Rate_Axy_1;
 152  float Axz_1,Ayz_1,Axy_1, Axz_0,Ayz_0,Axy_0;
 153  float RxEst_0,RyEst_0,RzEst_0, RxEst_1,RyEst_1,RzEst_1,Azr_Est;
 154  float RxGyro,RyGyro,RzGyro, R_Est;
 155  
 156  unsigned long now_timeperiod;
 157  unsigned long lasttime_timeperiod = 0;
 158  int Time_Period = 0;
 159  
 160  //Barometer BMP180
 161  
 162  /*resolution:
 163  BMP180_ULTRALOWPOWER - pressure oversampled 1 time  & power consumption 3μA
 164  BMP180_STANDARD      - pressure oversampled 2 times & power consumption 5μA
 165  BMP180_HIGHRES       - pressure oversampled 4 times & power consumption 7μA
 166  BMP180_ULTRAHIGHRES  - pressure oversampled 8 times & power consumption 12μA, library default
 167  */
 168  BMP180 myBMP(BMP180_ULTRAHIGHRES);
 169  float RADAR_Altitude;
 170  
 171  //GPS
 172  double RADAR_Longitude = 0;
 173  double RADAR_Latitude = 0;
 174  
 175  extern uint8_t GUI_start_flag_received;
 176  
 177  
 178  //RADAR
 179  // Radar parameters
 180  const int m_max = 32;  // Number of chirps per beam position
 181  const int n_max = 31;   // Number of beam positions
 182  const float T1 = 30.0f; // Chirp duration in microseconds
 183  const float PRI1 = 167.0f; // Pulse repetition interval in microseconds
 184  const float T2 = 0.5f;  // Short chirp duration in microseconds
 185  const float PRI2 = 175.0f; // Short PRI in microseconds
 186  const float Guard = 175.4f; // Guard time in microseconds
 187  
 188  uint8_t	m = 1; // m = N° of chirp/ position = 16 (made of T1 and PRF1)+ Guard = 175µs +16 (made of T2 and PRF2)
 189  uint8_t	n = 1; // n =[1-31] N° of elevations/azimuth
 190  uint8_t	y = 1;// y = N° of azimuths/revolution = 50 controlled by a microcontroller connected to a stepper motor
 191  uint8_t y_max = 50;// y = N° of azimuths/revolution
 192  uint64_t IF_freq = 120000000ULL;//120MHz
 193  
 194  #define PowerAmplifier 1
 195  
 196  //Stepper Motor
 197  float Stepper_steps = 200.0f;//step per revolution
 198  
 199  // DAC5578 handles (RF Power Amplifier DAC controlling Vg)
 200  DAC5578_HandleTypeDef hdac1, hdac2;
 201  /* Phase accumulators */
 202  float phase_dac1[8] = {0};
 203  float phase_dac2[8] = {0};
 204  const uint32_t sampleRate = 370;    // Sample rate in Hz
 205  const uint32_t period = 2700;       // Period in microseconds
 206  uint8_t DAC_val = 126;
 207  
 208  // ADC handles (RF Power Amplifier ADC measuring Idq)
 209  ADS7830_HandleTypeDef hadc1, hadc2;
 210  uint8_t adc1_readings[8] = {0};
 211  uint8_t adc2_readings[8] = {0};
 212  float Idq_reading[16]={0.0f};
 213  
 214  /* [GAP-3 FIX 2] Hardware IWDG watchdog handle
 215   * Prescaler=256, Reload=500 → timeout ≈ 4.096 s from 32 kHz LSI.
 216   * If the main loop stalls, the MCU resets automatically. */
 217  IWDG_HandleTypeDef hiwdg;
 218  
 219  
 220  // Global manager instance ADF4382A
 221  ADF4382A_Manager lo_manager;
 222  extern SPI_HandleTypeDef hspi4;
 223  
 224  //ADAR1000
 225  
 226  ADAR1000Manager adarManager;
 227  static uint8_t matrix1[15][16];
 228  static uint8_t matrix2[15][16];
 229  static uint8_t vector_0[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 230  
 231  /* Radar parameters
 232  const int m_max = 32;  // Number of chirps per beam position
 233  const int n_max = 31;   // Number of beam positions
 234  const float T1 = 30.0f; // Chirp duration in microseconds
 235  const float PRI1 = 167.0f; // Pulse repetition interval in microseconds
 236  const float T2 = 0.5f;  // Short chirp duration in microseconds
 237  const float T2 = 175.0f; // Short PRI in microseconds
 238  const float Guard = 175.40f; // Guard time in microseconds*/
 239  
 240  //Temperature Sensors
 241  ADS7830_HandleTypeDef hadc3;
 242  float Temperature_1 = 0.0f, Temperature_2 = 0.0f, Temperature_3 = 0.0f, Temperature_4 = 0.0f;
 243  float Temperature_5 = 0.0f, Temperature_6 = 0.0f, Temperature_7 = 0.0f, Temperature_8 = 0.0f;
 244  
 245  // Phase differences for 31 beam positions
 246  const float phase_differences[31] = {
 247      160.0f, 80.0f, 53.333f, 40.0f, 32.0f, 26.667f, 22.857f, 20.0f, 17.778f, 16.0f,
 248      14.545f, 13.333f, 12.308f, 11.429f, 10.667f, 0.0f,
 249      -10.667f, -11.429f, -12.308f, -13.333f, -14.545f, -16.0f, -17.778f, -20.0f,
 250      -22.857f, -26.667f, -32.0f, -40.0f, -53.333f, -80.0f, -160.0f
 251  };
 252  
 253  // Convenience HAL wrappers for AD9523 control pins (GPIOF as you said)
 254  static inline void AD9523_PD(bool v)        { HAL_GPIO_WritePin(GPIOF, AD9523_PD_Pin, v ? GPIO_PIN_SET : GPIO_PIN_RESET); }
 255  static inline void AD9523_REF_SEL(bool v)   { HAL_GPIO_WritePin(GPIOF, AD9523_REF_SEL_Pin, v ? GPIO_PIN_SET : GPIO_PIN_RESET); }
 256  static inline void AD9523_SYNC_PULSE(void)  { HAL_GPIO_WritePin(GPIOF, AD9523_SYNC_Pin, GPIO_PIN_SET); HAL_Delay(1); HAL_GPIO_WritePin(GPIOF, AD9523_SYNC_Pin, GPIO_PIN_RESET); }
 257  static inline void AD9523_RESET_ASSERT()    { HAL_GPIO_WritePin(GPIOF, AD9523_RESET_Pin, GPIO_PIN_RESET); } // check polarity
 258  static inline void AD9523_RESET_RELEASE()   { HAL_GPIO_WritePin(GPIOF, AD9523_RESET_Pin, GPIO_PIN_SET); }
 259  static inline void AD9523_CS(bool v)        { HAL_GPIO_WritePin(GPIOF, AD9523_CS_Pin, v ? GPIO_PIN_SET : GPIO_PIN_RESET); }
 260  static inline void AD9523_EEPROM_SEL(bool v){ HAL_GPIO_WritePin(GPIOF, AD9523_EEPROM_SEL_Pin, v ? GPIO_PIN_SET : GPIO_PIN_RESET); }
 261  
 262  /* USER CODE END PV */
 263  
 264  /* Private function prototypes -----------------------------------------------*/
 265  void SystemClock_Config(void);
 266  void PeriphCommonClock_Config(void);
 267  static void MPU_Config(void);
 268  static void MX_GPIO_Init(void);
 269  static void MX_TIM1_Init(void);
 270  static void MX_TIM3_Init(void);  // B15 fix: DELADJ PWM timer init
 271  static void MX_I2C1_Init(void);
 272  static void MX_I2C2_Init(void);
 273  static void MX_I2C3_Init(void);
 274  static void MX_SPI1_Init(void);
 275  static void MX_SPI4_Init(void);
 276  static void MX_UART5_Init(void);
 277  static void MX_USART3_UART_Init(void);
 278  static void MX_IWDG_Init(void);  /* GAP-3 FIX 2: hardware watchdog */
 279  /* USER CODE BEGIN PFP */
 280  
 281  // Function prototypes
 282  void systemPowerUpSequence();
 283  void systemPowerDownSequence();
 284  void initializeBeamMatrices();
 285  void runRadarPulseSequence();
 286  void executeChirpSequence(int num_chirps, uint32_t T1, uint32_t PRI1, uint32_t T2, uint32_t PRI2);
 287  void printSystemStatus();
 288  
 289  //////////////////////////////////////////////
 290  ////////////////////micros()//////////////////
 291  //////////////////////////////////////////////
 292  unsigned long micros(void){
 293  unsigned long Micros = __HAL_TIM_GET_COUNTER(&htim1);
 294  return Micros; //Clock TIM1 -> AHB/APB1 is set to 72MHz/presc+1   presc = 71
 295  }
 296  
 297  //////////////////////////////////////////////
 298  //////////////////Delay_us()//////////////////
 299  //////////////////////////////////////////////
 300  
 301  void delay_us(volatile uint32_t us){
 302  __HAL_TIM_SET_COUNTER(&htim1,0);  // set the counter value a
 303  while (__HAL_TIM_GET_COUNTER(&htim1) < us);  // //Clock TIMx -> AHB/APB1 is set to 72MHz/presc+1   presc = 71
 304  }
 305  
 306  //////////////////////////////////////////////
 307  //////////////////delay_ns()//////////////////
 308  //////////////////////////////////////////////
 309  void delay_ns(uint32_t nanoseconds)
 310  {
 311      // Get the starting cycle count
 312      uint32_t start_cycles = DWT->CYCCNT;
 313  
 314      // Convert nanoseconds to the number of CPU clock cycles
 315      // Use `SystemCoreClock` to get the current CPU frequency.
 316      // Use 64-bit math to prevent overflow for large nanosecond values.
 317      uint32_t cycles = (uint32_t)(((uint64_t)nanoseconds * SystemCoreClock) / 1000000000);
 318  
 319      // Busy-wait until the required number of cycles has passed
 320      while ((DWT->CYCCNT - start_cycles) < cycles);
 321  }
 322  
 323  //////////////////////////////////////////////
 324  //////////////////////RADAR///////////////////
 325  //////////////////////////////////////////////
 326  uint8_t degreesTo7BitPhase(float degrees) {
 327      // Normalize to 0-360 range
 328      while(degrees < 0) degrees += 360.0f;
 329      while(degrees >= 360.0f) degrees -= 360.0f;
 330  
 331      // Convert to 7-bit (0-127)
 332      uint8_t phase_7bit = (uint8_t)((degrees / 360.0f) * 128.0f);
 333  
 334      return phase_7bit % 128;
 335  }
 336  
 337  extern "C" {
 338  
 339      // USB CDC receive callback (called by STM32 HAL)
 340      void CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) {
 341          DIAG("USB", "CDC_Receive_FS callback: %lu bytes received", *Len);
 342          // Process received USB data
 343          usbHandler.processUSBData(Buf, *Len);
 344  
 345          // Prepare for next reception
 346          USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &usb_rx_buffer[0]);
 347          USBD_CDC_ReceivePacket(&hUsbDeviceFS);
 348      }
 349  }
 350  
 351  void systemPowerUpSequence() {
 352      DIAG_SECTION("PWR: systemPowerUpSequence");
 353      uint8_t msg[] = "Starting Power Up Sequence...\r\n";
 354      HAL_UART_Transmit(&huart3, msg, sizeof(msg)-1, 1000);
 355  
 356      // Step 1: Initialize ADTR1107 power sequence
 357      DIAG("PWR", "Step 1: initializeADTR1107Sequence()");
 358      if (!adarManager.initializeADTR1107Sequence()) {
 359          DIAG_ERR("PWR", "ADTR1107 power sequence FAILED -- calling Error_Handler()");
 360          uint8_t err[] = "ERROR: ADTR1107 power sequence failed!\r\n";
 361          HAL_UART_Transmit(&huart3, err, sizeof(err)-1, 1000);
 362          Error_Handler();
 363      }
 364      DIAG("PWR", "Step 1 OK: ADTR1107 sequence complete");
 365  
 366      // Step 2: Initialize all ADAR1000 devices
 367      DIAG("PWR", "Step 2: initializeAllDevices()");
 368      if (!adarManager.initializeAllDevices()) {
 369          DIAG_ERR("PWR", "ADAR1000 initialization FAILED -- calling Error_Handler()");
 370          uint8_t err[] = "ERROR: ADAR1000 initialization failed!\r\n";
 371          HAL_UART_Transmit(&huart3, err, sizeof(err)-1, 1000);
 372          Error_Handler();
 373      }
 374      DIAG("PWR", "Step 2 OK: All ADAR1000 devices initialized");
 375  
 376      // Step 3: Perform system calibration
 377      DIAG("PWR", "Step 3: performSystemCalibration()");
 378      if (!adarManager.performSystemCalibration()) {
 379          DIAG_WARN("PWR", "System calibration returned issues (non-fatal)");
 380          uint8_t warn[] = "WARNING: System calibration issues\r\n";
 381          HAL_UART_Transmit(&huart3, warn, sizeof(warn)-1, 1000);
 382      } else {
 383          DIAG("PWR", "Step 3 OK: System calibration passed");
 384      }
 385  
 386      // Step 4: Set to safe TX mode
 387      DIAG("PWR", "Step 4: setAllDevicesTXMode()");
 388      adarManager.setAllDevicesTXMode();
 389      DIAG("PWR", "Step 4 OK: All devices set to TX mode");
 390  
 391      uint8_t success[] = "Power Up Sequence Completed Successfully\r\n";
 392      HAL_UART_Transmit(&huart3, success, sizeof(success)-1, 1000);
 393      DIAG("PWR", "systemPowerUpSequence COMPLETE");
 394  }
 395  
 396  void systemPowerDownSequence() {
 397      DIAG_SECTION("PWR: systemPowerDownSequence");
 398      uint8_t msg[] = "Starting Power Down Sequence...\r\n";
 399      HAL_UART_Transmit(&huart3, msg, sizeof(msg)-1, 1000);
 400  
 401      // Step 1: Set all devices to RX mode (safest state)
 402      DIAG("PWR", "Step 1: setAllDevicesRXMode()");
 403      adarManager.setAllDevicesRXMode();
 404      HAL_Delay(10);
 405  
 406      // Step 2: Disable PA power supplies
 407      DIAG("PWR", "Step 2: Disable PA 5V supplies (EN_P_5V0_PA1/PA2/PA3 LOW)");
 408      HAL_GPIO_WritePin(EN_P_5V0_PA1_GPIO_Port, EN_P_5V0_PA1_Pin | EN_P_5V0_PA2_Pin | EN_P_5V0_PA3_Pin, GPIO_PIN_RESET);
 409      HAL_Delay(10);
 410  
 411      // Step 3: Set PA biases to safe values
 412      DIAG("PWR", "Step 3: Setting PA bias to safe value 0x20 on all 4 devices, 4 channels each");
 413      for (uint8_t dev = 0; dev < 4; dev++) {
 414          adarManager.adarWrite(dev, REG_PA_CH1_BIAS_ON, 0x20, BROADCAST_OFF);
 415          adarManager.adarWrite(dev, REG_PA_CH2_BIAS_ON, 0x20, BROADCAST_OFF);
 416          adarManager.adarWrite(dev, REG_PA_CH3_BIAS_ON, 0x20, BROADCAST_OFF);
 417          adarManager.adarWrite(dev, REG_PA_CH4_BIAS_ON, 0x20, BROADCAST_OFF);
 418      }
 419      HAL_Delay(10);
 420  
 421      // Step 4: Disable LNA power supply
 422      DIAG("PWR", "Step 4: Disable LNA 3.3V supply (EN_P_3V3_ADTR LOW)");
 423      HAL_GPIO_WritePin(EN_P_3V3_ADTR_GPIO_Port, EN_P_3V3_ADTR_Pin, GPIO_PIN_RESET);
 424      HAL_Delay(10);
 425  
 426      // Step 5: Set LNA bias to safe value
 427      DIAG("PWR", "Step 5: Setting LNA bias to 0x00 on all 4 devices");
 428      for (uint8_t dev = 0; dev < 4; dev++) {
 429          adarManager.adarWrite(dev, REG_LNA_BIAS_ON, 0x00, BROADCAST_OFF);
 430      }
 431      HAL_Delay(10);
 432  
 433      // Step 6: Disable switch power supplies
 434      DIAG("PWR", "Step 6: Disable switch supplies (EN_P_3V3_VDD_SW, EN_P_3V3_SW LOW)");
 435      HAL_GPIO_WritePin(EN_P_3V3_VDD_SW_GPIO_Port, EN_P_3V3_VDD_SW_Pin, GPIO_PIN_RESET);
 436      HAL_GPIO_WritePin(EN_P_3V3_SW_GPIO_Port, EN_P_3V3_SW_Pin, GPIO_PIN_RESET);
 437      HAL_Delay(10);
 438  
 439      uint8_t success[] = "Power Down Sequence Completed\r\n";
 440      HAL_UART_Transmit(&huart3, success, sizeof(success)-1, 1000);
 441      DIAG("PWR", "systemPowerDownSequence COMPLETE");
 442  }
 443  
 444  void initializeBeamMatrices() {
 445      uint8_t msg[] = "Initializing Beam Matrices...\r\n";
 446      HAL_UART_Transmit(&huart3, msg, sizeof(msg)-1, 1000);
 447  
 448      // Matrix1: Positions 1-15 (positive phase differences)
 449      for(int beam_pos = 0; beam_pos < 15; beam_pos++) {
 450          float phase_diff_degrees = phase_differences[beam_pos];
 451  
 452          for(int element = 0; element < 16; element++) {
 453              float cumulative_phase_degrees = element * phase_diff_degrees;
 454              matrix1[beam_pos][element] = degreesTo7BitPhase(cumulative_phase_degrees);
 455          }
 456      }
 457  
 458      // Matrix2: Positions 17-31 (negative phase differences)
 459      for(int beam_pos = 0; beam_pos < 15; beam_pos++) {
 460          float phase_diff_degrees = phase_differences[beam_pos + 16];
 461  
 462          for(int element = 0; element < 16; element++) {
 463              float cumulative_phase_degrees = element * phase_diff_degrees;
 464              matrix2[beam_pos][element] = degreesTo7BitPhase(cumulative_phase_degrees);
 465          }
 466      }
 467  
 468      // Vector_0: Position 16 (zero phase - broadside)
 469      for(int element = 0; element < 16; element++) {
 470          vector_0[element] = 0; // 0 in 7-bit = 0° phase
 471      }
 472  
 473      uint8_t done[] = "Beam Matrices Initialized\r\n";
 474      HAL_UART_Transmit(&huart3, done, sizeof(done)-1, 1000);
 475  }
 476  
 477  void executeChirpSequence(int num_chirps, float T1, float PRI1, float T2, float PRI2) {
 478      // NOTE: No per-chirp DIAG — this is a us/ns timing-critical path.
 479      // Only log entry params for post-mortem analysis.
 480      DIAG("SYS", "executeChirpSequence: num_chirps=%d T1=%.2f PRI1=%.2f T2=%.2f PRI2=%.2f",
 481           num_chirps, T1, PRI1, T2, PRI2);
 482      // First chirp sequence (microsecond timing)
 483      for(int i = 0; i < num_chirps; i++) {
 484          HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_8); // New chirp signal to FPGA
 485          adarManager.pulseTXMode();
 486          delay_us((uint32_t)T1);
 487          adarManager.pulseRXMode();
 488          delay_us((uint32_t)(PRI1 - T1));
 489      }
 490  
 491      delay_us((uint32_t)Guard);
 492  
 493      // Second chirp sequence (nanosecond timing)
 494      for(int i = 0; i < num_chirps; i++) {
 495      	HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_8); // New chirp signal to FPGA
 496          adarManager.pulseTXMode();
 497          delay_ns((uint32_t)(T2 * 1000));
 498          adarManager.pulseRXMode();
 499          delay_ns((uint32_t)((PRI2 - T2) * 1000));
 500  
 501      }
 502  }
 503  
 504  void runRadarPulseSequence() {
 505      static int sequence_count = 0;
 506      char msg[50];
 507  
 508      snprintf(msg, sizeof(msg), "Starting RADAR Sequence #%d\r\n", ++sequence_count);
 509      HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), 1000);
 510      DIAG("SYS", "runRadarPulseSequence #%d: m_max=%d n_max=%d y_max=%d",
 511           sequence_count, m_max, n_max, y_max);
 512  
 513      // Configure for fast switching
 514      DIAG("BF", "Enabling fast-switch mode for beam sweep");
 515      adarManager.setFastSwitchMode(true);
 516  
 517      int m = 1; // Chirp counter
 518      int n = 1; // Beam Elevation position counter
 519      int y = 1; // Beam Azimuth counter
 520  
 521      // Main beam steering sequence
 522      for(int beam_pos = 0; beam_pos < 15; beam_pos++) {
 523      	HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_9);// Notify FPGA of elevation change
 524      	DIAG("SYS", "Beam pos %d/15: elevation GPIO toggle, patterns matrix1/vector_0/matrix2", beam_pos);
 525          // Pattern 1: matrix1 (positive steering angles)
 526          adarManager.setCustomBeamPattern16(matrix1[beam_pos], ADAR1000Manager::BeamDirection::TX);
 527          adarManager.setCustomBeamPattern16(matrix1[beam_pos], ADAR1000Manager::BeamDirection::RX);
 528  
 529          executeChirpSequence(m_max/2, T1, PRI1, T2, PRI2);
 530          m += m_max/2;
 531  
 532          // Pattern 2: vector_0 (broadside)
 533          adarManager.setCustomBeamPattern16(vector_0, ADAR1000Manager::BeamDirection::TX);
 534          adarManager.setCustomBeamPattern16(vector_0, ADAR1000Manager::BeamDirection::RX);
 535  
 536          executeChirpSequence(m_max/2, T1, PRI1, T2, PRI2);
 537          m += m_max/2;
 538  
 539          // Pattern 3: matrix2 (negative steering angles)
 540          adarManager.setCustomBeamPattern16(matrix2[beam_pos], ADAR1000Manager::BeamDirection::TX);
 541          adarManager.setCustomBeamPattern16(matrix2[beam_pos], ADAR1000Manager::BeamDirection::RX);
 542  
 543          executeChirpSequence(m_max/2, T1, PRI1, T2, PRI2);
 544          m += m_max/2;
 545  
 546          // Reset chirp counter if needed
 547          if(m > m_max) m = 1;
 548  
 549          n++;
 550          if(n > n_max) n = 1;
 551  
 552      }
 553  
 554      HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_10);//Tell FPGA that there is a new azimuth
 555      DIAG("SYS", "Azimuth GPIO toggle (GPIOD pin 10), stepping motor");
 556  
 557      y++; if(y>y_max)y=1;
 558  	  //Rotate stepper to next y position
 559  	  for(int k= 0;k<(int)(Stepper_steps/y_max);k++){
 560  		  HAL_GPIO_WritePin(STEPPER_CLK_P_GPIO_Port, STEPPER_CLK_P_Pin, GPIO_PIN_SET);
 561  		  delay_us(500);
 562  		  HAL_GPIO_WritePin(STEPPER_CLK_P_GPIO_Port, STEPPER_CLK_P_Pin, GPIO_PIN_RESET);
 563  		  delay_us(500);
 564  	  }
 565      DIAG("MOT", "Stepper moved %d steps for azimuth position y=%d", (int)(Stepper_steps/y_max), y);
 566  
 567  
 568  
 569      snprintf(msg, sizeof(msg), "RADAR Sequence #%d Completed\r\n", sequence_count);
 570      HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), 1000);
 571      DIAG("SYS", "runRadarPulseSequence #%d COMPLETE", sequence_count);
 572  }
 573  
 574  
 575  
 576  
 577  void printSystemStatus() {
 578      char status_msg[100];
 579  
 580      // Print device status
 581      for(int i = 0; i < 4; i++) {
 582          if(adarManager.verifyDeviceCommunication(i)) {
 583              float temp = adarManager.readTemperature(i);
 584              snprintf(status_msg, sizeof(status_msg),
 585                      "ADAR1000 #%d: OK, Temperature: %.1fC\r\n", i+1, temp);
 586              HAL_UART_Transmit(&huart3, (uint8_t*)status_msg, strlen(status_msg), 1000);
 587          } else {
 588              snprintf(status_msg, sizeof(status_msg),
 589                      "ADAR1000 #%d: COMMUNICATION ERROR\r\n", i+1);
 590              HAL_UART_Transmit(&huart3, (uint8_t*)status_msg, strlen(status_msg), 1000);
 591          }
 592      }
 593  
 594      // Print matrix info
 595      snprintf(status_msg, sizeof(status_msg),
 596              "Beam Matrices: 31 positions, %d chirps/position\r\n", m_max);
 597      HAL_UART_Transmit(&huart3, (uint8_t*)status_msg, strlen(status_msg), 1000);
 598  }
 599  
 600  /***************************************************************/
 601  /**********************SYSTEM ERROR HANDLER*********************/
 602  /***************************************************************/
 603  
 604  typedef enum {
 605      ERROR_NONE = 0,
 606      ERROR_AD9523_CLOCK,
 607      ERROR_ADF4382_TX_UNLOCK,
 608      ERROR_ADF4382_RX_UNLOCK,
 609      ERROR_ADAR1000_COMM,
 610      ERROR_ADAR1000_TEMP,
 611      ERROR_IMU_COMM,
 612      ERROR_BMP180_COMM,
 613      ERROR_GPS_COMM,
 614      ERROR_RF_PA_OVERCURRENT,
 615      ERROR_RF_PA_BIAS,
 616      ERROR_STEPPER_MOTOR,
 617      ERROR_FPGA_COMM,
 618      ERROR_POWER_SUPPLY,
 619      ERROR_TEMPERATURE_HIGH,
 620      ERROR_MEMORY_ALLOC,
 621      ERROR_WATCHDOG_TIMEOUT
 622  } SystemError_t;
 623  
 624  static SystemError_t last_error = ERROR_NONE;
 625  static uint32_t error_count = 0;
 626  static bool system_emergency_state = false;
 627  
 628  // Error handler function
 629  SystemError_t checkSystemHealth(void) {
 630      SystemError_t current_error = ERROR_NONE;
 631  
 632      // 1. Check AD9523 Clock Generator
 633      static uint32_t last_clock_check = 0;
 634      if (HAL_GetTick() - last_clock_check > 5000) {
 635          GPIO_PinState s0 = HAL_GPIO_ReadPin(AD9523_STATUS0_GPIO_Port, AD9523_STATUS0_Pin);
 636          GPIO_PinState s1 = HAL_GPIO_ReadPin(AD9523_STATUS1_GPIO_Port, AD9523_STATUS1_Pin);
 637          DIAG_GPIO("CLK", "AD9523 STATUS0", s0);
 638          DIAG_GPIO("CLK", "AD9523 STATUS1", s1);
 639          if (s0 == GPIO_PIN_RESET || s1 == GPIO_PIN_RESET) {
 640              current_error = ERROR_AD9523_CLOCK;
 641              DIAG_ERR("CLK", "AD9523 clock health check FAILED (STATUS0=%d STATUS1=%d)", s0, s1);
 642          }
 643          last_clock_check = HAL_GetTick();
 644      }
 645  
 646      // 2. Check ADF4382 Lock Status
 647      bool tx_locked, rx_locked;
 648      if (ADF4382A_CheckLockStatus(&lo_manager, &tx_locked, &rx_locked) == ADF4382A_MANAGER_OK) {
 649          if (!tx_locked) {
 650              current_error = ERROR_ADF4382_TX_UNLOCK;
 651              DIAG_ERR("LO", "Health check: TX LO UNLOCKED");
 652          }
 653          if (!rx_locked) {
 654              current_error = ERROR_ADF4382_RX_UNLOCK;
 655              DIAG_ERR("LO", "Health check: RX LO UNLOCKED");
 656          }
 657      }
 658  
 659      // 3. Check ADAR1000 Communication and Temperature
 660      for (int i = 0; i < 4; i++) {
 661          if (!adarManager.verifyDeviceCommunication(i)) {
 662              current_error = ERROR_ADAR1000_COMM;
 663              DIAG_ERR("BF", "Health check: ADAR1000 #%d comm FAILED", i);
 664              break;
 665          }
 666  
 667          float temp = adarManager.readTemperature(i);
 668          if (temp > 85.0f) {
 669              current_error = ERROR_ADAR1000_TEMP;
 670              DIAG_ERR("BF", "Health check: ADAR1000 #%d OVERTEMP %.1fC > 85C", i, temp);
 671              break;
 672          }
 673      }
 674  
 675      // 4. Check IMU Communication
 676      static uint32_t last_imu_check = 0;
 677      if (HAL_GetTick() - last_imu_check > 10000) {
 678          if (!GY85_Update(&imu)) {
 679              current_error = ERROR_IMU_COMM;
 680              DIAG_ERR("IMU", "Health check: GY85_Update() FAILED");
 681          }
 682          last_imu_check = HAL_GetTick();
 683      }
 684  
 685      // 5. Check BMP180 Communication
 686      static uint32_t last_bmp_check = 0;
 687      if (HAL_GetTick() - last_bmp_check > 15000) {
 688          double pressure = myBMP.getPressure();
 689          if (pressure < 30000.0 || pressure > 110000.0 || isnan(pressure)) {
 690              current_error = ERROR_BMP180_COMM;
 691              DIAG_ERR("SYS", "Health check: BMP180 pressure out of range: %.0f", pressure);
 692          }
 693          last_bmp_check = HAL_GetTick();
 694      }
 695  
 696      // 6. Check GPS Communication
 697      static uint32_t last_gps_fix = 0;
 698      if (gps.location.isUpdated()) {
 699          last_gps_fix = HAL_GetTick();
 700      }
 701      if (HAL_GetTick() - last_gps_fix > 30000) {
 702          current_error = ERROR_GPS_COMM;
 703          DIAG_WARN("SYS", "Health check: GPS no fix for >30s");
 704      }
 705  
 706      // 7. Check RF Power Amplifier Current
 707      if (PowerAmplifier) {
 708          for (int i = 0; i < 16; i++) {
 709              if (Idq_reading[i] > 2.5f) {
 710                  current_error = ERROR_RF_PA_OVERCURRENT;
 711                  DIAG_ERR("PA", "Health check: PA ch%d OVERCURRENT Idq=%.3fA > 2.5A", i, Idq_reading[i]);
 712                  break;
 713              }
 714              if (Idq_reading[i] < 0.1f) {
 715                  current_error = ERROR_RF_PA_BIAS;
 716                  DIAG_ERR("PA", "Health check: PA ch%d BIAS FAULT Idq=%.3fA < 0.1A", i, Idq_reading[i]);
 717                  break;
 718              }
 719          }
 720      }
 721  
 722      // 8. Check System Temperature
 723      if (temperature > 75.0f) {
 724          current_error = ERROR_TEMPERATURE_HIGH;
 725          DIAG_ERR("SYS", "Health check: System OVERTEMP %.1fC > 75C", temperature);
 726      }
 727  
 728      // 9. Simple watchdog check
 729      static uint32_t last_health_check = 0;
 730      if (HAL_GetTick() - last_health_check > 60000) {
 731          current_error = ERROR_WATCHDOG_TIMEOUT;
 732          DIAG_ERR("SYS", "Health check: Watchdog timeout (>60s since last check)");
 733      }
 734      last_health_check = HAL_GetTick();
 735  
 736      if (current_error != ERROR_NONE) {
 737          DIAG_ERR("SYS", "checkSystemHealth returning error code %d", current_error);
 738      }
 739      return current_error;
 740  }
 741  
 742  // Error recovery function
 743  void attemptErrorRecovery(SystemError_t error) {
 744      DIAG_SECTION("SYS: attemptErrorRecovery");
 745      DIAG("SYS", "Attempting recovery from error code %d", error);
 746      char recovery_msg[80];
 747      snprintf(recovery_msg, sizeof(recovery_msg),
 748               "Attempting recovery from error: %d\r\n", error);
 749      HAL_UART_Transmit(&huart3, (uint8_t*)recovery_msg, strlen(recovery_msg), 1000);
 750  
 751      switch (error) {
 752          case ERROR_ADF4382_TX_UNLOCK:
 753          case ERROR_ADF4382_RX_UNLOCK:
 754              // Re-initialize LO
 755              DIAG("LO", "Recovery: Re-initializing LO manager (SYNC_METHOD_TIMED)");
 756              ADF4382A_Manager_Init(&lo_manager, SYNC_METHOD_TIMED);
 757              HAL_Delay(100);
 758              DIAG("LO", "Recovery: LO re-init complete");
 759              break;
 760  
 761          case ERROR_ADAR1000_COMM:
 762              // Reset ADAR1000 communication
 763              DIAG("BF", "Recovery: Re-initializing all ADAR1000 devices");
 764              adarManager.initializeAllDevices();
 765              HAL_Delay(50);
 766              DIAG("BF", "Recovery: ADAR1000 re-init complete");
 767              break;
 768  
 769          case ERROR_IMU_COMM:
 770              // Re-initialize IMU
 771              DIAG("IMU", "Recovery: Re-initializing GY85 IMU");
 772              GY85_Init();
 773              HAL_Delay(100);
 774              DIAG("IMU", "Recovery: IMU re-init complete");
 775              break;
 776  
 777          case ERROR_GPS_COMM:
 778              // GPS will auto-recover when signal returns
 779              DIAG("SYS", "Recovery: GPS error -- no action (auto-recover on signal)");
 780              break;
 781  
 782          default:
 783              // For other errors, just log and continue
 784              DIAG_WARN("SYS", "Recovery: No specific handler for error %d", error);
 785              break;
 786      }
 787  
 788      snprintf(recovery_msg, sizeof(recovery_msg),
 789               "Recovery attempt completed.\r\n");
 790      HAL_UART_Transmit(&huart3, (uint8_t*)recovery_msg, strlen(recovery_msg), 1000);
 791      DIAG("SYS", "attemptErrorRecovery COMPLETE");
 792  }
 793  
 794  ////////////////////////////////////////////////////////////////////////////////
 795  //:::::RF POWER AMPLIFIER DAC5578 Emergency stop function using CLR pin/////////
 796  ////////////////////////////////////////////////////////////////////////////////
 797  void Emergency_Stop(void) {
 798      DIAG_ERR("PA", ">>> EMERGENCY_STOP ACTIVATED <<<");
 799      /* Immediately clear all DAC outputs to zero using hardware CLR */
 800      DIAG_ERR("PA", "Clearing DAC1 outputs via CLR pin");
 801      DAC5578_ActivateClearPin(&hdac1);
 802      DIAG_ERR("PA", "Clearing DAC2 outputs via CLR pin");
 803      DAC5578_ActivateClearPin(&hdac2);
 804  
 805      /* [GAP-3 FIX 1] Cut RF and PA power rails — DAC CLR alone is not enough.
 806       * With gate voltage cleared but VDD still energized, PAs can self-bias
 807       * or oscillate.  Disable everything in fast-to-slow order:
 808       *   1. TX mixers (stop RF immediately)
 809       *   2. PA 5V per-element supplies
 810       *   3. PA 5.5V bulk supply
 811       *   4. RFPA VDD enable
 812       */
 813      DIAG_ERR("PA", "Disabling TX mixers (GPIOD pin 11 LOW)");
 814      HAL_GPIO_WritePin(GPIOD, GPIO_PIN_11, GPIO_PIN_RESET);
 815  
 816      DIAG_ERR("PA", "Cutting PA 5V supplies (PA1/PA2/PA3 LOW)");
 817      HAL_GPIO_WritePin(EN_P_5V0_PA1_GPIO_Port, EN_P_5V0_PA1_Pin, GPIO_PIN_RESET);
 818      HAL_GPIO_WritePin(EN_P_5V0_PA2_GPIO_Port, EN_P_5V0_PA2_Pin, GPIO_PIN_RESET);
 819      HAL_GPIO_WritePin(EN_P_5V0_PA3_GPIO_Port, EN_P_5V0_PA3_Pin, GPIO_PIN_RESET);
 820  
 821      DIAG_ERR("PA", "Cutting PA 5.5V supply (EN_P_5V5_PA LOW)");
 822      HAL_GPIO_WritePin(EN_P_5V5_PA_GPIO_Port, EN_P_5V5_PA_Pin, GPIO_PIN_RESET);
 823  
 824      DIAG_ERR("PA", "Disabling RFPA VDD (EN_DIS_RFPA_VDD LOW)");
 825      HAL_GPIO_WritePin(EN_DIS_RFPA_VDD_GPIO_Port, EN_DIS_RFPA_VDD_Pin, GPIO_PIN_RESET);
 826  
 827      DIAG_ERR("PA", "All PA rails cut -- entering infinite hold loop (manual reset required)");
 828      /* Keep outputs cleared until reset.
 829       * MUST refresh IWDG here — otherwise the watchdog would reset the MCU,
 830       * re-running startup code which re-energizes PA rails. */
 831      while (1) {
 832          HAL_IWDG_Refresh(&hiwdg);
 833          HAL_Delay(100);
 834      }
 835  }
 836  
 837  // Error response function
 838  void handleSystemError(SystemError_t error) {
 839      if (error == ERROR_NONE) return;
 840  
 841      error_count++;
 842      last_error = error;
 843      DIAG_ERR("SYS", "handleSystemError: error=%d error_count=%lu", error, error_count);
 844  
 845      char error_msg[100];
 846      const char* error_strings[] = {
 847          "No error",
 848          "AD9523 Clock failure",
 849          "ADF4382 TX LO unlocked",
 850          "ADF4382 RX LO unlocked",
 851          "ADAR1000 communication error",
 852          "ADAR1000 temperature high",
 853          "IMU communication error",
 854          "BMP180 communication error",
 855          "GPS communication lost",
 856          "RF PA overcurrent detected",
 857          "RF PA bias fault",
 858          "Stepper motor fault",
 859          "FPGA communication error",
 860          "Power supply fault",
 861          "System temperature high",
 862          "Memory allocation failed",
 863          "Watchdog timeout"
 864      };
 865  
 866      snprintf(error_msg, sizeof(error_msg),
 867               "ERROR #%d: %s (Count: %lu)\r\n",
 868               error, error_strings[error], error_count);
 869      HAL_UART_Transmit(&huart3, (uint8_t*)error_msg, strlen(error_msg), 1000);
 870  
 871      // Blink LED pattern based on error code
 872      DIAG("SYS", "Blinking LED3 %d times for error code %d", (error % 5) + 1, error);
 873      for (int i = 0; i < (error % 5) + 1; i++) {
 874          HAL_GPIO_TogglePin(LED_3_GPIO_Port, LED_3_Pin);
 875          HAL_Delay(200);
 876      }
 877  
 878      // Critical errors trigger emergency shutdown
 879      if (error >= ERROR_RF_PA_OVERCURRENT && error <= ERROR_POWER_SUPPLY) {
 880          DIAG_ERR("SYS", "CRITICAL ERROR (code %d: %s) -- initiating Emergency_Stop()", error, error_strings[error]);
 881          snprintf(error_msg, sizeof(error_msg),
 882                   "CRITICAL ERROR! Initiating emergency shutdown.\r\n");
 883          HAL_UART_Transmit(&huart3, (uint8_t*)error_msg, strlen(error_msg), 1000);
 884  
 885          /* [GAP-3 FIX 5] Set flag BEFORE Emergency_Stop() — the function
 886           * never returns (infinite loop), so the line after it was dead code. */
 887          system_emergency_state = true;
 888          Emergency_Stop();
 889          /* NOTREACHED — Emergency_Stop() loops forever */
 890      }
 891  
 892      // For non-critical errors, attempt recovery
 893      if (!system_emergency_state) {
 894          DIAG("SYS", "Non-critical error -- attempting recovery");
 895          attemptErrorRecovery(error);
 896      }
 897  }
 898  
 899  
 900  // System health monitoring function
 901  bool checkSystemHealthStatus(void) {
 902      SystemError_t error = checkSystemHealth();
 903  
 904      if (error != ERROR_NONE) {
 905          DIAG_ERR("SYS", "checkSystemHealthStatus: error detected (code %d), calling handleSystemError()", error);
 906          handleSystemError(error);
 907  
 908          // If we're in emergency state or too many errors, shutdown
 909          if (system_emergency_state || error_count > 10) {
 910              DIAG_ERR("SYS", "checkSystemHealthStatus returning FALSE (emergency=%s error_count=%lu)",
 911                       system_emergency_state ? "true" : "false", error_count);
 912              return false;
 913          }
 914      }
 915  
 916      return true;
 917  }
 918  
 919  // Get system status for GUI
 920  // Get system status for GUI with 8 temperature variables
 921  void getSystemStatusForGUI(char* status_buffer, size_t buffer_size) {
 922      char temp_buffer[200];
 923      char final_status[500] = "System Status: ";
 924  
 925      // Basic status
 926      if (system_emergency_state) {
 927          strcat(final_status, "EMERGENCY_STOP|");
 928      } else {
 929          strcat(final_status, "NORMAL|");
 930      }
 931  
 932      // Error information
 933      snprintf(temp_buffer, sizeof(temp_buffer), "LastError:%d|ErrorCount:%lu|",
 934               last_error, error_count);
 935      strcat(final_status, temp_buffer);
 936  
 937      // Sensor status
 938      snprintf(temp_buffer, sizeof(temp_buffer), "IMU:%.1f,%.1f,%.1f|GPS:%.6f,%.6f|ALT:%.1f|",
 939               Pitch_Sensor, Roll_Sensor, Yaw_Sensor,
 940               RADAR_Latitude, RADAR_Longitude, RADAR_Altitude);
 941      strcat(final_status, temp_buffer);
 942  
 943      // LO Status
 944      bool tx_locked, rx_locked;
 945      ADF4382A_CheckLockStatus(&lo_manager, &tx_locked, &rx_locked);
 946      snprintf(temp_buffer, sizeof(temp_buffer), "LO_TX:%s|LO_RX:%s|",
 947               tx_locked ? "LOCKED" : "UNLOCKED",
 948               rx_locked ? "LOCKED" : "UNLOCKED");
 949      strcat(final_status, temp_buffer);
 950  
 951      // Temperature readings (8 variables)
 952      // You'll need to populate these temperature values from your sensors
 953      // For now, I'll show how to format them - replace with actual temperature readings
 954      Temperature_1 = ADS7830_Measure_SingleEnded(&hadc3, 0);
 955      Temperature_2 = ADS7830_Measure_SingleEnded(&hadc3, 1);
 956      Temperature_3 = ADS7830_Measure_SingleEnded(&hadc3, 2);
 957      Temperature_4 = ADS7830_Measure_SingleEnded(&hadc3, 3);
 958      Temperature_5 = ADS7830_Measure_SingleEnded(&hadc3, 4);
 959      Temperature_6 = ADS7830_Measure_SingleEnded(&hadc3, 5);
 960      Temperature_7 = ADS7830_Measure_SingleEnded(&hadc3, 6);
 961      Temperature_8 = ADS7830_Measure_SingleEnded(&hadc3, 7);
 962  
 963      // Format all 8 temperature variables
 964      snprintf(temp_buffer, sizeof(temp_buffer),
 965               "T1:%.1f|T2:%.1f|T3:%.1f|T4:%.1f|T5:%.1f|T6:%.1f|T7:%.1f|T8:%.1f|",
 966               Temperature_1, Temperature_2, Temperature_3, Temperature_4,
 967               Temperature_5, Temperature_6, Temperature_7, Temperature_8);
 968      strcat(final_status, temp_buffer);
 969  
 970      // RF Power Amplifier status (if enabled)
 971      if (PowerAmplifier) {
 972          float avg_current = 0.0f;
 973          for (int i = 0; i < 16; i++) {
 974              avg_current += Idq_reading[i];
 975          }
 976          avg_current /= 16.0f;
 977  
 978          snprintf(temp_buffer, sizeof(temp_buffer), "PA_AvgCurrent:%.2f|PA_Enabled:%d|",
 979                   avg_current, PowerAmplifier);
 980          strcat(final_status, temp_buffer);
 981      }
 982  
 983      // Radar operation status
 984      snprintf(temp_buffer, sizeof(temp_buffer), "BeamPos:%d|Azimuth:%d|ChirpCount:%d|",
 985               n, y, m);
 986      strcat(final_status, temp_buffer);
 987  
 988      // Copy to output buffer
 989      strncpy(status_buffer, final_status, buffer_size - 1);
 990      status_buffer[buffer_size - 1] = '\0';
 991  }
 992  
 993  /* ---------- UART printing helpers (Bug #8 FIXED: uncommented) ---------- */
 994  static void uart_print(const char *msg)
 995  {
 996      HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
 997  }
 998  
 999  static void uart_println(const char *msg)
1000  {
1001      HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
1002      const char crlf[] = "\r\n";
1003      HAL_UART_Transmit(&huart3, (uint8_t*)crlf, 2, HAL_MAX_DELAY);
1004  }
1005  
1006  /* ---------- Helper delay wrappers ---------- */
1007  static inline void delay_ms(uint32_t ms) { HAL_Delay(ms); }
1008  
1009  
1010  
1011  // This custom version of delay() ensures that the gps object
1012  // is being "fed".
1013  static void smartDelay(unsigned long ms)
1014  {
1015      uint32_t start = HAL_GetTick();
1016      uint8_t ch;
1017  
1018      do {
1019          // While there is new data available in UART (non-blocking)
1020          if (HAL_UART_Receive(&huart5, &ch, 1, 0) == HAL_OK) {
1021              gps.encode(ch);   // Pass received byte to TinyGPS++ equivalent parser
1022          }
1023      } while (HAL_GetTick() - start < ms);
1024  }
1025  
1026  // Small helper to enable DWT cycle counter for microdelay
1027  static void DWT_Init(void)
1028  {
1029      // Enable DWT CYCCNT
1030      CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
1031      DWT->CYCCNT = 0;
1032      DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
1033  }
1034  
1035  // Configure and program AD9523 via no-os driver
1036  static int configure_ad9523(void)
1037  {
1038      int32_t ret;
1039      struct ad9523_dev *dev = NULL;
1040  
1041      static struct ad9523_platform_data pdata;
1042      memset(&pdata, 0, sizeof(pdata));
1043  
1044      // VCXO + refs
1045      pdata.vcxo_freq = 100000000; // 100 MHz VCXO on OSC_IN
1046      pdata.refa_diff_rcv_en = 0;  // REFA 10 MHz single-ended
1047      pdata.refb_diff_rcv_en = 0;  // REFB 100 MHz single-ended
1048      pdata.osc_in_diff_en = 0;
1049  
1050      // PLL1: keep bypass disabled so VCXO can be used as reference cleanup if desired
1051      pdata.pll1_bypass_en = 0;
1052      pdata.refa_r_div = 1;
1053      pdata.refb_r_div = 1;
1054  
1055      // PLL2: 100 MHz PFD (R2=1), N = 36 to get VCO = 3.6 GHz
1056      pdata.pll2_ndiv_a_cnt = 0;
1057      pdata.pll2_ndiv_b_cnt = 9; // 4*9 + 0 = 36
1058      pdata.pll2_r2_div = 0;     // R2=1
1059      pdata.pll2_charge_pump_current_nA = 3500; // example
1060  
1061      // Loop filters: reasonable starting values from examples
1062      pdata.rpole2 = RPOLE2_900_OHM;
1063      pdata.rzero = RZERO_2000_OHM;
1064      pdata.cpole1 = CPOLE1_24_PF;
1065      pdata.rzero_bypass_en = 0;
1066  
1067      // Channels array (must allocate AD9523_NUM_CHAN entries)
1068      static struct ad9523_channel_spec channels[AD9523_NUM_CHAN];
1069      pdata.channels = channels;
1070      pdata.num_channels = AD9523_NUM_CHAN;
1071  
1072      // Initialize channels to disabled defaults
1073      for (int i=0; i<AD9523_NUM_CHAN; ++i) {
1074          channels[i].channel_num = i;
1075          channels[i].driver_mode = TRISTATE;
1076          channels[i].channel_divider = 0;
1077          channels[i].divider_phase = 0;
1078          channels[i].use_alt_clock_src = 0;
1079          channels[i].output_dis = 1;
1080      }
1081  
1082      // Map your required outputs (3.6 GHz PLL2)
1083      // OUT0 = ADF4382A_TX= 300 MHz LVDS ( /12 )
1084      channels[0].channel_divider = 12;
1085      channels[0].driver_mode = LVDS_7mA;
1086      channels[0].divider_phase = 0;
1087      channels[0].output_dis = 0;
1088  
1089      // OUT1 = ADF4382A_RX = 300 MHz LVDS (phase aligned with OUT0)
1090      channels[1].channel_divider = 12;
1091      channels[1].driver_mode = LVDS_7mA;
1092      channels[1].divider_phase = 0;
1093      channels[1].output_dis = 0;
1094  
1095      // OUT4 = ADC = 400 MHz LVDS ( /9 )
1096      channels[4].channel_divider = 9;
1097      channels[4].driver_mode = LVDS_7mA;
1098      channels[4].divider_phase = 0;
1099      channels[4].output_dis = 0;
1100  
1101      // OUT5 = FPGA_ADC = 400 MHz LVDS (phase aligned with OUT4)
1102      channels[5].channel_divider = 9;
1103      channels[5].driver_mode = LVDS_7mA;
1104      channels[5].divider_phase = 0;
1105      channels[5].output_dis = 0;
1106  
1107      // OUT6 = FPGA_SYSTEM_CLOCK = 100 MHz LVCMOS ( /36 )
1108      channels[6].channel_divider = 36;
1109      channels[6].driver_mode = CMOS_CONF1;
1110      channels[6].divider_phase = 0;
1111      channels[6].output_dis = 0;
1112  
1113      // OUT7 = FPGA_TEST_CLOCK = 20 MHz LVCMOS ( /180 )
1114      channels[7].channel_divider = 180;
1115      channels[7].driver_mode = CMOS_CONF1;
1116      channels[7].divider_phase = 0;
1117      channels[7].output_dis = 0;
1118  
1119      // OUT8 = SYNC_TX = 60 MHz LVDS ( /60 )
1120      channels[8].channel_divider = 60;
1121      channels[8].driver_mode = LVDS_4mA;
1122      channels[8].divider_phase = 0;
1123      channels[8].output_dis = 0;
1124  
1125      // OUT9 = SYNC_RX = 60 MHz LVDS (phase aligned with OUT8)
1126      channels[9].channel_divider = 60;
1127      channels[9].driver_mode = LVDS_4mA;
1128      channels[9].divider_phase = 0;
1129      channels[9].output_dis = 0;
1130  
1131      // OUT10 = DAC = 120 MHz LVCMOS ( /30 )
1132      channels[10].channel_divider = 30;
1133      channels[10].driver_mode = CMOS_CONF1;
1134      channels[10].divider_phase = 0;
1135      channels[10].output_dis = 0;
1136  
1137      // OUT11 = FPGA_DAC = 120 MHz LVCMOS (phase aligned with OUT10)
1138      channels[11].channel_divider = 30;
1139      channels[11].driver_mode = CMOS_CONF1;
1140      channels[11].divider_phase = 0;
1141      channels[11].output_dis = 0;
1142  
1143      // Fill ad9523 init param
1144      struct ad9523_init_param init_param;
1145      memset(&init_param, 0, sizeof(init_param));
1146  
1147      // SPI init (no_os type)
1148      init_param.spi_init.max_speed_hz = 10000000; // 10 MHz SPI
1149      init_param.spi_init.chip_select = 0;
1150      init_param.spi_init.mode = NO_OS_SPI_MODE_0;
1151      init_param.spi_init.platform_ops = &stm32_spi_ops;
1152      init_param.spi_init.extra = &hspi4; // pass HAL handle via extra
1153  
1154  
1155      init_param.pdata = &pdata;
1156  
1157      DIAG_SECTION("AD9523 CONFIGURE");
1158      DIAG("CLK", "VCXO=%lu Hz, PLL2 N=%d (4*%d+%d)=%d, R2=%d",
1159           (unsigned long)pdata.vcxo_freq,
1160           4 * pdata.pll2_ndiv_b_cnt + pdata.pll2_ndiv_a_cnt,
1161           pdata.pll2_ndiv_b_cnt, pdata.pll2_ndiv_a_cnt,
1162           4 * pdata.pll2_ndiv_b_cnt + pdata.pll2_ndiv_a_cnt,
1163           pdata.pll2_r2_div);
1164      DIAG("CLK", "Enabled channels: 0,1(/12=300M) 4,5(/9=400M) 6(/36=100M) 7(/180=20M) 8,9(/60=60M) 10,11(/30=120M)");
1165  
1166      // init ad9523 defaults (fills any missing pdata defaults)
1167      DIAG("CLK", "Calling ad9523_init() -- fills pdata defaults");
1168      ad9523_init(&init_param);
1169  
1170      /* [Bug #2 FIXED] Removed first ad9523_setup() call that was here.
1171       * It wrote to the chip while still in reset — writes were lost.
1172       * Only the post-reset setup call below is needed. */
1173  
1174      // Bring AD9523 out of reset
1175      DIAG("CLK", "Releasing AD9523 reset (AD9523_RESET_RELEASE)");
1176      AD9523_RESET_RELEASE();
1177      HAL_Delay(5);
1178      DIAG("CLK", "AD9523 reset released, waited 5 ms");
1179  
1180      // Select REFB (100MHz) using REF_SEL pin (true selects REFB here)
1181      DIAG("CLK", "Selecting REFB (100 MHz) via REF_SEL pin");
1182      AD9523_REF_SEL(true);
1183  
1184      // Call setup which uses no_os_spi to write registers, io_update, calibrate, sync
1185      DIAG("CLK", "Calling ad9523_setup() -- post-reset configuration");
1186      uint32_t setup_start = HAL_GetTick();
1187      ret = ad9523_setup(&dev, &init_param);
1188      DIAG("CLK", "ad9523_setup() returned %ld (took %lu ms)",
1189           (long)ret, (unsigned long)(HAL_GetTick() - setup_start));
1190      if (ret != 0) {
1191          // handle error: lock missing or SPI error
1192          DIAG_ERR("CLK", "ad9523_setup() FAILED (ret=%ld) -- lock missing or SPI error", (long)ret);
1193          return -1;
1194      }
1195  
1196      // Final check
1197      DIAG("CLK", "Checking AD9523 status (PLL lock, etc.)");
1198      ret = ad9523_status(dev);
1199      DIAG("CLK", "ad9523_status() returned %ld", (long)ret);
1200      if (ret != 0) {
1201          // log/handle
1202          DIAG_ERR("CLK", "AD9523 status check FAILED (ret=%ld)", (long)ret);
1203          return -1;
1204      }
1205  
1206      // optionally manual sync
1207      DIAG("CLK", "Triggering manual ad9523_sync()");
1208      ad9523_sync(dev);
1209      DIAG("CLK", "AD9523 configuration complete -- all outputs should be active");
1210  
1211      // keep device pointer globally if needed (dev)
1212      return 0;
1213  }
1214  
1215  ////////////////////////////////////////////////////////////////////////////////
1216  //////////////////////////////ADAR1000//////////////////////////////////////////
1217  ////////////////////////////////////////////////////////////////////////////////
1218  // Alternative approach using the beam sequence feature
1219  void setupBeamSequences(ADAR1000Manager& manager) {
1220      std::vector<ADAR1000Manager::BeamConfig> tx_sequence;
1221      std::vector<ADAR1000Manager::BeamConfig> rx_sequence;
1222  
1223      // Create beam configurations for each pattern
1224      // Matrix1 sequences (14 steps)
1225      for(int i = 0; i < 14; i++) {
1226          ADAR1000Manager::BeamConfig tx_config;
1227          ADAR1000Manager::BeamConfig rx_config;
1228  
1229          // Calculate angles or use your matrix directly
1230          // For now, we'll use a placeholder angle and set phases manually later
1231          tx_config.angle_degrees = 0; // This would be calculated from your matrix
1232          rx_config.angle_degrees = 0;
1233  
1234          // Copy phase settings from matrix1
1235          for(int ch = 0; ch < 16; ch++) {
1236              if(ch < 4) {
1237                  tx_config.phase_settings[ch] = matrix1[i][ch];
1238                  rx_config.phase_settings[ch] = matrix1[i][ch];
1239              }
1240          }
1241  
1242          tx_sequence.push_back(tx_config);
1243          rx_sequence.push_back(rx_config);
1244      }
1245  
1246      // You would similarly add the zero phase and matrix2 sequences
1247  
1248      // Note: The beam sequence feature in the manager currently uses calculated phases
1249      // You might need to modify the manager to support pre-calculated phase arrays
1250  }
1251  void setCustomBeamPattern(ADAR1000Manager& manager, uint8_t phase_pattern[16]) {
1252      // Set TX phases for all 4 ADAR1000 devices
1253      for(int dev = 0; dev < 4; dev++) {
1254          for(int ch = 0; ch < 4; ch++) {
1255              uint8_t phase = phase_pattern[dev * 4 + ch];
1256              manager.adarSetTxPhase(dev, ch + 1, phase, BROADCAST_OFF);
1257          }
1258      }
1259  
1260      // Set RX phases for all 4 ADAR1000 devices
1261      for(int dev = 0; dev < 4; dev++) {
1262          for(int ch = 0; ch < 4; ch++) {
1263              uint8_t phase = phase_pattern[dev * 4 + ch];
1264              manager.adarSetRxPhase(dev, ch + 1, phase, BROADCAST_OFF);
1265          }
1266      }
1267  }
1268  
1269  void initializeBeamMatricesWithSteeringAngles() {
1270      const float wavelength = 0.02857f; // 10.5 GHz wavelength in meters
1271      const float element_spacing = wavelength / 2.0f;
1272  
1273      // Calculate steering angles from phase differences
1274      float steering_angles[31];
1275      for(int i = 0; i < 31; i++) {
1276          float phase_diff_rad = phase_differences[i] * M_PI / 180.0f;
1277          steering_angles[i] = asin((phase_diff_rad * wavelength) / (2 * M_PI * element_spacing)) * 180.0f / M_PI;
1278      }
1279  
1280      // Matrix1: Positive angles (positions 1-15)
1281      for(int beam_pos = 0; beam_pos < 15; beam_pos++) {
1282          float angle = steering_angles[beam_pos];
1283  
1284          for(int element = 0; element < 16; element++) {
1285              // Calculate phase shift for linear array
1286              float phase_shift_rad = (2 * M_PI * element_spacing * element * sin(angle * M_PI / 180.0f)) / wavelength;
1287              float phase_degrees = phase_shift_rad * 180.0f / M_PI;
1288  
1289              // Wrap to 0-360 degrees
1290              while(phase_degrees < 0) phase_degrees += 360;
1291              while(phase_degrees >= 360) phase_degrees -= 360;
1292  
1293              matrix1[beam_pos][element] = (uint8_t)((phase_degrees / 360.0f) * 128);
1294          }
1295      }
1296  
1297      // Matrix2: Negative angles (positions 17-31)
1298      for(int beam_pos = 0; beam_pos < 15; beam_pos++) {
1299          float angle = steering_angles[beam_pos + 16];
1300  
1301          for(int element = 0; element < 16; element++) {
1302              float phase_shift_rad = (2 * M_PI * element_spacing * element * sin(angle * M_PI / 180.0f)) / wavelength;
1303              float phase_degrees = phase_shift_rad * 180.0f / M_PI;
1304  
1305              while(phase_degrees < 0) phase_degrees += 360;
1306              while(phase_degrees >= 360) phase_degrees -= 360;
1307  
1308              matrix2[beam_pos][element] = (uint8_t)((phase_degrees / 360.0f) * 128);
1309          }
1310      }
1311  }
1312  
1313  
1314  
1315  /* USER CODE END PFP */
1316  
1317  /* Private user code ---------------------------------------------------------*/
1318  /* USER CODE BEGIN 0 */
1319  
1320  /* USER CODE END 0 */
1321  
1322  /**
1323    * @brief  The application entry point.
1324    * @retval int
1325    */
1326  int main(void)
1327  {
1328  
1329    /* USER CODE BEGIN 1 */
1330  
1331    /* USER CODE END 1 */
1332  
1333    /* MPU Configuration--------------------------------------------------------*/
1334    MPU_Config();
1335  
1336    /* MCU Configuration--------------------------------------------------------*/
1337  
1338    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
1339    HAL_Init();
1340  
1341    /* USER CODE BEGIN Init */
1342  
1343    /* USER CODE END Init */
1344  
1345    /* Configure the system clock */
1346    SystemClock_Config();
1347  
1348    /* Configure the peripherals common clocks */
1349    PeriphCommonClock_Config();
1350  
1351    /* USER CODE BEGIN SysInit */
1352  
1353  
1354    /* USER CODE END SysInit */
1355  
1356    /* Initialize all configured peripherals */
1357    MX_GPIO_Init();
1358    MX_TIM1_Init();
1359    MX_TIM3_Init();  // B15 fix: init DELADJ PWM timer before LO manager uses it
1360    MX_I2C1_Init();
1361    MX_I2C2_Init();
1362    MX_I2C3_Init();
1363    MX_SPI1_Init();
1364    MX_SPI4_Init();
1365    MX_UART5_Init();
1366    MX_USART3_UART_Init();
1367    MX_USB_DEVICE_Init();
1368    MX_IWDG_Init();  /* GAP-3 FIX 2: start hardware watchdog (~4 s timeout) */
1369    /* USER CODE BEGIN 2 */
1370  
1371    HAL_TIM_Base_Start(&htim1);
1372  
1373    /* --- Enable DWT cycle counter for accurate microsecond delays --- */
1374    DWT_Init();
1375  
1376    DIAG_SECTION("SYSTEM INIT");
1377    DIAG("SYS", "DWT cycle counter initialized, TIM1 started");
1378    DIAG("SYS", "HAL tick at init start: %lu ms", (unsigned long)HAL_GetTick());
1379  
1380    //Wait for OCXO 3mn
1381    DIAG("CLK", "OCXO warmup starting -- waiting 180 s (3 min)");
1382    uint32_t ocxo_start = HAL_GetTick();
1383    /* [GAP-3 FIX 2] Cannot use HAL_Delay(180000) — IWDG would reset MCU.
1384     * Instead loop in 1-second steps, kicking the watchdog each iteration. */
1385    for (int ocxo_sec = 0; ocxo_sec < 180; ocxo_sec++) {
1386        HAL_IWDG_Refresh(&hiwdg);
1387        HAL_Delay(1000);
1388    }
1389    DIAG_ELAPSED("CLK", "OCXO warmup", ocxo_start);
1390  
1391    DIAG_SECTION("AD9523 POWER SEQUENCING");
1392    DIAG("PWR", "Asserting AD9523 reset (pin LOW)");
1393    HAL_GPIO_WritePin(AD9523_RESET_GPIO_Port,AD9523_RESET_Pin,GPIO_PIN_RESET);
1394  
1395    //Power sequencing AD9523
1396    DIAG("PWR", "Enabling 1.8V clock rail");
1397    HAL_GPIO_WritePin(EN_P_1V8_CLOCK_GPIO_Port,EN_P_1V8_CLOCK_Pin,GPIO_PIN_SET);
1398    HAL_Delay(100);
1399    DIAG("PWR", "Enabling 3.3V clock rail");
1400    HAL_GPIO_WritePin(EN_P_3V3_CLOCK_GPIO_Port,EN_P_3V3_CLOCK_Pin,GPIO_PIN_SET);
1401    HAL_Delay(100);
1402    DIAG("PWR", "Releasing AD9523 reset (pin HIGH)");
1403    HAL_GPIO_WritePin(AD9523_RESET_GPIO_Port,AD9523_RESET_Pin,GPIO_PIN_SET);
1404    HAL_Delay(100);
1405    DIAG("PWR", "AD9523 power sequencing complete -- all rails up, reset released");
1406  
1407    //Set planned Clocks on AD9523
1408    /*
1409    o Channel 0 = 300MHz LVDS (ADF4382 TX)
1410    o Channel 1 = 300MHz LVDS (ADF4382 RX) (Phase aligned with Channel 0)
1411    o Channel 4 = 400MHz LVDS (ADC)
1412    o Channel 5 = 400MHz LVDS (FPGA_ADC)(Phase aligned with Channel 4)
1413    o Channel 6 = 100MHz LVCMOS (FPGA system clock)
1414    o Channel 7 = 20MHz LVCMOS (FPGA test)
1415    o Channel 8 = 60MHz LVDS (ADF4382 TX sync)
1416    o Channel 9 = 60MHz LVDS (ADF4382 RX sync)(Phase aligned with Channel 8)
1417    o Channel 10 = 120MHz LVCMOS
1418    o Channel 11 = 120MHz LVCMOS (Phase aligned with Channel 10)
1419     */
1420  
1421  
1422    // Ensure stm32_spi.c and stm32_delay.c are compiled and linked
1423  
1424    DIAG("CLK", "Calling configure_ad9523()...");
1425    uint32_t ad9523_cfg_start = HAL_GetTick();
1426    if (configure_ad9523() != 0) {
1427        // configuration error - handle as needed
1428        DIAG_ERR("CLK", "configure_ad9523() FAILED -- entering infinite halt loop");
1429        while (1) { HAL_Delay(1000); }
1430    }
1431    DIAG_ELAPSED("CLK", "configure_ad9523()", ad9523_cfg_start);
1432    DIAG("CLK", "AD9523 configured successfully");
1433  
1434    //Power sequencing FPGA
1435    DIAG_SECTION("FPGA POWER SEQUENCING");
1436    DIAG("PWR", "Enabling 1.0V FPGA rail");
1437    HAL_GPIO_WritePin(EN_P_1V0_FPGA_GPIO_Port,EN_P_1V0_FPGA_Pin,GPIO_PIN_SET);
1438    HAL_Delay(100);
1439    DIAG("PWR", "Enabling 1.8V FPGA rail");
1440    HAL_GPIO_WritePin(EN_P_1V8_FPGA_GPIO_Port,EN_P_1V8_FPGA_Pin,GPIO_PIN_SET);
1441    HAL_Delay(100);
1442    DIAG("PWR", "Enabling 3.3V FPGA rail");
1443    HAL_GPIO_WritePin(EN_P_3V3_FPGA_GPIO_Port,EN_P_3V3_FPGA_Pin,GPIO_PIN_SET);
1444    HAL_Delay(100);
1445    DIAG("PWR", "FPGA power sequencing complete -- 1.0V -> 1.8V -> 3.3V");
1446  
1447  
1448  // Initialize module IMU
1449    DIAG_SECTION("IMU INIT (GY-85)");
1450    DIAG("IMU", "Initializing GY-85 IMU...");
1451    if (!GY85_Init()) {
1452        DIAG_ERR("IMU", "GY85_Init() FAILED -- calling Error_Handler()");
1453        Error_Handler();
1454    }
1455    DIAG("IMU", "GY-85 initialized OK, running 10 calibration samples");
1456    for(int i=0; i<10;i++){
1457    if (!GY85_Update(&imu)) {
1458        Error_Handler();
1459    }
1460  
1461    ax = imu.ax;
1462    ay = imu.ay;
1463    az = imu.az;
1464    gx = -imu.gx;
1465    gy = -imu.gy;
1466    gz = imu.gz;
1467    mx = imu.mx;
1468    my = imu.my;
1469    mz = imu.mz;
1470  
1471    ax *= 6.10351e-5;   //2.0 / 32768.0;
1472    ay *= 6.10351e-5;
1473    az *= 6.10351e-5;
1474  
1475    ax -= abias[0];   // Convert to g's, remove accelerometer biases
1476    ay -= abias[1];
1477    az -= abias[2];
1478  
1479    gx *= 0.0152588f;   //500.0 / 32768.0;
1480    gy *= 0.0152588f;
1481    gz *= 0.0152588f;
1482  
1483    gx -= gbias[0];   // Convert to degrees per seconds, remove gyro biases
1484    gy -= gbias[1];
1485    gz -= gbias[2];
1486  
1487    mx *= 6.10351e-5;   //2.0 / 32768.0;
1488    my *= 6.10351e-5;
1489    mz *= 6.10351e-5;
1490  
1491    mxc = M11*(mx-mbias[0]) + M12*(my-mbias[1]) +M13*(mz-mbias[2]);
1492    myc = M21*(mx-mbias[0]) + M22*(my-mbias[1]) +M23*(mz-mbias[2]);
1493    mzc = M31*(mx-mbias[0]) + M32*(my-mbias[1]) +M33*(mz-mbias[2]);
1494  
1495    mx = mxc;
1496    my = myc;
1497    mz = mzc;
1498  
1499    float norm = sqrt((mx*mx) + (my*my) + (mz*mz));
1500    mx /=norm;
1501    my /=norm;
1502    mz /=norm;
1503  
1504    /***************************************************************/
1505    /*********************IMU Complementary Filter******************/
1506    /***************************************************************/
1507      RxAcc = ax;
1508      RyAcc = ay;
1509      RzAcc = az;
1510  
1511      Rate_Ayz_1 = gx;
1512      Rate_Axz_1 = gy;
1513      Rate_Axy_1 = gz;
1514  
1515      Rate_Ayz_1 = Rate_Ayz_1*0.01745;//Convertion from °/s to Radians/s
1516      Rate_Axz_1 = Rate_Axz_1*0.01745;
1517      Rate_Axy_1 = Rate_Axy_1*0.01745;
1518  
1519      /*Combining Accelerometer & Gyroscope Data*/
1520      Axz_0 = atan2(RxEst_0,RzEst_0);
1521      Ayz_0 = atan2(RyEst_0,RzEst_0);
1522      Axy_0 = atan2(RxEst_0,RyEst_0);
1523  
1524      now_timeperiod = micros();
1525  
1526      Time_Period = now_timeperiod - lasttime_timeperiod;
1527  
1528      Axz_1= Axz_0 + Rate_Axz_1*Time_Period*0.000001;
1529      Ayz_1= Ayz_0 + Rate_Ayz_1*Time_Period*0.000001;
1530      Axy_1= Axy_0 + Rate_Axy_1*Time_Period*0.000001;
1531  
1532      lasttime_timeperiod = now_timeperiod;
1533  
1534      RxGyro = sin(Axz_1)/(sqrt(1.0 + cos(Axz_1)*cos(Axz_1) * tan(Ayz_1)*tan(Ayz_1)));
1535      RyGyro = sin(Ayz_1)/(sqrt(1.0 + cos(Ayz_1)*cos(Ayz_1) * tan(Axz_1)*tan(Axz_1)));
1536      if(RzEst_0 >= 0){
1537        RzGyro = 1.0*sqrt(1 - RxGyro*RxGyro - RyGyro*RyGyro);
1538      }
1539      else {
1540        RzGyro = -1*sqrt(1 - RxGyro*RxGyro - RyGyro*RyGyro);
1541      }
1542  
1543      RxEst_1 = RxAcc*0.5 + RxGyro*0.5 ;// Weight of Gyro. over Acc.
1544      RyEst_1 = RyAcc*0.5 + RyGyro*0.5 ;
1545      RzEst_1 = RzAcc*0.5 + RzGyro*0.5 ;
1546  
1547      R_Est = sqrt(RxEst_1*RxEst_1+RyEst_1*RyEst_1+RzEst_1*RzEst_1);
1548  
1549      Pitch_Sensor = atan2(RxEst_1,sqrt(RyEst_1*RyEst_1)+(RzEst_1*RzEst_1))*180/PI;
1550      Roll_Sensor = atan2(RyEst_1,sqrt(RxEst_1*RxEst_1)+(RzEst_1*RzEst_1))*180/PI;
1551  
1552      float magRawX = mx*cos(Pitch_Sensor*PI/180.0f)  - mz*sin(Pitch_Sensor*PI/180.0f);
1553  	float magRawY = mx*sin(Roll_Sensor*PI/180.0f)*sin(Pitch_Sensor*PI/180.0f) + my*cos(Roll_Sensor*PI/180.0f)- mz*sin(Roll_Sensor*PI/180.0f)*cos(Pitch_Sensor*PI/180.0f);
1554      Yaw_Sensor = (180*atan2(magRawY,magRawX)/PI) - Mag_Declination;
1555  
1556      if(Yaw_Sensor<0)Yaw_Sensor+=360;
1557      RxEst_0 = RxEst_1;
1558      RyEst_0 = RyEst_1;
1559      RzEst_0 = RzEst_1;
1560  
1561      HAL_Delay(300);
1562  
1563    }
1564  
1565      ///////////////////////////////////////////////////////////////////////////////////
1566      ///////////////////////////////////BAROMETER BMP180////////////////////////////////
1567      ///////////////////////////////////////////////////////////////////////////////////
1568      DIAG_SECTION("BAROMETER INIT (BMP180)");
1569      DIAG("IMU", "Reading 5 barometer samples for altitude baseline");
1570    	for(int i = 0; i<5 ; i++){
1571  		float BMP_Perssure = myBMP.getPressure();
1572  		RADAR_Altitude = 44330*(1-(pow((BMP_Perssure/101325),(1/5.255))));
1573  		HAL_Delay(100);
1574    	}
1575      DIAG("IMU", "Barometer init complete, RADAR_Altitude baseline set");
1576  
1577      ///////////////////////////////////////////////////////////////////////////////////
1578      ///////////////////////////////////////ADF4382/////////////////////////////////////
1579      ///////////////////////////////////////////////////////////////////////////////////
1580      DIAG_SECTION("ADF4382A LO INIT");
1581      printf("Starting ADF4382A Radar LO System...\n");
1582      printf("Using SPI4 with TIMED SYNCHRONIZATION (60 MHz clocks)\n");
1583  
1584      // Initialize LO manager with TIMED synchronization
1585      DIAG("LO", "Calling ADF4382A_Manager_Init(sync=SYNC_METHOD_TIMED)");
1586      uint32_t lo_init_start = HAL_GetTick();
1587      int ret = ADF4382A_Manager_Init(&lo_manager, SYNC_METHOD_TIMED);
1588      DIAG("LO", "ADF4382A_Manager_Init returned %d (took %lu ms)",
1589           ret, (unsigned long)(HAL_GetTick() - lo_init_start));
1590  
1591      /* [Bug #4 FIXED] Check init return code BEFORE calling phase shift.
1592       * Previously SetPhaseShift/Strobe were called before this check. */
1593      if (ret != ADF4382A_MANAGER_OK) {
1594          printf("LO Manager initialization failed: %d\n", ret);
1595          DIAG_ERR("LO", "Manager init FAILED (ret=%d) -- calling Error_Handler()", ret);
1596          Error_Handler();
1597      }
1598  
1599      // Set phase shift (e.g., 500 ps for TX, 500 ps for RX)
1600      int ps_ret = ADF4382A_SetPhaseShift(&lo_manager, 500, 500);
1601      DIAG("LO", "ADF4382A_SetPhaseShift(500, 500) returned %d", ps_ret);
1602  
1603      // Strobe to apply phase shifts
1604      int strobe_tx_ret = ADF4382A_StrobePhaseShift(&lo_manager, 0); // TX device
1605      int strobe_rx_ret = ADF4382A_StrobePhaseShift(&lo_manager, 1); // RX device
1606      DIAG("LO", "StrobePhaseShift TX returned %d, RX returned %d", strobe_tx_ret, strobe_rx_ret);
1607  
1608      // Check initial lock status
1609      bool tx_locked, rx_locked;
1610      DIAG("LO", "Checking initial lock status...");
1611      ret = ADF4382A_CheckLockStatus(&lo_manager, &tx_locked, &rx_locked);
1612      if (ret == ADF4382A_MANAGER_OK) {
1613          printf("Initial Lock Status - TX: %s, RX: %s\n",
1614                 tx_locked ? "LOCKED" : "UNLOCKED",
1615                 rx_locked ? "LOCKED" : "UNLOCKED");
1616          DIAG("LO", "Initial lock: TX=%s RX=%s", tx_locked ? "LOCKED" : "UNLOCKED", rx_locked ? "LOCKED" : "UNLOCKED");
1617      } else {
1618          DIAG_ERR("LO", "CheckLockStatus returned %d", ret);
1619      }
1620      // Wait for both LOs to lock
1621          DIAG("LO", "Entering lock-wait loop (max 10 s = 100 x 100 ms)");
1622          uint32_t lock_wait_start = HAL_GetTick();
1623          uint32_t lock_timeout = 0;
1624          while (!(tx_locked && rx_locked) && lock_timeout < 100) {
1625              HAL_Delay(100);
1626              ADF4382A_CheckLockStatus(&lo_manager, &tx_locked, &rx_locked);
1627              lock_timeout++;
1628  
1629              if (lock_timeout % 10 == 0) {
1630                  printf("Waiting for LO lock... TX: %s, RX: %s\n",
1631                         tx_locked ? "LOCKED" : "UNLOCKED",
1632                         rx_locked ? "LOCKED" : "UNLOCKED");
1633                  DIAG("LO", "Lock poll #%lu: TX=%s RX=%s",
1634                       (unsigned long)lock_timeout,
1635                       tx_locked ? "LOCKED" : "UNLOCKED",
1636                       rx_locked ? "LOCKED" : "UNLOCKED");
1637              }
1638          }
1639          DIAG_ELAPSED("LO", "Lock wait loop", lock_wait_start);
1640  
1641          if (tx_locked && rx_locked) {
1642              printf("Both LOs locked successfully!\n");
1643              printf("Synchronization ready - 60 MHz clocks on SYNCP/SYNCN pins\n");
1644              DIAG("LO", "Both LOs LOCKED after %lu iterations", (unsigned long)lock_timeout);
1645              // - 60 MHz phase-aligned clocks on SYNCP/SYNCN pins
1646              // - SYNC pin connected for triggering
1647  
1648              // When ready to synchronize:
1649              DIAG("LO", "Calling TriggerTimedSync to pulse sw_sync on both PLLs");
1650              ADF4382A_TriggerTimedSync(&lo_manager);
1651              // At this point, the SYNC pin can be toggled to trigger synchronization
1652          } else {
1653              printf("LO lock timeout! TX: %s, RX: %s\n",
1654                     tx_locked ? "LOCKED" : "UNLOCKED",
1655                     rx_locked ? "LOCKED" : "UNLOCKED");
1656              DIAG_ERR("LO", "Lock TIMEOUT after %lu iterations! TX=%s RX=%s",
1657                       (unsigned long)lock_timeout,
1658                       tx_locked ? "LOCKED" : "UNLOCKED",
1659                       rx_locked ? "LOCKED" : "UNLOCKED");
1660          }
1661  
1662    // check if there is a lock via direct GPIO (independent of register read above)
1663    DIAG("LO", "Direct GPIO lock detect pins:");
1664    DIAG_GPIO("LO", "ADF4382_TX_LKDET", ADF4382_TX_LKDET_GPIO_Port, ADF4382_TX_LKDET_Pin);
1665    DIAG_GPIO("LO", "ADF4382_RX_LKDET", ADF4382_RX_LKDET_GPIO_Port, ADF4382_RX_LKDET_Pin);
1666    if(HAL_GPIO_ReadPin (ADF4382_TX_LKDET_GPIO_Port, ADF4382_TX_LKDET_Pin))
1667    {
1668        // Set The LED_1 ON!
1669        HAL_GPIO_WritePin(LED_1_GPIO_Port, LED_1_Pin, GPIO_PIN_SET);
1670        DIAG("LO", "TX lock detected via GPIO -- LED_1 ON");
1671    }
1672    else
1673    {
1674        // Else .. Turn LED_1 OFF!
1675        HAL_GPIO_WritePin(LED_1_GPIO_Port, LED_1_Pin, GPIO_PIN_RESET);
1676        DIAG_WARN("LO", "TX NOT locked via GPIO -- LED_1 OFF");
1677    }
1678  
1679    if(HAL_GPIO_ReadPin (ADF4382_RX_LKDET_GPIO_Port, ADF4382_RX_LKDET_Pin))
1680    {
1681        // Set The LED_2 ON!
1682        HAL_GPIO_WritePin(LED_2_GPIO_Port, LED_2_Pin, GPIO_PIN_SET);
1683        DIAG("LO", "RX lock detected via GPIO -- LED_2 ON");
1684    }
1685    else
1686    {
1687        // Else .. Turn LED_2 OFF!
1688        HAL_GPIO_WritePin(LED_2_GPIO_Port, LED_2_Pin, GPIO_PIN_RESET);
1689        DIAG_WARN("LO", "RX NOT locked via GPIO -- LED_2 OFF");
1690    }
1691  
1692  
1693    //////////////////////////////////////////////////////////////////////////////////////
1694    /////////////////////////////////////ADAR1000/////////////////////////////////////////
1695    //////////////////////////////////////////////////////////////////////////////////////
1696  
1697    //Power sequencing ADAR1000
1698    DIAG_SECTION("ADAR1000 POWER SEQUENCING");
1699  
1700    //Tell FPGA to turn off TX RF signal by disabling Mixers
1701    DIAG("BF", "Disabling TX mixers (GPIOD pin 11 LOW)");
1702    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_11, GPIO_PIN_RESET);
1703  
1704    DIAG("PWR", "Enabling 3.3V ADAR12 + ADAR34 rails");
1705    HAL_GPIO_WritePin(EN_P_3V3_ADAR12_GPIO_Port,EN_P_3V3_ADAR12_Pin,GPIO_PIN_SET);
1706    HAL_GPIO_WritePin(EN_P_3V3_ADAR34_GPIO_Port,EN_P_3V3_ADAR34_Pin,GPIO_PIN_SET);
1707    HAL_Delay(500);
1708    DIAG("PWR", "Enabling 5.0V ADAR rail");
1709    HAL_GPIO_WritePin(EN_P_5V0_ADAR_GPIO_Port,EN_P_5V0_ADAR_Pin,GPIO_PIN_SET);
1710    HAL_Delay(500);
1711    DIAG("PWR", "ADAR1000 power sequencing complete");
1712  
1713    // System startup message
1714        uint8_t startup_msg[] = "Starting Phased Array RADAR System...\r\n";
1715        HAL_UART_Transmit(&huart3, startup_msg, sizeof(startup_msg)-1, 1000);
1716  
1717        DIAG("BF", "Calling systemPowerUpSequence()");
1718        // Power up sequence
1719        systemPowerUpSequence();
1720  
1721        DIAG("BF", "Calling initializeBeamMatrices()");
1722        // Initialize beam matrices
1723        initializeBeamMatrices();
1724  
1725        // Print system status
1726        printSystemStatus();
1727        DIAG("SYS", "System init complete -- entering main loop");
1728  
1729    	//////////////////////////////////////////////////////////////////////////////////////
1730      //////////////////////////////////////////GPS/////////////////////////////////////////
1731      //////////////////////////////////////////////////////////////////////////////////////
1732    for(int i=0; i<10;i++){
1733    smartDelay(1000);
1734    RADAR_Longitude = gps.location.lng();
1735    RADAR_Latitude = gps.location.lat();
1736    }
1737  
1738    //move Stepper to position 1 = 0°
1739    HAL_GPIO_WritePin(STEPPER_CW_P_GPIO_Port, STEPPER_CW_P_Pin, GPIO_PIN_RESET);//Set stepper motor spinning direction to CCW
1740    //Point Stepper to North
1741    for(int i= 0;i<(int)(Yaw_Sensor*Stepper_steps/360);i++){
1742  	  HAL_GPIO_WritePin(STEPPER_CLK_P_GPIO_Port, STEPPER_CLK_P_Pin, GPIO_PIN_SET);
1743  	  delay_us(500);
1744  	  HAL_GPIO_WritePin(STEPPER_CLK_P_GPIO_Port, STEPPER_CLK_P_Pin, GPIO_PIN_RESET);
1745  	  delay_us(500);
1746    }
1747  
1748    /***************************************************************/
1749    /**********wait for GUI start flag and Send Lat/Long/alt********/
1750    /***************************************************************/
1751  
1752    GPS_Data_t gps_data;
1753    // Binary packet structure:
1754    // [Header 4 bytes][Latitude 8 bytes][Longitude 8 bytes][Altitude 4 bytes][Pitch 4 bytes][CRC 2 bytes]
1755    gps_data = {RADAR_Latitude, RADAR_Longitude, RADAR_Altitude, Pitch_Sensor, HAL_GetTick()};
1756    if (!GPS_SendBinaryToGUI(&gps_data)) {
1757        const uint8_t gps_send_error[] = "GPS binary send failed\r\n";
1758        HAL_UART_Transmit(&huart3, (uint8_t*)gps_send_error, sizeof(gps_send_error) - 1, 1000);
1759    }
1760  
1761    // Check if start flag was received and settings are ready
1762    do{
1763  	  if (usbHandler.isStartFlagReceived() &&
1764  		  usbHandler.getState() == USBHandler::USBState::READY_FOR_DATA) {
1765  
1766  		  const RadarSettings& settings = usbHandler.getSettings();
1767  
1768  		  // Use the settings to configure your radar system
1769  		  /*
1770  			  settings.getSystemFrequency();
1771  			  settings.getChirpDuration1();
1772  			  settings.getChirpDuration2();
1773  			  settings.getChirpsPerPosition();
1774  			  settings.getFreqMin();
1775  			  settings.getFreqMax();
1776  			  settings.getPRF1();
1777  			  settings.getPRF2();
1778  			  settings.getMaxDistance();
1779  			  */
1780  
1781  
1782                }
1783    }while(!usbHandler.isStartFlagReceived());
1784  
1785    /***************************************************************/
1786    /************RF Power Amplifier Powering up sequence************/
1787    /***************************************************************/
1788    if(PowerAmplifier){
1789  	  DIAG_SECTION("PA: RF Power Amplifier power-up sequence");
1790  	  /* Initialize DACs */
1791  	  /* DAC1: Address 0b1001000 = 0x48 */
1792  	  DIAG("PA", "Initializing DAC1 (I2C1, addr=0x48, 8-bit)");
1793  	  if (!DAC5578_Init(&hdac1, &hi2c1, 0x48, 8,
1794  			  DAC_1_VG_LDAC_GPIO_Port, DAC_1_VG_LDAC_Pin,
1795  			  DAC_1_VG_CLR_GPIO_Port, DAC_1_VG_CLR_Pin)) {
1796  		  DIAG_ERR("PA", "DAC1 init FAILED -- calling Error_Handler()");
1797  		  Error_Handler();
1798  	  }
1799  	  DIAG("PA", "DAC1 init OK");
1800  
1801  	  /* DAC2: Address 0b1001001 = 0x49 */
1802  	  DIAG("PA", "Initializing DAC2 (I2C1, addr=0x49, 8-bit)");
1803  	  if (!DAC5578_Init(&hdac2, &hi2c1, 0x49, 8,
1804  			  DAC_2_VG_LDAC_GPIO_Port, DAC_2_VG_LDAC_Pin,
1805  			  DAC_2_VG_CLR_GPIO_Port, DAC_2_VG_CLR_Pin)) {
1806  		  DIAG_ERR("PA", "DAC2 init FAILED -- calling Error_Handler()");
1807  		  Error_Handler();
1808  	  }
1809  	  DIAG("PA", "DAC2 init OK");
1810  
1811  	  /* Configure clear code behavior */
1812  	  DIAG("PA", "Setting clear code to ZERO on both DACs");
1813  	  DAC5578_SetClearCode(&hdac1, DAC5578_CLR_CODE_ZERO); // Clear to 0V on CLR pulse
1814  	  DAC5578_SetClearCode(&hdac2, DAC5578_CLR_CODE_ZERO); // Clear to 0V on CLR pulse
1815  
1816  	  /* Configure LDAC so all channels update simultaneously on hardware LDAC */
1817  	  DIAG("PA", "Setting LDAC mask=0xFF on both DACs (all channels respond)");
1818  	  DAC5578_SetupLDAC(&hdac1, 0xFF); // All channels respond to LDAC
1819  	  DAC5578_SetupLDAC(&hdac2, 0xFF); // All channels respond to LDAC
1820  
1821  	  //set Vg [1-8] to -3.98V -> input opamp = 1.63058V->126(8bits)
1822  	  DIAG("PA", "Writing initial DAC_val=%d to DAC1 channels 0-7", DAC_val);
1823  	  for(int channel = 0; channel < 8; channel++){
1824  		  DAC5578_WriteAndUpdateChannelValue(&hdac1, channel, DAC_val);
1825  	  }
1826  
1827  	  //set Vg [9-16] to -3.98V -> input opamp = 1.63058V->126(8bits)
1828  	  DIAG("PA", "Writing initial DAC_val=%d to DAC2 channels 0-7", DAC_val);
1829  	  for(int channel = 0; channel < 8; channel++){
1830  		  DAC5578_WriteAndUpdateChannelValue(&hdac2, channel, DAC_val);
1831  	  }
1832  
1833  	  /* Optional: Use hardware LDAC for simultaneous update of all channels */
1834  	  DIAG("PA", "Pulsing LDAC on both DACs for simultaneous update");
1835  	  HAL_GPIO_WritePin(DAC_1_VG_LDAC_GPIO_Port, DAC_1_VG_LDAC_Pin, GPIO_PIN_RESET);
1836  	  HAL_GPIO_WritePin(DAC_2_VG_LDAC_GPIO_Port, DAC_2_VG_LDAC_Pin, GPIO_PIN_RESET);
1837  	  HAL_Delay(1);
1838  	  HAL_GPIO_WritePin(DAC_1_VG_LDAC_GPIO_Port, DAC_1_VG_LDAC_Pin, GPIO_PIN_SET);
1839  	  HAL_GPIO_WritePin(DAC_2_VG_LDAC_GPIO_Port, DAC_2_VG_LDAC_Pin, GPIO_PIN_SET);
1840  
1841  	  //Enable RF Power Amplifier VDD = 22V
1842  	  DIAG("PA", "Enabling RFPA VDD=22V (EN_DIS_RFPA_VDD HIGH)");
1843  	  HAL_GPIO_WritePin(EN_DIS_RFPA_VDD_GPIO_Port, EN_DIS_RFPA_VDD_Pin, GPIO_PIN_SET);
1844  
1845  	  /* Initialize ADCs with correct addresses */
1846  	  /* ADC1: Address 0x48, Single-Ended mode, Internal Ref ON + ADC ON */
1847  	  DIAG("PA", "Initializing ADC1 (I2C2, addr=0x48, single-ended, ref+adc ON)");
1848  	  if (!ADS7830_Init(&hadc1, &hi2c2, 0x48,
1849  						ADS7830_SDMODE_SINGLE, ADS7830_PDIRON_ADON)) {
1850  		  DIAG_ERR("PA", "ADC1 init FAILED -- calling Error_Handler()");
1851  		  Error_Handler();
1852  	  }
1853  	  DIAG("PA", "ADC1 init OK");
1854  
1855  	  /* ADC2: Address 0x4A, Single-Ended mode, Internal Ref ON + ADC ON */
1856  	  DIAG("PA", "Initializing ADC2 (I2C2, addr=0x4A, single-ended, ref+adc ON)");
1857  	  if (!ADS7830_Init(&hadc2, &hi2c2, 0x4A,
1858  						ADS7830_SDMODE_SINGLE, ADS7830_PDIRON_ADON)) {
1859  		  DIAG_ERR("PA", "ADC2 init FAILED -- calling Error_Handler()");
1860  		  Error_Handler();
1861  	  }
1862  	  DIAG("PA", "ADC2 init OK");
1863  
1864  	  /* Read all 8 channels from ADC1 and calculate Idq */
1865  	  DIAG("PA", "Reading initial Idq from ADC1 channels 0-7");
1866  	  for (uint8_t channel = 0; channel < 8; channel++) {
1867  		  adc1_readings[channel] = ADS7830_Measure_SingleEnded(&hadc1, channel);
1868  		  Idq_reading[channel]= (3.3/255)*adc1_readings[channel]/(50*0.005);//Idq=Vadc/(GxRshunt)//G_INA241A3=50;Rshunt=5mOhms
1869  		  DIAG("PA", "  ADC1 ch%d: raw=%d Idq=%.3fA", channel, adc1_readings[channel], Idq_reading[channel]);
1870  	  }
1871  
1872  	  /* Read all 8 channels from ADC2 and calculate Idq*/
1873  	  DIAG("PA", "Reading initial Idq from ADC2 channels 0-7");
1874  	  for (uint8_t channel = 0; channel < 8; channel++) {
1875  		  adc2_readings[channel] = ADS7830_Measure_SingleEnded(&hadc2, channel);
1876  		  Idq_reading[channel+8]= (3.3/255)*adc2_readings[channel]/(50*0.005);//Idq=Vadc/(GxRshunt)//G_INA241A3=50;Rshunt=5mOhms
1877  		  DIAG("PA", "  ADC2 ch%d: raw=%d Idq=%.3fA", channel, adc2_readings[channel], Idq_reading[channel+8]);
1878  	  }
1879  
1880  	  DIAG("PA", "Starting Idq calibration loop for DAC1 channels 0-7 (target=1.680A)");
1881  	  for (uint8_t channel = 0; channel < 8; channel++){
1882  	      uint8_t safety_counter = 0;
1883  	      DAC_val = 126; // Reset for each channel
1884  
1885  	      do {
1886  	          if (safety_counter++ > 50) { // Prevent infinite loop
1887  	              DIAG_WARN("PA", "  DAC1 ch%d: safety limit reached (50 iterations), DAC_val=%d Idq=%.3fA",
1888  	                        channel, DAC_val, Idq_reading[channel]);
1889  	              break;
1890  	          }
1891  	          DAC_val = DAC_val - 4;
1892  	          DAC5578_WriteAndUpdateChannelValue(&hdac1, channel, DAC_val);
1893  	          adc1_readings[channel] = ADS7830_Measure_SingleEnded(&hadc1, channel);
1894  	          Idq_reading[channel] = (3.3/255) * adc1_readings[channel] / (50 * 0.005);
1895  	      } while (DAC_val > 38 && abs(Idq_reading[channel] - 1.680) > 0.2); // B12 fix: loop while FAR from target
1896  	      DIAG("PA", "  DAC1 ch%d calibrated: DAC_val=%d Idq=%.3fA iters=%d",
1897  	           channel, DAC_val, Idq_reading[channel], safety_counter);
1898  	  }
1899  
1900  	  DIAG("PA", "Starting Idq calibration loop for DAC2 channels 0-7 (target=1.680A)");
1901  	  for (uint8_t channel = 0; channel < 8; channel++){
1902  	      uint8_t safety_counter = 0;
1903  	      DAC_val = 126; // Reset for each channel
1904  
1905  	      do {
1906  	          if (safety_counter++ > 50) { // Prevent infinite loop
1907  	              DIAG_WARN("PA", "  DAC2 ch%d: safety limit reached (50 iterations), DAC_val=%d Idq=%.3fA",
1908  	                        channel, DAC_val, Idq_reading[channel+8]);
1909  	              break;
1910  	          }
1911  	          DAC_val = DAC_val - 4;
1912  	          DAC5578_WriteAndUpdateChannelValue(&hdac2, channel, DAC_val);
1913  	          adc2_readings[channel] = ADS7830_Measure_SingleEnded(&hadc2, channel); // B13 fix: was adc1_readings
1914  	          Idq_reading[channel+8] = (3.3/255) * adc2_readings[channel] / (50 * 0.005);
1915  	      } while (DAC_val > 38 && abs(Idq_reading[channel+8] - 1.680) > 0.2); // B12 fix: loop while FAR from target
1916  	      DIAG("PA", "  DAC2 ch%d calibrated: DAC_val=%d Idq=%.3fA iters=%d",
1917  	           channel, DAC_val, Idq_reading[channel+8], safety_counter);
1918  	  }
1919  	  DIAG("PA", "PA IDQ calibration sequence COMPLETE");
1920    }
1921  
1922    //RESET FPGA
1923    DIAG("FPGA", "Resetting FPGA (GPIOD pin 12: LOW -> 10ms -> HIGH)");
1924    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET);
1925    HAL_Delay(10);
1926    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET);
1927    DIAG("FPGA", "FPGA reset complete");
1928  
1929  
1930  
1931    //Tell FPGA to apply TX RF by enabling Mixers
1932    DIAG("FPGA", "Enabling TX mixers (GPIOD pin 11 HIGH)");
1933    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_11, GPIO_PIN_SET);
1934  
1935    /* T°C sensor TMP37 ADC3: Address 0x49, Single-Ended mode, Internal Ref ON + ADC ON */
1936    DIAG("SYS", "Initializing temperature sensor ADC3 (I2C2, addr=0x49, TMP37)");
1937    if (!ADS7830_Init(&hadc3, &hi2c2, 0x49,
1938  					ADS7830_SDMODE_SINGLE, ADS7830_PDIRON_ADON)) {
1939  	  DIAG_ERR("SYS", "Temperature sensor ADC3 init FAILED -- calling Error_Handler()");
1940  	  Error_Handler();
1941    }
1942    DIAG("SYS", "Temperature sensor ADC3 init OK");
1943  
1944    /***************************************************************/
1945    /************************ERRORS HANDLERS************************/
1946    /***************************************************************/
1947  
1948    // Initialize error handler system
1949    DIAG("SYS", "Initializing error handler: clearing error_count, last_error, emergency_state");
1950    error_count = 0;
1951    last_error = ERROR_NONE;
1952    system_emergency_state = false;
1953  
1954    /***************************************************************/
1955    /*********************SEND TO GUI STATUS************************/
1956    /***************************************************************/
1957  
1958    // Send initial status to GUI
1959    DIAG("USB", "Sending initial system status to GUI via USB CDC");
1960    char initial_status[500];
1961    getSystemStatusForGUI(initial_status, sizeof(initial_status));
1962    // Send via USB to GUI
1963    CDC_Transmit_FS((uint8_t*)initial_status, strlen(initial_status));
1964    DIAG("USB", "Initial status sent (%d bytes)", (int)strlen(initial_status));
1965  
1966    DIAG("SYS", "=== INIT COMPLETE -- entering main loop ===");
1967  
1968  
1969  
1970  
1971  
1972  
1973    // main loop
1974  
1975    /* USER CODE END 2 */
1976  
1977    /* Infinite loop */
1978    /* USER CODE BEGIN WHILE */
1979    while (1)
1980    {
1981  	  //////////////////////////////////////////////////////////////////////////////////////
1982  	  //////////////////////// Check system health at the start of each loop////////////////
1983  	  //////////////////////////////////////////////////////////////////////////////////////
1984  
1985  	    if (!checkSystemHealthStatus()) {
1986  	        // System is in bad state, enter safe mode
1987  	    	//Tell FPGA to turn off TX RF signal by disabling Mixers
1988  	    	DIAG_ERR("SYS", "checkSystemHealthStatus() FAILED -- entering SAFE MODE");
1989  	    	DIAG("SYS", "Disabling TX mixers (GPIOD pin 11 LOW)");
1990  	    	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_11, GPIO_PIN_RESET);
1991  	    	DIAG("SYS", "Calling systemPowerDownSequence()");
1992  	        systemPowerDownSequence();
1993  
1994  	        char emergency_msg[] = "SYSTEM IN SAFE MODE - Manual intervention required\r\n";
1995  	        HAL_UART_Transmit(&huart3, (uint8_t*)emergency_msg, strlen(emergency_msg), 1000);
1996  	        DIAG_ERR("SYS", "SAFE MODE ACTIVE -- blinking all LEDs, waiting for system_emergency_state clear");
1997  
1998  	        // Blink all LEDs to indicate safe mode
1999  	        while (system_emergency_state) {
2000  	            HAL_GPIO_TogglePin(LED_1_GPIO_Port, LED_1_Pin);
2001  	            HAL_GPIO_TogglePin(LED_2_GPIO_Port, LED_2_Pin);
2002  	            HAL_GPIO_TogglePin(LED_3_GPIO_Port, LED_3_Pin);
2003  	            HAL_GPIO_TogglePin(LED_4_GPIO_Port, LED_4_Pin);
2004  	        }
2005  	        DIAG("SYS", "Exited safe mode blink loop -- system_emergency_state cleared");
2006  	    }
2007  	  //////////////////////////////////////////////////////////////////////////////////////
2008  	  ////////////////////////// Monitor ADF4382A lock status periodically//////////////////
2009  	  //////////////////////////////////////////////////////////////////////////////////////
2010  
2011        // Monitor lock status periodically
2012        static uint32_t last_check = 0;
2013        if (HAL_GetTick() - last_check > 5000) {
2014            ADF4382A_CheckLockStatus(&lo_manager, &tx_locked, &rx_locked);
2015  
2016            if (!tx_locked || !rx_locked) {
2017                printf("LO Lock Lost! TX: %s, RX: %s\n",
2018                       tx_locked ? "LOCKED" : "UNLOCKED",
2019                       rx_locked ? "LOCKED" : "UNLOCKED");
2020                DIAG_ERR("LO", "Lock LOST in main loop! TX=%s RX=%s",
2021                         tx_locked ? "LOCKED" : "UNLOCKED",
2022                         rx_locked ? "LOCKED" : "UNLOCKED");
2023                DIAG_GPIO("LO", "TX_LKDET (direct)", ADF4382_TX_LKDET_GPIO_Port, ADF4382_TX_LKDET_Pin);
2024                DIAG_GPIO("LO", "RX_LKDET (direct)", ADF4382_RX_LKDET_GPIO_Port, ADF4382_RX_LKDET_Pin);
2025            } else {
2026                DIAG("LO", "Lock poll OK: TX=LOCKED RX=LOCKED");
2027            }
2028  
2029            last_check = HAL_GetTick();
2030        }
2031  	  //////////////////////////////////////////////////////////////////////////////////////
2032  	  ////////////////////////// Monitor Temperature Sensors periodically//////////////////
2033  	  //////////////////////////////////////////////////////////////////////////////////////
2034  	  /* Read all 8 channels from ADC2 and calculate Idq*/
2035        // Monitor T°C periodically
2036        static uint32_t last_check1 = 0;
2037  		  if (HAL_GetTick() - last_check1 > 5000) {
2038  		  //TMP37 3.3V-->165°C & ADS7830 3.3V-->255 => Temperature_n °C = ADC_val_n * 165/255
2039  		  Temperature_1 = ADS7830_Measure_SingleEnded(&hadc3, 0)*0.64705f;
2040  		  Temperature_2 = ADS7830_Measure_SingleEnded(&hadc3, 1)*0.64705f;
2041  		  Temperature_3 = ADS7830_Measure_SingleEnded(&hadc3, 2)*0.64705f;
2042  		  Temperature_4 = ADS7830_Measure_SingleEnded(&hadc3, 3)*0.64705f;
2043  		  Temperature_5 = ADS7830_Measure_SingleEnded(&hadc3, 4)*0.64705f;
2044  		  Temperature_6 = ADS7830_Measure_SingleEnded(&hadc3, 5)*0.64705f;
2045  		  Temperature_7 = ADS7830_Measure_SingleEnded(&hadc3, 6)*0.64705f;
2046  		  Temperature_8 = ADS7830_Measure_SingleEnded(&hadc3, 7)*0.64705f;
2047  
2048  		  DIAG("PA", "Temps: T1=%.1f T2=%.1f T3=%.1f T4=%.1f T5=%.1f T6=%.1f T7=%.1f T8=%.1f",
2049  		       (double)Temperature_1, (double)Temperature_2, (double)Temperature_3, (double)Temperature_4,
2050  		       (double)Temperature_5, (double)Temperature_6, (double)Temperature_7, (double)Temperature_8);
2051  
2052  		  /* [GAP-3 FIX 3] Populate `temperature` with hottest sensor reading.
2053  		   * checkSystemHealth() uses `temperature` for the >75 °C overtemp check;
2054  		   * previously it was uninitialized. */
2055  		  {
2056  		      float temps[8] = { Temperature_1, Temperature_2, Temperature_3, Temperature_4,
2057  		                         Temperature_5, Temperature_6, Temperature_7, Temperature_8 };
2058  		      temperature = temps[0];
2059  		      for (int ti = 1; ti < 8; ti++) {
2060  		          if (temps[ti] > temperature) temperature = temps[ti];
2061  		      }
2062  		      DIAG("PA", "System temperature (max of 8 sensors) = %.1f C", (double)temperature);
2063  		  }
2064  
2065  		  //(20 mV/°C on TMP37) QPA2962 RF amplifier Operating Temp. Range, TBASE min−40 normal+25 max+85 °C
2066  		  int Max_Temp = 25;
2067  		  if((Temperature_1>Max_Temp)||(Temperature_2>Max_Temp)||(Temperature_3>Max_Temp)||(Temperature_4>Max_Temp)
2068  				  ||(Temperature_5>Max_Temp)||(Temperature_6>Max_Temp)||(Temperature_7>Max_Temp)||(Temperature_8>Max_Temp))
2069  			{
2070  			  HAL_GPIO_WritePin(EN_DIS_COOLING_GPIO_Port, EN_DIS_COOLING_Pin, GPIO_PIN_SET);
2071  			  DIAG_WARN("PA", "Over-temp detected (>%d C) -- cooling ENABLED", Max_Temp);
2072  			}
2073  		  else{
2074  			  HAL_GPIO_WritePin(EN_DIS_COOLING_GPIO_Port, EN_DIS_COOLING_Pin, GPIO_PIN_RESET);
2075  		  }
2076  
2077  		  /* [GAP-3 FIX 4] Periodic IDQ re-read — the Idq_reading[] array was only
2078  		   * populated during startup/calibration.  checkSystemHealth() compares
2079  		   * stale values for overcurrent (>2.5 A) and bias fault (<0.1 A) checks.
2080  		   * Re-read all 16 channels every 5 s alongside temperature. */
2081  		  if (PowerAmplifier) {
2082  		      DIAG("PA", "Periodic IDQ re-read (ADC1 + ADC2, 16 channels)");
2083  		      for (uint8_t ch = 0; ch < 8; ch++) {
2084  		          adc1_readings[ch] = ADS7830_Measure_SingleEnded(&hadc1, ch);
2085  		          Idq_reading[ch] = (3.3f/255.0f) * adc1_readings[ch] / (50.0f * 0.005f);
2086  		      }
2087  		      for (uint8_t ch = 0; ch < 8; ch++) {
2088  		          adc2_readings[ch] = ADS7830_Measure_SingleEnded(&hadc2, ch);
2089  		          Idq_reading[ch + 8] = (3.3f/255.0f) * adc2_readings[ch] / (50.0f * 0.005f);
2090  		      }
2091  		      DIAG("PA", "IDQ[0..3]=%.3f %.3f %.3f %.3f  [4..7]=%.3f %.3f %.3f %.3f",
2092  		           (double)Idq_reading[0], (double)Idq_reading[1],
2093  		           (double)Idq_reading[2], (double)Idq_reading[3],
2094  		           (double)Idq_reading[4], (double)Idq_reading[5],
2095  		           (double)Idq_reading[6], (double)Idq_reading[7]);
2096  		      DIAG("PA", "IDQ[8..11]=%.3f %.3f %.3f %.3f  [12..15]=%.3f %.3f %.3f %.3f",
2097  		           (double)Idq_reading[8], (double)Idq_reading[9],
2098  		           (double)Idq_reading[10], (double)Idq_reading[11],
2099  		           (double)Idq_reading[12], (double)Idq_reading[13],
2100  		           (double)Idq_reading[14], (double)Idq_reading[15]);
2101  		  }
2102  
2103  
2104  		  /* [BUG #6 FIXED] Was 'last_check' — now correctly writes 'last_check1'
2105  		   * so the temperature timer runs independently of the lock-check timer. */
2106  		  last_check1 = HAL_GetTick();
2107  		  }
2108  	  //////////////////////////////////////////////////////////////////////////////////////
2109  	  /////////////////////////////////////ADAR1000/////////////////////////////////////////
2110  	  //////////////////////////////////////////////////////////////////////////////////////
2111  	 //phase_step = 0 => phase = 0°
2112  	 //phase_step = 127 => phase = 360°
2113  	 //steering angle (rad)= arcsin(phase_dif/Pi)
2114  
2115        runRadarPulseSequence();
2116  
2117        /* [GAP-3 FIX 2] Kick hardware watchdog — if we don't reach here within
2118         * ~4 s, the IWDG resets the MCU automatically. */
2119        HAL_IWDG_Refresh(&hiwdg);
2120  
2121        // Optional: Add system monitoring here
2122        // Check temperatures, power levels, etc.
2123  
2124  
2125      /* USER CODE END WHILE */
2126  
2127  
2128  
2129  
2130      /* USER CODE BEGIN 3 */
2131    }
2132    /* USER CODE END 3 */
2133  }
2134  
2135  /**
2136    * @brief System Clock Configuration
2137    * @retval None
2138    */
2139  void SystemClock_Config(void)
2140  {
2141    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
2142    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
2143  
2144    /** Configure LSE Drive Capability
2145    */
2146    HAL_PWR_EnableBkUpAccess();
2147  
2148    /** Configure the main internal regulator output voltage
2149    */
2150    __HAL_RCC_PWR_CLK_ENABLE();
2151    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
2152  
2153    /** Initializes the RCC Oscillators according to the specified parameters
2154    * in the RCC_OscInitTypeDef structure.
2155    */
2156    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
2157    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
2158    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
2159    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
2160    RCC_OscInitStruct.PLL.PLLM = 25;
2161    RCC_OscInitStruct.PLL.PLLN = 144;
2162    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
2163    RCC_OscInitStruct.PLL.PLLQ = 3;
2164    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
2165    {
2166      Error_Handler();
2167    }
2168  
2169    /** Initializes the CPU, AHB and APB buses clocks
2170    */
2171    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
2172                                |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
2173    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
2174    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
2175    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
2176    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
2177  
2178    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
2179    {
2180      Error_Handler();
2181    }
2182  }
2183  
2184  /**
2185    * @brief Peripherals Common Clock Configuration
2186    * @retval None
2187    */
2188  void PeriphCommonClock_Config(void)
2189  {
2190    RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
2191  
2192    /** Initializes the peripherals clock
2193    */
2194    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_TIM;
2195    PeriphClkInitStruct.TIMPresSelection = RCC_TIMPRES_ACTIVATED;
2196  
2197    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
2198    {
2199      Error_Handler();
2200    }
2201  }
2202  
2203  /**
2204    * @brief I2C1 Initialization Function
2205    * @param None
2206    * @retval None
2207    */
2208  static void MX_I2C1_Init(void)
2209  {
2210  
2211    /* USER CODE BEGIN I2C1_Init 0 */
2212  
2213    /* USER CODE END I2C1_Init 0 */
2214  
2215    /* USER CODE BEGIN I2C1_Init 1 */
2216  
2217    /* USER CODE END I2C1_Init 1 */
2218    hi2c1.Instance = I2C1;
2219    hi2c1.Init.Timing = 0x00808CD2;
2220    hi2c1.Init.OwnAddress1 = 0;
2221    hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
2222    hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
2223    hi2c1.Init.OwnAddress2 = 0;
2224    hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
2225    hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
2226    hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
2227    if (HAL_I2C_Init(&hi2c1) != HAL_OK)
2228    {
2229      Error_Handler();
2230    }
2231  
2232    /** Configure Analogue filter
2233    */
2234    if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
2235    {
2236      Error_Handler();
2237    }
2238  
2239    /** Configure Digital filter
2240    */
2241    if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
2242    {
2243      Error_Handler();
2244    }
2245    /* USER CODE BEGIN I2C1_Init 2 */
2246  
2247    /* USER CODE END I2C1_Init 2 */
2248  
2249  }
2250  
2251  /**
2252    * @brief I2C2 Initialization Function
2253    * @param None
2254    * @retval None
2255    */
2256  static void MX_I2C2_Init(void)
2257  {
2258  
2259    /* USER CODE BEGIN I2C2_Init 0 */
2260  
2261    /* USER CODE END I2C2_Init 0 */
2262  
2263    /* USER CODE BEGIN I2C2_Init 1 */
2264  
2265    /* USER CODE END I2C2_Init 1 */
2266    hi2c2.Instance = I2C2;
2267    hi2c2.Init.Timing = 0x00808CD2;
2268    hi2c2.Init.OwnAddress1 = 0;
2269    hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
2270    hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
2271    hi2c2.Init.OwnAddress2 = 0;
2272    hi2c2.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
2273    hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
2274    hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
2275    if (HAL_I2C_Init(&hi2c2) != HAL_OK)
2276    {
2277      Error_Handler();
2278    }
2279  
2280    /** Configure Analogue filter
2281    */
2282    if (HAL_I2CEx_ConfigAnalogFilter(&hi2c2, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
2283    {
2284      Error_Handler();
2285    }
2286  
2287    /** Configure Digital filter
2288    */
2289    if (HAL_I2CEx_ConfigDigitalFilter(&hi2c2, 0) != HAL_OK)
2290    {
2291      Error_Handler();
2292    }
2293    /* USER CODE BEGIN I2C2_Init 2 */
2294  
2295    /* USER CODE END I2C2_Init 2 */
2296  
2297  }
2298  
2299  /**
2300    * @brief I2C3 Initialization Function
2301    * @param None
2302    * @retval None
2303    */
2304  static void MX_I2C3_Init(void)
2305  {
2306  
2307    /* USER CODE BEGIN I2C3_Init 0 */
2308  
2309    /* USER CODE END I2C3_Init 0 */
2310  
2311    /* USER CODE BEGIN I2C3_Init 1 */
2312  
2313    /* USER CODE END I2C3_Init 1 */
2314    hi2c3.Instance = I2C3;
2315    hi2c3.Init.Timing = 0x00808CD2;
2316    hi2c3.Init.OwnAddress1 = 0;
2317    hi2c3.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
2318    hi2c3.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
2319    hi2c3.Init.OwnAddress2 = 0;
2320    hi2c3.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
2321    hi2c3.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
2322    hi2c3.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
2323    if (HAL_I2C_Init(&hi2c3) != HAL_OK)
2324    {
2325      Error_Handler();
2326    }
2327  
2328    /** Configure Analogue filter
2329    */
2330    if (HAL_I2CEx_ConfigAnalogFilter(&hi2c3, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
2331    {
2332      Error_Handler();
2333    }
2334  
2335    /** Configure Digital filter
2336    */
2337    if (HAL_I2CEx_ConfigDigitalFilter(&hi2c3, 0) != HAL_OK)
2338    {
2339      Error_Handler();
2340    }
2341    /* USER CODE BEGIN I2C3_Init 2 */
2342  
2343    /* USER CODE END I2C3_Init 2 */
2344  
2345  }
2346  
2347  /**
2348    * @brief SPI1 Initialization Function
2349    * @param None
2350    * @retval None
2351    */
2352  static void MX_SPI1_Init(void)
2353  {
2354  
2355    /* USER CODE BEGIN SPI1_Init 0 */
2356  
2357    /* USER CODE END SPI1_Init 0 */
2358  
2359    /* USER CODE BEGIN SPI1_Init 1 */
2360  
2361    /* USER CODE END SPI1_Init 1 */
2362    /* SPI1 parameter configuration*/
2363    hspi1.Instance = SPI1;
2364    hspi1.Init.Mode = SPI_MODE_MASTER;
2365    hspi1.Init.Direction = SPI_DIRECTION_2LINES;
2366    hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
2367    hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
2368    hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
2369    hspi1.Init.NSS = SPI_NSS_SOFT;
2370    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
2371    hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
2372    hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
2373    hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
2374    hspi1.Init.CRCPolynomial = 7;
2375    hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
2376    hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
2377    if (HAL_SPI_Init(&hspi1) != HAL_OK)
2378    {
2379      Error_Handler();
2380    }
2381    /* USER CODE BEGIN SPI1_Init 2 */
2382  
2383    /* USER CODE END SPI1_Init 2 */
2384  
2385  }
2386  
2387  /**
2388    * @brief SPI4 Initialization Function
2389    * @param None
2390    * @retval None
2391    */
2392  static void MX_SPI4_Init(void)
2393  {
2394  
2395    /* USER CODE BEGIN SPI4_Init 0 */
2396  
2397    /* USER CODE END SPI4_Init 0 */
2398  
2399    /* USER CODE BEGIN SPI4_Init 1 */
2400  
2401    /* USER CODE END SPI4_Init 1 */
2402    /* SPI4 parameter configuration*/
2403    hspi4.Instance = SPI4;
2404    hspi4.Init.Mode = SPI_MODE_MASTER;
2405    hspi4.Init.Direction = SPI_DIRECTION_2LINES;
2406    hspi4.Init.DataSize = SPI_DATASIZE_8BIT;
2407    hspi4.Init.CLKPolarity = SPI_POLARITY_LOW;
2408    hspi4.Init.CLKPhase = SPI_PHASE_1EDGE;
2409    hspi4.Init.NSS = SPI_NSS_SOFT;
2410    hspi4.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
2411    hspi4.Init.FirstBit = SPI_FIRSTBIT_MSB;
2412    hspi4.Init.TIMode = SPI_TIMODE_DISABLE;
2413    hspi4.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
2414    hspi4.Init.CRCPolynomial = 7;
2415    hspi4.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
2416    hspi4.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
2417    if (HAL_SPI_Init(&hspi4) != HAL_OK)
2418    {
2419      Error_Handler();
2420    }
2421    /* USER CODE BEGIN SPI4_Init 2 */
2422  
2423    /* USER CODE END SPI4_Init 2 */
2424  
2425  }
2426  
2427  /**
2428    * @brief TIM1 Initialization Function
2429    * @param None
2430    * @retval None
2431    */
2432  static void MX_TIM1_Init(void)
2433  {
2434  
2435    /* USER CODE BEGIN TIM1_Init 0 */
2436  
2437    /* USER CODE END TIM1_Init 0 */
2438  
2439    TIM_ClockConfigTypeDef sClockSourceConfig = {0};
2440    TIM_MasterConfigTypeDef sMasterConfig = {0};
2441  
2442    /* USER CODE BEGIN TIM1_Init 1 */
2443  
2444    /* USER CODE END TIM1_Init 1 */
2445    htim1.Instance = TIM1;
2446    htim1.Init.Prescaler = 71;
2447    htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
2448    htim1.Init.Period = 0xffff-1;
2449    htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
2450    htim1.Init.RepetitionCounter = 0;
2451    htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
2452    if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
2453    {
2454      Error_Handler();
2455    }
2456    sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
2457    if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
2458    {
2459      Error_Handler();
2460    }
2461    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
2462    sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
2463    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
2464    if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
2465    {
2466      Error_Handler();
2467    }
2468    /* USER CODE BEGIN TIM1_Init 2 */
2469  
2470    /* USER CODE END TIM1_Init 2 */
2471  
2472  }
2473  
2474  /**
2475    * @brief TIM3 Initialization Function — DELADJ PWM for ADF4382A phase shift
2476    *        CH2 = TX DELADJ, CH3 = RX DELADJ
2477    *        Period (ARR) = 999 → 1000 counts matching DELADJ_MAX_DUTY_CYCLE
2478    *        Prescaler = 71 → 1 MHz tick @ 72 MHz APB1 → 1 kHz PWM frequency
2479    * @param None
2480    * @retval None
2481    */
2482  static void MX_TIM3_Init(void)
2483  {
2484    /* B15 fix: provide htim3 definition so adf4382a_manager.c extern resolves */
2485  
2486    TIM_ClockConfigTypeDef sClockSourceConfig = {0};
2487    TIM_MasterConfigTypeDef sMasterConfig = {0};
2488    TIM_OC_InitTypeDef sConfigOC = {0};
2489  
2490    htim3.Instance = TIM3;
2491    htim3.Init.Prescaler = 71;                          // 72 MHz / (71+1) = 1 MHz tick
2492    htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
2493    htim3.Init.Period = 999;                             // ARR = 999 → 1000 counts = DELADJ_MAX_DUTY_CYCLE
2494    htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
2495    htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
2496    if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
2497    {
2498      Error_Handler();
2499    }
2500    sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
2501    if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
2502    {
2503      Error_Handler();
2504    }
2505    if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
2506    {
2507      Error_Handler();
2508    }
2509    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
2510    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
2511    if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
2512    {
2513      Error_Handler();
2514    }
2515    sConfigOC.OCMode = TIM_OCMODE_PWM1;
2516    sConfigOC.Pulse = 0;                                // Start with 0% duty cycle
2517    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
2518    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
2519    // Configure CH2 (TX DELADJ)
2520    if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
2521    {
2522      Error_Handler();
2523    }
2524    // Configure CH3 (RX DELADJ)
2525    if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
2526    {
2527      Error_Handler();
2528    }
2529  }
2530  
2531  /**
2532    * @brief UART5 Initialization Function
2533    * @param None
2534    * @retval None
2535    */
2536  static void MX_UART5_Init(void)
2537  {
2538  
2539    /* USER CODE BEGIN UART5_Init 0 */
2540  
2541    /* USER CODE END UART5_Init 0 */
2542  
2543    /* USER CODE BEGIN UART5_Init 1 */
2544  
2545    /* USER CODE END UART5_Init 1 */
2546    huart5.Instance = UART5;
2547    huart5.Init.BaudRate = 9600;
2548    huart5.Init.WordLength = UART_WORDLENGTH_8B;
2549    huart5.Init.StopBits = UART_STOPBITS_1;
2550    huart5.Init.Parity = UART_PARITY_NONE;
2551    huart5.Init.Mode = UART_MODE_TX_RX;
2552    huart5.Init.HwFlowCtl = UART_HWCONTROL_NONE;
2553    huart5.Init.OverSampling = UART_OVERSAMPLING_16;
2554    huart5.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
2555    huart5.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
2556    if (HAL_UART_Init(&huart5) != HAL_OK)
2557    {
2558      Error_Handler();
2559    }
2560    /* USER CODE BEGIN UART5_Init 2 */
2561  
2562    /* USER CODE END UART5_Init 2 */
2563  
2564  }
2565  
2566  /**
2567    * @brief USART3 Initialization Function
2568    * @param None
2569    * @retval None
2570    */
2571  static void MX_USART3_UART_Init(void)
2572  {
2573  
2574    /* USER CODE BEGIN USART3_Init 0 */
2575  
2576    /* USER CODE END USART3_Init 0 */
2577  
2578    /* USER CODE BEGIN USART3_Init 1 */
2579  
2580    /* USER CODE END USART3_Init 1 */
2581    huart3.Instance = USART3;
2582    huart3.Init.BaudRate = 115200;
2583    huart3.Init.WordLength = UART_WORDLENGTH_8B;
2584    huart3.Init.StopBits = UART_STOPBITS_1;
2585    huart3.Init.Parity = UART_PARITY_NONE;
2586    huart3.Init.Mode = UART_MODE_TX_RX;
2587    huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
2588    huart3.Init.OverSampling = UART_OVERSAMPLING_16;
2589    huart3.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
2590    huart3.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
2591    if (HAL_UART_Init(&huart3) != HAL_OK)
2592    {
2593      Error_Handler();
2594    }
2595    /* USER CODE BEGIN USART3_Init 2 */
2596  
2597    /* USER CODE END USART3_Init 2 */
2598  
2599  }
2600  
2601  /**
2602    * @brief GPIO Initialization Function
2603    * @param None
2604    * @retval None
2605    */
2606  static void MX_GPIO_Init(void)
2607  {
2608    GPIO_InitTypeDef GPIO_InitStruct = {0};
2609    /* USER CODE BEGIN MX_GPIO_Init_1 */
2610  
2611    /* USER CODE END MX_GPIO_Init_1 */
2612  
2613    /* GPIO Ports Clock Enable */
2614    __HAL_RCC_GPIOE_CLK_ENABLE();
2615    __HAL_RCC_GPIOC_CLK_ENABLE();
2616    __HAL_RCC_GPIOF_CLK_ENABLE();
2617    __HAL_RCC_GPIOH_CLK_ENABLE();
2618    __HAL_RCC_GPIOA_CLK_ENABLE();
2619    __HAL_RCC_GPIOG_CLK_ENABLE();
2620    __HAL_RCC_GPIOB_CLK_ENABLE();
2621    __HAL_RCC_GPIOD_CLK_ENABLE();
2622  
2623    /*Configure GPIO pin Output Level */
2624    HAL_GPIO_WritePin(GPIOF, AD9523_PD_Pin|AD9523_REF_SEL_Pin|AD9523_SYNC_Pin|AD9523_RESET_Pin
2625                            |AD9523_CS_Pin|AD9523_EEPROM_SEL_Pin|LED_1_Pin|LED_2_Pin
2626                            |LED_3_Pin|LED_4_Pin, GPIO_PIN_RESET);
2627  
2628    /*Configure GPIO pin Output Level */
2629    HAL_GPIO_WritePin(GPIOA, ADAR_1_CS_3V3_Pin|ADAR_2_CS_3V3_Pin|ADAR_3_CS_3V3_Pin|ADAR_4_CS_3V3_Pin, GPIO_PIN_RESET);
2630  
2631    /*Configure GPIO pin Output Level */
2632    HAL_GPIO_WritePin(GPIOG, EN_P_5V0_PA1_Pin|EN_P_5V0_PA2_Pin|EN_P_5V0_PA3_Pin|EN_P_5V5_PA_Pin
2633                            |EN_P_1V8_CLOCK_Pin|EN_P_3V3_CLOCK_Pin|ADF4382_RX_DELADJ_Pin|ADF4382_RX_DELSTR_Pin
2634                            |ADF4382_RX_CE_Pin|ADF4382_RX_CS_Pin|ADF4382_TX_DELSTR_Pin|ADF4382_TX_DELADJ_Pin
2635                            |ADF4382_TX_CS_Pin|ADF4382_TX_CE_Pin, GPIO_PIN_RESET);
2636  
2637    /*Configure GPIO pin Output Level */
2638    HAL_GPIO_WritePin(GPIOE, EN_P_1V0_FPGA_Pin|EN_P_1V8_FPGA_Pin|EN_P_3V3_FPGA_Pin|EN_P_5V0_ADAR_Pin
2639                            |EN_P_3V3_ADAR12_Pin|EN_P_3V3_ADAR34_Pin|EN_P_3V3_ADTR_Pin|EN_P_3V3_SW_Pin
2640                            |EN_P_3V3_VDD_SW_Pin, GPIO_PIN_RESET);
2641  
2642    /*Configure GPIO pin Output Level */
2643    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
2644                            |STEPPER_CW_P_Pin|STEPPER_CLK_P_Pin|EN_DIS_RFPA_VDD_Pin|EN_DIS_COOLING_Pin, GPIO_PIN_RESET);
2645  
2646    /*Configure GPIO pin Output Level */
2647    HAL_GPIO_WritePin(GPIOB, DAC_1_VG_CLR_Pin|DAC_1_VG_LDAC_Pin|DAC_2_VG_CLR_Pin|DAC_2_VG_LDAC_Pin, GPIO_PIN_RESET);
2648  
2649    /*Configure GPIO pins : AD9523_PD_Pin AD9523_REF_SEL_Pin AD9523_SYNC_Pin AD9523_RESET_Pin
2650                             AD9523_CS_Pin AD9523_EEPROM_SEL_Pin LED_1_Pin LED_2_Pin
2651                             LED_3_Pin LED_4_Pin */
2652    GPIO_InitStruct.Pin = AD9523_PD_Pin|AD9523_REF_SEL_Pin|AD9523_SYNC_Pin|AD9523_RESET_Pin
2653                            |AD9523_CS_Pin|AD9523_EEPROM_SEL_Pin|LED_1_Pin|LED_2_Pin
2654                            |LED_3_Pin|LED_4_Pin;
2655    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
2656    GPIO_InitStruct.Pull = GPIO_NOPULL;
2657    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
2658    HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
2659  
2660    /*Configure GPIO pins : AD9523_STATUS0_Pin AD9523_STATUS1_Pin */
2661    GPIO_InitStruct.Pin = AD9523_STATUS0_Pin|AD9523_STATUS1_Pin;
2662    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
2663    GPIO_InitStruct.Pull = GPIO_NOPULL;
2664    HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
2665  
2666    /*Configure GPIO pins : ADAR_1_CS_3V3_Pin ADAR_2_CS_3V3_Pin ADAR_3_CS_3V3_Pin ADAR_4_CS_3V3_Pin */
2667    GPIO_InitStruct.Pin = ADAR_1_CS_3V3_Pin|ADAR_2_CS_3V3_Pin|ADAR_3_CS_3V3_Pin|ADAR_4_CS_3V3_Pin;
2668    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
2669    GPIO_InitStruct.Pull = GPIO_NOPULL;
2670    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
2671    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
2672  
2673    /*Configure GPIO pins : EN_P_5V0_PA1_Pin EN_P_5V0_PA2_Pin EN_P_5V0_PA3_Pin EN_P_5V5_PA_Pin
2674                             EN_P_1V8_CLOCK_Pin EN_P_3V3_CLOCK_Pin ADF4382_RX_DELADJ_Pin ADF4382_RX_DELSTR_Pin
2675                             ADF4382_RX_CE_Pin ADF4382_RX_CS_Pin ADF4382_TX_DELSTR_Pin ADF4382_TX_DELADJ_Pin
2676                             ADF4382_TX_CS_Pin ADF4382_TX_CE_Pin */
2677    GPIO_InitStruct.Pin = EN_P_5V0_PA1_Pin|EN_P_5V0_PA2_Pin|EN_P_5V0_PA3_Pin|EN_P_5V5_PA_Pin
2678                            |EN_P_1V8_CLOCK_Pin|EN_P_3V3_CLOCK_Pin|ADF4382_RX_DELADJ_Pin|ADF4382_RX_DELSTR_Pin
2679                            |ADF4382_RX_CE_Pin|ADF4382_RX_CS_Pin|ADF4382_TX_DELSTR_Pin|ADF4382_TX_DELADJ_Pin
2680                            |ADF4382_TX_CS_Pin|ADF4382_TX_CE_Pin;
2681    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
2682    GPIO_InitStruct.Pull = GPIO_NOPULL;
2683    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
2684    HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
2685  
2686    /*Configure GPIO pins : EN_P_1V0_FPGA_Pin EN_P_1V8_FPGA_Pin EN_P_3V3_FPGA_Pin EN_P_5V0_ADAR_Pin
2687                             EN_P_3V3_ADAR12_Pin EN_P_3V3_ADAR34_Pin EN_P_3V3_ADTR_Pin EN_P_3V3_SW_Pin
2688                             EN_P_3V3_ADAR12EN_P_3V3_VDD_SW_Pin */
2689    GPIO_InitStruct.Pin = EN_P_1V0_FPGA_Pin|EN_P_1V8_FPGA_Pin|EN_P_3V3_FPGA_Pin|EN_P_5V0_ADAR_Pin
2690                            |EN_P_3V3_ADAR12_Pin|EN_P_3V3_ADAR34_Pin|EN_P_3V3_ADTR_Pin|EN_P_3V3_SW_Pin
2691                            |EN_P_3V3_VDD_SW_Pin;
2692    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
2693    GPIO_InitStruct.Pull = GPIO_NOPULL;
2694    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
2695    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
2696  
2697    /*Configure GPIO pins : PD8 PD9 PD10 PD11
2698                             STEPPER_CW_P_Pin STEPPER_CLK_P_Pin EN_DIS_RFPA_VDD_Pin EN_DIS_COOLING_Pin */
2699    GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12
2700                            |STEPPER_CW_P_Pin|STEPPER_CLK_P_Pin|EN_DIS_RFPA_VDD_Pin|EN_DIS_COOLING_Pin;
2701    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
2702    GPIO_InitStruct.Pull = GPIO_NOPULL;
2703    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
2704    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
2705  
2706    /*Configure GPIO pins : PD12 PD13 PD14 PD15 */
2707    GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
2708    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
2709    GPIO_InitStruct.Pull = GPIO_NOPULL;
2710    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
2711  
2712    /*Configure GPIO pins : ADF4382_RX_LKDET_Pin ADF4382_TX_LKDET_Pin */
2713    GPIO_InitStruct.Pin = ADF4382_RX_LKDET_Pin|ADF4382_TX_LKDET_Pin;
2714    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
2715    GPIO_InitStruct.Pull = GPIO_NOPULL;
2716    HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
2717  
2718    /*Configure GPIO pins : MAG_DRDY_Pin ACC_INT_Pin GYR_INT_Pin */
2719    GPIO_InitStruct.Pin = MAG_DRDY_Pin|ACC_INT_Pin|GYR_INT_Pin;
2720    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
2721    GPIO_InitStruct.Pull = GPIO_NOPULL;
2722    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
2723  
2724    /*Configure GPIO pins : DAC_1_VG_CLR_Pin DAC_1_VG_LDAC_Pin DAC_2_VG_CLR_Pin DAC_2_VG_LDAC_Pin */
2725    GPIO_InitStruct.Pin = DAC_1_VG_CLR_Pin|DAC_1_VG_LDAC_Pin|DAC_2_VG_CLR_Pin|DAC_2_VG_LDAC_Pin;
2726    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
2727    GPIO_InitStruct.Pull = GPIO_NOPULL;
2728    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
2729    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
2730  
2731    /* USER CODE BEGIN MX_GPIO_Init_2 */
2732  
2733    /* USER CODE END MX_GPIO_Init_2 */
2734  }
2735  
2736  /* USER CODE BEGIN 4 */
2737  /* ============================================================
2738   *                  DEVICE INITIALIZATION
2739   * ============================================================ */
2740  
2741  /**
2742   * [GAP-3 FIX 2] Initialize Independent Watchdog (IWDG).
2743   *
2744   * LSI clock ≈ 32 kHz.
2745   * Prescaler = 256  → IWDG counter clock ≈ 125 Hz (8 ms/tick).
2746   * Reload   = 500   → timeout ≈ 500 × 8 ms = 4.0 s.
2747   *
2748   * The main loop must call HAL_IWDG_Refresh() within this window
2749   * or the MCU hard-resets — protecting against firmware hangs when
2750   * PA rails may be energized.
2751   */
2752  static void MX_IWDG_Init(void)
2753  {
2754      hiwdg.Instance       = IWDG;
2755      hiwdg.Init.Prescaler = IWDG_PRESCALER_256;
2756      hiwdg.Init.Reload    = 500;
2757      hiwdg.Init.Window    = IWDG_WINDOW_DISABLE;
2758      if (HAL_IWDG_Init(&hiwdg) != HAL_OK) {
2759          DIAG_ERR("SYS", "IWDG init FAILED -- continuing without hardware watchdog");
2760      } else {
2761          DIAG("SYS", "IWDG hardware watchdog started (timeout ~4s)");
2762      }
2763  }
2764  
2765  
2766  
2767  /* USER CODE END 4 */
2768  
2769   /* MPU Configuration */
2770  
2771  void MPU_Config(void)
2772  {
2773    MPU_Region_InitTypeDef MPU_InitStruct = {0};
2774  
2775    /* Disables the MPU */
2776    HAL_MPU_Disable();
2777  
2778    /** Initializes and configures the Region and the memory to be protected
2779    */
2780    MPU_InitStruct.Enable = MPU_REGION_ENABLE;
2781    MPU_InitStruct.Number = MPU_REGION_NUMBER0;
2782    MPU_InitStruct.BaseAddress = 0x0;
2783    MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;
2784    MPU_InitStruct.SubRegionDisable = 0x87;
2785    MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
2786    MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
2787    MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
2788    MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
2789    MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
2790    MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
2791  
2792    HAL_MPU_ConfigRegion(&MPU_InitStruct);
2793    /* Enables the MPU */
2794    HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
2795  
2796  }
2797  
2798  /**
2799    * @brief  This function is executed in case of error occurrence.
2800    * @retval None
2801    */
2802  void Error_Handler(void)
2803  {
2804    /* USER CODE BEGIN Error_Handler_Debug */
2805    /* User can add his own implementation to report the HAL error return state */
2806    __disable_irq();
2807    while (1)
2808    {
2809    }
2810    /* USER CODE END Error_Handler_Debug */
2811  }
2812  
2813  #ifdef  USE_FULL_ASSERT
2814  /**
2815    * @brief  Reports the name of the source file and the source line number
2816    *         where the assert_param error has occurred.
2817    * @param  file: pointer to the source file name
2818    * @param  line: assert_param error line source number
2819    * @retval None
2820    */
2821  void assert_failed(uint8_t *file, uint32_t line)
2822  {
2823    /* USER CODE BEGIN 6 */
2824    /* User can add his own implementation to report the file name and line number,
2825       ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
2826    /* USER CODE END 6 */
2827  }
2828  #endif /* USE_FULL_ASSERT */