diff --git a/firmware/application/apps/ui_debug.cpp b/firmware/application/apps/ui_debug.cpp index 168d8a5f7..c5cd42ece 100644 --- a/firmware/application/apps/ui_debug.cpp +++ b/firmware/application/apps/ui_debug.cpp @@ -1342,16 +1342,16 @@ Si5351DebugView::Si5351DebugView(NavigationView& nav) &text_sys_init_status, &text_xtal_cap_label, &text_xtal_cap_value, - &text_clkin_label, - &text_clkin_status, &text_clk0_label, &text_clk0_status, - &text_clk0_freq_label, &text_clk0_freq_value, - &text_clk0_div_label, &text_clk0_div_value, &text_clk1_label, &text_clk1_status, + &text_clk4_label, + &text_clk4_status, + &text_clk5_label, + &text_clk5_status, &button_refresh, &button_reset_pll, &button_done}); @@ -1424,11 +1424,6 @@ void Si5351DebugView::refresh_status() { // Read clock output enables (reg 16-23 control, reg 3 for output enable mask) uint8_t output_enable_mask = portapack::clock_manager.si5351_read_register(3); - // CLKIN - text_clkin_status.set(los_clkin ? "LOS" : "CLOCK SIGNAL"); - text_clkin_status.set_style(los_clkin ? Theme::getInstance()->fg_red - : Theme::getInstance()->fg_green); - // CLK0 (bit 0 of reg 3, reg 16 for control) uint8_t clk0_ctrl = portapack::clock_manager.si5351_read_register(16); bool clk0_enabled = !(output_enable_mask & 0x01) && !(clk0_ctrl & 0x80); @@ -1465,8 +1460,8 @@ void Si5351DebugView::refresh_status() { uint32_t freq_khz = 800000 / ms_div / r_div; // Result in kHz // Show P1 value and R45 for debugging - text_clk0_freq_value.set(to_string_dec_uint(freq_khz) + " kHz (P1:" + to_string_hex(p1, 4) + ")"); - text_clk0_div_value.set("MS=" + to_string_dec_uint(ms_div) + + text_clk0_freq_value.set("F:" + to_string_dec_uint(freq_khz / 1000) + "MHz (P1:" + to_string_hex(p1, 4) + ")"); + text_clk0_div_value.set("DIV: MS=" + to_string_dec_uint(ms_div) + " R=" + to_string_dec_uint(r_div)); // Color code based on expected 8 MHz @@ -1484,6 +1479,20 @@ void Si5351DebugView::refresh_status() { text_clk1_status.set(clk1_enabled ? "ON" : "OFF"); text_clk1_status.set_style(clk1_enabled ? Theme::getInstance()->fg_green : Theme::getInstance()->fg_red); + + // CLK4 (MAX2831 reference - bit 4 of reg 3, reg 20 for control) + uint8_t clk4_ctrl = portapack::clock_manager.si5351_read_register(20); + bool clk4_enabled = !(output_enable_mask & 0x10) && !(clk4_ctrl & 0x80); + text_clk4_status.set(clk4_enabled ? "ON (40MHz)" : "OFF"); + text_clk4_status.set_style(clk4_enabled ? Theme::getInstance()->fg_green + : Theme::getInstance()->fg_red); + + // CLK5 (RFFC5072 reference - bit 5 of reg 3, reg 21 for control) + uint8_t clk5_ctrl = portapack::clock_manager.si5351_read_register(21); + bool clk5_enabled = !(output_enable_mask & 0x20) && !(clk5_ctrl & 0x80); + text_clk5_status.set(clk5_enabled ? "ON (40MHz)" : "OFF"); + text_clk5_status.set_style(clk5_enabled ? Theme::getInstance()->fg_green + : Theme::getInstance()->fg_red); } void Si5351DebugView::reset_pll() { @@ -1827,11 +1836,6 @@ void SystemDiagnosticsView::read_gpio_states() { uint32_t gpio3_state = LPC_GPIO->PIN[3]; // GPIO3 for mixer uint32_t gpio4_state = LPC_GPIO->PIN[4]; // GPIO4 for LPF and amp - // Extract specific pins based on hackrf_gpio.hpp definitions: - // gpio_mix_enable_n = GPIO3_2 (P6_3) - bit 2 of port 3, INVERTED - // gpio_lpf_enable = GPIO4_8 (PA_1) - bit 8 of port 4 - // gpio_rf_amp_enable = GPIO4_9 (PA_2) - bit 9 of port 4 - bool mix_n_actual = (gpio3_state >> 2) & 1; // GPIO3[2] bool lpf_actual = (gpio4_state >> 8) & 1; // GPIO4[8] bool amp_actual = (gpio4_state >> 9) & 1; // GPIO4[9] @@ -1927,8 +1931,8 @@ void SystemDiagnosticsView::refresh() { GPIODebugView::GPIODebugView(NavigationView& nav) { add_children({ &text_lbl_gpio4, - &text_lbl_dir4, - &text_dir4, + &text_lbl_mixr1, + &text_mixr1, &text_lbl_pin4, &text_pin4, &text_lbl_set4, @@ -2031,7 +2035,7 @@ void GPIODebugView::refresh() { uint32_t gpio4_set = LPC_GPIO->SET[4]; // What we're trying to output // Display full registers - text_dir4.set("0x" + to_string_hex(gpio4_dir, 8)); + // text_dir4.set("0x" + to_string_hex(gpio4_dir, 8)); text_pin4.set("0x" + to_string_hex(gpio4_pin, 8)); text_set4.set("0x" + to_string_hex(gpio4_set, 8)); @@ -2075,6 +2079,22 @@ void GPIODebugView::refresh() { text_mix_dir.set_style(mix_dir ? Theme::getInstance()->fg_green : Theme::getInstance()->fg_red); text_mix_pin.set_style(mix_pin ? Theme::getInstance()->fg_green : Theme::getInstance()->fg_red); + + // Read GPIO5 (Mixer R1) - bit 2 + uint32_t gpio3_state = LPC_GPIO->PIN[3]; // GPIO3 for mixer + bool mix_n_actual = (gpio3_state >> 2) & 1; // GPIO3[2] + uint32_t gpio5_state = LPC_GPIO->PIN[5]; + bool mix_r10_pin = (gpio5_state >> 6) & 1; // GPIO5[6] = P2_6 + // Mixer is active LOW, so invert for display + bool mixer_enabled = !mix_n_actual; + + // Append to existing mixer display: + text_mixr1.set( + std::string(mixer_enabled ? "ENABLED" : "BYPASSED") + + " P6_3=" + to_string_dec_uint(mix_n_actual ? 1 : 0) + + " P2_6=" + to_string_dec_uint(mix_r10_pin ? 1 : 0)); + + text_mixr1.set_style(mixer_enabled ? Theme::getInstance()->fg_green : Theme::getInstance()->fg_red); } #endif @@ -2087,7 +2107,6 @@ RFFC5072StatusView::RFFC5072StatusView(NavigationView& nav) &text_title, &text_lbl_lock, &text_lock, - &text_lbl_ctrl, &text_ctrl, &text_lbl_enabled, &text_enabled, @@ -2113,6 +2132,7 @@ RFFC5072StatusView::RFFC5072StatusView(NavigationView& nav) &text_lbl_regs_status, &text_regs_status, &button_refresh, + &button_force_enx, &button_done, }); @@ -2122,6 +2142,14 @@ RFFC5072StatusView::RFFC5072StatusView(NavigationView& nav) refresh_status(); }; + button_force_enx.on_select = [this](Button&) { + // Force ENX to OUTPUT and drive LOW + LPC_GPIO->DIR[2] |= (1 << 13); // Set as OUTPUT + LPC_GPIO->CLR[2] = (1 << 13); // Drive LOW (enabled) + + refresh_status(); + }; + button_done.on_select = [&nav](Button&) { nav.pop(); }; @@ -2135,6 +2163,10 @@ void RFFC5072StatusView::focus() { } void RFFC5072StatusView::refresh_status() { + // === DEBUG: Capture GPIO state BEFORE any operations === + uint32_t gpio2_before = LPC_GPIO->PIN[2]; + bool enx_before = (gpio2_before >> 13) & 1; + // === READ RAW GPIO STATES FOR DEBUGGING === uint32_t gpio2_dir = LPC_GPIO->DIR[2]; uint32_t gpio2_pin = LPC_GPIO->PIN[2]; @@ -2164,11 +2196,10 @@ void RFFC5072StatusView::refresh_status() { bool enx = (gpio2_pin >> 13) & 1; bool resetx = (gpio2_pin >> 14) & 1; - text_ctrl.set( - std::string(enx ? "DIS" : "EN") + " " + - std::string(resetx ? "RUN" : "RST") + " " + - "EO:" + std::string(enx_is_output ? "Y" : "N") + " " + - "RO:" + std::string(resetx_is_output ? "Y" : "N")); + text_ctrl.set("ENX: " + std::string(enx ? "DIS" : "EN") + + " O:" + std::string(enx_is_output ? "Y" : "N") + + " | RST: " + std::string(resetx ? "RUN" : "RST") + + " O:" + std::string(resetx_is_output ? "Y" : "N")); text_ctrl.set_style((enx == 0 && resetx == 1) ? Theme::getInstance()->fg_green : Theme::getInstance()->fg_red); @@ -2209,15 +2240,25 @@ void RFFC5072StatusView::refresh_status() { uint32_t f_vco_mhz = (f_ref_mhz * n_int) / presc_val; uint32_t f_lo_mhz = f_vco_mhz / lodiv_val; - text_calc.set(to_string_dec_uint(f_lo_mhz) + " MHz"); - text_freq.set(to_string_dec_uint(f_vco_mhz) + " MHz VCO"); - // Check ranges + // RFFC5072 datasheet: Output 85-4200 MHz, VCO 2700-5400 MHz bool vco_ok = (f_vco_mhz >= 2700) && (f_vco_mhz <= 5400); - bool lo_ok = (f_lo_mhz >= 2300) && (f_lo_mhz <= 2700); + bool lo_ok = (f_lo_mhz >= 85) && (f_lo_mhz <= 4200); - text_calc.set_style(lo_ok ? Theme::getInstance()->fg_green - : Theme::getInstance()->fg_red); + // PRALINE mid-band (2320-2740 MHz) uses direct path, not RFFC5072 + bool in_bypass_range = (f_lo_mhz >= 2320) && (f_lo_mhz <= 2740); + + // Display with range annotation + if (in_bypass_range) { + text_calc.set(to_string_dec_uint(f_lo_mhz) + " MHz (MID)"); + text_calc.set_style(Theme::getInstance()->fg_orange); // Orange = bypass band + } else { + text_calc.set(to_string_dec_uint(f_lo_mhz) + " MHz"); + text_calc.set_style(lo_ok ? Theme::getInstance()->fg_green + : Theme::getInstance()->fg_red); + } + + text_freq.set(to_string_dec_uint(f_vco_mhz) + " MHz VCO"); text_freq.set_style(vco_ok ? Theme::getInstance()->fg_green : Theme::getInstance()->fg_red); diff --git a/firmware/application/apps/ui_debug.hpp b/firmware/application/apps/ui_debug.hpp index 31a9fc50b..7914e2ea8 100644 --- a/firmware/application/apps/ui_debug.hpp +++ b/firmware/application/apps/ui_debug.hpp @@ -643,37 +643,36 @@ class Si5351DebugView : public View { private: NavigationView& nav_; - Text text_title{{8, 16, 200, 16}, "Si5351 Clock Generator"}; + Text text_title{{0, 0, 200, 16}, "Si5351 Clock Generator"}; - Text text_status_label{{8, 40, 80, 16}, "Status Reg:"}; - Text text_status_value{{96, 40, 144, 16}, ""}; + Text text_status_label{{0, 16, 80, 16}, "Status Reg:"}; + Text text_status_value{{96, 16, 144, 16}, ""}; - Text text_pll_a_label{{8, 60, 80, 16}, "PLL A:"}; - Text text_pll_a_status{{96, 60, 144, 16}, ""}; + Text text_pll_a_label{{0, 32, 80, 16}, "PLL A:"}; + Text text_pll_a_status{{96, 32, 144, 16}, ""}; - Text text_pll_b_label{{8, 80, 80, 16}, "PLL B:"}; - Text text_pll_b_status{{96, 80, 144, 16}, ""}; + Text text_pll_b_label{{0, 48, 80, 16}, "PLL B:"}; + Text text_pll_b_status{{96, 48, 144, 16}, ""}; - Text text_sys_init_label{{8, 100, 80, 16}, "SYS_INIT:"}; - Text text_sys_init_status{{96, 100, 144, 16}, ""}; + Text text_sys_init_label{{0, 64, 80, 16}, "SYS_INIT:"}; + Text text_sys_init_status{{96, 64, 144, 16}, ""}; - Text text_xtal_cap_label{{8, 120, 80, 16}, "XTAL Cap:"}; - Text text_xtal_cap_value{{96, 120, 144, 16}, ""}; + Text text_xtal_cap_label{{0, 80, 80, 16}, "XTAL Cap:"}; + Text text_xtal_cap_value{{96, 80, 144, 16}, ""}; - Text text_clkin_label{{8, 140, 72, 16}, "CLKIN:"}; - Text text_clkin_status{{88, 140, 160, 16}, ""}; + Text text_clk0_label{{0, 96, 48, 16}, "CLK0:"}; + Text text_clk0_status{{50, 96, 28, 16}, ""}; + Text text_clk0_freq_value{{80, 96, 160, 16}, ""}; + Text text_clk0_div_value{{50, 112, 190, 16}, ""}; - Text text_clk0_label{{8, 160, 72, 16}, "CLK0:"}; - Text text_clk0_status{{88, 160, 152, 16}, ""}; + Text text_clk1_label{{0, 128, 96, 16}, "CLK1 (SCT):"}; + Text text_clk1_status{{112, 128, 128, 16}, ""}; - Text text_clk0_freq_label{{8, 180, 72, 16}, " Freq:"}; - Text text_clk0_freq_value{{88, 180, 152, 16}, ""}; + Text text_clk4_label{{0, 144, 96, 16}, "CLK4 (MAX):"}; + Text text_clk4_status{{112, 144, 128, 16}, ""}; - Text text_clk0_div_label{{8, 200, 72, 16}, " Div:"}; - Text text_clk0_div_value{{88, 200, 152, 16}, ""}; - - Text text_clk1_label{{8, 220, 96, 16}, "CLK1 (SCT):"}; - Text text_clk1_status{{112, 220, 128, 16}, ""}; + Text text_clk5_label{{0, 160, 96, 16}, "CLK5 (RFFC):"}; + Text text_clk5_status{{112, 160, 128, 16}, ""}; Button button_refresh{{8, 240, 72, 24}, "Refresh"}; Button button_reset_pll{{88, 240, 72, 24}, "Reset PLL"}; @@ -697,7 +696,7 @@ class SignalPathStatusView : public View { Text text_title{{0, 0, 240, 16}, "=== Signal Path Status ==="}; - Text text_lbl_max_enable{{0, 20, 1114, 16}, "MAX2831:"}; + Text text_lbl_max_enable{{0, 20, 114, 16}, "MAX2831:"}; Text text_max_enable{{116, 20, 124, 16}, "---"}; Text text_lbl_max_mode{{0, 36, 114, 16}, "RX Mode:"}; @@ -751,8 +750,8 @@ class GPIODebugView : public View { // GPIO4 (LPF and RF Amp) Text text_lbl_gpio4{{0, 0, 240, 16}, "Pin Diag: GPIO4 (LPF|Amp|Mix)"}; - Text text_lbl_dir4{{0, 18, 114, 16}, "DIR[4]:"}; - Text text_dir4{{116, 18, 124, 16}, "---"}; + Text text_lbl_mixr1{{0, 18, 56, 16}, "MixR1:"}; + Text text_mixr1{{58, 18, 180, 16}, "---"}; Text text_lbl_pin4{{0, 36, 114, 16}, "PIN[4] (read):"}; Text text_pin4{{116, 36, 124, 16}, "---"}; @@ -810,8 +809,7 @@ class RFFC5072StatusView : public View { Text text_lbl_lock{{0, 16, 114, 16}, "Lock Detect:"}; Text text_lock{{116, 16, 124, 16}, "---"}; - Text text_lbl_ctrl{{0, 32, 114, 16}, "Control:"}; - Text text_ctrl{{116, 32, 124, 16}, "---"}; + Text text_ctrl{{0, 32, 240, 16}, "---"}; Text text_lbl_enabled{{0, 48, 114, 16}, "Status:"}; Text text_enabled{{116, 48, 124, 16}, "---"}; @@ -848,7 +846,8 @@ class RFFC5072StatusView : public View { Text text_lbl_regs_status{{0, 224, 48, 16}, "Regs:"}; Text text_regs_status{{50, 224, 190, 16}, "---"}; - Button button_refresh{{2, 280, 56, 24}, "Rfrsh"}; + Button button_refresh{{2, 280, 72, 24}, "Refresh"}; + Button button_force_enx{{98, 280, 60, 24}, "T_ENX"}; Button button_done{{182, 280, 56, 24}, "Done"}; }; diff --git a/firmware/application/hw/rffc507x.cpp b/firmware/application/hw/rffc507x.cpp index 87acc938f..ef71ac239 100644 --- a/firmware/application/hw/rffc507x.cpp +++ b/firmware/application/hw/rffc507x.cpp @@ -197,7 +197,15 @@ struct SynthConfig { */ void RFFC507x::init() { -#ifndef PRALINE +#ifdef PRALINE + // CRITICAL: Enable RFFC5072 BEFORE any SPI communication! + // Without this, SPI writes are ignored when ENX=1 (disabled) + gpio_rffc5072_enx.output(); + gpio_rffc5072_enx.clear(); // ENX=0 (enabled) + + // Small delay for chip to power up + chThdSleepMilliseconds(1); +#else gpio_rffc5072_resetx.set(); gpio_rffc5072_resetx.output(); reset(); @@ -291,6 +299,9 @@ void RFFC507x::set_frequency(const rf::Frequency lo_frequency) { const SynthConfig synth_config = SynthConfig::calculate(lo_frequency); #ifdef PRALINE + // Ensure RFFC5072 is enabled before SPI writes + gpio_rffc5072_enx.clear(); // ENX=0 (enabled) + // Calculate VCO frequency from LO frequency and divider const size_t lo_divider = 1U << synth_config.lo_divider_log2; // 2^lodiv_log2 const rf::Frequency vco_freq = lo_frequency * lo_divider; diff --git a/firmware/application/main.cpp b/firmware/application/main.cpp old mode 100755 new mode 100644 index 02b7531d8..76911cb8f --- a/firmware/application/main.cpp +++ b/firmware/application/main.cpp @@ -181,7 +181,9 @@ static void event_loop() { } int main(void) { +#ifndef PRALINE // Do not perform quick set up of GP01_RFF507X = 1 for PRALINE first_if.init(); /* To avoid initial short Ant_DC_Bias pulse ,we need quick set up GP01_RFF507X =1 */ +#endif if (config_mode_should_enter()) { config_mode_clear(); diff --git a/firmware/application/radio.cpp b/firmware/application/radio.cpp index fe5096f44..09266320e 100644 --- a/firmware/application/radio.cpp +++ b/firmware/application/radio.cpp @@ -147,15 +147,13 @@ void init() { ? (max283x::MAX283x*)&second_if_max2839 : (max283x::MAX283x*)&second_if_max2837; #endif + rf_path.init(); first_if.init(); second_if->init(); baseband_codec.init(); -#ifndef PRALINE - /* HackRF One uses CPLD for Q inversion control. - * PRALINE uses FPGA and the pin (P2_3) is used for LCD_TE on H4M. */ - baseband_cpld.init(); -#else + +#ifdef PRALINE /* Initialize FPGA registers - DC_BLOCK must be enabled for RX */ // debug::fpga::init(); fpga_debug_register_write(1, 0x01); // DC_BLOCK=1, QUARTER_SHIFT=0, Q_INVERT=0 @@ -166,6 +164,10 @@ void init() { ssp1_arbiter.invalidate(); chThdSleepMilliseconds(10); // Let FPGA registers settle +#else + /* HackRF One uses CPLD for Q inversion control. + * PRALINE uses FPGA and the pin (P2_3) is used for LCD_TE on H4M. */ + baseband_cpld.init(); #endif } @@ -204,9 +206,8 @@ void set_direction(const rf::Direction new_direction) { */ baseband_invert = false; } -#ifndef PRALINE - baseband_cpld.set_invert(mixer_invert ^ baseband_invert); -#else + +#ifdef PRALINE // TEST: Force baseband invert for Praline (like r9) // baseband_invert = (direction == rf::Direction::Receive); @@ -217,6 +218,8 @@ void set_direction(const rf::Direction new_direction) { } fpga_debug_register_write(1, ctrl_reg); ssp1_arbiter.invalidate(); +#else + baseband_cpld.set_invert(mixer_invert ^ baseband_invert); #endif second_if->set_mode((direction == rf::Direction::Transmit) ? max283x::Mode::Transmit : max283x::Mode::Receive); @@ -263,6 +266,10 @@ bool set_tuning_frequency(const rf::Frequency frequency) { if (tuning_config.first_lo_frequency) { first_if.set_frequency(tuning_config.first_lo_frequency); first_if.enable(); +#ifdef PRALINE + first_if.flush(); // Force register write with reference clock present + chThdSleepMilliseconds(10); // Allow PLL to settle +#endif } // Program second local oscillator frequency into MAX283x @@ -270,9 +277,8 @@ bool set_tuning_frequency(const rf::Frequency frequency) { rf_path.set_band(tuning_config.rf_path_band); mixer_invert = tuning_config.mixer_invert; -#ifndef PRALINE - baseband_cpld.set_invert(mixer_invert ^ baseband_invert); -#else + +#ifdef PRALINE // TEST: Force baseband invert for Praline (like r9) // baseband_invert = (direction == rf::Direction::Receive); @@ -283,6 +289,10 @@ bool set_tuning_frequency(const rf::Frequency frequency) { } fpga_debug_register_write(1, ctrl_reg); ssp1_arbiter.invalidate(); + // Log this value somewhere you can see it + uint32_t written_r15 = first_if.read(15); +#else + baseband_cpld.set_invert(mixer_invert ^ baseband_invert); #endif return result_second_if; @@ -352,20 +362,6 @@ void set_rx_max283x_iq_phase_calibration(const size_t v) { second_if->set_rx_LO_iq_phase_calibration(v); } -/*void enable(Configuration configuration) { - configure(configuration); -} - -void configure(Configuration configuration) { - set_tuning_frequency(configuration.tuning_frequency); - set_rf_amp(configuration.rf_amp); - set_lna_gain(configuration.lna_gain); - set_vga_gain(configuration.vga_gain); - set_baseband_rate(configuration.baseband_rate); - set_baseband_filter_bandwidth(configuration.baseband_filter_bandwidth); - set_direction(configuration.direction); -}*/ - void disable() { set_antenna_bias(false); baseband_codec.set_mode(max5864::Mode::Shutdown); diff --git a/firmware/application/rf_path.cpp b/firmware/application/rf_path.cpp index 9a2aa90a5..51b092db5 100644 --- a/firmware/application/rf_path.cpp +++ b/firmware/application/rf_path.cpp @@ -41,14 +41,18 @@ namespace { */ struct PralineConfig { bool tx_en; - bool mix_en_n; // Inverted: 0 = mixer enabled + // bool mix_en_n; // Inverted: 0 = mixer enabled + bool rffc_enx; // RFFC5072 ENX (GPIO2[13]) + bool mix_bypass; // RF path mixer bypass (GPIO3[2]) bool lpf_en; bool rf_amp_en; bool ant_bias_en_n; // Inverted: 0 = bias enabled static void gpio_init() { gpio_tx_enable.output(); - gpio_mix_enable_n.output(); + // gpio_mix_enable_n.output(); + gpio_rffc5072_enx.output(); + gpio_mix_bypass.output(); gpio_lpf_enable.output(); gpio_rf_amp_enable.output(); gpio_ant_bias_disable.output(); @@ -56,7 +60,9 @@ struct PralineConfig { void apply() const { gpio_tx_enable.write(tx_en); - gpio_mix_enable_n.write(mix_en_n); + // gpio_mix_enable_n.write(mix_en_n); + gpio_rffc5072_enx.write(rffc_enx); // Control RFFC5072 ENX + gpio_mix_bypass.write(mix_bypass); // Control RF path mixer gpio_lpf_enable.write(lpf_en); gpio_rf_amp_enable.write(rf_amp_en); gpio_ant_bias_disable.write(ant_bias_en_n); @@ -239,7 +245,9 @@ void Path::init() { /* Set safe initial state: RX mode, mixer enabled, LPF on, amp off, no bias */ PralineConfig config = { .tx_en = false, - .mix_en_n = false, // Mixer enabled (inverted) + //.mix_en_n = false, // Mixer enabled (inverted) + .rffc_enx = false, // RFFC5072 ENX (GPIO2[13]) + .mix_bypass = false, // RF path mixer bypass (GPIO3[2]) .lpf_en = true, // LPF on for low band .rf_amp_en = false, // Amp off .ant_bias_en_n = true // Bias off (inverted) @@ -276,7 +284,9 @@ void Path::update() { #ifdef PRALINE /* PRALINE RF path control: * - tx_en: 1 for TX, 0 for RX - * - mix_en_n: 0 to enable mixer (inverted), 1 to bypass + * // - mix_en_n: 0 to enable mixer (inverted), 1 to bypass + * - rffc_enx: 0 to enable RFFC5072 ENX (GPIO2[13]) + * - mix_bypass: 0 to enable RF path mixer bypass (GPIO3[2]) * - lpf_en: 1 for low band (< 2.4 GHz), 0 for high band * - rf_amp_en: 1 to enable RF amplifier * - ant_bias_en_n: 0 to enable antenna bias (inverted) @@ -294,8 +304,12 @@ void Path::update() { config.tx_en = (direction == Direction::Transmit); - /* Mixer bypass for mid band (2.3-2.7 GHz direct to MAX2831) */ - config.mix_en_n = (band == Band::Mid); // 1 = bypass (disabled) + // RFFC5072 ENX: Active LOW, so invert the band check + // ENX=0 (enabled) for Low/High, ENX=1 (disabled) for Mid + config.rffc_enx = (band == Band::Mid); // 0=enabled, 1=disabled + + // RF path mixer bypass: 0=enabled, 1=bypassed + config.mix_bypass = (band == Band::Mid); /* Move to the final state by turning on required signals. */ /* LPF for low band */ diff --git a/firmware/application/rf_path.hpp b/firmware/application/rf_path.hpp index 5393df87b..d098b2e37 100644 --- a/firmware/application/rf_path.hpp +++ b/firmware/application/rf_path.hpp @@ -39,9 +39,17 @@ enum class Direction { namespace path { +#ifdef PRALINE +/* PRALINE: MAX2831 direct path is 2320-2740 MHz */ +constexpr FrequencyRange band_low{0, 2320'000'000}; +constexpr FrequencyRange band_high{2740'000'000, 7250'000'000}; +constexpr FrequencyRange band_mid{band_low.maximum, band_high.minimum}; +#else +/* HackRF One: Original band boundaries */ constexpr FrequencyRange band_low{0, 2170'000'000}; constexpr FrequencyRange band_high{2740'000'000, 7250'000'000}; constexpr FrequencyRange band_mid{band_low.maximum, band_high.minimum}; +#endif enum class Band { /* Zero-based, used as index into frequency_bands table */ diff --git a/firmware/chibios-portapack/boards/PORTAPACK_APPLICATION/board.cpp b/firmware/chibios-portapack/boards/PORTAPACK_APPLICATION/board.cpp index 7aa060554..02ec6573f 100755 --- a/firmware/chibios-portapack/boards/PORTAPACK_APPLICATION/board.cpp +++ b/firmware/chibios-portapack/boards/PORTAPACK_APPLICATION/board.cpp @@ -61,7 +61,11 @@ const PALConfig pal_default_config = { .P = { { // GPIO0 .data +#ifdef PRALINE + = (0 << 15) // P1_20: CLKIN_CTRL - start low +#else = (1 << 15) // P1_20: CS_XCVR +#endif | (1 << 14) // P2_10: AMP_BYPASS | (0 << 13) // P1_18: SGPIO12, HOST_Q_INVERT | (0 << 12) // P1_17: SGPIO11, HOST_DIRECTION @@ -79,8 +83,12 @@ const PALConfig pal_default_config = { | (1 << 0) // P0_0: SGPIO0, HOST_DATA0 , .dir +#ifdef PRALINE + = (1 << 15) // P1_20: CLKIN_CTRL - output +#else = (1 << 15) // P1_20: CS_XCVR - | (1 << 14) // P2_10: AMP_BYPASS +#endif + | (1 << 14) // P2_10: AMP_BYPASS | (1 << 13) // P1_18: SGPIO12, HOST_Q_INVERT | (0 << 12) // P1_17: SGPIO11, HOST_DIRECTION | (0 << 11) // P1_4: SSP1_MOSI @@ -137,7 +145,11 @@ const PALConfig pal_default_config = { .data = (0 << 15) // P5_6: TX_AMP | (1 << 14) // P5_5: MIXER_RESETX, 10K PU +#ifdef PRALINE + | (0 << 13) // P5_4: MIXER_ENX, 10K PU +#else | (1 << 13) // P5_4: MIXER_ENX, 10K PU +#endif | (1 << 12) // P5_3: RX_MIX_BP | (0 << 11) // P5_2: TX_MIX_BP | (0 << 10) // P5_1: LP @@ -154,11 +166,19 @@ const PALConfig pal_default_config = { , .dir = (1 << 15) // P5_6: TX_AMP - | (1 << 14) // P5_5: MIXER_RESETX, 10K PU - | (1 << 13) // P5_4: MIXER_ENX, 10K PU +#ifdef PRALINE + | (0 << 14) // P5_5: MIXER_RESETX, 10K PU + | (1 << 13) // P5_4: MIXER_ENX - OUTPUT (MCU controlled) + | (0 << 12) // P5_3: RX_MIX_BP - unused on PRALINE + | (0 << 11) // P5_2: FPGA_CRESET - INPUT initially + | (0 << 10) // P5_1: FPGA_SPI_CS - INPUT initially +#else + | (1 << 14) // P5_5: MIXER_RESETX, 10K PU + | (1 << 13) // P5_4: MIXER_ENX, 10K PU | (1 << 12) // P5_3: RX_MIX_BP | (1 << 11) // P5_2: TX_MIX_BP | (1 << 10) // P5_1: LP +#endif | (0 << 9) // P5_0: Varies by revision, float until detection | (1 << 8) // P6_12: LED3 (TX) | (1 << 7) // P5_7: CS_AD @@ -306,7 +326,13 @@ const PALConfig pal_default_config = { { 1, 7, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* !MIX_BYPASS/P35: U1.VCTL1(I), U11.VCTL2(I), U9.V2(I) */ { 1, 19, scu_config_normal_drive_t { .mode=1, .epd=0, .epun=0, .ehs=0, .ezi=0, .zif=0 } }, /* SSP1_SCK/P39: MAX2837.SCLK(I), MAX5864.SCLK(I) */ { 1, 20, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* CS_XCVR/P53: MAX2837.CS(I) */ + +#ifdef PRALINE + { 2, 6, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=1, .ehs=1, .ezi=0, .zif=1 } }, /* TRIGGER_OUT / MIX_EN_N_R1_0: GPIO5[6] - PRALINE */ +#else + /* HackRF One RFFC5072 SPI pins */ { 2, 6, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* MIXER_SCLK/P31: 33pF, RFFC5072.SCLK(I) */ +#endif { 2, 10, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* AMP_BYPASS/P50: U14.V2(I), U12.V2(I) */ { 2, 11, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* RX_AMP/P49: U12.V1(I), U14.V3(I) */ { 2, 12, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* !RX_AMP_PWR/P52: 10K PU, Q1.G(I), power to U13 (RX amp) */ @@ -319,8 +345,16 @@ const PALConfig pal_default_config = { { 5, 4, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* MIXER_ENX/P32: 10K PU, 33pF, RFFC5072.ENX(I) */ { 5, 5, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* MIXER_RESETX/P33: 10K PU, 33pF, RFFC5072.RESETX(I) */ { 5, 6, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* TX_AMP/P48: U12.V3(I), U14.V1(I) */ +#ifdef PRALINE + /* PRALINE RFFC5072 SPI pins - different from HackRF One */ + { 5, 7, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* P5_7: GPIO2[7], RFFC5072 CS */ + { 9, 5, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=0, .ehs=1, .ezi=0, .zif=0 } }, /* P9_5: GPIO5[18], RFFC5072 SCLK */ + { 9, 2, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=0, .ehs=1, .ezi=1, .zif=0 } }, /* P9_2: GPIO4[14], RFFC5072 SDATA (bidirectional) */ +#else +/* HackRF One RFFC5072 SPI pins - NOT used on PRALINE */ { 5, 7, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* CS_AD/P54: MAX5864.CS(I) */ { 6, 4, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=0, .ehs=0, .ezi=1, .zif=0 } }, /* MIXER_SDATA/P27: 33pF, RFFC5072.SDATA(IO) */ +#endif { 6, 8, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* MIX_BYPASS/P34: U1.VCTL2(I), U11.VCTL1(I) */ { 6, 9, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* !TX_AMP_PWR/P51: 10K PU, Q2.G(I), power to U25 (TX amp) */ @@ -346,7 +380,9 @@ const PALConfig pal_default_config = { { 6, 1, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* CPLD_TCK: PortaPack CPLD.TCK(I) */ { 6, 2, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=1, .zif=0 } }, /* CPLD_TDI: PortaPack CPLD.TDI(I), I2S0_RX_SDA(O) */ { 6, 5, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=1, .ehs=0, .ezi=0, .zif=0 } }, /* CPLD_TMS: HackRF CPLD.TMS(I) */ +#ifndef PRALINE { 9, 5, scu_config_normal_drive_t { .mode=4, .epd=0, .epun=0, .ehs=0, .ezi=1, .zif=0 } }, /* CPLD_TDO: HackRF CPLD.TDO(O) */ +#endif /* PortaPack CPLD */ { 1, 5, scu_config_normal_drive_t { .mode=0, .epd=0, .epun=0, .ehs=0, .ezi=1, .zif=0 } }, /* SD_POW: PortaPack CPLD.TDO(O) */ @@ -885,21 +921,34 @@ extern "C" void boardInit(void) { { volatile uint32_t delay = 100000; while(delay--); } /* Configure RFFC5072 pins for PRALINE */ - /* P9_2 = GPIO4[14] RFFC5072 data (SCU_GPIO_FAST | FUNCTION0 = 0xF0) */ - LPC_SCU->SFSP[9][2] = 0xF0; - /* P9_5 = GPIO5[18] RFFC5072 clock (SCU_GPIO_FAST | FUNCTION4 = 0xF4) */ - LPC_SCU->SFSP[9][5] = 0xF4; - LPC_GPIO->DIR[5] |= (1 << 18); /* Clock as output */ + /* Set GPIO directions for RFFC5072 SPI pins */ + /* P5_7 = GPIO2[7] RFFC5072 CS */ + LPC_GPIO->SET[2] = (1 << 7); /* CS high (deselected) */ + LPC_GPIO->DIR[2] |= (1 << 7); /* CS as output */ + + /* P9_5 = GPIO5[18] RFFC5072 SCLK */ + LPC_GPIO->CLR[5] = (1 << 18); /* CLK low */ + LPC_GPIO->DIR[5] |= (1 << 18); /* CLK as output */ + + /* P9_2 = GPIO4[14] RFFC5072 DATA (bidirectional) */ + LPC_GPIO->DIR[4] |= (1 << 14); /* DATA as output initially */ + + /* P2_6 = GPIO5[6] TRIGGER_OUT / MIX_EN_N_R1_0 (PRALINE R1.0 mixer bypass) */ + /* SCU configured in PAL array above with mode=4 */ + LPC_GPIO->CLR[5] = (1 << 6); /* Default low (mixer enabled) */ + LPC_GPIO->DIR[5] |= (1 << 6); /* Output */ /* Configure Port D pins for PRALINE (use SFSPD registers) */ /* PD_14 = GPIO6[28] MAX2831 chip select */ LPC_SCU->SFSPD[14] = 0xF4; /* SCU_GPIO_FAST | FUNCTION4 */ LPC_GPIO->SET[6] = (1 << 28); /* CS high (inactive) */ LPC_GPIO->DIR[6] |= (1 << 28); /* Output */ + /* PD_15 = GPIO6[29] MAX2831 RXHP control */ LPC_SCU->SFSPD[15] = 0xF4; /* SCU_GPIO_FAST | FUNCTION4 */ LPC_GPIO->CLR[6] = (1 << 29); /* RXHP low = 100 Hz HPF */ LPC_GPIO->DIR[6] |= (1 << 29); /* Output */ + /* PD_16 = GPIO6[30] MAX5864 chip select */ LPC_SCU->SFSPD[16] = 0xF4; /* SCU_GPIO_FAST | FUNCTION4 */ LPC_GPIO->SET[6] |= (1 << 30); /* CS high (inactive) */ @@ -938,14 +987,15 @@ extern "C" void boardInit(void) { /* Configure RFFC5072 control pins for PRALINE */ /* P5_4 = GPIO2[13] RFFC5072 ENX (active low: 0=enabled) */ LPC_SCU->SFSP[5][4] = 0xF0; /* FUNCTION0 (GPIO), no pulls */ - LPC_GPIO->DIR[2] &= ~(1 << 13); /* ENX: INPUT (let FPGA control) */ + LPC_GPIO->DIR[2] |= (1 << 13); /* ENX: OUTPUT */ + LPC_GPIO->CLR[2] = (1 << 13); /* ENX = 0 (ENABLED) */ /* P5_5 = GPIO2[14] RFFC5072 RESETX - FPGA controlled, MCU should not touch */ LPC_SCU->SFSP[5][5] = 0xF0; /* FUNCTION0 (GPIO), no pulls */ LPC_GPIO->DIR[2] &= ~(1 << 14); /* RESETX: INPUT (let FPGA control) */ /* PD_11 = GPIO6[25] RFFC5072 Lock Detect (input) */ - LPC_SCU->SFSP[0xD][11] = 0xF0; /* FUNCTION0 (GPIO), no pulls */ + LPC_SCU->SFSP[0xD][11] = 0xF4; /* FUNCTION4 (GPIO), no pulls */ /* Small delay for signals to stabilize */ for (volatile int i = 0; i < 10000; i++) {} @@ -979,9 +1029,6 @@ extern "C" void boardInit(void) { LPC_SCU->SFSP[2][2] = 0xF0; /* SGPIO6: P2_2 function 0, HOST_DATA6 */ LPC_SCU->SFSP[1][0] = 0xF6; /* SGPIO7: P1_0 function 6, HOST_DATA7 */ - /* NOTE: P9_5 is RFFC5072 mixer clock (SCU_MIXER_SCLK), NOT SGPIO! - * Do NOT override P9_5 here. */ - // Trigger FPGA bitstream loading via fpga bridge // Attempt to load the FPGA bitstream // This function returns LD_SUCCESS (0) if the FPGA confirms the bitstream diff --git a/firmware/common/cpld_update.cpp b/firmware/common/cpld_update.cpp index b0d359aa0..8865bb08a 100644 --- a/firmware/common/cpld_update.cpp +++ b/firmware/common/cpld_update.cpp @@ -213,6 +213,24 @@ CpldUpdateStatus update_autodetect(const Config config_rev_20150901, const Confi namespace hackrf { namespace cpld { +#ifdef PRALINE + +/* PRALINE has no HackRF CPLD - stub these functions out */ +bool load_sram() { + return true; +} +void load_sram_no_verify() { + return; +} +bool verify_eeprom() { + return true; +} +void init_from_eeprom() { + return; +} + +#else + static jtag::GPIOTarget jtag_target_hackrf() { return { hackrf::one::gpio_cpld_tck, @@ -262,5 +280,7 @@ void init_from_eeprom() { hackrf_cpld.init_from_eeprom(); } +#endif // PRALINE + } /* namespace cpld */ } /* namespace hackrf */ diff --git a/firmware/common/hackrf_gpio.hpp b/firmware/common/hackrf_gpio.hpp index 588928dfa..dedc6f4fe 100644 --- a/firmware/common/hackrf_gpio.hpp +++ b/firmware/common/hackrf_gpio.hpp @@ -52,7 +52,12 @@ constexpr GPIO gpio_r9_vaa_disable = gpio[GPIO3_6]; constexpr GPIO gpio_rx_mix_bp = gpio[GPIO2_12]; constexpr GPIO gpio_tx_mix_bp = gpio[GPIO2_11]; +#ifdef PRALINE +constexpr GPIO gpio_mix_bypass = gpio[GPIO3_2]; // P6_3: PRALINE RF path mixer bypass inverted +constexpr GPIO gpio_mix_en_n_r1_0 = gpio[GPIO5_6]; // P2_6: R1.0 board mixer bypass +#else constexpr GPIO gpio_mix_bypass = gpio[GPIO5_16]; +#endif constexpr GPIO gpio_not_mix_bypass = gpio[GPIO1_0]; constexpr GPIO gpio_og_rx = gpio[GPIO5_5]; @@ -68,8 +73,18 @@ constexpr GPIO gpio_amp_bypass = gpio[GPIO0_14]; constexpr GPIO gpio_not_rx_amp_pwr = gpio[GPIO1_12]; constexpr GPIO gpio_not_tx_amp_pwr = gpio[GPIO3_5]; +#ifndef PRALINE constexpr GPIO gpio_rffc5072_resetx = gpio[GPIO2_14]; +#endif + +#ifdef PRALINE +constexpr GPIO gpio_rffc5072_enx = gpio[GPIO2_13]; // P5_4: RFFC5072 ENX (active LOW) +constexpr GPIO gpio_rffc5072_select = gpio[GPIO2_13]; // P5_4: ENX doubles as SPI strobe +// constexpr GPIO gpio_rffc5072_select = gpio[GPIO2_7]; // P5_7: PRALINE CS +#else constexpr GPIO gpio_rffc5072_select = gpio[GPIO2_13]; +#endif + #ifdef PRALINE constexpr GPIO gpio_rffc5072_clock = gpio[GPIO5_18]; constexpr GPIO gpio_rffc5072_data = gpio[GPIO4_14]; @@ -103,8 +118,8 @@ constexpr GPIO gpio_max2839_rxtx = gpio[GPIO2_5]; #endif #ifdef PRALINE -constexpr GPIO gpio_max5864_select = gpio[GPIO6_30]; -constexpr GPIO gpio_fpga_select = gpio[GPIO2_10]; // FPGA SPI CS (P5_1) +constexpr GPIO gpio_max5864_select = gpio[GPIO6_30]; // PD_16: PRALINE MAX5864 CS +constexpr GPIO gpio_fpga_select = gpio[GPIO2_10]; // FPGA SPI CS (P5_1) #else constexpr GPIO gpio_max5864_select = gpio[GPIO2_7]; #endif @@ -118,8 +133,8 @@ constexpr GPIO gpio_1v2_enable = gpio[GPIO4_7]; // 1V2 enable (P8_7) constexpr GPIO gpio_3v3aux_disable = gpio[GPIO5_15]; // 3V3 aux disable (P6_7) // PRALINE RF path control -constexpr GPIO gpio_tx_enable = gpio[GPIO3_4]; // TX enable (P6_5) -constexpr GPIO gpio_mix_enable_n = gpio[GPIO3_2]; // Mixer enable inverted (P6_3) +constexpr GPIO gpio_tx_enable = gpio[GPIO3_4]; // TX enable (P6_5) +// constexpr GPIO gpio_mix_enable_n = gpio[GPIO3_2]; // Mixer enable inverted (P6_3) constexpr GPIO gpio_lpf_enable = gpio[GPIO4_8]; // LPF enable (PA_1) constexpr GPIO gpio_rf_amp_enable = gpio[GPIO4_9]; // RF amp enable (PA_2) constexpr GPIO gpio_ant_bias_disable = gpio[GPIO1_12]; // Antenna bias disable (P2_12) @@ -144,9 +159,17 @@ constexpr GPIO gpio_trigger_out = gpio[GPIO5_6]; // Trigger output (P2_6) constexpr GPIO gpio_pps_out = gpio[GPIO5_5]; // PPS output (P2_5) #endif +#ifdef PRALINE +/* PRALINE has no HackRF CPLD. These pins are used for RFFC5072 and TX_EN instead. + * Dummy assignments here allow cpld_update.cpp to compile; the functions + * that use them are never called on PRALINE. */ +constexpr GPIO gpio_cpld_tdo = gpio[GPIO3_0]; // dummy: reuse TCK pin +constexpr GPIO gpio_cpld_tms = gpio[GPIO3_1]; // dummy: reuse TDI pin +#else constexpr GPIO gpio_cpld_tdo = gpio[GPIO5_18]; -constexpr GPIO gpio_cpld_tck = gpio[GPIO3_0]; constexpr GPIO gpio_cpld_tms = gpio[GPIO3_4]; +#endif +constexpr GPIO gpio_cpld_tck = gpio[GPIO3_0]; constexpr GPIO gpio_cpld_tdi = gpio[GPIO3_1]; constexpr GPIO gpio_r9_clkin_en = gpio[GPIO5_15];