Add files via upload

This commit is contained in:
NawfalMotii79
2026-03-09 00:17:39 +00:00
committed by GitHub
parent 8974a38ff6
commit 5fbe97fa5f
99 changed files with 52953 additions and 0 deletions
@@ -0,0 +1,757 @@
// ADAR1000_Manager.cpp
#include "main.h"
#include "stm32f7xx_hal.h"
#include "ADAR1000_Manager.h"
#include <cmath>
#include <cstring>
extern SPI_HandleTypeDef hspi1;
extern UART_HandleTypeDef huart3;
// Chip Select GPIO definitions
static const struct {
GPIO_TypeDef* port;
uint16_t pin;
} CHIP_SELECTS[4] = {
{GPIOA, GPIO_PIN_0}, // ADAR1000 #1
{GPIOA, GPIO_PIN_1}, // ADAR1000 #2
{GPIOA, GPIO_PIN_2}, // ADAR1000 #3
{GPIOA, GPIO_PIN_3} // ADAR1000 #4
};
// Vector Modulator lookup tables
const uint8_t ADAR1000Manager::VM_I[128] = {
// ... (same as in your original file)
};
const uint8_t ADAR1000Manager::VM_Q[128] = {
// ... (same as in your original file)
};
const uint8_t ADAR1000Manager::VM_GAIN[128] = {
// ... (same as in your original file)
};
ADAR1000Manager::ADAR1000Manager() {
for (int i = 0; i < 4; ++i) {
devices_.push_back(std::make_unique<ADAR1000Device>(i));
}
}
ADAR1000Manager::~ADAR1000Manager() {
// Automatic cleanup by unique_ptr
}
// System Management
bool ADAR1000Manager::powerUpSystem() {
const uint8_t msg[] = "Starting System Power-Up Sequence...\r\n";
HAL_UART_Transmit(&huart3, msg, sizeof(msg) - 1, 1000);
// Power-up sequence steps...
HAL_GPIO_WritePin(EN_P_3V3_VDD_SW_GPIO_Port, EN_P_3V3_VDD_SW_Pin, GPIO_PIN_SET);
HAL_Delay(2);
HAL_GPIO_WritePin(EN_P_3V3_SW_GPIO_Port, EN_P_3V3_SW_Pin, GPIO_PIN_SET);
HAL_Delay(2);
// Initialize devices
if (!initializeAllDevices()) {
const uint8_t err[] = "ERROR: ADAR1000 initialization failed!\r\n";
HAL_UART_Transmit(&huart3, err, sizeof(err) - 1, 1000);
return false;
}
// Start in RX mode
switchToRXMode();
const uint8_t success[] = "System Power-Up Sequence Completed Successfully.\r\n";
HAL_UART_Transmit(&huart3, success, sizeof(success) - 1, 1000);
return true;
}
bool ADAR1000Manager::powerDownSystem() {
switchToRXMode();
HAL_Delay(10);
disablePASupplies();
disableLNASupplies();
HAL_GPIO_WritePin(EN_P_3V3_SW_GPIO_Port, EN_P_3V3_SW_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(EN_P_3V3_VDD_SW_GPIO_Port, EN_P_3V3_VDD_SW_Pin, GPIO_PIN_RESET);
return true;
}
// Mode Switching
void ADAR1000Manager::switchToTXMode() {
setLNABias(false);
delayUs(10);
enablePASupplies();
delayUs(100);
setPABias(true);
delayUs(50);
setADTR1107Control(true);
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
adarWrite(dev, REG_RX_ENABLES, 0x00, BROADCAST_OFF);
adarWrite(dev, REG_TX_ENABLES, 0x0F, BROADCAST_OFF);
adarSetTxBias(dev, BROADCAST_OFF);
devices_[dev]->current_mode = BeamDirection::TX;
}
current_mode_ = BeamDirection::TX;
}
void ADAR1000Manager::switchToRXMode() {
setPABias(false);
delayUs(50);
disablePASupplies();
delayUs(10);
setADTR1107Control(false);
enableLNASupplies();
delayUs(50);
setLNABias(true);
delayUs(50);
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
adarWrite(dev, REG_TX_ENABLES, 0x00, BROADCAST_OFF);
adarWrite(dev, REG_RX_ENABLES, 0x0F, BROADCAST_OFF);
devices_[dev]->current_mode = BeamDirection::RX;
}
current_mode_ = BeamDirection::RX;
}
void ADAR1000Manager::fastTXMode() {
setADTR1107Control(true);
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
adarWrite(dev, REG_RX_ENABLES, 0x00, BROADCAST_OFF);
adarWrite(dev, REG_TX_ENABLES, 0x0F, BROADCAST_OFF);
devices_[dev]->current_mode = BeamDirection::TX;
}
current_mode_ = BeamDirection::TX;
}
void ADAR1000Manager::fastRXMode() {
setADTR1107Control(false);
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
adarWrite(dev, REG_TX_ENABLES, 0x00, BROADCAST_OFF);
adarWrite(dev, REG_RX_ENABLES, 0x0F, BROADCAST_OFF);
devices_[dev]->current_mode = BeamDirection::RX;
}
current_mode_ = BeamDirection::RX;
}
void ADAR1000Manager::pulseTXMode() {
setADTR1107Control(true);
last_switch_time_us_ = HAL_GetTick() * 1000;
}
void ADAR1000Manager::pulseRXMode() {
setADTR1107Control(false);
last_switch_time_us_ = HAL_GetTick() * 1000;
}
// Beam Steering
bool ADAR1000Manager::setBeamAngle(float angle_degrees, BeamDirection direction) {
uint8_t phase_settings[4];
calculatePhaseSettings(angle_degrees, phase_settings);
if (direction == BeamDirection::TX) {
setAllDevicesTXMode();
} else {
setAllDevicesRXMode();
}
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
for (uint8_t ch = 0; ch < 4; ++ch) {
if (direction == BeamDirection::TX) {
adarSetTxPhase(dev, ch + 1, phase_settings[ch], BROADCAST_OFF);
adarSetTxVgaGain(dev, ch + 1, 0x7F, BROADCAST_OFF);
} else {
adarSetRxPhase(dev, ch + 1, phase_settings[ch], BROADCAST_OFF);
adarSetRxVgaGain(dev, ch + 1, 30, BROADCAST_OFF);
}
}
}
return true;
}
bool ADAR1000Manager::setCustomBeamPattern(const uint8_t phase_settings[4], const uint8_t gain_settings[4], BeamDirection direction) {
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
for (uint8_t ch = 0; ch < 4; ++ch) {
if (direction == BeamDirection::TX) {
adarSetTxPhase(dev, ch + 1, phase_settings[ch], BROADCAST_OFF);
adarSetTxVgaGain(dev, ch + 1, gain_settings[ch], BROADCAST_OFF);
} else {
adarSetRxPhase(dev, ch + 1, phase_settings[ch], BROADCAST_OFF);
adarSetRxVgaGain(dev, ch + 1, gain_settings[ch], BROADCAST_OFF);
}
}
}
return true;
}
// Beam Sweeping
void ADAR1000Manager::startBeamSweeping() {
beam_sweeping_active_ = true;
current_beam_index_ = 0;
last_beam_update_time_ = HAL_GetTick();
}
void ADAR1000Manager::stopBeamSweeping() {
beam_sweeping_active_ = false;
}
void ADAR1000Manager::updateBeamPosition() {
if (!beam_sweeping_active_) return;
uint32_t current_time = HAL_GetTick();
const std::vector<BeamConfig>& sequence =
(current_mode_ == BeamDirection::TX) ? tx_beam_sequence_ : rx_beam_sequence_;
if (sequence.empty()) return;
if (current_time - last_beam_update_time_ >= beam_dwell_time_ms_) {
const BeamConfig& beam = sequence[current_beam_index_];
setCustomBeamPattern(beam.phase_settings, beam.gain_settings, current_mode_);
current_beam_index_ = (current_beam_index_ + 1) % sequence.size();
last_beam_update_time_ = current_time;
}
}
void ADAR1000Manager::setBeamSequence(const std::vector<BeamConfig>& sequence, BeamDirection direction) {
if (direction == BeamDirection::TX) {
tx_beam_sequence_ = sequence;
} else {
rx_beam_sequence_ = sequence;
}
}
void ADAR1000Manager::clearBeamSequence(BeamDirection direction) {
if (direction == BeamDirection::TX) {
tx_beam_sequence_.clear();
} else {
rx_beam_sequence_.clear();
}
}
// Monitoring and Diagnostics
float ADAR1000Manager::readTemperature(uint8_t deviceIndex) {
if (deviceIndex >= devices_.size() || !devices_[deviceIndex]->initialized) {
return -273.15f;
}
uint8_t temp_raw = adarAdcRead(deviceIndex, BROADCAST_OFF);
return (temp_raw * 0.5f) - 50.0f;
}
bool ADAR1000Manager::verifyDeviceCommunication(uint8_t deviceIndex) {
if (deviceIndex >= devices_.size()) return false;
uint8_t test_value = 0xA5;
adarWrite(deviceIndex, REG_SCRATCHPAD, test_value, BROADCAST_OFF);
HAL_Delay(1);
uint8_t readback = adarRead(deviceIndex, REG_SCRATCHPAD);
return (readback == test_value);
}
uint8_t ADAR1000Manager::readRegister(uint8_t deviceIndex, uint32_t address) {
return adarRead(deviceIndex, address);
}
void ADAR1000Manager::writeRegister(uint8_t deviceIndex, uint32_t address, uint8_t value) {
adarWrite(deviceIndex, address, value, BROADCAST_OFF);
}
// Configuration
void ADAR1000Manager::setSwitchSettlingTime(uint32_t us) {
switch_settling_time_us_ = us;
}
void ADAR1000Manager::setFastSwitchMode(bool enable) {
fast_switch_mode_ = enable;
if (enable) {
switch_settling_time_us_ = 10;
enablePASupplies();
enableLNASupplies();
setPABias(true);
setLNABias(true);
} else {
switch_settling_time_us_ = 50;
}
}
void ADAR1000Manager::setBeamDwellTime(uint32_t ms) {
beam_dwell_time_ms_ = ms;
}
// Private helper methods (implementation continues...)
// ... include all the private method implementations from your original file
// ============================================================================
// PRIVATE HELPER METHODS - Add these to the end of ADAR1000_Manager.cpp
// ============================================================================
bool ADAR1000Manager::initializeAllDevices() {
// Initialize each ADAR1000
for (uint8_t i = 0; i < devices_.size(); ++i) {
if (!initializeSingleDevice(i)) {
return false;
}
}
setAllDevicesTXMode();
return true;
}
bool ADAR1000Manager::initializeSingleDevice(uint8_t deviceIndex) {
if (deviceIndex >= devices_.size()) return false;
adarSoftReset(deviceIndex);
HAL_Delay(10);
adarWriteConfigA(deviceIndex, INTERFACE_CONFIG_A_SDO_ACTIVE, BROADCAST_OFF);
adarSetRamBypass(deviceIndex, BROADCAST_OFF);
// Initialize ADC
adarWrite(deviceIndex, REG_ADC_CONTROL, ADAR1000_ADC_2MHZ_CLK | ADAR1000_ADC_EN, BROADCAST_OFF);
devices_[deviceIndex]->initialized = true;
return true;
}
bool ADAR1000Manager::initializeADTR1107Sequence() {
//Powering up ADTR1107 TX mode
const uint8_t msg[] = "Starting ADTR1107 Power Sequence...\r\n";
HAL_UART_Transmit(&huart3, msg, sizeof(msg) - 1, 1000);
// Step 1: Connect all GND pins to ground (assumed in hardware)
// Step 2: Set VDD_SW to 3.3V
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_15, GPIO_PIN_SET); // EN_P_3V3_VDD_SW
HAL_Delay(1);
// Step 3: Set VSS_SW to -3.3V
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_14, GPIO_PIN_SET); // EN_P_3V3_SW
HAL_Delay(1);
// Step 4: Set CTRL_SW to RX mode initially via GPIO
setADTR1107Control(false); // RX mode
HAL_Delay(1);
// Step 5: Set VGG_LNA to 0
uint8_t lna_bias_voltage = 0x00; // Example value, adjust based on your LNA requirements
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_OFF, 0x00, BROADCAST_OFF);
}
// 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_Delay(2);
// Step 7: Set VGG_PA to safe negative voltage (PA off for TX mode)
/*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 4.8 V output.*/
uint8_t safe_pa_bias = 0x5D; // Safe negative voltage (-1.75V) to keep PA off
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_CH2_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);
}
HAL_Delay(10);
// 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
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_1, GPIO_PIN_SET);
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
//Set VGG_PA to safe negative voltage (PA off for TX mode)
/*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 4.8 V output.*/
uint8_t Idq_pa_bias = 0x0D; // Safe negative voltage (-0.2447V) to keep PA off
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_CH2_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);
}
HAL_Delay(10);
const uint8_t success[] = "ADTR1107 power sequence completed.\r\n";
HAL_UART_Transmit(&huart3, success, sizeof(success) - 1, 1000);
return true;
}
bool ADAR1000Manager::setAllDevicesTXMode() {
// Set ADTR1107 to TX mode first
setADTR1107Mode(BeamDirection::TX);
// Then configure ADAR1000 for TX
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
// Disable RX first
adarWrite(dev, REG_RX_ENABLES, 0x00, BROADCAST_OFF);
// Enable TX channels and set bias
adarWrite(dev, REG_TX_ENABLES, 0x0F, BROADCAST_OFF); // Enable all 4 channels
adarSetTxBias(dev, BROADCAST_OFF);
devices_[dev]->current_mode = BeamDirection::TX;
}
current_mode_ = BeamDirection::TX;
return true;
}
bool ADAR1000Manager::setAllDevicesRXMode() {
// Set ADTR1107 to RX mode first
setADTR1107Mode(BeamDirection::RX);
// Then configure ADAR1000 for RX
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
// Disable TX first
adarWrite(dev, REG_TX_ENABLES, 0x00, BROADCAST_OFF);
// Enable RX channels
adarWrite(dev, REG_RX_ENABLES, 0x0F, BROADCAST_OFF); // Enable all 4 channels
devices_[dev]->current_mode = BeamDirection::RX;
}
current_mode_ = BeamDirection::RX;
return true;
}
void ADAR1000Manager::setADTR1107Mode(BeamDirection direction) {
if (direction == BeamDirection::TX) {
setADTR1107Control(true); // TX mode
// Step 1: Disable LNA power first
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_RESET); // Disable LNA power
HAL_Delay(5);
// Step 2: Set LNA bias to safe off value
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
adarWrite(dev, REG_LNA_BIAS_ON, 0x00, BROADCAST_OFF); // Turn off LNA bias
}
HAL_Delay(5);
// Step 3: Enable PA power
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_0, GPIO_PIN_SET); // EN_P_5V0_PA
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_1, GPIO_PIN_SET);
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 = 0x7F; // Maximum bias for full power
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_CH2_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);
}
HAL_Delay(5);
// Step 5: Set TR switch to TX mode
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
adarSetBit(dev, REG_SW_CONTROL, 2, BROADCAST_OFF); // TR_SOURCE = 1 (TX)
adarSetBit(dev, REG_MISC_ENABLES, 5, BROADCAST_OFF); // BIAS_EN
}
} else {
// RECEIVE MODE: Enable LNA, Disable PA
setADTR1107Control(false); // RX mode
// Step 1: Disable PA power first
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_0, GPIO_PIN_RESET); // EN_P_5V0_PA
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_1, GPIO_PIN_RESET);
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 = 0x20;
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_CH2_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);
}
HAL_Delay(5);
// Step 3: Enable LNA power
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_SET); // EN_P_3V3_LNA
HAL_Delay(10);
// Step 4: Set LNA bias to operational value
uint8_t operational_lna_bias = 0x30; // Adjust based on your LNA requirements
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
adarWrite(dev, REG_LNA_BIAS_ON, operational_lna_bias, BROADCAST_OFF);
}
HAL_Delay(5);
// Step 5: Set TR switch to RX mode
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
adarResetBit(dev, REG_SW_CONTROL, 2, BROADCAST_OFF); // TR_SOURCE = 0 (RX)
adarSetBit(dev, REG_MISC_ENABLES, 4, BROADCAST_OFF); // LNA_BIAS_OUT_EN
}
}
}
void ADAR1000Manager::setADTR1107Control(bool tx_mode) {
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
setTRSwitchPosition(dev, tx_mode);
}
delayUs(switch_settling_time_us_);
}
void ADAR1000Manager::setTRSwitchPosition(uint8_t deviceIndex, bool tx_mode) {
if (tx_mode) {
// TX mode: Set TR_SOURCE = 1
adarSetBit(deviceIndex, REG_SW_CONTROL, 2, BROADCAST_OFF);
} else {
// RX mode: Set TR_SOURCE = 0
adarResetBit(deviceIndex, REG_SW_CONTROL, 2, BROADCAST_OFF);
}
}
// Add the new public method
bool ADAR1000Manager::setCustomBeamPattern16(const uint8_t phase_pattern[16], BeamDirection direction) {
for (uint8_t dev = 0; dev < 4; ++dev) {
for (uint8_t ch = 0; ch < 4; ++ch) {
uint8_t phase = phase_pattern[dev * 4 + ch];
if (direction == BeamDirection::TX) {
adarSetTxPhase(dev, ch + 1, phase, BROADCAST_OFF);
} else {
adarSetRxPhase(dev, ch + 1, phase, BROADCAST_OFF);
}
}
}
return true;
}
void ADAR1000Manager::enablePASupplies() {
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_0, GPIO_PIN_SET); // EN_P_5V0_PA
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_1, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_2, GPIO_PIN_SET);
}
void ADAR1000Manager::disablePASupplies() {
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_0, GPIO_PIN_RESET); // EN_P_5V0_PA
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_2, GPIO_PIN_RESET);
}
void ADAR1000Manager::enableLNASupplies() {
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_SET); // EN_P_3V3_LNA
}
void ADAR1000Manager::disableLNASupplies() {
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_RESET); // EN_P_3V3_LNA
}
void ADAR1000Manager::setPABias(bool enable) {
uint8_t pa_bias = enable ? 0x7F : 0x20; // Operational vs safe bias
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
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_CH3_BIAS_ON, pa_bias, BROADCAST_OFF);
adarWrite(dev, REG_PA_CH4_BIAS_ON, pa_bias, BROADCAST_OFF);
}
}
void ADAR1000Manager::setLNABias(bool enable) {
uint8_t lna_bias = enable ? 0x30 : 0x00; // Operational vs off
for (uint8_t dev = 0; dev < devices_.size(); ++dev) {
adarWrite(dev, REG_LNA_BIAS_ON, lna_bias, BROADCAST_OFF);
}
}
void ADAR1000Manager::delayUs(uint32_t microseconds) {
// Simple implementation - for F7 @ 216MHz, each loop ~7 cycles ≈ 0.032us
volatile uint32_t cycles = microseconds * 10; // Adjust this multiplier for your clock
while (cycles--) {
__NOP();
}
}
void ADAR1000Manager::calculatePhaseSettings(float angle_degrees, uint8_t phase_settings[4]) {
const float freq = 10.5e9;
const float c = 3e8;
const float wavelength = c / freq;
const float element_spacing = wavelength / 2;
float angle_rad = angle_degrees * M_PI / 180.0;
float phase_shift = (2 * M_PI * element_spacing * sin(angle_rad)) / wavelength;
for (int i = 0; i < 4; ++i) {
float element_phase = i * phase_shift;
while (element_phase < 0) element_phase += 2 * M_PI;
while (element_phase >= 2 * M_PI) element_phase -= 2 * M_PI;
phase_settings[i] = static_cast<uint8_t>((element_phase / (2 * M_PI)) * 128);
}
}
bool ADAR1000Manager::performSystemCalibration() {
for (uint8_t i = 0; i < devices_.size(); ++i) {
if (!verifyDeviceCommunication(i)) {
return false;
}
}
return true;
}
// ============================================================================
// LOW-LEVEL SPI COMMUNICATION METHODS
// ============================================================================
uint32_t ADAR1000Manager::spiTransfer(uint8_t* txData, uint8_t* rxData, uint32_t size) {
HAL_StatusTypeDef status;
if (rxData) {
status = HAL_SPI_TransmitReceive(&hspi1, txData, rxData, size, 1000);
} else {
status = HAL_SPI_Transmit(&hspi1, txData, size, 1000);
}
return (status == HAL_OK) ? size : 0;
}
void ADAR1000Manager::setChipSelect(uint8_t deviceIndex, bool state) {
if (deviceIndex >= devices_.size()) return;
HAL_GPIO_WritePin(CHIP_SELECTS[deviceIndex].port,
CHIP_SELECTS[deviceIndex].pin,
state ? GPIO_PIN_RESET : GPIO_PIN_SET);
}
void ADAR1000Manager::adarWrite(uint8_t deviceIndex, uint32_t mem_addr, uint8_t data, uint8_t broadcast) {
uint8_t instruction[3];
if (broadcast) {
instruction[0] = 0x08;
} else {
instruction[0] = ((devices_[deviceIndex]->dev_addr & 0x03) << 5);
}
instruction[0] |= (0x1F00 & mem_addr) >> 8;
instruction[1] = (0xFF & mem_addr);
instruction[2] = data;
setChipSelect(deviceIndex, true);
spiTransfer(instruction, nullptr, sizeof(instruction));
setChipSelect(deviceIndex, false);
}
uint8_t ADAR1000Manager::adarRead(uint8_t deviceIndex, uint32_t mem_addr) {
uint8_t instruction[3] = {0};
uint8_t rx_buffer[3] = {0};
// Set SDO active
adarWrite(deviceIndex, REG_INTERFACE_CONFIG_A, INTERFACE_CONFIG_A_SDO_ACTIVE, 0);
instruction[0] = 0x80 | ((devices_[deviceIndex]->dev_addr & 0x03) << 5);
instruction[0] |= ((0xff00 & mem_addr) >> 8);
instruction[1] = (0xff & mem_addr);
instruction[2] = 0x00;
setChipSelect(deviceIndex, true);
spiTransfer(instruction, rx_buffer, sizeof(instruction));
setChipSelect(deviceIndex, false);
// Set SDO Inactive
adarWrite(deviceIndex, REG_INTERFACE_CONFIG_A, 0, 0);
return rx_buffer[2];
}
void ADAR1000Manager::adarSetBit(uint8_t deviceIndex, uint32_t mem_addr, uint8_t bit, uint8_t broadcast) {
uint8_t temp = adarRead(deviceIndex, mem_addr);
uint8_t data = temp | (1 << bit);
adarWrite(deviceIndex, mem_addr, data, broadcast);
}
void ADAR1000Manager::adarResetBit(uint8_t deviceIndex, uint32_t mem_addr, uint8_t bit, uint8_t broadcast) {
uint8_t temp = adarRead(deviceIndex, mem_addr);
uint8_t data = temp & ~(1 << bit);
adarWrite(deviceIndex, mem_addr, data, broadcast);
}
void ADAR1000Manager::adarSoftReset(uint8_t deviceIndex) {
uint8_t instruction[3];
instruction[0] = ((devices_[deviceIndex]->dev_addr & 0x03) << 5);
instruction[1] = 0x00;
instruction[2] = 0x81;
setChipSelect(deviceIndex, true);
spiTransfer(instruction, nullptr, sizeof(instruction));
setChipSelect(deviceIndex, false);
}
void ADAR1000Manager::adarWriteConfigA(uint8_t deviceIndex, uint8_t flags, uint8_t broadcast) {
adarWrite(deviceIndex, REG_INTERFACE_CONFIG_A, flags, broadcast);
}
void ADAR1000Manager::adarSetRamBypass(uint8_t deviceIndex, uint8_t broadcast) {
uint8_t data = (MEM_CTRL_BIAS_RAM_BYPASS | MEM_CTRL_BEAM_RAM_BYPASS);
adarWrite(deviceIndex, REG_MEM_CTL, data, broadcast);
}
void ADAR1000Manager::adarSetRxPhase(uint8_t deviceIndex, uint8_t channel, uint8_t phase, uint8_t broadcast) {
uint8_t i_val = VM_I[phase % 128];
uint8_t q_val = VM_Q[phase % 128];
uint32_t mem_addr_i = REG_CH1_RX_PHS_I + (channel & 0x03) * 2;
uint32_t mem_addr_q = REG_CH1_RX_PHS_Q + (channel & 0x03) * 2;
adarWrite(deviceIndex, mem_addr_i, i_val, broadcast);
adarWrite(deviceIndex, mem_addr_q, q_val, broadcast);
adarWrite(deviceIndex, REG_LOAD_WORKING, 0x1, broadcast);
}
void ADAR1000Manager::adarSetTxPhase(uint8_t deviceIndex, uint8_t channel, uint8_t phase, uint8_t broadcast) {
uint8_t i_val = VM_I[phase % 128];
uint8_t q_val = VM_Q[phase % 128];
uint32_t mem_addr_i = REG_CH1_TX_PHS_I + (channel & 0x03) * 2;
uint32_t mem_addr_q = REG_CH1_TX_PHS_Q + (channel & 0x03) * 2;
adarWrite(deviceIndex, mem_addr_i, i_val, broadcast);
adarWrite(deviceIndex, mem_addr_q, q_val, broadcast);
adarWrite(deviceIndex, REG_LOAD_WORKING, 0x1, broadcast);
}
void ADAR1000Manager::adarSetRxVgaGain(uint8_t deviceIndex, uint8_t channel, uint8_t gain, uint8_t broadcast) {
uint32_t mem_addr = REG_CH1_RX_GAIN + (channel & 0x03);
adarWrite(deviceIndex, mem_addr, gain, broadcast);
adarWrite(deviceIndex, REG_LOAD_WORKING, 0x1, broadcast);
}
void ADAR1000Manager::adarSetTxVgaGain(uint8_t deviceIndex, uint8_t channel, uint8_t gain, uint8_t broadcast) {
uint32_t mem_addr = REG_CH1_TX_GAIN + (channel & 0x03);
adarWrite(deviceIndex, mem_addr, gain, broadcast);
adarWrite(deviceIndex, REG_LOAD_WORKING, LD_WRK_REGS_LDTX_OVERRIDE, broadcast);
}
void ADAR1000Manager::adarSetTxBias(uint8_t deviceIndex, uint8_t broadcast) {
adarWrite(deviceIndex, REG_BIAS_CURRENT_TX, 0x2D, broadcast);
adarWrite(deviceIndex, REG_BIAS_CURRENT_TX_DRV, 0x06, broadcast);
adarWrite(deviceIndex, REG_LOAD_WORKING, 0x2, broadcast);
}
uint8_t ADAR1000Manager::adarAdcRead(uint8_t deviceIndex, uint8_t broadcast) {
adarWrite(deviceIndex, REG_ADC_CONTROL, ADAR1000_ADC_ST_CONV, broadcast);
// Wait for conversion
while (!(adarRead(deviceIndex, REG_ADC_CONTROL) & 0x01)) {
// Busy wait
}
return adarRead(deviceIndex, REG_ADC_OUT);
}
@@ -0,0 +1,222 @@
// ADAR1000_Manager.h
#ifndef ADAR1000_MANAGER_H
#define ADAR1000_MANAGER_H
#include "stm32f7xx_hal.h"
#include "main.h"
#include <vector>
#include <memory>
class ADAR1000Manager {
public:
enum class BeamDirection {
TX = 0,
RX = 1
};
struct BeamConfig {
float angle_degrees;
uint8_t phase_settings[4];
uint8_t gain_settings[4];
uint32_t dwell_time_ms;
BeamConfig() : angle_degrees(0), dwell_time_ms(100) {
for(int i = 0; i < 4; i++) {
phase_settings[i] = 0;
gain_settings[i] = 0x7F;
}
}
BeamConfig(float angle, uint32_t dwell = 100) : angle_degrees(angle), dwell_time_ms(dwell) {
for(int i = 0; i < 4; i++) {
phase_settings[i] = 0;
gain_settings[i] = 0x7F;
}
}
};
ADAR1000Manager();
~ADAR1000Manager();
// System Management
bool powerUpSystem();
bool powerDownSystem();
bool initializeAllDevices();
bool performSystemCalibration();
// Mode Switching
void switchToTXMode();
void switchToRXMode();
void fastTXMode();
void fastRXMode();
void pulseTXMode();
void pulseRXMode();
// Beam Steering
bool setBeamAngle(float angle_degrees, BeamDirection direction);
bool setCustomBeamPattern(const uint8_t phase_settings[16], const uint8_t gain_settings[4], BeamDirection direction);
bool setCustomBeamPattern16(const uint8_t phase_pattern[16], BeamDirection direction);
// Beam Sweeping
void startBeamSweeping();
void stopBeamSweeping();
void updateBeamPosition();
void setBeamSequence(const std::vector<BeamConfig>& sequence, BeamDirection direction);
void clearBeamSequence(BeamDirection direction);
// Device Control
bool setAllDevicesTXMode();
bool setAllDevicesRXMode();
void setADTR1107Mode(BeamDirection direction);
void setADTR1107Control(bool tx_mode);
// Monitoring and Diagnostics
float readTemperature(uint8_t deviceIndex);
bool verifyDeviceCommunication(uint8_t deviceIndex);
uint8_t readRegister(uint8_t deviceIndex, uint32_t address);
void writeRegister(uint8_t deviceIndex, uint32_t address, uint8_t value);
// Configuration
void setSwitchSettlingTime(uint32_t us);
void setFastSwitchMode(bool enable);
void setBeamDwellTime(uint32_t ms);
// Getters
bool isBeamSweepingActive() const { return beam_sweeping_active_; }
uint8_t getCurrentBeamIndex() const { return current_beam_index_; }
BeamDirection getCurrentMode() const { return current_mode_; }
uint32_t getLastSwitchTime() const { return last_switch_time_us_; }
struct ADAR1000Device {
uint8_t dev_addr;
bool initialized;
BeamDirection current_mode;
float temperature;
ADAR1000Device(uint8_t addr)
: dev_addr(addr), initialized(false), current_mode(BeamDirection::RX), temperature(25.0f) {
}
};
// Configuration
bool fast_switch_mode_ = false;
uint32_t switch_settling_time_us_ = 50;
uint32_t beam_dwell_time_ms_ = 100;
uint32_t last_switch_time_us_ = 0;
// Device Management
std::vector<std::unique_ptr<ADAR1000Device>> devices_;
BeamDirection current_mode_ = BeamDirection::RX;
// Beam Sweeping
std::vector<BeamConfig> tx_beam_sequence_;
std::vector<BeamConfig> rx_beam_sequence_;
uint8_t current_beam_index_ = 0;
bool beam_sweeping_active_ = false;
uint32_t last_beam_update_time_ = 0;
// Lookup tables
static const uint8_t VM_I[128];
static const uint8_t VM_Q[128];
static const uint8_t VM_GAIN[128];
// Private Methods
bool initializeSingleDevice(uint8_t deviceIndex);
bool initializeADTR1107Sequence();
void calculatePhaseSettings(float angle_degrees, uint8_t phase_settings[4]);
void delayUs(uint32_t microseconds);
// Power Management
void enablePASupplies();
void disablePASupplies();
void enableLNASupplies();
void disableLNASupplies();
void setPABias(bool enable);
void setLNABias(bool enable);
// SPI Communication
void setChipSelect(uint8_t deviceIndex, bool state);
uint32_t spiTransfer(uint8_t* txData, uint8_t* rxData, uint32_t size);
void adarWrite(uint8_t deviceIndex, uint32_t mem_addr, uint8_t data, uint8_t broadcast);
uint8_t adarRead(uint8_t deviceIndex, uint32_t mem_addr);
void adarSetBit(uint8_t deviceIndex, uint32_t mem_addr, uint8_t bit, uint8_t broadcast);
void adarResetBit(uint8_t deviceIndex, uint32_t mem_addr, uint8_t bit, uint8_t broadcast);
void adarSoftReset(uint8_t deviceIndex);
void adarWriteConfigA(uint8_t deviceIndex, uint8_t flags, uint8_t broadcast);
void adarSetRamBypass(uint8_t deviceIndex, uint8_t broadcast);
// Channel Configuration
void adarSetRxPhase(uint8_t deviceIndex, uint8_t channel, uint8_t phase, uint8_t broadcast);
void adarSetTxPhase(uint8_t deviceIndex, uint8_t channel, uint8_t phase, uint8_t broadcast);
void adarSetRxVgaGain(uint8_t deviceIndex, uint8_t channel, uint8_t gain, uint8_t broadcast);
void adarSetTxVgaGain(uint8_t deviceIndex, uint8_t channel, uint8_t gain, uint8_t broadcast);
void adarSetTxBias(uint8_t deviceIndex, uint8_t broadcast);
uint8_t adarAdcRead(uint8_t deviceIndex, uint8_t broadcast);
void setTRSwitchPosition(uint8_t deviceIndex, bool tx_mode);
private:
};
// Register Definitions
#define BROADCAST_OFF 0
#define BROADCAST_ON 1
#define REG_INTERFACE_CONFIG_A 0x000
#define REG_SCRATCHPAD 0x00A
#define REG_CH1_RX_GAIN 0x010
#define REG_CH2_RX_GAIN 0x011
#define REG_CH3_RX_GAIN 0x012
#define REG_CH4_RX_GAIN 0x013
#define REG_CH1_RX_PHS_I 0x014
#define REG_CH1_RX_PHS_Q 0x015
#define REG_CH2_RX_PHS_I 0x016
#define REG_CH2_RX_PHS_Q 0x017
#define REG_CH3_RX_PHS_I 0x018
#define REG_CH3_RX_PHS_Q 0x019
#define REG_CH4_RX_PHS_I 0x01A
#define REG_CH4_RX_PHS_Q 0x01B
#define REG_CH1_TX_GAIN 0x01C
#define REG_CH2_TX_GAIN 0x01D
#define REG_CH3_TX_GAIN 0x01E
#define REG_CH4_TX_GAIN 0x01F
#define REG_CH1_TX_PHS_I 0x020
#define REG_CH1_TX_PHS_Q 0x021
#define REG_CH2_TX_PHS_I 0x022
#define REG_CH2_TX_PHS_Q 0x023
#define REG_CH3_TX_PHS_I 0x024
#define REG_CH3_TX_PHS_Q 0x025
#define REG_CH4_TX_PHS_I 0x026
#define REG_CH4_TX_PHS_Q 0x027
#define REG_LOAD_WORKING 0x028
#define REG_PA_CH1_BIAS_ON 0x029
#define REG_PA_CH2_BIAS_ON 0x02A
#define REG_PA_CH3_BIAS_ON 0x02B
#define REG_PA_CH4_BIAS_ON 0x02C
#define REG_LNA_BIAS_ON 0x02D
#define REG_RX_ENABLES 0x02E
#define REG_TX_ENABLES 0x02F
#define REG_MISC_ENABLES 0x030
#define REG_SW_CONTROL 0x031
#define REG_ADC_CONTROL 0x032
#define REG_ADC_OUT 0x033
#define REG_BIAS_CURRENT_TX 0x036
#define REG_BIAS_CURRENT_TX_DRV 0x037
#define REG_MEM_CTL 0x038
#define REG_PA_CH1_BIAS_OFF 0x046
#define REG_PA_CH2_BIAS_OFF 0x047
#define REG_PA_CH3_BIAS_OFF 0x048
#define REG_PA_CH4_BIAS_OFF 0x049
#define REG_LNA_BIAS_OFF 0x04A
// Register Constants
#define INTERFACE_CONFIG_A_SDO_ACTIVE ((1 << 4) | (1 << 3))
#define ADAR1000_ADC_2MHZ_CLK 0x00
#define ADAR1000_ADC_EN 0x60
#define ADAR1000_ADC_ST_CONV 0x70
#define MEM_CTRL_BIAS_RAM_BYPASS (1 << 5)
#define MEM_CTRL_BEAM_RAM_BYPASS (1 << 6)
#define LD_WRK_REGS_LDTX_OVERRIDE (1 << 1)
#endif // ADAR1000_MANAGER_H
@@ -0,0 +1,86 @@
#ifndef __ADS7830_H
#define __ADS7830_H
#ifdef __cplusplus
extern "C" {
#endif
#include "stm32f7xx_hal.h"
#include <stdbool.h>
#include <stdint.h>
/* I2C Address Definitions */
#define ADS7830_DEFAULT_ADDRESS (0x48) // 1001 000 (ADDR = GND)
#define ADS7830_VDD_ADDRESS (0x49) // 1001 001 (ADDR = VDD)
#define ADS7830_SDA_ADDRESS (0x4A) // 1001 010 (ADDR = SDA)
#define ADS7830_SCL_ADDRESS (0x4B) // 1001 011 (ADDR = SCL)
/* Conversion Delay (in ms) */
#define ADS7830_CONVERSIONDELAY (1)
/* Command Byte Register Masks */
#define ADS7830_REG_COMMAND_SD_MASK (0x80) // Single-Ended/Differential Inputs
#define ADS7830_REG_COMMAND_SD_DIFF (0x00) // Bit = 0, Differential Inputs
#define ADS7830_REG_COMMAND_SD_SINGLE (0x80) // Bit = 1, Single-Ended Inputs
#define ADS7830_REG_COMMAND_CH_MASK (0x70) // Input multiplexer Configuration
#define ADS7830_REG_COMMAND_CH_DIFF_0_1 (0x00) // Differential P = CH0, N = CH1
#define ADS7830_REG_COMMAND_CH_DIFF_2_3 (0x10) // Differential P = CH2, N = CH3
#define ADS7830_REG_COMMAND_CH_DIFF_4_5 (0x20) // Differential P = CH4, N = CH5
#define ADS7830_REG_COMMAND_CH_DIFF_6_7 (0x30) // Differential P = CH6, N = CH7
#define ADS7830_REG_COMMAND_CH_DIFF_1_0 (0x40) // Differential P = CH1, N = CH0
#define ADS7830_REG_COMMAND_CH_DIFF_3_2 (0x50) // Differential P = CH3, N = CH2
#define ADS7830_REG_COMMAND_CH_DIFF_5_4 (0x60) // Differential P = CH5, N = CH4
#define ADS7830_REG_COMMAND_CH_DIFF_7_6 (0x70) // Differential P = CH7, N = CH6
#define ADS7830_REG_COMMAND_CH_SINGLE_0 (0x00) // Single-ended P = CH0, N = COM
#define ADS7830_REG_COMMAND_CH_SINGLE_1 (0x10) // Single-ended P = CH1, N = COM
#define ADS7830_REG_COMMAND_CH_SINGLE_2 (0x20) // Single-ended P = CH2, N = COM
#define ADS7830_REG_COMMAND_CH_SINGLE_3 (0x30) // Single-ended P = CH3, N = COM
#define ADS7830_REG_COMMAND_CH_SINGLE_4 (0x40) // Single-ended P = CH4, N = COM
#define ADS7830_REG_COMMAND_CH_SINGLE_5 (0x50) // Single-ended P = CH5, N = COM
#define ADS7830_REG_COMMAND_CH_SINGLE_6 (0x60) // Single-ended P = CH6, N = COM
#define ADS7830_REG_COMMAND_CH_SINGLE_7 (0x70) // Single-ended P = CH7, N = COM
#define ADS7830_REG_COMMAND_PD_MASK (0x0C) // Power-Down Selection
#define ADS7830_REG_COMMAND_PD_PDADCONV (0x00) // Power Down Between A/D Converter Conversions
#define ADS7830_REG_COMMAND_PD_IROFF_ADON (0x04) // Internal Reference OFF and A/D Converter ON
#define ADS7830_REG_COMMAND_PD_IRON_ADOFF (0x08) // Internal Reference ON and A/D Converter OFF
#define ADS7830_REG_COMMAND_PD_IRON_ADON (0x0C) // Internal Reference ON and A/D Converter ON
/* Mode Enumerations */
typedef enum {
ADS7830_SDMODE_DIFF = ADS7830_REG_COMMAND_SD_DIFF,
ADS7830_SDMODE_SINGLE = ADS7830_REG_COMMAND_SD_SINGLE
} ADS7830_SDMode_t;
typedef enum {
ADS7830_PDADCONV = ADS7830_REG_COMMAND_PD_PDADCONV,
ADS7830_PDIROFF_ADON = ADS7830_REG_COMMAND_PD_IROFF_ADON,
ADS7830_PDIRON_ADOFF = ADS7830_REG_COMMAND_PD_IRON_ADOFF,
ADS7830_PDIRON_ADON = ADS7830_REG_COMMAND_PD_IRON_ADON
} ADS7830_PDMode_t;
/* ADC Handle Structure */
typedef struct {
I2C_HandleTypeDef *hi2c;
uint8_t i2c_addr;
ADS7830_SDMode_t sdmode;
ADS7830_PDMode_t pdmode;
uint8_t conversion_delay;
uint8_t last_conversion_result;
} ADS7830_HandleTypeDef;
/* Function Prototypes */
bool ADS7830_Init(ADS7830_HandleTypeDef *hadc, I2C_HandleTypeDef *hi2c, uint8_t i2c_addr,
ADS7830_SDMode_t sdmode, ADS7830_PDMode_t pdmode);
bool ADS7830_SetSDMode(ADS7830_HandleTypeDef *hadc, ADS7830_SDMode_t sdmode);
bool ADS7830_SetPDMode(ADS7830_HandleTypeDef *hadc, ADS7830_PDMode_t pdmode);
uint8_t ADS7830_Measure_SingleEnded(ADS7830_HandleTypeDef *hadc, uint8_t channel);
int8_t ADS7830_Measure_Differential(ADS7830_HandleTypeDef *hadc, uint8_t channel);
uint8_t ADS7830_GetLastConversionResult(ADS7830_HandleTypeDef *hadc);
#ifdef __cplusplus
}
#endif
#endif /* __ADS7830_H */
@@ -0,0 +1,211 @@
#include "ADS7830.h"
#include <string.h>
/**
* @brief Initialize the ADS7830 ADC
* @param hadc: pointer to an ADS7830_HandleTypeDef structure
* @param hi2c: pointer to an I2C_HandleTypeDef structure
* @param i2c_addr: I2C address of the ADC
* @param sdmode: Single-ended or differential mode
* @param pdmode: Power-down mode
* @retval bool: true if successful, false otherwise
*/
bool ADS7830_Init(ADS7830_HandleTypeDef *hadc, I2C_HandleTypeDef *hi2c, uint8_t i2c_addr,
ADS7830_SDMode_t sdmode, ADS7830_PDMode_t pdmode) {
if (hadc == NULL || hi2c == NULL) {
return false;
}
hadc->hi2c = hi2c;
hadc->i2c_addr = i2c_addr << 1; // HAL requires 7-bit address shifted left
hadc->sdmode = sdmode;
hadc->pdmode = pdmode;
hadc->conversion_delay = ADS7830_CONVERSIONDELAY;
hadc->last_conversion_result = 0;
/* Test communication by reading from a channel */
return (ADS7830_Measure_SingleEnded(hadc, 0) != 0xFF); // 0xFF indicates communication error
}
/**
* @brief Set Single-Ended/Differential mode
* @param hadc: pointer to an ADS7830_HandleTypeDef structure
* @param sdmode: Single-ended or differential mode
* @retval bool: true if successful, false otherwise
*/
bool ADS7830_SetSDMode(ADS7830_HandleTypeDef *hadc, ADS7830_SDMode_t sdmode) {
if (hadc == NULL) {
return false;
}
hadc->sdmode = sdmode;
return true;
}
/**
* @brief Set Power-Down mode
* @param hadc: pointer to an ADS7830_HandleTypeDef structure
* @param pdmode: Power-down mode
* @retval bool: true if successful, false otherwise
*/
bool ADS7830_SetPDMode(ADS7830_HandleTypeDef *hadc, ADS7830_PDMode_t pdmode) {
if (hadc == NULL) {
return false;
}
hadc->pdmode = pdmode;
return true;
}
/**
* @brief Measure single-ended voltage on specified channel
* @param hadc: pointer to an ADS7830_HandleTypeDef structure
* @param channel: ADC channel (0-7)
* @retval uint8_t: 8-bit conversion result (0-255), 0xFF on error
*/
uint8_t ADS7830_Measure_SingleEnded(ADS7830_HandleTypeDef *hadc, uint8_t channel) {
if (hadc == NULL || channel > 7) {
return 0xFF;
}
uint8_t config = 0;
// Set Single-Ended/Differential Inputs
config |= hadc->sdmode;
// Set Power-Down Selection
config |= hadc->pdmode;
// Set single-ended input channel
switch (channel) {
case (0):
config |= ADS7830_REG_COMMAND_CH_SINGLE_0;
break;
case (1):
config |= ADS7830_REG_COMMAND_CH_SINGLE_1;
break;
case (2):
config |= ADS7830_REG_COMMAND_CH_SINGLE_2;
break;
case (3):
config |= ADS7830_REG_COMMAND_CH_SINGLE_3;
break;
case (4):
config |= ADS7830_REG_COMMAND_CH_SINGLE_4;
break;
case (5):
config |= ADS7830_REG_COMMAND_CH_SINGLE_5;
break;
case (6):
config |= ADS7830_REG_COMMAND_CH_SINGLE_6;
break;
case (7):
config |= ADS7830_REG_COMMAND_CH_SINGLE_7;
break;
default:
return 0xFF;
}
// Write config register to the ADC
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hadc->hi2c, hadc->i2c_addr, &config, 1, HAL_MAX_DELAY);
if (status != HAL_OK) {
return 0xFF;
}
// Wait for the conversion to complete
HAL_Delay(hadc->conversion_delay);
// Read the conversion results
uint8_t result = 0;
status = HAL_I2C_Master_Receive(hadc->hi2c, hadc->i2c_addr, &result, 1, HAL_MAX_DELAY);
if (status != HAL_OK) {
return 0xFF;
}
hadc->last_conversion_result = result;
return result;
}
/**
* @brief Measure differential voltage between specified channel pairs
* @param hadc: pointer to an ADS7830_HandleTypeDef structure
* @param channel: Channel pair (01, 10, 23, 32, 45, 54, 67, 76)
* @retval int8_t: 8-bit signed conversion result (-128 to 127), 0x80 on error
*/
int8_t ADS7830_Measure_Differential(ADS7830_HandleTypeDef *hadc, uint8_t channel) {
if (hadc == NULL) {
return (int8_t)0x80;
}
uint8_t config = 0;
// Set Single-Ended/Differential Inputs
config |= hadc->sdmode;
// Set Power-Down Selection
config |= hadc->pdmode;
// Set Differential input channel
switch (channel) {
case (01):
config |= ADS7830_REG_COMMAND_CH_DIFF_0_1; // CH0 = P, CH1 = N
break;
case (10):
config |= ADS7830_REG_COMMAND_CH_DIFF_1_0; // CH1 = P, CH0 = N
break;
case (23):
config |= ADS7830_REG_COMMAND_CH_DIFF_2_3; // CH2 = P, CH3 = N
break;
case (32):
config |= ADS7830_REG_COMMAND_CH_DIFF_3_2; // CH3 = P, CH2 = N
break;
case (45):
config |= ADS7830_REG_COMMAND_CH_DIFF_4_5; // CH4 = P, CH5 = N
break;
case (54):
config |= ADS7830_REG_COMMAND_CH_DIFF_5_4; // CH5 = P, CH4 = N
break;
case (67):
config |= ADS7830_REG_COMMAND_CH_DIFF_6_7; // CH6 = P, CH7 = N
break;
case (76):
config |= ADS7830_REG_COMMAND_CH_DIFF_7_6; // CH7 = P, CH6 = N
break;
default:
return (int8_t)0x80;
}
// Write config register to the ADC
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hadc->hi2c, hadc->i2c_addr, &config, 1, HAL_MAX_DELAY);
if (status != HAL_OK) {
return (int8_t)0x80;
}
// Wait for the conversion to complete
HAL_Delay(hadc->conversion_delay);
// Read the conversion results
uint8_t raw_adc = 0;
status = HAL_I2C_Master_Receive(hadc->hi2c, hadc->i2c_addr, &raw_adc, 1, HAL_MAX_DELAY);
if (status != HAL_OK) {
return (int8_t)0x80;
}
// Convert to signed 8-bit value
int8_t result = (int8_t)raw_adc;
hadc->last_conversion_result = raw_adc;
return result;
}
/**
* @brief Get the last conversion result
* @param hadc: pointer to an ADS7830_HandleTypeDef structure
* @retval uint8_t: Last conversion result
*/
uint8_t ADS7830_GetLastConversionResult(ADS7830_HandleTypeDef *hadc) {
if (hadc == NULL) {
return 0;
}
return hadc->last_conversion_result;
}
@@ -0,0 +1,462 @@
/***************************************************************************************************/
/*
This is an Arduino basic library for Bosch BMP180 & BMP085 barometric pressure &
temperature sensor
Power supply voltage: 1.8v - 3.6v
Range: 30,000Pa..110,000Pa at -40°C..+85°C
Typ. resolution: 1Pa / 0.1°C
Typ. accuracy: ±100Pa* / ±1.0°C* at 0°C..+65°C
Typ. relative accuracy: ±12Pa / xx°C
Duty cycle: 10% active & 90% inactive, to prevent self heating
*sensor is sensitive to direct light, which can affect
the accuracy of the measurement
written by : enjoyneering79
sourse code: https://github.com/enjoyneering/
This chip uses I2C bus to communicate, specials pins are required to interface
Board: SDA SCL Level
Uno, Mini, Pro, ATmega168, ATmega328..... A4 A5 5v
Mega2560................................. 20 21 5v
Due, SAM3X8E............................. 20 21 3.3v
Leonardo, Micro, ATmega32U4.............. 2 3 5v
Digistump, Trinket, ATtiny85............. 0/physical pin no.5 2/physical pin no.7 5v
Blue Pill, STM32F103xxxx boards.......... PB7 PB6 3.3v/5v
ESP8266 ESP-01........................... GPIO0/D5 GPIO2/D3 3.3v/5v
NodeMCU 1.0, WeMos D1 Mini............... GPIO4/D2 GPIO5/D1 3.3v/5v
ESP32.................................... GPIO21/D21 GPIO22/D22 3.3v
NOTE:
- EOC pin is not used, shows the end of conversion
- XCLR pin is not used, reset pin
Frameworks & Libraries:
ATtiny Core - https://github.com/SpenceKonde/ATTinyCore
ESP32 Core - https://github.com/espressif/arduino-esp32
ESP8266 Core - https://github.com/esp8266/Arduino
STM32 Core - https://github.com/rogerclarkmelbourne/Arduino_STM32
GNU GPL license, all text above must be included in any redistribution,
see link for details - https://www.gnu.org/licenses/licenses.html
*/
/***************************************************************************************************/
#include "BMP180.h"
/**************************************************************************/
/*
Constructor
NOTE:
- BMP180_ULTRALOWPOWER, pressure oversampled 1 time & consumption 3μA
- BMP180_STANDARD, pressure oversampled 2 times & consumption 5μA
- BMP180_HIGHRES, pressure oversampled 4 times & consumption 7μA
- BMP180_ULTRAHIGHRES, pressure oversampled 8 times & consumption 12μA
*/
/**************************************************************************/
BMP180::BMP180(BMP180_RESOLUTION res_mode)
{
_resolution = res_mode;
}
/**************************************************************************/
/*
getPressure()
Calculates compensated pressure, in Pa
NOTE:
- resolutin 1Pa with accuracy ±150Pa at range 30,000Pa..110,000Pa
*/
/**************************************************************************/
int32_t BMP180::getPressure(void)
{
int32_t UT = 0;
int32_t UP = 0;
int32_t B3 = 0;
int32_t B5 = 0;
int32_t B6 = 0;
int32_t X1 = 0;
int32_t X2 = 0;
int32_t X3 = 0;
int32_t pressure = 0;
uint32_t B4 = 0;
uint32_t B7 = 0;
UT = readRawTemperature(); //read uncompensated temperature, 16-bit
if (UT == BMP180_ERROR) return BMP180_ERROR; //error handler, collision on i2c bus
UP = readRawPressure(); //read uncompensated pressure, 19-bit
if (UP == BMP180_ERROR) return BMP180_ERROR; //error handler, collision on i2c bus
B5 = computeB5(UT);
/* pressure calculation */
B6 = B5 - 4000;
X1 = ((int32_t)_calCoeff.bmpB2 * ((B6 * B6) >> 12)) >> 11;
X2 = ((int32_t)_calCoeff.bmpAC2 * B6) >> 11;
X3 = X1 + X2;
B3 = ((((int32_t)_calCoeff.bmpAC1 * 4 + X3) << _resolution) + 2) / 4;
X1 = ((int32_t)_calCoeff.bmpAC3 * B6) >> 13;
X2 = ((int32_t)_calCoeff.bmpB1 * ((B6 * B6) >> 12)) >> 16;
X3 = ((X1 + X2) + 2) >> 2;
B4 = ((uint32_t)_calCoeff.bmpAC4 * (X3 + 32768L)) >> 15;
B7 = (UP - B3) * (50000UL >> _resolution);
if (B4 == 0) return BMP180_ERROR; //safety check, avoiding division by zero
if (B7 < 0x80000000) pressure = (B7 * 2) / B4;
else pressure = (B7 / B4) * 2;
X1 = pow((pressure >> 8), 2);
X1 = (X1 * 3038L) >> 16;
X2 = (-7357L * pressure) >> 16;
return pressure = pressure + ((X1 + X2 + 3791L) >> 4);
}
/**************************************************************************/
/*
getTemperature()
Calculates compensated temperature, in °C
NOTE:
- resolution 0.1°C with accuracy ±1.0°C at range 0°C..+65°C
*/
/**************************************************************************/
float BMP180::getTemperature(void)
{
int16_t rawTemperature = readRawTemperature();
if (rawTemperature == BMP180_ERROR) return BMP180_ERROR; //error handler, collision on i2c bus
return (float)((computeB5(rawTemperature) + 8) >> 4) / 10;
}
/**************************************************************************/
/*
getSeaLevelPressure()
Converts current pressure to sea level pressure at specific true
altitude, in Pa
NOTE:
- true altitude is the actual elevation above sea level, to find out
your current true altitude do search with google earth or gps
- see level pressure is commonly used in weather reports & forecasts
to compensate current true altitude
- for example, we know that a sunny day happens if the current sea
level pressure is 250Pa above the average sea level pressure of
101325 Pa, so by converting the current pressure to sea level &
comparing it with an average sea level pressure we can instantly
predict the weather conditions
*/
/**************************************************************************/
int32_t BMP180::getSeaLevelPressure(int16_t trueAltitude)
{
int32_t pressure = getPressure();
if (pressure == BMP180_ERROR) return BMP180_ERROR;
return (pressure / pow(1.0 - (float)trueAltitude / 44330, 5.255));
}
/**************************************************************************/
/*
softReset()
Soft reset
NOTE:
- performs the same sequence as power on reset
*/
/**************************************************************************/
void BMP180::softReset(void)
{
write8(BMP180_SOFT_RESET_REG, BMP180_SOFT_RESET_CTRL);
}
/**************************************************************************/
/*
readFirmwareVersion()
Reads ML & AL Version
NOTE:
- ML version is LSB, 4-bit..0-bit
- AL version is MSB, 7-bit..5-bit
*/
/**************************************************************************/
uint8_t BMP180::readFirmwareVersion(void)
{
return read8(BMP180_GET_VERSION_REG);
}
/**************************************************************************/
/*
readDeviceID()
Reads chip ID
*/
/**************************************************************************/
uint8_t BMP180::readDeviceID(void)
{
if (read8(BMP180_GET_ID_REG) == BMP180_CHIP_ID) return 180;
return false;
}
/**************************************************************************/
/*
readCalibrationCoefficients()
Reads factory calibration coefficients from E2PROM
NOTE:
- every sensor module has individual calibration coefficients
- before first temperature & pressure calculation master have to read
calibration coefficients from 176-bit E2PROM
*/
/**************************************************************************/
bool BMP180::readCalibrationCoefficients()
{
int32_t value = 0;
for (uint8_t reg = BMP180_CAL_AC1_REG; reg <= BMP180_CAL_MD_REG; reg++)
{
value = read16(reg);
if (value == BMP180_ERROR) return false; //error handler, collision on i2c bus
switch (reg)
{
case BMP180_CAL_AC1_REG: //used for pressure computation
_calCoeff.bmpAC1 = value;
break;
case BMP180_CAL_AC2_REG: //used for pressure computation
_calCoeff.bmpAC2 = value;
break;
case BMP180_CAL_AC3_REG: //used for pressure computation
_calCoeff.bmpAC3 = value;
break;
case BMP180_CAL_AC4_REG: //used for pressure computation
_calCoeff.bmpAC4 = value;
break;
case BMP180_CAL_AC5_REG: //used for temperature computation
_calCoeff.bmpAC5 = value;
break;
case BMP180_CAL_AC6_REG: //used for temperature computation
_calCoeff.bmpAC6 = value;
break;
case BMP180_CAL_B1_REG: //used for pressure computation
_calCoeff.bmpB1 = value;
break;
case BMP180_CAL_B2_REG: //used for pressure computation
_calCoeff.bmpB2 = value;
break;
case BMP180_CAL_MB_REG: //???
_calCoeff.bmpMB = value;
break;
case BMP180_CAL_MC_REG: //used for temperature computation
_calCoeff.bmpMC = value;
break;
case BMP180_CAL_MD_REG: //used for temperature computation
_calCoeff.bmpMD = value;
break;
}
}
return true;
}
/**************************************************************************/
/*
readRawTemperature()
Reads raw/uncompensated temperature value, 16-bit
*/
/**************************************************************************/
uint16_t BMP180::readRawTemperature(void)
{
/* send temperature measurement command */
if (write8(BMP180_START_MEASURMENT_REG, BMP180_GET_TEMPERATURE_CTRL) != true) return BMP180_ERROR; //error handler, collision on i2c bus
/* set measurement delay */
HAL_Delay(5);
/* read result */
return read16(BMP180_READ_ADC_MSB_REG); //reads msb + lsb
}
/**************************************************************************/
/*
readRawPressure()
Reads raw/uncompensated pressure value, 19-bits
*/
/**************************************************************************/
uint32_t BMP180::readRawPressure(void)
{
uint8_t regControl = 0;
uint32_t rawPressure = 0;
/* convert resolution to register control */
switch (_resolution)
{
case BMP180_ULTRALOWPOWER: //oss0
regControl = BMP180_GET_PRESSURE_OSS0_CTRL;
break;
case BMP180_STANDARD: //oss1
regControl = BMP180_GET_PRESSURE_OSS1_CTRL;
break;
case BMP180_HIGHRES: //oss2
regControl = BMP180_GET_PRESSURE_OSS2_CTRL;
break;
case BMP180_ULTRAHIGHRES: //oss3
regControl = BMP180_GET_PRESSURE_OSS3_CTRL;
break;
}
/* send pressure measurement command */
if (write8(BMP180_START_MEASURMENT_REG, regControl) != true) return BMP180_ERROR; //error handler, collision on i2c bus
/* set measurement delay */
switch (_resolution)
{
case BMP180_ULTRALOWPOWER:
HAL_Delay(5);
break;
case BMP180_STANDARD:
HAL_Delay(8);
break;
case BMP180_HIGHRES:
HAL_Delay(14);
break;
case BMP180_ULTRAHIGHRES:
HAL_Delay(26);
break;
}
/* read result msb + lsb */
rawPressure = read16(BMP180_READ_ADC_MSB_REG); //16-bits
if (rawPressure == BMP180_ERROR) return BMP180_ERROR; //error handler, collision on i2c bus
/* read result xlsb */
rawPressure <<= 8;
rawPressure |= read8(BMP180_READ_ADC_XLSB_REG); //19-bits
rawPressure >>= (8 - _resolution);
return rawPressure;
}
/**************************************************************************/
/*
computeB5()
Computes B5 value
NOTE:
- to compensate raw/uncompensated temperature
- also used for compensated pressure calculation
*/
/**************************************************************************/
int32_t BMP180::computeB5(int32_t UT)
{
int32_t X1 = ((UT - (int32_t)_calCoeff.bmpAC6) * (int32_t)_calCoeff.bmpAC5) >> 15;
int32_t X2 = ((int32_t)_calCoeff.bmpMC << 11) / (X1 + (int32_t)_calCoeff.bmpMD);
return X1 + X2;
}
/**************************************************************************/
/*
read8()
Reads 8-bit value over I2C
*/
/**************************************************************************/
uint8_t BMP180::read8(uint8_t reg)
{
uint8_t data = 0;
HAL_StatusTypeDef status;
// Write register address
status = HAL_I2C_Master_Transmit(&hi2c3, BMP180_ADDRESS, &reg, 1, I2C_TIMEOUT);
if (status != HAL_OK) return BMP180_ERROR;
// Read data from register
status = HAL_I2C_Master_Receive(&hi2c3, BMP180_ADDRESS, &data, 1, I2C_TIMEOUT);
if (status != HAL_OK) return BMP180_ERROR;
return data;
}
/**************************************************************************/
/*
read16()
Reads 16-bits value over I2C
*/
/**************************************************************************/
uint16_t BMP180::read16(uint8_t reg)
{
uint8_t data[2] = {0, 0};
uint16_t value = 0;
HAL_StatusTypeDef status;
// Write register address
status = HAL_I2C_Master_Transmit(&hi2c3, BMP180_ADDRESS, &reg, 1, I2C_TIMEOUT);
if (status != HAL_OK) return BMP180_ERROR;
// Read 2 bytes from register
status = HAL_I2C_Master_Receive(&hi2c3, BMP180_ADDRESS, data, 2, I2C_TIMEOUT);
if (status != HAL_OK) return BMP180_ERROR;
// Combine bytes (MSB first)
value = (data[0] << 8) | data[1];
return value;
}
/**************************************************************************/
/*
write8()
Writes 8-bits value over I2C
*/
/**************************************************************************/
bool BMP180::write8(uint8_t reg, uint8_t control)
{
uint8_t data[2] = {reg, control};
HAL_StatusTypeDef status;
// Write register address and data
status = HAL_I2C_Master_Transmit(&hi2c3, BMP180_ADDRESS, data, 2, I2C_TIMEOUT);
return (status == HAL_OK);
}
@@ -0,0 +1,156 @@
/***************************************************************************************************/
/*
This is an Arduino basic library for Bosch BMP180 & BMP085 barometric pressure &
temperature sensor
Power supply voltage: 1.8v - 3.6v
Range: 30,000Pa..110,000Pa at -40°C..+85°C
Typ. resolution: 1Pa / 0.1°C
Typ. accuracy: ±100Pa* / ±1.0°C* at 0°C..+65°C
Typ. relative accuracy: ±12Pa / xx°C
Duty cycle: 10% active & 90% inactive, to prevent self heating
*sensor is sensitive to direct light, which can affect
the accuracy of the measurement
written by : enjoyneering79
sourse code: https://github.com/enjoyneering/
This chip uses I2C bus to communicate, specials pins are required to interface
Board: SDA SCL Level
Uno, Mini, Pro, ATmega168, ATmega328..... A4 A5 5v
Mega2560................................. 20 21 5v
Due, SAM3X8E............................. 20 21 3.3v
Leonardo, Micro, ATmega32U4.............. 2 3 5v
Digistump, Trinket, ATtiny85............. 0/physical pin no.5 2/physical pin no.7 5v
Blue Pill, STM32F103xxxx boards.......... PB7 PB6 3.3v/5v
ESP8266 ESP-01........................... GPIO0/D5 GPIO2/D3 3.3v/5v
NodeMCU 1.0, WeMos D1 Mini............... GPIO4/D2 GPIO5/D1 3.3v/5v
ESP32.................................... GPIO21/D21 GPIO22/D22 3.3v
NOTE:
- EOC pin is not used, shows the end of conversion
- XCLR pin is not used, reset pin
Frameworks & Libraries:
ATtiny Core - https://github.com/SpenceKonde/ATTinyCore
ESP32 Core - https://github.com/espressif/arduino-esp32
ESP8266 Core - https://github.com/esp8266/Arduino
STM32 Core - https://github.com/rogerclarkmelbourne/Arduino_STM32
GNU GPL license, all text above must be included in any redistribution,
see link for details - https://www.gnu.org/licenses/licenses.html
*/
/***************************************************************************************************/
#ifndef BMP180_h
#define BMP180_h
#include "stm32f7xx_hal.h"
#include <cmath>
extern I2C_HandleTypeDef hi2c3;
/* resolutions */
typedef enum : uint8_t
{
BMP180_ULTRALOWPOWER = 0x00, //low power mode, oss0
BMP180_STANDARD = 0x01, //standard mode, oss1
BMP180_HIGHRES = 0x02, //high resolution mode, oss2
BMP180_ULTRAHIGHRES = 0x03 //ultra high resolution mode, oss3
}
BMP180_RESOLUTION;
/* calibration registers */
typedef enum : uint8_t
{
BMP180_CAL_AC1_REG = 0xAA, //ac1 pressure computation
BMP180_CAL_AC2_REG = 0xAC, //ac2 pressure computation
BMP180_CAL_AC3_REG = 0xAE, //ac3 pressure computation
BMP180_CAL_AC4_REG = 0xB0, //ac4 pressure computation
BMP180_CAL_AC5_REG = 0xB2, //ac5 temperature computation
BMP180_CAL_AC6_REG = 0xB4, //ac6 temperature computation
BMP180_CAL_B1_REG = 0xB6, //b1 pressure computation
BMP180_CAL_B2_REG = 0xB8, //b2 pressure computation
BMP180_CAL_MB_REG = 0xBA, //mb
BMP180_CAL_MC_REG = 0xBC, //mc temperature computation
BMP180_CAL_MD_REG = 0xBE //md temperature computation
}
BMP180_CAL_REG;
#define BMP180_GET_ID_REG 0xD0 //device id register
#define BMP180_GET_VERSION_REG 0xD1 //device version register
#define BMP180_SOFT_RESET_REG 0xE0 //soft reset register
#define BMP180_SOFT_RESET_CTRL 0xB6 //soft reset control
#define BMP180_START_MEASURMENT_REG 0xF4 //start measurment register
#define BMP180_READ_ADC_MSB_REG 0xF6 //read adc msb register
#define BMP180_READ_ADC_LSB_REG 0xF7 //read adc lsb register
#define BMP180_READ_ADC_XLSB_REG 0xF8 //read adc xlsb register
/* BMP180_START_MEASURMENT_REG controls */
#define BMP180_GET_TEMPERATURE_CTRL 0x2E //get temperature control
#define BMP180_GET_PRESSURE_OSS0_CTRL 0x34 //get pressure oversampling 1 time/oss0 control
#define BMP180_GET_PRESSURE_OSS1_CTRL 0x74 //get pressure oversampling 2 time/oss1 control
#define BMP180_GET_PRESSURE_OSS2_CTRL 0xB4 //get pressure oversampling 4 time/oss2 control
#define BMP180_GET_PRESSURE_OSS3_CTRL 0xF4 //get pressure oversampling 8 time/oss3 control
/* misc */
#define BMP180_CHIP_ID 0x55 //id number
#define BMP180_ERROR 255 //returns 255, if communication error is occurred
#define BMP180_ADDRESS (0x77 << 1) // HAL requires 7-bit address shifted left by 1 bit
#define I2C_TIMEOUT 100
/* to store calibration coefficients */
typedef struct
{
int16_t bmpAC1 = 0;
int16_t bmpAC2 = 0;
int16_t bmpAC3 = 0;
uint16_t bmpAC4 = 0;
uint16_t bmpAC5 = 0;
uint16_t bmpAC6 = 0;
int16_t bmpB1 = 0;
int16_t bmpB2 = 0;
int16_t bmpMB = 0;
int16_t bmpMC = 0;
int16_t bmpMD = 0;
}
BMP180_CAL_COEFF;
class BMP180
{
public:
BMP180(BMP180_RESOLUTION = BMP180_ULTRAHIGHRES); //BMP180_ULTRAHIGHRES, by default
int32_t getPressure(void); //in Pa
float getTemperature(void); //in °C
int32_t getSeaLevelPressure(int16_t trueAltitude = 115); //in Pa, by default true altitude id 115 meters
void softReset(void);
uint8_t readFirmwareVersion(void);
uint8_t readDeviceID(void);
private:
BMP180_CAL_COEFF _calCoeff;
uint8_t _resolution;
bool readCalibrationCoefficients(void);
uint16_t readRawTemperature(void);
uint32_t readRawPressure(void);
int32_t computeB5(int32_t UT);
uint8_t read8(uint8_t reg);
uint16_t read16(uint8_t reg);
bool write8(uint8_t reg, uint8_t control);
};
#endif
@@ -0,0 +1,397 @@
#include "DAC5578.h"
#include <string.h>
/**
* @brief Initialize the DAC5578
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
* @param hi2c: pointer to an I2C_HandleTypeDef structure
* @param i2c_addr: I2C address of the DAC
* @param resolution: DAC resolution (only 8 is valid for DAC5578)
* @param ldac_port: GPIO port for LDAC pin
* @param ldac_pin: GPIO pin for LDAC pin
* @param clr_port: GPIO port for CLR pin
* @param clr_pin: GPIO pin for CLR pin
* @retval bool: true if successful, false otherwise
*/
bool DAC5578_Init(DAC5578_HandleTypeDef *hdac, I2C_HandleTypeDef *hi2c, uint8_t i2c_addr,
uint8_t resolution, GPIO_TypeDef *ldac_port, uint16_t ldac_pin,
GPIO_TypeDef *clr_port, uint16_t clr_pin) {
if (hdac == NULL || hi2c == NULL) {
return false;
}
/* DAC5578 is 8-bit only */
hdac->resolution_bits = 8;
hdac->clear_code = DAC5578_CLR_CODE_ZERO; // Default clear to zero
hdac->hi2c = hi2c;
hdac->i2c_addr = i2c_addr << 1; // HAL requires 7-bit address shifted left
hdac->ldac_port = ldac_port;
hdac->ldac_pin = ldac_pin;
hdac->clr_port = clr_port;
hdac->clr_pin = clr_pin;
/* Set LDAC high (inactive) and CLR high (normal operation) */
if (ldac_port != NULL) {
HAL_GPIO_WritePin(ldac_port, ldac_pin, GPIO_PIN_SET);
}
if (clr_port != NULL) {
HAL_GPIO_WritePin(clr_port, clr_pin, GPIO_PIN_SET);
}
/* Reset the DAC and enable internal reference by default */
bool success = DAC5578_Reset(hdac);
if (success) {
success = DAC5578_SetInternalReference(hdac, true);
}
/* Set the clear code in the device */
if (success) {
success = DAC5578_SetClearCode(hdac, hdac->clear_code);
}
return success;
}
/**
* @brief Reset the DAC5578
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
* @retval bool: true if successful, false otherwise
*/
bool DAC5578_Reset(DAC5578_HandleTypeDef *hdac) {
uint8_t buffer[3];
buffer[0] = DAC5578_CMD_RESET;
buffer[1] = 0x00;
buffer[2] = 0x00;
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hdac->hi2c, hdac->i2c_addr, buffer, 3, HAL_MAX_DELAY);
return (status == HAL_OK);
}
/**
* @brief Write a value to a specific channel's input register
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
* @param channel: DAC channel (0-7)
* @param value: 8-bit value to write
* @retval bool: true if successful, false otherwise
*/
bool DAC5578_WriteChannelValue(DAC5578_HandleTypeDef *hdac, uint8_t channel, uint16_t value) {
if (channel > 7) {
return false;
}
/* DAC5578 is 8-bit, so mask value */
value &= 0xFF;
return DAC5578_CommandWrite(hdac, DAC5578_CMD_WRITE | (channel & 0x7), value);
}
/**
* @brief Update a specific channel's DAC register from input register
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
* @param channel: DAC channel (0-7) or DAC5578_CHANNEL_BROADCAST
* @retval bool: true if successful, false otherwise
*/
bool DAC5578_UpdateChannel(DAC5578_HandleTypeDef *hdac, uint8_t channel) {
if (channel > 7 && channel != DAC5578_CHANNEL_BROADCAST) {
return false;
}
/* Update command with channel selection */
uint8_t command = DAC5578_CMD_UPDATE | (channel & 0x7);
if (channel == DAC5578_CHANNEL_BROADCAST) {
command = DAC5578_CMD_UPDATE | 0x8; // Broadcast flag
}
uint8_t buffer[3];
buffer[0] = command;
buffer[1] = 0x00;
buffer[2] = 0x00;
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hdac->hi2c, hdac->i2c_addr, buffer, 3, HAL_MAX_DELAY);
return (status == HAL_OK);
}
/**
* @brief Write and update a specific channel in one operation
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
* @param channel: DAC channel (0-7)
* @param value: 8-bit value to write and update
* @retval bool: true if successful, false otherwise
*/
bool DAC5578_WriteAndUpdateChannelValue(DAC5578_HandleTypeDef *hdac, uint8_t channel, uint16_t value) {
if (channel > 7) {
return false;
}
/* DAC5578 is 8-bit, so mask value */
value &= 0xFF;
return DAC5578_CommandWrite(hdac, DAC5578_CMD_WRITE_UPDATE | (channel & 0x7), value);
}
/**
* @brief Write the same value to all channels' input registers
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
* @param value: 8-bit value to write to all channels
* @retval bool: true if successful, false otherwise
*/
bool DAC5578_WriteAllChannels(DAC5578_HandleTypeDef *hdac, uint16_t value) {
/* DAC5578 is 8-bit, so mask value */
value &= 0xFF;
return DAC5578_CommandWrite(hdac, DAC5578_CMD_WRITE_ALL, value);
}
/**
* @brief Read the input register value of a specific channel
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
* @param channel: DAC channel (0-7)
* @param value: pointer to store the read value
* @retval bool: true if successful, false otherwise
*/
bool DAC5578_ReadInputChannelValue(DAC5578_HandleTypeDef *hdac, uint8_t channel, uint16_t *value) {
if (channel > 7) {
return false;
}
/* Note: DAC5578 has limited read capability - this reads back the input register */
return DAC5578_CommandRead(hdac, DAC5578_CMD_WRITE | (channel & 0x7), value);
}
/**
* @brief Read the DAC register value (current output) of a specific channel
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
* @param channel: DAC channel (0-7)
* @param value: pointer to store the read value
* @retval bool: true if successful, false otherwise
*/
bool DAC5578_ReadDACChannelValue(DAC5578_HandleTypeDef *hdac, uint8_t channel, uint16_t *value) {
if (channel > 7) {
return false;
}
/* Note: DAC5578 has limited read capability - this reads back the DAC register */
return DAC5578_CommandRead(hdac, DAC5578_CMD_UPDATE | (channel & 0x7), value);
}
/**
* @brief Set power down mode for a specific channel
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
* @param channel: DAC channel (0-7)
* @param mode: power down mode
* @retval bool: true if successful, false otherwise
*/
bool DAC5578_SetPowerDownMode(DAC5578_HandleTypeDef *hdac, uint8_t channel, DAC5578_PowerDownMode_t mode) {
if (channel > 7 || mode > 3) {
return false;
}
uint8_t buffer[3];
buffer[0] = DAC5578_CMD_POWERDOWN | (channel & 0x7);
buffer[1] = 0x00;
buffer[2] = mode & 0x03;
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hdac->hi2c, hdac->i2c_addr, buffer, 3, HAL_MAX_DELAY);
return (status == HAL_OK);
}
/**
* @brief Set power down mode for all channels
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
* @param mode: power down mode
* @retval bool: true if successful, false otherwise
*/
bool DAC5578_SetPowerDownAll(DAC5578_HandleTypeDef *hdac, DAC5578_PowerDownMode_t mode) {
if (mode > 3) {
return false;
}
uint8_t buffer[3];
buffer[0] = DAC5578_CMD_POWERDOWN_ALL;
buffer[1] = 0x00;
buffer[2] = mode & 0x03;
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hdac->hi2c, hdac->i2c_addr, buffer, 3, HAL_MAX_DELAY);
return (status == HAL_OK);
}
/**
* @brief Enable or disable the internal reference
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
* @param enable: true to enable, false to disable
* @retval bool: true if successful, false otherwise
*/
bool DAC5578_SetInternalReference(DAC5578_HandleTypeDef *hdac, bool enable) {
uint8_t command = enable ? DAC5578_CMD_INT_REF_ENABLE : DAC5578_CMD_INT_REF_DISABLE;
uint8_t buffer[3];
buffer[0] = command;
buffer[1] = 0x00;
buffer[2] = 0x00;
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hdac->hi2c, hdac->i2c_addr, buffer, 3, HAL_MAX_DELAY);
return (status == HAL_OK);
}
/**
* @brief Setup LDAC mask for hardware LDAC control
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
* @param ldac_mask: 8-bit mask where each bit corresponds to a channel
* @retval bool: true if successful, false otherwise
*/
bool DAC5578_SetupLDAC(DAC5578_HandleTypeDef *hdac, uint8_t ldac_mask) {
uint8_t buffer[3];
buffer[0] = DAC5578_CMD_LDAC_SETUP;
buffer[1] = 0x00;
buffer[2] = ldac_mask & 0xFF; // Each bit corresponds to a channel (0-7)
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hdac->hi2c, hdac->i2c_addr, buffer, 3, HAL_MAX_DELAY);
return (status == HAL_OK);
}
/**
* @brief Trigger software LDAC update
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
* @retval bool: true if successful, false otherwise
*/
bool DAC5578_SoftwareLDAC(DAC5578_HandleTypeDef *hdac) {
uint8_t buffer[3];
buffer[0] = DAC5578_CMD_SOFTWARE_LDAC;
buffer[1] = 0x00;
buffer[2] = 0x00;
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hdac->hi2c, hdac->i2c_addr, buffer, 3, HAL_MAX_DELAY);
return (status == HAL_OK);
}
/* CLR Pin Functions */
/**
* @brief Set the clear code that determines what happens when CLR pin is activated
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
* @param clear_code: desired clear code behavior
* @retval bool: true if successful, false otherwise
*/
bool DAC5578_SetClearCode(DAC5578_HandleTypeDef *hdac, DAC5578_ClearCode_t clear_code) {
if (clear_code > DAC5578_CLR_CODE_NOP) {
return false;
}
/* The clear code is set using the RESET command with specific data bits */
uint8_t buffer[3];
buffer[0] = DAC5578_CMD_RESET;
buffer[1] = 0x00;
buffer[2] = (clear_code & 0x03); // Clear code in bits 1:0
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hdac->hi2c, hdac->i2c_addr, buffer, 3, HAL_MAX_DELAY);
if (status == HAL_OK) {
hdac->clear_code = clear_code;
return true;
}
return false;
}
/**
* @brief Get the current clear code setting
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
* @retval DAC5578_ClearCode_t: current clear code setting
*/
DAC5578_ClearCode_t DAC5578_GetClearCode(DAC5578_HandleTypeDef *hdac) {
return hdac->clear_code;
}
/**
* @brief Activate the CLR pin (set low) to clear DAC outputs
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
* @retval None
*/
void DAC5578_ActivateClearPin(DAC5578_HandleTypeDef *hdac) {
if (hdac->clr_port != NULL) {
HAL_GPIO_WritePin(hdac->clr_port, hdac->clr_pin, GPIO_PIN_RESET);
}
}
/**
* @brief Deactivate the CLR pin (set high) for normal operation
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
* @retval None
*/
void DAC5578_DeactivateClearPin(DAC5578_HandleTypeDef *hdac) {
if (hdac->clr_port != NULL) {
HAL_GPIO_WritePin(hdac->clr_port, hdac->clr_pin, GPIO_PIN_SET);
}
}
/**
* @brief Pulse the CLR pin to clear all DAC outputs according to clear code
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
* @retval None
*/
void DAC5578_ClearOutputs(DAC5578_HandleTypeDef *hdac) {
if (hdac->clr_port != NULL) {
/* Generate a pulse on CLR pin (active low) */
HAL_GPIO_WritePin(hdac->clr_port, hdac->clr_pin, GPIO_PIN_RESET);
HAL_Delay(1); // Hold for at least 50ns (1ms is plenty)
HAL_GPIO_WritePin(hdac->clr_port, hdac->clr_pin, GPIO_PIN_SET);
}
}
/**
* @brief Software clear - uses I2C command to clear outputs without CLR pin
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
* @retval bool: true if successful, false otherwise
*/
bool DAC5578_SoftwareClear(DAC5578_HandleTypeDef *hdac) {
/* Use the reset command with the current clear code to perform software clear */
return DAC5578_SetClearCode(hdac, hdac->clear_code);
}
/* Private functions */
/**
* @brief Write a command and value to the DAC
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
* @param command: command byte
* @param value: 8-bit value to write
* @retval bool: true if successful, false otherwise
*/
bool DAC5578_CommandWrite(DAC5578_HandleTypeDef *hdac, uint8_t command, uint16_t value) {
uint8_t buffer[3];
buffer[0] = command;
buffer[1] = (value >> 8) & 0xFF; // MSB (should be 0 for 8-bit DAC)
buffer[2] = value & 0xFF; // LSB (actual 8-bit data)
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hdac->hi2c, hdac->i2c_addr, buffer, 3, HAL_MAX_DELAY);
return (status == HAL_OK);
}
/**
* @brief Read a value from the DAC after sending a command
* @param hdac: pointer to a DAC5578_HandleTypeDef structure
* @param command: command byte
* @param value: pointer to store the read value
* @retval bool: true if successful, false otherwise
*/
bool DAC5578_CommandRead(DAC5578_HandleTypeDef *hdac, uint8_t command, uint16_t *value) {
uint8_t buffer[3];
/* First write the command to set up readback */
HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(hdac->hi2c, hdac->i2c_addr, &command, 1, HAL_MAX_DELAY);
if (status != HAL_OK) {
return false;
}
/* Then read 3 bytes back */
status = HAL_I2C_Master_Receive(hdac->hi2c, hdac->i2c_addr, buffer, 3, HAL_MAX_DELAY);
if (status != HAL_OK) {
return false;
}
/* Extract the 8-bit value from the response */
*value = buffer[2] & 0xFF;
return true;
}
@@ -0,0 +1,91 @@
#ifndef __DAC5578_H
#define __DAC5578_H
#ifdef __cplusplus
extern "C" {
#endif
#include "stm32f7xx_hal.h"
#include <stdbool.h>
extern I2C_HandleTypeDef hi2c1;
/* Command definitions - DAC5578 specific */
#define DAC5578_CMD_WRITE (0x0 << 4) // Write to input register
#define DAC5578_CMD_UPDATE (0x1 << 4) // Update DAC register
#define DAC5578_CMD_WRITE_UPDATE (0x2 << 4) // Write and update
#define DAC5578_CMD_WRITE_ALL (0x3 << 4) // Write to all channels
#define DAC5578_CMD_POWERDOWN (0x4 << 4) // Power down
#define DAC5578_CMD_POWERDOWN_ALL (0x5 << 4) // Power down all channels
#define DAC5578_CMD_INT_REF_ENABLE (0x6 << 4) // Enable internal reference
#define DAC5578_CMD_INT_REF_DISABLE (0x7 << 4) // Disable internal reference
#define DAC5578_CMD_RESET (0x8 << 4) // Software reset
#define DAC5578_CMD_LDAC_SETUP (0x9 << 4) // LDAC setup register
#define DAC5578_CMD_SOFTWARE_LDAC (0xA << 4) // Software LDAC trigger
/* Broadcast channel for simultaneous updates */
#define DAC5578_CHANNEL_BROADCAST 0x8
/* Power down modes */
typedef enum {
DAC5578_PWD_NORMAL = 0, // Normal operation
DAC5578_PWD_1K = 1, // 1kΩ to GND
DAC5578_PWD_100K = 2, // 100kΩ to GND
DAC5578_PWD_HIZ = 3 // High impedance
} DAC5578_PowerDownMode_t;
/* Clear code options - determines what happens when CLR pin is activated */
typedef enum {
DAC5578_CLR_CODE_ZERO = 0, // Clear to zero scale (0x00)
DAC5578_CLR_CODE_MID = 1, // Clear to midscale (0x80)
DAC5578_CLR_CODE_FULL = 2, // Clear to full scale (0xFF)
DAC5578_CLR_CODE_NOP = 3 // No operation (retain current value)
} DAC5578_ClearCode_t;
/* DAC handle structure */
typedef struct {
I2C_HandleTypeDef *hi2c;
uint8_t i2c_addr;
uint8_t resolution_bits;
GPIO_TypeDef *ldac_port;
uint16_t ldac_pin;
GPIO_TypeDef *clr_port;
uint16_t clr_pin;
DAC5578_ClearCode_t clear_code; // Current clear code setting
} DAC5578_HandleTypeDef;
/* Function prototypes */
bool DAC5578_Init(DAC5578_HandleTypeDef *hdac, I2C_HandleTypeDef *hi2c, uint8_t i2c_addr,
uint8_t resolution, GPIO_TypeDef *ldac_port, uint16_t ldac_pin,
GPIO_TypeDef *clr_port, uint16_t clr_pin);
bool DAC5578_Reset(DAC5578_HandleTypeDef *hdac);
bool DAC5578_WriteChannelValue(DAC5578_HandleTypeDef *hdac, uint8_t channel, uint16_t value);
bool DAC5578_UpdateChannel(DAC5578_HandleTypeDef *hdac, uint8_t channel);
bool DAC5578_WriteAndUpdateChannelValue(DAC5578_HandleTypeDef *hdac, uint8_t channel, uint16_t value);
bool DAC5578_WriteAllChannels(DAC5578_HandleTypeDef *hdac, uint16_t value);
bool DAC5578_ReadInputChannelValue(DAC5578_HandleTypeDef *hdac, uint8_t channel, uint16_t *value);
bool DAC5578_ReadDACChannelValue(DAC5578_HandleTypeDef *hdac, uint8_t channel, uint16_t *value);
bool DAC5578_SetPowerDownMode(DAC5578_HandleTypeDef *hdac, uint8_t channel, DAC5578_PowerDownMode_t mode);
bool DAC5578_SetPowerDownAll(DAC5578_HandleTypeDef *hdac, DAC5578_PowerDownMode_t mode);
bool DAC5578_SetInternalReference(DAC5578_HandleTypeDef *hdac, bool enable);
bool DAC5578_SetupLDAC(DAC5578_HandleTypeDef *hdac, uint8_t ldac_mask);
bool DAC5578_SoftwareLDAC(DAC5578_HandleTypeDef *hdac);
/* CLR Pin Functions */
bool DAC5578_SetClearCode(DAC5578_HandleTypeDef *hdac, DAC5578_ClearCode_t clear_code);
DAC5578_ClearCode_t DAC5578_GetClearCode(DAC5578_HandleTypeDef *hdac);
void DAC5578_ActivateClearPin(DAC5578_HandleTypeDef *hdac);
void DAC5578_DeactivateClearPin(DAC5578_HandleTypeDef *hdac);
void DAC5578_ClearOutputs(DAC5578_HandleTypeDef *hdac); // Pulse CLR pin to clear outputs
/* Private functions */
bool DAC5578_CommandWrite(DAC5578_HandleTypeDef *hdac, uint8_t command, uint16_t value);
bool DAC5578_CommandRead(DAC5578_HandleTypeDef *hdac, uint8_t command, uint16_t *value);
#ifdef __cplusplus
}
#endif
#endif /* __DAC5578_H */
@@ -0,0 +1,121 @@
#include "GY_85_HAL.h"
static int16_t g_offx = 0, g_offy = 0, g_offz = 0;
// ---------------- Internal Functions ---------------- //
static void GY85_SetAccelerometer(void);
static void GY85_ReadAccelerometer(GY85_t *imu);
static void GY85_SetCompass(void);
static void GY85_ReadCompass(GY85_t *imu);
static void GY85_SetGyro(void);
static void GY85_GyroCalibrate(void);
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_offy = tmpy / 10;
g_offz = tmpz / 10;
}
static void GY85_ReadGyro(GY85_t *imu)
{
uint8_t reg = 0x1B;
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);
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;
}
@@ -0,0 +1,25 @@
#ifndef __GY_85_HAL_H__
#define __GY_85_HAL_H__
#include "stm32f7xx_hal.h" // change depending on MCU family
#include <stdint.h>
#define ADXL345_ADDR (0x53 << 1)
#define HMC5883_ADDR (0x1E << 1)
#define ITG3200_ADDR (0x68 << 1)
extern I2C_HandleTypeDef hi2c3;
// Struct to hold all sensor data
typedef struct {
int16_t ax, ay, az; // accelerometer
float gx, gy, gz; // gyroscope
int16_t mx, my, mz; // magnetometer
} GY85_t;
// Public API
void GY85_Init(void);
void GY85_Update(GY85_t *imu); // reads all sensors and stores in struct
#endif
@@ -0,0 +1,113 @@
#include "RadarSettings.h"
#include <cstring>
RadarSettings::RadarSettings() {
resetToDefaults();
}
void RadarSettings::resetToDefaults() {
system_frequency = 10.0e9; // 10 GHz
chirp_duration_1 = 30.0e-6; // 30 µs
chirp_duration_2 = 0.5e-6; // 0.5 µs
chirps_per_position = 32;
freq_min = 10.0e6; // 10 MHz
freq_max = 30.0e6; // 30 MHz
prf1 = 1000.0; // 1 kHz
prf2 = 2000.0; // 2 kHz
max_distance = 50000.0; // 50 km
map_size = 50000.0; // 50 km
settings_valid = true;
}
bool RadarSettings::parseFromUSB(const uint8_t* data, uint32_t length) {
// Minimum packet size: "SET" + 8 doubles + 1 uint32_t + "END" = 3 + 8*8 + 4 + 3 = 74 bytes
if (data == nullptr || length < 74) {
settings_valid = false;
return false;
}
// Check for start marker "SET"
if (memcmp(data, "SET", 3) != 0) {
settings_valid = false;
return false;
}
// Check for end marker "END"
if (memcmp(data + length - 3, "END", 3) != 0) {
settings_valid = false;
return false;
}
uint32_t offset = 3; // Skip "SET"
// Extract all parameters in order
system_frequency = extractDouble(data + offset);
offset += 8;
chirp_duration_1 = extractDouble(data + offset);
offset += 8;
chirp_duration_2 = extractDouble(data + offset);
offset += 8;
chirps_per_position = extractUint32(data + offset);
offset += 4;
freq_min = extractDouble(data + offset);
offset += 8;
freq_max = extractDouble(data + offset);
offset += 8;
prf1 = extractDouble(data + offset);
offset += 8;
prf2 = extractDouble(data + offset);
offset += 8;
max_distance = extractDouble(data + offset);
offset += 8;
map_size = extractDouble(data + offset);
// Validate the received settings
settings_valid = validateSettings();
return settings_valid;
}
bool RadarSettings::validateSettings() {
// Check for reasonable value ranges
if (system_frequency < 1e9 || system_frequency > 100e9) return false;
if (chirp_duration_1 < 1e-6 || chirp_duration_1 > 1000e-6) return false;
if (chirp_duration_2 < 0.1e-6 || chirp_duration_2 > 10e-6) return false;
if (chirps_per_position < 1 || chirps_per_position > 256) return false;
if (freq_min < 1e6 || freq_min > 100e6) return false;
if (freq_max <= freq_min || freq_max > 100e6) return false;
if (prf1 < 100 || prf1 > 10000) return false;
if (prf2 < 100 || prf2 > 10000) return false;
if (max_distance < 100 || max_distance > 100000) return false;
if (map_size < 1000 || map_size > 200000) return false;
return true;
}
double RadarSettings::extractDouble(const uint8_t* data) {
uint64_t bits = 0;
for (int i = 0; i < 8; i++) {
bits = (bits << 8) | data[i];
}
double value;
memcpy(&value, &bits, sizeof(double));
return value;
}
uint32_t RadarSettings::extractUint32(const uint8_t* data) {
uint32_t value = 0;
for (int i = 0; i < 4; i++) {
value = (value << 8) | data[i];
}
return value;
}
@@ -0,0 +1,53 @@
#ifndef RADARSETTINGS_H
#define RADARSETTINGS_H
#include <cstdint>
class RadarSettings {
public:
// Default constructor with initial values
RadarSettings();
// Parse settings from USB CDC data
bool parseFromUSB(const uint8_t* data, uint32_t length);
// Getters for all settings
double getSystemFrequency() const { return system_frequency; }
double getChirpDuration1() const { return chirp_duration_1; }
double getChirpDuration2() const { return chirp_duration_2; }
uint32_t getChirpsPerPosition() const { return chirps_per_position; }
double getFreqMin() const { return freq_min; }
double getFreqMax() const { return freq_max; }
double getPRF1() const { return prf1; }
double getPRF2() const { return prf2; }
double getMaxDistance() const { return max_distance; }
double getMapSize() const { return map_size; }
// Check if settings are valid
bool isValid() const { return settings_valid; }
// Reset to default values
void resetToDefaults();
private:
// Radar system parameters
double system_frequency; // Hz
double chirp_duration_1; // seconds (long chirp)
double chirp_duration_2; // seconds (short chirp)
uint32_t chirps_per_position;
double freq_min; // Hz
double freq_max; // Hz
double prf1; // Hz
double prf2; // Hz
double max_distance; // meters
double map_size; // meters
bool settings_valid;
// Helper methods
bool validateSettings();
double extractDouble(const uint8_t* data);
uint32_t extractUint32(const uint8_t* data);
};
#endif // RADARSETTINGS_H
@@ -0,0 +1,509 @@
/*
TinyGPS++ - a small GPS library for Arduino providing universal NMEA parsing
Based on work by and "distanceBetween" and "courseTo" courtesy of Maarten Lamers.
Suggestion to add satellites, courseTo(), and cardinal() by Matt Monson.
Location precision improvements suggested by Wayne Holder.
Copyright (C) 2008-2024 Mikal Hart
All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "TinyGPS++.h"
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
#define _RMCterm "RMC"
#define _GGAterm "GGA"
TinyGPSPlus::TinyGPSPlus()
: parity(0)
, isChecksumTerm(false)
, curSentenceType(GPS_SENTENCE_OTHER)
, curTermNumber(0)
, curTermOffset(0)
, sentenceHasFix(false)
, customElts(0)
, customCandidates(0)
, encodedCharCount(0)
, sentencesWithFixCount(0)
, failedChecksumCount(0)
, passedChecksumCount(0)
{
term[0] = '\0';
}
//
// public methods
//
bool TinyGPSPlus::encode(char c)
{
++encodedCharCount;
switch(c)
{
case ',': // term terminators
parity ^= (uint8_t)c;
case '\r':
case '\n':
case '*':
{
bool isValidSentence = false;
if (curTermOffset < sizeof(term))
{
term[curTermOffset] = 0;
isValidSentence = endOfTermHandler();
}
++curTermNumber;
curTermOffset = 0;
isChecksumTerm = c == '*';
return isValidSentence;
}
break;
case '$': // sentence begin
curTermNumber = curTermOffset = 0;
parity = 0;
curSentenceType = GPS_SENTENCE_OTHER;
isChecksumTerm = false;
sentenceHasFix = false;
return false;
default: // ordinary characters
if (curTermOffset < sizeof(term) - 1)
term[curTermOffset++] = c;
if (!isChecksumTerm)
parity ^= c;
return false;
}
return false;
}
//
// internal utilities
//
int TinyGPSPlus::fromHex(char a)
{
if (a >= 'A' && a <= 'F')
return a - 'A' + 10;
else if (a >= 'a' && a <= 'f')
return a - 'a' + 10;
else
return a - '0';
}
// static
// Parse a (potentially negative) number with up to 2 decimal digits -xxxx.yy
int32_t TinyGPSPlus::parseDecimal(const char *term)
{
bool negative = *term == '-';
if (negative) ++term;
int32_t ret = 100 * (int32_t)atol(term);
while (isdigit(*term)) ++term;
if (*term == '.' && isdigit(term[1]))
{
ret += 10 * (term[1] - '0');
if (isdigit(term[2]))
ret += term[2] - '0';
}
return negative ? -ret : ret;
}
// static
// Parse degrees in that funny NMEA format DDMM.MMMM
void TinyGPSPlus::parseDegrees(const char *term, RawDegrees &deg)
{
uint32_t leftOfDecimal = (uint32_t)atol(term);
uint16_t minutes = (uint16_t)(leftOfDecimal % 100);
uint32_t multiplier = 10000000UL;
uint32_t tenMillionthsOfMinutes = minutes * multiplier;
deg.deg = (int16_t)(leftOfDecimal / 100);
while (isdigit(*term))
++term;
if (*term == '.')
while (isdigit(*++term))
{
multiplier /= 10;
tenMillionthsOfMinutes += (*term - '0') * multiplier;
}
deg.billionths = (5 * tenMillionthsOfMinutes + 1) / 3;
deg.negative = false;
}
#define COMBINE(sentence_type, term_number) (((unsigned)(sentence_type) << 5) | term_number)
// Processes a just-completed term
// Returns true if new sentence has just passed checksum test and is validated
bool TinyGPSPlus::endOfTermHandler()
{
// If it's the checksum term, and the checksum checks out, commit
if (isChecksumTerm)
{
uint8_t checksum = 16 * fromHex(term[0]) + fromHex(term[1]);
if (checksum == parity)
{
passedChecksumCount++;
if (sentenceHasFix)
++sentencesWithFixCount;
switch(curSentenceType)
{
case GPS_SENTENCE_RMC:
date.commit();
time.commit();
if (sentenceHasFix)
{
location.commit();
speed.commit();
course.commit();
}
break;
case GPS_SENTENCE_GGA:
time.commit();
if (sentenceHasFix)
{
location.commit();
altitude.commit();
}
satellites.commit();
hdop.commit();
break;
}
// Commit all custom listeners of this sentence type
for (TinyGPSCustom *p = customCandidates; p != NULL && strcmp(p->sentenceName, customCandidates->sentenceName) == 0; p = p->next)
p->commit();
return true;
}
else
{
++failedChecksumCount;
}
return false;
}
// the first term determines the sentence type
if (curTermNumber == 0)
{
if (term[0] == 'G' && strchr("PNABL", term[1]) != NULL && !strcmp(term + 2, _RMCterm))
curSentenceType = GPS_SENTENCE_RMC;
else if (term[0] == 'G' && strchr("PNABL", term[1]) != NULL && !strcmp(term + 2, _GGAterm))
curSentenceType = GPS_SENTENCE_GGA;
else
curSentenceType = GPS_SENTENCE_OTHER;
// Any custom candidates of this sentence type?
for (customCandidates = customElts; customCandidates != NULL && strcmp(customCandidates->sentenceName, term) < 0; customCandidates = customCandidates->next);
if (customCandidates != NULL && strcmp(customCandidates->sentenceName, term) > 0)
customCandidates = NULL;
return false;
}
if (curSentenceType != GPS_SENTENCE_OTHER && term[0])
switch(COMBINE(curSentenceType, curTermNumber))
{
case COMBINE(GPS_SENTENCE_RMC, 1): // Time in both sentences
case COMBINE(GPS_SENTENCE_GGA, 1):
time.setTime(term);
break;
case COMBINE(GPS_SENTENCE_RMC, 2): // RMC validity
sentenceHasFix = term[0] == 'A';
break;
case COMBINE(GPS_SENTENCE_RMC, 3): // Latitude
case COMBINE(GPS_SENTENCE_GGA, 2):
location.setLatitude(term);
break;
case COMBINE(GPS_SENTENCE_RMC, 4): // N/S
case COMBINE(GPS_SENTENCE_GGA, 3):
location.rawNewLatData.negative = term[0] == 'S';
break;
case COMBINE(GPS_SENTENCE_RMC, 5): // Longitude
case COMBINE(GPS_SENTENCE_GGA, 4):
location.setLongitude(term);
break;
case COMBINE(GPS_SENTENCE_RMC, 6): // E/W
case COMBINE(GPS_SENTENCE_GGA, 5):
location.rawNewLngData.negative = term[0] == 'W';
break;
case COMBINE(GPS_SENTENCE_RMC, 7): // Speed (RMC)
speed.set(term);
break;
case COMBINE(GPS_SENTENCE_RMC, 8): // Course (RMC)
course.set(term);
break;
case COMBINE(GPS_SENTENCE_RMC, 9): // Date (RMC)
date.setDate(term);
break;
case COMBINE(GPS_SENTENCE_GGA, 6): // Fix data (GGA)
sentenceHasFix = term[0] > '0';
location.newFixQuality = (TinyGPSLocation::Quality)term[0];
break;
case COMBINE(GPS_SENTENCE_GGA, 7): // Satellites used (GGA)
satellites.set(term);
break;
case COMBINE(GPS_SENTENCE_GGA, 8): // HDOP
hdop.set(term);
break;
case COMBINE(GPS_SENTENCE_GGA, 9): // Altitude (GGA)
altitude.set(term);
break;
case COMBINE(GPS_SENTENCE_RMC, 12):
location.newFixMode = (TinyGPSLocation::Mode)term[0];
break;
}
// Set custom values as needed
for (TinyGPSCustom *p = customCandidates; p != NULL && strcmp(p->sentenceName, customCandidates->sentenceName) == 0 && p->termNumber <= curTermNumber; p = p->next)
if (p->termNumber == curTermNumber)
p->set(term);
return false;
}
/* static */
double TinyGPSPlus::distanceBetween(double lat1, double long1, double lat2, double long2)
{
// returns distance in meters between two positions, both specified
// as signed decimal-degrees latitude and longitude. Uses great-circle
// distance computation for hypothetical sphere of radius 6371009 meters.
// Because Earth is no exact sphere, rounding errors may be up to 0.5%.
// Courtesy of Maarten Lamers
double delta = (long1-long2)* (PI / 180);
double sdlong = sin(delta);
double cdlong = cos(delta);
lat1 = (lat1)* (PI / 180);
lat2 = (lat2)* (PI / 180);
double slat1 = sin(lat1);
double clat1 = cos(lat1);
double slat2 = sin(lat2);
double clat2 = cos(lat2);
delta = (clat1 * slat2) - (slat1 * clat2 * cdlong);
delta = delta*delta;
delta += (clat2 * sdlong)*(clat2 * sdlong);
delta = sqrt(delta);
double denom = (slat1 * slat2) + (clat1 * clat2 * cdlong);
delta = atan2(delta, denom);
return delta * _GPS_EARTH_MEAN_RADIUS;
}
double TinyGPSPlus::courseTo(double lat1, double long1, double lat2, double long2)
{
// returns course in degrees (North=0, West=270) from position 1 to position 2,
// both specified as signed decimal-degrees latitude and longitude.
// Because Earth is no exact sphere, calculated course may be off by a tiny fraction.
// Courtesy of Maarten Lamers
double dlon = (PI/180)*(long2-long1);
lat1 = (PI/180)*(lat1);
lat2 = (PI/180)*(lat2);
double a1 = sin(dlon) * cos(lat2);
double a2 = sin(lat1) * cos(lat2) * cos(dlon);
a2 = cos(lat1) * sin(lat2) - a2;
a2 = atan2(a1, a2);
if (a2 < 0.0)
{
a2 += TWO_PI;
}
return 180/PI*(a2);
}
const char *TinyGPSPlus::cardinal(double course)
{
static const char* directions[] = {"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"};
int direction = (int)((course + 11.25f) / 22.5f);
return directions[direction % 16];
}
void TinyGPSLocation::commit()
{
rawLatData = rawNewLatData;
rawLngData = rawNewLngData;
fixQuality = newFixQuality;
fixMode = newFixMode;
lastCommitTime = HAL_GetTick();
valid = updated = true;
}
void TinyGPSLocation::setLatitude(const char *term)
{
TinyGPSPlus::parseDegrees(term, rawNewLatData);
}
void TinyGPSLocation::setLongitude(const char *term)
{
TinyGPSPlus::parseDegrees(term, rawNewLngData);
}
double TinyGPSLocation::lat()
{
updated = false;
double ret = rawLatData.deg + rawLatData.billionths / 1000000000.0;
return rawLatData.negative ? -ret : ret;
}
double TinyGPSLocation::lng()
{
updated = false;
double ret = rawLngData.deg + rawLngData.billionths / 1000000000.0;
return rawLngData.negative ? -ret : ret;
}
void TinyGPSDate::commit()
{
date = newDate;
lastCommitTime = HAL_GetTick();
valid = updated = true;
}
void TinyGPSTime::commit()
{
time = newTime;
lastCommitTime = HAL_GetTick();
valid = updated = true;
}
void TinyGPSTime::setTime(const char *term)
{
newTime = (uint32_t)TinyGPSPlus::parseDecimal(term);
}
void TinyGPSDate::setDate(const char *term)
{
newDate = atol(term);
}
uint16_t TinyGPSDate::year()
{
updated = false;
uint16_t year = date % 100;
return year + 2000;
}
uint8_t TinyGPSDate::month()
{
updated = false;
return (date / 100) % 100;
}
uint8_t TinyGPSDate::day()
{
updated = false;
return date / 10000;
}
uint8_t TinyGPSTime::hour()
{
updated = false;
return time / 1000000;
}
uint8_t TinyGPSTime::minute()
{
updated = false;
return (time / 10000) % 100;
}
uint8_t TinyGPSTime::second()
{
updated = false;
return (time / 100) % 100;
}
uint8_t TinyGPSTime::centisecond()
{
updated = false;
return time % 100;
}
void TinyGPSDecimal::commit()
{
val = newval;
lastCommitTime = HAL_GetTick();
valid = updated = true;
}
void TinyGPSDecimal::set(const char *term)
{
newval = TinyGPSPlus::parseDecimal(term);
}
void TinyGPSInteger::commit()
{
val = newval;
lastCommitTime = HAL_GetTick();
valid = updated = true;
}
void TinyGPSInteger::set(const char *term)
{
newval = atol(term);
}
TinyGPSCustom::TinyGPSCustom(TinyGPSPlus &gps, const char *_sentenceName, int _termNumber)
{
begin(gps, _sentenceName, _termNumber);
}
void TinyGPSCustom::begin(TinyGPSPlus &gps, const char *_sentenceName, int _termNumber)
{
lastCommitTime = 0;
updated = valid = false;
sentenceName = _sentenceName;
termNumber = _termNumber;
memset(stagingBuffer, '\0', sizeof(stagingBuffer));
memset(buffer, '\0', sizeof(buffer));
// Insert this item into the GPS tree
gps.insertCustom(this, _sentenceName, _termNumber);
}
void TinyGPSCustom::commit()
{
strcpy(this->buffer, this->stagingBuffer);
lastCommitTime = HAL_GetTick();
valid = updated = true;
}
void TinyGPSCustom::set(const char *term)
{
strncpy(this->stagingBuffer, term, sizeof(this->stagingBuffer) - 1);
}
void TinyGPSPlus::insertCustom(TinyGPSCustom *pElt, const char *sentenceName, int termNumber)
{
TinyGPSCustom **ppelt;
for (ppelt = &this->customElts; *ppelt != NULL; ppelt = &(*ppelt)->next)
{
int cmp = strcmp(sentenceName, (*ppelt)->sentenceName);
if (cmp < 0 || (cmp == 0 && termNumber < (*ppelt)->termNumber))
break;
}
pElt->next = *ppelt;
*ppelt = pElt;
}
@@ -0,0 +1,289 @@
/*
TinyGPS++ - a small GPS library for Arduino providing universal NMEA parsing
Based on work by and "distanceBetween" and "courseTo" courtesy of Maarten Lamers.
Suggestion to add satellites, courseTo(), and cardinal() by Matt Monson.
Location precision improvements suggested by Wayne Holder.
Copyright (C) 2008-2024 Mikal Hart
All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __TinyGPSPlus_h
#define __TinyGPSPlus_h
#include <inttypes.h>
#include <limits.h>
#include "stm32f7xx_hal.h"
#define _GPS_VERSION "1.1.0" // software version of this library
#define _GPS_MPH_PER_KNOT 1.15077945
#define _GPS_MPS_PER_KNOT 0.51444444
#define _GPS_KMPH_PER_KNOT 1.852
#define _GPS_MILES_PER_METER 0.00062137112
#define _GPS_KM_PER_METER 0.001
#define _GPS_FEET_PER_METER 3.2808399
#define _GPS_MAX_FIELD_SIZE 15
#define _GPS_EARTH_MEAN_RADIUS 6371009 // old: 6372795
#define PI 3.14159265359
#define TWO_PI 6.28318530718
struct RawDegrees
{
uint16_t deg;
uint32_t billionths;
bool negative;
public:
RawDegrees() : deg(0), billionths(0), negative(false)
{}
};
struct TinyGPSLocation
{
friend class TinyGPSPlus;
public:
enum Quality { Invalid = '0', GPS = '1', DGPS = '2', PPS = '3', RTK = '4', FloatRTK = '5', Estimated = '6', Manual = '7', Simulated = '8' };
enum Mode { N = 'N', A = 'A', D = 'D', E = 'E'};
bool isValid() const { return valid; }
bool isUpdated() const { return updated; }
uint32_t age() const { return valid ? HAL_GetTick() - lastCommitTime : (uint32_t)ULONG_MAX; }
const RawDegrees &rawLat() { updated = false; return rawLatData; }
const RawDegrees &rawLng() { updated = false; return rawLngData; }
double lat();
double lng();
Quality FixQuality() { updated = false; return fixQuality; }
Mode FixMode() { updated = false; return fixMode; }
TinyGPSLocation() : valid(false), updated(false), fixQuality(Invalid), fixMode(N)
{}
private:
bool valid, updated;
RawDegrees rawLatData, rawLngData, rawNewLatData, rawNewLngData;
Quality fixQuality, newFixQuality;
Mode fixMode, newFixMode;
uint32_t lastCommitTime;
void commit();
void setLatitude(const char *term);
void setLongitude(const char *term);
};
struct TinyGPSDate
{
friend class TinyGPSPlus;
public:
bool isValid() const { return valid; }
bool isUpdated() const { return updated; }
uint32_t age() const { return valid ? HAL_GetTick() - lastCommitTime : (uint32_t)ULONG_MAX; }
uint32_t value() { updated = false; return date; }
uint16_t year();
uint8_t month();
uint8_t day();
TinyGPSDate() : valid(false), updated(false), date(0)
{}
private:
bool valid, updated;
uint32_t date, newDate;
uint32_t lastCommitTime;
void commit();
void setDate(const char *term);
};
struct TinyGPSTime
{
friend class TinyGPSPlus;
public:
bool isValid() const { return valid; }
bool isUpdated() const { return updated; }
uint32_t age() const { return valid ? HAL_GetTick() - lastCommitTime : (uint32_t)ULONG_MAX; }
uint32_t value() { updated = false; return time; }
uint8_t hour();
uint8_t minute();
uint8_t second();
uint8_t centisecond();
TinyGPSTime() : valid(false), updated(false), time(0)
{}
private:
bool valid, updated;
uint32_t time, newTime;
uint32_t lastCommitTime;
void commit();
void setTime(const char *term);
};
struct TinyGPSDecimal
{
friend class TinyGPSPlus;
public:
bool isValid() const { return valid; }
bool isUpdated() const { return updated; }
uint32_t age() const { return valid ? HAL_GetTick() - lastCommitTime : (uint32_t)ULONG_MAX; }
int32_t value() { updated = false; return val; }
TinyGPSDecimal() : valid(false), updated(false), val(0)
{}
private:
bool valid, updated;
uint32_t lastCommitTime;
int32_t val, newval;
void commit();
void set(const char *term);
};
struct TinyGPSInteger
{
friend class TinyGPSPlus;
public:
bool isValid() const { return valid; }
bool isUpdated() const { return updated; }
uint32_t age() const { return valid ? HAL_GetTick() - lastCommitTime : (uint32_t)ULONG_MAX; }
uint32_t value() { updated = false; return val; }
TinyGPSInteger() : valid(false), updated(false), val(0)
{}
private:
bool valid, updated;
uint32_t lastCommitTime;
uint32_t val, newval;
void commit();
void set(const char *term);
};
struct TinyGPSSpeed : TinyGPSDecimal
{
double knots() { return value() / 100.0; }
double mph() { return _GPS_MPH_PER_KNOT * value() / 100.0; }
double mps() { return _GPS_MPS_PER_KNOT * value() / 100.0; }
double kmph() { return _GPS_KMPH_PER_KNOT * value() / 100.0; }
};
struct TinyGPSCourse : public TinyGPSDecimal
{
double deg() { return value() / 100.0; }
};
struct TinyGPSAltitude : TinyGPSDecimal
{
double meters() { return value() / 100.0; }
double miles() { return _GPS_MILES_PER_METER * value() / 100.0; }
double kilometers() { return _GPS_KM_PER_METER * value() / 100.0; }
double feet() { return _GPS_FEET_PER_METER * value() / 100.0; }
};
struct TinyGPSHDOP : TinyGPSDecimal
{
double hdop() { return value() / 100.0; }
};
class TinyGPSPlus;
class TinyGPSCustom
{
public:
TinyGPSCustom() {};
TinyGPSCustom(TinyGPSPlus &gps, const char *sentenceName, int termNumber);
void begin(TinyGPSPlus &gps, const char *_sentenceName, int _termNumber);
bool isUpdated() const { return updated; }
bool isValid() const { return valid; }
uint32_t age() const { return valid ? HAL_GetTick() - lastCommitTime : (uint32_t)ULONG_MAX; }
const char *value() { updated = false; return buffer; }
private:
void commit();
void set(const char *term);
char stagingBuffer[_GPS_MAX_FIELD_SIZE + 1];
char buffer[_GPS_MAX_FIELD_SIZE + 1];
unsigned long lastCommitTime;
bool valid, updated;
const char *sentenceName;
int termNumber;
friend class TinyGPSPlus;
TinyGPSCustom *next;
};
class TinyGPSPlus
{
public:
TinyGPSPlus();
bool encode(char c); // process one character received from GPS
TinyGPSPlus &operator << (char c) {encode(c); return *this;}
TinyGPSLocation location;
TinyGPSDate date;
TinyGPSTime time;
TinyGPSSpeed speed;
TinyGPSCourse course;
TinyGPSAltitude altitude;
TinyGPSInteger satellites;
TinyGPSHDOP hdop;
static const char *libraryVersion() { return _GPS_VERSION; }
static double distanceBetween(double lat1, double long1, double lat2, double long2);
static double courseTo(double lat1, double long1, double lat2, double long2);
static const char *cardinal(double course);
static int32_t parseDecimal(const char *term);
static void parseDegrees(const char *term, RawDegrees &deg);
uint32_t charsProcessed() const { return encodedCharCount; }
uint32_t sentencesWithFix() const { return sentencesWithFixCount; }
uint32_t failedChecksum() const { return failedChecksumCount; }
uint32_t passedChecksum() const { return passedChecksumCount; }
private:
enum {GPS_SENTENCE_GGA, GPS_SENTENCE_RMC, GPS_SENTENCE_OTHER};
// parsing state variables
uint8_t parity;
bool isChecksumTerm;
char term[_GPS_MAX_FIELD_SIZE];
uint8_t curSentenceType;
uint8_t curTermNumber;
uint8_t curTermOffset;
bool sentenceHasFix;
// custom element support
friend class TinyGPSCustom;
TinyGPSCustom *customElts;
TinyGPSCustom *customCandidates;
void insertCustom(TinyGPSCustom *pElt, const char *sentenceName, int index);
// statistics
uint32_t encodedCharCount;
uint32_t sentencesWithFixCount;
uint32_t failedChecksumCount;
uint32_t passedChecksumCount;
// internal utilities
int fromHex(char a);
bool endOfTermHandler();
};
#endif // def(__TinyGPSPlus_h)
@@ -0,0 +1,26 @@
/*
TinyGPSPlus - a small GPS library for Arduino providing universal NMEA parsing
Based on work by and "distanceBetween" and "courseTo" courtesy of Maarten Lamers.
Suggestion to add satellites, courseTo(), and cardinal() by Matt Monson.
Location precision improvements suggested by Wayne Holder.
Copyright (C) 2008-2024 Mikal Hart
All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __TinyGPSPlus_h
#include "TinyGPS++.h"
#endif
@@ -0,0 +1,93 @@
#include "USBHandler.h"
#include <cstring>
USBHandler::USBHandler() {
reset();
}
void USBHandler::reset() {
current_state = USBState::WAITING_FOR_START;
start_flag_received = false;
buffer_index = 0;
current_settings.resetToDefaults();
}
void USBHandler::processUSBData(const uint8_t* data, uint32_t length) {
if (data == nullptr || length == 0) {
return;
}
switch (current_state) {
case USBState::WAITING_FOR_START:
processStartFlag(data, length);
break;
case USBState::RECEIVING_SETTINGS:
processSettingsData(data, length);
break;
case USBState::READY_FOR_DATA:
// Ready to receive radar data commands
// Add additional command processing here if needed
break;
}
}
void USBHandler::processStartFlag(const uint8_t* data, uint32_t length) {
// Start flag: bytes [23, 46, 158, 237]
const uint8_t START_FLAG[] = {23, 46, 158, 237};
// Check if start flag is in the received data
for (uint32_t i = 0; i <= length - 4; i++) {
if (memcmp(data + i, START_FLAG, 4) == 0) {
start_flag_received = true;
current_state = USBState::RECEIVING_SETTINGS;
buffer_index = 0; // Reset buffer for settings data
// You can send an acknowledgment back here if needed
// sendUSBAcknowledgment();
// If there's more data after the start flag, process it
if (length > i + 4) {
processSettingsData(data + i + 4, length - i - 4);
}
return;
}
}
}
void USBHandler::processSettingsData(const uint8_t* data, uint32_t length) {
// Add data to buffer
uint32_t bytes_to_copy = (length < (MAX_BUFFER_SIZE - buffer_index)) ?
length : (MAX_BUFFER_SIZE - buffer_index);
memcpy(usb_buffer + buffer_index, data, bytes_to_copy);
buffer_index += bytes_to_copy;
// Check if we have a complete settings packet (contains "SET" and "END")
if (buffer_index >= 74) { // Minimum size for valid settings packet
// Look for "SET" at beginning and "END" somewhere in the packet
bool has_set = (memcmp(usb_buffer, "SET", 3) == 0);
bool has_end = false;
for (uint32_t i = 3; i <= buffer_index - 3; i++) {
if (memcmp(usb_buffer + i, "END", 3) == 0) {
has_end = true;
// Parse the complete packet up to "END"
if (has_set && current_settings.parseFromUSB(usb_buffer, i + 3)) {
current_state = USBState::READY_FOR_DATA;
// You can send settings acknowledgment back here
// sendSettingsAcknowledgment();
}
break;
}
}
// If we didn't find a valid packet but buffer is full, reset
if (buffer_index >= MAX_BUFFER_SIZE && !has_end) {
buffer_index = 0; // Reset buffer to avoid overflow
}
}
}
@@ -0,0 +1,46 @@
#ifndef USBHANDLER_H
#define USBHANDLER_H
#include "RadarSettings.h"
#include <cstdint>
class USBHandler {
public:
enum class USBState {
WAITING_FOR_START,
RECEIVING_SETTINGS,
READY_FOR_DATA
};
USBHandler();
// Process incoming USB data
void processUSBData(const uint8_t* data, uint32_t length);
// Check if start flag was received
bool isStartFlagReceived() const { return start_flag_received; }
// Get current settings
const RadarSettings& getSettings() const { return current_settings; }
// Get current state
USBState getState() const { return current_state; }
// Reset USB handler
void reset();
private:
RadarSettings current_settings;
USBState current_state;
bool start_flag_received;
// Buffer for accumulating USB data
static constexpr uint32_t MAX_BUFFER_SIZE = 256;
uint8_t usb_buffer[MAX_BUFFER_SIZE];
uint32_t buffer_index;
void processStartFlag(const uint8_t* data, uint32_t length);
void processSettingsData(const uint8_t* data, uint32_t length);
};
#endif // USBHANDLER_H
@@ -0,0 +1,731 @@
/***************************************************************************//**
* @file AD9523.c
* @brief Implementation of AD9523 Driver.
* @author ACozma(andrei.cozma@analog.com)
********************************************************************************
* Copyright 2012-2016(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include "ad9523.h"
#include "no_os_alloc.h"
/* Helpers to avoid excess line breaks */
#define AD_IFE(_pde, _a, _b) ((dev->pdata->_pde) ? _a : _b)
#define AD_IF(_pde, _a) AD_IFE(_pde, _a, 0)
/***************************************************************************//**
* @brief Reads the value of the selected register.
*
* @param dev - The device structure.
* @param reg_addr - The address of the register to read.
* @param reg_data - Pointer to the read value.
* @return Returns 0 in case of success or negative error code.
*******************************************************************************/
int32_t ad9523_spi_read(struct ad9523_dev *dev,
uint32_t reg_addr,
uint32_t *reg_data)
{
uint8_t buf[3];
int32_t ret = 0;
uint8_t index;
*reg_data = 0;
for (index = 0; index < AD9523_TRANSF_LEN(reg_addr); index++) {
buf[0] = 0x80 | (reg_addr >> 8);
buf[1] = reg_addr & 0xFF;
buf[2] = 0x00;
ret |= no_os_spi_write_and_read(dev->spi_desc,
buf,
3);
reg_addr--;
*reg_data <<= 8;
*reg_data |= buf[2];
}
return ret;
}
/***************************************************************************//**
* @brief Writes a value to the selected register.
*
* @param dev - The device structure.
* @param reg_addr - The address of the register to write to.
* @param reg_data - The value to write to the register.
*
* @return Returns 0 in case of success or negative error code.
*******************************************************************************/
int32_t ad9523_spi_write(struct ad9523_dev *dev,
uint32_t reg_addr,
uint32_t reg_data)
{
uint8_t buf[3];
int32_t ret = 0;
uint8_t index;
for (index = 0; index < AD9523_TRANSF_LEN(reg_addr); index++) {
buf[0] = reg_addr >> 8;
buf[1] = reg_addr & 0xFF;
buf[2] = (reg_data >> ((AD9523_TRANSF_LEN(reg_addr) - index - 1) * 8)) & 0xFF;
ret |= no_os_spi_write_and_read(dev->spi_desc,
buf,
3);
reg_addr--;
}
return ret;
}
/***************************************************************************//**
* @brief Updates the AD9523 configuration
*
* @param dev - The device structure.
*
* @return Returns 0 in case of success or negative error code.
*******************************************************************************/
int32_t ad9523_io_update(struct ad9523_dev *dev)
{
return ad9523_spi_write(dev,
AD9523_IO_UPDATE,
AD9523_IO_UPDATE_EN);
}
/***************************************************************************//**
* @brief Sets the clock provider for selected channel.
*
* @param dev - The device structure.
* @param ch - Selected channel.
* @param out - Selected clock provider.
*
* @return Returns 0 in case of success or negative error code.
*******************************************************************************/
int32_t ad9523_vco_out_map(struct ad9523_dev *dev,
uint32_t ch,
uint32_t out)
{
int32_t ret;
uint32_t mask;
uint32_t reg_data;
switch (ch) {
case 0 ... 3:
ret = ad9523_spi_read(dev,
AD9523_PLL1_OUTPUT_CHANNEL_CTRL,
&reg_data);
if (ret < 0)
break;
mask = AD9523_PLL1_OUTP_CH_CTRL_VCXO_SRC_SEL_CH0 << ch;
if (out) {
reg_data |= mask;
out = AD9523_VCXO;
} else {
reg_data &= ~mask;
}
ret = ad9523_spi_write(dev,
AD9523_PLL1_OUTPUT_CHANNEL_CTRL,
reg_data);
break;
case 4 ... 6:
ret = ad9523_spi_read(dev,
AD9523_PLL1_OUTPUT_CTRL,
&reg_data);
if (ret < 0)
break;
mask = AD9523_PLL1_OUTP_CTRL_VCO_DIV_SEL_CH4_M2 << (ch - 4);
if (out)
reg_data |= mask;
else
reg_data &= ~mask;
ret = ad9523_spi_write(dev,
AD9523_PLL1_OUTPUT_CTRL,
reg_data);
break;
case 7 ... 9:
ret = ad9523_spi_read(dev,
AD9523_PLL1_OUTPUT_CHANNEL_CTRL,
&reg_data);
if (ret < 0)
break;
mask = AD9523_PLL1_OUTP_CH_CTRL_VCO_DIV_SEL_CH7_M2 << (ch - 7);
if (out)
reg_data |= mask;
else
reg_data &= ~mask;
ret = ad9523_spi_write(dev,
AD9523_PLL1_OUTPUT_CHANNEL_CTRL,
reg_data);
break;
default:
return 0;
}
dev->ad9523_st.vco_out_map[ch] = out;
return ret;
}
/***************************************************************************//**
* @brief Updates the AD9523 configuration.
*
* @return Returns 0 in case of success or negative error code.
*******************************************************************************/
// vco calibration on default setup may not work (as it is a buffered write)
// calibration requires all registers to be written (not in hold registers) first.
int32_t ad9523_calibrate(struct ad9523_dev *dev)
{
uint32_t reg_data;
uint32_t timeout;
ad9523_spi_write(dev,
AD9523_PLL2_VCO_CTRL,
AD9523_PLL2_VCO_CALIBRATE);
ad9523_io_update(dev);
timeout = 0;
while (timeout < 100) {
no_os_mdelay(1);
timeout = timeout + 1;
ad9523_spi_read(dev,
AD9523_READBACK_1,
&reg_data);
if ((reg_data & 0x1) == 0x0)
break;
}
ad9523_spi_read(dev,
AD9523_READBACK_1,
&reg_data);
if ((reg_data & 0x1) != 0x0) {
printf("AD9523: VCO calibration failed (%#06lx)!\n", reg_data);
return (-1);
}
return (0);
}
/***************************************************************************//**
* @brief Updates the AD9523 configuration.
*
* @param dev - The device structure.
*
* @return Returns 0 in case of success or negative error code.
*******************************************************************************/
// status
// calibration requires all registers to be written (not in hold registers) first.
int32_t ad9523_status(struct ad9523_dev *dev)
{
int32_t ret;
uint32_t reg_data;
uint32_t status;
uint32_t timeout;
status = 0;
// vcxo + pll2 must always be okay- (is it not?)
status = status | AD9523_READBACK_0_STAT_VCXO;
status = status | AD9523_READBACK_0_STAT_PLL2_LD;
if (dev->pdata->pll1_bypass_en == 0) {
status = status | AD9523_READBACK_0_STAT_PLL2_REF_CLK;
status = status | AD9523_READBACK_0_STAT_PLL2_FB_CLK;
status = status | AD9523_READBACK_0_STAT_REF_TEST;
status = status | AD9523_READBACK_0_STAT_REFB;
status = status | AD9523_READBACK_0_STAT_REFA;
status = status | AD9523_READBACK_0_STAT_PLL1_LD;
}
timeout = 0;
while (timeout < 100) {
no_os_mdelay(1);
timeout = timeout + 1;
ad9523_spi_read(dev,
AD9523_READBACK_0,
&reg_data);
if ((reg_data & status) == status)
break;
}
ret = 0;
if ((reg_data & AD9523_READBACK_0_STAT_VCXO) != AD9523_READBACK_0_STAT_VCXO) {
printf("AD9523: VCXO status errors (%#06lx)!\n", reg_data);
ret = -1;
}
if ((reg_data & AD9523_READBACK_0_STAT_PLL2_LD) !=
AD9523_READBACK_0_STAT_PLL2_LD) {
printf("AD9523: PLL2 NOT locked (%#06lx)!\n", reg_data);
ret = -1;
}
return (ret);
}
/***************************************************************************//**
* @brief Updates the AD9523 configuration.
*
* @param dev - The device structure.
*
* @return Returns 0 in case of success or negative error code.
*******************************************************************************/
int32_t ad9523_sync(struct ad9523_dev *dev)
{
int32_t ret, tmp;
uint32_t reg_data;
ret = ad9523_spi_read(dev,
AD9523_STATUS_SIGNALS,
&reg_data);
if (ret < 0)
return ret;
tmp = reg_data;
tmp |= AD9523_STATUS_SIGNALS_SYNC_MAN_CTRL;
ret = ad9523_spi_write(dev,
AD9523_STATUS_SIGNALS,
tmp);
if (ret < 0)
return ret;
ad9523_io_update(dev);
tmp &= ~AD9523_STATUS_SIGNALS_SYNC_MAN_CTRL;
ret = ad9523_spi_write(dev,
AD9523_STATUS_SIGNALS,
tmp);
if (ret < 0)
return ret;
return ad9523_io_update(dev);
}
/***************************************************************************//**
* @brief Initialize the AD9523 data structure with the default register values.
*
* @param init_param - The device initial parameters.
*
* @return Always return 0.
*******************************************************************************/
int32_t ad9523_init(struct ad9523_init_param *init_param)
{
int32_t i = 0;
init_param->pdata->vcxo_freq = 0;
init_param->pdata->spi3wire = 0;
/* Differential/ Single-Ended Input Configuration */
init_param->pdata->refa_diff_rcv_en = 0;
init_param->pdata->refb_diff_rcv_en = 0;
init_param->pdata->zd_in_diff_en = 0;
init_param->pdata->osc_in_diff_en = 0;
/*
* Valid if differential input disabled
* if not true defaults to pos input
*/
init_param->pdata->refa_cmos_neg_inp_en = 0;
init_param->pdata->refb_cmos_neg_inp_en = 0;
init_param->pdata->zd_in_cmos_neg_inp_en = 0;
init_param->pdata->osc_in_cmos_neg_inp_en = 0;
/* PLL1 Setting */
init_param->pdata->refa_r_div = 1;
init_param->pdata->refb_r_div = 1;
init_param->pdata->pll1_feedback_div = 1;
init_param->pdata->pll1_charge_pump_current_nA = 0;
init_param->pdata->zero_delay_mode_internal_en = 0;
init_param->pdata->osc_in_feedback_en = 0;
init_param->pdata->pll1_bypass_en = 1;
init_param->pdata->pll1_loop_filter_rzero = 1;
/* Reference */
init_param->pdata->ref_mode = 0;
/* PLL2 Setting */
init_param->pdata->pll2_charge_pump_current_nA = 0;
init_param->pdata->pll2_ndiv_a_cnt = 0;
init_param->pdata->pll2_ndiv_b_cnt = 4;
init_param->pdata->pll2_freq_doubler_en = 0;
init_param->pdata->pll2_r2_div = 0;
init_param->pdata->pll2_vco_diff_m1 = 0; /* 3..5 */
init_param->pdata->pll2_vco_diff_m2 = 0; /* 3..5 */
/* Loop Filter PLL2 */
init_param->pdata->rpole2 = 0;
init_param->pdata->rzero = 0;
init_param->pdata->cpole1 = 0;
init_param->pdata->rzero_bypass_en = 0;
/* Output Channel Configuration */
for (i = 0; i < init_param->pdata->num_channels; i++) {
(&init_param->pdata->channels[i])->channel_num = 0;
(&init_param->pdata->channels[i])->divider_output_invert_en = 0;
(&init_param->pdata->channels[i])->sync_ignore_en = 0;
(&init_param->pdata->channels[i])->low_power_mode_en = 0;
(&init_param->pdata->channels[i])->use_alt_clock_src = 0;
(&init_param->pdata->channels[i])->output_dis = 0;
(&init_param->pdata->channels[i])->driver_mode = LVPECL_8mA;
(&init_param->pdata->channels[i])->divider_phase = 0;
(&init_param->pdata->channels[i])->channel_divider = 0;
}
return 0;
}
/***************************************************************************//**
* @brief Setup the AD9523 device.
*
* @param device - The device structure.
* @param init_param - The structure holding the device initial parameters.
*
* @return Returns 0 in case of success or negative error code.
*******************************************************************************/
int32_t ad9523_setup(struct ad9523_dev **device,
const struct ad9523_init_param *init_param)
{
struct ad9523_channel_spec *chan;
uint32_t active_mask = 0;
int32_t ret, i;
uint32_t reg_data;
uint32_t version_id;
struct ad9523_dev *dev;
dev = (struct ad9523_dev *)no_os_malloc(sizeof(*dev));
if (!dev)
return -1;
/* SPI */
ret = no_os_spi_init(&dev->spi_desc, &init_param->spi_init);
if (ret < 0)
return ret;
dev->pdata = init_param->pdata;
ret = ad9523_spi_write(dev,
AD9523_SERIAL_PORT_CONFIG,
AD9523_SER_CONF_SOFT_RESET |
(dev->pdata->spi3wire ? 0 :
AD9523_SER_CONF_SDO_ACTIVE));
if (ret < 0)
return ret;
no_os_mdelay(1);
ret = ad9523_spi_write(dev,
AD9523_READBACK_CTRL,
AD9523_READBACK_CTRL_READ_BUFFERED);
if (ret < 0)
return ret;
ret = ad9523_io_update(dev);
if (ret < 0)
return ret;
ret = ad9523_spi_read(dev,
AD9523_EEPROM_CUSTOMER_VERSION_ID,
&version_id);
if (ret < 0)
return ret;
ret = ad9523_spi_write(dev,
AD9523_EEPROM_CUSTOMER_VERSION_ID,
0xAD95);
if (ret < 0)
return ret;
ret = ad9523_spi_read(dev,
AD9523_EEPROM_CUSTOMER_VERSION_ID,
&reg_data);
if (ret < 0)
return ret;
if (reg_data != 0xAD95) {
printf("AD9523: SPI write-verify failed (%#06lX)!\n\r",
reg_data);
return -1;
}
ret = ad9523_spi_write(dev,
AD9523_EEPROM_CUSTOMER_VERSION_ID,
version_id);
if (ret < 0)
return ret;
/*
* PLL1 Setup
*/
ret = ad9523_spi_write(dev,
AD9523_PLL1_REF_A_DIVIDER,
dev->pdata->refa_r_div);
if (ret < 0)
return ret;
ret = ad9523_spi_write(dev,
AD9523_PLL1_REF_B_DIVIDER,
dev->pdata->refb_r_div);
if (ret < 0)
return ret;
ret = ad9523_spi_write(dev,
AD9523_PLL1_FEEDBACK_DIVIDER,
dev->pdata->pll1_feedback_div);
if (ret < 0)
return ret;
ret = ad9523_spi_write(dev,
AD9523_PLL1_CHARGE_PUMP_CTRL,
AD_IFE(pll1_bypass_en, AD9523_PLL1_CHARGE_PUMP_TRISTATE,
AD9523_PLL1_CHARGE_PUMP_CURRENT_nA(dev->pdata->
pll1_charge_pump_current_nA) |
AD9523_PLL1_CHARGE_PUMP_MODE_NORMAL |
AD9523_PLL1_BACKLASH_PW_MIN));
if (ret < 0)
return ret;
ret = ad9523_spi_write(dev,
AD9523_PLL1_INPUT_RECEIVERS_CTRL,
AD_IFE(pll1_bypass_en, AD9523_PLL1_REFA_REFB_PWR_CTRL_EN |
AD_IF(osc_in_diff_en, AD9523_PLL1_OSC_IN_DIFF_EN) |
AD_IF(osc_in_cmos_neg_inp_en, AD9523_PLL1_OSC_IN_CMOS_NEG_INP_EN),
AD_IF(refa_diff_rcv_en, AD9523_PLL1_REFA_RCV_EN) |
AD_IF(refb_diff_rcv_en, AD9523_PLL1_REFB_RCV_EN) |
AD_IF(osc_in_diff_en, AD9523_PLL1_OSC_IN_DIFF_EN) |
AD_IF(osc_in_cmos_neg_inp_en,
AD9523_PLL1_OSC_IN_CMOS_NEG_INP_EN) |
AD_IF(refa_diff_rcv_en, AD9523_PLL1_REFA_DIFF_RCV_EN) |
AD_IF(refb_diff_rcv_en, AD9523_PLL1_REFB_DIFF_RCV_EN)));
if (ret < 0)
return ret;
ret = ad9523_spi_write(dev,
AD9523_PLL1_REF_CTRL,
AD_IFE(pll1_bypass_en, AD9523_PLL1_BYPASS_FEEDBACK_DIV_EN |
AD9523_PLL1_ZERO_DELAY_MODE_INT,
AD_IF(zd_in_diff_en, AD9523_PLL1_ZD_IN_DIFF_EN) |
AD_IF(zd_in_cmos_neg_inp_en,
AD9523_PLL1_ZD_IN_CMOS_NEG_INP_EN) |
AD_IF(zero_delay_mode_internal_en,
AD9523_PLL1_ZERO_DELAY_MODE_INT) |
AD_IF(osc_in_feedback_en, AD9523_PLL1_OSC_IN_PLL_FEEDBACK_EN) |
AD_IF(refa_cmos_neg_inp_en, AD9523_PLL1_REFA_CMOS_NEG_INP_EN) |
AD_IF(refb_cmos_neg_inp_en, AD9523_PLL1_REFB_CMOS_NEG_INP_EN)));
if (ret < 0)
return ret;
ret = ad9523_spi_write(dev,
AD9523_PLL1_MISC_CTRL,
AD9523_PLL1_REFB_INDEP_DIV_CTRL_EN |
AD9523_PLL1_REF_MODE(dev->pdata->ref_mode));
if (ret < 0)
return ret;
ret = ad9523_spi_write(dev,
AD9523_PLL1_LOOP_FILTER_CTRL,
AD9523_PLL1_LOOP_FILTER_RZERO(dev->pdata->
pll1_loop_filter_rzero));
if (ret < 0)
return ret;
/*
* PLL2 Setup
*/
ret = ad9523_spi_write(dev,
AD9523_PLL2_CHARGE_PUMP,
AD9523_PLL2_CHARGE_PUMP_CURRENT_nA(dev->pdata->
pll2_charge_pump_current_nA));
if (ret < 0)
return ret;
ret = ad9523_spi_write(dev,
AD9523_PLL2_FEEDBACK_DIVIDER_AB,
AD9523_PLL2_FB_NDIV_A_CNT(dev->pdata->pll2_ndiv_a_cnt) |
AD9523_PLL2_FB_NDIV_B_CNT(dev->pdata->pll2_ndiv_b_cnt));
if (ret < 0)
return ret;
ret = ad9523_spi_write(dev,
AD9523_PLL2_CTRL,
AD9523_PLL2_CHARGE_PUMP_MODE_NORMAL |
AD9523_PLL2_BACKLASH_CTRL_EN |
AD_IF(pll2_freq_doubler_en,
AD9523_PLL2_FREQ_DOUBLER_EN));
if (ret < 0)
return ret;
dev->ad9523_st.vco_freq = (dev->pdata->vcxo_freq *
(dev->pdata->pll2_freq_doubler_en ? 2 : 1)
/ dev->pdata->pll2_r2_div) * AD9523_PLL2_FB_NDIV(dev->pdata->
pll2_ndiv_a_cnt,
dev->pdata->
pll2_ndiv_b_cnt);
ret = ad9523_spi_write(dev,
AD9523_PLL2_VCO_CTRL,
AD9523_PLL2_VCO_CALIBRATE);
if (ret < 0)
return ret;
ret = ad9523_spi_write(dev,
AD9523_PLL2_VCO_DIVIDER,
AD9523_PLL2_VCO_DIV_M1(dev->pdata->
pll2_vco_diff_m1) |
AD9523_PLL2_VCO_DIV_M2(dev->pdata->
pll2_vco_diff_m2) |
AD_IFE(pll2_vco_diff_m1,
0,
AD9523_PLL2_VCO_DIV_M1_PWR_DOWN_EN) |
AD_IFE(pll2_vco_diff_m2,
0,
AD9523_PLL2_VCO_DIV_M2_PWR_DOWN_EN));
if (ret < 0)
return ret;
if (dev->pdata->pll2_vco_diff_m1)
dev->ad9523_st.vco_out_freq[AD9523_VCO1] =
dev->ad9523_st.vco_freq / dev->pdata->pll2_vco_diff_m1;
if (dev->pdata->pll2_vco_diff_m2)
dev->ad9523_st.vco_out_freq[AD9523_VCO2] =
dev->ad9523_st.vco_freq / dev->pdata->pll2_vco_diff_m2;
dev->ad9523_st.vco_out_freq[AD9523_VCXO] = dev->pdata->vcxo_freq;
ret = ad9523_spi_write(dev,
AD9523_PLL2_R2_DIVIDER,
AD9523_PLL2_R2_DIVIDER_VAL(dev->pdata->pll2_r2_div));
if (ret < 0)
return ret;
ret = ad9523_spi_write(dev,
AD9523_PLL2_LOOP_FILTER_CTRL,
AD9523_PLL2_LOOP_FILTER_CPOLE1(dev->pdata->cpole1) |
AD9523_PLL2_LOOP_FILTER_RZERO(dev->pdata->rzero) |
AD9523_PLL2_LOOP_FILTER_RPOLE2(dev->pdata->rpole2) |
AD_IF(rzero_bypass_en,
AD9523_PLL2_LOOP_FILTER_RZERO_BYPASS_EN));
if (ret < 0)
return ret;
for (i = 0; i < dev->pdata->num_channels; i++) {
chan = &dev->pdata->channels[i];
if (chan->channel_num < AD9523_NUM_CHAN) {
active_mask |= (1 << chan->channel_num);
ret = ad9523_spi_write(dev,
AD9523_CHANNEL_CLOCK_DIST(chan->channel_num),
AD9523_CLK_DIST_DRIVER_MODE(chan->driver_mode) |
AD9523_CLK_DIST_DIV(chan->channel_divider) |
AD9523_CLK_DIST_DIV_PHASE(chan->divider_phase) |
(chan->sync_ignore_en ?
AD9523_CLK_DIST_IGNORE_SYNC_EN : 0) |
(chan->divider_output_invert_en ?
AD9523_CLK_DIST_INV_DIV_OUTPUT_EN : 0) |
(chan->low_power_mode_en ?
AD9523_CLK_DIST_LOW_PWR_MODE_EN : 0) |
(chan->output_dis ?
AD9523_CLK_DIST_PWR_DOWN_EN : 0));
if (ret < 0)
return ret;
ret = ad9523_vco_out_map(dev,
chan->channel_num,
chan->use_alt_clock_src);
if (ret < 0)
return ret;
}
}
for (i = 0; i < AD9523_NUM_CHAN; i++) {
if (!(active_mask & (1 << i))) {
ad9523_spi_write(dev,
AD9523_CHANNEL_CLOCK_DIST(i),
AD9523_CLK_DIST_DRIVER_MODE(TRISTATE) |
AD9523_CLK_DIST_PWR_DOWN_EN);
}
}
ret = ad9523_spi_write(dev,
AD9523_POWER_DOWN_CTRL,
0);
if (ret < 0)
return ret;
ret = ad9523_spi_write(dev,
AD9523_STATUS_SIGNALS,
AD9523_STATUS_MONITOR_01_PLL12_LOCKED);
if (ret < 0)
return ret;
ret = ad9523_io_update(dev);
if (ret < 0)
return ret;
ret = ad9523_sync(dev);
if (ret < 0)
return ret;
ad9523_spi_write(dev,
AD9523_READBACK_CTRL,
0x0);
ad9523_io_update(dev);
ad9523_calibrate(dev);
ad9523_sync(dev);
*device = dev;
return (ad9523_status(dev));
}
/***************************************************************************//**
* @brief Free the resources allocated by ad9523_setup().
*
* @param dev - The device structure.
*
* @return 0 in case of success, negative error code otherwise.
*******************************************************************************/
int32_t ad9523_remove(struct ad9523_dev *dev)
{
int32_t ret;
ret = no_os_spi_remove(dev->spi_desc);
no_os_free(dev);
return ret;
}
@@ -0,0 +1,509 @@
/***************************************************************************//**
* @file AD9523.h
* @brief Header file of AD9523 Driver.
* @author DBogdan (dragos.bogdan@analog.com)
********************************************************************************
* Copyright 2012-2016(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/
#ifndef _AD9523_H_
#define _AD9523_H_
#include <stdint.h>
#include "no_os_delay.h"
#include "no_os_spi.h"
/* Registers */
#define AD9523_READ (1 << 15)
#define AD9523_WRITE (0 << 15)
#define AD9523_CNT(x) (((x) - 1) << 13)
#define AD9523_ADDR(x) ((x) & 0xFFF)
#define AD9523_R1B (1 << 16)
#define AD9523_R2B (2 << 16)
#define AD9523_R3B (3 << 16)
#define AD9523_TRANSF_LEN(x) ((x) >> 16)
#define AD9523_SERIAL_PORT_CONFIG (AD9523_R1B | 0x0)
#define AD9523_VERSION_REGISTER (AD9523_R1B | 0x2)
#define AD9523_PART_REGISTER (AD9523_R1B | 0x3)
#define AD9523_READBACK_CTRL (AD9523_R1B | 0x4)
#define AD9523_EEPROM_CUSTOMER_VERSION_ID (AD9523_R2B | 0x6)
#define AD9523_PLL1_REF_A_DIVIDER (AD9523_R2B | 0x11)
#define AD9523_PLL1_REF_B_DIVIDER (AD9523_R2B | 0x13)
#define AD9523_PLL1_REF_TEST_DIVIDER (AD9523_R1B | 0x14)
#define AD9523_PLL1_FEEDBACK_DIVIDER (AD9523_R2B | 0x17)
#define AD9523_PLL1_CHARGE_PUMP_CTRL (AD9523_R2B | 0x19)
#define AD9523_PLL1_INPUT_RECEIVERS_CTRL (AD9523_R1B | 0x1A)
#define AD9523_PLL1_REF_CTRL (AD9523_R1B | 0x1B)
#define AD9523_PLL1_MISC_CTRL (AD9523_R1B | 0x1C)
#define AD9523_PLL1_LOOP_FILTER_CTRL (AD9523_R1B | 0x1D)
#define AD9523_PLL2_CHARGE_PUMP (AD9523_R1B | 0xF0)
#define AD9523_PLL2_FEEDBACK_DIVIDER_AB (AD9523_R1B | 0xF1)
#define AD9523_PLL2_CTRL (AD9523_R1B | 0xF2)
#define AD9523_PLL2_VCO_CTRL (AD9523_R1B | 0xF3)
#define AD9523_PLL2_VCO_DIVIDER (AD9523_R1B | 0xF4)
#define AD9523_PLL2_LOOP_FILTER_CTRL (AD9523_R2B | 0xF6)
#define AD9523_PLL2_R2_DIVIDER (AD9523_R1B | 0xF7)
#define AD9523_CHANNEL_CLOCK_DIST(ch) (AD9523_R3B | (0x192 + 3 * ch))
#define AD9523_PLL1_OUTPUT_CTRL (AD9523_R1B | 0x1BA)
#define AD9523_PLL1_OUTPUT_CHANNEL_CTRL (AD9523_R1B | 0x1BB)
#define AD9523_READBACK_0 (AD9523_R1B | 0x22C)
#define AD9523_READBACK_1 (AD9523_R1B | 0x22D)
#define AD9523_STATUS_SIGNALS (AD9523_R3B | 0x232)
#define AD9523_POWER_DOWN_CTRL (AD9523_R1B | 0x233)
#define AD9523_IO_UPDATE (AD9523_R1B | 0x234)
#define AD9523_EEPROM_DATA_XFER_STATUS (AD9523_R1B | 0xB00)
#define AD9523_EEPROM_ERROR_READBACK (AD9523_R1B | 0xB01)
#define AD9523_EEPROM_CTRL1 (AD9523_R1B | 0xB02)
#define AD9523_EEPROM_CTRL2 (AD9523_R1B | 0xB03)
/* AD9523_SERIAL_PORT_CONFIG */
#define AD9523_SER_CONF_SDO_ACTIVE ((1 << 7) | (1 << 0))
#define AD9523_SER_CONF_SOFT_RESET ((1 << 5) | (1 << 2))
/* AD9523_READBACK_CTRL */
#define AD9523_READBACK_CTRL_READ_BUFFERED (1 << 0)
/* AD9523_PLL1_CHARGE_PUMP_CTRL */
#define AD9523_PLL1_CHARGE_PUMP_CURRENT_nA(x) (((x) / 500) & 0x7F)
#define AD9523_PLL1_CHARGE_PUMP_TRISTATE (1 << 7)
#define AD9523_PLL1_CHARGE_PUMP_MODE_NORMAL (3 << 8)
#define AD9523_PLL1_CHARGE_PUMP_MODE_PUMP_DOWN (2 << 8)
#define AD9523_PLL1_CHARGE_PUMP_MODE_PUMP_UP (1 << 8)
#define AD9523_PLL1_CHARGE_PUMP_MODE_TRISTATE (0 << 8)
#define AD9523_PLL1_BACKLASH_PW_MIN (0 << 10)
#define AD9523_PLL1_BACKLASH_PW_LOW (1 << 10)
#define AD9523_PLL1_BACKLASH_PW_HIGH (2 << 10)
#define AD9523_PLL1_BACKLASH_PW_MAX (3 << 10)
/* AD9523_PLL1_INPUT_RECEIVERS_CTRL */
#define AD9523_PLL1_REF_TEST_RCV_EN (1 << 7)
#define AD9523_PLL1_REFB_DIFF_RCV_EN (1 << 6)
#define AD9523_PLL1_REFA_DIFF_RCV_EN (1 << 5)
#define AD9523_PLL1_REFB_RCV_EN (1 << 4)
#define AD9523_PLL1_REFA_RCV_EN (1 << 3)
#define AD9523_PLL1_REFA_REFB_PWR_CTRL_EN (1 << 2)
#define AD9523_PLL1_OSC_IN_CMOS_NEG_INP_EN (1 << 1)
#define AD9523_PLL1_OSC_IN_DIFF_EN (1 << 0)
/* AD9523_PLL1_REF_CTRL */
#define AD9523_PLL1_BYPASS_REF_TEST_DIV_EN (1 << 7)
#define AD9523_PLL1_BYPASS_FEEDBACK_DIV_EN (1 << 6)
#define AD9523_PLL1_ZERO_DELAY_MODE_INT (1 << 5)
#define AD9523_PLL1_ZERO_DELAY_MODE_EXT (0 << 5)
#define AD9523_PLL1_OSC_IN_PLL_FEEDBACK_EN (1 << 4)
#define AD9523_PLL1_ZD_IN_CMOS_NEG_INP_EN (1 << 3)
#define AD9523_PLL1_ZD_IN_DIFF_EN (1 << 2)
#define AD9523_PLL1_REFB_CMOS_NEG_INP_EN (1 << 1)
#define AD9523_PLL1_REFA_CMOS_NEG_INP_EN (1 << 0)
/* AD9523_PLL1_MISC_CTRL */
#define AD9523_PLL1_REFB_INDEP_DIV_CTRL_EN (1 << 7)
#define AD9523_PLL1_OSC_CTRL_FAIL_VCC_BY2_EN (1 << 6)
#define AD9523_PLL1_REF_MODE(x) ((x) << 2)
#define AD9523_PLL1_BYPASS_REFB_DIV (1 << 1)
#define AD9523_PLL1_BYPASS_REFA_DIV (1 << 0)
/* AD9523_PLL1_LOOP_FILTER_CTRL */
#define AD9523_PLL1_LOOP_FILTER_RZERO(x) ((x) & 0xF)
/* AD9523_PLL2_CHARGE_PUMP */
#define AD9523_PLL2_CHARGE_PUMP_CURRENT_nA(x) ((x) / 3500)
/* AD9523_PLL2_FEEDBACK_DIVIDER_AB */
#define AD9523_PLL2_FB_NDIV_A_CNT(x) (((x) & 0x3) << 6)
#define AD9523_PLL2_FB_NDIV_B_CNT(x) (((x) & 0x3F) << 0)
#define AD9523_PLL2_FB_NDIV(a, b) (4 * (b) + (a))
/* AD9523_PLL2_CTRL */
#define AD9523_PLL2_CHARGE_PUMP_MODE_NORMAL (3 << 0)
#define AD9523_PLL2_CHARGE_PUMP_MODE_PUMP_DOWN (2 << 0)
#define AD9523_PLL2_CHARGE_PUMP_MODE_PUMP_UP (1 << 0)
#define AD9523_PLL2_CHARGE_PUMP_MODE_TRISTATE (0 << 0)
#define AD9523_PLL2_BACKLASH_PW_MIN (0 << 2)
#define AD9523_PLL2_BACKLASH_PW_LOW (1 << 2)
#define AD9523_PLL2_BACKLASH_PW_HIGH (2 << 2)
#define AD9523_PLL2_BACKLASH_PW_MAX (3 << 1)
#define AD9523_PLL2_BACKLASH_CTRL_EN (1 << 4)
#define AD9523_PLL2_FREQ_DOUBLER_EN (1 << 5)
#define AD9523_PLL2_LOCK_DETECT_PWR_DOWN_EN (1 << 7)
/* AD9523_PLL2_VCO_CTRL */
#define AD9523_PLL2_VCO_CALIBRATE (1 << 1)
#define AD9523_PLL2_FORCE_VCO_MIDSCALE (1 << 2)
#define AD9523_PLL2_FORCE_REFERENCE_VALID (1 << 3)
#define AD9523_PLL2_FORCE_RELEASE_SYNC (1 << 4)
/* AD9523_PLL2_VCO_DIVIDER */
#define AD9523_PLL2_VCO_DIV_M1(x) ((((x) - 3) & 0x3) << 0)
#define AD9523_PLL2_VCO_DIV_M2(x) ((((x) - 3) & 0x3) << 4)
#define AD9523_PLL2_VCO_DIV_M1_PWR_DOWN_EN (1 << 2)
#define AD9523_PLL2_VCO_DIV_M2_PWR_DOWN_EN (1 << 6)
/* AD9523_PLL2_LOOP_FILTER_CTRL */
#define AD9523_PLL2_LOOP_FILTER_CPOLE1(x) (((x) & 0x7) << 0)
#define AD9523_PLL2_LOOP_FILTER_RZERO(x) (((x) & 0x7) << 3)
#define AD9523_PLL2_LOOP_FILTER_RPOLE2(x) (((x) & 0x7) << 6)
#define AD9523_PLL2_LOOP_FILTER_RZERO_BYPASS_EN (1 << 8)
/* AD9523_PLL2_R2_DIVIDER */
#define AD9523_PLL2_R2_DIVIDER_VAL(x) (((x) & 0x1F) << 0)
/* AD9523_CHANNEL_CLOCK_DIST */
#define AD9523_CLK_DIST_DIV_PHASE(x) (((x) & 0x3F) << 18)
#define AD9523_CLK_DIST_DIV_PHASE_REV(x) ((ret >> 18) & 0x3F)
#define AD9523_CLK_DIST_DIV(x) ((((x) - 1) & 0x3FF) << 8)
#define AD9523_CLK_DIST_DIV_REV(x) (((ret >> 8) & 0x3FF) + 1)
#define AD9523_CLK_DIST_INV_DIV_OUTPUT_EN (1 << 7)
#define AD9523_CLK_DIST_IGNORE_SYNC_EN (1 << 6)
#define AD9523_CLK_DIST_PWR_DOWN_EN (1 << 5)
#define AD9523_CLK_DIST_LOW_PWR_MODE_EN (1 << 4)
#define AD9523_CLK_DIST_DRIVER_MODE(x) (((x) & 0xF) << 0)
/* AD9523_PLL1_OUTPUT_CTRL */
#define AD9523_PLL1_OUTP_CTRL_VCO_DIV_SEL_CH6_M2 (1 << 7)
#define AD9523_PLL1_OUTP_CTRL_VCO_DIV_SEL_CH5_M2 (1 << 6)
#define AD9523_PLL1_OUTP_CTRL_VCO_DIV_SEL_CH4_M2 (1 << 5)
#define AD9523_PLL1_OUTP_CTRL_CMOS_DRV_WEAK (1 << 4)
#define AD9523_PLL1_OUTP_CTRL_OUTPUT_DIV_1 (0 << 0)
#define AD9523_PLL1_OUTP_CTRL_OUTPUT_DIV_2 (1 << 0)
#define AD9523_PLL1_OUTP_CTRL_OUTPUT_DIV_4 (2 << 0)
#define AD9523_PLL1_OUTP_CTRL_OUTPUT_DIV_8 (4 << 0)
#define AD9523_PLL1_OUTP_CTRL_OUTPUT_DIV_16 (8 << 0)
/* AD9523_PLL1_OUTPUT_CHANNEL_CTRL */
#define AD9523_PLL1_OUTP_CH_CTRL_OUTPUT_PWR_DOWN_EN (1 << 7)
#define AD9523_PLL1_OUTP_CH_CTRL_VCO_DIV_SEL_CH9_M2 (1 << 6)
#define AD9523_PLL1_OUTP_CH_CTRL_VCO_DIV_SEL_CH8_M2 (1 << 5)
#define AD9523_PLL1_OUTP_CH_CTRL_VCO_DIV_SEL_CH7_M2 (1 << 4)
#define AD9523_PLL1_OUTP_CH_CTRL_VCXO_SRC_SEL_CH3 (1 << 3)
#define AD9523_PLL1_OUTP_CH_CTRL_VCXO_SRC_SEL_CH2 (1 << 2)
#define AD9523_PLL1_OUTP_CH_CTRL_VCXO_SRC_SEL_CH1 (1 << 1)
#define AD9523_PLL1_OUTP_CH_CTRL_VCXO_SRC_SEL_CH0 (1 << 0)
/* AD9523_READBACK_0 */
#define AD9523_READBACK_0_STAT_PLL2_REF_CLK (1 << 7)
#define AD9523_READBACK_0_STAT_PLL2_FB_CLK (1 << 6)
#define AD9523_READBACK_0_STAT_VCXO (1 << 5)
#define AD9523_READBACK_0_STAT_REF_TEST (1 << 4)
#define AD9523_READBACK_0_STAT_REFB (1 << 3)
#define AD9523_READBACK_0_STAT_REFA (1 << 2)
#define AD9523_READBACK_0_STAT_PLL2_LD (1 << 1)
#define AD9523_READBACK_0_STAT_PLL1_LD (1 << 0)
/* AD9523_READBACK_1 */
#define AD9523_READBACK_1_HOLDOVER_ACTIVE (1 << 3)
#define AD9523_READBACK_1_AUTOMODE_SEL_REFB (1 << 2)
#define AD9523_READBACK_1_VCO_CALIB_IN_PROGRESS (1 << 0)
/* AD9523_STATUS_SIGNALS */
#define AD9523_STATUS_SIGNALS_SYNC_MAN_CTRL (1 << 16)
#define AD9523_STATUS_MONITOR_01_PLL12_LOCKED (0x302)
/* AD9523_POWER_DOWN_CTRL */
#define AD9523_POWER_DOWN_CTRL_PLL1_PWR_DOWN (1 << 2)
#define AD9523_POWER_DOWN_CTRL_PLL2_PWR_DOWN (1 << 1)
#define AD9523_POWER_DOWN_CTRL_DIST_PWR_DOWN (1 << 0)
/* AD9523_IO_UPDATE */
#define AD9523_IO_UPDATE_EN (1 << 0)
/* AD9523_EEPROM_DATA_XFER_STATUS */
#define AD9523_EEPROM_DATA_XFER_IN_PROGRESS (1 << 0)
/* AD9523_EEPROM_ERROR_READBACK */
#define AD9523_EEPROM_ERROR_READBACK_FAIL (1 << 0)
/* AD9523_EEPROM_CTRL1 */
#define AD9523_EEPROM_CTRL1_SOFT_EEPROM (1 << 1)
#define AD9523_EEPROM_CTRL1_EEPROM_WRITE_PROT_DIS (1 << 0)
/* AD9523_EEPROM_CTRL2 */
#define AD9523_EEPROM_CTRL2_REG2EEPROM (1 << 0)
#define AD9523_NUM_CHAN 14
#define AD9523_NUM_CHAN_ALT_CLK_SRC 10
enum outp_drv_mode {
TRISTATE,
LVPECL_8mA,
LVDS_4mA,
LVDS_7mA,
HSTL0_16mA,
HSTL1_8mA,
CMOS_CONF1,
CMOS_CONF2,
CMOS_CONF3,
CMOS_CONF4,
CMOS_CONF5,
CMOS_CONF6,
CMOS_CONF7,
CMOS_CONF8,
CMOS_CONF9
};
enum ref_sel_mode {
NONEREVERTIVE_STAY_ON_REFB,
REVERT_TO_REFA,
SELECT_REFA,
SELECT_REFB,
EXT_REF_SEL
};
/**
* @struct ad9523_channel_spec
* @brief Output channel configuration
*/
struct ad9523_channel_spec {
/** Output channel number. */
uint8_t channel_num;
/** Invert the polarity of the output clock. */
uint8_t divider_output_invert_en;
/** Ignore chip-level SYNC signal. */
uint8_t sync_ignore_en;
/** Reduce power used in the differential output modes. */
uint8_t low_power_mode_en;
/** Channel divider uses alternative clk source: CH0..CH3 VCXO, CH4..CH9 VCO2 */
uint8_t use_alt_clock_src;
/** Disables, powers down the entire channel. */
uint8_t output_dis;
/** Output driver mode (logic level family). */
uint8_t driver_mode;
/** Divider initial phase after a SYNC. Range 0..63
* LSB = 1/2 of a period of the divider input clock.
*/
uint8_t divider_phase;
/** 10-bit channel divider. */
uint16_t channel_divider;
/** Optional descriptive channel name. */
int8_t extended_name[16];
};
enum pll1_rzero_resistor {
RZERO_883_OHM,
RZERO_677_OHM,
RZERO_341_OHM,
RZERO_135_OHM,
RZERO_10_OHM,
RZERO_USE_EXT_RES = 8,
};
enum rpole2_resistor {
RPOLE2_900_OHM,
RPOLE2_450_OHM,
RPOLE2_300_OHM,
RPOLE2_225_OHM,
};
enum rzero_resistor {
RZERO_3250_OHM,
RZERO_2750_OHM,
RZERO_2250_OHM,
RZERO_2100_OHM,
RZERO_3000_OHM,
RZERO_2500_OHM,
RZERO_2000_OHM,
RZERO_1850_OHM,
};
enum cpole1_capacitor {
CPOLE1_0_PF,
CPOLE1_8_PF,
CPOLE1_16_PF,
CPOLE1_24_PF,
_CPOLE1_24_PF, /* place holder */
CPOLE1_32_PF,
CPOLE1_40_PF,
CPOLE1_48_PF,
};
/**
* @struct ad9523_platform_data
* @brief platform specific information
*/
struct ad9523_platform_data {
/** External VCXO frequency in Hz */
uint32_t vcxo_freq;
/** Enable SPI-3wire mode */
uint8_t spi3wire;
/** REFA differential/single-ended input selection. */
uint8_t refa_diff_rcv_en;
/** REFB differential/single-ended input selection. */
uint8_t refb_diff_rcv_en;
/** Zero Delay differential/single-ended input selection. */
uint8_t zd_in_diff_en;
/** OSC differential/ single-ended input selection. */
uint8_t osc_in_diff_en;
/*
* Valid if differential input disabled
* if not true defaults to pos input
*/
/** REFA single-ended neg./pos. input enable. */
uint8_t refa_cmos_neg_inp_en;
/* REFB single-ended neg./pos. input enable. */
uint8_t refb_cmos_neg_inp_en;
/** Zero Delay single-ended neg./pos. input enable. */
uint8_t zd_in_cmos_neg_inp_en;
/** OSC single-ended neg./pos. input enable. */
uint8_t osc_in_cmos_neg_inp_en;
/* PLL1 Setting */
/** PLL1 10-bit: REFA R divider. */
uint16_t refa_r_div;
/** PLL1 10-bit: REFB R divider. */
uint16_t refb_r_div;
/** PLL1 10-bit Feedback N divider. */
uint16_t pll1_feedback_div;
/** Magnitude of PLL1 charge pump current (nA). */
uint16_t pll1_charge_pump_current_nA;
/** Internal, external Zero Delay mode selection. */
uint8_t zero_delay_mode_internal_en;
/** PLL1 feedback path, local feedback from the
* OSC_IN receiver or zero delay mode
*/
uint8_t osc_in_feedback_en;
/** Bypass PLL1 - Single loop mode */
uint8_t pll1_bypass_en;
/** PLL1 Loop Filter Zero Resistor selection. */
uint8_t pll1_loop_filter_rzero;
/** Reference mode selection. */
uint8_t ref_mode;
/* PLL2 Setting */
/** Magnitude of PLL2 charge pump current (nA). */
uint32_t pll2_charge_pump_current_nA;
/** PLL2 Feedback N-divider, A Counter, range 0..4. */
uint8_t pll2_ndiv_a_cnt;
/** PLL2 Feedback N-divider, B Counter, range 0..63. */
uint8_t pll2_ndiv_b_cnt;
/** PLL2 frequency doubler enable. */
uint8_t pll2_freq_doubler_en;
/** PLL2 R2 divider, range 0..31. */
uint8_t pll2_r2_div;
/** VCO1 divider, range 3..5. */
uint8_t pll2_vco_diff_m1;
/** VCO2 divider, range 3..5. */
uint8_t pll2_vco_diff_m2;
/* Loop Filter PLL2 */
/** PLL2 loop filter Rpole resistor value. */
uint8_t rpole2;
/** PLL2 loop filter Rzero resistor value. */
uint8_t rzero;
/** PLL2 loop filter Cpole capacitor value. */
uint8_t cpole1;
/** PLL2 loop filter Rzero bypass enable. */
uint8_t rzero_bypass_en;
/* Output Channel Configuration */
/** Array size of struct ad9523_channel_spec. */
int32_t num_channels;
/** Pointer to channel array. */
struct ad9523_channel_spec *channels;
/** Optional alternative iio device name. */
int8_t name[16];
};
struct ad9523_state {
struct ad9523_platform_data *pdata;
uint32_t vcxo_freq;
uint32_t vco_freq;
uint32_t vco_out_freq[3];
uint8_t vco_out_map[14];
};
enum ad9523_out_frequencies {
AD9523_VCO1,
AD9523_VCO2,
AD9523_VCXO,
AD9523_NUM_CLK_SRC,
};
struct ad9523_dev {
/* SPI */
struct no_os_spi_desc *spi_desc;
/* Device Settings */
struct ad9523_state ad9523_st;
struct ad9523_platform_data *pdata;
};
struct ad9523_init_param {
/* SPI */
struct no_os_spi_init_param spi_init;
/* Device Settings */
struct ad9523_platform_data *pdata;
};
/* Reads the value of the selected register. */
int32_t ad9523_spi_read(struct ad9523_dev *dev,
uint32_t reg_addr,
uint32_t *reg_data);
/* Writes a value to the selected register. */
int32_t ad9523_spi_write(struct ad9523_dev *dev,
uint32_t reg_addr,
uint32_t reg_data);
/* Updates the AD9523 configuration */
int32_t ad9523_io_update(struct ad9523_dev *dev);
/* Sets the clock provider for selected channel. */
int32_t ad9523_vco_out_map(struct ad9523_dev *dev,
uint32_t ch,
uint32_t out);
/* Updates the AD9523 configuration. */
int32_t ad9523_sync(struct ad9523_dev *dev);
/* Initialize the AD9523 data structure*/
int32_t ad9523_init(struct ad9523_init_param *init_param);
/* Configure the AD9523. */
int32_t ad9523_setup(struct ad9523_dev **device,
const struct ad9523_init_param *init_param);
/* Free the resources allocated by ad9523_setup(). */
int32_t ad9523_remove(struct ad9523_dev *dev);
int32_t ad9523_status(struct ad9523_dev *dev);
#endif // __AD9523_H__
@@ -0,0 +1,693 @@
/**
* MIT License
*
* Copyright (c) 2020 Jimmy Pentz
*
* Reach me at: github.com/jgpentz, jpentz1(at)gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sells
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* ADAR1000 4-Channel, X Band and Ku Band Beamformer */
// ----------------------------------------------------------------------------
// Includes
// ----------------------------------------------------------------------------
#include "main.h"
#include "stm32f7xx_hal.h"
#include "stm32f7xx_hal_spi.h"
#include "stm32f7xx_hal_gpio.h"
#include "adar1000.h"
// ----------------------------------------------------------------------------
// Preprocessor Definitions and Constants
// ----------------------------------------------------------------------------
// VM_GAIN is 15 dB of gain in 128 steps. ~0.12 dB per step.
// A 15 dB attenuator can be applied on top of these values.
const uint8_t VM_GAIN[128] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
};
// VM_I and VM_Q are the settings for the vector modulator. 128 steps in 360 degrees. ~2.813 degrees per step.
const uint8_t VM_I[128] = {
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3E, 0x3E, 0x3D, 0x3D, 0x3C, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37,
0x36, 0x35, 0x34, 0x33, 0x32, 0x30, 0x2F, 0x2E, 0x2C, 0x2B, 0x2A, 0x28, 0x27, 0x25, 0x24, 0x22,
0x21, 0x01, 0x03, 0x04, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0D, 0x0E, 0x0F, 0x11, 0x12, 0x13, 0x14,
0x16, 0x17, 0x18, 0x19, 0x19, 0x1A, 0x1B, 0x1C, 0x1C, 0x1D, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F,
0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1D, 0x1D, 0x1C, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17,
0x16, 0x15, 0x14, 0x13, 0x12, 0x10, 0x0F, 0x0E, 0x0C, 0x0B, 0x0A, 0x08, 0x07, 0x05, 0x04, 0x02,
0x01, 0x21, 0x23, 0x24, 0x26, 0x27, 0x28, 0x2A, 0x2B, 0x2D, 0x2E, 0x2F, 0x31, 0x32, 0x33, 0x34,
0x36, 0x37, 0x38, 0x39, 0x39, 0x3A, 0x3B, 0x3C, 0x3C, 0x3D, 0x3E, 0x3E, 0x3E, 0x3F, 0x3F, 0x3F,
};
const uint8_t VM_Q[128] = {
0x20, 0x21, 0x23, 0x24, 0x26, 0x27, 0x28, 0x2A, 0x2B, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x33, 0x34,
0x35, 0x36, 0x37, 0x38, 0x38, 0x39, 0x3A, 0x3A, 0x3B, 0x3C, 0x3C, 0x3C, 0x3D, 0x3D, 0x3D, 0x3D,
0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3C, 0x3C, 0x3C, 0x3B, 0x3A, 0x3A, 0x39, 0x38, 0x38, 0x37, 0x36,
0x35, 0x34, 0x33, 0x31, 0x30, 0x2F, 0x2E, 0x2D, 0x2B, 0x2A, 0x28, 0x27, 0x26, 0x24, 0x23, 0x21,
0x20, 0x01, 0x03, 0x04, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x13, 0x14,
0x15, 0x16, 0x17, 0x18, 0x18, 0x19, 0x1A, 0x1A, 0x1B, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D,
0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1C, 0x1C, 0x1C, 0x1B, 0x1A, 0x1A, 0x19, 0x18, 0x18, 0x17, 0x16,
0x15, 0x14, 0x13, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0B, 0x0A, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01,
};
// ----------------------------------------------------------------------------
// Function Definitions
// ----------------------------------------------------------------------------
/**
* @brief Initialize the ADC on the ADAR by setting the ADC with a 2 MHz clk,
* and then enable it.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
* if this set to BROADCAST_ON.
*
* @warning This is setup to only read temperature sensor data, not the power detectors.
*/
void Adar_AdcInit(const AdarDevice * p_adar, uint8_t broadcast)
{
uint8_t data;
data = ADAR1000_ADC_2MHZ_CLK | ADAR1000_ADC_EN;
Adar_Write(p_adar, REG_ADC_CONTROL, data, broadcast);
}
/**
* @brief Read a byte of data from the ADAR.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
* if this set to BROADCAST_ON.
*
* @return Returns a byte of data that has been converted from the temperature sensor.
*
* @warning This is setup to only read temperature sensor data, not the power detectors.
*/
uint8_t Adar_AdcRead(const AdarDevice * p_adar, uint8_t broadcast)
{
uint8_t data;
// Start the ADC conversion
Adar_Write(p_adar, REG_ADC_CONTROL, ADAR1000_ADC_ST_CONV, broadcast);
// This is blocking for now... wait until data is converted, then read it
while (!(Adar_Read(p_adar, REG_ADC_CONTROL) & 0x01))
{
}
data = Adar_Read(p_adar, REG_ADC_OUT);
return(data);
}
/**
* @brief Requests the device info from a specific ADAR and stores it in the
* provided AdarDeviceInfo struct.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param info[out] Struct that contains the device info fields.
*
* @return Returns ADAR_ERROR_NOERROR if information was successfully received and stored in the struct.
*/
uint8_t Adar_GetDeviceInfo(const AdarDevice * p_adar, AdarDeviceInfo * info)
{
*((uint8_t *)info) = Adar_Read(p_adar, 0x002);
info->chip_type = Adar_Read(p_adar, 0x003);
info->product_id = ((uint16_t)Adar_Read(p_adar, 0x004)) << 8;
info->product_id |= ((uint16_t)Adar_Read(p_adar, 0x005)) & 0x00ff;
info->scratchpad = Adar_Read(p_adar, 0x00A);
info->spi_rev = Adar_Read(p_adar, 0x00B);
info->vendor_id = ((uint16_t)Adar_Read(p_adar, 0x00C)) << 8;
info->vendor_id |= ((uint16_t)Adar_Read(p_adar, 0x00D)) & 0x00ff;
info->rev_id = Adar_Read(p_adar, 0x045);
return(ADAR_ERROR_NOERROR);
}
/**
* @brief Read the data that is stored in a single ADAR register.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param mem_addr Memory address of the register you wish to read from.
*
* @return Returns the byte of data that is stored in the desired register.
*
* @warning This function will clear ADDR_ASCN bits.
* @warning The ADAR does not allow for block reads.
*/
uint8_t Adar_Read(const AdarDevice * p_adar, uint32_t mem_addr)
{
uint8_t instruction[3];
// Set SDO active
Adar_Write(p_adar, REG_INTERFACE_CONFIG_A, INTERFACE_CONFIG_A_SDO_ACTIVE, 0);
instruction[0] = 0x80 | ((p_adar->dev_addr & 0x03) << 5);
instruction[0] |= ((0xff00 & mem_addr) >> 8);
instruction[1] = (0xff & mem_addr);
instruction[2] = 0x00;
p_adar->Transfer(instruction, p_adar->p_rx_buffer, ADAR1000_RD_SIZE);
// Set SDO Inactive
Adar_Write(p_adar, REG_INTERFACE_CONFIG_A, 0, 0);
return(p_adar->p_rx_buffer[2]);
}
/**
* @brief Block memory write to an ADAR device.
*
* @pre ADDR_ASCN bits in register zero must be set!
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param mem_addr Memory address of the register you wish to read from.
* @param p_data Pointer to block of data to transfer (must have two unused bytes preceding the data for instruction).
* @param size Size of data in bytes, including the two additional leading bytes.
*
* @warning First two bytes of data will be corrupted if you do not provide two unused leading bytes!
*/
void Adar_ReadBlock(const AdarDevice * p_adar, uint16_t mem_addr, uint8_t * p_data, uint32_t size)
{
// Set SDO active
Adar_Write(p_adar, REG_INTERFACE_CONFIG_A, INTERFACE_CONFIG_A_SDO_ACTIVE | INTERFACE_CONFIG_A_ADDR_ASCN, 0);
// Prepare command
p_data[0] = 0x80 | ((p_adar->dev_addr & 0x03) << 5);
p_data[0] |= ((mem_addr) >> 8) & 0x1F;
p_data[1] = (0xFF & mem_addr);
// Start the transfer
p_adar->Transfer(p_data, p_data, size);
Adar_Write(p_adar, REG_INTERFACE_CONFIG_A, 0, 0);
// Return nothing since we assume this is non-blocking and won't wait around
}
/**
* @brief Sets the Rx/Tx bias currents for the LNA, VM, and VGA to be in either
* low power setting or nominal setting.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param p_bias[in] An AdarBiasCurrents struct filled with bias settings
* as seen in the datasheet Table 6. SPI Settings for
* Different Power Modules
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
* if this set to BROADCAST_ON.
*
* @return Returns ADAR_ERR_NOERROR if the bias currents were set
*/
uint8_t Adar_SetBiasCurrents(const AdarDevice * p_adar, AdarBiasCurrents * p_bias, uint8_t broadcast)
{
uint8_t bias = 0;
// RX LNA/VGA/VM bias
bias = (p_bias->rx_lna & 0x0f);
Adar_Write(p_adar, REG_BIAS_CURRENT_RX_LNA, bias, broadcast); // RX LNA bias
bias = (p_bias->rx_vga & 0x07 << 3) | (p_bias->rx_vm & 0x07);
Adar_Write(p_adar, REG_BIAS_CURRENT_RX, bias, broadcast); // RX VM/VGA bias
// TX VGA/VM/DRV bias
bias = (p_bias->tx_vga & 0x07 << 3) | (p_bias->tx_vm & 0x07);
Adar_Write(p_adar, REG_BIAS_CURRENT_TX, bias, broadcast); // TX VM/VGA bias
bias = (p_bias->tx_drv & 0x07);
Adar_Write(p_adar, REG_BIAS_CURRENT_TX_DRV, bias, broadcast); // TX DRV bias
return(ADAR_ERROR_NOERROR);
}
/**
* @brief Set the bias ON and bias OFF voltages for the four PA's and one LNA.
*
* @pre This will set all 5 bias ON values and all 5 bias OFF values at once.
* To enable these bias values, please see the data sheet and ensure that the BIAS_CTRL,
* LNA_BIAS_OUT_EN, TR_SOURCE, TX_EN, RX_EN, TR (input to chip), and PA_ON (input to chip)
* bits have all been properly set.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param bias_on_voltage Array that contains the bias ON voltages.
* @param bias_off_voltage Array that contains the bias OFF voltages.
*
* @return Returns ADAR_ERR_NOERROR if the bias currents were set
*/
uint8_t Adar_SetBiasVoltages(const AdarDevice * p_adar, uint8_t bias_on_voltage[5], uint8_t bias_off_voltage[5])
{
Adar_SetBit(p_adar, 0x30, 6, BROADCAST_OFF);
Adar_SetBit(p_adar, 0x31, 2, BROADCAST_OFF);
Adar_SetBit(p_adar, 0x38, 5, BROADCAST_OFF);
Adar_Write(p_adar, REG_PA_CH1_BIAS_ON,bias_on_voltage[0], BROADCAST_OFF);
Adar_Write(p_adar, REG_PA_CH2_BIAS_ON,bias_on_voltage[1], BROADCAST_OFF);
Adar_Write(p_adar, REG_PA_CH3_BIAS_ON,bias_on_voltage[2], BROADCAST_OFF);
Adar_Write(p_adar, REG_PA_CH4_BIAS_ON,bias_on_voltage[3], BROADCAST_OFF);
Adar_Write(p_adar, REG_PA_CH1_BIAS_OFF,bias_off_voltage[0], BROADCAST_OFF);
Adar_Write(p_adar, REG_PA_CH2_BIAS_OFF,bias_off_voltage[1], BROADCAST_OFF);
Adar_Write(p_adar, REG_PA_CH3_BIAS_OFF,bias_off_voltage[2], BROADCAST_OFF);
Adar_Write(p_adar, REG_PA_CH4_BIAS_OFF,bias_off_voltage[3], BROADCAST_OFF);
Adar_SetBit(p_adar, 0x30, 4, BROADCAST_OFF);
Adar_SetBit(p_adar, 0x30, 6, BROADCAST_OFF);
Adar_SetBit(p_adar, 0x31, 2, BROADCAST_OFF);
Adar_SetBit(p_adar, 0x38, 5, BROADCAST_OFF);
Adar_Write(p_adar, REG_LNA_BIAS_ON,bias_on_voltage[4], BROADCAST_OFF);
Adar_Write(p_adar, REG_LNA_BIAS_OFF,bias_off_voltage[4], BROADCAST_OFF);
Adar_ResetBit(p_adar, 0x30, 7, BROADCAST_OFF);
Adar_SetBit(p_adar, 0x31, 2, BROADCAST_OFF);
Adar_SetBit(p_adar, 0x31, 4, BROADCAST_OFF);
Adar_SetBit(p_adar, 0x31, 7, BROADCAST_OFF);
return(ADAR_ERROR_NOERROR);
}
/**
* @brief Setup the ADAR to use settings that are transferred over SPI.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
* if this set to BROADCAST_ON.
*
* @return Returns ADAR_ERR_NOERROR if the bias currents were set
*/
uint8_t Adar_SetRamBypass(const AdarDevice * p_adar, uint8_t broadcast)
{
uint8_t data;
data = (MEM_CTRL_BIAS_RAM_BYPASS | MEM_CTRL_BEAM_RAM_BYPASS);
Adar_Write(p_adar, REG_MEM_CTL, data, broadcast);
return(ADAR_ERROR_NOERROR);
}
/**
* @brief Set the VGA gain value of a Receive channel in dB.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param channel Channel in which to set the gain (1-4).
* @param vga_gain_db Gain to be applied to the channel, ranging from 0 - 30 dB.
* (Intended operation >16 dB).
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
* if this set to BROADCAST_ON.
*
* @return Returns ADAR_ERROR_NOERROR if the gain was successfully set.
* ADAR_ERROR_FAILED if an invalid channel was selected.
*
* @warning 0 dB or 15 dB step attenuator may also be turned on, which is why intended operation is >16 dB.
*/
uint8_t Adar_SetRxVgaGain(const AdarDevice * p_adar, uint8_t channel, uint8_t vga_gain_db, uint8_t broadcast)
{
uint8_t vga_gain_bits = (uint8_t)(255*vga_gain_db/16);
uint32_t mem_addr = 0;
if((channel == 0) || (channel > 4))
{
return(ADAR_ERROR_FAILED);
}
mem_addr = REG_CH1_RX_GAIN + (channel & 0x03);
// Set gain
Adar_Write(p_adar, mem_addr, vga_gain_bits, broadcast);
// Load the new setting
Adar_Write(p_adar, REG_LOAD_WORKING, 0x1, broadcast);
return(ADAR_ERROR_NOERROR);
}
/**
* @brief Set the phase of a given receive channel using the I/Q vector modulator.
*
* @pre According to the given @param phase, this sets the polarity (bit 5) and gain (bits 4-0)
* of the @param channel, and then loads them into the working register.
* A vector modulator I/Q look-up table has been provided at the beginning of this library.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param channel Channel in which to set the gain (1-4).
* @param phase Byte that is used to set the polarity (bit 5) and gain (bits 4-0).
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
* if this set to BROADCAST_ON.
*
* @return Returns ADAR_ERROR_NOERROR if the phase was successfully set.
* ADAR_ERROR_FAILED if an invalid channel was selected.
*
* @note To obtain your phase:
* phase = degrees * 128;
* phase /= 360;
*/
uint8_t Adar_SetRxPhase(const AdarDevice * p_adar, uint8_t channel, uint8_t phase, uint8_t broadcast)
{
uint8_t i_val = 0;
uint8_t q_val = 0;
uint32_t mem_addr_i, mem_addr_q;
if((channel == 0) || (channel > 4))
{
return(ADAR_ERROR_FAILED);
}
//phase = phase % 128;
i_val = VM_I[phase];
q_val = VM_Q[phase];
mem_addr_i = REG_CH1_RX_PHS_I + (channel & 0x03) * 2;
mem_addr_q = REG_CH1_RX_PHS_Q + (channel & 0x03) * 2;
Adar_Write(p_adar, mem_addr_i, i_val, broadcast);
Adar_Write(p_adar, mem_addr_q, q_val, broadcast);
Adar_Write(p_adar, REG_LOAD_WORKING, 0x1, broadcast);
return(ADAR_ERROR_NOERROR);
}
/**
* @brief Set the VGA gain value of a Tx channel in dB.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
* if this set to BROADCAST_ON.
*
* @return Returns ADAR_ERROR_NOERROR if the bias was successfully set.
* ADAR_ERROR_FAILED if an invalid channel was selected.
*
* @warning 0 dB or 15 dB step attenuator may also be turned on, which is why intended operation is >16 dB.
*/
uint8_t Adar_SetTxBias(const AdarDevice * p_adar, uint8_t broadcast)
{
uint8_t vga_bias_bits;
uint8_t drv_bias_bits;
uint32_t mem_vga_bias;
uint32_t mem_drv_bias;
mem_vga_bias = REG_BIAS_CURRENT_TX;
mem_drv_bias = REG_BIAS_CURRENT_TX_DRV;
// Set bias to nom
vga_bias_bits = 0x2D;
drv_bias_bits = 0x06;
// Set bias
Adar_Write(p_adar, mem_vga_bias, vga_bias_bits, broadcast);
// Set bias
Adar_Write(p_adar, mem_drv_bias, drv_bias_bits, broadcast);
// Load the new setting
Adar_Write(p_adar, REG_LOAD_WORKING, 0x2, broadcast);
return(ADAR_ERROR_NOERROR);
}
/**
* @brief Set the VGA gain value of a Tx channel.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param channel Tx channel in which to set the gain, ranging from 1 - 4.
* @param gain Gain to be applied to the channel, ranging from 0 - 127,
* plus the MSb 15dB attenuator (Intended operation >16 dB).
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
* if this set to BROADCAST_ON.
*
* @return Returns ADAR_ERROR_NOERROR if the gain was successfully set.
* ADAR_ERROR_FAILED if an invalid channel was selected.
*
* @warning 0 dB or 15 dB step attenuator may also be turned on, which is why intended operation is >16 dB.
*/
uint8_t Adar_SetTxVgaGain(const AdarDevice * p_adar, uint8_t channel, uint8_t gain, uint8_t broadcast)
{
uint32_t mem_addr;
if((channel == 0) || (channel > 4))
{
return(ADAR_ERROR_FAILED);
}
mem_addr = REG_CH1_TX_GAIN + (channel & 0x03);
// Set gain
Adar_Write(p_adar, mem_addr, gain, broadcast);
// Load the new setting
Adar_Write(p_adar, REG_LOAD_WORKING, LD_WRK_REGS_LDTX_OVERRIDE, broadcast);
return(ADAR_ERROR_NOERROR);
}
/**
* @brief Set the phase of a given transmit channel using the I/Q vector modulator.
*
* @pre According to the given @param phase, this sets the polarity (bit 5) and gain (bits 4-0)
* of the @param channel, and then loads them into the working register.
* A vector modulator I/Q look-up table has been provided at the beginning of this library.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param channel Channel in which to set the gain (1-4).
* @param phase Byte that is used to set the polarity (bit 5) and gain (bits 4-0).
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
* if this set to BROADCAST_ON.
*
* @return Returns ADAR_ERROR_NOERROR if the phase was successfully set.
* ADAR_ERROR_FAILED if an invalid channel was selected.
*
* @note To obtain your phase:
* phase = degrees * 128;
* phase /= 360;
*/
uint8_t Adar_SetTxPhase(const AdarDevice * p_adar, uint8_t channel, uint8_t phase, uint8_t broadcast)
{
uint8_t i_val = 0;
uint8_t q_val = 0;
uint32_t mem_addr_i, mem_addr_q;
if((channel == 0) || (channel > 4))
{
return(ADAR_ERROR_FAILED);
}
//phase = phase % 128;
i_val = VM_I[phase];
q_val = VM_Q[phase];
mem_addr_i = REG_CH1_TX_PHS_I + (channel & 0x03) * 2;
mem_addr_q = REG_CH1_TX_PHS_Q + (channel & 0x03) * 2;
Adar_Write(p_adar, mem_addr_i, i_val, broadcast);
Adar_Write(p_adar, mem_addr_q, q_val, broadcast);
Adar_Write(p_adar, REG_LOAD_WORKING, 0x1, broadcast);
return(ADAR_ERROR_NOERROR);
}
/**
* @brief Reset the whole ADAR device.
*
* @param p_adar[in] ADAR pointer Which specifies the device and what function
* to use for SPI transfer.
*/
void Adar_SoftReset(const AdarDevice * p_adar)
{
uint8_t instruction[3];
instruction[0] = ((p_adar->dev_addr & 0x03) << 5);
instruction[1] = 0x00;
instruction[2] = 0x81;
p_adar->Transfer(instruction, NULL, sizeof(instruction));
}
/**
* @brief Reset ALL ADAR devices in the SPI chain.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
*/
void Adar_SoftResetAll(const AdarDevice * p_adar)
{
uint8_t instruction[3];
instruction[0] = 0x08;
instruction[1] = 0x00;
instruction[2] = 0x81;
p_adar->Transfer(instruction, NULL, sizeof(instruction));
}
/**
* @brief Write a byte of @param data to the register located at @param mem_addr.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param mem_addr Memory address of the register you wish to read from.
* @param data Byte of data to be stored in the register.
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
if this set to BROADCAST_ON.
*
* @warning If writing the same data to multiple registers, use ADAR_WriteBlock.
*/
void Adar_Write(const AdarDevice * p_adar, uint32_t mem_addr, uint8_t data, uint8_t broadcast)
{
uint8_t instruction[3];
if (broadcast)
{
instruction[0] = 0x08;
}
else
{
instruction[0] = ((p_adar->dev_addr & 0x03) << 5);
}
instruction[0] |= (0x1F00 & mem_addr) >> 8;
instruction[1] = (0xFF & mem_addr);
instruction[2] = data;
p_adar->Transfer(instruction, NULL, sizeof(instruction));
}
/**
* @brief Block memory write to an ADAR device.
*
* @pre ADDR_ASCN BITS IN REGISTER ZERO MUST BE SET!
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param mem_addr Memory address of the register you wish to read from.
* @param p_data[in] Pointer to block of data to transfer (must have two unused bytes
preceding the data for instruction).
* @param size Size of data in bytes, including the two additional leading bytes.
*
* @warning First two bytes of data will be corrupted if you do not provide two unused leading bytes!
*/
void Adar_WriteBlock(const AdarDevice * p_adar, uint16_t mem_addr, uint8_t * p_data, uint32_t size)
{
// Prepare command
p_data[0] = ((p_adar->dev_addr & 0x03) << 5);
p_data[0] |= ((mem_addr) >> 8) & 0x1F;
p_data[1] = (0xFF & mem_addr);
// Start the transfer
p_adar->Transfer(p_data, NULL, size);
// Return nothing since we assume this is non-blocking and won't wait around
}
/**
* @brief Set contents of the INTERFACE_CONFIG_A register.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param flags #INTERFACE_CONFIG_A_SOFTRESET, #INTERFACE_CONFIG_A_LSB_FIRST,
* #INTERFACE_CONFIG_A_ADDR_ASCN, #INTERFACE_CONFIG_A_SDO_ACTIVE
* @param broadcast Send the message as a broadcast to all ADARs in the SPI chain
* if this set to BROADCAST_ON.
*/
void Adar_WriteConfigA(const AdarDevice * p_adar, uint8_t flags, uint8_t broadcast)
{
Adar_Write(p_adar, 0x00, flags, broadcast);
}
/**
* @brief Write a byte of @param data to the register located at @param mem_addr and
* then read from the device and verify that the register was correctly set.
*
* @param p_adar[in] Adar pointer Which specifies the device and what function
* to use for SPI transfer.
* @param mem_addr Memory address of the register you wish to read from.
* @param data Byte of data to be stored in the register.
*
* @return Returns the number of attempts that it took to successfully write to a register,
* starting from zero.
* @warning This function currently only supports writes to a single regiter in a single ADAR.
*/
uint8_t Adar_WriteVerify(const AdarDevice * p_adar, uint32_t mem_addr, uint8_t data)
{
uint8_t rx_data;
for (uint8_t ii = 0; ii < 3; ii++)
{
Adar_Write(p_adar, mem_addr, data, 0);
// Can't read back from an ADAR with HW address 0
if (!((p_adar->dev_addr) % 4))
{
return(ADAR_ERROR_INVALIDADDR);
}
rx_data = Adar_Read(p_adar, mem_addr);
if (rx_data == data)
{
return(ii);
}
}
return(ADAR_ERROR_FAILED);
}
void Adar_SetBit(const AdarDevice * p_adar, uint32_t mem_addr, uint8_t bit, uint8_t broadcast)
{
uint8_t temp = Adar_Read(p_adar, mem_addr);
uint8_t data = temp|(1<<bit);
Adar_Write(p_adar,mem_addr, data,broadcast);
}
void Adar_ResetBit(const AdarDevice * p_adar, uint32_t mem_addr, uint8_t bit, uint8_t broadcast)
{
uint8_t temp = Adar_Read(p_adar, mem_addr);
uint8_t data = temp&~(1<<bit);
Adar_Write(p_adar,mem_addr, data,broadcast);
}
@@ -0,0 +1,294 @@
/**
* MIT License
*
* Copyright (c) 2020 Jimmy Pentz
*
* Reach me at: github.com/jgpentz, jpentz1( at )gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sells
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* ADAR1000 4-Channel, X Band and Ku Band Beamformer */
#ifndef LIB_ADAR1000_H_
#define LIB_ADAR1000_H_
#ifndef NULL
#define NULL (0)
#endif
// ----------------------------------------------------------------------------
// Includes
// ----------------------------------------------------------------------------
#include "main.h"
#include "stm32f7xx_hal.h"
#include "stm32f7xx_hal_spi.h"
#include "stm32f7xx_hal_gpio.h"
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#ifdef __cplusplus
extern "C" { // Prevent C++ name mangling
#endif
// ----------------------------------------------------------------------------
// Datatypes
// ----------------------------------------------------------------------------
extern SPI_HandleTypeDef hspi1;
extern const uint8_t VM_GAIN[128];
extern const uint8_t VM_I[128];
extern const uint8_t VM_Q[128];
/// A function pointer prototype for a SPI transfer, the 3 parameters would be
/// p_txData, p_rxData, and size (number of bytes to transfer), respectively.
typedef uint32_t (*Adar_SpiTransfer)( uint8_t *, uint8_t *, uint32_t);
typedef struct
{
uint8_t dev_addr; ///< 2-bit device hardware address, 0x00, 0x01, 0x10, 0x11
Adar_SpiTransfer Transfer; ///< Function pointer to the function used for SPI transfers
uint8_t * p_rx_buffer; ///< Data buffer to store received bytes into
}const AdarDevice;
/// Use this to store bias current values into, as seen in the datasheet
/// Table 6. SPI Settings for Different Power Modules
typedef struct
{
uint8_t rx_lna; ///< nominal: 8, low power: 5
uint8_t rx_vm; ///< nominal: 5, low power: 2
uint8_t rx_vga; ///< nominal: 10, low power: 3
uint8_t tx_vm; ///< nominal: 5, low power: 2
uint8_t tx_vga; ///< nominal: 5, low power: 5
uint8_t tx_drv; ///< nominal: 6, low power: 3
} AdarBiasCurrents;
/// Useful for queries regarding the device info
typedef struct
{
uint8_t norm_operating_mode : 2;
uint8_t cust_operating_mode : 2;
uint8_t dev_status : 4;
uint8_t chip_type;
uint16_t product_id;
uint8_t scratchpad;
uint8_t spi_rev;
uint16_t vendor_id;
uint8_t rev_id;
} AdarDeviceInfo;
/// Return types for functions in this library
typedef enum {
ADAR_ERROR_NOERROR = 0,
ADAR_ERROR_FAILED = 1,
ADAR_ERROR_INVALIDADDR = 2,
} AdarErrorCodes;
// ----------------------------------------------------------------------------
// Function Prototypes
// ----------------------------------------------------------------------------
void Adar_AdcInit(const AdarDevice * p_adar, uint8_t broadcast_bit);
uint8_t Adar_AdcRead(const AdarDevice * p_adar, uint8_t broadcast_bit);
uint8_t Adar_GetDeviceInfo(const AdarDevice * p_adar, AdarDeviceInfo * info);
uint8_t Adar_Read(const AdarDevice * p_adar, uint32_t mem_addr);
void Adar_ReadBlock(const AdarDevice * p_adar, uint16_t mem_addr, uint8_t * p_data, uint32_t size);
uint8_t Adar_SetBiasCurrents(const AdarDevice * p_adar, AdarBiasCurrents * p_bias, uint8_t broadcast_bit);
uint8_t Adar_SetBiasVoltages(const AdarDevice * p_adar, uint8_t bias_on_voltage[5], uint8_t bias_off_voltage[5]);
uint8_t Adar_SetRamBypass(const AdarDevice * p_adar, uint8_t broadcast_bit);
uint8_t Adar_SetRxVgaGain(const AdarDevice * p_adar, uint8_t channel, uint8_t vga_gain_db, uint8_t broadcast_bit);
uint8_t Adar_SetRxPhase(const AdarDevice * p_adar, uint8_t channel, uint8_t phase, uint8_t broadcast_bit);
uint8_t Adar_SetTxBias(const AdarDevice * p_adar, uint8_t broadcast_bit);
uint8_t Adar_SetTxVgaGain(const AdarDevice * p_adar, uint8_t channel, uint8_t vga_gain_db, uint8_t broadcast_bit);
uint8_t Adar_SetTxPhase(const AdarDevice * p_adar, uint8_t channel, uint8_t phase, uint8_t broadcast_bit);
void Adar_SoftReset(const AdarDevice * p_adar);
void Adar_SoftResetAll(const AdarDevice * p_adar);
void Adar_Write(const AdarDevice * p_adar, uint32_t mem_addr, uint8_t data, uint8_t broadcast_bit);
void Adar_WriteBlock(const AdarDevice * p_adar, uint16_t mem_addr, uint8_t * p_data, uint32_t size);
void Adar_WriteConfigA(const AdarDevice * p_adar, uint8_t flags, uint8_t broadcast);
uint8_t Adar_WriteVerify(const AdarDevice * p_adar, uint32_t mem_addr, uint8_t data);
void Adar_SetBit(const AdarDevice * p_adar, uint32_t mem_addr, uint8_t bit, uint8_t broadcast);
void Adar_ResetBit(const AdarDevice * p_adar, uint32_t mem_addr, uint8_t bit, uint8_t broadcast);
// ----------------------------------------------------------------------------
// Preprocessor Definitions and Constants
// ----------------------------------------------------------------------------
// Using BROADCAST_ON will send a command to all ADARs that share a bus
#define BROADCAST_OFF 0
#define BROADCAST_ON 1
// The minimum size of a read from the ADARs consists of 3 bytes
#define ADAR1000_RD_SIZE 3
// Address at which the TX RAM starts
#define ADAR_TX_RAM_START_ADDR 0x1800
// ADC Defines
#define ADAR1000_ADC_2MHZ_CLK 0x00
#define ADAR1000_ADC_EN 0x60
#define ADAR1000_ADC_ST_CONV 0x70
/* REGISTER DEFINITIONS */
#define REG_INTERFACE_CONFIG_A 0x000
#define REG_INTERFACE_CONFIG_B 0x001
#define REG_DEV_CONFIG 0x002
#define REG_SCRATCHPAD 0x00A
#define REG_TRANSFER 0x00F
#define REG_CH1_RX_GAIN 0x010
#define REG_CH2_RX_GAIN 0x011
#define REG_CH3_RX_GAIN 0x012
#define REG_CH4_RX_GAIN 0x013
#define REG_CH1_RX_PHS_I 0x014
#define REG_CH1_RX_PHS_Q 0x015
#define REG_CH2_RX_PHS_I 0x016
#define REG_CH2_RX_PHS_Q 0x017
#define REG_CH3_RX_PHS_I 0x018
#define REG_CH3_RX_PHS_Q 0x019
#define REG_CH4_RX_PHS_I 0x01A
#define REG_CH4_RX_PHS_Q 0x01B
#define REG_CH1_TX_GAIN 0x01C
#define REG_CH2_TX_GAIN 0x01D
#define REG_CH3_TX_GAIN 0x01E
#define REG_CH4_TX_GAIN 0x01F
#define REG_CH1_TX_PHS_I 0x020
#define REG_CH1_TX_PHS_Q 0x021
#define REG_CH2_TX_PHS_I 0x022
#define REG_CH2_TX_PHS_Q 0x023
#define REG_CH3_TX_PHS_I 0x024
#define REG_CH3_TX_PHS_Q 0x025
#define REG_CH4_TX_PHS_I 0x026
#define REG_CH4_TX_PHS_Q 0x027
#define REG_LOAD_WORKING 0x028
#define REG_PA_CH1_BIAS_ON 0x029
#define REG_PA_CH2_BIAS_ON 0x02A
#define REG_PA_CH3_BIAS_ON 0x02B
#define REG_PA_CH4_BIAS_ON 0x02C
#define REG_LNA_BIAS_ON 0x02D
#define REG_RX_ENABLES 0x02E
#define REG_TX_ENABLES 0x02F
#define REG_MISC_ENABLES 0x030
#define REG_SW_CONTROL 0x031
#define REG_ADC_CONTROL 0x032
#define REG_ADC_CONTROL_TEMP_EN 0xf0
#define REG_ADC_OUT 0x033
#define REG_BIAS_CURRENT_RX_LNA 0x034
#define REG_BIAS_CURRENT_RX 0x035
#define REG_BIAS_CURRENT_TX 0x036
#define REG_BIAS_CURRENT_TX_DRV 0x037
#define REG_MEM_CTL 0x038
#define REG_RX_CHX_MEM 0x039
#define REG_TX_CHX_MEM 0x03A
#define REG_RX_CH1_MEM 0x03D
#define REG_RX_CH2_MEM 0x03E
#define REG_RX_CH3_MEM 0x03F
#define REG_RX_CH4_MEM 0x040
#define REG_TX_CH1_MEM 0x041
#define REG_TX_CH2_MEM 0x042
#define REG_TX_CH3_MEM 0x043
#define REG_TX_CH4_MEM 0x044
#define REG_PA_CH1_BIAS_OFF 0x046
#define REG_PA_CH2_BIAS_OFF 0x047
#define REG_PA_CH3_BIAS_OFF 0x048
#define REG_PA_CH4_BIAS_OFF 0x049
#define REG_LNA_BIAS_OFF 0x04A
#define REG_TX_BEAM_STEP_START 0x04D
#define REG_TX_BEAM_STEP_STOP 0x04E
#define REG_RX_BEAM_STEP_START 0x04F
#define REG_RX_BEAM_STEP_STOP 0x050
// REGISTER CONSTANTS
#define INTERFACE_CONFIG_A_SOFTRESET ((1 << 7) | (1 << 0))
#define INTERFACE_CONFIG_A_LSB_FIRST ((1 << 6) | (1 << 1))
#define INTERFACE_CONFIG_A_ADDR_ASCN ((1 << 5) | (1 << 2))
#define INTERFACE_CONFIG_A_SDO_ACTIVE ((1 << 4) | (1 << 3))
#define LD_WRK_REGS_LDRX_OVERRIDE (1 << 0)
#define LD_WRK_REGS_LDTX_OVERRIDE (1 << 1)
#define RX_ENABLES_TX_VGA_EN (1 << 0)
#define RX_ENABLES_TX_VM_EN (1 << 1)
#define RX_ENABLES_TX_DRV_EN (1 << 2)
#define RX_ENABLES_CH3_TX_EN (1 << 3)
#define RX_ENABLES_CH2_TX_EN (1 << 4)
#define RX_ENABLES_CH1_TX_EN (1 << 5)
#define RX_ENABLES_CH0_TX_EN (1 << 6)
#define TX_ENABLES_TX_VGA_EN (1 << 0)
#define TX_ENABLES_TX_VM_EN (1 << 1)
#define TX_ENABLES_TX_DRV_EN (1 << 2)
#define TX_ENABLES_CH3_TX_EN (1 << 3)
#define TX_ENABLES_CH2_TX_EN (1 << 4)
#define TX_ENABLES_CH1_TX_EN (1 << 5)
#define TX_ENABLES_CH0_TX_EN (1 << 6)
#define MISC_ENABLES_CH4_DET_EN (1 << 0)
#define MISC_ENABLES_CH3_DET_EN (1 << 1)
#define MISC_ENABLES_CH2_DET_EN (1 << 2)
#define MISC_ENABLES_CH1_DET_EN (1 << 3)
#define MISC_ENABLES_LNA_BIAS_OUT_EN (1 << 4)
#define MISC_ENABLES_BIAS_EN (1 << 5)
#define MISC_ENABLES_BIAS_CTRL (1 << 6)
#define MISC_ENABLES_SW_DRV_TR_MODE_SEL (1 << 7)
#define SW_CTRL_POL (1 << 0)
#define SW_CTRL_TR_SPI (1 << 1)
#define SW_CTRL_TR_SOURCE (1 << 2)
#define SW_CTRL_SW_DRV_EN_POL (1 << 3)
#define SW_CTRL_SW_DRV_EN_TR (1 << 4)
#define SW_CTRL_RX_EN (1 << 5)
#define SW_CTRL_TX_EN (1 << 6)
#define SW_CTRL_SW_DRV_TR_STATE (1 << 7)
#define MEM_CTRL_RX_CHX_RAM_BYPASS (1 << 0)
#define MEM_CTRL_TX_CHX_RAM_BYPASS (1 << 1)
#define MEM_CTRL_RX_BEAM_STEP_EN (1 << 2)
#define MEM_CTRL_TX_BEAM_STEP_EN (1 << 3)
#define MEM_CTRL_BIAS_RAM_BYPASS (1 << 5)
#define MEM_CTRL_BEAM_RAM_BYPASS (1 << 6)
#define MEM_CTRL_SCAN_MODE_EN (1 << 7)
#ifdef __cplusplus
} // End extern "C"
#endif
#endif /* LIB_ADAR1000_H_ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,809 @@
/***************************************************************************//**
* @file adf4382.h
* @brief Implementation of adf4382 Driver.
* @author Ciprian Hegbeli (ciprian.hegbeli@analog.com)
* @author Jude Osemene (jude.osemene@analog.com)
********************************************************************************
* Copyright 2024(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _ADF4382_H_
#define _ADF4382_H_
#include <stdint.h>
#include <string.h>
#include "no_os_units.h"
#include "no_os_util.h"
#include "no_os_spi.h"
/* ADF4382 REG0000 Map */
#define ADF4382_SOFT_RESET_R_MSK NO_OS_BIT(7)
#define ADF4382_LSB_FIRST_R_MSK NO_OS_BIT(6)
#define ADF4382_ADDRESS_ASC_R_MSK NO_OS_BIT(5)
#define ADF4382_SDO_ACTIVE_R_MSK NO_OS_BIT(4)
#define ADF4382_SDO_ACTIVE_MSK NO_OS_BIT(3)
#define ADF4382_ADDRESS_ASC_MSK NO_OS_BIT(2)
#define ADF4382_LSB_FIRST_MSK NO_OS_BIT(1)
#define ADF4382_SOFT_RESET_MSK NO_OS_BIT(0)
#define ADF4382_RESET_CMD 0x81
/* ADF4382 REG0000 NO_OS_BIT Definition */
#define ADF4382_SDO_ACTIVE_SPI_3W 0x0
#define ADF4382_SDO_ACTIVE_SPI_4W 0x1
#define ADF4382_ADDR_ASC_AUTO_DECR 0x0
#define ADF4382_ADDR_ASC_AUTO_INCR 0x1
#define ADF4382_LSB_FIRST_MSB 0x0
#define ADF4382_LSB_FIRST_LSB 0x1
#define ADF4382_SOFT_RESET_N_OP 0x0
#define ADF4382_SOFT_RESET_EN 0x1
/* ADF4382 REG0001 Map */
#define ADF4382_SINGLE_INSTR_MSK NO_OS_BIT(7)
#define ADF4382_MASTER_RB_CTRL_MSK NO_OS_BIT(5)
/* ADF4382 REG0001 NO_OS_BIT Definition */
#define ADF4382_SPI_STREAM_EN 0x0
#define ADF4382_SPI_STREAM_DIS 0x1
#define ADF4382_RB_SLAVE_REG 0x0
#define ADF4382_RB_MASTER_REG 0x1
/* ADF4382 REG0003 NO_OS_BIT Definition */
#define ADF4382_CHIP_TYPE 0x06
/* ADF4382 REG0004 NO_OS_BIT Definition */
#define ADF4382_PRODUCT_ID_LSB 0x0005
/* ADF4382 REG0005 NO_OS_BIT Definition */
#define ADF4382_PRODUCT_ID_MSB 0x0005
/* ADF4382 REG000A Map */
#define ADF4382_SCRATCHPAD_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG000C NO_OS_BIT Definition */
#define ADF4382_VENDOR_ID_LSB 0x56
/* ADF4382 REG000D NO_OS_BIT Definition */
#define ADF4382_VENDOR_ID_MSB 0x04
/* ADF4382 REG000F NO_OS_BIT Definition */
#define ADF4382_M_S_TRANSF_NO_OS_BIT_MSK NO_OS_BIT(0)
/* ADF4382 REG0010 Map*/
#define ADF4382_N_INT_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0011 Map*/
#define ADF4382_CLKOUT_DIV_MSK NO_OS_GENMASK(7, 5)
#define ADF4382_INV_CLK_OUT_MSK NO_OS_BIT(4)
#define ADF4382_N_INT_MSB_MSK NO_OS_GENMASK(3, 0)
/* ADF4382 REG0012 Map */
#define ADF4382_FRAC1WORD_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0013 Map */
#define ADF4382_FRAC1WORD_MID_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0014 Map */
#define ADF4382_FRAC1WORD_MSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0015 Map */
#define ADF4382_M_VCO_BAND_LSB_MSK NO_OS_BIT(7)
#define ADF4382_M_VCO_CORE_MSK NO_OS_BIT(6)
#define ADF4382_BIAS_DEC_MODE_MSK NO_OS_GENMASK(5, 3)
#define ADF4382_INT_MODE_MSK NO_OS_BIT(2)
#define ADF4382_PFD_POL_MSK NO_OS_BIT(1)
#define ADF4382_FRAC1WORD_MSB NO_OS_BIT(0)
/* ADF4382 REG0016 Map */
#define ADF4382_M_VCO_BAND_MSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0017 Map */
#define ADF4382_FRAC2WORD_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0018 Map */
#define ADF4382_FRAC2WORD_MID_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0019 Map */
#define ADF4382_FRAC2WORD_MSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG001A Map */
#define ADF4382_MOD2WORD_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG001B Map */
#define ADF4382_MOD2WORD_MID_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG001C Map */
#define ADF4382_MOD2WORD_MSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG001D Map */
#define ADF4382_FINE_BLEED_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG001E Map */
#define ADF4382_EN_PHASE_RESYNC_MSK NO_OS_BIT(7)
#define ADF4382_EN_REF_RST_MSK NO_OS_BIT(6)
#define ADF4382_TIMED_SYNC_MSK NO_OS_BIT(5)
#define ADF4382_COARSE_BLEED_MSK NO_OS_GENMASK(4, 1)
#define ADF4382_FINE_BLEED_MSB_MSK NO_OS_BIT(0)
/* ADF4382 REG001F Map */
#define ADF4382_SW_SYNC_MSK NO_OS_BIT(7)
#define ADF4382_SPARE_1F_MSK NO_OS_BIT(6)
#define ADF4382_BLEED_POL_MSK NO_OS_BIT(5)
#define ADF4382_EN_BLEED_MSK NO_OS_BIT(4)
#define ADF4382_CP_I_MSK NO_OS_GENMASK(3, 0)
/* ADF4382 REG0020 Map */
#define ADF4382_EN_AUTOCAL_MSK NO_OS_BIT(7)
#define ADF4382_EN_RDBLR_MSK NO_OS_BIT(6)
#define ADF4382_R_DIV_MSK NO_OS_GENMASK(5, 0)
/* ADF4382 REG0021 Map */
#define ADF4382_PHASE_WORD_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0022 Map */
#define ADF4382_PHASE_WORD_MID_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0023 Map */
#define ADF4382_PHASE_WORD_MSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0024 Map */
#define ADF4382_SPARE_24_MSK NO_OS_GENMASK(7, 5)
#define ADF4382_DCLK_DIV_SEL_MSK NO_OS_BIT(4)
#define ADF4382_DNCLK_DIV1_MSK NO_OS_GENMASK(3, 2)
#define ADF4382_DCLK_DIV1_MSK NO_OS_GENMASK(1, 0)
/* ADF4382 REG0025 Map */
#define ADF4382_RESYNC_WAIT_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0026 Map */
#define ADF4382_RESYNC_WAIT_MSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0027 Map */
#define ADF4382_CAL_BLEED_FINE_MIN_MSK NO_OS_GENMASK(7, 4)
#define ADF4382_BLEED_ADJ_SCALE_MSK NO_OS_GENMASK(3, 0)
/* ADF4382 REG0028 Map */
#define ADF4382_PH_RESYNC_RB_SEL_MSK NO_OS_BIT(7)
#define ADF4382_LSB_P1_MSK NO_OS_BIT(6)
#define ADF4382_VAR_MOD_EN_MSK NO_OS_BIT(5)
#define ADF4382_DITHER1_SCALE_MSK NO_OS_GENMASK(4, 2)
#define ADF4382_EN_DITHER2_MSK NO_OS_BIT(1)
#define ADF4382_EN_DITHER1_MSK NO_OS_BIT(0)
/* ADF4382 REG0029 Map */
#define ADF4382_CLK2_OPWR_MSK NO_OS_GENMASK(7, 4)
#define ADF4382_CLK1_OPWR_MSK NO_OS_GENMASK(3, 0)
/* ADF4382 REG002A Map */
#define ADF4382_FN_DBL_MSK NO_OS_BIT(7)
#define ADF4382_PD_NDIV_TL_MSK NO_OS_BIT(6)
#define ADF4382_CLKOUT_BST_MSK NO_OS_BIT(5)
#define ADF4382_PD_SYNC_MSK NO_OS_BIT(4)
#define ADF4382_PD_CLK_MSK NO_OS_BIT(3)
#define ADF4382_PD_RDET_MSK NO_OS_BIT(2)
#define ADF4382_PD_ADC_MSK NO_OS_BIT(1)
#define ADF4382_PD_CALGEN_MSK NO_OS_BIT(0)
/* ADF4382 REG002B Map */
#define ADF4382_PD_ALL_MSK NO_OS_BIT(7)
#define ADF4382_PD_RDIV_TL_MSK NO_OS_BIT(6)
#define ADF4382_PD_NDIV_MSK NO_OS_BIT(5)
#define ADF4382_PD_VCO_MSK NO_OS_BIT(4)
#define ADF4382_PD_LD_MSK NO_OS_BIT(3)
#define ADF4382_PD_PFDCP_MSK NO_OS_BIT(2)
#define ADF4382_PD_CLKOUT1_MSK NO_OS_BIT(1)
#define ADF4382_PD_CLKOUT2_MSK NO_OS_BIT(0)
/* ADF4382 REG002C Map */
#define ADF4382_LDWIN_PW_MSK NO_OS_GENMASK(7, 5)
#define ADF4382_LD_COUNT_OPWR_MSK NO_OS_GENMASK(4, 0)
/* ADF4382 REG002D Map */
#define ADF4382_EN_DNCLK_MSK NO_OS_BIT(7)
#define ADF4382_EN_DRCLK_MSK NO_OS_BIT(6)
#define ADF4382_EN_LOL_MSK NO_OS_BIT(5)
#define ADF4382_EN_LDWIN_MSK NO_OS_BIT(4)
#define ADF4382_PDET_POL_MSK NO_OS_BIT(3)
#define ADF4382_RST_LD_MSK NO_OS_BIT(2)
#define ADF4382_LD_O_CTRL_MSK NO_OS_GENMASK(1, 0)
/* ADF4382 REG002E Map */
#define ADF4382_MUXOUT_MSK NO_OS_GENMASK(7, 4)
#define ADF4382_ABPW_WD_MSK NO_OS_BIT(3)
#define ADF4382_EN_CPTEST_MSK NO_OS_BIT(2)
#define ADF4382_CP_DOWN_MSK NO_OS_BIT(1)
#define ADF4382_CP_UP_MSK NO_OS_BIT(0)
/* ADF4382 REG002F Map*/
#define ADF4382_BST_REF_MSK NO_OS_BIT(7)
#define ADF4382_FILT_REF_MSK NO_OS_BIT(6)
#define ADF4382_RDBLR_DC_MSK NO_OS_GENMASK(5, 0)
/* ADF4382 REG0030 Map */
#define ADF4382_MUTE_NCLK_MSK NO_OS_BIT(7)
#define ADF4382_MUTE_RCLK_MSK NO_OS_BIT(6)
#define ADF4382_REF_SEL_MSK NO_OS_BIT(5)
#define ADF4382_INV_RDBLR_MSK NO_OS_BIT(4)
#define ADF4382_RDBLR_DEL_SEL_MSK NO_OS_GENMASK(3, 0)
/* ADF4382 REG0031 Map */
#define ADF4382_SYNC_DEL_MSK NO_OS_GENMASK(7, 5)
#define ADF4382_RST_SYS_MSK NO_OS_BIT(4)
#define ADF4382_EN_ADC_CLK_MSK NO_OS_BIT(3)
#define ADF4382_EN_VCAL_MSK NO_OS_BIT(2)
#define ADF4382_CAL_CT_SEL_MSK NO_OS_BIT(1)
#define ADF4382_DCLK_MODE_MSK NO_OS_BIT(0)
/* ADF4382 REG0032 Map */
#define ADF4382_SPARE_32_MSK NO_OS_BIT(7)
#define ADF4382_BLEED_ADJ_CAL_MSK NO_OS_BIT(6)
#define ADF4382_DEL_MODE_MSK NO_OS_BIT(5)
#define ADF4382_EN_AUTO_ALIGN_MSK NO_OS_BIT(4)
#define ADF4382_PHASE_ADJ_POL_MSK NO_OS_BIT(3)
#define ADF4382_EFM3_MODE_MSK NO_OS_GENMASK(2, 0)
/* ADF4382 REG0033 Map */
#define ADF4382_PHASE_ADJUST_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0034 Map */
#define ADF4382_PHASE_ADJ_MSK NO_OS_BIT(7)
#define ADF4382_DRCLK_DEL_MSK NO_OS_GENMASK(6, 4)
#define ADF4382_DNCLK_DEL_MSK NO_OS_GENMASK(3, 1)
#define ADF4382_RST_CNTR_MSK NO_OS_BIT(0)
/* ADF4382 REG0035 Map */
#define ADF4382_SPARE_35_MSK NO_OS_GENMASK(7, 6)
#define ADF4382_M_VCO_BIAS_MSK NO_OS_GENMASK(5, 0)
/* ADF4382 REG0036 Map */
#define ADF4382_CLKODIV_DB_MSK NO_OS_BIT(7)
#define ADF4382_DCLK_DIV_DB_MSK NO_OS_BIT(6)
#define ADF4382_SPARE_36_MSK NO_OS_GENMASK(5, 2)
#define ADF4382_EN_LUT_GEN_MSK NO_OS_BIT(1)
#define ADF4382_EN_LUT_CAL_MSK NO_OS_BIT(0)
/* ADF4382 REG0037 Map */
#define ADF4382_CAL_COUNT_TO_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0038 Map */
#define ADF4382_CAL_VTUNE_TO_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0039 Map */
#define ADF4382_O_VCO_DB_MSK NO_OS_BIT(7)
#define ADF4382_CAL_VTUNE_TO_MSB_MSK NO_OS_GENMASK(6, 0)
/* ADF4382 REG003A Map */
#define ADF4382_CAL_VCO_TO_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG003B Map */
#define ADF4382_DEL_CTRL_DB_MSK NO_OS_BIT(7)
#define ADF4382_CAL_VCO_TO_MSB_MSK NO_OS_GENMASK(6, 0)
/* ADF4382 REG003C Map */
#define ADF4382_CNTR_DIV_WORD_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG003D Map */
#define ADF4382_SPARE_3D_MSK NO_OS_BIT(7)
#define ADF4382_SYNC_SP_DB_MSK NO_OS_BIT(6)
#define ADF4382_CMOS_OV_MSK NO_OS_BIT(5)
#define ADF4382_READ_MODE_MSK NO_OS_BIT(4)
#define ADF4382_CNTR_DIV_WORD_MSB_MSK NO_OS_GENMASK(3, 0)
/* ADF4382 REG003E Map */
#define ADF4382_ADC_CLK_DIV_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG003F Map */
#define ADF4382_EN_ADC_CNV_MSK NO_OS_BIT(7)
#define ADF4382_EN_ADC_VTEST_MSK NO_OS_BIT(6)
#define ADF4382_ADC_VTEST_SEL_MSK NO_OS_BIT(5)
#define ADF4382_ADC_MUX_SEL_MSK NO_OS_BIT(4)
#define ADF4382_ADC_F_CONV_MSK NO_OS_BIT(3)
#define ADF4382_ADC_C_CONV_MSK NO_OS_BIT(2)
#define ADF4382_EN_ADC_MSK NO_OS_BIT(1)
#define ADF4382_SPARE_3F_MSK NO_OS_BIT(0)
/* ADF4382 REG0040 Map */
#define ADF4382_EXT_DIV_DEC_SEL_MSK NO_OS_BIT(7)
#define ADF4382_ADC_CLK_TEST_SEL_MSK NO_OS_BIT(6)
#define ADF4382_MUTE_CLKOUT2_MSK NO_OS_GENMASK(5, 3)
#define ADF4382_MUTE_CLKOUT1_MSK NO_OS_GENMASK(2, 0)
/* ADF4382 REG0041 Map */
#define ADF4382_EXT_DIV_MSK NO_OS_GENMASK(7, 5)
#define ADF4382_EN_VCO_CAP_TEST_MSK NO_OS_BIT(4)
#define ADF4382_EN_CALGEN_CAP_TEST_MSK NO_OS_BIT(3)
#define ADF4382_EN_CP_CAP_TEST_MSK NO_OS_BIT(2)
#define ADF4382_CAP_TEST_STATE_MSK NO_OS_BIT(1)
#define ADF4382_TRANS_LOOP_SEL_MSK NO_OS_BIT(0)
/* ADF4382 REG0042 Map */
#define ADF4382_NDIV_PWRUP_TIMEOUT_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0043 Map */
#define ADF4382_CAL_BLEED_FINE_MAX_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0044 Map */
#define ADF4382_VCAL_ZERO_MSK NO_OS_BIT(7)
#define ADF4382_VPTAT_CALGEN_MSK NO_OS_GENMASK(6, 0)
/* ADF4382 REG0045 Map */
#define ADF4382_SPARE_45_MSK NO_OS_BIT(7)
#define ADF4382_VCTAT_CALGEN_MSK NO_OS_GENMASK(6, 0)
/* ADF4382 REG0046 Map */
#define ADF4382_NVMDIN_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0047 Map */
#define ADF4382_SPARE_47_MSK NO_OS_BIT(7)
#define ADF4382_NVMADDR_MSK NO_OS_GENMASK(6, 3)
#define ADF4382_NVMNO_OS_BIT_SEL NO_OS_GENMASK(2, 0)
/* ADF4382 REG0048 Map */
#define ADF4382_TRIM_LATCH_MSK NO_OS_BIT(7)
#define ADF4382_NVMTEST_MSK NO_OS_BIT(6)
#define ADF4382_NVMPROG_MSK NO_OS_BIT(5)
#define ADF4382_NVMRD_MSK NO_OS_BIT(4)
#define ADF4382_NVMSTART_MSK NO_OS_BIT(3)
#define ADF4382_NVMON_MSK NO_OS_BIT(2)
#define ADF4382_MARGIN_MSK NO_OS_GENMASK(1, 0)
/* ADF4382 REG0049 Map */
#define ADF4382_NVMDOUT_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG004A Map */
#define ADF4382_SCAN_MODE_CODE_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG004B Map */
#define ADF4382_TEMP_OFFSET_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG004C Map */
#define ADF4382_SPARE_4C_MSK NO_OS_GENMASK(7, 6)
#define ADF4382_TEMP_SLOPE_MSK NO_OS_GENMASK(5, 0)
/* ADF4382 REG004D Map */
#define ADF4382_VCO_FSM_TEST_MUX_MSK NO_OS_GENMASK(7, 5)
#define ADF4382_SPARE_4D_MSK NO_OS_GENMASK(4, 3)
#define ADF4382_O_VCO_BIAS_MSK NO_OS_BIT(2)
#define ADF4382_O_VCO_BAND_MSK NO_OS_BIT(1)
#define ADF4382_O_VCO_CORE_MSK NO_OS_BIT(0)
/* ADF4382 REG004E Map */
#define ADF4382_SPARE_4E_MSK NO_OS_GENMASK(7, 5)
#define ADF4382_EN_TWO_PASS_CAL_MSK NO_OS_BIT(4)
#define ADF4382_TWO_PASS_BAND_START_MSK NO_OS_GENMASK(3, 0)
/* ADF4382 REG004F Map */
#define ADF4382_LUT_SCALE_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0050 Map */
#define ADF4382_SPARE0_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0051 Map */
#define ADF4382_SPARE1_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0052 Map */
#define ADF4382_SYNC_REF_SPARE_MSK NO_OS_GENMASK(7, 4)
#define ADF4382_SYNC_MON_DEL_MSK NO_OS_GENMASK(3, 0)
/* ADF4382 REG0053 Map */
#define ADF4382_SPARE_53_MSK NO_OS_BIT(7)
#define ADF4382_PD_SYNC_MON_MSK NO_OS_BIT(6)
#define ADF4382_SYNC_SEL_MSK NO_OS_BIT(5)
#define ADF4382_RST_SYNC_MON_MSK NO_OS_BIT(4)
#define ADF4382_SYNC_SH_DEL_MSK NO_OS_GENMASK(3, 0)
/* ADF4382 REG0054 Map */
#define ADF4382_ADC_ST_CNV_MSK NO_OS_BIT(0)
/* ADF4382 REG0058 Map */
#define ADF4382_FSM_BUSY_MSK NO_OS_BIT(1)
#define ADF4382_LOCKED_MSK NO_OS_BIT(0)
/* ADF4382 REG005E Map */
#define ADF4382_VCO_BAND_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG005F Map */
#define ADF4382_VCO_CORE_MSK NO_OS_BIT(1)
#define ADF4382_VCO_BAND_MSB_MSK NO_OS_BIT(0)
/* ADF4382 REG0200 Map */
#define ADF4382_LUT_WR_ADDR_MSK NO_OS_GENMASK(5, 1)
#define ADF4382_O_VCO_LUT_MSK NO_OS_BIT(0)
/* ADF4382 REG0201 Map */
#define ADF4382_M_LUT_BAND_LSB_MSK NO_OS_GENMASK(7, 0)
/* ADF4382 REG0202 Map */
#define ADF4382_M_LUT_N_LSB_MSK NO_OS_GENMASK(7, 2)
#define ADF4382_M_LUT_CORE_MSK NO_OS_BIT(1)
#define ADF4382_M_LUT_BAND_MSB_MSK NO_OS_BIT(0)
/* ADF4382 REG0203 Map */
#define ADF4382_M_LUT_N_MSB_MSK NO_OS_GENMASK(5, 0)
#define ADF4382_SPI_3W_CFG(x) (no_os_field_prep(ADF4382_SDO_ACTIVE_MSK, x) | \
no_os_field_prep(ADF4382_SDO_ACTIVE_R_MSK, x))
#define ADF4382_BLEED_MSB_MSK (ADF4382_COARSE_BLEED_MSK | \
ADF4382_FINE_BLEED_MSB_MSK)
#define ADF4382_SPI_SCRATCHPAD_TEST 0x5A
/* Specifications */
#define ADF4382_SPI_WRITE_CMD 0x0
#define ADF4382_SPI_READ_CMD 0x8000
#define ADF4382_SPI_DUMMY_DATA 0x00
#define ADF4382_BUFF_SIZE_BYTES 3
#define ADF4382_VCO_FREQ_MIN 11000000000U // 11GHz
#define ADF4382_VCO_FREQ_MAX 22000000000U // 22GHz
#define ADF4383_VCO_FREQ_MIN 10000000000U // 10GHz
#define ADF4383_VCO_FREQ_MAX 20000000000U // 20GHz
#define ADF4382A_VCO_FREQ_MIN 11500000000U // 11.5GHz
#define ADF4382A_VCO_FREQ_MAX 21000000000U // 21GHz
#define ADF4382_MOD1WORD 0x2000000U // 2^25
#define ADF4382_MOD2WORD_MAX 0xFFFFFFU // 2^24 - 1
#define ADF4382_PHASE_RESYNC_MOD2WORD_MAX 0x1FFFFU // 2^17 - 1
#define ADF4382_CHANNEL_SPACING_MAX 78125U
#define ADF4382_PFD_FREQ_MAX 625000000U // 625MHz
#define ADF4382_PFD_FREQ_FRAC_MAX 250000000U // 250MHz
#define ADF4382_PFD_FREQ_MIN 5400000U // 5.4MHz
#define ADF4382_DCLK_DIV1_0_MAX 160000000U // 160MHz
#define ADF4382_DCLK_DIV1_1_MAX 320000000U // 320MHz
#define ADF4382_CLKOUT_DIV_REG_VAL_MAX 4
#define ADF4382A_CLKOUT_DIV_REG_VAL_MAX 2
#define ADF4383_RFOUT_MAX 20000000000U
#define ADF4383_RFOUT_MIN 625000000U
#define ADF4382_RFOUT_MAX 22000000000U
#define ADF4382_RFOUT_MIN 687500000U
#define ADF4382A_RFOUT_MAX 21000000000U
#define ADF4382A_RFOUT_MIN 2875000000U
#define ADF4382_REF_CLK_MAX 5000000000U
#define ADF4382_REF_CLK_MIN 10000000
#define ADF4382_REF_DIV_MAX 63
#define ADF4382_OUT_PWR_MAX 15
#define ADF4382_CPI_VAL_MAX 15
#define ADF4382_BLEED_WORD_MAX 8191
#define ADF4382_VPTAT_CALGEN 46
#define ADF4382_VCTAT_CALGEN 82
#define ADF4382_FASTCAL_VPTAT_CALGEN 7
#define ADF4382_FASTCAL_VCTAT_CALGEN 21
#define ADF4382_PHASE_BLEED_CNST 2044000
#define ADF4382_VCO_CAL_CNT 183
#define ADF4382_VCO_CAL_VTUNE 640
#define ADF4382_VCO_CAL_ALC 123
#define ADF4382_POR_DELAY_US 200
#define ADF4382_LKD_DELAY_US 1000
#define ADF4382_COARSE_BLEED_CONST 180U // 180 microseconds
#define ADF4382_FINE_BLEED_CONST_1 512U // 512 microseconds
#define ADF4382_FINE_BLEED_CONST_2 250U // 250 microseconds
#define ADF4382_CAL_VTUNE_TO 124U
#define ADF4382_FSM_BUSY_LOOP_CNT 100U
#define MHZ MEGA
#define S_TO_NS NANO
#define PS_TO_S PICO
#define NS_TO_PS KHZ_PER_MHZ
/**
* @brief Supported device ids.
*/
enum adf4382_dev_id {
ID_ADF4382,
ID_ADF4382A,
ID_ADF4383,
};
/**
* @struct adf4382_init_param
* @brief ADF4382 Initialization Parameters structure.
*/
struct adf4382_init_param {
/** SPI Initialization parameters */
struct no_os_spi_init_param *spi_init;
bool spi_3wire_en;
bool cmos_3v3;
uint64_t ref_freq_hz;
uint64_t freq;
bool ref_doubler_en;
uint8_t ref_div;
uint8_t cp_i;
uint16_t bleed_word;
uint8_t ld_count;
uint8_t en_lut_gen;
uint8_t en_lut_cal;
uint8_t max_lpf_cap_value_uf;
enum adf4382_dev_id id;
};
/**
* @struct adf4382_dev
* @brief ADF4382 Device Descriptor.
*/
struct adf4382_dev {
/** SPI Descriptor */
struct no_os_spi_desc *spi_desc;
bool spi_3wire_en;
bool cmos_3v3;
uint64_t ref_freq_hz;
uint64_t freq;
bool ref_doubler_en;
uint8_t ref_div;
uint8_t cp_i;
uint16_t bleed_word;
uint8_t ld_count;
uint32_t phase_adj;
uint8_t en_lut_gen;
uint8_t en_lut_cal;
uint64_t vco_max;
uint64_t vco_min;
uint64_t freq_max;
uint64_t freq_min;
uint8_t clkout_div_reg_val_max;
uint8_t max_lpf_cap_value_uf;
uint32_t cal_vtune_to;
// N_INT variable to trigger auto calibration
uint16_t n_int;
};
/**
* @struct reg_sequence
* @brief ADF4382 register format structure for default values
*/
struct reg_sequence {
uint16_t reg;
uint8_t val;
};
/**
* @struct adf4382_reg_defaults
* @brief ADF4382 register initialization
*/
static const struct reg_sequence adf4382_reg_defaults[] = {
{ 0x000, 0x18 },
{ 0x00a, 0xA5 },
{ 0x200, 0x00 },
{ 0x201, 0x00 },
{ 0x202, 0x00 },
{ 0x203, 0x00 },
{ 0x203, 0x00 },
{ 0x203, 0x00 },
{ 0x100, 0x25 },
{ 0x101, 0x3F },
{ 0x102, 0x3F },
{ 0x103, 0x3F },
{ 0x104, 0x3F },
{ 0x105, 0x3F },
{ 0x106, 0x3F },
{ 0x107, 0x3F },
{ 0x108, 0x3F },
{ 0x109, 0x25 },
{ 0x10A, 0x25 },
{ 0x10B, 0x3F },
{ 0x10C, 0x3F },
{ 0x10D, 0x3F },
{ 0x10E, 0x3F },
{ 0x10F, 0x3F },
{ 0x110, 0x3F },
{ 0x111, 0x3F },
{ 0x054, 0x00 },
{ 0x053, 0x45 },
{ 0x052, 0x00 },
{ 0x051, 0x00 },
{ 0x050, 0x00 },
{ 0x04f, 0x08 },
{ 0x04e, 0x06 },
{ 0x04d, 0x00 },
{ 0x04c, 0x2B },
{ 0x04b, 0x5D },
{ 0x04a, 0x00 },
{ 0x048, 0x00 },
{ 0x047, 0x00 },
{ 0x046, 0x00 },
{ 0x045, 0x52 },
{ 0x044, 0x2E },
{ 0x043, 0xB8 },
{ 0x042, 0x01 },
{ 0x041, 0x00 },
{ 0x040, 0x00 },
{ 0x03f, 0x82 },
{ 0x03e, 0x4E },
{ 0x03d, 0x00 },
{ 0x03c, 0x00 },
{ 0x03b, 0x00 },
{ 0x03a, 0xFA },
{ 0x039, 0x00 },
{ 0x038, 0x7C },
{ 0x037, 0xCA },
{ 0x036, 0xC0 },
{ 0x035, 0x00 },
{ 0x034, 0x36 },
{ 0x033, 0x00 },
{ 0x032, 0x40 },
{ 0x031, 0x63 },
{ 0x030, 0x0F },
{ 0x02f, 0x3F },
{ 0x02e, 0x00 },
{ 0x02d, 0xF1 },
{ 0x02c, 0x0E },
{ 0x02b, 0x01 },
{ 0x02a, 0x30 },
{ 0x029, 0x09 },
{ 0x028, 0x00 },
{ 0x027, 0xF0 },
{ 0x026, 0x00 },
{ 0x025, 0x01 },
{ 0x024, 0x01 },
{ 0x023, 0x00 },
{ 0x022, 0x00 },
{ 0x021, 0x00 },
{ 0x020, 0xC1 },
{ 0x01f, 0x0F },
{ 0x01e, 0x20 },
{ 0x01d, 0x00 },
{ 0x01c, 0x00 },
{ 0x01b, 0x00 },
{ 0x01a, 0x00 },
{ 0x019, 0x00 },
{ 0x018, 0x00 },
{ 0x017, 0x00 },
{ 0x016, 0x00 },
{ 0x015, 0x06 },
{ 0x014, 0x00 },
{ 0x013, 0x00 },
{ 0x012, 0x00 },
{ 0x011, 0x00 },
{ 0x010, 0x50 },
};
/** ADF4382 SPI write */
int adf4382_spi_write(struct adf4382_dev *dev, uint16_t reg_addr, uint8_t data);
/** ADF4382 SPI Read */
int adf4382_spi_read(struct adf4382_dev *dev, uint16_t reg_addr, uint8_t *data);
/** ADF4382 updates a bit in the register space over SPI */
int adf4382_spi_update_bits(struct adf4382_dev *dev, uint16_t reg_addr,
uint8_t mask, uint8_t data);
/** ADF4382 Register dump */
int adf4382_reg_dump(struct adf4382_dev *dev);
/** ADF4382 Set reference frequency attribute */
int adf4382_set_ref_clk(struct adf4382_dev *dev, uint64_t val);
/** ADF4382 Get reference frequency attribute */
int adf4382_get_ref_clk(struct adf4382_dev *dev, uint64_t *val);
/** ADF4382 Set reference doubler attribute */
int adf4382_set_en_ref_doubler(struct adf4382_dev *dev, bool en);
/** ADF4382 Get reference doubler attribute */
int adf4382_get_en_ref_doubler(struct adf4382_dev *dev, bool *en);
/** ADF4382 Set reference divider attribute */
int adf4382_set_ref_div(struct adf4382_dev *dev, int32_t div);
/** ADF4382 Get reference divider attribute */
int adf4382_get_ref_div(struct adf4382_dev *dev, int32_t *div);
/** ADF4382 Set charge pump current attribute */
int adf4382_set_cp_i(struct adf4382_dev *dev, int32_t reg_val);
/** ADF4382 Get charge pump current attribute */
int adf4382_get_cp_i(struct adf4382_dev *dev, int32_t *reg_val);
/** ADF4382 Set bleed current attribute */
int adf4382_set_bleed_word(struct adf4382_dev *dev, int32_t word);
/** ADF4382 Get bleed current attribute */
int adf4382_get_bleed_word(struct adf4382_dev *dev, int32_t *word);
/** ADF4382 Set output frequency attribute */
int adf4382_set_rfout(struct adf4382_dev *dev, uint64_t val);
/** ADF4382 Get output frequency attribute */
int adf4382_get_rfout(struct adf4382_dev *dev, uint64_t *val);
/** ADF4382 Set output power attributes */
int adf4382_set_out_power(struct adf4382_dev *dev, uint8_t ch, int32_t pwr);
/** ADF4382 Get output power attributes */
int adf4382_get_out_power(struct adf4382_dev *dev, uint8_t ch, int32_t *pwr);
/** ADF4382 Set channel enable attributes */
int adf4382_set_en_chan(struct adf4382_dev *dev, uint8_t ch, bool en);
/** ADF4382 Get channel enable attributes */
int adf4382_get_en_chan(struct adf4382_dev *dev, uint8_t ch, bool *en);
/** ADF4382 Sets frequency */
int adf4382_set_freq(struct adf4382_dev *dev);
/** ADF4382 Set fast calibration attributes */
int adf4382_set_en_fast_calibration(struct adf4382_dev *dev, bool en_fast_cal);
/** ADF4382 Set fast calibration LUT calibration attributes */
int adf4382_set_en_lut_calibration(struct adf4382_dev *dev, bool en_lut_cal);
/** ADF4382 Get Fast Calibration LUT Calibration attributes */
int adf4382_get_en_lut_calibration(struct adf4382_dev *dev, bool *en);
/** ADF4382 Set Output Frequency without writing the Ndiv Register */
int adf4382_set_change_freq(struct adf4382_dev *dev);
/** ADF4382 Get Change Output Frequency attribute value */
int adf4382_get_change_rfout(struct adf4382_dev *dev, uint64_t *val);
/** ADF4382 Set Change Output Frequency attribute value */
int adf4382_set_change_rfout(struct adf4382_dev *dev, uint64_t val);
/** ADF4382 Set the NDIV register attribute value */
int adf4382_set_start_calibration(struct adf4382_dev *dev);
/** ADF4382 Get the NDIV register attribute value as 0 */
int adf4382_get_start_calibration(struct adf4382_dev *dev, bool *start_cal);
/** ADF4382 Sets Phase adjustment */
int adf4382_set_phase_adjust(struct adf4382_dev *dev, uint32_t phase_ps);
/** ADF4382 Sets Phase adjustment polarity*/
int adf4382_set_phase_pol(struct adf4382_dev *dev, bool polarity);
/** ADF4382 Gets Phase adjustment polarity*/
int adf4382_get_phase_pol(struct adf4382_dev *dev, bool *polarity);
/** ADF4382 Set EZSYNC feature attributes */
int adf4382_set_ezsync_setup(struct adf4382_dev *dev, bool sync);
/** ADF4382 Set Timed SYNC feature attributes */
int adf4382_set_timed_sync_setup(struct adf4382_dev *dev, bool sync);
/** ADF4382 Get EZSYNC and Timed SYNC feature attributes */
int adf4382_get_phase_sync_setup(struct adf4382_dev *dev, bool *en);
/** ADF4382 Set sw_sync attribute */
int adf4382_set_sw_sync(struct adf4382_dev *dev, bool sw_sync);
/** ADF4382 Get sw_sync attribute */
int adf4382_get_sw_sync(struct adf4382_dev *dev, bool *sw_sync);
/** ADF4382 Set VCO calibration settings attributes */
int adf4382_set_vco_cal_timeout(struct adf4382_dev *dev);
/** ADF4382 Initialization */
int adf4382_init(struct adf4382_dev **device,
struct adf4382_init_param *init_param);
/** ADF4382 Remove */
int adf4382_remove(struct adf4382_dev *dev);
#endif
@@ -0,0 +1,510 @@
#include "adf4382a_manager.h"
#include "no_os_delay.h"
#include <stdio.h>
#include <string.h>
// External SPI handle
extern SPI_HandleTypeDef hspi4;
// Static function prototypes
static void set_chip_enable(uint8_t ce_pin, bool state);
static void set_deladj_pin(uint8_t device, bool state);
static void set_delstr_pin(uint8_t device, bool state);
static uint16_t phase_ps_to_duty_cycle(uint16_t phase_ps);
int ADF4382A_Manager_Init(ADF4382A_Manager *manager, SyncMethod method)
{
struct adf4382_init_param tx_param, rx_param;
int ret;
if (!manager) {
return ADF4382A_MANAGER_ERROR_INVALID;
}
// Initialize manager structure
manager->tx_dev = NULL;
manager->rx_dev = NULL;
manager->initialized = false;
manager->sync_method = method;
manager->tx_phase_shift_ps = 0;
manager->rx_phase_shift_ps = 0;
// Initialize SPI parameters in manager
memset(&manager->spi_tx_param, 0, sizeof(manager->spi_tx_param));
memset(&manager->spi_rx_param, 0, sizeof(manager->spi_rx_param));
// Setup TX SPI parameters for SPI4
manager->spi_tx_param.device_id = ADF4382A_SPI_DEVICE_ID;
manager->spi_tx_param.max_speed_hz = ADF4382A_SPI_SPEED_HZ;
manager->spi_tx_param.mode = NO_OS_SPI_MODE_0;
manager->spi_tx_param.chip_select = TX_CS_Pin;
manager->spi_tx_param.bit_order = NO_OS_SPI_BIT_ORDER_MSB_FIRST;
manager->spi_tx_param.platform_ops = NULL;
manager->spi_tx_param.extra = &hspi4;
// Setup RX SPI parameters for SPI4
manager->spi_rx_param.device_id = ADF4382A_SPI_DEVICE_ID;
manager->spi_rx_param.max_speed_hz = ADF4382A_SPI_SPEED_HZ;
manager->spi_rx_param.mode = NO_OS_SPI_MODE_0;
manager->spi_rx_param.chip_select = RX_CS_Pin;
manager->spi_rx_param.bit_order = NO_OS_SPI_BIT_ORDER_MSB_FIRST;
manager->spi_rx_param.platform_ops = NULL;
manager->spi_rx_param.extra = &hspi4;
// Configure TX parameters (10.5 GHz)
memset(&tx_param, 0, sizeof(tx_param));
tx_param.spi_3wire_en = 0;
tx_param.cmos_3v3 = 1;
tx_param.ref_freq_hz = REF_FREQ_HZ;
tx_param.ref_div = 1;
tx_param.ref_doubler_en = false;
tx_param.freq = TX_FREQ_HZ;
tx_param.id = ID_ADF4382A;
tx_param.cp_i = 3;
tx_param.bleed_word = 1000;
tx_param.ld_count = 0x07;
tx_param.spi_init = &manager->spi_tx_param;
// Configure RX parameters (10.38 GHz)
memset(&rx_param, 0, sizeof(rx_param));
rx_param.spi_3wire_en = 0;
rx_param.cmos_3v3 = 1;
rx_param.ref_freq_hz = REF_FREQ_HZ;
rx_param.ref_div = 1;
rx_param.ref_doubler_en = false;
rx_param.freq = RX_FREQ_HZ;
rx_param.id = ID_ADF4382A;
rx_param.cp_i = 4;
rx_param.bleed_word = 1200;
rx_param.ld_count = 0x07;
rx_param.spi_init = &manager->spi_rx_param;
// Enable chips
set_chip_enable(TX_CE_Pin, true);
set_chip_enable(RX_CE_Pin, true);
no_os_udelay(1000);
// Initialize DELADJ and DELSTR pins
set_deladj_pin(0, false); // TX device
set_deladj_pin(1, false); // RX device
set_delstr_pin(0, false); // TX device
set_delstr_pin(1, false); // RX device
// Initialize TX device first
printf("Initializing TX ADF4382A (10.5 GHz) on SPI4...\n");
ret = adf4382_init(&manager->tx_dev, &tx_param);
if (ret) {
printf("TX ADF4382A initialization failed: %d\n", ret);
set_chip_enable(TX_CE_Pin, false);
set_chip_enable(RX_CE_Pin, false);
return ADF4382A_MANAGER_ERROR_SPI;
}
// Small delay between initializations
no_os_udelay(5000);
// Initialize RX device
printf("Initializing RX ADF4382A (10.38 GHz) on SPI4...\n");
ret = adf4382_init(&manager->rx_dev, &rx_param);
if (ret) {
printf("RX ADF4382A initialization failed: %d\n", ret);
adf4382_remove(manager->tx_dev);
set_chip_enable(TX_CE_Pin, false);
set_chip_enable(RX_CE_Pin, false);
return ADF4382A_MANAGER_ERROR_SPI;
}
// Set output power
adf4382_set_out_power(manager->tx_dev, 0, 12);
adf4382_set_out_power(manager->tx_dev, 1, 12);
adf4382_set_out_power(manager->rx_dev, 0, 12);
adf4382_set_out_power(manager->rx_dev, 1, 12);
// Enable outputs
adf4382_set_en_chan(manager->tx_dev, 0, true);
adf4382_set_en_chan(manager->tx_dev, 1, false);
adf4382_set_en_chan(manager->rx_dev, 0, true);
adf4382_set_en_chan(manager->rx_dev, 1, false);
// Setup synchronization based on selected method
if (method == SYNC_METHOD_TIMED) {
ret = ADF4382A_SetupTimedSync(manager);
if (ret) {
printf("Timed sync setup failed: %d\n", ret);
}
} else {
ret = ADF4382A_SetupEZSync(manager);
if (ret) {
printf("EZSync setup failed: %d\n", ret);
}
}
manager->initialized = true;
printf("ADF4382A Manager initialized with %s synchronization on SPI4\n",
(method == SYNC_METHOD_TIMED) ? "TIMED" : "EZSYNC");
return ADF4382A_MANAGER_OK;
}
int ADF4382A_SetupTimedSync(ADF4382A_Manager *manager)
{
int ret;
if (!manager || !manager->initialized) {
return ADF4382A_MANAGER_ERROR_NOT_INIT;
}
printf("Setting up Timed Synchronization (60 MHz SYNCP/SYNCN)...\n");
// Setup TX for timed sync
ret = adf4382_set_timed_sync_setup(manager->tx_dev, true);
if (ret) {
printf("TX timed sync setup failed: %d\n", ret);
return ret;
}
// Setup RX for timed sync
ret = adf4382_set_timed_sync_setup(manager->rx_dev, true);
if (ret) {
printf("RX timed sync setup failed: %d\n", ret);
return ret;
}
manager->sync_method = SYNC_METHOD_TIMED;
printf("Timed synchronization configured for 60 MHz SYNCP/SYNCN\n");
return ADF4382A_MANAGER_OK;
}
int ADF4382A_SetupEZSync(ADF4382A_Manager *manager)
{
int ret;
if (!manager || !manager->initialized) {
return ADF4382A_MANAGER_ERROR_NOT_INIT;
}
printf("Setting up EZSync (SPI-based synchronization)...\n");
// Setup TX for EZSync
ret = adf4382_set_ezsync_setup(manager->tx_dev, true);
if (ret) {
printf("TX EZSync setup failed: %d\n", ret);
return ret;
}
// Setup RX for EZSync
ret = adf4382_set_ezsync_setup(manager->rx_dev, true);
if (ret) {
printf("RX EZSync setup failed: %d\n", ret);
return ret;
}
manager->sync_method = SYNC_METHOD_EZSYNC;
printf("EZSync configured\n");
return ADF4382A_MANAGER_OK;
}
int ADF4382A_TriggerTimedSync(ADF4382A_Manager *manager)
{
if (!manager || !manager->initialized || manager->sync_method != SYNC_METHOD_TIMED) {
return ADF4382A_MANAGER_ERROR_NOT_INIT;
}
printf("Timed sync ready - SYNC pin will trigger synchronization\n");
printf("Ensure 60 MHz phase-aligned clocks are present on SYNCP/SYNCN pins\n");
return ADF4382A_MANAGER_OK;
}
int ADF4382A_TriggerEZSync(ADF4382A_Manager *manager)
{
int ret;
if (!manager || !manager->initialized || manager->sync_method != SYNC_METHOD_EZSYNC) {
return ADF4382A_MANAGER_ERROR_NOT_INIT;
}
// Trigger software sync on both devices
ret = adf4382_set_sw_sync(manager->tx_dev, true);
if (ret) {
printf("TX software sync failed: %d\n", ret);
return ADF4382A_MANAGER_ERROR_SPI;
}
ret = adf4382_set_sw_sync(manager->rx_dev, true);
if (ret) {
printf("RX software sync failed: %d\n", ret);
return ADF4382A_MANAGER_ERROR_SPI;
}
// Small delay for sync to take effect
no_os_udelay(10);
// Clear software sync
ret = adf4382_set_sw_sync(manager->tx_dev, false);
if (ret) {
printf("TX sync clear failed: %d\n", ret);
return ADF4382A_MANAGER_ERROR_SPI;
}
ret = adf4382_set_sw_sync(manager->rx_dev, false);
if (ret) {
printf("RX sync clear failed: %d\n", ret);
return ADF4382A_MANAGER_ERROR_SPI;
}
printf("EZSync triggered via SPI\n");
return ADF4382A_MANAGER_OK;
}
int ADF4382A_Manager_Deinit(ADF4382A_Manager *manager)
{
if (!manager || !manager->initialized) {
return ADF4382A_MANAGER_ERROR_NOT_INIT;
}
// Disable outputs first
if (manager->tx_dev) {
adf4382_set_en_chan(manager->tx_dev, 0, false);
adf4382_set_en_chan(manager->tx_dev, 1, false);
}
if (manager->rx_dev) {
adf4382_set_en_chan(manager->rx_dev, 0, false);
adf4382_set_en_chan(manager->rx_dev, 1, false);
}
// Remove devices
if (manager->tx_dev) {
adf4382_remove(manager->tx_dev);
manager->tx_dev = NULL;
}
if (manager->rx_dev) {
adf4382_remove(manager->rx_dev);
manager->rx_dev = NULL;
}
// Disable chips and phase control pins
set_chip_enable(TX_CE_Pin, false);
set_chip_enable(RX_CE_Pin, false);
set_deladj_pin(0, false);
set_deladj_pin(1, false);
set_delstr_pin(0, false);
set_delstr_pin(1, false);
manager->initialized = false;
printf("ADF4382A Manager deinitialized\n");
return ADF4382A_MANAGER_OK;
}
int ADF4382A_CheckLockStatus(ADF4382A_Manager *manager, bool *tx_locked, bool *rx_locked)
{
uint8_t tx_status, rx_status;
int ret;
if (!manager || !manager->initialized || !tx_locked || !rx_locked) {
return ADF4382A_MANAGER_ERROR_NOT_INIT;
}
// Read lock status from registers
ret = adf4382_spi_read(manager->tx_dev, 0x58, &tx_status);
if (ret) {
printf("TX lock status read failed: %d\n", ret);
return ADF4382A_MANAGER_ERROR_SPI;
}
ret = adf4382_spi_read(manager->rx_dev, 0x58, &rx_status);
if (ret) {
printf("RX lock status read failed: %d\n", ret);
return ADF4382A_MANAGER_ERROR_SPI;
}
*tx_locked = (tx_status & ADF4382_LOCKED_MSK) != 0;
*rx_locked = (rx_status & ADF4382_LOCKED_MSK) != 0;
// Also check GPIO lock detect pins as backup
bool tx_gpio_locked = HAL_GPIO_ReadPin(TX_LKDET_GPIO_Port, TX_LKDET_Pin) == GPIO_PIN_SET;
bool rx_gpio_locked = HAL_GPIO_ReadPin(RX_LKDET_GPIO_Port, RX_LKDET_Pin) == GPIO_PIN_SET;
// Use both register and GPIO status
*tx_locked = *tx_locked && tx_gpio_locked;
*rx_locked = *rx_locked && rx_gpio_locked;
return ADF4382A_MANAGER_OK;
}
int ADF4382A_SetOutputPower(ADF4382A_Manager *manager, uint8_t tx_power, uint8_t rx_power)
{
int ret;
if (!manager || !manager->initialized) {
return ADF4382A_MANAGER_ERROR_NOT_INIT;
}
// Clamp power values (0-15)
tx_power = (tx_power > 15) ? 15 : tx_power;
rx_power = (rx_power > 15) ? 15 : rx_power;
// Set TX power for both channels
ret = adf4382_set_out_power(manager->tx_dev, 0, tx_power);
if (ret) return ret;
ret = adf4382_set_out_power(manager->tx_dev, 1, tx_power);
if (ret) return ret;
// Set RX power for both channels
ret = adf4382_set_out_power(manager->rx_dev, 0, rx_power);
if (ret) return ret;
ret = adf4382_set_out_power(manager->rx_dev, 1, rx_power);
printf("Output power set: TX=%d, RX=%d\n", tx_power, rx_power);
return ADF4382A_MANAGER_OK;
}
int ADF4382A_EnableOutputs(ADF4382A_Manager *manager, bool tx_enable, bool rx_enable)
{
int ret;
if (!manager || !manager->initialized) {
return ADF4382A_MANAGER_ERROR_NOT_INIT;
}
// Enable/disable TX outputs
ret = adf4382_set_en_chan(manager->tx_dev, 0, tx_enable);
if (ret) return ret;
ret = adf4382_set_en_chan(manager->tx_dev, 1, tx_enable);
if (ret) return ret;
// Enable/disable RX outputs
ret = adf4382_set_en_chan(manager->rx_dev, 0, rx_enable);
if (ret) return ret;
ret = adf4382_set_en_chan(manager->rx_dev, 1, rx_enable);
printf("Outputs: TX=%s, RX=%s\n",
tx_enable ? "ENABLED" : "DISABLED",
rx_enable ? "ENABLED" : "DISABLED");
return ADF4382A_MANAGER_OK;
}
// New phase delay functions
int ADF4382A_SetPhaseShift(ADF4382A_Manager *manager, uint16_t tx_phase_ps, uint16_t rx_phase_ps)
{
if (!manager || !manager->initialized) {
return ADF4382A_MANAGER_ERROR_NOT_INIT;
}
// Clamp phase shift values
tx_phase_ps = (tx_phase_ps > PHASE_SHIFT_MAX_PS) ? PHASE_SHIFT_MAX_PS : tx_phase_ps;
rx_phase_ps = (rx_phase_ps > PHASE_SHIFT_MAX_PS) ? PHASE_SHIFT_MAX_PS : rx_phase_ps;
// Convert phase shift to duty cycle and apply
if (tx_phase_ps != manager->tx_phase_shift_ps) {
uint16_t duty_cycle = phase_ps_to_duty_cycle(tx_phase_ps);
ADF4382A_SetFinePhaseShift(manager, 0, duty_cycle); // 0 = TX device
manager->tx_phase_shift_ps = tx_phase_ps;
}
if (rx_phase_ps != manager->rx_phase_shift_ps) {
uint16_t duty_cycle = phase_ps_to_duty_cycle(rx_phase_ps);
ADF4382A_SetFinePhaseShift(manager, 1, duty_cycle); // 1 = RX device
manager->rx_phase_shift_ps = rx_phase_ps;
}
printf("Phase shift set: TX=%d ps, RX=%d ps\n", tx_phase_ps, rx_phase_ps);
return ADF4382A_MANAGER_OK;
}
int ADF4382A_GetPhaseShift(ADF4382A_Manager *manager, uint16_t *tx_phase_ps, uint16_t *rx_phase_ps)
{
if (!manager || !manager->initialized || !tx_phase_ps || !rx_phase_ps) {
return ADF4382A_MANAGER_ERROR_NOT_INIT;
}
*tx_phase_ps = manager->tx_phase_shift_ps;
*rx_phase_ps = manager->rx_phase_shift_ps;
return ADF4382A_MANAGER_OK;
}
int ADF4382A_SetFinePhaseShift(ADF4382A_Manager *manager, uint8_t device, uint16_t duty_cycle)
{
if (!manager || !manager->initialized) {
return ADF4382A_MANAGER_ERROR_NOT_INIT;
}
// Clamp duty cycle
duty_cycle = (duty_cycle > DELADJ_MAX_DUTY_CYCLE) ? DELADJ_MAX_DUTY_CYCLE : duty_cycle;
// For simplicity, we'll use a basic implementation
// In a real system, you would generate a PWM signal on DELADJ pin
// Here we just set the pin state based on a simplified approach
if (duty_cycle == 0) {
set_deladj_pin(device, false);
} else if (duty_cycle >= DELADJ_MAX_DUTY_CYCLE) {
set_deladj_pin(device, true);
} else {
// For intermediate values, you would need PWM generation
// This is a simplified implementation
set_deladj_pin(device, true);
}
printf("Device %d DELADJ duty cycle set to %d/%d\n",
device, duty_cycle, DELADJ_MAX_DUTY_CYCLE);
return ADF4382A_MANAGER_OK;
}
int ADF4382A_StrobePhaseShift(ADF4382A_Manager *manager, uint8_t device)
{
if (!manager || !manager->initialized) {
return ADF4382A_MANAGER_ERROR_NOT_INIT;
}
// Generate a pulse on DELSTR pin to latch the current DELADJ value
set_delstr_pin(device, true);
no_os_udelay(DELADJ_PULSE_WIDTH_US);
set_delstr_pin(device, false);
printf("Device %d phase shift strobed\n", device);
return ADF4382A_MANAGER_OK;
}
// Static helper functions
static void set_chip_enable(uint8_t ce_pin, bool state)
{
GPIO_TypeDef* port = (ce_pin == TX_CE_Pin) ? TX_CE_GPIO_Port : RX_CE_GPIO_Port;
HAL_GPIO_WritePin(port, ce_pin, state ? GPIO_PIN_SET : GPIO_PIN_RESET);
}
static void set_deladj_pin(uint8_t device, bool state)
{
if (device == 0) { // TX device
HAL_GPIO_WritePin(TX_DELADJ_GPIO_Port, TX_DELADJ_Pin, state ? GPIO_PIN_SET : GPIO_PIN_RESET);
} else { // RX device
HAL_GPIO_WritePin(RX_DELADJ_GPIO_Port, RX_DELADJ_Pin, state ? GPIO_PIN_SET : GPIO_PIN_RESET);
}
}
static void set_delstr_pin(uint8_t device, bool state)
{
if (device == 0) { // TX device
HAL_GPIO_WritePin(TX_DELSTR_GPIO_Port, TX_DELSTR_Pin, state ? GPIO_PIN_SET : GPIO_PIN_RESET);
} else { // RX device
HAL_GPIO_WritePin(RX_DELSTR_GPIO_Port, RX_DELSTR_Pin, state ? GPIO_PIN_SET : GPIO_PIN_RESET);
}
}
static uint16_t phase_ps_to_duty_cycle(uint16_t phase_ps)
{
// Convert phase shift in picoseconds to DELADJ duty cycle
// This is a linear mapping - adjust based on your specific requirements
uint32_t duty = (uint32_t)phase_ps * DELADJ_MAX_DUTY_CYCLE / PHASE_SHIFT_MAX_PS;
return (uint16_t)duty;
}
@@ -0,0 +1,85 @@
#ifndef ADF4382A_MANAGER_H
#define ADF4382A_MANAGER_H
#include "main.h"
#include "adf4382.h"
#include "no_os_spi.h"
// GPIO Definitions
#define TX_CE_Pin GPIO_PIN_0
#define TX_CE_GPIO_Port GPIOG
#define TX_CS_Pin GPIO_PIN_1
#define TX_CS_GPIO_Port GPIOG
#define TX_DELADJ_Pin GPIO_PIN_2
#define TX_DELADJ_GPIO_Port GPIOG
#define TX_DELSTR_Pin GPIO_PIN_3
#define TX_DELSTR_GPIO_Port GPIOG
#define TX_LKDET_Pin GPIO_PIN_4
#define TX_LKDET_GPIO_Port GPIOG
#define RX_CE_Pin GPIO_PIN_5
#define RX_CE_GPIO_Port GPIOG
#define RX_CS_Pin GPIO_PIN_6
#define RX_CS_GPIO_Port GPIOG
#define RX_DELADJ_Pin GPIO_PIN_7
#define RX_DELADJ_GPIO_Port GPIOG
#define RX_DELSTR_Pin GPIO_PIN_8
#define RX_DELSTR_GPIO_Port GPIOG
#define RX_LKDET_Pin GPIO_PIN_9
#define RX_LKDET_GPIO_Port GPIOG
// Frequency definitions
#define REF_FREQ_HZ 300000000ULL // 300 MHz
#define TX_FREQ_HZ 10500000000ULL // 10.5 GHz
#define RX_FREQ_HZ 10380000000ULL // 10.38 GHz
#define SYNC_CLOCK_FREQ 60000000ULL // 60 MHz sync clock
// SPI Configuration
#define ADF4382A_SPI_DEVICE_ID 4 // Using SPI4
#define ADF4382A_SPI_SPEED_HZ 10000000 // 10 MHz
// Phase delay configuration
#define DELADJ_MAX_DUTY_CYCLE 1000 // Maximum duty cycle for DELADJ PWM (1000 = 100%)
#define DELADJ_PULSE_WIDTH_US 10 // Width of DELSTR pulse in microseconds
#define PHASE_SHIFT_MAX_PS 10000 // Maximum phase shift in picoseconds
// Error code definitions
#define ADF4382A_MANAGER_OK 0
#define ADF4382A_MANAGER_ERROR_INVALID -1
#define ADF4382A_MANAGER_ERROR_NOT_INIT -2
#define ADF4382A_MANAGER_ERROR_SPI -3
typedef enum {
SYNC_METHOD_EZSYNC = 0, // Software synchronization via SPI
SYNC_METHOD_TIMED = 1 // Hardware synchronization via SYNCP/SYNCN
} SyncMethod;
typedef struct {
struct adf4382_dev *tx_dev;
struct adf4382_dev *rx_dev;
struct no_os_spi_init_param spi_tx_param;
struct no_os_spi_init_param spi_rx_param;
bool initialized;
SyncMethod sync_method;
uint16_t tx_phase_shift_ps; // Current TX phase shift in picoseconds
uint16_t rx_phase_shift_ps; // Current RX phase shift in picoseconds
} ADF4382A_Manager;
// Public functions
int ADF4382A_Manager_Init(ADF4382A_Manager *manager, SyncMethod method);
int ADF4382A_Manager_Deinit(ADF4382A_Manager *manager);
int ADF4382A_SetupTimedSync(ADF4382A_Manager *manager);
int ADF4382A_SetupEZSync(ADF4382A_Manager *manager);
int ADF4382A_TriggerTimedSync(ADF4382A_Manager *manager);
int ADF4382A_TriggerEZSync(ADF4382A_Manager *manager);
int ADF4382A_CheckLockStatus(ADF4382A_Manager *manager, bool *tx_locked, bool *rx_locked);
int ADF4382A_SetOutputPower(ADF4382A_Manager *manager, uint8_t tx_power, uint8_t rx_power);
int ADF4382A_EnableOutputs(ADF4382A_Manager *manager, bool tx_enable, bool rx_enable);
// New phase delay functions
int ADF4382A_SetPhaseShift(ADF4382A_Manager *manager, uint16_t tx_phase_ps, uint16_t rx_phase_ps);
int ADF4382A_GetPhaseShift(ADF4382A_Manager *manager, uint16_t *tx_phase_ps, uint16_t *rx_phase_ps);
int ADF4382A_SetFinePhaseShift(ADF4382A_Manager *manager, uint8_t device, uint16_t duty_cycle);
int ADF4382A_StrobePhaseShift(ADF4382A_Manager *manager, uint8_t device);
#endif // ADF4382A_MANAGER_H
@@ -0,0 +1,100 @@
/***************************************************************************//**
* @file errno.h
* @brief Error macro definition for ARM Compiler
********************************************************************************
* Copyright (c) 2021-2022 Analog Devices, Inc.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef MBED_ERRNO_H_
#define MBED_ERRNO_H_
// Platform drivers needs to be C-compatible to work with other drivers
#ifdef __cplusplus
extern "C"
{
#endif // _cplusplus
#if defined(__ARMCC_VERSION)
#if !defined(__ELASTERROR)
#define __ELASTERROR 2000
#endif
#if !defined(ENOTSUP)
#define ENOTSUP 9926
#endif
#if !defined(EBADMSG)
#define EBADMSG 9905
#endif
#if !defined(ETIME)
#define ETIME 9935
#endif
#if !defined(EACCES)
#define EACCES 9973
#endif
#if !defined(ETIMEDOUT)
#define ETIMEDOUT 9938
#endif
#if !defined(ENODEV)
#define ENODEV 9967
#endif
#if !defined(EFAULT)
#define EFAULT 9948
#endif
#if !defined(EIO)
#define EIO 9961
#endif
#if !defined(ENOENT)
#define ENOENT 9968
#endif
#if !defined(EBUSY)
#define EBUSY 9952
#endif
#if !defined(EAGAIN)
#define EAGAIN 9976
#endif
#if !defined(EINVAL)
#define EINVAL 9943
#endif
#if !defined(ENOMEM)
#define ENOMEM 9971
#endif
#if !defined(ENOSYS)
#define ENOSYS 88
#endif
#if !defined(ENOTCONN)
#define ENOTCONN 128
#endif
// End of defined(__ARMCC_VERSION)
#endif
#include_next <errno.h>
#ifdef __cplusplus
}
#endif // _cplusplus
#endif // MBED_ERRNO_H_
@@ -0,0 +1,119 @@
// gps_handler.cpp
#include "gps_handler.h"
#include <cmath>
// UART handle for communication with GUI
static UART_HandleTypeDef* gui_huart = NULL;
// GPS data buffer
static GPS_Data_t current_gps = {0};
void GPS_Init(UART_HandleTypeDef* huart)
{
gui_huart = huart;
memset(&current_gps, 0, sizeof(GPS_Data_t));
}
uint8_t GPS_IsDataValid(GPS_Data_t* gps_data)
{
// 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)
return 0;
if (gps_data->altitude < -1000.0 || gps_data->altitude > 10000.0) // -1km to 10km
return 0;
return 1;
}
void GPS_ProcessData(GPS_Data_t* gps_data)
{
// Validate GPS data
if (!GPS_IsDataValid(gps_data)) {
return;
}
// Update current GPS data
memcpy(&current_gps, gps_data, sizeof(GPS_Data_t));
current_gps.timestamp = HAL_GetTick();
// Send to GUI
GPS_SendToGUI(&current_gps);
}
void GPS_SendToGUI(GPS_Data_t* gps_data)
{
if (gui_huart == NULL) return;
// Create packet: "GPS:lat,lon,alt\r\n"
char buffer[64];
// Convert double and float to string with high precision
int len = snprintf(buffer, sizeof(buffer), "GPS:%.8f,%.8f,%.2f\r\n",
gps_data->latitude,
gps_data->longitude,
gps_data->altitude);
if (len > 0 && len < (int)sizeof(buffer)) {
// Send via UART3 to GUI
HAL_UART_Transmit(gui_huart, (uint8_t*)buffer, len, 1000);
}
}
// Alternative binary protocol version (more efficient)
void GPS_SendBinaryToGUI(GPS_Data_t* gps_data)
{
if (gui_huart == NULL) return;
// 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
uint16_t crc = 0;
// Header: "GPSB"
packet[0] = 'G';
packet[1] = 'P';
packet[2] = 'S';
packet[3] = 'B';
// Convert double latitude to bytes (big-endian)
uint64_t lat_bits;
memcpy(&lat_bits, &gps_data->latitude, sizeof(double));
for(int i = 0; i < 8; i++) {
packet[4 + i] = (lat_bits >> (56 - i*8)) & 0xFF;
}
// Convert double longitude to bytes (big-endian)
uint64_t lon_bits;
memcpy(&lon_bits, &gps_data->longitude, sizeof(double));
for(int i = 0; i < 8; i++) {
packet[12 + i] = (lon_bits >> (56 - i*8)) & 0xFF;
}
// Convert float altitude to bytes (big-endian)
uint32_t alt_bits;
memcpy(&alt_bits, &gps_data->altitude, sizeof(float));
for(int i = 0; i < 4; i++) {
packet[20 + i] = (alt_bits >> (24 - i*8)) & 0xFF;
}
// Convert float altitude to bytes (big-endian)
uint32_t pitch_bits;
memcpy(&pitch_bits, &gps_data->pitch, sizeof(float));
for(int i = 0; i < 4; i++) {
packet[24 + i] = (pitch_bits >> (24 - i*8)) & 0xFF;
}
// Calculate simple checksum (you can use CRC16 instead)
for(int i = 0; i < 28; i++) {
crc += packet[i];
}
packet[28] = (crc >> 8) & 0xFF;
packet[29] = crc & 0xFF;
// Send binary packet
CDC_Transmit_FS(packet, sizeof(packet));
}
@@ -0,0 +1,33 @@
// gps_handler.h
#ifndef GPS_HANDLER_H
#define GPS_HANDLER_H
#include "main.h"
#include "usb_device.h"
#include "usbd_cdc_if.h"
#include <stdint.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
double latitude;
double longitude;
float altitude;
float pitch;
uint32_t timestamp;
} GPS_Data_t;
void GPS_Init(UART_HandleTypeDef* huart);
void GPS_ProcessData(GPS_Data_t* gps_data);
void GPS_SendToGUI(GPS_Data_t* gps_data);
void GPS_SendBinaryToGUI(GPS_Data_t* gps_data);
uint8_t GPS_IsDataValid(GPS_Data_t* gps_data);
#ifdef __cplusplus
}
#endif
#endif /* GPS_HANDLER_H */
@@ -0,0 +1,25 @@
/* platform_noos_stm32.h */
#ifndef PLATFORM_NOOS_STM32_H
#define PLATFORM_NOOS_STM32_H
#include "stm32f7xx_hal.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdint.h>
/* Export the HAL SPI handle that will be used by no-OS SPI wrapper */
extern SPI_HandleTypeDef hspi4;
/* Simple wrapper prototypes for no-OS */
int32_t platform_spi_init(void **desc, uint32_t max_speed_hz, uint8_t mode);
int32_t platform_spi_write_and_read(void *desc, uint8_t *data, uint16_t len);
int32_t platform_spi_remove(void *desc);
int32_t platform_gpio_init(void *gpio_desc, uint8_t port_pin, bool is_output);
int32_t platform_gpio_direction_output(void *gpio_desc, uint8_t port_pin, uint8_t value);
int32_t platform_gpio_set_value(void *gpio_desc, uint8_t port_pin, uint8_t value);
int32_t platform_gpio_remove(void *gpio_desc);
void platform_delay_ms(uint32_t ms);
#endif
@@ -0,0 +1,64 @@
/* platform_noos_stm32.c */
#include "platform_noos_stm32.h"
/* Use existing CubeMX handles */
extern SPI_HandleTypeDef hspi4;
/* SPI descriptor we pass to no-OS (just a pointer to HAL handle) */
int32_t platform_spi_init(void **desc, uint32_t max_speed_hz, uint8_t mode)
{
/* For STM32 HAL we already configured hspi4 in CubeMX,
so just return that pointer as the descriptor. */
if (!desc) return -1;
*desc = (void*)&hspi4;
return 0;
}
/* SPI write/read - single transaction (no-OS expects raw transfer) */
int32_t platform_spi_write_and_read(void *desc, uint8_t *data, uint16_t len)
{
SPI_HandleTypeDef *hdl = (SPI_HandleTypeDef*)desc;
if (!hdl) return -1;
/* ADI no-OS SPI wrappers often do full-duplex transfers */
if (HAL_SPI_Transmit(hdl, data, len, HAL_MAX_DELAY) != HAL_OK)
return -1;
return 0;
}
int32_t platform_spi_remove(void *desc)
{
(void)desc;
return 0;
}
/* Minimal GPIO wrapper: we will just use HAL GPIO directly */
/* For simplicity we store nothing in gpio_desc, port_pin encodes both port and pin:
You'll map an enum (0..n) -> HAL GPIO Port/Pin in your code. */
int32_t platform_gpio_init(void *gpio_desc, uint8_t port_pin, bool is_output)
{
(void)gpio_desc; (void)port_pin; (void)is_output;
/* Assume CubeMX already configured the GPIO pins: nothing to do */
return 0;
}
int32_t platform_gpio_direction_output(void *gpio_desc, uint8_t port_pin, uint8_t value)
{
(void)gpio_desc;
/* Implement mapping here from port_pin index to actual port/pin */
/* Example stub: user must implement mapping function: hal_set_gpio_by_index(port_pin, value) */
extern void hal_set_gpio_by_index(uint8_t idx, uint8_t value);
hal_set_gpio_by_index(port_pin, value);
return 0;
}
int32_t platform_gpio_set_value(void *gpio_desc, uint8_t port_pin, uint8_t value)
{
extern void hal_set_gpio_by_index(uint8_t idx, uint8_t value);
hal_set_gpio_by_index(port_pin, value);
return 0;
}
int32_t platform_gpio_remove(void *gpio_desc) { (void)gpio_desc; return 0; }
void platform_delay_ms(uint32_t ms) { HAL_Delay(ms); }
@@ -0,0 +1,17 @@
#include "stm32f7xx_hal.h"
#include "no_os_delay.h"
/* microsecond delay using DWT cycle counter */
void no_os_udelay(uint32_t usec)
{
uint32_t start = DWT->CYCCNT;
uint32_t cycles = (HAL_RCC_GetHCLKFreq() / 1000000U) * usec;
while ((DWT->CYCCNT - start) < cycles);
}
/* millisecond delay wrapper */
void no_os_mdelay(uint32_t msec)
{
HAL_Delay(msec);
}
@@ -0,0 +1,10 @@
#ifndef _STM32_DELAY_H_
#define _STM32_DELAY_H_
#include "stm32f7xx_hal.h"
/* prototypes for compatibility */
void no_os_udelay(uint32_t usec);
void no_os_mdelay(uint32_t msec);
#endif /* _STM32_DELAY_H_ */
@@ -0,0 +1,287 @@
/***************************************************************************//**
* @file stm32/stm32_dma.c
* @brief Implementation of stm32 DMA functionality.
* @author Janani Sunil (janani.sunil@analog.com)
********************************************************************************
* Copyright 2024(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include "stm32_dma.h"
#include "no_os_error.h"
#include "no_os_alloc.h"
#include "stm32_irq.h"
/**
* @brief There is only one DMA controller
*/
static struct no_os_dma_desc *dma_descriptor;
/**
* @brief Configure a DMA channel for a transfer.
* @param channel - The DMA channel descriptor.
* @param xfer - Descriptor for the transfer.
* @return 0 in case of success, negative error codes otherwise
*/
int stm32_dma_config_xfer(struct no_os_dma_ch *channel,
struct no_os_dma_xfer_desc *xfer)
{
struct stm32_dma_channel* sdma_ch;
int ret;
if (!channel || !xfer || !channel->extra)
return -EINVAL;
sdma_ch = channel->extra;
/* Note: Channel number is assigned via the Instance for MCU
* families other than STM32F2, STM32F4 and STM32F7 */
#if defined (STM32F2) || defined (STM32F4) || defined (STM32F7)
sdma_ch->hdma->Init.Channel = sdma_ch->ch_num;
#else
sdma_ch->hdma->Instance = sdma_ch->ch_num;
#endif
sdma_ch->hdma->Init.MemInc = sdma_ch->mem_increment ? DMA_MINC_ENABLE :
DMA_MINC_DISABLE;
sdma_ch->hdma->Init.PeriphInc = sdma_ch->per_increment ? DMA_PINC_ENABLE :
DMA_PINC_DISABLE;
switch (sdma_ch->mem_data_alignment) {
case DATA_ALIGN_BYTE:
sdma_ch->hdma->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
break;
case DATA_ALIGN_HALF_WORD:
sdma_ch->hdma->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
break;
case DATA_ALIGN_WORD:
sdma_ch->hdma->Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
break;
default:
return -EINVAL;
}
switch (sdma_ch->per_data_alignment) {
case DATA_ALIGN_BYTE:
sdma_ch->hdma->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
break;
case DATA_ALIGN_HALF_WORD:
sdma_ch->hdma->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
break;
case DATA_ALIGN_WORD:
sdma_ch->hdma->Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
break;
default:
return -EINVAL;
}
switch (sdma_ch->dma_mode) {
case DMA_NORMAL_MODE:
sdma_ch->hdma->Init.Mode = DMA_NORMAL;
break;
case DMA_CIRCULAR_MODE:
sdma_ch->hdma->Init.Mode = DMA_CIRCULAR;
break;
default:
return -EINVAL;
}
switch (xfer->xfer_type) {
case MEM_TO_MEM:
sdma_ch->hdma->Init.Direction = DMA_MEMORY_TO_MEMORY;
break;
case MEM_TO_DEV:
sdma_ch->hdma->Init.Direction = DMA_MEMORY_TO_PERIPH;
break;
case DEV_TO_MEM:
sdma_ch->hdma->Init.Direction = DMA_PERIPH_TO_MEMORY;
break;
default:
return -EINVAL;
}
sdma_ch->src = xfer->src;
sdma_ch->dst = xfer->dst;
sdma_ch->length = xfer->length;
ret = HAL_DMA_Init(sdma_ch->hdma);
if (ret != HAL_OK)
return -EINVAL;
return 0;
}
/**
* @brief Initialize a DMA controller.
* @param desc - Descriptor to be initialized.
* @param param - Initialization parameter for the decriptor.
* @return 0 in case of success
* -ENOMEM if there is not enough free memory
*/
int stm32_dma_init(struct no_os_dma_desc** desc,
const struct no_os_dma_init_param* param)
{
struct no_os_dma_desc* descriptor;
int ret;
uint8_t i;
struct no_os_irq_init_param irq_param = {
.irq_ctrl_id = 0,
.platform_ops = &stm32_irq_ops,
.extra = NULL
};
if (!desc)
return -EINVAL;
if (dma_descriptor) {
/*
* There is only one DMA controller and it's already
* initialized.
*/
*desc = dma_descriptor;
return 0;
}
descriptor = no_os_calloc(1, sizeof(*descriptor));
if (!descriptor)
return -ENOMEM;
descriptor->channels = no_os_calloc(param->num_ch,
sizeof(*descriptor->channels));
if (!descriptor->channels) {
ret = -ENOMEM;
goto free_descriptor;
}
descriptor->id = param->id;
descriptor->num_ch = param->num_ch;
descriptor->sg_handler = param->sg_handler;
for (i = 0; i < param->num_ch; i++) {
descriptor->channels[i].free = true;
}
no_os_irq_ctrl_init(&descriptor->irq_ctrl, &irq_param);
*desc = descriptor;
return 0;
free_descriptor:
no_os_free(descriptor);
descriptor = NULL;
return ret;
}
/**
* @brief Start a DMA transfer for a specific channel .
* @param desc - Descriptor for the DMA controller.
* @param chan - The DMA Channel
* @return 0 in case of success, negative error codes otherwise
*/
int stm32_dma_xfer_start(struct no_os_dma_desc *desc,
struct no_os_dma_ch *chan)
{
int ret;
struct stm32_dma_channel* sdma_chan;
if (!desc || !chan || !chan->extra)
return -EINVAL;
sdma_chan = chan->extra;
if (chan->irq_num) {
ret = HAL_DMA_Start_IT(sdma_chan->hdma, (uint32_t)sdma_chan->src,
(uint32_t)sdma_chan->dst, sdma_chan->length);
} else {
ret = HAL_DMA_Start(sdma_chan->hdma, (uint32_t)sdma_chan->src,
(uint32_t)sdma_chan->dst, sdma_chan->length);
}
if (ret != HAL_OK)
return -EINVAL;
return 0;
}
/**
* @brief Disable a DMA channel.
* @param desc - Descriptor for the DMA controller.
* @param chan - The DMA Channel
* @return 0 in case of success, negative error codes otherwise
*/
int stm32_dma_xfer_abort(struct no_os_dma_desc* desc,
struct no_os_dma_ch* chan)
{
int ret;
struct stm32_dma_channel* sdma_chan;
if (!desc || !chan || !chan->extra)
return -EINVAL;
sdma_chan = chan->extra;
if (chan->irq_num)
ret = HAL_DMA_Abort_IT(sdma_chan->hdma);
else
ret = HAL_DMA_Abort(sdma_chan->hdma);
if (ret != HAL_OK)
return -EINVAL;
return 0;
}
/**
* @brief Free the resources allocated for a DMA descriptor.
* @param desc - Descriptor to be freed.
* @return 0 in case of success, negative error code otherwise
*/
int stm32_dma_remove(struct no_os_dma_desc* desc)
{
no_os_irq_ctrl_remove(desc->irq_ctrl);
no_os_free(desc->channels);
no_os_free(desc);
dma_descriptor = NULL;
return 0;
}
/**
* @brief stm32 platform specific DMA platform ops structure
*/
const struct no_os_dma_platform_ops stm32_dma_ops = {
.dma_init = stm32_dma_init,
.dma_config_xfer = stm32_dma_config_xfer,
.dma_xfer_start = stm32_dma_xfer_start,
.dma_xfer_abort = stm32_dma_xfer_abort,
.dma_remove = stm32_dma_remove
};
@@ -0,0 +1,101 @@
/***************************************************************************//**
* @file stm32_dma.h
* @brief Platform independent function definitions and data types
* for the DMA API.
* @author Janani Sunil (janani.sunil@analog.com)
********************************************************************************
* Copyright 2024(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef STM32_DMA_H_
#define STM32_DMA_H_
#include "no_os_dma.h"
#include "stm32_hal.h"
/**
* @enum stm32_dma_data_alignment
* @brief DMA Data alignment
*/
enum stm32_dma_data_alignment {
DATA_ALIGN_BYTE = 0,
DATA_ALIGN_HALF_WORD = 1,
DATA_ALIGN_WORD = 2
};
/**
* @enum stm32_dma_mode
* @brief DMA Data Modes
*/
enum stm32_dma_mode {
DMA_NORMAL_MODE = 0,
DMA_CIRCULAR_MODE = 1
};
/**
* @struct stm32_dma_channel
* @brief STM32 DMA Channels
*/
struct stm32_dma_channel {
/* DMA Handle */
DMA_HandleTypeDef *hdma;
/* Channel Number */
uint32_t ch_num;
/* Memory Increment */
bool mem_increment;
/* Peripheral Increment */
bool per_increment;
/* Memory Data Alignment */
enum stm32_dma_data_alignment mem_data_alignment;
/* Peripheral Data Alignment */
enum stm32_dma_data_alignment per_data_alignment;
/* DMA Mode */
enum stm32_dma_mode dma_mode;
/* Source Address for the data */
uint8_t* src;
/* Destination Address for the data */
uint8_t* dst;
/* Transfer length in Bytes */
uint32_t length;
};
struct stm32_dma_init_param {
/* DMA Channel descriptor */
struct stm32_dma_channel *chn;
};
struct stm32_dma_desc {
/* DMA Channel Descriptor */
struct stm32_dma_channel* chn;
};
extern const struct no_os_dma_platform_ops stm32_dma_ops;
extern const struct no_os_dma_platform_ops stm32_gpdma_ops;
#endif
@@ -0,0 +1,394 @@
/***************************************************************************//**
* @file stm32/stm32_gpio.c
* @brief Implementation of stm32 gpio functionality.
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <stdlib.h>
#include <errno.h>
#include "no_os_util.h"
#include "no_os_gpio.h"
#include "no_os_alloc.h"
#include "stm32_gpio.h"
/**
* @brief Prepare the GPIO decriptor.
* @param desc - The GPIO descriptor.
* @param param - The structure that contains the GPIO parameters.
* @return 0 in case of success, -1 otherwise.
*/
static int32_t _gpio_init(struct no_os_gpio_desc *desc,
const struct no_os_gpio_init_param *param)
{
int32_t ret = 0;
struct stm32_gpio_desc *extra = desc->extra;
struct stm32_gpio_init_param *pextra = param->extra;
uint32_t mode = GPIO_MODE_INPUT;
uint32_t speed = GPIO_SPEED_FREQ_LOW;
if (!param)
return -EINVAL;
/* enable gpio port in RCC */
if (param->port == 0) {
__HAL_RCC_GPIOA_CLK_ENABLE();
extra->port = GPIOA;
}
#ifdef GPIOB
else if (param->port == 1) {
__HAL_RCC_GPIOB_CLK_ENABLE();
extra->port = GPIOB;
}
#endif
#ifdef GPIOC
else if (param->port == 2) {
__HAL_RCC_GPIOC_CLK_ENABLE();
extra->port = GPIOC;
}
#endif
#ifdef GPIOD
else if (param->port == 3) {
__HAL_RCC_GPIOD_CLK_ENABLE();
extra->port = GPIOD;
}
#endif
#ifdef GPIOE
else if (param->port == 4) {
__HAL_RCC_GPIOE_CLK_ENABLE();
extra->port = GPIOE;
}
#endif
#ifdef GPIOF
else if (param->port == 5) {
__HAL_RCC_GPIOF_CLK_ENABLE();
extra->port = GPIOF;
}
#endif
#ifdef GPIOG
else if (param->port == 6) {
__HAL_RCC_GPIOG_CLK_ENABLE();
extra->port = GPIOG;
}
#endif
#ifdef GPIOH
else if (param->port == 7) {
__HAL_RCC_GPIOH_CLK_ENABLE();
extra->port = GPIOH;
}
#endif
#ifdef GPIOI
else if (param->port == 8) {
__HAL_RCC_GPIOI_CLK_ENABLE();
extra->port = GPIOI;
}
#endif
#ifdef GPIOJ
else if (param->port == 9) {
__HAL_RCC_GPIOJ_CLK_ENABLE();
extra->port = GPIOJ;
}
#endif
#ifdef GPIOK
else if (param->port == 10) {
__HAL_RCC_GPIOK_CLK_ENABLE();
extra->port = GPIOK;
}
#endif
else
return -EINVAL;
if (param->extra) {
mode = pextra->mode;
speed = pextra->speed;
}
if (!IS_GPIO_MODE(mode))
return -EINVAL;
switch (mode) {
case GPIO_MODE_INPUT:
case GPIO_MODE_OUTPUT_PP:
case GPIO_MODE_OUTPUT_OD:
break;
case GPIO_MODE_AF_PP:
extra->gpio_config.Alternate = pextra->alternate;
break;
default:
return -EINVAL;
}
/* copy the settings to gpio descriptor */
desc->port = param->port;
desc->number = param->number;
desc->pull = param->pull;
switch (param->pull) {
case NO_OS_PULL_NONE:
extra->gpio_config.Pull = GPIO_NOPULL;
break;
case NO_OS_PULL_UP:
case NO_OS_PULL_UP_WEAK:
extra->gpio_config.Pull = GPIO_PULLUP;
break;
case NO_OS_PULL_DOWN:
case NO_OS_PULL_DOWN_WEAK:
extra->gpio_config.Pull = GPIO_PULLDOWN;
break;
default:
return -EINVAL;
}
/* configure gpio with user configuration */
extra->gpio_config.Pin = NO_OS_BIT(param->number);
extra->gpio_config.Mode = mode;
extra->gpio_config.Speed = speed;
HAL_GPIO_Init(extra->port, &extra->gpio_config);
return ret;
}
/**
* @brief Obtain the GPIO decriptor.
* @param desc - The GPIO descriptor.
* @param param - GPIO initialization parameters
* @return 0 in case of success, -1 otherwise.
*/
int32_t stm32_gpio_get(struct no_os_gpio_desc **desc,
const struct no_os_gpio_init_param *param)
{
struct no_os_gpio_desc *descriptor;
struct stm32_gpio_desc *extra;
int32_t ret;
if (!desc || !param)
return -EINVAL;
descriptor = (struct no_os_gpio_desc *)no_os_malloc(sizeof(*descriptor));
if (!descriptor) {
ret = -ENOMEM;
goto error;
}
extra = (struct stm32_gpio_desc*)no_os_malloc(sizeof(*extra));
if (!extra) {
ret = -ENOMEM;
goto error;
}
descriptor->extra = extra;
ret = _gpio_init(descriptor, param);
if (ret < 0)
goto error;
*desc = descriptor;
return 0;
error:
no_os_free(extra);
no_os_free(descriptor);
return ret;
}
/**
* @brief Get the value of an optional GPIO.
* @param desc - The GPIO descriptor.
* @param param - GPIO Initialization parameters.
* @return 0 in case of success, -1 otherwise.
*/
int32_t stm32_gpio_get_optional(struct no_os_gpio_desc **desc,
const struct no_os_gpio_init_param *param)
{
if (param == NULL) {
*desc = NULL;
return 0;
}
return stm32_gpio_get(desc, param);
}
/**
* @brief Free the resources allocated by no_os_gpio_get().
* @param desc - The GPIO descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t stm32_gpio_remove(struct no_os_gpio_desc *desc)
{
if (desc != NULL)
no_os_free(desc->extra);
no_os_free(desc);
return 0;
}
/**
* @brief Enable the input direction of the specified GPIO.
* @param desc - The GPIO descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t stm32_gpio_direction_input(struct no_os_gpio_desc *desc)
{
struct stm32_gpio_desc *extra;
if (!desc)
return -EINVAL;
if (!desc->extra)
return -EFAULT;
extra = desc->extra;
/* configure gpio with user configuration */
extra->gpio_config.Mode = GPIO_MODE_INPUT;
HAL_GPIO_Init(extra->port, &extra->gpio_config);
return 0;
}
/**
* @brief Enable the output direction of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param value - The value.
* Example: NO_OS_GPIO_HIGH
* NO_OS_GPIO_LOW
* @return 0 in case of success, -1 otherwise.
*/
int32_t stm32_gpio_direction_output(struct no_os_gpio_desc *desc,
uint8_t value)
{
struct stm32_gpio_desc *extra;
if (!desc)
return -EINVAL;
if (!desc->extra)
return -EFAULT;
extra = desc->extra;
/* configure gpio output level */
HAL_GPIO_WritePin(extra->port, NO_OS_BIT(desc->number), (GPIO_PinState)value);
/* configure gpio with user configuration */
if (extra->gpio_config.Mode == GPIO_MODE_INPUT)
extra->gpio_config.Mode = GPIO_MODE_OUTPUT_PP;
HAL_GPIO_Init(extra->port, &extra->gpio_config);
return 0;
}
/**
* @brief Get the direction of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param direction - The direction.
* Example: NO_OS_GPIO_OUT
* NO_OS_GPIO_IN
* @return 0 in case of success, -1 otherwise.
*/
int32_t stm32_gpio_get_direction(struct no_os_gpio_desc *desc,
uint8_t *direction)
{
if (!desc || !direction)
return -EINVAL;
struct stm32_gpio_desc *extra = desc->extra;
if (!extra->gpio_config.Mode)
*direction = NO_OS_GPIO_IN;
else
*direction = NO_OS_GPIO_OUT;
return 0;
}
/**
* @brief Set the value of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param value - The value.
* Example: NO_OS_GPIO_HIGH
* NO_OS_GPIO_LOW
* @return 0 in case of success, -1 otherwise.
*/
int32_t stm32_gpio_set_value(struct no_os_gpio_desc *desc,
uint8_t value)
{
struct stm32_gpio_desc *extra;
if (!desc)
return -EINVAL;
if (!desc->extra)
return -EFAULT;
extra = desc->extra;
/* configure gpio output level */
HAL_GPIO_WritePin(extra->port, NO_OS_BIT(desc->number), (GPIO_PinState)value);
return 0;
}
/**
* @brief Get the value of the specified GPIO.
* @param desc - The GPIO descriptor.
* @param value - The value.
* Example: NO_OS_GPIO_HIGH
* NO_OS_GPIO_LOW
* @return 0 in case of success, -1 otherwise.
*/
int32_t stm32_gpio_get_value(struct no_os_gpio_desc *desc,
uint8_t *value)
{
struct stm32_gpio_desc *extra;
if (!desc || !value)
return -EINVAL;
if (!desc->extra)
return -EFAULT;
extra = desc->extra;
*value = (uint8_t)HAL_GPIO_ReadPin(extra->port, NO_OS_BIT(desc->number));
return 0;
}
/**
* @brief stm32 platform specific GPIO platform ops structure
*/
const struct no_os_gpio_platform_ops stm32_gpio_ops = {
.gpio_ops_get = &stm32_gpio_get,
.gpio_ops_get_optional = &stm32_gpio_get_optional,
.gpio_ops_remove = &stm32_gpio_remove,
.gpio_ops_direction_input = &stm32_gpio_direction_input,
.gpio_ops_direction_output = &stm32_gpio_direction_output,
.gpio_ops_get_direction = &stm32_gpio_get_direction,
.gpio_ops_set_value = &stm32_gpio_set_value,
.gpio_ops_get_value = &stm32_gpio_get_value,
};
@@ -0,0 +1,69 @@
/***************************************************************************//**
* @file stm32/stm32_gpio.h
* @brief Header file for stm32 gpio specifics.
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef STM32_GPIO_H_
#define STM32_GPIO_H_
#include <stdint.h>
#include <stdbool.h>
#include "stm32_hal.h"
/**
* @struct stm32_gpio_init_param
* @brief Structure holding the initialization parameters for stm32 platform
*/
struct stm32_gpio_init_param {
/** Output mode */
uint32_t mode;
/** Speed grade */
uint32_t speed;
/** Alternate functionality */
uint32_t alternate;
};
/**
* @struct stm32_gpio_desc
* @brief stm32 platform specific gpio descriptor
*/
struct stm32_gpio_desc {
/** Port */
GPIO_TypeDef *port;
/** GPIO configuration */
GPIO_InitTypeDef gpio_config;
};
/**
* @brief stm32 platform specific gpio platform ops structure
*/
extern const struct no_os_gpio_platform_ops stm32_gpio_ops;
#endif
@@ -0,0 +1,463 @@
/***************************************************************************//**
* @file stm32/stm32_gpio_irq.c
* @brief Source file for GPIO IRQ driver.
* @author Ramona Bolboaca (ramona.bolboaca@analog.com)
********************************************************************************
* Copyright 2022(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include "no_os_list.h"
#include "no_os_irq.h"
#include "no_os_util.h"
#include "no_os_alloc.h"
#include "stm32_gpio_irq.h"
#define STM32_IRQ_CTRL_NB 16
/**
* @brief Struct used to store a (peripheral, callback) pair
*/
struct irq_action {
uint32_t irq_id;
void (*callback)(void *context);
void *ctx;
};
static struct no_os_list_desc *actions;
static int32_t irq_action_cmp(void *data1, void *data2)
{
return ((struct irq_action *)data1)->irq_id -
((struct irq_action *)data2)->irq_id;
}
static bool initialized[STM32_IRQ_CTRL_NB] = {false};
/**
* @brief Generic Interrupt handler callback
* @param pin pin number on which the interrupt occurred (GPIO_PIN_pin)
*/
static inline void stm32_handle_generic_callback(uint16_t pin)
{
int ret;
struct irq_action *action;
struct irq_action key;
key.irq_id = no_os_find_first_set_bit(pin);
ret = no_os_list_read_find(actions, (void **)&action, &key);
if (ret)
return;
if (action->callback)
action->callback(action->ctx);
}
/**
* @brief EXTI GPIO Interrupt handler callback
* @param pin pin number on which the interrupt occurred (GPIO_PIN_pin)
*/
void HAL_GPIO_EXTI_Callback(uint16_t pin)
{
stm32_handle_generic_callback(pin);
}
/**
* @brief EXTI GPIO Interrupt handler callback for rising edge detection
* @param pin pin number on which the interrupt occurred (GPIO_PIN_pin)
*/
void HAL_GPIO_EXTI_Rising_Callback(uint16_t pin)
{
stm32_handle_generic_callback(pin);
}
/**
* @brief EXTI GPIO Interrupt handler callback for falling edge detection
* @param pin pin number on which the interrupt occurred (GPIO_PIN_pin)
*/
void HAL_GPIO_EXTI_Falling_Callback(uint16_t pin)
{
stm32_handle_generic_callback(pin);
}
/**
* @brief Initialize the GPIO interrupt controller
* @param desc - Pointer where the configured instance is stored
* @param param - Configuration information for the instance
* @return 0 in case of success, errno error codes otherwise.
*/
static int stm32_gpio_irq_ctrl_init(struct no_os_irq_ctrl_desc **desc,
const struct no_os_irq_init_param *param)
{
static struct no_os_irq_ctrl_desc *gpio_irq_desc_arr[STM32_IRQ_CTRL_NB];
int ret;
struct no_os_irq_ctrl_desc *gpio_irq_desc;
struct stm32_gpio_irq_desc *sdesc;
struct stm32_gpio_irq_init_param *gpio_irq_ip;
if (!param || !param->extra)
return -EINVAL;
gpio_irq_ip = param->extra;
/* Check port number */
if (!IS_EXTI_GPIO_PORT(gpio_irq_ip->port_nb))
return -EINVAL;
/* Check pin number */
if (!IS_EXTI_GPIO_PIN(param->irq_ctrl_id))
return -EINVAL;
if (!initialized[param->irq_ctrl_id]) {
gpio_irq_desc = no_os_calloc(1, sizeof(*gpio_irq_desc));
if (!gpio_irq_desc)
return -ENOMEM;
sdesc = (struct stm32_gpio_irq_desc*)no_os_calloc(1, sizeof(*sdesc));
if (!sdesc) {
ret = -ENOMEM;
goto error;
}
/* Add port number */
sdesc->port_nb = gpio_irq_ip->port_nb;
gpio_irq_desc->extra = sdesc;
gpio_irq_desc->irq_ctrl_id = param->irq_ctrl_id;
ret = no_os_list_init(&actions, NO_OS_LIST_PRIORITY_LIST, irq_action_cmp);
if (ret)
goto error;
gpio_irq_desc_arr[param->irq_ctrl_id] = gpio_irq_desc;
initialized[param->irq_ctrl_id] = true;
}
*desc = gpio_irq_desc_arr[param->irq_ctrl_id];
return 0;
error:
no_os_list_remove(actions);
no_os_free(gpio_irq_desc);
no_os_free(sdesc);
return ret;
}
/**
* @brief Free the resources allocated by irq_ctrl_init()
* @param desc - GPIO interrupt controller descriptor.
* @return 0 in case of success, errno error codes otherwise.
*/
static int stm32_gpio_irq_ctrl_remove(struct no_os_irq_ctrl_desc *desc)
{
struct no_os_callback_desc *discard;
if (!desc)
return -EINVAL;
while (0 == no_os_list_get_first(actions, (void **)&discard))
no_os_free(discard);
no_os_list_remove(actions);
initialized[desc->irq_ctrl_id] = false;
no_os_free(desc->extra);
no_os_free(desc);
return 0;
}
/**
* @brief Set the trigger condition.
* @param desc - GPIO interrupt controller descriptor.
* @param irq_id - Not used, pin id is already present in desc.
* @param level - the trigger condition.
* @return 0 in case of success, errno error codes otherwise
*/
static int stm32_gpio_irq_trigger_level_set(struct no_os_irq_ctrl_desc
*desc,
uint32_t irq_id,
enum no_os_irq_trig_level level)
{
int ret;
EXTI_ConfigTypeDef config;
struct stm32_gpio_irq_desc *sdesc;
if (!desc || !desc->extra || !IS_EXTI_GPIO_PIN(desc->irq_ctrl_id))
return -EINVAL;
sdesc = desc->extra;
ret = HAL_EXTI_GetConfigLine(&sdesc->hexti, &config);
if (ret != HAL_OK)
return -EFAULT;
switch (level) {
case NO_OS_IRQ_EDGE_FALLING:
config.Trigger = EXTI_TRIGGER_FALLING;
break;
case NO_OS_IRQ_EDGE_RISING:
config.Trigger = EXTI_TRIGGER_RISING;
break;
case NO_OS_IRQ_EDGE_BOTH:
config.Trigger = EXTI_TRIGGER_RISING_FALLING;
break;
default:
return -EINVAL;
}
config.GPIOSel = sdesc->port_nb;
ret = HAL_EXTI_SetConfigLine(&sdesc->hexti, &config);
if (ret != HAL_OK)
return -EFAULT;
return 0;
}
/**
* @brief Register a callback function to be triggered when an
* interrupt occurs.
* @param desc - GPIO interrupt controller descriptor.
* @param irq_id - Not used, pin id is already present in desc.
* @param cb - Descriptor of the callback.
* @return 0 if successful, negative error code otherwise.
*/
static int stm32_gpio_irq_register_callback(struct no_os_irq_ctrl_desc
*desc,
uint32_t irq_id,
struct no_os_callback_desc *cb)
{
int ret;
struct irq_action *action;
struct irq_action action_key = {.irq_id = desc->irq_ctrl_id};
struct stm32_gpio_irq_desc *sdesc;
if (!desc || !desc->extra || !cb || !IS_EXTI_GPIO_PIN(desc->irq_ctrl_id))
return -EINVAL;
sdesc = desc->extra;
ret = no_os_list_read_find(actions, (void **)&action, &action_key);
/*
* If no action was found, insert a new one, otherwise update it
*/
if (ret) {
action = no_os_calloc(1, sizeof(*action));
if (!action)
return -ENOMEM;
action->irq_id = desc->irq_ctrl_id;
action->ctx = cb->ctx;
action->callback = cb->callback;
ret = no_os_list_add_last(actions, action);
if (ret)
goto free_action;
} else {
action->irq_id = desc->irq_ctrl_id;
action->ctx = cb->ctx;
action->callback = cb->callback;
}
EXTI_ConfigTypeDef config;
config.Mode = EXTI_MODE_INTERRUPT;
config.GPIOSel = sdesc->port_nb;
config.Line = EXTI_GPIO | desc->irq_ctrl_id;
ret = HAL_EXTI_SetConfigLine(&sdesc->hexti, &config);
if (ret) {
ret = -EFAULT;
goto free_action;
}
return 0;
free_action:
no_os_free(action);
return ret;
}
/**
* @brief Unregister a callback.
* @param desc - GPIO interrupt controller descriptor.
* @param irq_id - Not used, pin id is already present in desc.
* @param cb - Descriptor of the callback.
* @return 0 if successful, negative error code otherwise.
*/
static int stm32_gpio_irq_unregister_callback(struct no_os_irq_ctrl_desc
*desc,
uint32_t irq_id, struct no_os_callback_desc *cb)
{
int ret;
struct irq_action *discard_action = NULL;
struct irq_action action_key = {.irq_id = desc->irq_ctrl_id};
if (!desc || !cb || !IS_EXTI_GPIO_PIN(desc->irq_ctrl_id))
return -EINVAL;
ret = no_os_list_read_find(actions, (void **)&discard_action, &action_key);
if (ret)
return -ENODEV;
no_os_free(discard_action);
return 0;
}
/**
* @brief Unused
* @param desc - GPIO interrupt controller descriptor.
* @return -ENOSYS
*/
static int stm32_gpio_irq_global_enable(struct no_os_irq_ctrl_desc *desc)
{
return -ENOSYS;
}
/**
* @brief Unused
* @param desc - GPIO interrupt controller descriptor.
* @return -ENOSYS
*/
static int stm32_gpio_irq_global_disable(struct no_os_irq_ctrl_desc *desc)
{
return -ENOSYS;
}
/**
* @brief Enable a specific gpio interrupt.
* @param desc - GPIO interrupt controller descriptor.
* @param irq_id - Not used, pin id is already present in desc.
* @return 0 in case of success, -EINVAL otherwise.
*/
static int stm32_gpio_irq_enable(struct no_os_irq_ctrl_desc *desc,
uint32_t irq_id)
{
IRQn_Type nvic_irq_id;
int ret;
if (!desc || !desc->extra || !IS_EXTI_GPIO_PIN(desc->irq_ctrl_id))
return -EINVAL;
ret = stm32_get_exti_irq_id_from_pin(desc->irq_ctrl_id, &nvic_irq_id);
if (ret)
return ret;
HAL_NVIC_EnableIRQ(nvic_irq_id);
return 0;
}
/**
* @brief Disable a specific gpio interrupt.
* @param desc - GPIO interrupt controller descriptor.
* @param irq_id - Not used, pin id is already present in desc.
* @return 0 in case of success, -EINVAL otherwise.
*/
static int stm32_gpio_irq_disable(struct no_os_irq_ctrl_desc *desc,
uint32_t irq_id)
{
IRQn_Type nvic_irq_id;
int ret;
if (!desc || !desc->extra || !IS_EXTI_GPIO_PIN(desc->irq_ctrl_id))
return -EINVAL;
ret = stm32_get_exti_irq_id_from_pin(desc->irq_ctrl_id, &nvic_irq_id);
if (ret)
return ret;
HAL_NVIC_DisableIRQ(nvic_irq_id);
return 0;
}
/*
* @brief Set the interrupt priority for the current GPIO pin.
* @param desc - GPIO interrupt controller descriptor.
* @param irq_id - Not used, pin id is already present in desc.
* @param priority_level - The interrupt priority level.
* @return 0
*/
static int stm32_gpio_irq_set_priority(struct no_os_irq_ctrl_desc *desc,
uint32_t irq_id,
uint32_t priority_level)
{
IRQn_Type nvic_irq_id;
int ret;
if (!desc || !desc->extra || !IS_EXTI_GPIO_PIN(desc->irq_ctrl_id))
return -EINVAL;
ret = stm32_get_exti_irq_id_from_pin(desc->irq_ctrl_id, &nvic_irq_id);
if (ret)
return ret;
NVIC_SetPriority(nvic_irq_id, priority_level);
return 0;
}
/*
* @brief Clear the pending interrupt for the current GPIO pin.
* @param desc - GPIO interrupt controller descriptor.
* @param irq_id - Not used, pin id is already present in desc.
* @return 0
*/
static int stm32_irq_clear_pending(struct no_os_irq_ctrl_desc* desc,
uint32_t irq_id)
{
if (!desc || !desc->extra || !IS_EXTI_GPIO_PIN(desc->irq_ctrl_id))
return -EINVAL;
if (__HAL_GPIO_EXTI_GET_IT(1 << (desc->irq_ctrl_id)))
__HAL_GPIO_EXTI_CLEAR_IT(1 << (desc->irq_ctrl_id));
return 0;
}
/**
* @brief stm32 specific IRQ platform ops structure
*/
const struct no_os_irq_platform_ops stm32_gpio_irq_ops = {
.init = &stm32_gpio_irq_ctrl_init,
.trigger_level_set = &stm32_gpio_irq_trigger_level_set,
.register_callback = &stm32_gpio_irq_register_callback,
.unregister_callback = &stm32_gpio_irq_unregister_callback,
.global_enable = &stm32_gpio_irq_global_enable,
.global_disable = &stm32_gpio_irq_global_disable,
.enable = &stm32_gpio_irq_enable,
.disable = &stm32_gpio_irq_disable,
.set_priority = &stm32_gpio_irq_set_priority,
.remove = &stm32_gpio_irq_ctrl_remove,
.clear_pending = &stm32_irq_clear_pending
};
@@ -0,0 +1,64 @@
/***************************************************************************//**
* @file stm32/stm32_gpio_irq.h
* @brief Header file for stm32 gpio irq specifics.
* @author Ramona Bolboaca (ramona.bolboaca@analog.com)
********************************************************************************
* Copyright 2022(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef STM32_GPIO_IRQ_H
#define STM32_GPIO_IRQ_H
#include "no_os_irq.h"
#include "stm32_hal.h"
/**
* @struct stm32_gpio_irq_init_param
* @brief Structure holding the initialization parameters for stm32 platform
* specific GPIO IRQ parameters.
*/
struct stm32_gpio_irq_init_param {
uint8_t port_nb;
};
/**
* @struct stm32_gpio_irq_desc
* @brief stm32 platform specific GPIO IRQ descriptor
*/
struct stm32_gpio_irq_desc {
/** EXTI line instance */
EXTI_HandleTypeDef hexti;
/** Port number */
uint8_t port_nb;
};
/**
* @brief stm32 platform specific irq platform ops structure
*/
extern const struct no_os_irq_platform_ops stm32_gpio_irq_ops;
#endif
@@ -0,0 +1,9 @@
#ifndef _STM32_HAL_H
#define _STM32_HAL_H
#include "main.h"
int stm32_init(void);
int stm32_get_exti_irq_id_from_pin(uint8_t pin_nb, IRQn_Type *irq_id);
#endif
@@ -0,0 +1,227 @@
/***************************************************************************//**
* @file stm32/stm32_i2c.c
* @brief Implementation of stm32 i2c driver.
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* Copyright 2021(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <stdlib.h>
#include <errno.h>
#include "no_os_util.h"
#include "no_os_alloc.h"
#include "no_os_i2c.h"
#include "stm32_i2c.h"
/**
* @brief Initialize the I2C communication peripheral.
* @param desc - The I2C descriptor.
* @param param - The structure that contains the I2C parameters.
* @return 0 in case of success, -1 otherwise.
*/
int32_t stm32_i2c_init(struct no_os_i2c_desc **desc,
const struct no_os_i2c_init_param *param)
{
int32_t ret;
struct no_os_i2c_desc *descriptor;
struct stm32_i2c_desc *xdesc;
struct stm32_i2c_init_param *i2cinit;
I2C_TypeDef *base = NULL;
if (!desc || !param)
return -EINVAL;
descriptor = (struct no_os_i2c_desc *)no_os_calloc(1,
sizeof(struct no_os_i2c_desc));
if (!descriptor)
return -ENOMEM;
xdesc = (struct stm32_i2c_desc *)no_os_calloc(1, sizeof(struct stm32_i2c_desc));
if (!xdesc) {
ret = -ENOMEM;
goto error_1;
}
i2cinit = param->extra;
descriptor->extra = xdesc;
switch (param->device_id) {
#if defined(I2C1)
case 1:
base = I2C1;
break;
#endif
#if defined(I2C2)
case 2:
base = I2C2;
break;
#endif
#if defined(I2C3)
case 3:
base = I2C3;
break;
#endif
default:
ret = -EINVAL;
goto error_2;
};
xdesc->hi2c.Instance = base;
#if defined (STM32F4) || defined (STM32F1) || defined (STM32F2) || defined (STM32L1)
xdesc->hi2c.Init.ClockSpeed = param->max_speed_hz;
xdesc->hi2c.Init.DutyCycle = I2C_DUTYCYCLE_2;
#else
xdesc->hi2c.Init.Timing = i2cinit->i2c_timing;
#endif
xdesc->hi2c.Init.OwnAddress1 = 0;
xdesc->hi2c.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
xdesc->hi2c.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
xdesc->hi2c.Init.OwnAddress2 = 0;
xdesc->hi2c.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
xdesc->hi2c.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
ret = HAL_I2C_Init(&xdesc->hi2c);
if (ret != HAL_OK) {
ret = -EIO;
goto error_2;
}
/* copy settings to device descriptor */
descriptor->device_id = param->device_id;
descriptor->max_speed_hz = param->max_speed_hz;
descriptor->slave_address = param->slave_address;
*desc = descriptor;
return 0;
error_2:
no_os_free(xdesc);
error_1:
no_os_free(descriptor);
return ret;
}
/**
* @brief Free the resources allocated by no_os_i2c_init().
* @param desc - The I2C descriptor.
* @return 0 in case of success, -1 otherwise.
*/
int32_t stm32_i2c_remove(struct no_os_i2c_desc *desc)
{
struct stm32_i2c_desc *sdesc;
if (!desc || !desc->extra)
return -EINVAL;
sdesc = desc->extra;
HAL_I2C_DeInit(&sdesc->hi2c);
no_os_free(desc->extra);
no_os_free(desc);
return 0;
}
/**
* @brief I2C write transaction as master.
* @param desc - The I2C descriptor.
* @param data - The buffer with the data to transmit.
* @param bytes_number - Number of bytes in the buffer.
* @param stop_bit - Specifis whether to end the transaction with a stop bit.
* @return 0 in case of success, -1 otherwise.
*/
int32_t stm32_i2c_write(struct no_os_i2c_desc *desc,
uint8_t *data,
uint8_t bytes_number,
uint8_t stop_bit)
{
int ret;
struct stm32_i2c_desc *xdesc;
if (!desc || !desc->extra || !data)
return -EINVAL;
xdesc = desc->extra;
if (!stop_bit) {
ret = HAL_I2C_Master_Seq_Transmit_IT(&xdesc->hi2c, desc->slave_address << 1,
data,
bytes_number, I2C_FIRST_FRAME);
} else {
ret = HAL_I2C_Master_Transmit(&xdesc->hi2c, desc->slave_address << 1, data,
bytes_number, HAL_MAX_DELAY);
}
if (ret != HAL_OK)
return -EIO;
return 0;
}
/**
* @brief I2C read transaction as master.
* @param desc - The I2C descriptor.
* @param data - The buffer where received data is to be stored.
* @param bytes_number - Number of bytes to receive.
* @param stop_bit - Specifis whether to end the transaction with a stop bit.
* @return 0 in case of success, -1 otherwise.
*/
int32_t stm32_i2c_read(struct no_os_i2c_desc *desc,
uint8_t *data,
uint8_t bytes_number,
uint8_t stop_bit)
{
int ret;
struct stm32_i2c_desc *xdesc;
if (!desc || !desc->extra || !data)
return -EINVAL;
xdesc = desc->extra;
if (!stop_bit) {
ret = HAL_I2C_Master_Seq_Receive_IT(&xdesc->hi2c, desc->slave_address << 1,
data,
bytes_number, I2C_LAST_FRAME);
} else {
ret = HAL_I2C_Master_Receive(&xdesc->hi2c, desc->slave_address << 1, data,
bytes_number, HAL_MAX_DELAY);
}
if (ret != HAL_OK)
return -EIO;
return 0;
}
/**
* @brief stm32 platform specific I2C platform ops structure
*/
const struct no_os_i2c_platform_ops stm32_i2c_ops = {
.i2c_ops_init = &stm32_i2c_init,
.i2c_ops_write = &stm32_i2c_write,
.i2c_ops_read = &stm32_i2c_read,
.i2c_ops_remove = &stm32_i2c_remove
};
@@ -0,0 +1,64 @@
/***************************************************************************//**
* @file stm32/stm32_i2c.h
* @brief Header file for the stm32 i2c driver.
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* Copyright 2021(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef STM32_I2C_H_
#define STM32_I2C_H_
#include <stdint.h>
#include "no_os_i2c.h"
#include "stm32_hal.h"
/**
* @struct stm32_i2c_desc
* @brief stm32 platform specific I2C descriptor
*/
struct stm32_i2c_desc {
/** I2C instance */
I2C_HandleTypeDef hi2c;
};
/**
* @struct stm32_i2c_init_param
* @brief Structure holding the initialization parameters for stm32 platform
* specific I2C parameters.
*/
struct stm32_i2c_init_param {
/** I2C Timing */
uint32_t i2c_timing;
};
/**
* @brief stm32 specific I2C platform ops structure
*/
extern const struct no_os_i2c_platform_ops stm32_i2c_ops;
#endif // STM32_I2C_H_
@@ -0,0 +1,701 @@
/***************************************************************************//**
* @file stm32/stm32_irq.c
* @brief Implementation of external irq driver.
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* Copyright 2022(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include "main.h"
#include "no_os_list.h"
#include "no_os_irq.h"
#include "no_os_util.h"
#include "no_os_alloc.h"
#include "stm32_irq.h"
#include "stm32_hal.h"
#include "stm32f7xx_hal.h"
#include "stm32f7xx_hal_uart.h"
#include "stm32f7xx_hal_conf.h"
#include "stm32f7xx_hal_def.h"
#include "stm32f7xx_hal_tim.h"
struct irq_action {
void *handle;
void (*callback)(void *context);
void *ctx;
};
struct event_list {
enum no_os_irq_event event;
uint32_t hal_event;
struct no_os_list_desc *actions;
};
static bool initialized = false;
typedef enum
{
HAL_UART_TX_HALFCOMPLETE_CB_ID = 0x00U, /*!< UART Tx Half Complete Callback ID */
HAL_UART_TX_COMPLETE_CB_ID = 0x01U, /*!< UART Tx Complete Callback ID */
HAL_UART_RX_HALFCOMPLETE_CB_ID = 0x02U, /*!< UART Rx Half Complete Callback ID */
HAL_UART_RX_COMPLETE_CB_ID = 0x03U, /*!< UART Rx Complete Callback ID */
HAL_UART_ERROR_CB_ID = 0x04U, /*!< UART Error Callback ID */
HAL_UART_ABORT_COMPLETE_CB_ID = 0x05U, /*!< UART Abort Complete Callback ID */
HAL_UART_ABORT_TRANSMIT_COMPLETE_CB_ID = 0x06U, /*!< UART Abort Transmit Complete Callback ID */
HAL_UART_ABORT_RECEIVE_COMPLETE_CB_ID = 0x07U, /*!< UART Abort Receive Complete Callback ID */
HAL_UART_WAKEUP_CB_ID = 0x08U, /*!< UART Wakeup Callback ID */
HAL_UART_MSPINIT_CB_ID = 0x0BU, /*!< UART MspInit callback ID */
HAL_UART_MSPDEINIT_CB_ID = 0x0CU /*!< UART MspDeInit callback ID */
} HAL_UART_CallbackIDTypeDef;
typedef enum
{
HAL_TIM_BASE_MSPINIT_CB_ID = 0x00U /*!< TIM Base MspInit Callback ID */
, HAL_TIM_BASE_MSPDEINIT_CB_ID = 0x01U /*!< TIM Base MspDeInit Callback ID */
, HAL_TIM_IC_MSPINIT_CB_ID = 0x02U /*!< TIM IC MspInit Callback ID */
, HAL_TIM_IC_MSPDEINIT_CB_ID = 0x03U /*!< TIM IC MspDeInit Callback ID */
, HAL_TIM_OC_MSPINIT_CB_ID = 0x04U /*!< TIM OC MspInit Callback ID */
, HAL_TIM_OC_MSPDEINIT_CB_ID = 0x05U /*!< TIM OC MspDeInit Callback ID */
, HAL_TIM_PWM_MSPINIT_CB_ID = 0x06U /*!< TIM PWM MspInit Callback ID */
, HAL_TIM_PWM_MSPDEINIT_CB_ID = 0x07U /*!< TIM PWM MspDeInit Callback ID */
, HAL_TIM_ONE_PULSE_MSPINIT_CB_ID = 0x08U /*!< TIM One Pulse MspInit Callback ID */
, HAL_TIM_ONE_PULSE_MSPDEINIT_CB_ID = 0x09U /*!< TIM One Pulse MspDeInit Callback ID */
, HAL_TIM_ENCODER_MSPINIT_CB_ID = 0x0AU /*!< TIM Encoder MspInit Callback ID */
, HAL_TIM_ENCODER_MSPDEINIT_CB_ID = 0x0BU /*!< TIM Encoder MspDeInit Callback ID */
, HAL_TIM_HALL_SENSOR_MSPINIT_CB_ID = 0x0CU /*!< TIM Hall Sensor MspDeInit Callback ID */
, HAL_TIM_HALL_SENSOR_MSPDEINIT_CB_ID = 0x0DU /*!< TIM Hall Sensor MspDeInit Callback ID */
, HAL_TIM_PERIOD_ELAPSED_CB_ID = 0x0EU /*!< TIM Period Elapsed Callback ID */
, HAL_TIM_PERIOD_ELAPSED_HALF_CB_ID = 0x0FU /*!< TIM Period Elapsed half complete Callback ID */
, HAL_TIM_TRIGGER_CB_ID = 0x10U /*!< TIM Trigger Callback ID */
, HAL_TIM_TRIGGER_HALF_CB_ID = 0x11U /*!< TIM Trigger half complete Callback ID */
, HAL_TIM_IC_CAPTURE_CB_ID = 0x12U /*!< TIM Input Capture Callback ID */
, HAL_TIM_IC_CAPTURE_HALF_CB_ID = 0x13U /*!< TIM Input Capture half complete Callback ID */
, HAL_TIM_OC_DELAY_ELAPSED_CB_ID = 0x14U /*!< TIM Output Compare Delay Elapsed Callback ID */
, HAL_TIM_PWM_PULSE_FINISHED_CB_ID = 0x15U /*!< TIM PWM Pulse Finished Callback ID */
, HAL_TIM_PWM_PULSE_FINISHED_HALF_CB_ID = 0x16U /*!< TIM PWM Pulse Finished half complete Callback ID */
, HAL_TIM_ERROR_CB_ID = 0x17U /*!< TIM Error Callback ID */
, HAL_TIM_COMMUTATION_CB_ID = 0x18U /*!< TIM Commutation Callback ID */
, HAL_TIM_COMMUTATION_HALF_CB_ID = 0x19U /*!< TIM Commutation half complete Callback ID */
, HAL_TIM_BREAK_CB_ID = 0x1AU /*!< TIM Break Callback ID */
, HAL_TIM_BREAK2_CB_ID = 0x1BU /*!< TIM Break2 Callback ID */
} HAL_TIM_CallbackIDTypeDef;
static struct event_list _events[] = {
[NO_OS_EVT_GPIO] = {.event = NO_OS_EVT_GPIO, .hal_event = HAL_EXTI_COMMON_CB_ID},
[NO_OS_EVT_UART_TX_COMPLETE] = {.event = NO_OS_EVT_UART_TX_COMPLETE, .hal_event = HAL_UART_TX_COMPLETE_CB_ID},
[NO_OS_EVT_UART_RX_COMPLETE] = {.event = NO_OS_EVT_UART_RX_COMPLETE, .hal_event = HAL_UART_RX_COMPLETE_CB_ID},
[NO_OS_EVT_UART_ERROR] = {.event = NO_OS_EVT_UART_ERROR, .hal_event = HAL_UART_ERROR_CB_ID},
#ifdef HAL_TIM_MODULE_ENABLED
[NO_OS_EVT_TIM_ELAPSED] = {.event = NO_OS_EVT_TIM_ELAPSED, .hal_event = HAL_TIM_PERIOD_ELAPSED_CB_ID},
[NO_OS_EVT_TIM_PWM_PULSE_FINISHED] = {.event = NO_OS_EVT_TIM_PWM_PULSE_FINISHED, .hal_event = HAL_TIM_PWM_PULSE_FINISHED_CB_ID},
#endif
#ifdef HAL_LPTIM_MODULE_ENABLED
[NO_OS_EVT_LPTIM_PWM_PULSE_FINISHED] = {.event = NO_OS_EVT_LPTIM_PWM_PULSE_FINISHED, .hal_event = HAL_LPTIM_COMPARE_MATCH_CB_ID},
#endif
#ifdef HAL_DMA_MODULE_ENABLED
[NO_OS_EVT_DMA_RX_COMPLETE] = {.event = NO_OS_EVT_DMA_RX_COMPLETE, .hal_event = HAL_DMA_XFER_CPLT_CB_ID},
[NO_OS_EVT_DMA_RX_HALF_COMPLETE] = {.event = NO_OS_EVT_DMA_RX_HALF_COMPLETE, .hal_event = HAL_DMA_XFER_HALFCPLT_CB_ID},
[NO_OS_EVT_DMA_TX_COMPLETE] = {.event = NO_OS_EVT_DMA_TX_COMPLETE, .hal_event = HAL_DMA_XFER_CPLT_CB_ID},
#endif
};
static int32_t irq_action_cmp(void *data1, void *data2)
{
return (int32_t)((struct irq_action *)data1)->handle -
(int32_t)((struct irq_action *)data2)->handle;
}
#ifdef HAL_TIM_MODULE_ENABLED
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
struct event_list *ee = &_events[NO_OS_EVT_TIM_ELAPSED];
struct irq_action *a;
struct irq_action key = {.handle = htim};
int ret;
/* Find & call callback */
ret = no_os_list_read_find(ee->actions, (void **)&a, &key);
if (ret < 0)
return;
if (a->callback)
a->callback(a->ctx);
}
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
struct event_list *ee = &_events[NO_OS_EVT_TIM_PWM_PULSE_FINISHED];
struct irq_action *a;
struct irq_action key = {.handle = htim};
int ret;
/* Find & call callback */
ret = no_os_list_read_find(ee->actions, (void **)&a, &key);
if (ret < 0)
return;
if (a->callback)
a->callback(a->ctx);
}
#endif
#ifdef HAL_LPTIM_MODULE_ENABLED
void HAL_LPTIM_CompareMatchCallback(LPTIM_HandleTypeDef *hlptim)
{
struct event_list *ee = &_events[NO_OS_EVT_LPTIM_PWM_PULSE_FINISHED];
struct irq_action *a;
struct irq_action key = {.handle = hlptim};
int ret;
/* Find & call callback */
ret = no_os_list_read_find(ee->actions, (void **)&a, &key);
if (ret < 0)
return;
if (a->callback)
a->callback(a->ctx);
}
#endif
static inline void _common_uart_callback(UART_HandleTypeDef *huart,
uint32_t no_os_event)
{
struct event_list *ue = &_events[no_os_event];
struct irq_action *a;
struct irq_action key = {.handle = huart};
int ret;
ret = no_os_list_read_find(ue->actions, (void **)&a, &key);
if (ret < 0)
return;
if (a->callback)
a->callback(a->ctx);
}
#if defined (HAL_SAI_MODULE_ENABLED)
static inline void _common_sai_dma_callback(SAI_HandleTypeDef *hsai,
uint32_t no_os_event)
{
struct event_list *ue = &_events[no_os_event];
struct irq_action *a;
struct irq_action key = {.handle = hsai};
int ret;
ret = no_os_list_read_find(ue->actions, (void **)&a, &key);
if (ret < 0)
return;
if (a->callback)
a->callback(a->ctx);
}
#endif
#if defined (HAL_DMA_MODULE_ENABLED)
static inline void _common_dma_callback(DMA_HandleTypeDef *hdma,
uint32_t no_os_event)
{
struct event_list *ue = &_events[no_os_event];
struct irq_action *a;
struct irq_action key = {.handle = hdma};
int ret;
ret = no_os_list_read_find(ue->actions, (void **)&a, &key);
if (ret < 0)
return;
if (a->callback)
a->callback(a->ctx);
}
#endif
// equivalent of HAL_UART_TxCpltCallback
void _TxCpltCallback(UART_HandleTypeDef *huart)
{
_common_uart_callback(huart, NO_OS_EVT_UART_TX_COMPLETE);
}
// equivalent of HAL_UART_RxCpltCallback
void _RxCpltCallback(UART_HandleTypeDef *huart)
{
_common_uart_callback(huart, NO_OS_EVT_UART_RX_COMPLETE);
}
#if defined (HAL_SAI_MODULE_ENABLED)
void _SAIRxCpltCallback(SAI_HandleTypeDef *hsai)
{
_common_sai_dma_callback(hsai, NO_OS_EVT_DMA_RX_COMPLETE);
}
void _SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai)
{
_common_sai_dma_callback(hsai, NO_OS_EVT_DMA_RX_HALF_COMPLETE);
}
#endif
#if defined (HAL_DMA_MODULE_ENABLED)
void _DMA_RX_CpltCallback(DMA_HandleTypeDef* hdma)
{
_common_dma_callback(hdma, NO_OS_EVT_DMA_RX_COMPLETE);
}
void _DMA_TX_CpltCallback(DMA_HandleTypeDef* hdma)
{
_common_dma_callback(hdma, NO_OS_EVT_DMA_TX_COMPLETE);
}
void _DMA_HalfCpltCallback(DMA_HandleTypeDef *hdma)
{
_common_dma_callback(hdma, NO_OS_EVT_DMA_RX_HALF_COMPLETE);
}
#endif
// equivalent of HAL_UART_ErrorCallback
void _ErrorCallback(UART_HandleTypeDef *huart)
{
_common_uart_callback(huart, NO_OS_EVT_UART_ERROR);
}
/**
* @brief Initialized the controller for the STM32 external interrupts
* @param desc - Pointer where the configured instance is stored
* @param param - Configuration information for the instance
* @return 0 in case of success, errno error codes otherwise.
*/
int stm32_irq_ctrl_init(struct no_os_irq_ctrl_desc **desc,
const struct no_os_irq_init_param *param)
{
static struct no_os_irq_ctrl_desc *descriptor;
if (!param)
return -EINVAL;
if (!initialized) {
descriptor = no_os_calloc(1, sizeof(*descriptor));
if (!descriptor)
return -ENOMEM;
}
// unused, there is only 1 interrupt controller and that is NVIC
descriptor->irq_ctrl_id = param->irq_ctrl_id;
descriptor->extra = param->extra;
*desc = descriptor;
return 0;
}
/**
* @brief Free the resources allocated by irq_ctrl_init()
* @param desc - Interrupt controller descriptor.
* @return 0 in case of success, errno error codes otherwise.
*/
int stm32_irq_ctrl_remove(struct no_os_irq_ctrl_desc *desc)
{
initialized = false;
if (desc)
no_os_free(desc);
return 0;
}
/**
* @brief Unused.
* @param desc -irq descriptor.
* @param irq_id - The interrupt vector entry id of the peripheral.
* @param level - the trigger condition.
* @return -ENOSYS
*/
int stm32_trigger_level_set(struct no_os_irq_ctrl_desc *desc,
uint32_t irq_id,
enum no_os_irq_trig_level level)
{
return -ENOSYS;
}
/**
* @brief Register a callback.
* @param desc - The IRQ controller descriptor.
* @param irq_id - Interrupt identifier.
* @param cb - Descriptor of the callback.
* @return 0 if successfull, negative error code otherwise.
*/
typedef void (*pUART_CallbackTypeDef)(UART_HandleTypeDef *huart); /*!< pointer to an UART callback function */
typedef void (*pTIM_CallbackTypeDef)(TIM_HandleTypeDef *htim); /*!< pointer to the TIM callback function */
int stm32_irq_register_callback(struct no_os_irq_ctrl_desc *desc,
uint32_t irq_id,
struct no_os_callback_desc *cb)
{
int ret;
pUART_CallbackTypeDef pUartCallback;
#ifdef HAL_SAI_MODULE_ENABLED
pSAI_CallbackTypeDef pSaiDmaCallback;
#endif
#ifdef HAL_TIM_MODULE_ENABLED
pTIM_CallbackTypeDef pTimCallback;
#endif
#ifdef HAL_LPTIM_MODULE_ENABLED
pLPTIM_CallbackTypeDef pLPTimCallback;
#endif
struct irq_action action_key = {.handle = cb->handle};
#ifdef HAL_DMA_MODULE_ENABLED
DMA_HandleTypeDef pDmaCallback;
#endif
struct irq_action *li;
uint32_t hal_event = _events[cb->event].hal_event;
switch (cb->peripheral) {
case NO_OS_UART_IRQ:
switch (hal_event) {
case HAL_UART_TX_COMPLETE_CB_ID:
pUartCallback = _TxCpltCallback;
break;
case HAL_UART_RX_COMPLETE_CB_ID:
pUartCallback = _RxCpltCallback;
break;
case HAL_UART_ERROR_CB_ID:
pUartCallback = _ErrorCallback;
break;
default:
return -EINVAL;
};
ret = HAL_UART_RegisterCallback(cb->handle, hal_event, pUartCallback);
if (ret != HAL_OK)
return -EFAULT;
break;
#ifdef HAL_LPTIM_MODULE_ENABLED
case NO_OS_LPTIM_IRQ:
switch (hal_event) {
case HAL_LPTIM_COMPARE_MATCH_CB_ID:
pLPTimCallback = HAL_LPTIM_CompareMatchCallback;
break;
default:
return -EINVAL;
};
ret = HAL_LPTIM_RegisterCallback(cb->handle, hal_event, pLPTimCallback);
if (ret != HAL_OK)
return -EFAULT;
break;
#endif
#ifdef HAL_TIM_MODULE_ENABLED
case NO_OS_TIM_IRQ:
switch (hal_event) {
case HAL_TIM_PWM_PULSE_FINISHED_CB_ID:
pTimCallback = HAL_TIM_PWM_PulseFinishedCallback;
break;
case HAL_TIM_PERIOD_ELAPSED_CB_ID:
pTimCallback = HAL_TIM_PeriodElapsedCallback;
break;
default:
return -EINVAL;
};
ret = HAL_TIM_RegisterCallback(cb->handle, hal_event, pTimCallback);
if (ret != HAL_OK)
return -EFAULT;
break;
#endif
#if defined(HAL_DMA_MODULE_ENABLED) && defined(HAL_SAI_MODULE_ENABLED)
case NO_OS_TDM_DMA_IRQ:
switch (hal_event) {
case HAL_DMA_XFER_CPLT_CB_ID:
pSaiDmaCallback = _SAIRxCpltCallback;
ret = HAL_SAI_RegisterCallback(cb->handle, hal_event, pSaiDmaCallback);
if (ret != HAL_OK)
return -EFAULT;
break;
case HAL_DMA_XFER_HALFCPLT_CB_ID:
pSaiDmaCallback = _SAI_RxHalfCpltCallback;
ret = HAL_SAI_RegisterCallback(cb->handle, hal_event, pSaiDmaCallback);
if (ret != HAL_OK)
return -EFAULT;
break;
}
break;
#endif
#if defined (HAL_TIM_MODULE_ENABLED) && defined(HAL_DMA_MODULE_ENABLED)
case NO_OS_TIM_DMA_IRQ:
switch (hal_event) {
case HAL_DMA_XFER_CPLT_CB_ID:
pDmaCallback.XferCpltCallback = _DMA_RX_CpltCallback;
ret = HAL_DMA_RegisterCallback(cb->handle, hal_event,
pDmaCallback.XferCpltCallback);
if (ret != HAL_OK)
return -EFAULT;
break;
case HAL_DMA_XFER_HALFCPLT_CB_ID:
pDmaCallback.XferHalfCpltCallback = _DMA_HalfCpltCallback;
ret = HAL_DMA_RegisterCallback(cb->handle, hal_event,
pDmaCallback.XferHalfCpltCallback);
if (ret != HAL_OK)
return -EFAULT;
break;
default:
return -EINVAL;
};
break;
#endif
#if defined (HAL_DMA_MODULE_ENABLED)
case NO_OS_DMA_IRQ:
switch (hal_event) {
case HAL_DMA_XFER_CPLT_CB_ID:
if (cb->event == NO_OS_EVT_DMA_RX_COMPLETE)
pDmaCallback.XferCpltCallback = _DMA_RX_CpltCallback;
else
pDmaCallback.XferCpltCallback = _DMA_TX_CpltCallback;
ret = HAL_DMA_RegisterCallback((DMA_HandleTypeDef *)cb->handle, hal_event,
pDmaCallback.XferCpltCallback);
if (ret != HAL_OK)
return -EFAULT;
break;
default:
return -EINVAL;
};
break;
#endif
default:
return -EINVAL;
}
if (_events[cb->event].actions == NULL) {
ret = no_os_list_init(&_events[cb->event].actions, NO_OS_LIST_PRIORITY_LIST,
irq_action_cmp);
if (ret < 0)
return ret;
}
/*
* If an action with the same handle as the function parameter does not exists, insert a new one,
* otherwise update
*/
ret = no_os_list_read_find(_events[cb->event].actions,
(void**)&li,
&action_key);
if (ret) {
li = no_os_calloc(1, sizeof(struct irq_action));
if (!li)
return -ENOMEM;
li->handle = cb->handle;
li->callback = cb->callback;
li->ctx = cb->ctx;
ret = no_os_list_add_last(_events[cb->event].actions, li);
if (ret < 0) {
no_os_free(li);
return ret;
}
} else {
li->handle = cb->handle;
li->callback = cb->callback;
li->ctx = cb->ctx;
}
return 0;
}
/**
* @brief Unregister a callback.
* @param desc - Interrupt controller descriptor.
* @param irq_id - Id of the interrupt
* @param cb - Descriptor of the callback.
* @return 0 if successfull, negative error code otherwise.
*/
int stm32_irq_unregister_callback(struct no_os_irq_ctrl_desc *desc,
uint32_t irq_id, struct no_os_callback_desc *cb)
{
int ret;
void *discard = NULL;
struct irq_action key;
uint32_t hal_event = _events[cb->event].hal_event;
switch (cb->peripheral) {
case NO_OS_UART_IRQ:
key.handle = cb->handle;
ret = no_os_list_get_find(_events[cb->event].actions, &discard, &key);
if (ret < 0)
break;
ret = HAL_UART_UnRegisterCallback(cb->handle, hal_event);
if (ret != HAL_OK)
ret = -EFAULT;
break;
#ifdef HAL_TIM_MODULE_ENABLED
case NO_OS_TIM_IRQ:
key.handle = cb->handle;
ret = no_os_list_get_find(_events[cb->event].actions, &discard, &key);
if (ret < 0)
break;
ret = HAL_TIM_UnRegisterCallback(cb->handle, hal_event);
if (ret != HAL_OK)
ret = -EFAULT;
break;
#endif
#if defined(HAL_DMA_MODULE_ENABLED) && defined(HAL_SAI_MODULE_ENABLED)
case NO_OS_TDM_DMA_IRQ:
key.handle = cb->handle;
ret = no_os_list_get_find(_events[cb->event].actions, &discard, &key);
if (ret < 0)
break;
ret = HAL_SAI_UnRegisterCallback(cb->handle, hal_event);
if (ret != HAL_OK)
ret = -EFAULT;
break;
#endif
#if defined (HAL_TIM_MODULE_ENABLED) && defined(HAL_DMA_MODULE_ENABLED)
case NO_OS_TIM_DMA_IRQ:
case NO_OS_DMA_IRQ:
key.handle = cb->handle;
ret = no_os_list_get_find(_events[cb->event].actions, &discard, &key);
if (ret < 0)
break;
ret = HAL_DMA_UnRegisterCallback(cb->handle, hal_event);
if (ret != HAL_OK)
ret = -EFAULT;
break;
#endif
default:
ret = -EINVAL;
break;
}
if (discard)
no_os_free(discard);
return ret;
}
/**
* @brief Enable all interrupts
* @param desc - Interrupt controller descriptor.
* @return 0
*/
int stm32_irq_global_enable(struct no_os_irq_ctrl_desc *desc)
{
__enable_irq();
return 0;
}
/**
* @brief Disable all interrupts
* @param desc - Interrupt controller descriptor.
* @return 0
*/
int stm32_irq_global_disable(struct no_os_irq_ctrl_desc *desc)
{
__disable_irq();
return 0;
}
/**
* @brief Enable a specific interrupt
* @param desc - Interrupt controller descriptor.
* @param irq_id - Interrupt identifier
* @return 0 in case of success, errno error codes otherwise.
*/
int stm32_irq_enable(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id)
{
NVIC_EnableIRQ(irq_id);
return 0;
}
/**
* @brief Disable a specific interrupt
* @param desc - Interrupt controller descriptor.
* @param irq_id - Interrupt identifier
* @return 0 in case of success, -EINVAL otherwise.
*/
int stm32_irq_disable(struct no_os_irq_ctrl_desc *desc, uint32_t irq_id)
{
NVIC_DisableIRQ(irq_id);
return 0;
}
/**
* @brief Set a priority level for an interrupt
* @param desc - Interrupt controller descriptor.
* @param irq_id - The interrupt vector entry id of the peripheral.
* @param priority_level - The interrupt priority level
* @return 0
*/
static int stm32_irq_set_priority(struct no_os_irq_ctrl_desc *desc,
uint32_t irq_id,
uint32_t priority_level)
{
HAL_NVIC_SetPriority(irq_id, priority_level, 0);
return 0;
}
/**
* @brief Get a priority level for an interrupt
* @param desc - Interrupt controller descriptor.
* @param irq_id - The interrupt vector entry id of the peripheral.
* @param priority_level - The interrupt priority level
* @return 0
*/
static int stm32_irq_get_priority(struct no_os_irq_ctrl_desc *desc,
uint32_t irq_id,
uint32_t *priority_level)
{
uint32_t priority_group, sub_priority;
priority_group = HAL_NVIC_GetPriorityGrouping();
HAL_NVIC_GetPriority(irq_id, priority_group, priority_level, &sub_priority);
return 0;
}
/**
* @brief stm32 specific IRQ platform ops structure
*/
const struct no_os_irq_platform_ops stm32_irq_ops = {
.init = &stm32_irq_ctrl_init,
.trigger_level_set = &stm32_trigger_level_set,
.register_callback = &stm32_irq_register_callback,
.unregister_callback = &stm32_irq_unregister_callback,
.global_enable = &stm32_irq_global_enable,
.global_disable = &stm32_irq_global_disable,
.enable = &stm32_irq_enable,
.disable = &stm32_irq_disable,
.set_priority = &stm32_irq_set_priority,
.get_priority = &stm32_irq_get_priority,
.remove = &stm32_irq_ctrl_remove
};
@@ -0,0 +1,44 @@
/***************************************************************************//**
* @file stm32/stm32_irq.h
* @brief Header file for stm32 irq specifics.
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* Copyright 2022(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef STM32_IRQ_H
#define STM32_IRQ_H
#include "no_os_irq.h"
#include "stm32_hal.h"
/**
* @brief stm32 platform specific irq platform ops structure
*/
extern const struct no_os_irq_platform_ops stm32_irq_ops;
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,151 @@
/***************************************************************************//**
* @file stm32/stm32_pwm.h
* @brief Header file for stm32 pwm specifics.
********************************************************************************
* Copyright 2023(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef STM32_PWM_H_
#define STM32_PWM_H_
#include <stdint.h>
#include <stdbool.h>
#include "no_os_gpio.h"
#include "no_os_irq.h"
#include "stm32_gpio.h"
#include "stm32_hal.h"
enum stm32_pwm_timer {
STM32_PWM_TIMER_TIM = 0,
STM32_PWM_TIMER_LPTIM = 1,
};
enum TimOCMode {
TIM_OC_TOGGLE = 0,
TIM_OC_PWM1 = 1,
TIM_OC_PWM2 = 2,
};
enum stm32_pwm_trigger {
PWM_TS_ITR0,
PWM_TS_ITR1,
PWM_TS_ITR2,
PWM_TS_ITR3,
};
enum stm32_pwm_trigger_out {
PWM_TRGO_RESET,
PWM_TRGO_ENABLE,
PWM_TRGO_UPDATE,
PWM_TRGO_OC1,
PWM_TRGO_OC1REF,
PWM_TRGO_OC2REF,
PWM_TRGO_OC3REF,
PWM_TRGO_OC4REF,
};
/**
* @struct stm32_pwm_init_param
* @brief Structure holding the STM32 PWM parameters.
*/
struct stm32_pwm_init_param {
/** PWM Timer Handle */
void *htimer;
/** Type of timer used for PWM */
enum stm32_pwm_timer pwm_timer;
/** Timer prescaler (0 to 0xFFFF) */
uint32_t prescaler;
/** Timer autoreload enable */
bool timer_autoreload;
/** Timer output compare Mode */
enum TimOCMode mode;
/** PWM timer channel */
uint32_t timer_chn;
/** Complementary channel */
bool complementary_channel;
/** Get timer source clock function */
uint32_t (*get_timer_clock)(void);
/** Get timer source clock divider */
uint32_t clock_divider;
/** Enable trigger source */
bool trigger_enable;
/** Trigger source selection */
enum stm32_pwm_trigger trigger_source;
/** Trigger out selection */
enum stm32_pwm_trigger_out trigger_output;
/* Enable one pulse */
bool onepulse_enable;
/* Number of pulse repetitions */
uint32_t repetitions;
/* Enable dma */
bool dma_enable;
/** Timer callback */
struct no_os_callback_desc timer_callback;
};
/**
* @struct stm32_pwm_desc
* @brief Structure holding the STM32 PWM descriptor.
*/
struct stm32_pwm_desc {
/** PWM Timer Handle */
void *htimer;
/** Type of timer used for PWM */
enum stm32_pwm_timer pwm_timer;
/** Timer GPIO instance */
struct no_os_gpio_desc *gpio;
/** Timer prescaler */
uint32_t prescaler;
/** Timer autoreload enable */
bool timer_autoreload;
/** Timer output compare Mode */
enum TimOCMode mode;
/** PWM timer channel */
uint32_t timer_chn;
/** Complementary channel */
bool complementary_channel;
/** Get timer source clock function */
uint32_t (*get_timer_clock)(void);
/** Get timer source clock divider */
uint32_t clock_divider;
/** Interrupt controller descriptor */
struct no_os_irq_ctrl_desc *nvic_tim;
/** Timer callback */
struct no_os_callback_desc timer_callback;
/* Number of pulse repetitions */
uint32_t repetitions;
/* Enable dma */
bool dma_enable;
/* Enable one pulse */
bool onepulse_enable;
};
/**
* @brief STM32 specific PWM platform ops structure
*/
extern const struct no_os_pwm_platform_ops stm32_pwm_ops;
#endif // STM32_PWM_H_
@@ -0,0 +1,53 @@
#include "stm32_spi.h"
#include "no_os_error.h"
#include <stdlib.h>
int32_t stm32_spi_init(struct no_os_spi_desc **desc,
const struct no_os_spi_init_param *param)
{
if (!desc || !param)
return -EINVAL;
*desc = calloc(1, sizeof(**desc));
if (!*desc)
return -ENOMEM;
/* store platform handle (HAL SPI_HandleTypeDef*) in extra */
(*desc)->extra = param->extra;
(*desc)->max_speed_hz = param->max_speed_hz;
(*desc)->mode = param->mode;
return 0;
}
int32_t stm32_spi_write_and_read(struct no_os_spi_desc *desc,
uint8_t *data,
uint32_t bytes_number)
{
if (!desc || !data || bytes_number == 0)
return -EINVAL;
SPI_HandleTypeDef *hspi = (SPI_HandleTypeDef *)desc->extra;
if (!hspi)
return -EINVAL;
if (HAL_SPI_TransmitReceive(hspi, data, data, bytes_number, 200) != HAL_OK)
return -EIO;
return 0;
}
int32_t stm32_spi_remove(struct no_os_spi_desc *desc)
{
if (!desc)
return -EINVAL;
free(desc);
return 0;
}
/* platform ops struct */
const struct no_os_spi_platform_ops stm32_spi_ops = {
.init = &stm32_spi_init,
.write_and_read = &stm32_spi_write_and_read,
.remove = &stm32_spi_remove,
};
@@ -0,0 +1,9 @@
#ifndef _STM32_SPI_H_
#define _STM32_SPI_H_
#include "no_os_spi.h"
#include "stm32f7xx_hal.h"
extern const struct no_os_spi_platform_ops stm32_spi_ops;
#endif /* _STM32_SPI_H_ */
@@ -0,0 +1,352 @@
/***************************************************************************//**
* @file stm32/stm32_timer.c
* @brief Implementation of stm32 timer driver.
* @author RBolboac (ramona.bolboaca@analog.com)
********************************************************************************
* Copyright 2022(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <stdlib.h>
#include <errno.h>
#include "no_os_util.h"
#include "no_os_timer.h"
#include "no_os_alloc.h"
#include "stm32_timer.h"
static int get_timer_base(uint32_t device_id, TIM_TypeDef **base,
uint32_t *clk_freq)
{
uint32_t apb2_freq = HAL_RCC_GetPCLK2Freq();
*clk_freq = HAL_RCC_GetPCLK1Freq();
switch (device_id) {
#if defined(TIM1)
case 1:
*base = TIM1;
*clk_freq = apb2_freq;
break;
#endif
#if defined(TIM2)
case 2:
*base = TIM2;
break;
#endif
#if defined(TIM3)
case 3:
*base = TIM3;
break;
#endif
break;
#if defined(TIM4)
case 4:
*base = TIM4;
break;
#endif
#if defined(TIM5)
case 5:
*base = TIM5;
break;
#endif
#if defined(TIM6)
case 6:
*base = TIM6;
break;
#endif
#if defined(TIM7)
case 7:
*base = TIM7;
break;
#endif
#if defined(TIM8)
case 8:
*base = TIM8;
*clk_freq = apb2_freq;
break;
#endif
#if defined(TIM9)
case 9:
*base = TIM9;
break;
#endif
#if defined(TIM10)
case 10:
*base = TIM10;
break;
#endif
#if defined(TIM11)
case 11:
*base = TIM11;
break;
#endif
#if defined(TIM12)
case 12:
*base = TIM12;
break;
#endif
#if defined(TIM13)
case 13:
*base = TIM13;
break;
#endif
#if defined(TIM14)
case 14:
*base = TIM14;
break;
#endif
default:
return -EINVAL;
};
return 0;
}
/**
* @brief Initialize the timer peripheral.
* @param desc - The timer descriptor.
* @param param - The structure that contains the timer parameters.
* @return ret - Result of the init procedure.
*/
int32_t stm32_timer_init(struct no_os_timer_desc **desc,
const struct no_os_timer_init_param *param)
{
int32_t ret;
struct no_os_timer_desc *no_os_desc;
struct stm32_timer_desc *stm_desc;
uint32_t src_freq;
TIM_TypeDef *base = NULL;
if (!desc || !param)
return -EINVAL;
no_os_desc = (struct no_os_timer_desc *)no_os_calloc(1, sizeof(*no_os_desc));
if (!no_os_desc)
return -ENOMEM;
stm_desc = param->extra;
ret = get_timer_base(param->id, &base, &src_freq);
if (ret)
goto error;
/* Make sure the same id is used as the selected instance */
if (base != stm_desc->htimer->Instance) {
ret = -EINVAL;
goto error;
}
/* Make sure the selected frequency is in range */
if (src_freq < param->freq_hz) {
ret = -EINVAL;
goto error;
}
/* Overwrite generated values with given values */
stm_desc->htimer->Init.Prescaler = src_freq / param->freq_hz;
stm_desc->htimer->Init.Period = param->ticks_count;
ret = HAL_TIM_Base_Init(stm_desc->htimer);
if (ret != HAL_OK) {
ret = -EIO;
goto error;
}
/* Copy settings to device descriptor */
no_os_desc->extra = stm_desc->htimer;
no_os_desc->id = param->id;
no_os_desc->freq_hz = param->freq_hz;
no_os_desc->ticks_count = param->ticks_count;
*desc = no_os_desc;
return 0;
error:
no_os_free(no_os_desc);
return ret;
}
/**
* @brief Free the resources allocated by no_os_timer_init().
* @param desc - The timer descriptor.
*
* @return ret - Result of the remove procedure.
*/
int32_t stm32_timer_remove(struct no_os_timer_desc *desc)
{
if (!desc)
return -EINVAL;
if (!HAL_TIM_Base_DeInit(desc->extra)) {
no_os_free(desc);
return 0;
}
return -1;
}
/**
* @brief Start a timer.
* @param desc - Pointer to the device handler.
*
* @return ret - Result of the start procedure.
*/
int32_t stm32_timer_start(struct no_os_timer_desc *desc)
{
if (!desc)
return -EINVAL;
if (!HAL_TIM_Base_Start_IT((TIM_HandleTypeDef*)desc->extra))
return 0;
return -1;
}
/**
* @brief Stop a timer from counting.
* @param desc - Pointer to the device handler.
*
* @return ret - Result of the stop procedure.
*/
int32_t stm32_timer_stop(struct no_os_timer_desc *desc)
{
if (!desc)
return -EINVAL;
if (!HAL_TIM_Base_Stop_IT((TIM_HandleTypeDef*)desc->extra))
return 0;
return -1;
}
/**
* @brief Get the value of the counter register for the timer.
* @param [in] desc - Pointer to the device handler.
* @param [out] counter - Pointer to the counter value.
* @return 0 in case of success, error code otherwise.
*/
int32_t stm32_timer_counter_get(struct no_os_timer_desc *desc,
uint32_t *counter)
{
if (!desc && !counter)
return -EINVAL;
*counter = __HAL_TIM_GetCounter((TIM_HandleTypeDef*)desc->extra);
return 0;
}
/**
* @brief Set the timer counter register value.
* @param [in] desc - Pointer to the device handler.
* @param [in] new_val - The new value of the counter register.
* @return 0 in case of success, error code otherwise.
*/
int32_t stm32_timer_counter_set(struct no_os_timer_desc *desc, uint32_t new_val)
{
if (!desc || (new_val > desc->ticks_count))
return -EINVAL;
__HAL_TIM_SetCounter((TIM_HandleTypeDef*)desc->extra, new_val);
return 0;
}
/**
* @brief Get the timer clock frequency.
* @param [in] desc - Pointer to the device handler.
* @param [out] freq_hz - The value in Hz of the timer clock.
* @return 0 in case of success, error code otherwise.
*/
int32_t stm32_timer_count_clk_get(struct no_os_timer_desc *desc,
uint32_t *freq_hz)
{
if (!desc || !freq_hz)
return -EINVAL;
*freq_hz = desc->freq_hz;
return 0;
}
/**
* @brief Set the timer clock frequency.
* @param [in] desc - Pointer to the device handler.
* @param [in] freq_hz - The value in Hz of the new timer clock.
* @return 0 in case of success, error code otherwise.
*/
int32_t stm32_timer_count_clk_set(struct no_os_timer_desc *desc,
uint32_t freq_hz)
{
int ret;
uint32_t src_freq;
TIM_TypeDef *base = NULL;
TIM_HandleTypeDef* tim_desc;
if (!desc)
return -EINVAL;
ret = get_timer_base(desc->id, &base, &src_freq);
if (ret)
return -EINVAL;
if (src_freq < freq_hz)
return -EINVAL;
tim_desc = desc->extra;
__HAL_TIM_SET_PRESCALER(tim_desc, src_freq / freq_hz);
tim_desc->Init.Prescaler = src_freq / freq_hz;
desc->freq_hz = freq_hz;
return 0;
}
/**
* @brief Get the elapsed time in nsec for the timer.
* @param [in] desc - Pointer to the device handler.
* @param [in] elapsed_time - The elapsed time in nsec.
* @return 0 in case of success, error code otherwise.
*/
int32_t stm32_timer_get_elapsed_time_nsec(struct no_os_timer_desc *desc,
uint64_t *elapsed_time)
{
/* Function not implemented because it is not needed at the moment */
return -ENOSYS;
}
/**
* @brief stm32 platform specific timer platform ops structure
*/
const struct no_os_timer_platform_ops stm32_timer_ops = {
.init = &stm32_timer_init,
.start = &stm32_timer_start,
.stop = &stm32_timer_stop,
.counter_get = &stm32_timer_counter_get,
.counter_set = &stm32_timer_counter_set,
.count_clk_get = &stm32_timer_count_clk_get,
.count_clk_set = &stm32_timer_count_clk_set,
.get_elapsed_time_nsec = &stm32_timer_get_elapsed_time_nsec,
.remove = &stm32_timer_remove
};
@@ -0,0 +1,63 @@
/***************************************************************************//**
* @file stm32/stm32_timer.h
* @brief Header file for the stm32 timer driver.
* @author RBolboac (ramona.bolboaca@analog.com)
********************************************************************************
* Copyright 2022(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef STM32_TIMER_H_
#define STM32_TIMER_H_
#include <stdint.h>
#include "no_os_timer.h"
#include "stm32_hal.h"
/**
* @struct stm32_timer_init_param
* @brief Structure holding the initialization parameters for stm32 platform
* specific timer parameters.
*/
struct stm32_timer_init_param {
TIM_HandleTypeDef *htimer;
};
/**
* @struct stm32_timer_desc
* @brief stm32 platform specific timer descriptor
*/
struct stm32_timer_desc {
/** timer instance */
TIM_HandleTypeDef *htimer;
};
/**
* @brief stm32 specific timer platform ops structure
*/
extern const struct no_os_timer_platform_ops stm32_timer_ops;
#endif // STM32_TIMER_H_
@@ -0,0 +1,302 @@
/***************************************************************************//**
* @file stm32/stm32_uart.c
* @brief Source file of UART driver for STM32
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <errno.h>
#include <stdlib.h>
#include "no_os_uart.h"
#include "no_os_irq.h"
#include "no_os_lf256fifo.h"
#include "no_os_alloc.h"
#include "stm32_irq.h"
#include "stm32_uart.h"
#include "stm32_hal.h"
static uint8_t c;
void uart_rx_callback(void *context)
{
struct no_os_uart_desc *d = context;
lf256fifo_write(d->rx_fifo, c);
HAL_UART_Receive_IT(((struct stm32_uart_desc *)d->extra)->huart, &c, 1);
}
/**
* @brief Initialize the UART communication peripheral.
* @param desc - The UART descriptor.
* @param param - The structure that contains the UART parameters.
* @return 0 in case of success, error code otherwise.
*/
static int32_t stm32_uart_init(struct no_os_uart_desc **desc,
struct no_os_uart_init_param *param)
{
struct stm32_uart_init_param *suip;
struct stm32_uart_desc *sud;
struct no_os_uart_desc *descriptor;
int ret;
if (!desc || !param)
return -EINVAL;
descriptor = (struct no_os_uart_desc *) no_os_calloc(1, sizeof(*descriptor));
if (!descriptor)
return -ENOMEM;
sud = (struct stm32_uart_desc *) no_os_calloc(1,
sizeof(struct stm32_uart_desc));
if (!sud) {
ret = -ENOMEM;
goto error;
}
descriptor->irq_id = param->irq_id;
descriptor->extra = sud;
suip = param->extra;
sud->huart = suip->huart;
sud->huart->Init.BaudRate = param->baud_rate;
switch (param->size) {
case NO_OS_UART_CS_8:
sud->huart->Init.WordLength = UART_WORDLENGTH_8B;
break;
case NO_OS_UART_CS_9:
sud->huart->Init.WordLength = UART_WORDLENGTH_9B;
break;
default:
ret = -EINVAL;
goto error;
};
switch (param->parity) {
case NO_OS_UART_PAR_NO:
sud->huart->Init.Parity = UART_PARITY_NONE;
break;
case NO_OS_UART_PAR_ODD:
sud->huart->Init.Parity = UART_PARITY_ODD;
break;
case NO_OS_UART_PAR_EVEN:
sud->huart->Init.Parity = UART_PARITY_EVEN;
break;
default:
ret = -EINVAL;
goto error;
};
sud->huart->Init.StopBits = param->stop == NO_OS_UART_STOP_1_BIT ?
UART_STOPBITS_1 :
UART_STOPBITS_2;
sud->huart->Init.Mode = suip->huart->Init.Mode;
sud->huart->Init.HwFlowCtl = suip->huart->Init.HwFlowCtl;
sud->huart->Init.OverSampling = suip->huart->Init.OverSampling;
ret = HAL_UART_Init(sud->huart);
if (ret != HAL_OK) {
ret = -EIO;
goto error;
}
sud->timeout = suip->timeout ? suip->timeout : HAL_MAX_DELAY;
// nonblocking uart_read
if (param->asynchronous_rx) {
ret = lf256fifo_init(&descriptor->rx_fifo);
if (ret < 0)
goto error;
struct no_os_irq_init_param nvic_ip = {
.platform_ops = &stm32_irq_ops,
.extra = sud->huart,
};
ret = no_os_irq_ctrl_init(&sud->nvic, &nvic_ip);
if (ret < 0)
goto error;
sud->rx_callback.callback = uart_rx_callback;
sud->rx_callback.ctx = descriptor;
sud->rx_callback.event = NO_OS_EVT_UART_RX_COMPLETE;
sud->rx_callback.peripheral = NO_OS_UART_IRQ;
sud->rx_callback.handle = sud->huart;
ret = no_os_irq_register_callback(sud->nvic, descriptor->irq_id,
&sud->rx_callback);
if (ret < 0)
goto error_nvic;
ret = no_os_irq_enable(sud->nvic, descriptor->irq_id);
if (ret < 0)
goto error_register;
HAL_UART_Receive_IT(sud->huart, (uint8_t *)&c, 1);
if (ret != HAL_OK) {
ret = -EIO;
goto error_enable;
}
}
descriptor->device_id = param->device_id;
descriptor->baud_rate = param->baud_rate;
*desc = descriptor;
return 0;
error_enable:
no_os_irq_disable(sud->nvic, descriptor->irq_id);
error_register:
no_os_irq_unregister_callback(sud->nvic, descriptor->irq_id, &sud->rx_callback);
error_nvic:
no_os_irq_ctrl_remove(sud->nvic);
error:
no_os_free(descriptor);
no_os_free(sud);
return ret;
}
/**
* @brief Free the resources allocated by stm32_uart_init().
* @param desc - The UART descriptor.
* @return 0 in case of success, -1 otherwise.
*/
static int32_t stm32_uart_remove(struct no_os_uart_desc *desc)
{
struct stm32_uart_desc *sud;
if (!desc)
return -EINVAL;
sud = desc->extra;
HAL_UART_DeInit(sud->huart);
if (desc->rx_fifo) {
no_os_irq_disable(sud->nvic, desc->irq_id);
lf256fifo_remove(desc->rx_fifo);
desc->rx_fifo = NULL;
no_os_irq_unregister_callback(sud->nvic, desc->irq_id, &sud->rx_callback);
no_os_irq_ctrl_remove(sud->nvic);
}
no_os_free(desc->extra);
no_os_free(desc);
return 0;
};
/**
* @brief Write data to UART device.
* @param desc - Instance of UART.
* @param data - Pointer to buffer containing data.
* @param bytes_number - Number of bytes to read.
* @return 0 in case of success, -1 otherwise.
*/
static int32_t stm32_uart_write(struct no_os_uart_desc *desc,
const uint8_t *data,
uint32_t bytes_number)
{
struct stm32_uart_desc *sud;
int32_t ret;
if (!desc || !desc->extra || !data)
return -EINVAL;
if (!bytes_number)
return 0;
sud = desc->extra;
ret = HAL_UART_Transmit(sud->huart, (uint8_t *)data, bytes_number,
sud->timeout);
switch (ret) {
case HAL_OK:
break;
case HAL_BUSY:
return -EBUSY;
case HAL_TIMEOUT:
return -ETIMEDOUT;
default:
return -EIO;
};
return bytes_number;
}
/**
* @brief Read data from UART device.
* @param desc - Instance of UART.
* @param data - Pointer to buffer containing data.
* @param bytes_number - Number of bytes to read.
* @return positive number of received bytes in case of success, negative error code otherwise.
*/
static int32_t stm32_uart_read(struct no_os_uart_desc *desc, uint8_t *data,
uint32_t bytes_number)
{
struct stm32_uart_desc *sud;
uint32_t i = 0;
int32_t ret;
if (!desc || !desc->extra || !data)
return -EINVAL;
if (!bytes_number)
return 0;
sud = desc->extra;
if (desc->rx_fifo) {
while (i < bytes_number) {
ret = lf256fifo_read(desc->rx_fifo, &data[i]);
if (ret < 0)
return i ? i : -EAGAIN;
i++;
}
return i;
} else {
ret = HAL_UART_Receive(sud->huart, (uint8_t *)data, bytes_number,
sud->timeout);
switch (ret) {
case HAL_OK:
break;
case HAL_BUSY:
return -EBUSY;
case HAL_TIMEOUT:
return -ETIMEDOUT;
default:
return -EIO;
};
}
return bytes_number;
}
/**
* @brief STM32 platform specific UART platform ops structure
*/
const struct no_os_uart_platform_ops stm32_uart_ops = {
.init = &stm32_uart_init,
.read = &stm32_uart_read,
.write = &stm32_uart_write,
.remove = &stm32_uart_remove
};
@@ -0,0 +1,73 @@
/***************************************************************************//**
* @file stm32/stm32_uart.h
* @brief Header file of UART driver for STM32
* @author Darius Berghe (darius.berghe@analog.com)
********************************************************************************
* Copyright 2020(c) Analog Devices, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of Analog Devices, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#ifndef _STM32_UART_H_
#define _STM32_UART_H_
#include <stdint.h>
#include <stdbool.h>
#include "no_os_uart.h"
#include "no_os_irq.h"
#include "stm32_hal.h"
/**
* @struct stm32_uart_init_param
* @brief Specific initialization parameters for stm32 UART.
*/
struct stm32_uart_init_param {
/** UART instance */
UART_HandleTypeDef *huart;
/** UART transaction timeout (HAL_IncTick() units) */
uint32_t timeout;
};
/**
* @struct stm32_uart_desc
* @brief stm32 platform specific UART descriptor
*/
struct stm32_uart_desc {
/** UART instance */
UART_HandleTypeDef *huart;
/** UART transaction timeout (HAL_IncTick() units) */
uint32_t timeout;
/** Interrupt controller descriptor */
struct no_os_irq_ctrl_desc *nvic;
/** RX complete callback */
struct no_os_callback_desc rx_callback;
};
/**
* @brief STM32 specific UART platform ops structure
*/
extern const struct no_os_uart_platform_ops stm32_uart_ops;
#endif
@@ -0,0 +1,484 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file stm32f7xx_hal_conf_template.h
* @author MCD Application Team
* @brief HAL configuration template file.
* This file should be copied to the application folder and renamed
* to stm32f7xx_hal_conf.h.
******************************************************************************
* @attention
*
* Copyright (c) 2017 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F7xx_HAL_CONF_H
#define __STM32F7xx_HAL_CONF_H
#ifdef __cplusplus
extern "C" {
#endif
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
*/
#define HAL_MODULE_ENABLED
/* #define HAL_CRYP_MODULE_ENABLED */
/* #define HAL_ADC_MODULE_ENABLED */
/* #define HAL_CAN_MODULE_ENABLED */
/* #define HAL_CEC_MODULE_ENABLED */
/* #define HAL_CRC_MODULE_ENABLED */
/* #define HAL_DAC_MODULE_ENABLED */
/* #define HAL_DCMI_MODULE_ENABLED */
/* #define HAL_DMA2D_MODULE_ENABLED */
/* #define HAL_ETH_MODULE_ENABLED */
/* #define HAL_ETH_LEGACY_MODULE_ENABLED */
/* #define HAL_NAND_MODULE_ENABLED */
/* #define HAL_NOR_MODULE_ENABLED */
/* #define HAL_SRAM_MODULE_ENABLED */
/* #define HAL_SDRAM_MODULE_ENABLED */
/* #define HAL_HASH_MODULE_ENABLED */
/* #define HAL_I2S_MODULE_ENABLED */
/* #define HAL_IWDG_MODULE_ENABLED */
/* #define HAL_LPTIM_MODULE_ENABLED */
/* #define HAL_LTDC_MODULE_ENABLED */
/* #define HAL_QSPI_MODULE_ENABLED */
/* #define HAL_RNG_MODULE_ENABLED */
/* #define HAL_RTC_MODULE_ENABLED */
/* #define HAL_SAI_MODULE_ENABLED */
/* #define HAL_SD_MODULE_ENABLED */
/* #define HAL_MMC_MODULE_ENABLED */
/* #define HAL_SPDIFRX_MODULE_ENABLED */
#define HAL_SPI_MODULE_ENABLED
#define HAL_TIM_MODULE_ENABLED
#define HAL_UART_MODULE_ENABLED
/* #define HAL_USART_MODULE_ENABLED */
/* #define HAL_IRDA_MODULE_ENABLED */
/* #define HAL_SMARTCARD_MODULE_ENABLED */
/* #define HAL_WWDG_MODULE_ENABLED */
#define HAL_PCD_MODULE_ENABLED
/* #define HAL_HCD_MODULE_ENABLED */
/* #define HAL_DFSDM_MODULE_ENABLED */
/* #define HAL_DSI_MODULE_ENABLED */
/* #define HAL_JPEG_MODULE_ENABLED */
/* #define HAL_MDIOS_MODULE_ENABLED */
/* #define HAL_SMBUS_MODULE_ENABLED */
/* #define HAL_EXTI_MODULE_ENABLED */
#define HAL_GPIO_MODULE_ENABLED
#define HAL_EXTI_MODULE_ENABLED
#define HAL_DMA_MODULE_ENABLED
#define HAL_RCC_MODULE_ENABLED
#define HAL_FLASH_MODULE_ENABLED
#define HAL_PWR_MODULE_ENABLED
#define HAL_I2C_MODULE_ENABLED
#define HAL_CORTEX_MODULE_ENABLED
/* ########################## HSE/HSI Values adaptation ##################### */
/**
* @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
* This value is used by the RCC HAL module to compute the system frequency
* (when HSE is used as system clock source, directly or through the PLL).
*/
#if !defined (HSE_VALUE)
#define HSE_VALUE ((uint32_t)25000000U) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
#if !defined (HSE_STARTUP_TIMEOUT)
#define HSE_STARTUP_TIMEOUT ((uint32_t)100U) /*!< Time out for HSE start up, in ms */
#endif /* HSE_STARTUP_TIMEOUT */
/**
* @brief Internal High Speed oscillator (HSI) value.
* This value is used by the RCC HAL module to compute the system frequency
* (when HSI is used as system clock source, directly or through the PLL).
*/
#if !defined (HSI_VALUE)
#define HSI_VALUE ((uint32_t)16000000U) /*!< Value of the Internal oscillator in Hz*/
#endif /* HSI_VALUE */
/**
* @brief Internal Low Speed oscillator (LSI) value.
*/
#if !defined (LSI_VALUE)
#define LSI_VALUE ((uint32_t)32000U) /*!< LSI Typical Value in Hz*/
#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
The real value may vary depending on the variations
in voltage and temperature. */
/**
* @brief External Low Speed oscillator (LSE) value.
*/
#if !defined (LSE_VALUE)
#define LSE_VALUE ((uint32_t)32768U) /*!< Value of the External Low Speed oscillator in Hz */
#endif /* LSE_VALUE */
#if !defined (LSE_STARTUP_TIMEOUT)
#define LSE_STARTUP_TIMEOUT ((uint32_t)5000U) /*!< Time out for LSE start up, in ms */
#endif /* LSE_STARTUP_TIMEOUT */
/**
* @brief External clock source for I2S peripheral
* This value is used by the I2S HAL module to compute the I2S clock source
* frequency, this source is inserted directly through I2S_CKIN pad.
*/
#if !defined (EXTERNAL_CLOCK_VALUE)
#define EXTERNAL_CLOCK_VALUE ((uint32_t)12288000U) /*!< Value of the Internal oscillator in Hz*/
#endif /* EXTERNAL_CLOCK_VALUE */
/* Tip: To avoid modifying this file each time you need to use different HSE,
=== you can define the HSE value in your toolchain compiler preprocessor. */
/* ########################### System Configuration ######################### */
/**
* @brief This is the HAL system configuration section
*/
#define VDD_VALUE 3300U /*!< Value of VDD in mv */
#define TICK_INT_PRIORITY ((uint32_t)15U) /*!< tick interrupt priority */
#define USE_RTOS 0U
#define PREFETCH_ENABLE 0U
#define ART_ACCELERATOR_ENABLE 0U /* To enable instruction cache and prefetch */
#define USE_HAL_ADC_REGISTER_CALLBACKS 0U /* ADC register callback disabled */
#define USE_HAL_CAN_REGISTER_CALLBACKS 0U /* CAN register callback disabled */
#define USE_HAL_CEC_REGISTER_CALLBACKS 0U /* CEC register callback disabled */
#define USE_HAL_CRYP_REGISTER_CALLBACKS 0U /* CRYP register callback disabled */
#define USE_HAL_DAC_REGISTER_CALLBACKS 0U /* DAC register callback disabled */
#define USE_HAL_DCMI_REGISTER_CALLBACKS 0U /* DCMI register callback disabled */
#define USE_HAL_DFSDM_REGISTER_CALLBACKS 0U /* DFSDM register callback disabled */
#define USE_HAL_DMA2D_REGISTER_CALLBACKS 0U /* DMA2D register callback disabled */
#define USE_HAL_DSI_REGISTER_CALLBACKS 0U /* DSI register callback disabled */
#define USE_HAL_ETH_REGISTER_CALLBACKS 0U /* ETH register callback disabled */
#define USE_HAL_HASH_REGISTER_CALLBACKS 0U /* HASH register callback disabled */
#define USE_HAL_HCD_REGISTER_CALLBACKS 0U /* HCD register callback disabled */
#define USE_HAL_I2C_REGISTER_CALLBACKS 0U /* I2C register callback disabled */
#define USE_HAL_I2S_REGISTER_CALLBACKS 0U /* I2S register callback disabled */
#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U /* IRDA register callback disabled */
#define USE_HAL_JPEG_REGISTER_CALLBACKS 0U /* JPEG register callback disabled */
#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0U /* LPTIM register callback disabled */
#define USE_HAL_LTDC_REGISTER_CALLBACKS 0U /* LTDC register callback disabled */
#define USE_HAL_MDIOS_REGISTER_CALLBACKS 0U /* MDIOS register callback disabled */
#define USE_HAL_MMC_REGISTER_CALLBACKS 0U /* MMC register callback disabled */
#define USE_HAL_NAND_REGISTER_CALLBACKS 0U /* NAND register callback disabled */
#define USE_HAL_NOR_REGISTER_CALLBACKS 0U /* NOR register callback disabled */
#define USE_HAL_PCD_REGISTER_CALLBACKS 0U /* PCD register callback disabled */
#define USE_HAL_QSPI_REGISTER_CALLBACKS 0U /* QSPI register callback disabled */
#define USE_HAL_RNG_REGISTER_CALLBACKS 0U /* RNG register callback disabled */
#define USE_HAL_RTC_REGISTER_CALLBACKS 0U /* RTC register callback disabled */
#define USE_HAL_SAI_REGISTER_CALLBACKS 0U /* SAI register callback disabled */
#define USE_HAL_SD_REGISTER_CALLBACKS 0U /* SD register callback disabled */
#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U /* SMARTCARD register callback disabled */
#define USE_HAL_SDRAM_REGISTER_CALLBACKS 0U /* SDRAM register callback disabled */
#define USE_HAL_SRAM_REGISTER_CALLBACKS 0U /* SRAM register callback disabled */
#define USE_HAL_SPDIFRX_REGISTER_CALLBACKS 0U /* SPDIFRX register callback disabled */
#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0U /* SMBUS register callback disabled */
#define USE_HAL_SPI_REGISTER_CALLBACKS 0U /* SPI register callback disabled */
#define USE_HAL_TIM_REGISTER_CALLBACKS 0U /* TIM register callback disabled */
#define USE_HAL_UART_REGISTER_CALLBACKS 0U /* UART register callback disabled */
#define USE_HAL_USART_REGISTER_CALLBACKS 0U /* USART register callback disabled */
#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U /* WWDG register callback disabled */
/* ########################## Assert Selection ############################## */
/**
* @brief Uncomment the line below to expanse the "assert_param" macro in the
* HAL drivers code
*/
/* #define USE_FULL_ASSERT 1U */
/* ################## Ethernet peripheral configuration ##################### */
/* Section 1 : Ethernet peripheral configuration */
/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */
#define MAC_ADDR0 2U
#define MAC_ADDR1 0U
#define MAC_ADDR2 0U
#define MAC_ADDR3 0U
#define MAC_ADDR4 0U
#define MAC_ADDR5 0U
/* Definition of the Ethernet driver buffers size and count */
#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */
#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */
#define ETH_RXBUFNB ((uint32_t)4U) /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
#define ETH_TXBUFNB ((uint32_t)4U) /* 4 Tx buffers of size ETH_TX_BUF_SIZE */
/* Section 2: PHY configuration section */
/* DP83848_PHY_ADDRESS Address*/
#define DP83848_PHY_ADDRESS
/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
#define PHY_RESET_DELAY ((uint32_t)0x000000FFU)
/* PHY Configuration delay */
#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFFU)
#define PHY_READ_TO ((uint32_t)0x0000FFFFU)
#define PHY_WRITE_TO ((uint32_t)0x0000FFFFU)
/* Section 3: Common PHY Registers */
#define PHY_BCR ((uint16_t)0x0000U) /*!< Transceiver Basic Control Register */
#define PHY_BSR ((uint16_t)0x0001U) /*!< Transceiver Basic Status Register */
#define PHY_RESET ((uint16_t)0x8000U) /*!< PHY Reset */
#define PHY_LOOPBACK ((uint16_t)0x4000U) /*!< Select loop-back mode */
#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100U) /*!< Set the full-duplex mode at 100 Mb/s */
#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000U) /*!< Set the half-duplex mode at 100 Mb/s */
#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100U) /*!< Set the full-duplex mode at 10 Mb/s */
#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000U) /*!< Set the half-duplex mode at 10 Mb/s */
#define PHY_AUTONEGOTIATION ((uint16_t)0x1000U) /*!< Enable auto-negotiation function */
#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200U) /*!< Restart auto-negotiation function */
#define PHY_POWERDOWN ((uint16_t)0x0800U) /*!< Select the power down mode */
#define PHY_ISOLATE ((uint16_t)0x0400U) /*!< Isolate PHY from MII */
#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020U) /*!< Auto-Negotiation process completed */
#define PHY_LINKED_STATUS ((uint16_t)0x0004U) /*!< Valid link established */
#define PHY_JABBER_DETECTION ((uint16_t)0x0002U) /*!< Jabber condition detected */
/* Section 4: Extended PHY Registers */
#define PHY_SR ((uint16_t)) /*!< PHY status register Offset */
#define PHY_SPEED_STATUS ((uint16_t)) /*!< PHY Speed mask */
#define PHY_DUPLEX_STATUS ((uint16_t)) /*!< PHY Duplex mask */
/* ################## SPI peripheral configuration ########################## */
/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver
* Activated: CRC code is present inside driver
* Deactivated: CRC code cleaned from driver
*/
#define USE_SPI_CRC 0U
/* Includes ------------------------------------------------------------------*/
/**
* @brief Include module's header file
*/
#ifdef HAL_RCC_MODULE_ENABLED
#include "stm32f7xx_hal_rcc.h"
#endif /* HAL_RCC_MODULE_ENABLED */
#ifdef HAL_EXTI_MODULE_ENABLED
#include "stm32f7xx_hal_exti.h"
#endif /* HAL_EXTI_MODULE_ENABLED */
#ifdef HAL_GPIO_MODULE_ENABLED
#include "stm32f7xx_hal_gpio.h"
#endif /* HAL_GPIO_MODULE_ENABLED */
#ifdef HAL_DMA_MODULE_ENABLED
#include "stm32f7xx_hal_dma.h"
#endif /* HAL_DMA_MODULE_ENABLED */
#ifdef HAL_CORTEX_MODULE_ENABLED
#include "stm32f7xx_hal_cortex.h"
#endif /* HAL_CORTEX_MODULE_ENABLED */
#ifdef HAL_ADC_MODULE_ENABLED
#include "stm32f7xx_hal_adc.h"
#endif /* HAL_ADC_MODULE_ENABLED */
#ifdef HAL_CAN_MODULE_ENABLED
#include "stm32f7xx_hal_can.h"
#endif /* HAL_CAN_MODULE_ENABLED */
#ifdef HAL_CEC_MODULE_ENABLED
#include "stm32f7xx_hal_cec.h"
#endif /* HAL_CEC_MODULE_ENABLED */
#ifdef HAL_CRC_MODULE_ENABLED
#include "stm32f7xx_hal_crc.h"
#endif /* HAL_CRC_MODULE_ENABLED */
#ifdef HAL_CRYP_MODULE_ENABLED
#include "stm32f7xx_hal_cryp.h"
#endif /* HAL_CRYP_MODULE_ENABLED */
#ifdef HAL_DMA2D_MODULE_ENABLED
#include "stm32f7xx_hal_dma2d.h"
#endif /* HAL_DMA2D_MODULE_ENABLED */
#ifdef HAL_DAC_MODULE_ENABLED
#include "stm32f7xx_hal_dac.h"
#endif /* HAL_DAC_MODULE_ENABLED */
#ifdef HAL_DCMI_MODULE_ENABLED
#include "stm32f7xx_hal_dcmi.h"
#endif /* HAL_DCMI_MODULE_ENABLED */
#ifdef HAL_ETH_MODULE_ENABLED
#include "stm32f7xx_hal_eth.h"
#endif /* HAL_ETH_MODULE_ENABLED */
#ifdef HAL_ETH_LEGACY_MODULE_ENABLED
#include "stm32f7xx_hal_eth_legacy.h"
#endif /* HAL_ETH_LEGACY_MODULE_ENABLED */
#ifdef HAL_FLASH_MODULE_ENABLED
#include "stm32f7xx_hal_flash.h"
#endif /* HAL_FLASH_MODULE_ENABLED */
#ifdef HAL_SRAM_MODULE_ENABLED
#include "stm32f7xx_hal_sram.h"
#endif /* HAL_SRAM_MODULE_ENABLED */
#ifdef HAL_NOR_MODULE_ENABLED
#include "stm32f7xx_hal_nor.h"
#endif /* HAL_NOR_MODULE_ENABLED */
#ifdef HAL_NAND_MODULE_ENABLED
#include "stm32f7xx_hal_nand.h"
#endif /* HAL_NAND_MODULE_ENABLED */
#ifdef HAL_SDRAM_MODULE_ENABLED
#include "stm32f7xx_hal_sdram.h"
#endif /* HAL_SDRAM_MODULE_ENABLED */
#ifdef HAL_HASH_MODULE_ENABLED
#include "stm32f7xx_hal_hash.h"
#endif /* HAL_HASH_MODULE_ENABLED */
#ifdef HAL_I2C_MODULE_ENABLED
#include "stm32f7xx_hal_i2c.h"
#endif /* HAL_I2C_MODULE_ENABLED */
#ifdef HAL_I2S_MODULE_ENABLED
#include "stm32f7xx_hal_i2s.h"
#endif /* HAL_I2S_MODULE_ENABLED */
#ifdef HAL_IWDG_MODULE_ENABLED
#include "stm32f7xx_hal_iwdg.h"
#endif /* HAL_IWDG_MODULE_ENABLED */
#ifdef HAL_LPTIM_MODULE_ENABLED
#include "stm32f7xx_hal_lptim.h"
#endif /* HAL_LPTIM_MODULE_ENABLED */
#ifdef HAL_LTDC_MODULE_ENABLED
#include "stm32f7xx_hal_ltdc.h"
#endif /* HAL_LTDC_MODULE_ENABLED */
#ifdef HAL_PWR_MODULE_ENABLED
#include "stm32f7xx_hal_pwr.h"
#endif /* HAL_PWR_MODULE_ENABLED */
#ifdef HAL_QSPI_MODULE_ENABLED
#include "stm32f7xx_hal_qspi.h"
#endif /* HAL_QSPI_MODULE_ENABLED */
#ifdef HAL_RNG_MODULE_ENABLED
#include "stm32f7xx_hal_rng.h"
#endif /* HAL_RNG_MODULE_ENABLED */
#ifdef HAL_RTC_MODULE_ENABLED
#include "stm32f7xx_hal_rtc.h"
#endif /* HAL_RTC_MODULE_ENABLED */
#ifdef HAL_SAI_MODULE_ENABLED
#include "stm32f7xx_hal_sai.h"
#endif /* HAL_SAI_MODULE_ENABLED */
#ifdef HAL_SD_MODULE_ENABLED
#include "stm32f7xx_hal_sd.h"
#endif /* HAL_SD_MODULE_ENABLED */
#ifdef HAL_MMC_MODULE_ENABLED
#include "stm32f7xx_hal_mmc.h"
#endif /* HAL_MMC_MODULE_ENABLED */
#ifdef HAL_SPDIFRX_MODULE_ENABLED
#include "stm32f7xx_hal_spdifrx.h"
#endif /* HAL_SPDIFRX_MODULE_ENABLED */
#ifdef HAL_SPI_MODULE_ENABLED
#include "stm32f7xx_hal_spi.h"
#endif /* HAL_SPI_MODULE_ENABLED */
#ifdef HAL_TIM_MODULE_ENABLED
#include "stm32f7xx_hal_tim.h"
#endif /* HAL_TIM_MODULE_ENABLED */
#ifdef HAL_UART_MODULE_ENABLED
#include "stm32f7xx_hal_uart.h"
#endif /* HAL_UART_MODULE_ENABLED */
#ifdef HAL_USART_MODULE_ENABLED
#include "stm32f7xx_hal_usart.h"
#endif /* HAL_USART_MODULE_ENABLED */
#ifdef HAL_IRDA_MODULE_ENABLED
#include "stm32f7xx_hal_irda.h"
#endif /* HAL_IRDA_MODULE_ENABLED */
#ifdef HAL_SMARTCARD_MODULE_ENABLED
#include "stm32f7xx_hal_smartcard.h"
#endif /* HAL_SMARTCARD_MODULE_ENABLED */
#ifdef HAL_WWDG_MODULE_ENABLED
#include "stm32f7xx_hal_wwdg.h"
#endif /* HAL_WWDG_MODULE_ENABLED */
#ifdef HAL_PCD_MODULE_ENABLED
#include "stm32f7xx_hal_pcd.h"
#endif /* HAL_PCD_MODULE_ENABLED */
#ifdef HAL_HCD_MODULE_ENABLED
#include "stm32f7xx_hal_hcd.h"
#endif /* HAL_HCD_MODULE_ENABLED */
#ifdef HAL_DFSDM_MODULE_ENABLED
#include "stm32f7xx_hal_dfsdm.h"
#endif /* HAL_DFSDM_MODULE_ENABLED */
#ifdef HAL_DSI_MODULE_ENABLED
#include "stm32f7xx_hal_dsi.h"
#endif /* HAL_DSI_MODULE_ENABLED */
#ifdef HAL_JPEG_MODULE_ENABLED
#include "stm32f7xx_hal_jpeg.h"
#endif /* HAL_JPEG_MODULE_ENABLED */
#ifdef HAL_MDIOS_MODULE_ENABLED
#include "stm32f7xx_hal_mdios.h"
#endif /* HAL_MDIOS_MODULE_ENABLED */
#ifdef HAL_SMBUS_MODULE_ENABLED
#include "stm32f7xx_hal_smbus.h"
#endif /* HAL_SMBUS_MODULE_ENABLED */
/* Exported macro ------------------------------------------------------------*/
#ifdef USE_FULL_ASSERT
/**
* @brief The assert_param macro is used for function's parameters check.
* @param expr: If expr is false, it calls assert_failed function
* which reports the name of the source file and the source
* line number of the call that failed.
* If expr is true, it returns no value.
* @retval None
*/
#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t* file, uint32_t line);
#else
#define assert_param(expr) ((void)0U)
#endif /* USE_FULL_ASSERT */
#ifdef __cplusplus
}
#endif
#endif /* __STM32F7xx_HAL_CONF_H */
@@ -0,0 +1,567 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file stm32f7xx_hal_msp.c
* @brief This file provides code for the MSP Initialization
* and de-Initialization codes.
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN TD */
/* USER CODE END TD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN Define */
/* USER CODE END Define */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN Macro */
/* USER CODE END Macro */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* External functions --------------------------------------------------------*/
/* USER CODE BEGIN ExternalFunctions */
/* USER CODE END ExternalFunctions */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* Initializes the Global MSP.
*/
void HAL_MspInit(void)
{
/* USER CODE BEGIN MspInit 0 */
/* USER CODE END MspInit 0 */
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_RCC_SYSCFG_CLK_ENABLE();
/* System interrupt init*/
/* USER CODE BEGIN MspInit 1 */
/* USER CODE END MspInit 1 */
}
/**
* @brief I2C MSP Initialization
* This function configures the hardware resources used in this example
* @param hi2c: I2C handle pointer
* @retval None
*/
void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
if(hi2c->Instance==I2C1)
{
/* USER CODE BEGIN I2C1_MspInit 0 */
/* USER CODE END I2C1_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C1;
PeriphClkInitStruct.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
__HAL_RCC_GPIOB_CLK_ENABLE();
/**I2C1 GPIO Configuration
PB6 ------> I2C1_SCL
PB7 ------> I2C1_SDA
*/
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Peripheral clock enable */
__HAL_RCC_I2C1_CLK_ENABLE();
/* USER CODE BEGIN I2C1_MspInit 1 */
/* USER CODE END I2C1_MspInit 1 */
}
else if(hi2c->Instance==I2C2)
{
/* USER CODE BEGIN I2C2_MspInit 0 */
/* USER CODE END I2C2_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C2;
PeriphClkInitStruct.I2c2ClockSelection = RCC_I2C2CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
__HAL_RCC_GPIOF_CLK_ENABLE();
/**I2C2 GPIO Configuration
PF0 ------> I2C2_SDA
PF1 ------> I2C2_SCL
*/
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C2;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
/* Peripheral clock enable */
__HAL_RCC_I2C2_CLK_ENABLE();
/* USER CODE BEGIN I2C2_MspInit 1 */
/* USER CODE END I2C2_MspInit 1 */
}
else if(hi2c->Instance==I2C3)
{
/* USER CODE BEGIN I2C3_MspInit 0 */
/* USER CODE END I2C3_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C3;
PeriphClkInitStruct.I2c3ClockSelection = RCC_I2C3CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**I2C3 GPIO Configuration
PC9 ------> I2C3_SDA
PA8 ------> I2C3_SCL
*/
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C3;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF4_I2C3;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* Peripheral clock enable */
__HAL_RCC_I2C3_CLK_ENABLE();
/* USER CODE BEGIN I2C3_MspInit 1 */
/* USER CODE END I2C3_MspInit 1 */
}
}
/**
* @brief I2C MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param hi2c: I2C handle pointer
* @retval None
*/
void HAL_I2C_MspDeInit(I2C_HandleTypeDef* hi2c)
{
if(hi2c->Instance==I2C1)
{
/* USER CODE BEGIN I2C1_MspDeInit 0 */
/* USER CODE END I2C1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_I2C1_CLK_DISABLE();
/**I2C1 GPIO Configuration
PB6 ------> I2C1_SCL
PB7 ------> I2C1_SDA
*/
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6);
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_7);
/* USER CODE BEGIN I2C1_MspDeInit 1 */
/* USER CODE END I2C1_MspDeInit 1 */
}
else if(hi2c->Instance==I2C2)
{
/* USER CODE BEGIN I2C2_MspDeInit 0 */
/* USER CODE END I2C2_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_I2C2_CLK_DISABLE();
/**I2C2 GPIO Configuration
PF0 ------> I2C2_SDA
PF1 ------> I2C2_SCL
*/
HAL_GPIO_DeInit(GPIOF, GPIO_PIN_0);
HAL_GPIO_DeInit(GPIOF, GPIO_PIN_1);
/* USER CODE BEGIN I2C2_MspDeInit 1 */
/* USER CODE END I2C2_MspDeInit 1 */
}
else if(hi2c->Instance==I2C3)
{
/* USER CODE BEGIN I2C3_MspDeInit 0 */
/* USER CODE END I2C3_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_I2C3_CLK_DISABLE();
/**I2C3 GPIO Configuration
PC9 ------> I2C3_SDA
PA8 ------> I2C3_SCL
*/
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_9);
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_8);
/* USER CODE BEGIN I2C3_MspDeInit 1 */
/* USER CODE END I2C3_MspDeInit 1 */
}
}
/**
* @brief SPI MSP Initialization
* This function configures the hardware resources used in this example
* @param hspi: SPI handle pointer
* @retval None
*/
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(hspi->Instance==SPI1)
{
/* USER CODE BEGIN SPI1_MspInit 0 */
/* USER CODE END SPI1_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_SPI1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**SPI1 GPIO Configuration
PA5 ------> SPI1_SCK
PA6 ------> SPI1_MISO
PA7 ------> SPI1_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN SPI1_MspInit 1 */
/* USER CODE END SPI1_MspInit 1 */
}
else if(hspi->Instance==SPI4)
{
/* USER CODE BEGIN SPI4_MspInit 0 */
/* USER CODE END SPI4_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_SPI4_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
/**SPI4 GPIO Configuration
PE2 ------> SPI4_SCK
PE5 ------> SPI4_MISO
PE6 ------> SPI4_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_5|GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI4;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/* USER CODE BEGIN SPI4_MspInit 1 */
/* USER CODE END SPI4_MspInit 1 */
}
}
/**
* @brief SPI MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param hspi: SPI handle pointer
* @retval None
*/
void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi)
{
if(hspi->Instance==SPI1)
{
/* USER CODE BEGIN SPI1_MspDeInit 0 */
/* USER CODE END SPI1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_SPI1_CLK_DISABLE();
/**SPI1 GPIO Configuration
PA5 ------> SPI1_SCK
PA6 ------> SPI1_MISO
PA7 ------> SPI1_MOSI
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7);
/* USER CODE BEGIN SPI1_MspDeInit 1 */
/* USER CODE END SPI1_MspDeInit 1 */
}
else if(hspi->Instance==SPI4)
{
/* USER CODE BEGIN SPI4_MspDeInit 0 */
/* USER CODE END SPI4_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_SPI4_CLK_DISABLE();
/**SPI4 GPIO Configuration
PE2 ------> SPI4_SCK
PE5 ------> SPI4_MISO
PE6 ------> SPI4_MOSI
*/
HAL_GPIO_DeInit(GPIOE, GPIO_PIN_2|GPIO_PIN_5|GPIO_PIN_6);
/* USER CODE BEGIN SPI4_MspDeInit 1 */
/* USER CODE END SPI4_MspDeInit 1 */
}
}
/**
* @brief TIM_Base MSP Initialization
* This function configures the hardware resources used in this example
* @param htim_base: TIM_Base handle pointer
* @retval None
*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==TIM1)
{
/* USER CODE BEGIN TIM1_MspInit 0 */
/* USER CODE END TIM1_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_TIM1_CLK_ENABLE();
/* USER CODE BEGIN TIM1_MspInit 1 */
/* USER CODE END TIM1_MspInit 1 */
}
}
/**
* @brief TIM_Base MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param htim_base: TIM_Base handle pointer
* @retval None
*/
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==TIM1)
{
/* USER CODE BEGIN TIM1_MspDeInit 0 */
/* USER CODE END TIM1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_TIM1_CLK_DISABLE();
/* USER CODE BEGIN TIM1_MspDeInit 1 */
/* USER CODE END TIM1_MspDeInit 1 */
}
}
/**
* @brief UART MSP Initialization
* This function configures the hardware resources used in this example
* @param huart: UART handle pointer
* @retval None
*/
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
if(huart->Instance==UART5)
{
/* USER CODE BEGIN UART5_MspInit 0 */
/* USER CODE END UART5_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_UART5;
PeriphClkInitStruct.Uart5ClockSelection = RCC_UART5CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* Peripheral clock enable */
__HAL_RCC_UART5_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/**UART5 GPIO Configuration
PC12 ------> UART5_TX
PD2 ------> UART5_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF8_UART5;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF8_UART5;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/* USER CODE BEGIN UART5_MspInit 1 */
/* USER CODE END UART5_MspInit 1 */
}
else if(huart->Instance==USART3)
{
/* USER CODE BEGIN USART3_MspInit 0 */
/* USER CODE END USART3_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART3;
PeriphClkInitStruct.Usart3ClockSelection = RCC_USART3CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* Peripheral clock enable */
__HAL_RCC_USART3_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**USART3 GPIO Configuration
PB10 ------> USART3_TX
PB11 ------> USART3_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USER CODE BEGIN USART3_MspInit 1 */
/* USER CODE END USART3_MspInit 1 */
}
}
/**
* @brief UART MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param huart: UART handle pointer
* @retval None
*/
void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
{
if(huart->Instance==UART5)
{
/* USER CODE BEGIN UART5_MspDeInit 0 */
/* USER CODE END UART5_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_UART5_CLK_DISABLE();
/**UART5 GPIO Configuration
PC12 ------> UART5_TX
PD2 ------> UART5_RX
*/
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_12);
HAL_GPIO_DeInit(GPIOD, GPIO_PIN_2);
/* USER CODE BEGIN UART5_MspDeInit 1 */
/* USER CODE END UART5_MspDeInit 1 */
}
else if(huart->Instance==USART3)
{
/* USER CODE BEGIN USART3_MspDeInit 0 */
/* USER CODE END USART3_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_USART3_CLK_DISABLE();
/**USART3 GPIO Configuration
PB10 ------> USART3_TX
PB11 ------> USART3_RX
*/
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10|GPIO_PIN_11);
/* USER CODE BEGIN USART3_MspDeInit 1 */
/* USER CODE END USART3_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
@@ -0,0 +1,217 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file stm32f7xx_it.c
* @brief Interrupt Service Routines.
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f7xx_it.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN TD */
/* USER CODE END TD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/* External variables --------------------------------------------------------*/
extern PCD_HandleTypeDef hpcd_USB_OTG_FS;
/* USER CODE BEGIN EV */
/* USER CODE END EV */
/******************************************************************************/
/* Cortex-M7 Processor Interruption and Exception Handlers */
/******************************************************************************/
/**
* @brief This function handles Non maskable interrupt.
*/
void NMI_Handler(void)
{
/* USER CODE BEGIN NonMaskableInt_IRQn 0 */
/* USER CODE END NonMaskableInt_IRQn 0 */
/* USER CODE BEGIN NonMaskableInt_IRQn 1 */
while (1)
{
}
/* USER CODE END NonMaskableInt_IRQn 1 */
}
/**
* @brief This function handles Hard fault interrupt.
*/
void HardFault_Handler(void)
{
/* USER CODE BEGIN HardFault_IRQn 0 */
/* USER CODE END HardFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
/* USER CODE END W1_HardFault_IRQn 0 */
}
}
/**
* @brief This function handles Memory management fault.
*/
void MemManage_Handler(void)
{
/* USER CODE BEGIN MemoryManagement_IRQn 0 */
/* USER CODE END MemoryManagement_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */
/* USER CODE END W1_MemoryManagement_IRQn 0 */
}
}
/**
* @brief This function handles Pre-fetch fault, memory access fault.
*/
void BusFault_Handler(void)
{
/* USER CODE BEGIN BusFault_IRQn 0 */
/* USER CODE END BusFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_BusFault_IRQn 0 */
/* USER CODE END W1_BusFault_IRQn 0 */
}
}
/**
* @brief This function handles Undefined instruction or illegal state.
*/
void UsageFault_Handler(void)
{
/* USER CODE BEGIN UsageFault_IRQn 0 */
/* USER CODE END UsageFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_UsageFault_IRQn 0 */
/* USER CODE END W1_UsageFault_IRQn 0 */
}
}
/**
* @brief This function handles System service call via SWI instruction.
*/
void SVC_Handler(void)
{
/* USER CODE BEGIN SVCall_IRQn 0 */
/* USER CODE END SVCall_IRQn 0 */
/* USER CODE BEGIN SVCall_IRQn 1 */
/* USER CODE END SVCall_IRQn 1 */
}
/**
* @brief This function handles Debug monitor.
*/
void DebugMon_Handler(void)
{
/* USER CODE BEGIN DebugMonitor_IRQn 0 */
/* USER CODE END DebugMonitor_IRQn 0 */
/* USER CODE BEGIN DebugMonitor_IRQn 1 */
/* USER CODE END DebugMonitor_IRQn 1 */
}
/**
* @brief This function handles Pendable request for system service.
*/
void PendSV_Handler(void)
{
/* USER CODE BEGIN PendSV_IRQn 0 */
/* USER CODE END PendSV_IRQn 0 */
/* USER CODE BEGIN PendSV_IRQn 1 */
/* USER CODE END PendSV_IRQn 1 */
}
/**
* @brief This function handles System tick timer.
*/
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
/* USER CODE END SysTick_IRQn 0 */
HAL_IncTick();
/* USER CODE BEGIN SysTick_IRQn 1 */
/* USER CODE END SysTick_IRQn 1 */
}
/******************************************************************************/
/* STM32F7xx Peripheral Interrupt Handlers */
/* Add here the Interrupt Handlers for the used peripherals. */
/* For the available peripheral interrupt handler names, */
/* please refer to the startup file (startup_stm32f7xx.s). */
/******************************************************************************/
/**
* @brief This function handles USB On The Go FS global interrupt.
*/
void OTG_FS_IRQHandler(void)
{
/* USER CODE BEGIN OTG_FS_IRQn 0 */
/* USER CODE END OTG_FS_IRQn 0 */
HAL_PCD_IRQHandler(&hpcd_USB_OTG_FS);
/* USER CODE BEGIN OTG_FS_IRQn 1 */
/* USER CODE END OTG_FS_IRQn 1 */
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
@@ -0,0 +1,67 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file stm32f7xx_it.h
* @brief This file contains the headers of the interrupt handlers.
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F7xx_IT_H
#define __STM32F7xx_IT_H
#ifdef __cplusplus
extern "C" {
#endif
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
/* USER CODE END ET */
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
/* USER CODE END EC */
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
/* USER CODE END EM */
/* Exported functions prototypes ---------------------------------------------*/
void NMI_Handler(void);
void HardFault_Handler(void);
void MemManage_Handler(void);
void BusFault_Handler(void);
void UsageFault_Handler(void);
void SVC_Handler(void);
void DebugMon_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);
void OTG_FS_IRQHandler(void);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
#ifdef __cplusplus
}
#endif
#endif /* __STM32F7xx_IT_H */
@@ -0,0 +1,176 @@
/**
******************************************************************************
* @file syscalls.c
* @author Auto-generated by STM32CubeIDE
* @brief STM32CubeIDE Minimal System calls file
*
* For more information about which c-functions
* need which of these lowlevel functions
* please consult the Newlib libc-manual
******************************************************************************
* @attention
*
* Copyright (c) 2020-2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes */
#include <sys/stat.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
/* Variables */
extern int __io_putchar(int ch) __attribute__((weak));
extern int __io_getchar(void) __attribute__((weak));
char *__env[1] = { 0 };
char **environ = __env;
/* Functions */
void initialise_monitor_handles()
{
}
int _getpid(void)
{
return 1;
}
int _kill(int pid, int sig)
{
(void)pid;
(void)sig;
errno = EINVAL;
return -1;
}
void _exit (int status)
{
_kill(status, -1);
while (1) {} /* Make sure we hang here */
}
__attribute__((weak)) int _read(int file, char *ptr, int len)
{
(void)file;
int DataIdx;
for (DataIdx = 0; DataIdx < len; DataIdx++)
{
*ptr++ = __io_getchar();
}
return len;
}
__attribute__((weak)) int _write(int file, char *ptr, int len)
{
(void)file;
int DataIdx;
for (DataIdx = 0; DataIdx < len; DataIdx++)
{
__io_putchar(*ptr++);
}
return len;
}
int _close(int file)
{
(void)file;
return -1;
}
int _fstat(int file, struct stat *st)
{
(void)file;
st->st_mode = S_IFCHR;
return 0;
}
int _isatty(int file)
{
(void)file;
return 1;
}
int _lseek(int file, int ptr, int dir)
{
(void)file;
(void)ptr;
(void)dir;
return 0;
}
int _open(char *path, int flags, ...)
{
(void)path;
(void)flags;
/* Pretend like we always fail */
return -1;
}
int _wait(int *status)
{
(void)status;
errno = ECHILD;
return -1;
}
int _unlink(char *name)
{
(void)name;
errno = ENOENT;
return -1;
}
int _times(struct tms *buf)
{
(void)buf;
return -1;
}
int _stat(char *file, struct stat *st)
{
(void)file;
st->st_mode = S_IFCHR;
return 0;
}
int _link(char *old, char *new)
{
(void)old;
(void)new;
errno = EMLINK;
return -1;
}
int _fork(void)
{
errno = EAGAIN;
return -1;
}
int _execve(char *name, char **argv, char **env)
{
(void)name;
(void)argv;
(void)env;
errno = ENOMEM;
return -1;
}
@@ -0,0 +1,79 @@
/**
******************************************************************************
* @file sysmem.c
* @author Generated by STM32CubeIDE
* @brief STM32CubeIDE System Memory calls file
*
* For more information about which C functions
* need which of these lowlevel functions
* please consult the newlib libc manual
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes */
#include <errno.h>
#include <stdint.h>
/**
* Pointer to the current high watermark of the heap usage
*/
static uint8_t *__sbrk_heap_end = NULL;
/**
* @brief _sbrk() allocates memory to the newlib heap and is used by malloc
* and others from the C library
*
* @verbatim
* ############################################################################
* # .data # .bss # newlib heap # MSP stack #
* # # # # Reserved by _Min_Stack_Size #
* ############################################################################
* ^-- RAM start ^-- _end _estack, RAM end --^
* @endverbatim
*
* This implementation starts allocating at the '_end' linker symbol
* The '_Min_Stack_Size' linker symbol reserves a memory for the MSP stack
* The implementation considers '_estack' linker symbol to be RAM end
* NOTE: If the MSP stack, at any point during execution, grows larger than the
* reserved size, please increase the '_Min_Stack_Size'.
*
* @param incr Memory size
* @return Pointer to allocated memory
*/
void *_sbrk(ptrdiff_t incr)
{
extern uint8_t _end; /* Symbol defined in the linker script */
extern uint8_t _estack; /* Symbol defined in the linker script */
extern uint32_t _Min_Stack_Size; /* Symbol defined in the linker script */
const uint32_t stack_limit = (uint32_t)&_estack - (uint32_t)&_Min_Stack_Size;
const uint8_t *max_heap = (uint8_t *)stack_limit;
uint8_t *prev_heap_end;
/* Initialize heap end at first call */
if (NULL == __sbrk_heap_end)
{
__sbrk_heap_end = &_end;
}
/* Protect heap from growing into the reserved MSP stack */
if (__sbrk_heap_end + incr > max_heap)
{
errno = ENOMEM;
return (void *)-1;
}
prev_heap_end = __sbrk_heap_end;
__sbrk_heap_end += incr;
return (void *)prev_heap_end;
}
@@ -0,0 +1,259 @@
/**
******************************************************************************
* @file system_stm32f7xx.c
* @author MCD Application Team
* @brief CMSIS Cortex-M7 Device Peripheral Access Layer System Source File.
*
* This file provides two functions and one global variable to be called from
* user application:
* - SystemInit(): This function is called at startup just after reset and
* before branch to main program. This call is made inside
* the "startup_stm32f7xx.s" file.
*
* - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
* by the user application to setup the SysTick
* timer or configure other parameters.
*
* - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
* be called whenever the core clock is changed
* during program execution.
*
*
******************************************************************************
* @attention
*
* Copyright (c) 2016 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/** @addtogroup CMSIS
* @{
*/
/** @addtogroup stm32f7xx_system
* @{
*/
/** @addtogroup STM32F7xx_System_Private_Includes
* @{
*/
#include "stm32f7xx.h"
#if !defined (HSE_VALUE)
#define HSE_VALUE ((uint32_t)25000000) /*!< Default value of the External oscillator in Hz */
#endif /* HSE_VALUE */
#if !defined (HSI_VALUE)
#define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/
#endif /* HSI_VALUE */
/**
* @}
*/
/** @addtogroup STM32F7xx_System_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F7xx_System_Private_Defines
* @{
*/
/************************* Miscellaneous Configuration ************************/
/* Note: Following vector table addresses must be defined in line with linker
configuration. */
/*!< Uncomment the following line if you need to relocate the vector table
anywhere in Flash or Sram, else the vector table is kept at the automatic
remap of boot address selected */
/* #define USER_VECT_TAB_ADDRESS */
#if defined(USER_VECT_TAB_ADDRESS)
/*!< Uncomment the following line if you need to relocate your vector Table
in Sram else user remap will be done in Flash. */
/* #define VECT_TAB_SRAM */
#if defined(VECT_TAB_SRAM)
#define VECT_TAB_BASE_ADDRESS RAMDTCM_BASE /*!< Vector Table base address field.
This value must be a multiple of 0x200. */
#else
#define VECT_TAB_BASE_ADDRESS FLASH_BASE /*!< Vector Table base address field.
This value must be a multiple of 0x200. */
#endif /* VECT_TAB_SRAM */
#if !defined(VECT_TAB_OFFSET)
#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table offset field.
This value must be a multiple of 0x200. */
#endif /* VECT_TAB_OFFSET */
#endif /* USER_VECT_TAB_ADDRESS */
/******************************************************************************/
/**
* @}
*/
/** @addtogroup STM32F7xx_System_Private_Macros
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F7xx_System_Private_Variables
* @{
*/
/* This variable is updated in three ways:
1) by calling CMSIS function SystemCoreClockUpdate()
2) by calling HAL API function HAL_RCC_GetHCLKFreq()
3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
Note: If you use this function to configure the system clock; then there
is no need to call the 2 first functions listed above, since SystemCoreClock
variable is updated automatically.
*/
uint32_t SystemCoreClock = 16000000;
const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4};
/**
* @}
*/
/** @addtogroup STM32F7xx_System_Private_FunctionPrototypes
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F7xx_System_Private_Functions
* @{
*/
/**
* @brief Setup the microcontroller system
* Initialize the Embedded Flash Interface, the PLL and update the
* SystemFrequency variable.
* @param None
* @retval None
*/
void SystemInit(void)
{
/* FPU settings ------------------------------------------------------------*/
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
#endif
/* Configure the Vector Table location -------------------------------------*/
#if defined(USER_VECT_TAB_ADDRESS)
SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#endif /* USER_VECT_TAB_ADDRESS */
}
/**
* @brief Update SystemCoreClock variable according to Clock Register Values.
* The SystemCoreClock variable contains the core clock (HCLK), it can
* be used by the user application to setup the SysTick timer or configure
* other parameters.
*
* @note Each time the core clock (HCLK) changes, this function must be called
* to update SystemCoreClock variable value. Otherwise, any configuration
* based on this variable will be incorrect.
*
* @note - The system frequency computed by this function is not the real
* frequency in the chip. It is calculated based on the predefined
* constant and the selected clock source:
*
* - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
*
* - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
*
* - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
* or HSI_VALUE(*) multiplied/divided by the PLL factors.
*
* (*) HSI_VALUE is a constant defined in stm32f7xx_hal_conf.h file (default value
* 16 MHz) but the real value may vary depending on the variations
* in voltage and temperature.
*
* (**) HSE_VALUE is a constant defined in stm32f7xx_hal_conf.h file (default value
* 25 MHz), user has to ensure that HSE_VALUE is same as the real
* frequency of the crystal used. Otherwise, this function may
* have wrong result.
*
* - The result of this function could be not correct when using fractional
* value for HSE crystal.
*
* @param None
* @retval None
*/
void SystemCoreClockUpdate(void)
{
uint32_t tmp, pllvco, pllp, pllsource, pllm;
/* Get SYSCLK source -------------------------------------------------------*/
tmp = RCC->CFGR & RCC_CFGR_SWS;
switch (tmp)
{
case 0x00: /* HSI used as system clock source */
SystemCoreClock = HSI_VALUE;
break;
case 0x04: /* HSE used as system clock source */
SystemCoreClock = HSE_VALUE;
break;
case 0x08: /* PLL used as system clock source */
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
SYSCLK = PLL_VCO / PLL_P
*/
pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22;
pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;
if (pllsource != 0)
{
/* HSE used as PLL clock source */
pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
}
else
{
/* HSI used as PLL clock source */
pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
}
pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2;
SystemCoreClock = pllvco/pllp;
break;
default:
SystemCoreClock = HSI_VALUE;
break;
}
/* Compute HCLK frequency --------------------------------------------------*/
/* Get HCLK prescaler */
tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
/* HCLK frequency */
SystemCoreClock >>= tmp;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,175 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.h
* @brief : Header for main.c file.
* This file contains the common defines of the application.
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f7xx_hal.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
extern uint8_t GUI_start_flag_received;
extern uint8_t USB_Buffer[64];
/* USER CODE END ET */
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
/* USER CODE END EC */
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
/* USER CODE END EM */
/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
/* Private defines -----------------------------------------------------------*/
#define AD9523_PD_Pin GPIO_PIN_3
#define AD9523_PD_GPIO_Port GPIOF
#define AD9523_REF_SEL_Pin GPIO_PIN_4
#define AD9523_REF_SEL_GPIO_Port GPIOF
#define AD9523_SYNC_Pin GPIO_PIN_5
#define AD9523_SYNC_GPIO_Port GPIOF
#define AD9523_RESET_Pin GPIO_PIN_6
#define AD9523_RESET_GPIO_Port GPIOF
#define AD9523_CS_Pin GPIO_PIN_7
#define AD9523_CS_GPIO_Port GPIOF
#define AD9523_STATUS0_Pin GPIO_PIN_8
#define AD9523_STATUS0_GPIO_Port GPIOF
#define AD9523_STATUS1_Pin GPIO_PIN_9
#define AD9523_STATUS1_GPIO_Port GPIOF
#define AD9523_EEPROM_SEL_Pin GPIO_PIN_10
#define AD9523_EEPROM_SEL_GPIO_Port GPIOF
#define ADAR_1_CS_3V3_Pin GPIO_PIN_0
#define ADAR_1_CS_3V3_GPIO_Port GPIOA
#define ADAR_2_CS_3V3_Pin GPIO_PIN_1
#define ADAR_2_CS_3V3_GPIO_Port GPIOA
#define ADAR_3_CS_3V3_Pin GPIO_PIN_2
#define ADAR_3_CS_3V3_GPIO_Port GPIOA
#define ADAR_4_CS_3V3_Pin GPIO_PIN_3
#define ADAR_4_CS_3V3_GPIO_Port GPIOA
#define LED_1_Pin GPIO_PIN_12
#define LED_1_GPIO_Port GPIOF
#define LED_2_Pin GPIO_PIN_13
#define LED_2_GPIO_Port GPIOF
#define LED_3_Pin GPIO_PIN_14
#define LED_3_GPIO_Port GPIOF
#define LED_4_Pin GPIO_PIN_15
#define LED_4_GPIO_Port GPIOF
#define EN_P_5V0_PA1_Pin GPIO_PIN_0
#define EN_P_5V0_PA1_GPIO_Port GPIOG
#define EN_P_5V0_PA2_Pin GPIO_PIN_1
#define EN_P_5V0_PA2_GPIO_Port GPIOG
#define EN_P_1V0_FPGA_Pin GPIO_PIN_7
#define EN_P_1V0_FPGA_GPIO_Port GPIOE
#define EN_P_1V8_FPGA_Pin GPIO_PIN_8
#define EN_P_1V8_FPGA_GPIO_Port GPIOE
#define EN_P_3V3_FPGA_Pin GPIO_PIN_9
#define EN_P_3V3_FPGA_GPIO_Port GPIOE
#define EN_P_5V0_ADAR_Pin GPIO_PIN_10
#define EN_P_5V0_ADAR_GPIO_Port GPIOE
#define EN_P_3V3_ADAR12_Pin GPIO_PIN_11
#define EN_P_3V3_ADAR12_GPIO_Port GPIOE
#define EN_P_3V3_ADAR34_Pin GPIO_PIN_12
#define EN_P_3V3_ADAR34_GPIO_Port GPIOE
#define EN_P_3V3_ADTR_Pin GPIO_PIN_13
#define EN_P_3V3_ADTR_GPIO_Port GPIOE
#define EN_P_3V3_SW_Pin GPIO_PIN_14
#define EN_P_3V3_SW_GPIO_Port GPIOE
#define EN_P_3V3_VDD_SW_Pin GPIO_PIN_15
#define EN_P_3V3_VDD_SW_GPIO_Port GPIOE
#define EN_P_5V0_PA3_Pin GPIO_PIN_2
#define EN_P_5V0_PA3_GPIO_Port GPIOG
#define EN_P_5V5_PA_Pin GPIO_PIN_3
#define EN_P_5V5_PA_GPIO_Port GPIOG
#define EN_P_1V8_CLOCK_Pin GPIO_PIN_4
#define EN_P_1V8_CLOCK_GPIO_Port GPIOG
#define EN_P_3V3_CLOCK_Pin GPIO_PIN_5
#define EN_P_3V3_CLOCK_GPIO_Port GPIOG
#define ADF4382_RX_LKDET_Pin GPIO_PIN_6
#define ADF4382_RX_LKDET_GPIO_Port GPIOG
#define ADF4382_RX_DELADJ_Pin GPIO_PIN_7
#define ADF4382_RX_DELADJ_GPIO_Port GPIOG
#define ADF4382_RX_DELSTR_Pin GPIO_PIN_8
#define ADF4382_RX_DELSTR_GPIO_Port GPIOG
#define MAG_DRDY_Pin GPIO_PIN_6
#define MAG_DRDY_GPIO_Port GPIOC
#define ACC_INT_Pin GPIO_PIN_7
#define ACC_INT_GPIO_Port GPIOC
#define GYR_INT_Pin GPIO_PIN_8
#define GYR_INT_GPIO_Port GPIOC
#define STEPPER_CW_P_Pin GPIO_PIN_4
#define STEPPER_CW_P_GPIO_Port GPIOD
#define STEPPER_CLK_P_Pin GPIO_PIN_5
#define STEPPER_CLK_P_GPIO_Port GPIOD
#define EN_DIS_RFPA_VDD_Pin GPIO_PIN_6
#define EN_DIS_RFPA_VDD_GPIO_Port GPIOD
#define EN_DIS_COOLING_Pin GPIO_PIN_7
#define EN_DIS_COOLING_GPIO_Port GPIOD
#define ADF4382_RX_CE_Pin GPIO_PIN_9
#define ADF4382_RX_CE_GPIO_Port GPIOG
#define ADF4382_RX_CS_Pin GPIO_PIN_10
#define ADF4382_RX_CS_GPIO_Port GPIOG
#define ADF4382_TX_LKDET_Pin GPIO_PIN_11
#define ADF4382_TX_LKDET_GPIO_Port GPIOG
#define ADF4382_TX_DELSTR_Pin GPIO_PIN_12
#define ADF4382_TX_DELSTR_GPIO_Port GPIOG
#define ADF4382_TX_DELADJ_Pin GPIO_PIN_13
#define ADF4382_TX_DELADJ_GPIO_Port GPIOG
#define ADF4382_TX_CS_Pin GPIO_PIN_14
#define ADF4382_TX_CS_GPIO_Port GPIOG
#define ADF4382_TX_CE_Pin GPIO_PIN_15
#define ADF4382_TX_CE_GPIO_Port GPIOG
#define DAC_1_VG_CLR_Pin GPIO_PIN_4
#define DAC_1_VG_CLR_GPIO_Port GPIOB
#define DAC_1_VG_LDAC_Pin GPIO_PIN_5
#define DAC_1_VG_LDAC_GPIO_Port GPIOB
#define DAC_2_VG_CLR_Pin GPIO_PIN_8
#define DAC_2_VG_CLR_GPIO_Port GPIOB
#define DAC_2_VG_LDAC_Pin GPIO_PIN_9
#define DAC_2_VG_LDAC_GPIO_Port GPIOB
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */