Add files via upload
This commit is contained in:
@@ -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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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 °)
|
||||
{
|
||||
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 °);
|
||||
|
||||
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,
|
||||
®_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,
|
||||
®_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,
|
||||
®_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,
|
||||
®_data);
|
||||
if ((reg_data & 0x1) == 0x0)
|
||||
break;
|
||||
}
|
||||
ad9523_spi_read(dev,
|
||||
AD9523_READBACK_1,
|
||||
®_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,
|
||||
®_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,
|
||||
®_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,
|
||||
®_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(¤t_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(¤t_gps, gps_data, sizeof(GPS_Data_t));
|
||||
current_gps.timestamp = HAL_GetTick();
|
||||
|
||||
// Send to GUI
|
||||
GPS_SendToGUI(¤t_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 */
|
||||
Reference in New Issue
Block a user