Merge branch 'main' of https://github.com/NawfalMotii79/PLFM_RADAR
This commit is contained in:
@@ -13,10 +13,10 @@ 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
|
||||||
@@ -164,10 +164,10 @@ bool ADAR1000Manager::setBeamAngle(float angle_degrees, BeamDirection direction)
|
|||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -329,11 +329,11 @@ bool ADAR1000Manager::initializeADTR1107Sequence() {
|
|||||||
// 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
|
||||||
@@ -341,21 +341,21 @@ bool ADAR1000Manager::initializeADTR1107Sequence() {
|
|||||||
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);
|
||||||
@@ -365,9 +365,7 @@ bool ADAR1000Manager::initializeADTR1107Sequence() {
|
|||||||
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_GPIO_WritePin(GPIOG, GPIO_PIN_2, GPIO_PIN_SET);
|
|
||||||
HAL_Delay(50);
|
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
|
||||||
@@ -375,7 +373,7 @@ bool ADAR1000Manager::initializeADTR1107Sequence() {
|
|||||||
/*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);
|
||||||
@@ -433,23 +431,21 @@ void ADAR1000Manager::setADTR1107Mode(BeamDirection direction) {
|
|||||||
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_GPIO_WritePin(GPIOG, GPIO_PIN_2, GPIO_PIN_SET);
|
|
||||||
HAL_Delay(10);
|
HAL_Delay(10);
|
||||||
|
|
||||||
// Step 4: Set PA bias to operational value
|
// Step 4: Set PA bias to operational value
|
||||||
uint8_t operational_pa_bias = 0x7F; // Maximum bias for full power
|
uint8_t operational_pa_bias = kPaBiasOperational; // Maximum bias for full power
|
||||||
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, 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_CH2_BIAS_ON, operational_pa_bias, BROADCAST_OFF);
|
||||||
@@ -469,13 +465,11 @@ void ADAR1000Manager::setADTR1107Mode(BeamDirection direction) {
|
|||||||
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_GPIO_WritePin(GPIOG, GPIO_PIN_2, GPIO_PIN_RESET);
|
|
||||||
HAL_Delay(5);
|
HAL_Delay(5);
|
||||||
|
|
||||||
// Step 2: Set PA bias to safe negative voltage
|
// Step 2: Set PA bias to safe negative voltage
|
||||||
uint8_t safe_pa_bias = 0x20;
|
uint8_t safe_pa_bias = kPaBiasRxSafe;
|
||||||
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);
|
||||||
@@ -485,11 +479,11 @@ void ADAR1000Manager::setADTR1107Mode(BeamDirection direction) {
|
|||||||
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);
|
||||||
}
|
}
|
||||||
@@ -536,27 +530,27 @@ bool ADAR1000Manager::setCustomBeamPattern16(const uint8_t phase_pattern[16], Be
|
|||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
@@ -567,7 +561,7 @@ void ADAR1000Manager::setPABias(bool enable) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
@@ -740,8 +734,8 @@ void ADAR1000Manager::adarSetTxVgaGain(uint8_t deviceIndex, uint8_t channel, uin
|
|||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -121,6 +121,18 @@ public:
|
|||||||
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];
|
||||||
|
|
||||||
|
// Named defaults for the ADTR1107 and ADAR1000 power sequence.
|
||||||
|
static constexpr uint8_t kDefaultTxVgaGain = 0x7F;
|
||||||
|
static constexpr uint8_t kDefaultRxVgaGain = 30;
|
||||||
|
static constexpr uint8_t kLnaBiasOff = 0x00;
|
||||||
|
static constexpr uint8_t kLnaBiasOperational = 0x30;
|
||||||
|
static constexpr uint8_t kPaBiasTxSafe = 0x5D;
|
||||||
|
static constexpr uint8_t kPaBiasIdqCalibration = 0x0D;
|
||||||
|
static constexpr uint8_t kPaBiasOperational = 0x7F;
|
||||||
|
static constexpr uint8_t kPaBiasRxSafe = 0x20;
|
||||||
|
static constexpr uint8_t kTxBiasCurrent = 0x2D;
|
||||||
|
static constexpr uint8_t kTxDriverBiasCurrent = 0x06;
|
||||||
|
|
||||||
// Private Methods
|
// Private Methods
|
||||||
bool initializeSingleDevice(uint8_t deviceIndex);
|
bool initializeSingleDevice(uint8_t deviceIndex);
|
||||||
bool initializeADTR1107Sequence();
|
bool initializeADTR1107Sequence();
|
||||||
|
|||||||
@@ -3,93 +3,121 @@
|
|||||||
static int16_t g_offx = 0, g_offy = 0, g_offz = 0;
|
static int16_t g_offx = 0, g_offy = 0, g_offz = 0;
|
||||||
|
|
||||||
// ---------------- Internal Functions ---------------- //
|
// ---------------- Internal Functions ---------------- //
|
||||||
static void GY85_SetAccelerometer(void);
|
static bool GY85_SetAccelerometer(void);
|
||||||
static void GY85_ReadAccelerometer(GY85_t *imu);
|
static bool GY85_ReadAccelerometer(GY85_t *imu);
|
||||||
static void GY85_SetCompass(void);
|
static bool GY85_SetCompass(void);
|
||||||
static void GY85_ReadCompass(GY85_t *imu);
|
static bool GY85_ReadCompass(GY85_t *imu);
|
||||||
static void GY85_SetGyro(void);
|
static bool GY85_SetGyro(void);
|
||||||
static void GY85_GyroCalibrate(void);
|
static bool GY85_GyroCalibrate(void);
|
||||||
static void GY85_ReadGyro(GY85_t *imu);
|
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 ---------------- //
|
// ---------------- Initialization ---------------- //
|
||||||
void GY85_Init(void)
|
bool GY85_Init(void)
|
||||||
{
|
{
|
||||||
GY85_SetAccelerometer();
|
if (!GY85_SetAccelerometer()) {
|
||||||
GY85_SetCompass();
|
return false;
|
||||||
GY85_SetGyro();
|
}
|
||||||
|
if (!GY85_SetCompass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return GY85_SetGyro();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------- Update All Sensors ---------------- //
|
// ---------------- Update All Sensors ---------------- //
|
||||||
void GY85_Update(GY85_t *imu)
|
bool GY85_Update(GY85_t *imu)
|
||||||
{
|
{
|
||||||
GY85_ReadAccelerometer(imu);
|
GY85_t next_sample;
|
||||||
GY85_ReadCompass(imu);
|
|
||||||
GY85_ReadGyro(imu);
|
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 ---------------- //
|
// ---------------- Accelerometer ---------------- //
|
||||||
static void GY85_SetAccelerometer(void)
|
static bool GY85_SetAccelerometer(void)
|
||||||
{
|
{
|
||||||
uint8_t data[2];
|
if (!GY85_WriteRegister(ADXL345_ADDR, 0x31, 0x01)) {
|
||||||
data[0] = 0x31; data[1] = 0x01;
|
return false;
|
||||||
HAL_I2C_Master_Transmit(&hi2c3, ADXL345_ADDR, data, 2, HAL_MAX_DELAY);
|
}
|
||||||
|
|
||||||
data[0] = 0x2D; data[1] = 0x08;
|
return GY85_WriteRegister(ADXL345_ADDR, 0x2D, 0x08);
|
||||||
HAL_I2C_Master_Transmit(&hi2c3, ADXL345_ADDR, data, 2, HAL_MAX_DELAY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GY85_ReadAccelerometer(GY85_t *imu)
|
static bool GY85_ReadAccelerometer(GY85_t *imu)
|
||||||
{
|
{
|
||||||
uint8_t reg = 0x32;
|
|
||||||
uint8_t buf[6];
|
uint8_t buf[6];
|
||||||
HAL_I2C_Master_Transmit(&hi2c3, ADXL345_ADDR, ®, 1, HAL_MAX_DELAY);
|
|
||||||
HAL_I2C_Master_Receive(&hi2c3, ADXL345_ADDR, buf, 6, HAL_MAX_DELAY);
|
if (imu == NULL || !GY85_ReadRegisters(ADXL345_ADDR, 0x32, buf, sizeof(buf))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
imu->ax = (int16_t)((buf[1] << 8) | buf[0]);
|
imu->ax = (int16_t)((buf[1] << 8) | buf[0]);
|
||||||
imu->ay = (int16_t)((buf[3] << 8) | buf[2]);
|
imu->ay = (int16_t)((buf[3] << 8) | buf[2]);
|
||||||
imu->az = (int16_t)((buf[5] << 8) | buf[4]);
|
imu->az = (int16_t)((buf[5] << 8) | buf[4]);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------- Compass ---------------- //
|
// ---------------- Compass ---------------- //
|
||||||
static void GY85_SetCompass(void)
|
static bool GY85_SetCompass(void)
|
||||||
{
|
{
|
||||||
uint8_t data[2] = {0x02, 0x00};
|
return GY85_WriteRegister(HMC5883_ADDR, 0x02, 0x00);
|
||||||
HAL_I2C_Master_Transmit(&hi2c3, HMC5883_ADDR, data, 2, HAL_MAX_DELAY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GY85_ReadCompass(GY85_t *imu)
|
static bool GY85_ReadCompass(GY85_t *imu)
|
||||||
{
|
{
|
||||||
uint8_t reg = 0x03;
|
|
||||||
uint8_t buf[6];
|
uint8_t buf[6];
|
||||||
HAL_I2C_Master_Transmit(&hi2c3, HMC5883_ADDR, ®, 1, HAL_MAX_DELAY);
|
|
||||||
HAL_I2C_Master_Receive(&hi2c3, HMC5883_ADDR, buf, 6, HAL_MAX_DELAY);
|
if (imu == NULL || !GY85_ReadRegisters(HMC5883_ADDR, 0x03, buf, sizeof(buf))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
imu->mx = (int16_t)((buf[0] << 8) | buf[1]);
|
imu->mx = (int16_t)((buf[0] << 8) | buf[1]);
|
||||||
imu->mz = (int16_t)((buf[2] << 8) | buf[3]);
|
imu->mz = (int16_t)((buf[2] << 8) | buf[3]);
|
||||||
imu->my = (int16_t)((buf[4] << 8) | buf[5]);
|
imu->my = (int16_t)((buf[4] << 8) | buf[5]);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------- Gyroscope ---------------- //
|
// ---------------- Gyroscope ---------------- //
|
||||||
static void GY85_SetGyro(void)
|
static bool GY85_SetGyro(void)
|
||||||
{
|
{
|
||||||
uint8_t data[2];
|
if (!GY85_WriteRegister(ITG3200_ADDR, 0x3E, 0x00)) {
|
||||||
data[0] = 0x3E; data[1] = 0x00;
|
return false;
|
||||||
HAL_I2C_Master_Transmit(&hi2c3, ITG3200_ADDR, data, 2, HAL_MAX_DELAY);
|
}
|
||||||
|
|
||||||
data[0] = 0x15; data[1] = 0x07;
|
if (!GY85_WriteRegister(ITG3200_ADDR, 0x15, 0x07)) {
|
||||||
HAL_I2C_Master_Transmit(&hi2c3, ITG3200_ADDR, data, 2, HAL_MAX_DELAY);
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
data[0] = 0x16; data[1] = 0x1E;
|
if (!GY85_WriteRegister(ITG3200_ADDR, 0x16, 0x1E)) {
|
||||||
HAL_I2C_Master_Transmit(&hi2c3, ITG3200_ADDR, data, 2, HAL_MAX_DELAY);
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
data[0] = 0x17; data[1] = 0x00;
|
if (!GY85_WriteRegister(ITG3200_ADDR, 0x17, 0x00)) {
|
||||||
HAL_I2C_Master_Transmit(&hi2c3, ITG3200_ADDR, data, 2, HAL_MAX_DELAY);
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
HAL_Delay(10);
|
HAL_Delay(10);
|
||||||
GY85_GyroCalibrate();
|
return GY85_GyroCalibrate();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GY85_GyroCalibrate(void)
|
static bool GY85_GyroCalibrate(void)
|
||||||
{
|
{
|
||||||
int32_t tmpx = 0, tmpy = 0, tmpz = 0;
|
int32_t tmpx = 0, tmpy = 0, tmpz = 0;
|
||||||
GY85_t imu;
|
GY85_t imu;
|
||||||
@@ -97,7 +125,9 @@ static void GY85_GyroCalibrate(void)
|
|||||||
for(uint8_t i = 0; i < 10; i++)
|
for(uint8_t i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
HAL_Delay(10);
|
HAL_Delay(10);
|
||||||
GY85_ReadGyro(&imu);
|
if (!GY85_ReadGyro(&imu)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
tmpx += imu.gx;
|
tmpx += imu.gx;
|
||||||
tmpy += imu.gy;
|
tmpy += imu.gy;
|
||||||
tmpz += imu.gz;
|
tmpz += imu.gz;
|
||||||
@@ -106,16 +136,38 @@ static void GY85_GyroCalibrate(void)
|
|||||||
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, ®, 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->gx = ((int16_t)((buf[2] << 8) | buf[3])) - g_offx;
|
||||||
imu->gy = ((int16_t)((buf[4] << 8) | buf[5])) - g_offy;
|
imu->gy = ((int16_t)((buf[4] << 8) | buf[5])) - g_offy;
|
||||||
imu->gz = ((int16_t)((buf[6] << 8) | buf[7])) - g_offz;
|
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, ®, 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;
|
||||||
@@ -16,6 +17,10 @@ void GPS_Init(UART_HandleTypeDef* huart)
|
|||||||
|
|
||||||
uint8_t GPS_IsDataValid(GPS_Data_t* gps_data)
|
uint8_t GPS_IsDataValid(GPS_Data_t* gps_data)
|
||||||
{
|
{
|
||||||
|
if (gps_data == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if GPS data is within valid ranges
|
// Check if GPS data is within valid ranges
|
||||||
if (gps_data->latitude < -90.0 || gps_data->latitude > 90.0)
|
if (gps_data->latitude < -90.0 || gps_data->latitude > 90.0)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -27,11 +32,11 @@ uint8_t GPS_IsDataValid(GPS_Data_t* gps_data)
|
|||||||
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
|
||||||
@@ -39,12 +44,14 @@ void GPS_ProcessData(GPS_Data_t* gps_data)
|
|||||||
current_gps.timestamp = HAL_GetTick();
|
current_gps.timestamp = HAL_GetTick();
|
||||||
|
|
||||||
// Send to GUI
|
// Send to GUI
|
||||||
GPS_SendToGUI(¤t_gps);
|
return GPS_SendToGUI(¤t_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"
|
// Create packet: "GPS:lat,lon,alt\r\n"
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
@@ -55,16 +62,20 @@ 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)
|
// Alternative binary protocol version (more efficient)
|
||||||
void GPS_SendBinaryToGUI(GPS_Data_t* gps_data)
|
bool GPS_SendBinaryToGUI(GPS_Data_t* gps_data)
|
||||||
{
|
{
|
||||||
if (gui_huart == NULL) return;
|
if (gui_huart == NULL || gps_data == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Binary packet structure:
|
// Binary packet structure:
|
||||||
// [Header 4 bytes][Latitude 8 bytes][Longitude 8 bytes][Altitude 4 bytes][Pitch 4 bytes][CRC 2 bytes]
|
// [Header 4 bytes][Latitude 8 bytes][Longitude 8 bytes][Altitude 4 bytes][Pitch 4 bytes][CRC 2 bytes]
|
||||||
@@ -99,7 +110,7 @@ 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++) {
|
||||||
@@ -115,5 +126,5 @@ void GPS_SendBinaryToGUI(GPS_Data_t* gps_data)
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#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 <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -21,9 +22,9 @@ typedef struct {
|
|||||||
} 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
|
||||||
|
|||||||
@@ -620,8 +620,7 @@ 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();
|
||||||
@@ -1277,9 +1276,13 @@ int main(void)
|
|||||||
|
|
||||||
|
|
||||||
// Initialize module IMU
|
// Initialize module IMU
|
||||||
GY85_Init();
|
if (!GY85_Init()) {
|
||||||
|
Error_Handler();
|
||||||
|
}
|
||||||
for(int i=0; i<10;i++){
|
for(int i=0; i<10;i++){
|
||||||
GY85_Update(&imu);
|
if (!GY85_Update(&imu)) {
|
||||||
|
Error_Handler();
|
||||||
|
}
|
||||||
|
|
||||||
ax = imu.ax;
|
ax = imu.ax;
|
||||||
ay = imu.ay;
|
ay = imu.ay;
|
||||||
@@ -1526,9 +1529,12 @@ int main(void)
|
|||||||
|
|
||||||
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{
|
||||||
|
|||||||
@@ -52,6 +52,19 @@ 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:
|
||||||
id: int
|
id: int
|
||||||
@@ -1156,6 +1169,38 @@ class RadarGUI:
|
|||||||
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):
|
||||||
"""
|
"""
|
||||||
Apply pitch correction to elevation angle
|
Apply pitch correction to elevation angle
|
||||||
@@ -1265,23 +1310,22 @@ class RadarGUI:
|
|||||||
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.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.freq_min = float(self.settings_vars['freq_min'].get())
|
|
||||||
self.settings.freq_max = float(self.settings_vars['freq_max'].get())
|
|
||||||
self.settings.prf1 = float(self.settings_vars['prf1'].get())
|
|
||||||
self.settings.prf2 = float(self.settings_vars['prf2'].get())
|
|
||||||
self.settings.max_distance = float(self.settings_vars['max_distance'].get())
|
|
||||||
self.settings.map_size = float(self.settings_vars['map_size'].get())
|
|
||||||
self.google_maps_api_key = self.settings_vars['google_maps_api_key'].get()
|
self.google_maps_api_key = self.settings_vars['google_maps_api_key'].get()
|
||||||
|
|
||||||
|
self.settings = parsed_settings
|
||||||
|
|
||||||
if self.stm32_usb_interface.is_open:
|
if self.stm32_usb_interface.is_open:
|
||||||
self.stm32_usb_interface.send_settings(self.settings)
|
if not self.stm32_usb_interface.send_settings(self.settings):
|
||||||
|
messagebox.showerror("Error", "Failed to send settings to STM32 via USB")
|
||||||
|
logging.error("Radar settings validation passed, but USB send failed")
|
||||||
|
return
|
||||||
|
|
||||||
messagebox.showinfo("Success", "Settings applied and sent to STM32 via USB")
|
messagebox.showinfo("Success", "Settings applied and sent to STM32 via USB")
|
||||||
logging.info("Radar settings applied via USB")
|
logging.info("Radar settings applied and sent via USB")
|
||||||
|
else:
|
||||||
|
messagebox.showinfo("Success", "Settings applied locally")
|
||||||
|
logging.info("Radar settings applied locally; STM32 USB is not connected")
|
||||||
|
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
messagebox.showerror("Error", f"Invalid setting value: {e}")
|
messagebox.showerror("Error", f"Invalid setting value: {e}")
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -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
|
||||||
|
|
||||||
[](https://opensource.org/licenses/MIT)
|
[](https://ohwr.org/cern_ohl_p_v2.txt)
|
||||||
|
[](https://opensource.org/licenses/MIT)
|
||||||
[](https://github.com/NawfalMotii79/PLFM_RADAR)
|
[](https://github.com/NawfalMotii79/PLFM_RADAR)
|
||||||
[](https://github.com/NawfalMotii79/PLFM_RADAR))
|
[](https://github.com/NawfalMotii79/PLFM_RADAR))
|
||||||
[](https://github.com/NawfalMotii79/PLFM_RADAR/pulls)
|
[](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.
|
||||||
|
|||||||
Reference in New Issue
Block a user