mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-09-10 00:29:33 +00:00
Resolved root cause for loss of bluetooth functionality and added more testing options (#3049)
* Added PRO button to analog_audio.cpp for debugging metallic ringing sounds in Audio app. Ensured consitency to 4MHz in analog_audio.cpp * Restored blutooth after loss. * Added several sampling rates to analog_audio for testing. * Ran format-code.sh * Fixed 0x03 mode for DC/Q-INV/Q-SHFT being set at every tuning and sample rate change. This was the root cause for loss of bluetooth before. Sample rate, and frequency can now be changed without need for manually resetting DC/Q-INV/Q-SHIFT settings. Updated method for setting frequncies in praline so that we have more testing options. * Ran format-code.sh and cleaned up stale comments. * Addressed comments, and removed commented line, opting for higher register values, 5E and 5D. Added WFM Debug View to support testing demodulation ringing. * Addressed comments in PR conversation to clean comments and ensure consistency at initializtion accross updated methods and displays. * Ran format-code.sh
This commit is contained in:
@@ -208,13 +208,13 @@ PralineOptionsView::PralineOptionsView(Rect parent_rect, const Style* style) {
|
||||
&label_qi, &options_qi, &label_qs, &options_qs,
|
||||
&label_dec, &options_dec});
|
||||
|
||||
options_sr.set_by_value(receiver_model.sampling_rate());
|
||||
options_sr.set_value(receiver_model.sampling_rate() / 1000);
|
||||
options_dc.set_by_value(1);
|
||||
options_qi.set_by_value(1);
|
||||
options_qi.set_by_value(0);
|
||||
options_qs.set_by_value(0);
|
||||
options_dec.set_by_value(0);
|
||||
|
||||
options_sr.on_change = [this](size_t, OptionsField::value_t v) { receiver_model.set_sampling_rate(v); };
|
||||
options_sr.on_change = [this](int32_t v) { receiver_model.set_sampling_rate(static_cast<uint32_t>(v) * 1000); };
|
||||
options_dc.on_change = [this](size_t, OptionsField::value_t v) { if (v) fpga_reg_1 |= 0x01; else fpga_reg_1 &= ~0x01; update_fpga_ctrl(); };
|
||||
options_qi.on_change = [this](size_t, OptionsField::value_t v) { if (v) fpga_reg_1 |= 0x02; else fpga_reg_1 &= ~0x02; update_fpga_ctrl(); };
|
||||
options_qs.on_change = [this](size_t, OptionsField::value_t v) { if (v) fpga_reg_1 |= 0x04; else fpga_reg_1 &= ~0x04; update_fpga_ctrl(); };
|
||||
|
||||
@@ -45,7 +45,15 @@ class PralineOptionsView : public View {
|
||||
private:
|
||||
// Layout: SR (Sample Rate), DC (DC Block), QI (Q-Invert), QS (Quarter Shift), D (Decim)
|
||||
Text label_sr{{UI_POS_X(0), UI_POS_Y(0), UI_POS_WIDTH(2), UI_POS_HEIGHT(1)}, "SR"};
|
||||
OptionsField options_sr{{UI_POS_X(3), UI_POS_Y(0)}, 4, {{"0.25M", 250000}, {"0.5M", 500000}, {"0.75M", 750000}, {"1.0M", 1000000}, {"1.25M", 1250000}, {"1.5M", 1500000}, {"1.75M", 1750000}, {"2.0M", 2000000}, {"2.25M", 2250000}, {"2.5M", 2500000}, {"2.75M", 2750000}, {"3.0M", 3000000}, {"3.05M", 3050000}, {"3.072M", 3072000}, {"3.10M", 3100000}, {"3.15M", 3150000}, {"3.20M", 3200000}, {"3.25M", 3250000}, {"3.30M", 3300000}, {"3.35M", 3350000}, {"3.40M", 3400000}, {"3.45M", 3450000}, {"3.5M", 3500000}, {"3.51M", 3510000}, {"3.52M", 3520000}, {"3.53M", 3530000}, {"3.54M", 3540000}, {"3.55M", 3550000}, {"3.56M", 3560000}, {"3.57M", 3570000}, {"3.58M", 3580000}, {"3.59M", 3590000}, {"3.60M", 3600000}, {"3.61M", 3610000}, {"3.62M", 3620000}, {"3.63M", 3630000}, {"3.64M", 3640000}, {"3.65M", 3650000}, {"3.66M", 3660000}, {"3.67M", 3670000}, {"3.68M", 3680000}, {"3.69M", 3690000}, {"3.70M", 3700000}, {"3.71M", 3710000}, {"3.72M", 3720000}, {"3.73M", 3730000}, {"3.74M", 3740000}, {"3.75M", 3750000}, {"3.76M", 3760000}, {"3.77M", 3770000}, {"3.78M", 3780000}, {"3.79M", 3790000}, {"3.80M", 3800000}, {"3.81M", 3810000}, {"3.82M", 3820000}, {"3.83M", 3830000}, {"3.84M", 3840000}, {"3.85M", 3850000}, {"3.86M", 3860000}, {"3.87M", 3870000}, {"3.88M", 3880000}, {"3.89M", 3890000}, {"3.90M", 3900000}, {"3.91M", 3910000}, {"3.92M", 3920000}, {"3.93M", 3930000}, {"3.94M", 3940000}, {"3.95M", 3950000}, {"3.96M", 3960000}, {"3.97M", 3970000}, {"3.98M", 3980000}, {"3.99M", 3990000}, {"4.0M", 4000000}, {"5.0M", 5000000}}};
|
||||
|
||||
// Parameters: Position, Length (in chars), Range, Step, and default value
|
||||
NumberField options_sr{
|
||||
{UI_POS_X(3), UI_POS_Y(0)},
|
||||
5, // Number of digits to show
|
||||
{0, 40000}, // Range: 0 to 40,000 kHz
|
||||
1, // Step: 1 kHz
|
||||
' ' // Fix: Single quotes for char
|
||||
};
|
||||
|
||||
Text label_dc{{UI_POS_X(8), UI_POS_Y(0), UI_POS_WIDTH(2), UI_POS_HEIGHT(1)}, "DC"};
|
||||
OptionsField options_dc{{UI_POS_X(11), UI_POS_Y(0)}, 2, {{"Of", 0}, {"On", 1}}};
|
||||
@@ -59,7 +67,7 @@ class PralineOptionsView : public View {
|
||||
Text label_dec{{UI_POS_X(26), UI_POS_Y(0), UI_POS_WIDTH(1), UI_POS_HEIGHT(1)}, "D"};
|
||||
OptionsField options_dec{{UI_POS_X(28), UI_POS_Y(0)}, 2, {{" 1", 0}, {" 2", 1}, {" 4", 2}, {" 8", 3}, {"16", 4}}};
|
||||
|
||||
uint8_t fpga_reg_1{0x03}; // Tracks DC, QI, QS bits
|
||||
uint8_t fpga_reg_1{0x01}; // Tracks DC, QI, QS bits
|
||||
void update_fpga_ctrl();
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -590,6 +590,187 @@ void PralineRadioDebugView::refresh() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PRALINE
|
||||
/* WFMAudioDebugView *************************************************/
|
||||
|
||||
WFMAudioDebugView::WFMAudioDebugView(NavigationView& nav)
|
||||
: nav_(nav) {
|
||||
add_children({
|
||||
&text_title,
|
||||
&text_lbl_clk0,
|
||||
&text_clk0,
|
||||
&text_lbl_fpga_dec,
|
||||
&text_fpga_dec,
|
||||
&text_lbl_post_fpga,
|
||||
&text_post_fpga,
|
||||
&text_section1,
|
||||
&text_lbl_reg8,
|
||||
&text_reg8,
|
||||
&text_lbl_lpf_bw,
|
||||
&text_lpf_bw,
|
||||
&text_section2,
|
||||
&text_lbl_fpga_r1,
|
||||
&text_fpga_r1,
|
||||
&text_lbl_dc_q,
|
||||
&text_dc_q,
|
||||
&text_section3,
|
||||
&text_lbl_expected,
|
||||
&text_expected,
|
||||
&text_lbl_deemph,
|
||||
&text_deemph,
|
||||
&text_status,
|
||||
&text_status2,
|
||||
&button_refresh,
|
||||
&button_toggle_q,
|
||||
&button_done,
|
||||
});
|
||||
|
||||
text_title.set_style(Theme::getInstance()->fg_yellow);
|
||||
text_section1.set_style(Theme::getInstance()->fg_yellow);
|
||||
text_section2.set_style(Theme::getInstance()->fg_yellow);
|
||||
text_section3.set_style(Theme::getInstance()->fg_yellow);
|
||||
|
||||
button_refresh.on_select = [this](Button&) {
|
||||
refresh();
|
||||
};
|
||||
|
||||
button_toggle_q.on_select = [this](Button&) {
|
||||
uint32_t current = radio::debug::fpga::register_read(1);
|
||||
uint8_t new_val = current ^ 0x02; // Toggle Q_INVERT bit
|
||||
radio::debug::fpga::register_write(1, new_val);
|
||||
radio::invalidate_spi_config();
|
||||
refresh();
|
||||
};
|
||||
|
||||
button_done.on_select = [&nav](Button&) {
|
||||
nav.pop();
|
||||
};
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
void WFMAudioDebugView::focus() {
|
||||
button_refresh.focus();
|
||||
}
|
||||
|
||||
void WFMAudioDebugView::refresh() {
|
||||
// === Si5351 CLK0 Sample Rate ===
|
||||
// Read MS0 parameters to calculate frequency
|
||||
uint8_t reg44 = portapack::clock_manager.si5351_read_register(44);
|
||||
uint8_t reg45 = portapack::clock_manager.si5351_read_register(45);
|
||||
uint8_t reg46 = portapack::clock_manager.si5351_read_register(46);
|
||||
|
||||
uint8_t r_div_encoded = (reg44 >> 4) & 0x07;
|
||||
uint32_t r_div = 1 << r_div_encoded;
|
||||
uint32_t p1 = ((uint32_t)(reg44 & 0x03) << 16) | ((uint32_t)reg45 << 8) | reg46;
|
||||
uint32_t ms_div = (p1 + 512) / 128;
|
||||
|
||||
// PLL A is 800 MHz
|
||||
uint32_t clk0_khz = 800000 / ms_div / r_div;
|
||||
uint32_t clk0_mhz_int = clk0_khz / 1000;
|
||||
uint32_t clk0_khz_frac = clk0_khz % 1000;
|
||||
|
||||
text_clk0.set(to_string_dec_uint(clk0_mhz_int) + "." +
|
||||
to_string_dec_uint(clk0_khz_frac / 100) +
|
||||
to_string_dec_uint((clk0_khz_frac / 10) % 10) +
|
||||
to_string_dec_uint(clk0_khz_frac % 10) + " MHz");
|
||||
|
||||
if (clk0_khz >= 3000 && clk0_khz <= 3200) {
|
||||
text_clk0.set_style(Theme::getInstance()->fg_green);
|
||||
} else {
|
||||
text_clk0.set_style(Theme::getInstance()->fg_red);
|
||||
}
|
||||
|
||||
// === FPGA Decimation ===
|
||||
uint8_t fpga_decim = radio::debug::fpga::register_read(2);
|
||||
uint32_t fpga_div = 1 << fpga_decim;
|
||||
text_fpga_dec.set("/" + to_string_dec_uint(fpga_div) + " (n=" + to_string_dec_uint(fpga_decim) + ")");
|
||||
|
||||
// === Post-FPGA Rate ===
|
||||
uint32_t post_fpga_khz = clk0_khz / fpga_div;
|
||||
text_post_fpga.set(to_string_dec_uint(post_fpga_khz) + " kHz");
|
||||
|
||||
// For WFM, post-FPGA should be >= 384 kHz for proper audio decimation
|
||||
if (post_fpga_khz >= 384) {
|
||||
text_post_fpga.set_style(Theme::getInstance()->fg_green);
|
||||
} else {
|
||||
text_post_fpga.set_style(Theme::getInstance()->fg_orange);
|
||||
}
|
||||
|
||||
// === MAX2831 LPF ===
|
||||
uint32_t reg8 = radio::debug::second_if::register_read(8);
|
||||
text_reg8.set("0x" + to_string_hex(reg8, 4));
|
||||
|
||||
uint8_t lpf_coarse = reg8 & 0x03;
|
||||
const char* lpf_names[] = {"7.5 MHz", "8.5 MHz", "15 MHz", "18 MHz"};
|
||||
text_lpf_bw.set(lpf_names[lpf_coarse]);
|
||||
|
||||
// 7.5 MHz is minimum, OK for mono WFM but tight for stereo
|
||||
if (lpf_coarse >= 1) {
|
||||
text_lpf_bw.set_style(Theme::getInstance()->fg_green);
|
||||
} else {
|
||||
text_lpf_bw.set_style(Theme::getInstance()->fg_orange);
|
||||
}
|
||||
|
||||
// === FPGA Control Register ===
|
||||
uint32_t fpga_ctrl = radio::debug::fpga::register_read(1);
|
||||
text_fpga_r1.set("0x" + to_string_hex(fpga_ctrl, 2));
|
||||
|
||||
bool dc_block = fpga_ctrl & 0x01;
|
||||
bool q_invert = fpga_ctrl & 0x02;
|
||||
uint8_t quarter_shift = (fpga_ctrl >> 2) & 0x03;
|
||||
|
||||
text_dc_q.set(std::string(dc_block ? "DC:ON" : "DC:OFF") +
|
||||
" Q:" + std::string(q_invert ? "INV" : "NOR") +
|
||||
" QS:" + to_string_dec_uint(quarter_shift));
|
||||
|
||||
if (dc_block) {
|
||||
text_dc_q.set_style(Theme::getInstance()->fg_green);
|
||||
} else {
|
||||
text_dc_q.set_style(Theme::getInstance()->fg_orange);
|
||||
}
|
||||
|
||||
// === Expected Audio Rate ===
|
||||
// WFM typically: 3072 kHz / 64 = 48 kHz audio
|
||||
// Or: 3072 kHz → /8 (channel) → 384 kHz → /8 (audio) → 48 kHz
|
||||
uint32_t expected_audio = post_fpga_khz / 64; // Simplified assumption
|
||||
text_expected.set(to_string_dec_uint(expected_audio) + " kHz (est)");
|
||||
|
||||
if (expected_audio >= 44 && expected_audio <= 50) {
|
||||
text_expected.set_style(Theme::getInstance()->fg_green);
|
||||
} else {
|
||||
text_expected.set_style(Theme::getInstance()->fg_red);
|
||||
}
|
||||
|
||||
// === De-emphasis Status ===
|
||||
// We can't directly read the M4 de-emphasis config, but we can indicate what SHOULD be set
|
||||
// 75µs for USA, 50µs for Europe
|
||||
text_deemph.set("Check M4 config");
|
||||
text_deemph.set_style(Theme::getInstance()->fg_orange);
|
||||
|
||||
// === Status Summary ===
|
||||
bool sample_rate_ok = (clk0_khz >= 3000 && clk0_khz <= 3200);
|
||||
bool lpf_ok = (lpf_coarse >= 0); // 7.5 MHz minimum is technically OK
|
||||
bool dc_ok = dc_block;
|
||||
|
||||
if (sample_rate_ok && lpf_ok && dc_ok) {
|
||||
text_status.set("Hardware config looks OK.");
|
||||
text_status.set_style(Theme::getInstance()->fg_green);
|
||||
text_status2.set("If ringy: Check de-emphasis in M4!");
|
||||
text_status2.set_style(Theme::getInstance()->fg_orange);
|
||||
} else {
|
||||
std::string issues = "Issues: ";
|
||||
if (!sample_rate_ok) issues += "SampleRate ";
|
||||
if (!lpf_ok) issues += "LPF ";
|
||||
if (!dc_ok) issues += "DC_Block ";
|
||||
text_status.set(issues);
|
||||
text_status.set_style(Theme::getInstance()->fg_red);
|
||||
text_status2.set("Fix above before checking audio.");
|
||||
text_status2.set_style(Theme::getInstance()->fg_red);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* BasebandStatusView ******************************************************/
|
||||
|
||||
BasebandStatusView::BasebandStatusView(NavigationView& nav)
|
||||
@@ -2823,6 +3004,7 @@ void DebugMenuView::on_populate() {
|
||||
#ifdef PRALINE
|
||||
{"System Diag", ui::Theme::getInstance()->fg_yellow->foreground, &bitmap_icon_peripherals, [this]() { nav_.push<SystemDiagnosticsView>(); }},
|
||||
{"Radio Diag", ui::Theme::getInstance()->fg_yellow->foreground, &bitmap_icon_peripherals, [this]() { nav_.push<RadioDiagnosticsView>(); }},
|
||||
{"WFM Audio", ui::Theme::getInstance()->fg_yellow->foreground, &bitmap_icon_peripherals, [this]() { nav_.push<WFMAudioDebugView>(); }},
|
||||
{"ProRadio Debug", ui::Theme::getInstance()->fg_yellow->foreground, &bitmap_icon_peripherals, [this]() { nav_.push<PralineRadioDebugView>(); }},
|
||||
{"Signal Path", ui::Theme::getInstance()->fg_yellow->foreground, &bitmap_icon_peripherals, [this]() { nav_.push<SignalPathStatusView>(); }},
|
||||
{"GPIO Debug", ui::Theme::getInstance()->fg_yellow->foreground, &bitmap_icon_peripherals, [this]() { nav_.push<GPIODebugView>(); }},
|
||||
|
||||
@@ -482,6 +482,69 @@ class PralineRadioDebugView : public View {
|
||||
};
|
||||
#endif
|
||||
|
||||
/* WFMAudioDebugView ***************************************************/
|
||||
|
||||
#ifdef PRALINE
|
||||
class WFMAudioDebugView : public View {
|
||||
public:
|
||||
WFMAudioDebugView(NavigationView& nav);
|
||||
void focus() override;
|
||||
std::string title() const override { return "WFM Audio Debug"; }
|
||||
|
||||
private:
|
||||
void refresh();
|
||||
|
||||
NavigationView& nav_;
|
||||
|
||||
Text text_title{{0, 0, 240, 16}, "=== WFM Audio Debug ==="};
|
||||
|
||||
// Sample rates section
|
||||
Text text_lbl_clk0{{0, 20, 140, 16}, "Si5351 CLK0 Rate:"};
|
||||
Text text_clk0{{150, 20, 90, 16}, "---"};
|
||||
|
||||
Text text_lbl_fpga_dec{{0, 36, 140, 16}, "FPGA Decimation:"};
|
||||
Text text_fpga_dec{{150, 36, 90, 16}, "---"};
|
||||
|
||||
Text text_lbl_post_fpga{{0, 52, 140, 16}, "Post-FPGA Rate:"};
|
||||
Text text_post_fpga{{150, 52, 90, 16}, "---"};
|
||||
|
||||
// MAX2831 section
|
||||
Text text_section1{{0, 72, 240, 16}, "--- MAX2831 LPF ---"};
|
||||
|
||||
Text text_lbl_reg8{{0, 88, 140, 16}, "Reg8 (LPF RX):"};
|
||||
Text text_reg8{{150, 88, 90, 16}, "---"};
|
||||
|
||||
Text text_lbl_lpf_bw{{0, 104, 140, 16}, "LPF Bandwidth:"};
|
||||
Text text_lpf_bw{{150, 104, 90, 16}, "---"};
|
||||
|
||||
// FPGA section
|
||||
Text text_section2{{0, 124, 240, 16}, "--- FPGA Control ---"};
|
||||
|
||||
Text text_lbl_fpga_r1{{0, 140, 140, 16}, "Reg1 (Ctrl):"};
|
||||
Text text_fpga_r1{{150, 140, 90, 16}, "---"};
|
||||
|
||||
Text text_lbl_dc_q{{0, 156, 140, 16}, "DC/Q/QS:"};
|
||||
Text text_dc_q{{150, 156, 90, 16}, "---"};
|
||||
|
||||
// Audio section
|
||||
Text text_section3{{0, 176, 240, 16}, "--- Audio Path ---"};
|
||||
|
||||
Text text_lbl_expected{{0, 192, 140, 16}, "Expected Audio:"};
|
||||
Text text_expected{{150, 192, 90, 16}, "---"};
|
||||
|
||||
Text text_lbl_deemph{{0, 208, 140, 16}, "De-emph Config:"};
|
||||
Text text_deemph{{150, 208, 90, 16}, "---"};
|
||||
|
||||
// Status
|
||||
Text text_status{{0, 228, 240, 16}, "---"};
|
||||
Text text_status2{{0, 244, 240, 16}, "---"};
|
||||
|
||||
Button button_refresh{{10, 268, 70, 24}, "Refresh"};
|
||||
Button button_toggle_q{{90, 268, 70, 24}, "Toggle Q"};
|
||||
Button button_done{{170, 268, 60, 24}, "Done"};
|
||||
};
|
||||
#endif
|
||||
|
||||
/* BasebandStatusView ***************************************************/
|
||||
|
||||
class BasebandStatusView : public View {
|
||||
|
||||
Reference in New Issue
Block a user