This commit is contained in:
Jason
2026-03-15 06:22:27 +02:00
10 changed files with 695 additions and 381 deletions
@@ -9,15 +9,15 @@ extern SPI_HandleTypeDef hspi1;
extern UART_HandleTypeDef huart3; extern UART_HandleTypeDef huart3;
// Chip Select GPIO definitions // Chip Select GPIO definitions
static const struct { static const struct {
GPIO_TypeDef* port; GPIO_TypeDef* port;
uint16_t pin; uint16_t pin;
} CHIP_SELECTS[4] = { } CHIP_SELECTS[4] = {
{GPIOA, GPIO_PIN_0}, // ADAR1000 #1 {ADAR_1_CS_3V3_GPIO_Port, ADAR_1_CS_3V3_Pin}, // ADAR1000 #1
{GPIOA, GPIO_PIN_1}, // ADAR1000 #2 {ADAR_2_CS_3V3_GPIO_Port, ADAR_2_CS_3V3_Pin}, // ADAR1000 #2
{GPIOA, GPIO_PIN_2}, // ADAR1000 #3 {ADAR_3_CS_3V3_GPIO_Port, ADAR_3_CS_3V3_Pin}, // ADAR1000 #3
{GPIOA, GPIO_PIN_3} // ADAR1000 #4 {ADAR_4_CS_3V3_GPIO_Port, ADAR_4_CS_3V3_Pin} // ADAR1000 #4
}; };
// Vector Modulator lookup tables // Vector Modulator lookup tables
const uint8_t ADAR1000Manager::VM_I[128] = { const uint8_t ADAR1000Manager::VM_I[128] = {
@@ -162,15 +162,15 @@ bool ADAR1000Manager::setBeamAngle(float angle_degrees, BeamDirection direction)
for (uint8_t dev = 0; dev < devices_.size(); ++dev) { for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
for (uint8_t ch = 0; ch < 4; ++ch) { for (uint8_t ch = 0; ch < 4; ++ch) {
if (direction == BeamDirection::TX) { if (direction == BeamDirection::TX) {
adarSetTxPhase(dev, ch + 1, phase_settings[ch], BROADCAST_OFF); adarSetTxPhase(dev, ch + 1, phase_settings[ch], BROADCAST_OFF);
adarSetTxVgaGain(dev, ch + 1, 0x7F, BROADCAST_OFF); adarSetTxVgaGain(dev, ch + 1, kDefaultTxVgaGain, BROADCAST_OFF);
} else { } else {
adarSetRxPhase(dev, ch + 1, phase_settings[ch], BROADCAST_OFF); adarSetRxPhase(dev, ch + 1, phase_settings[ch], BROADCAST_OFF);
adarSetRxVgaGain(dev, ch + 1, 30, BROADCAST_OFF); adarSetRxVgaGain(dev, ch + 1, kDefaultRxVgaGain, BROADCAST_OFF);
} }
} }
} }
return true; return true;
} }
@@ -326,59 +326,57 @@ bool ADAR1000Manager::initializeADTR1107Sequence() {
const uint8_t msg[] = "Starting ADTR1107 Power Sequence...\r\n"; const uint8_t msg[] = "Starting ADTR1107 Power Sequence...\r\n";
HAL_UART_Transmit(&huart3, msg, sizeof(msg) - 1, 1000); HAL_UART_Transmit(&huart3, msg, sizeof(msg) - 1, 1000);
// Step 1: Connect all GND pins to ground (assumed in hardware) // Step 1: Connect all GND pins to ground (assumed in hardware)
// Step 2: Set VDD_SW to 3.3V // Step 2: Set VDD_SW to 3.3V
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_15, GPIO_PIN_SET); // EN_P_3V3_VDD_SW HAL_GPIO_WritePin(EN_P_3V3_VDD_SW_GPIO_Port, EN_P_3V3_VDD_SW_Pin, GPIO_PIN_SET);
HAL_Delay(1); HAL_Delay(1);
// Step 3: Set VSS_SW to -3.3V // Step 3: Set VSS_SW to -3.3V
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_14, GPIO_PIN_SET); // EN_P_3V3_SW HAL_GPIO_WritePin(EN_P_3V3_SW_GPIO_Port, EN_P_3V3_SW_Pin, GPIO_PIN_SET);
HAL_Delay(1); HAL_Delay(1);
// Step 4: Set CTRL_SW to RX mode initially via GPIO // Step 4: Set CTRL_SW to RX mode initially via GPIO
setADTR1107Control(false); // RX mode setADTR1107Control(false); // RX mode
HAL_Delay(1); HAL_Delay(1);
// Step 5: Set VGG_LNA to 0 // Step 5: Set VGG_LNA to 0
uint8_t lna_bias_voltage = 0x00; // Example value, adjust based on your LNA requirements uint8_t lna_bias_voltage = kLnaBiasOff;
for (uint8_t dev = 0; dev < devices_.size(); ++dev) { for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
adarWrite(dev, REG_LNA_BIAS_ON, lna_bias_voltage, BROADCAST_OFF); adarWrite(dev, REG_LNA_BIAS_ON, lna_bias_voltage, BROADCAST_OFF);
adarWrite(dev, REG_LNA_BIAS_OFF, 0x00, BROADCAST_OFF); adarWrite(dev, REG_LNA_BIAS_OFF, kLnaBiasOff, BROADCAST_OFF);
} }
// Step 6: Set VDD_LNA to 0V for TX mode // Step 6: Set VDD_LNA to 0V for TX mode
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_RESET); // EN_P_3V3_LNA HAL_GPIO_WritePin(EN_P_3V3_ADTR_GPIO_Port, EN_P_3V3_ADTR_Pin, GPIO_PIN_RESET);
HAL_Delay(2); HAL_Delay(2);
// Step 7: Set VGG_PA to safe negative voltage (PA off for TX mode) // Step 7: Set VGG_PA to safe negative voltage (PA off for TX mode)
/*A 0x00 value in the /*A 0x00 value in the
on or off bias registers, correspond to a 0 V output. A 0xFF in the on or off bias registers, correspond to a 0 V output. A 0xFF in the
on or off bias registers correspond to a 4.8 V output.*/ on or off bias registers correspond to a 4.8 V output.*/
uint8_t safe_pa_bias = 0x5D; // Safe negative voltage (-1.75V) to keep PA off uint8_t safe_pa_bias = kPaBiasTxSafe; // Safe negative voltage (-1.75V) to keep PA off
for (uint8_t dev = 0; dev < devices_.size(); ++dev) { for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
adarWrite(dev, REG_PA_CH1_BIAS_ON, safe_pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH1_BIAS_ON, safe_pa_bias, BROADCAST_OFF);
adarWrite(dev, REG_PA_CH2_BIAS_ON, safe_pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH2_BIAS_ON, safe_pa_bias, BROADCAST_OFF);
adarWrite(dev, REG_PA_CH3_BIAS_ON, safe_pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH3_BIAS_ON, safe_pa_bias, BROADCAST_OFF);
adarWrite(dev, REG_PA_CH4_BIAS_ON, safe_pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH4_BIAS_ON, safe_pa_bias, BROADCAST_OFF);
} }
HAL_Delay(10); HAL_Delay(10);
// Step 8: Set VDD_PA to 0V (PA powered up for TX mode) // Step 8: Set VDD_PA to 0V (PA powered up for TX mode)
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_0, GPIO_PIN_SET); // EN_P_5V0_PA enablePASupplies();
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_1, GPIO_PIN_SET); HAL_Delay(50);
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_2, GPIO_PIN_SET);
HAL_Delay(50);
// Step 9: Adjust VGG_PA voltage between 1.75 V and 0.25 V to achieve the desired IDQ_PA=220mA // Step 9: Adjust VGG_PA voltage between 1.75 V and 0.25 V to achieve the desired IDQ_PA=220mA
//Set VGG_PA to safe negative voltage (PA off for TX mode) //Set VGG_PA to safe negative voltage (PA off for TX mode)
/*A 0x00 value in the /*A 0x00 value in the
on or off bias registers, correspond to a 0 V output. A 0xFF in the on or off bias registers, correspond to a 0 V output. A 0xFF in the
on or off bias registers correspond to a 4.8 V output.*/ on or off bias registers correspond to a 4.8 V output.*/
uint8_t Idq_pa_bias = 0x0D; // Safe negative voltage (-0.2447V) to keep PA off uint8_t Idq_pa_bias = kPaBiasIdqCalibration; // Safe negative voltage (-0.2447V) to keep PA off
for (uint8_t dev = 0; dev < devices_.size(); ++dev) { for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
adarWrite(dev, REG_PA_CH1_BIAS_ON, Idq_pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH1_BIAS_ON, Idq_pa_bias, BROADCAST_OFF);
adarWrite(dev, REG_PA_CH2_BIAS_ON, Idq_pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH2_BIAS_ON, Idq_pa_bias, BROADCAST_OFF);
adarWrite(dev, REG_PA_CH3_BIAS_ON, Idq_pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH3_BIAS_ON, Idq_pa_bias, BROADCAST_OFF);
adarWrite(dev, REG_PA_CH4_BIAS_ON, Idq_pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH4_BIAS_ON, Idq_pa_bias, BROADCAST_OFF);
} }
@@ -429,30 +427,28 @@ bool ADAR1000Manager::setAllDevicesRXMode() {
} }
void ADAR1000Manager::setADTR1107Mode(BeamDirection direction) { void ADAR1000Manager::setADTR1107Mode(BeamDirection direction) {
if (direction == BeamDirection::TX) { if (direction == BeamDirection::TX) {
setADTR1107Control(true); // TX mode setADTR1107Control(true); // TX mode
// Step 1: Disable LNA power first // Step 1: Disable LNA power first
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_RESET); // Disable LNA power disableLNASupplies();
HAL_Delay(5); HAL_Delay(5);
// Step 2: Set LNA bias to safe off value // Step 2: Set LNA bias to safe off value
for (uint8_t dev = 0; dev < devices_.size(); ++dev) { for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
adarWrite(dev, REG_LNA_BIAS_ON, 0x00, BROADCAST_OFF); // Turn off LNA bias adarWrite(dev, REG_LNA_BIAS_ON, kLnaBiasOff, BROADCAST_OFF); // Turn off LNA bias
} }
HAL_Delay(5); HAL_Delay(5);
// Step 3: Enable PA power // Step 3: Enable PA power
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_0, GPIO_PIN_SET); // EN_P_5V0_PA enablePASupplies();
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_1, GPIO_PIN_SET); HAL_Delay(10);
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_2, GPIO_PIN_SET);
HAL_Delay(10); // Step 4: Set PA bias to operational value
uint8_t operational_pa_bias = kPaBiasOperational; // Maximum bias for full power
// Step 4: Set PA bias to operational value for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
uint8_t operational_pa_bias = 0x7F; // Maximum bias for full power adarWrite(dev, REG_PA_CH1_BIAS_ON, operational_pa_bias, BROADCAST_OFF);
for (uint8_t dev = 0; dev < devices_.size(); ++dev) { adarWrite(dev, REG_PA_CH2_BIAS_ON, operational_pa_bias, BROADCAST_OFF);
adarWrite(dev, REG_PA_CH1_BIAS_ON, operational_pa_bias, BROADCAST_OFF);
adarWrite(dev, REG_PA_CH2_BIAS_ON, operational_pa_bias, BROADCAST_OFF);
adarWrite(dev, REG_PA_CH3_BIAS_ON, operational_pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH3_BIAS_ON, operational_pa_bias, BROADCAST_OFF);
adarWrite(dev, REG_PA_CH4_BIAS_ON, operational_pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH4_BIAS_ON, operational_pa_bias, BROADCAST_OFF);
} }
@@ -466,33 +462,31 @@ void ADAR1000Manager::setADTR1107Mode(BeamDirection direction) {
} else { } else {
// RECEIVE MODE: Enable LNA, Disable PA // RECEIVE MODE: Enable LNA, Disable PA
setADTR1107Control(false); // RX mode setADTR1107Control(false); // RX mode
// Step 1: Disable PA power first // Step 1: Disable PA power first
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_0, GPIO_PIN_RESET); // EN_P_5V0_PA disablePASupplies();
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_1, GPIO_PIN_RESET); HAL_Delay(5);
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_2, GPIO_PIN_RESET);
HAL_Delay(5); // Step 2: Set PA bias to safe negative voltage
uint8_t safe_pa_bias = kPaBiasRxSafe;
// Step 2: Set PA bias to safe negative voltage for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
uint8_t safe_pa_bias = 0x20; adarWrite(dev, REG_PA_CH1_BIAS_ON, safe_pa_bias, BROADCAST_OFF);
for (uint8_t dev = 0; dev < devices_.size(); ++dev) { adarWrite(dev, REG_PA_CH2_BIAS_ON, safe_pa_bias, BROADCAST_OFF);
adarWrite(dev, REG_PA_CH1_BIAS_ON, safe_pa_bias, BROADCAST_OFF);
adarWrite(dev, REG_PA_CH2_BIAS_ON, safe_pa_bias, BROADCAST_OFF);
adarWrite(dev, REG_PA_CH3_BIAS_ON, safe_pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH3_BIAS_ON, safe_pa_bias, BROADCAST_OFF);
adarWrite(dev, REG_PA_CH4_BIAS_ON, safe_pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH4_BIAS_ON, safe_pa_bias, BROADCAST_OFF);
} }
HAL_Delay(5); HAL_Delay(5);
// Step 3: Enable LNA power // Step 3: Enable LNA power
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_SET); // EN_P_3V3_LNA enableLNASupplies();
HAL_Delay(10); HAL_Delay(10);
// Step 4: Set LNA bias to operational value // Step 4: Set LNA bias to operational value
uint8_t operational_lna_bias = 0x30; // Adjust based on your LNA requirements uint8_t operational_lna_bias = kLnaBiasOperational;
for (uint8_t dev = 0; dev < devices_.size(); ++dev) { for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
adarWrite(dev, REG_LNA_BIAS_ON, operational_lna_bias, BROADCAST_OFF); adarWrite(dev, REG_LNA_BIAS_ON, operational_lna_bias, BROADCAST_OFF);
} }
HAL_Delay(5); HAL_Delay(5);
// Step 5: Set TR switch to RX mode // Step 5: Set TR switch to RX mode
@@ -535,42 +529,42 @@ bool ADAR1000Manager::setCustomBeamPattern16(const uint8_t phase_pattern[16], Be
return true; return true;
} }
void ADAR1000Manager::enablePASupplies() { void ADAR1000Manager::enablePASupplies() {
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_0, GPIO_PIN_SET); // EN_P_5V0_PA HAL_GPIO_WritePin(EN_P_5V0_PA1_GPIO_Port, EN_P_5V0_PA1_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_1, GPIO_PIN_SET); HAL_GPIO_WritePin(EN_P_5V0_PA2_GPIO_Port, EN_P_5V0_PA2_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_2, GPIO_PIN_SET); HAL_GPIO_WritePin(EN_P_5V0_PA3_GPIO_Port, EN_P_5V0_PA3_Pin, GPIO_PIN_SET);
} }
void ADAR1000Manager::disablePASupplies() { void ADAR1000Manager::disablePASupplies() {
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_0, GPIO_PIN_RESET); // EN_P_5V0_PA HAL_GPIO_WritePin(EN_P_5V0_PA1_GPIO_Port, EN_P_5V0_PA1_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_1, GPIO_PIN_RESET); HAL_GPIO_WritePin(EN_P_5V0_PA2_GPIO_Port, EN_P_5V0_PA2_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_2, GPIO_PIN_RESET); HAL_GPIO_WritePin(EN_P_5V0_PA3_GPIO_Port, EN_P_5V0_PA3_Pin, GPIO_PIN_RESET);
} }
void ADAR1000Manager::enableLNASupplies() { void ADAR1000Manager::enableLNASupplies() {
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_SET); // EN_P_3V3_LNA HAL_GPIO_WritePin(EN_P_3V3_ADTR_GPIO_Port, EN_P_3V3_ADTR_Pin, GPIO_PIN_SET);
} }
void ADAR1000Manager::disableLNASupplies() { void ADAR1000Manager::disableLNASupplies() {
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_RESET); // EN_P_3V3_LNA HAL_GPIO_WritePin(EN_P_3V3_ADTR_GPIO_Port, EN_P_3V3_ADTR_Pin, GPIO_PIN_RESET);
} }
void ADAR1000Manager::setPABias(bool enable) { void ADAR1000Manager::setPABias(bool enable) {
uint8_t pa_bias = enable ? 0x7F : 0x20; // Operational vs safe bias uint8_t pa_bias = enable ? kPaBiasOperational : kPaBiasRxSafe; // Operational vs safe bias
for (uint8_t dev = 0; dev < devices_.size(); ++dev) { for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
adarWrite(dev, REG_PA_CH1_BIAS_ON, pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH1_BIAS_ON, pa_bias, BROADCAST_OFF);
adarWrite(dev, REG_PA_CH2_BIAS_ON, pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH2_BIAS_ON, pa_bias, BROADCAST_OFF);
adarWrite(dev, REG_PA_CH3_BIAS_ON, pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH3_BIAS_ON, pa_bias, BROADCAST_OFF);
adarWrite(dev, REG_PA_CH4_BIAS_ON, pa_bias, BROADCAST_OFF); adarWrite(dev, REG_PA_CH4_BIAS_ON, pa_bias, BROADCAST_OFF);
} }
} }
void ADAR1000Manager::setLNABias(bool enable) { void ADAR1000Manager::setLNABias(bool enable) {
uint8_t lna_bias = enable ? 0x30 : 0x00; // Operational vs off uint8_t lna_bias = enable ? kLnaBiasOperational : kLnaBiasOff; // Operational vs off
for (uint8_t dev = 0; dev < devices_.size(); ++dev) { for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
adarWrite(dev, REG_LNA_BIAS_ON, lna_bias, BROADCAST_OFF); adarWrite(dev, REG_LNA_BIAS_ON, lna_bias, BROADCAST_OFF);
} }
} }
@@ -739,11 +733,11 @@ void ADAR1000Manager::adarSetTxVgaGain(uint8_t deviceIndex, uint8_t channel, uin
adarWrite(deviceIndex, REG_LOAD_WORKING, LD_WRK_REGS_LDTX_OVERRIDE, broadcast); adarWrite(deviceIndex, REG_LOAD_WORKING, LD_WRK_REGS_LDTX_OVERRIDE, broadcast);
} }
void ADAR1000Manager::adarSetTxBias(uint8_t deviceIndex, uint8_t broadcast) { void ADAR1000Manager::adarSetTxBias(uint8_t deviceIndex, uint8_t broadcast) {
adarWrite(deviceIndex, REG_BIAS_CURRENT_TX, 0x2D, broadcast); adarWrite(deviceIndex, REG_BIAS_CURRENT_TX, kTxBiasCurrent, broadcast);
adarWrite(deviceIndex, REG_BIAS_CURRENT_TX_DRV, 0x06, broadcast); adarWrite(deviceIndex, REG_BIAS_CURRENT_TX_DRV, kTxDriverBiasCurrent, broadcast);
adarWrite(deviceIndex, REG_LOAD_WORKING, 0x2, broadcast); adarWrite(deviceIndex, REG_LOAD_WORKING, 0x2, broadcast);
} }
uint8_t ADAR1000Manager::adarAdcRead(uint8_t deviceIndex, uint8_t broadcast) { uint8_t ADAR1000Manager::adarAdcRead(uint8_t deviceIndex, uint8_t broadcast) {
adarWrite(deviceIndex, REG_ADC_CONTROL, ADAR1000_ADC_ST_CONV, broadcast); adarWrite(deviceIndex, REG_ADC_CONTROL, ADAR1000_ADC_ST_CONV, broadcast);
@@ -116,13 +116,25 @@ public:
bool beam_sweeping_active_ = false; bool beam_sweeping_active_ = false;
uint32_t last_beam_update_time_ = 0; uint32_t last_beam_update_time_ = 0;
// Lookup tables // Lookup tables
static const uint8_t VM_I[128]; static const uint8_t VM_I[128];
static const uint8_t VM_Q[128]; static const uint8_t VM_Q[128];
static const uint8_t VM_GAIN[128]; static const uint8_t VM_GAIN[128];
// Private Methods // Named defaults for the ADTR1107 and ADAR1000 power sequence.
bool initializeSingleDevice(uint8_t deviceIndex); static constexpr uint8_t kDefaultTxVgaGain = 0x7F;
static constexpr uint8_t kDefaultRxVgaGain = 30;
static constexpr uint8_t kLnaBiasOff = 0x00;
static constexpr uint8_t kLnaBiasOperational = 0x30;
static constexpr uint8_t kPaBiasTxSafe = 0x5D;
static constexpr uint8_t kPaBiasIdqCalibration = 0x0D;
static constexpr uint8_t kPaBiasOperational = 0x7F;
static constexpr uint8_t kPaBiasRxSafe = 0x20;
static constexpr uint8_t kTxBiasCurrent = 0x2D;
static constexpr uint8_t kTxDriverBiasCurrent = 0x06;
// Private Methods
bool initializeSingleDevice(uint8_t deviceIndex);
bool initializeADTR1107Sequence(); bool initializeADTR1107Sequence();
void calculatePhaseSettings(float angle_degrees, uint8_t phase_settings[4]); void calculatePhaseSettings(float angle_degrees, uint8_t phase_settings[4]);
void delayUs(uint32_t microseconds); void delayUs(uint32_t microseconds);
@@ -1,121 +1,173 @@
#include "GY_85_HAL.h" #include "GY_85_HAL.h"
static int16_t g_offx = 0, g_offy = 0, g_offz = 0;
// ---------------- Internal Functions ---------------- //
static bool GY85_SetAccelerometer(void);
static bool GY85_ReadAccelerometer(GY85_t *imu);
static bool GY85_SetCompass(void);
static bool GY85_ReadCompass(GY85_t *imu);
static bool GY85_SetGyro(void);
static bool GY85_GyroCalibrate(void);
static bool GY85_ReadGyro(GY85_t *imu);
static bool GY85_WriteRegister(uint16_t address, uint8_t reg, uint8_t value);
static bool GY85_ReadRegisters(uint16_t address, uint8_t reg, uint8_t *buffer, uint16_t length);
// ---------------- Initialization ---------------- //
bool GY85_Init(void)
{
if (!GY85_SetAccelerometer()) {
return false;
}
if (!GY85_SetCompass()) {
return false;
}
return GY85_SetGyro();
}
// ---------------- Update All Sensors ---------------- //
bool GY85_Update(GY85_t *imu)
{
GY85_t next_sample;
if (imu == NULL) {
return false;
}
next_sample = *imu;
if (!GY85_ReadAccelerometer(&next_sample)) {
return false;
}
if (!GY85_ReadCompass(&next_sample)) {
return false;
}
if (!GY85_ReadGyro(&next_sample)) {
return false;
}
*imu = next_sample;
return true;
}
// ---------------- Accelerometer ---------------- //
static bool GY85_SetAccelerometer(void)
{
if (!GY85_WriteRegister(ADXL345_ADDR, 0x31, 0x01)) {
return false;
}
return GY85_WriteRegister(ADXL345_ADDR, 0x2D, 0x08);
}
static bool GY85_ReadAccelerometer(GY85_t *imu)
{
uint8_t buf[6];
if (imu == NULL || !GY85_ReadRegisters(ADXL345_ADDR, 0x32, buf, sizeof(buf))) {
return false;
}
imu->ax = (int16_t)((buf[1] << 8) | buf[0]);
imu->ay = (int16_t)((buf[3] << 8) | buf[2]);
imu->az = (int16_t)((buf[5] << 8) | buf[4]);
return true;
}
// ---------------- Compass ---------------- //
static bool GY85_SetCompass(void)
{
return GY85_WriteRegister(HMC5883_ADDR, 0x02, 0x00);
}
static bool GY85_ReadCompass(GY85_t *imu)
{
uint8_t buf[6];
if (imu == NULL || !GY85_ReadRegisters(HMC5883_ADDR, 0x03, buf, sizeof(buf))) {
return false;
}
imu->mx = (int16_t)((buf[0] << 8) | buf[1]);
imu->mz = (int16_t)((buf[2] << 8) | buf[3]);
imu->my = (int16_t)((buf[4] << 8) | buf[5]);
return true;
}
// ---------------- Gyroscope ---------------- //
static bool GY85_SetGyro(void)
{
if (!GY85_WriteRegister(ITG3200_ADDR, 0x3E, 0x00)) {
return false;
}
if (!GY85_WriteRegister(ITG3200_ADDR, 0x15, 0x07)) {
return false;
}
if (!GY85_WriteRegister(ITG3200_ADDR, 0x16, 0x1E)) {
return false;
}
if (!GY85_WriteRegister(ITG3200_ADDR, 0x17, 0x00)) {
return false;
}
HAL_Delay(10);
return GY85_GyroCalibrate();
}
static bool GY85_GyroCalibrate(void)
{
int32_t tmpx = 0, tmpy = 0, tmpz = 0;
GY85_t imu;
static int16_t g_offx = 0, g_offy = 0, g_offz = 0; for(uint8_t i = 0; i < 10; i++)
{
// ---------------- Internal Functions ---------------- // HAL_Delay(10);
static void GY85_SetAccelerometer(void); if (!GY85_ReadGyro(&imu)) {
static void GY85_ReadAccelerometer(GY85_t *imu); return false;
static void GY85_SetCompass(void); }
static void GY85_ReadCompass(GY85_t *imu); tmpx += imu.gx;
static void GY85_SetGyro(void); tmpy += imu.gy;
static void GY85_GyroCalibrate(void); tmpz += imu.gz;
static void GY85_ReadGyro(GY85_t *imu);
// ---------------- Initialization ---------------- //
void GY85_Init(void)
{
GY85_SetAccelerometer();
GY85_SetCompass();
GY85_SetGyro();
}
// ---------------- Update All Sensors ---------------- //
void GY85_Update(GY85_t *imu)
{
GY85_ReadAccelerometer(imu);
GY85_ReadCompass(imu);
GY85_ReadGyro(imu);
}
// ---------------- Accelerometer ---------------- //
static void GY85_SetAccelerometer(void)
{
uint8_t data[2];
data[0] = 0x31; data[1] = 0x01;
HAL_I2C_Master_Transmit(&hi2c3, ADXL345_ADDR, data, 2, HAL_MAX_DELAY);
data[0] = 0x2D; data[1] = 0x08;
HAL_I2C_Master_Transmit(&hi2c3, ADXL345_ADDR, data, 2, HAL_MAX_DELAY);
}
static void GY85_ReadAccelerometer(GY85_t *imu)
{
uint8_t reg = 0x32;
uint8_t buf[6];
HAL_I2C_Master_Transmit(&hi2c3, ADXL345_ADDR, &reg, 1, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(&hi2c3, ADXL345_ADDR, buf, 6, HAL_MAX_DELAY);
imu->ax = (int16_t)((buf[1] << 8) | buf[0]);
imu->ay = (int16_t)((buf[3] << 8) | buf[2]);
imu->az = (int16_t)((buf[5] << 8) | buf[4]);
}
// ---------------- Compass ---------------- //
static void GY85_SetCompass(void)
{
uint8_t data[2] = {0x02, 0x00};
HAL_I2C_Master_Transmit(&hi2c3, HMC5883_ADDR, data, 2, HAL_MAX_DELAY);
}
static void GY85_ReadCompass(GY85_t *imu)
{
uint8_t reg = 0x03;
uint8_t buf[6];
HAL_I2C_Master_Transmit(&hi2c3, HMC5883_ADDR, &reg, 1, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(&hi2c3, HMC5883_ADDR, buf, 6, HAL_MAX_DELAY);
imu->mx = (int16_t)((buf[0] << 8) | buf[1]);
imu->mz = (int16_t)((buf[2] << 8) | buf[3]);
imu->my = (int16_t)((buf[4] << 8) | buf[5]);
}
// ---------------- Gyroscope ---------------- //
static void GY85_SetGyro(void)
{
uint8_t data[2];
data[0] = 0x3E; data[1] = 0x00;
HAL_I2C_Master_Transmit(&hi2c3, ITG3200_ADDR, data, 2, HAL_MAX_DELAY);
data[0] = 0x15; data[1] = 0x07;
HAL_I2C_Master_Transmit(&hi2c3, ITG3200_ADDR, data, 2, HAL_MAX_DELAY);
data[0] = 0x16; data[1] = 0x1E;
HAL_I2C_Master_Transmit(&hi2c3, ITG3200_ADDR, data, 2, HAL_MAX_DELAY);
data[0] = 0x17; data[1] = 0x00;
HAL_I2C_Master_Transmit(&hi2c3, ITG3200_ADDR, data, 2, HAL_MAX_DELAY);
HAL_Delay(10);
GY85_GyroCalibrate();
}
static void GY85_GyroCalibrate(void)
{
int32_t tmpx = 0, tmpy = 0, tmpz = 0;
GY85_t imu;
for(uint8_t i = 0; i < 10; i++)
{
HAL_Delay(10);
GY85_ReadGyro(&imu);
tmpx += imu.gx;
tmpy += imu.gy;
tmpz += imu.gz;
} }
g_offx = tmpx / 10; g_offx = tmpx / 10;
g_offy = tmpy / 10; g_offy = tmpy / 10;
g_offz = tmpz / 10; g_offz = tmpz / 10;
} return true;
}
static void GY85_ReadGyro(GY85_t *imu)
{ static bool GY85_ReadGyro(GY85_t *imu)
uint8_t reg = 0x1B; {
uint8_t buf[8]; uint8_t buf[8];
HAL_I2C_Master_Transmit(&hi2c3, ITG3200_ADDR, &reg, 1, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(&hi2c3, ITG3200_ADDR, buf, 8, HAL_MAX_DELAY); if (imu == NULL || !GY85_ReadRegisters(ITG3200_ADDR, 0x1B, buf, sizeof(buf))) {
return false;
imu->gx = ((int16_t)((buf[2] << 8) | buf[3])) - g_offx; }
imu->gy = ((int16_t)((buf[4] << 8) | buf[5])) - g_offy;
imu->gz = ((int16_t)((buf[6] << 8) | buf[7])) - g_offz; imu->gx = ((int16_t)((buf[2] << 8) | buf[3])) - g_offx;
} imu->gy = ((int16_t)((buf[4] << 8) | buf[5])) - g_offy;
imu->gz = ((int16_t)((buf[6] << 8) | buf[7])) - g_offz;
return true;
}
static bool GY85_WriteRegister(uint16_t address, uint8_t reg, uint8_t value)
{
uint8_t data[2] = {reg, value};
return HAL_I2C_Master_Transmit(&hi2c3, address, data, sizeof(data), HAL_MAX_DELAY) == HAL_OK;
}
static bool GY85_ReadRegisters(uint16_t address, uint8_t reg, uint8_t *buffer, uint16_t length)
{
if (buffer == NULL) {
return false;
}
if (HAL_I2C_Master_Transmit(&hi2c3, address, &reg, 1, HAL_MAX_DELAY) != HAL_OK) {
return false;
}
return HAL_I2C_Master_Receive(&hi2c3, address, buffer, length, HAL_MAX_DELAY) == HAL_OK;
}
@@ -2,6 +2,7 @@
#define __GY_85_HAL_H__ #define __GY_85_HAL_H__
#include "stm32f7xx_hal.h" // change depending on MCU family #include "stm32f7xx_hal.h" // change depending on MCU family
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#define ADXL345_ADDR (0x53 << 1) #define ADXL345_ADDR (0x53 << 1)
@@ -18,8 +19,8 @@ typedef struct {
} GY85_t; } GY85_t;
// Public API // Public API
void GY85_Init(void); bool GY85_Init(void);
void GY85_Update(GY85_t *imu); // reads all sensors and stores in struct bool GY85_Update(GY85_t *imu); // reads all sensors and stores in struct
#endif #endif
@@ -1,6 +1,7 @@
// gps_handler.cpp // gps_handler.cpp
#include "gps_handler.h" #include "gps_handler.h"
#include <cmath> #include <cmath>
#include <cstdio>
// UART handle for communication with GUI // UART handle for communication with GUI
static UART_HandleTypeDef* gui_huart = NULL; static UART_HandleTypeDef* gui_huart = NULL;
@@ -14,40 +15,46 @@ void GPS_Init(UART_HandleTypeDef* huart)
memset(&current_gps, 0, sizeof(GPS_Data_t)); memset(&current_gps, 0, sizeof(GPS_Data_t));
} }
uint8_t GPS_IsDataValid(GPS_Data_t* gps_data) uint8_t GPS_IsDataValid(GPS_Data_t* gps_data)
{ {
// Check if GPS data is within valid ranges if (gps_data == NULL) {
if (gps_data->latitude < -90.0 || gps_data->latitude > 90.0) return 0;
return 0; }
// Check if GPS data is within valid ranges
if (gps_data->latitude < -90.0 || gps_data->latitude > 90.0)
return 0;
if (gps_data->longitude < -180.0 || gps_data->longitude > 180.0) if (gps_data->longitude < -180.0 || gps_data->longitude > 180.0)
return 0; return 0;
if (gps_data->altitude < -1000.0 || gps_data->altitude > 10000.0) // -1km to 10km if (gps_data->altitude < -1000.0 || gps_data->altitude > 10000.0) // -1km to 10km
return 0; return 0;
return 1; return 1;
} }
void GPS_ProcessData(GPS_Data_t* gps_data) bool GPS_ProcessData(GPS_Data_t* gps_data)
{ {
// Validate GPS data // Validate GPS data
if (!GPS_IsDataValid(gps_data)) { if (!GPS_IsDataValid(gps_data)) {
return; return false;
} }
// Update current GPS data // Update current GPS data
memcpy(&current_gps, gps_data, sizeof(GPS_Data_t)); memcpy(&current_gps, gps_data, sizeof(GPS_Data_t));
current_gps.timestamp = HAL_GetTick(); current_gps.timestamp = HAL_GetTick();
// Send to GUI // Send to GUI
GPS_SendToGUI(&current_gps); return GPS_SendToGUI(&current_gps);
} }
void GPS_SendToGUI(GPS_Data_t* gps_data) bool GPS_SendToGUI(GPS_Data_t* gps_data)
{ {
if (gui_huart == NULL) return; if (gui_huart == NULL || gps_data == NULL) {
return false;
// Create packet: "GPS:lat,lon,alt\r\n" }
char buffer[64];
// Create packet: "GPS:lat,lon,alt\r\n"
char buffer[64];
// Convert double and float to string with high precision // Convert double and float to string with high precision
int len = snprintf(buffer, sizeof(buffer), "GPS:%.8f,%.8f,%.2f\r\n", int len = snprintf(buffer, sizeof(buffer), "GPS:%.8f,%.8f,%.2f\r\n",
@@ -55,19 +62,23 @@ void GPS_SendToGUI(GPS_Data_t* gps_data)
gps_data->longitude, gps_data->longitude,
gps_data->altitude); gps_data->altitude);
if (len > 0 && len < (int)sizeof(buffer)) { if (len <= 0 || len >= (int)sizeof(buffer)) {
// Send via UART3 to GUI return false;
HAL_UART_Transmit(gui_huart, (uint8_t*)buffer, len, 1000); }
}
} // Send via UART3 to GUI
return HAL_UART_Transmit(gui_huart, (uint8_t*)buffer, len, 1000) == HAL_OK;
// Alternative binary protocol version (more efficient) }
void GPS_SendBinaryToGUI(GPS_Data_t* gps_data)
{ // Alternative binary protocol version (more efficient)
if (gui_huart == NULL) return; bool GPS_SendBinaryToGUI(GPS_Data_t* gps_data)
{
// Binary packet structure: if (gui_huart == NULL || gps_data == NULL) {
// [Header 4 bytes][Latitude 8 bytes][Longitude 8 bytes][Altitude 4 bytes][Pitch 4 bytes][CRC 2 bytes] return false;
}
// Binary packet structure:
// [Header 4 bytes][Latitude 8 bytes][Longitude 8 bytes][Altitude 4 bytes][Pitch 4 bytes][CRC 2 bytes]
uint8_t packet[30]; // 4 + 8 + 8 + 4 + 4 + 2 = 30 bytes uint8_t packet[30]; // 4 + 8 + 8 + 4 + 4 + 2 = 30 bytes
uint16_t crc = 0; uint16_t crc = 0;
@@ -99,10 +110,10 @@ void GPS_SendBinaryToGUI(GPS_Data_t* gps_data)
packet[20 + i] = (alt_bits >> (24 - i*8)) & 0xFF; packet[20 + i] = (alt_bits >> (24 - i*8)) & 0xFF;
} }
// Convert float altitude to bytes (big-endian) // Convert float pitch to bytes (big-endian)
uint32_t pitch_bits; uint32_t pitch_bits;
memcpy(&pitch_bits, &gps_data->pitch, sizeof(float)); memcpy(&pitch_bits, &gps_data->pitch, sizeof(float));
for(int i = 0; i < 4; i++) { for(int i = 0; i < 4; i++) {
packet[24 + i] = (pitch_bits >> (24 - i*8)) & 0xFF; packet[24 + i] = (pitch_bits >> (24 - i*8)) & 0xFF;
} }
@@ -112,8 +123,8 @@ void GPS_SendBinaryToGUI(GPS_Data_t* gps_data)
} }
packet[28] = (crc >> 8) & 0xFF; packet[28] = (crc >> 8) & 0xFF;
packet[29] = crc & 0xFF; packet[29] = crc & 0xFF;
// Send binary packet // Send binary packet
CDC_Transmit_FS(packet, sizeof(packet)); return CDC_Transmit_FS(packet, sizeof(packet)) == USBD_OK;
} }
@@ -3,10 +3,11 @@
#define GPS_HANDLER_H #define GPS_HANDLER_H
#include "main.h" #include "main.h"
#include "usb_device.h" #include "usb_device.h"
#include "usbd_cdc_if.h" #include "usbd_cdc_if.h"
#include <stdint.h> #include <stdbool.h>
#include <string.h> #include <stdint.h>
#include <string.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -20,11 +21,11 @@ typedef struct {
uint32_t timestamp; uint32_t timestamp;
} GPS_Data_t; } GPS_Data_t;
void GPS_Init(UART_HandleTypeDef* huart); void GPS_Init(UART_HandleTypeDef* huart);
void GPS_ProcessData(GPS_Data_t* gps_data); bool GPS_ProcessData(GPS_Data_t* gps_data);
void GPS_SendToGUI(GPS_Data_t* gps_data); bool GPS_SendToGUI(GPS_Data_t* gps_data);
void GPS_SendBinaryToGUI(GPS_Data_t* gps_data); bool GPS_SendBinaryToGUI(GPS_Data_t* gps_data);
uint8_t GPS_IsDataValid(GPS_Data_t* gps_data); uint8_t GPS_IsDataValid(GPS_Data_t* gps_data);
#ifdef __cplusplus #ifdef __cplusplus
} }
@@ -617,14 +617,13 @@ SystemError_t checkSystemHealth(void) {
} }
} }
// 4. Check IMU Communication // 4. Check IMU Communication
static uint32_t last_imu_check = 0; static uint32_t last_imu_check = 0;
if (HAL_GetTick() - last_imu_check > 10000) { if (HAL_GetTick() - last_imu_check > 10000) {
GY85_Update(&imu); if (!GY85_Update(&imu)) {
if (isnan(imu.ax) || isnan(imu.ay) || isnan(imu.az)) { current_error = ERROR_IMU_COMM;
current_error = ERROR_IMU_COMM; }
} last_imu_check = HAL_GetTick();
last_imu_check = HAL_GetTick();
} }
// 5. Check BMP180 Communication // 5. Check BMP180 Communication
@@ -1274,14 +1273,18 @@ int main(void)
HAL_Delay(100); HAL_Delay(100);
HAL_GPIO_WritePin(EN_P_3V3_FPGA_GPIO_Port,EN_P_3V3_FPGA_Pin,GPIO_PIN_SET); HAL_GPIO_WritePin(EN_P_3V3_FPGA_GPIO_Port,EN_P_3V3_FPGA_Pin,GPIO_PIN_SET);
HAL_Delay(100); HAL_Delay(100);
// Initialize module IMU // Initialize module IMU
GY85_Init(); if (!GY85_Init()) {
for(int i=0; i<10;i++){ Error_Handler();
GY85_Update(&imu); }
for(int i=0; i<10;i++){
ax = imu.ax; if (!GY85_Update(&imu)) {
Error_Handler();
}
ax = imu.ax;
ay = imu.ay; ay = imu.ay;
az = imu.az; az = imu.az;
gx = -imu.gx; gx = -imu.gx;
@@ -1524,11 +1527,14 @@ int main(void)
/**********wait for GUI start flag and Send Lat/Long/alt********/ /**********wait for GUI start flag and Send Lat/Long/alt********/
/***************************************************************/ /***************************************************************/
GPS_Data_t gps_data; GPS_Data_t gps_data;
// Binary packet structure: // Binary packet structure:
// [Header 4 bytes][Latitude 8 bytes][Longitude 8 bytes][Altitude 4 bytes][CRC 2 bytes] // [Header 4 bytes][Latitude 8 bytes][Longitude 8 bytes][Altitude 4 bytes][Pitch 4 bytes][CRC 2 bytes]
gps_data = {RADAR_Latitude, RADAR_Longitude, RADAR_Altitude, Pitch_Sensor, HAL_GetTick()}; gps_data = {RADAR_Latitude, RADAR_Longitude, RADAR_Altitude, Pitch_Sensor, HAL_GetTick()};
GPS_SendBinaryToGUI(&gps_data); if (!GPS_SendBinaryToGUI(&gps_data)) {
const uint8_t gps_send_error[] = "GPS binary send failed\r\n";
HAL_UART_Transmit(&huart3, (uint8_t*)gps_send_error, sizeof(gps_send_error) - 1, 1000);
}
// Check if start flag was received and settings are ready // Check if start flag was received and settings are ready
do{ do{
+77 -33
View File
@@ -47,10 +47,23 @@ DARK_ACCENT = "#3c3f41"
DARK_HIGHLIGHT = "#4e5254" DARK_HIGHLIGHT = "#4e5254"
DARK_BORDER = "#555555" DARK_BORDER = "#555555"
DARK_TEXT = "#cccccc" DARK_TEXT = "#cccccc"
DARK_BUTTON = "#3c3f41" DARK_BUTTON = "#3c3f41"
DARK_BUTTON_HOVER = "#4e5254" DARK_BUTTON_HOVER = "#4e5254"
DARK_TREEVIEW = "#3c3f41" DARK_TREEVIEW = "#3c3f41"
DARK_TREEVIEW_ALT = "#404040" DARK_TREEVIEW_ALT = "#404040"
RADAR_SETTINGS_LIMITS = {
'system_frequency': (1e9, 100e9),
'chirp_duration_1': (1e-6, 1000e-6),
'chirp_duration_2': (0.1e-6, 10e-6),
'chirps_per_position': (1, 256),
'freq_min': (1e6, 100e6),
'freq_max': (1e6, 100e6),
'prf1': (100, 10000),
'prf2': (100, 10000),
'max_distance': (100, 100000),
'map_size': (1000, 200000),
}
@dataclass @dataclass
class RadarTarget: class RadarTarget:
@@ -1125,10 +1138,10 @@ class RadarGUI:
self.map_info_label = ttk.Label(info_frame, text="No GPS data received yet", font=('Arial', 10)) self.map_info_label = ttk.Label(info_frame, text="No GPS data received yet", font=('Arial', 10))
self.map_info_label.pack() self.map_info_label.pack()
def setup_settings_tab(self): def setup_settings_tab(self):
"""Setup the settings tab with additional chirp durations and map size""" """Setup the settings tab with additional chirp durations and map size"""
settings_frame = ttk.Frame(self.tab_settings) settings_frame = ttk.Frame(self.tab_settings)
settings_frame.pack(fill='both', expand=True, padx=10, pady=10) settings_frame.pack(fill='both', expand=True, padx=10, pady=10)
entries = [ entries = [
('System Frequency (Hz):', 'system_frequency', 10e9), ('System Frequency (Hz):', 'system_frequency', 10e9),
@@ -1153,8 +1166,40 @@ class RadarGUI:
entry.grid(row=i, column=1, padx=5, pady=5) entry.grid(row=i, column=1, padx=5, pady=5)
self.settings_vars[attr] = var self.settings_vars[attr] = var
ttk.Button(settings_frame, text="Apply Settings", ttk.Button(settings_frame, text="Apply Settings",
command=self.apply_settings).grid(row=len(entries), column=0, columnspan=2, pady=10) command=self.apply_settings).grid(row=len(entries), column=0, columnspan=2, pady=10)
def _parse_settings_from_form(self):
"""Read settings from the UI and return a validated RadarSettings instance."""
parsed_settings = RadarSettings(
system_frequency=float(self.settings_vars['system_frequency'].get()),
chirp_duration_1=float(self.settings_vars['chirp_duration_1'].get()),
chirp_duration_2=float(self.settings_vars['chirp_duration_2'].get()),
chirps_per_position=int(self.settings_vars['chirps_per_position'].get()),
freq_min=float(self.settings_vars['freq_min'].get()),
freq_max=float(self.settings_vars['freq_max'].get()),
prf1=float(self.settings_vars['prf1'].get()),
prf2=float(self.settings_vars['prf2'].get()),
max_distance=float(self.settings_vars['max_distance'].get()),
map_size=float(self.settings_vars['map_size'].get()),
)
self._validate_radar_settings(parsed_settings)
return parsed_settings
def _validate_radar_settings(self, settings):
"""Mirror the firmware-side range checks before sending settings to STM32."""
for field_name, (minimum, maximum) in RADAR_SETTINGS_LIMITS.items():
value = getattr(settings, field_name)
if value < minimum or value > maximum:
raise ValueError(
f"{field_name} must be between {minimum:g} and {maximum:g}."
)
if settings.freq_max <= settings.freq_min:
raise ValueError("freq_max must be greater than freq_min.")
return True
def apply_pitch_correction(self, raw_elevation, pitch_angle): def apply_pitch_correction(self, raw_elevation, pitch_angle):
""" """
@@ -1262,29 +1307,28 @@ class RadarGUI:
logging.info("Radar system stopped") logging.info("Radar system stopped")
def apply_settings(self): def apply_settings(self):
"""Step 13: Apply and send radar settings via USB""" """Step 13: Apply and send radar settings via USB"""
try: try:
self.settings.system_frequency = float(self.settings_vars['system_frequency'].get()) parsed_settings = self._parse_settings_from_form()
self.settings.chirp_duration_1 = float(self.settings_vars['chirp_duration_1'].get()) self.google_maps_api_key = self.settings_vars['google_maps_api_key'].get()
self.settings.chirp_duration_2 = float(self.settings_vars['chirp_duration_2'].get())
self.settings.chirps_per_position = int(self.settings_vars['chirps_per_position'].get()) self.settings = parsed_settings
self.settings.freq_min = float(self.settings_vars['freq_min'].get())
self.settings.freq_max = float(self.settings_vars['freq_max'].get()) if self.stm32_usb_interface.is_open:
self.settings.prf1 = float(self.settings_vars['prf1'].get()) if not self.stm32_usb_interface.send_settings(self.settings):
self.settings.prf2 = float(self.settings_vars['prf2'].get()) messagebox.showerror("Error", "Failed to send settings to STM32 via USB")
self.settings.max_distance = float(self.settings_vars['max_distance'].get()) logging.error("Radar settings validation passed, but USB send failed")
self.settings.map_size = float(self.settings_vars['map_size'].get()) return
self.google_maps_api_key = self.settings_vars['google_maps_api_key'].get()
messagebox.showinfo("Success", "Settings applied and sent to STM32 via USB")
if self.stm32_usb_interface.is_open: logging.info("Radar settings applied and sent via USB")
self.stm32_usb_interface.send_settings(self.settings) else:
messagebox.showinfo("Success", "Settings applied locally")
messagebox.showinfo("Success", "Settings applied and sent to STM32 via USB") logging.info("Radar settings applied locally; STM32 USB is not connected")
logging.info("Radar settings applied via USB")
except ValueError as e:
except ValueError as e: messagebox.showerror("Error", f"Invalid setting value: {e}")
messagebox.showerror("Error", f"Invalid setting value: {e}")
def start_background_threads(self): def start_background_threads(self):
"""Start background data processing threads""" """Start background data processing threads"""
+154
View File
@@ -0,0 +1,154 @@
CERN Open Hardware Licence Version 2 - Permissive
Preamble
CERN has developed this licence to promote collaboration among
hardware designers and to provide a legal tool for the dissemination
of hardware designs. The CERN Open Hardware Licence Version 2 is
available in two variants: Weakly Reciprocal (CERN-OHL-W) and
Permissive (CERN-OHL-P). The CERN-OHL-P is for you if you want to
maximise the ability of people to use your hardware design
including for use in commercial applications with a minimum of
obligations. It is a continuation of the CERN Open Hardware Licence
version 1 (but with a new structure) and is focused more narrowly
on the design itself and what you must do to give proper credit and
to allow others to build and modify the design.
Please see the CERN-OHL version 2 family page (www.ohwr.org/cernohl)
for more information.
Terms and conditions
1. Definitions
In this Licence, the following terms have the following meanings:
“Additive” means something you add to the Design that was not part
of it when it was first published by the Licensor.
“Design” means the design documentation for the hardware that is
licensed under this Licence, in any format or medium. It may
include both the Hardware Description and the Modifications.
“Documentation” means all the materials that are provided by the
Licensor or any Contributor to describe the Design, including
schematics, netlists, PCB layout files, bills of materials,
drawings, specifications, and the like, and also includes the
Modifications.
“Hardware” means any physical device that embodies the Design or
any part thereof, in any form.
“Hardware Description” means the files that specify the Hardware in
a form that can be read by a computer and that, when used
appropriately, can be used to fabricate Hardware, for example in
whole or in part.
“Licence” means this licence (the CERN-OHL-P).
“Licensor” means the person or entity that first publishes the
Design under the terms of this Licence.
“Modification” means any change to the Design, including changes to
the Hardware Description.
“Product” means either an unchanged Design or a Design with
Modifications, that is offered for sale, or otherwise made
available for commercial use, whether as Hardware or in other forms.
“Source” means the format of the Design that is preferred for
making Modifications, including all the files that are provided for
that purpose.
“You” means any person or entity that exercises any right under
this Licence.
2. What this Licence covers
The Licensor grants you a worldwide, royalty-free, non-exclusive,
perpetual licence to:
a) use the Design and any associated Documentation,
b) make Modifications,
c) communicate the Design and any Documentation, including by
making it available for copying and modification,
d) manufacture and distribute Hardware that implements the Design
or any part thereof,
e) sell Products, and
f) otherwise deal in the Design or any part thereof,
all in each case subject to the conditions set out in this Licence.
3. Conditions
3.1. Availability of Source
The Design and any Documentation that is made available under this
Licence must be made available in Source format. If the Design is
available in a format that is not Source, you must also make a
version of the Design in Source format available, and you must
inform others of how to obtain it.
3.2. Retention of copyright and other notices
You must retain all copyright and other notices that appear in the
Design or Documentation.
3.3. Notice of Modifications
If you make Modifications, you must include a notice in any
Distribution of the Design or Documentation, stating that
Modifications have been made, by whom, and in what they consist.
3.4. Distribution of Modifications
If you distribute any Design or Documentation, whether unchanged or
with Modifications, you must distribute it under this Licence, and
you must inform the recipient that the Design or Documentation is
licensed under this Licence.
3.5. No implicit approval
The Licensor shall not be taken to have approved any Modifications
unless the Licessor expressly approves them in writing.
4. Disclaimer of warranty
THE DESIGN AND ANY DOCUMENTATION IS PROVIDED "AS IS" AND THE
LICENSOR MAKES NO WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
NON-INFRINGEMENT, TITLE, AND FITNESS FOR A PARTICULAR PURPOSE. THE
DESIGN MAY CONTAIN DESIGN DEFECTS OR ERRORS THAT MAKE IT
UNSUITABLE FOR USE IN CERTAIN APPLICATIONS. THE ENTIRE RISK AS TO
ITS QUALITY AND PERFORMANCE REMAINS WITH YOU.
5. Limitation of liability
TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT WILL THE LICENSOR
BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION
LOST PROFITS, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR ANY
OTHER LOSSES ARISING OUT OF THE USE OF THE DESIGN OR ANY
DOCUMENTATION, HOWEVER CAUSED, WHETHER UNDER THEORY OF CONTRACT,
TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY, OR OTHERWISE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
6. Termination
This Licence is perpetual except that if you fail to comply with
its terms, your rights under this Licence will terminate immediately.
If you bring or defend any litigation or other claim alleging that
the Design or any part thereof infringes any intellectual property
right, all your rights under this Licence granted by the Licensor
will terminate forty-five days after you bring or defend such claim.
7. General
This Licence shall be governed by the laws of the country of the
Licensor, without reference to its conflict of laws provisions.
If any part of this Licence is held to be invalid or unenforceable,
the remaining parts shall remain in full force and effect.
---------------------------------------------------------------------
CERN-OHL-P is a variant of the CERN-OHL family. For more information
see www.ohwr.org/cernohl.
+40 -1
View File
@@ -1,6 +1,7 @@
# AERIS-10: Open Source Pulse Linear Frequency Modulated Phased Array Radar # AERIS-10: Open Source Pulse Linear Frequency Modulated Phased Array Radar
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Hardware: CERN-OHL-P](https://img.shields.io/badge/Hardware-CERN--OHL--P-blue.svg)](https://ohwr.org/cern_ohl_p_v2.txt)
[![Software: MIT](https://img.shields.io/badge/Software-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Status: Alpha](https://img.shields.io/badge/Status-Alpha-orange)](https://github.com/NawfalMotii79/PLFM_RADAR) [![Status: Alpha](https://img.shields.io/badge/Status-Alpha-orange)](https://github.com/NawfalMotii79/PLFM_RADAR)
[![Frequency: 10.5GHz](https://img.shields.io/badge/Frequency-10.5GHz-blue)](https://github.com/NawfalMotii79/PLFM_RADAR)) [![Frequency: 10.5GHz](https://img.shields.io/badge/Frequency-10.5GHz-blue)](https://github.com/NawfalMotii79/PLFM_RADAR))
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/NawfalMotii79/PLFM_RADAR/pulls) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/NawfalMotii79/PLFM_RADAR/pulls)
@@ -142,3 +143,41 @@ The AERIS-10 main sub-systems are:
4. **Antenna**: Choose appropriate array for your version 4. **Antenna**: Choose appropriate array for your version
5. **Enclosure**: 3D printable files in `/10_docs/Hardware/Enclosure` 5. **Enclosure**: 3D printable files in `/10_docs/Hardware/Enclosure`
## 📜 License
This project is open-source but uses **different licenses for hardware and software** to ensure proper legal coverage.
### Hardware Documentation
The hardware design files—including:
- Schematics and PCB layouts (in `/4_Schematics and Boards Layout`)
- Bill of Materials (BOM) files
- Gerber files and manufacturing outputs
- Mechanical drawings and enclosure designs
are licensed under the **CERN Open Hardware Licence Version 2 Permissive (CERN-OHL-P)** .
This is a hardware-specific license that:
- ✅ Clearly defines "Hardware," "Documentation," and "Products"
- ✅ Includes explicit patent protection for contributors and users
- ✅ Provides stronger liability limitations (important for high-power RF)
- ✅ Aligns with professional open-hardware standards (CERN, OSHWA)
You may use, modify, and sell products based on these designs, provided you:
- Maintain the original copyright notices
- Distribute any modified designs under the same license
- Make your modifications available in Source format
### Software and Firmware
The software components—including:
- FPGA code (VHDL/Verilog in `/9_Firmware`)
- Microcontroller firmware (STM32)
- Python GUI and utilities
remain under the **MIT License** for maximum flexibility.
### Full License Texts
- The complete CERN-OHL-P license text is in the `LICENSE` file
- MIT license terms apply to software where not otherwise specified
### Why This Change?
Originally, the entire project used the MIT license. The community (special thanks to [GitHub Username]!) pointed out that MIT lacks legal protections needed for physical hardware. The switch to CERN-OHL-P ensures the project is properly protected while maintaining the same permissive spirit.