diff --git a/firmware/application/apps/ui_mictx.cpp b/firmware/application/apps/ui_mictx.cpp index 6a1a7acb..901fcf71 100644 --- a/firmware/application/apps/ui_mictx.cpp +++ b/firmware/application/apps/ui_mictx.cpp @@ -31,6 +31,7 @@ #include "tonesets.hpp" #include "ui_tone_key.hpp" #include "wm8731.hpp" +#include "radio.hpp" #include @@ -336,6 +337,7 @@ MicTXView::MicTXView( &field_rxlna, &field_rxvga, &field_rxamp, + hackrf_r9 ? &field_tx_iq_phase_cal_2839 : &field_tx_iq_phase_cal_2837, &tx_button, &tx_icon}); @@ -368,6 +370,21 @@ MicTXView::MicTXView( receiver_model.set_rf_amp(v); }; + radio::set_tx_max283x_iq_phase_calibration(iq_phase_calibration_value); + if (hackrf_r9) { // MAX2839 has 6 bits IQ CAL phasse adjustment. + field_tx_iq_phase_cal_2839.set_value(iq_phase_calibration_value); + field_tx_iq_phase_cal_2839.on_change = [this](int32_t v) { + iq_phase_calibration_value = v; + radio::set_tx_max283x_iq_phase_calibration(iq_phase_calibration_value); + }; + } else { // MAX2837 has 5 bits IQ CAL phase adjustment. + field_tx_iq_phase_cal_2837.set_value(iq_phase_calibration_value); + field_tx_iq_phase_cal_2837.on_change = [this](int32_t v) { + iq_phase_calibration_value = v; + radio::set_tx_max283x_iq_phase_calibration(iq_phase_calibration_value); + }; + } + options_gain.on_change = [this](size_t, int32_t v) { mic_gain_x10 = v; configure_baseband(); diff --git a/firmware/application/apps/ui_mictx.hpp b/firmware/application/apps/ui_mictx.hpp index e9843e13..8bba0217 100644 --- a/firmware/application/apps/ui_mictx.hpp +++ b/firmware/application/apps/ui_mictx.hpp @@ -113,6 +113,7 @@ class MicTXView : public View { uint32_t va_level{40}; uint32_t attack_ms{500}; uint32_t decay_ms{1000}; + uint8_t iq_phase_calibration_value{15}; app_settings::SettingsManager settings_{ "tx_mic", app_settings::Mode::RX_TX, @@ -132,6 +133,7 @@ class MicTXView : public View { {"vox"sv, &va_enabled}, {"rogerbeep"sv, &rogerbeep_enabled}, {"tone_key_index"sv, &tone_key_index}, + {"iq_phase_calibration"sv, &iq_phase_calibration_value}, }}; rf::Frequency tx_frequency{0}; @@ -160,7 +162,8 @@ class MicTXView : public View { {{5 * 8, (25 * 8) + 2}, "F_RX:", Color::light_grey()}, {{5 * 8, (27 * 8) + 2}, "LNA:", Color::light_grey()}, {{12 * 8, (27 * 8) + 2}, "VGA:", Color::light_grey()}, - {{19 * 8, (27 * 8) + 2}, "AMP:", Color::light_grey()}}; + {{19 * 8, (27 * 8) + 2}, "AMP:", Color::light_grey()}, + {{21 * 8, (31 * 8)}, "TX-IQ-CAL:", Color::light_grey()}}; Labels labels_WM8731{ {{17 * 8, 1 * 8}, "Boost", Color::light_grey()}}; Labels labels_AK4951{ @@ -338,6 +341,22 @@ class MicTXView : public View { ' ', }; + NumberField field_tx_iq_phase_cal_2837{ + {24 * 8, (33 * 8)}, + 2, + {0, 31}, // 5 bits IQ CAL phase adjustment. + 1, + ' ', + }; + + NumberField field_tx_iq_phase_cal_2839{ + {24 * 8, (33 * 8)}, + 2, + {0, 63}, // 6 bits IQ CAL phasse adjustment. + 1, + ' ', + }; + Button tx_button{ {10 * 8, 30 * 8, 10 * 8, 5 * 8}, "PTT TX", diff --git a/firmware/application/hw/max2837.cpp b/firmware/application/hw/max2837.cpp index c2259c27..f262bec9 100644 --- a/firmware/application/hw/max2837.cpp +++ b/firmware/application/hw/max2837.cpp @@ -149,7 +149,33 @@ void MAX2837::init() { set_mode(Mode::Standby); } -enum class Mask { +void MAX2837::set_tx_LO_iq_phase_calibration(const size_t v) { + /* IQ phase deg CAL adj (+4 ...-4) in 32 steps (5 bits), 00000 = +4deg (Q lags I by 94degs, default), 01111 = +0deg, 11111 = -4deg (Q lags I by 86degs) */ + + // TX calibration , Logic pins , ENABLE, RXENABLE, TXENABLE = 1,0,1 (5dec), and Reg address 16, D1 (CAL mode 1):DO (CHIP ENABLE 1) + set_mode(Mode::Tx_Calibration); // write to ram 3 LOGIC Pins . + + gpio_max283x_enable.output(); + gpio_max2837_rxenable.output(); + gpio_max2837_txenable.output(); + + _map.r.spi_en.CAL_SPI = 1; // Register Settings reg address 16, D1 (CAL mode 1) + _map.r.spi_en.EN_SPI = 1; // Register Settings reg address 16, DO (CHIP ENABLE 1) + flush_one(Register::SPI_EN); + + _map.r.tx_lo_iq.TXLO_IQ_SPI_EN = 1; // reg 30 D5, TX LO I/Q Phase SPI Adjust. Active when Address 30 D5 (TXLO_IQ_SPI_EN) = 1. + _map.r.tx_lo_iq.TXLO_IQ_SPI = v; // reg 30 D4:D0, TX LO I/Q Phase SPI Adjust. + flush_one(Register::TX_LO_IQ); + + // Exit Calibration mode, Go back to reg 16, D1:D0 , Out of CALIBRATION , back to default conditions, but keep CS activated. + _map.r.spi_en.CAL_SPI = 0; // Register Settings reg address 16, D1 (0 = Normal operation (default) + _map.r.spi_en.EN_SPI = 1; // Register Settings reg address 16, DO (1 = Chip select enable ) + flush_one(Register::SPI_EN); + + set_mode(Mode::Standby); // Back 3 logic pins CALIBRATION mode -> Standby. +} + +enum class Mask { // There are class Mask ,and class mode with same names, but they are not same. Enable = 0b001, RxEnable = 0b010, TxEnable = 0b100, @@ -157,9 +183,11 @@ enum class Mask { Standby = Enable, Receive = Enable | RxEnable, Transmit = Enable | TxEnable, + Rx_calibration = Enable | RxEnable, // sets the same 3 x logic pins to the Receive operating mode. + Tx_calibration = Enable | TxEnable, // sets the same 3 x logic pins to the Transmit operating mode. }; -Mask mode_mask(const Mode mode) { +Mask mode_mask(const Mode mode) { // based on enum Mode cases, we set up the correct 3 logic PINS . switch (mode) { case Mode::Standby: return Mask::Standby; @@ -167,12 +195,16 @@ Mask mode_mask(const Mode mode) { return Mask::Receive; case Mode::Transmit: return Mask::Transmit; + case Mode::Rx_Calibration: // Let's add those two CAL logic pin settings- Rx and Tx calibration modes. + return Mask::Rx_calibration; // same logic pins as Receive mode = Enable | RxEnable, (the difference is in Reg add 16 D1:DO) + case Mode::Tx_Calibration: // Let's add this CAL Tx calibration mode = Transmit. + return Mask::Tx_calibration; // same logic pins as Transmit = Enable | TxEnable,(the difference is in Reg add 16 D1:DO) default: return Mask::Shutdown; } } -void MAX2837::set_mode(const Mode mode) { +void MAX2837::set_mode(const Mode mode) { // We set up the 3 Logic Pins ENABLE, RXENABLE, TXENABLE accordingly to the max2837 mode case, that we want to set up . Mask mask = mode_mask(mode); gpio_max283x_enable.write(toUType(mask) & toUType(Mask::Enable)); gpio_max2837_rxenable.write(toUType(mask) & toUType(Mask::RxEnable)); diff --git a/firmware/application/hw/max2837.hpp b/firmware/application/hw/max2837.hpp index 28c3fc38..96eb2709 100644 --- a/firmware/application/hw/max2837.hpp +++ b/firmware/application/hw/max2837.hpp @@ -829,6 +829,7 @@ class MAX2837 : public MAX283x { bool set_frequency(const rf::Frequency lo_frequency) override; void set_rx_lo_iq_calibration(const size_t v) override; + void set_tx_LO_iq_phase_calibration(const size_t v) override; void set_rx_bias_trim(const size_t v); void set_vco_bias(const size_t v); void set_rx_buff_vcm(const size_t v) override; diff --git a/firmware/application/hw/max2839.cpp b/firmware/application/hw/max2839.cpp index 1b4bc8c2..bc50b118 100644 --- a/firmware/application/hw/max2839.cpp +++ b/firmware/application/hw/max2839.cpp @@ -142,6 +142,31 @@ void MAX2839::init() { set_mode(Mode::Standby); } +void MAX2839::set_tx_LO_iq_phase_calibration(const size_t v) { + /* IQ phase deg CAL adj (+4 ...-4) This IC in 64 steps (6 bits), 000000 = +4deg (Q lags I by 94degs, default), 011111 = +0deg, 111111 = -4deg (Q lags I by 86degs) */ + + // TX calibration , 2 x Logic pins , ENABLE, RXENABLE = 1,0, (2dec), and Reg address 16, D1 (CAL mode 1):DO (CHIP ENABLE 1) + set_mode(Mode::Tx_Calibration); // write to ram 3 LOGIC Pins . + + gpio_max283x_enable.output(); // max2839 has only 2 x pins + regs to decide mode. + gpio_max2839_rxtx.output(); // Here is combined rx & tx pin in one port. + + _map.r.spi_en.CAL_SPI = 1; // Register Settings reg address 16, D1 (CAL mode 1) + _map.r.spi_en.EN_SPI = 1; // Register Settings reg address 16, DO (CHIP ENABLE 1) + flush_one(Register::SPI_EN); + + _map.r.pa_drv.TXLO_IQ_SPI_EN = 1; // reg 27 D6, TX LO I/Q Phase SPI Adjust. Active when Address 27 D6 (TXLO_IQ_SPI_EN) = 1. + _map.r.pa_drv.TXLO_IQ_SPI = v; // reg 27 D5:D0 6 bits, TX LO I/Q Phase SPI Adjust. + flush_one(Register::PA_DRV); + + // Exit Calibration mode, Go back to reg 16, D1:D0 , Out of CALIBRATION , back to default conditions, but keep CS activated. + _map.r.spi_en.CAL_SPI = 0; // Register Settings reg address 16, D1 (0 = Normal operation (default) + _map.r.spi_en.EN_SPI = 1; // Register Settings reg address 16, DO (1 = Chip select enable ) + flush_one(Register::SPI_EN); + + set_mode(Mode::Standby); // Back 3 logic pins CALIBRATION mode -> Standby. +} + enum class Mask { Enable = 0b01, RxTx = 0b10, @@ -149,6 +174,8 @@ enum class Mask { Standby = RxTx, Receive = Enable | RxTx, Transmit = Enable, + Rx_calibration = Enable | RxTx, // sets the same 2 x logic pins to the Receive operating mode. + Tx_calibration = Enable, // sets the same 2 x logic pins to the Transmit operating mode. }; Mask mode_mask(const Mode mode) { @@ -159,6 +186,10 @@ Mask mode_mask(const Mode mode) { return Mask::Receive; case Mode::Transmit: return Mask::Transmit; + case Mode::Rx_Calibration: // Let's add this not used previously Rx calibration mode. + return Mask::Rx_calibration; // same logic pins as Receive mode = Enable | RxTx, ,(the difference is in Regs ) + case Mode::Tx_Calibration: // Let's add this not used previously Tx calibration mode. + return Mask::Tx_calibration; // same logic pins as Transmit = Enable , (the difference is in Reg add 16 D1:DO) default: return Mask::Shutdown; } diff --git a/firmware/application/hw/max2839.hpp b/firmware/application/hw/max2839.hpp index 7c9fac11..fba590fd 100644 --- a/firmware/application/hw/max2839.hpp +++ b/firmware/application/hw/max2839.hpp @@ -690,6 +690,7 @@ class MAX2839 : public MAX283x { void set_lpf_rf_bandwidth_tx(const uint32_t bandwidth_minimum) override; bool set_frequency(const rf::Frequency lo_frequency) override; void set_rx_lo_iq_calibration(const size_t v) override; + void set_tx_LO_iq_phase_calibration(const size_t v) override; void set_rx_buff_vcm(const size_t v) override; int8_t temp_sense() override; diff --git a/firmware/application/hw/max283x.hpp b/firmware/application/hw/max283x.hpp index 05591db4..b25de3f8 100644 --- a/firmware/application/hw/max283x.hpp +++ b/firmware/application/hw/max283x.hpp @@ -98,11 +98,13 @@ constexpr auto bandwidth_maximum = bandwidths[bandwidths.size() - 1]; /*************************************************************************/ -enum Mode { +enum Mode { // MAX283x Operating modes. Shutdown, Standby, Receive, Transmit, + Rx_Calibration, // just add the sequential enum of those two CAL operating modes . + Tx_Calibration, }; using reg_t = uint16_t; @@ -124,6 +126,8 @@ class MAX283x { virtual bool set_frequency(const rf::Frequency lo_frequency); virtual void set_rx_lo_iq_calibration(const size_t v); + virtual void set_tx_LO_iq_phase_calibration(const size_t v); + virtual void set_rx_buff_vcm(const size_t v); virtual int8_t temp_sense(); diff --git a/firmware/application/radio.cpp b/firmware/application/radio.cpp index b6fd614d..5ef06b22 100644 --- a/firmware/application/radio.cpp +++ b/firmware/application/radio.cpp @@ -248,6 +248,10 @@ void set_antenna_bias(const bool on) { } } +void set_tx_max283x_iq_phase_calibration(const size_t v) { + second_if->set_tx_LO_iq_phase_calibration(v); +} + /*void enable(Configuration configuration) { configure(configuration); } diff --git a/firmware/application/radio.hpp b/firmware/application/radio.hpp index 5b2a74d2..293b9363 100644 --- a/firmware/application/radio.hpp +++ b/firmware/application/radio.hpp @@ -54,6 +54,7 @@ void set_baseband_filter_bandwidth_rx(const uint32_t bandwidth_minimum); void set_baseband_filter_bandwidth_tx(const uint32_t bandwidth_minimum); void set_baseband_rate(const uint32_t rate); void set_antenna_bias(const bool on); +void set_tx_max283x_iq_phase_calibration(const size_t v); /* Use ReceiverModel or TransmitterModel instead. */ // void enable(Configuration configuration);