From c387565f0c3280d8024c301d4142230fc586d170 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Fri, 24 Jul 2020 09:56:30 +0200 Subject: Connect voltage switch relay --- README.md | 13 ++++ kicad/control.sch | 1 + kicad/picardy.sch | 8 +-- kicad/power.sch | 6 +- sw/picardy/src/main.rs | 146 ++++++++++++++++++++++++++++++++++----------- sw/picardy/src/si_clock.rs | 32 ++++++---- sw/pio.txt | 7 +++ 7 files changed, 158 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 29946d9..e551148 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,19 @@ Open questions * Put sidetone volume setting before RV303? * Hook up to LM375 BYPASS? +Issues +====== + +* SEQ0 is used in inverted-logic in baseband, and noninverted for power relay + * Due to inconsistent naming + * Ugly fix on K603 side, use SEQ0n, SEQ1, SEQ2 +* G6K-2F-RF all have the Y footprint, not the equidistant one. + * And they have additional GND flaps too, which are not in the Kicad footprint library + * Can be kludged-in +* 5V jumper is less useful as hoped + * Intention: disable VHF stuff + * Unintended effect: removes LCD backlight + PCB Assembly Plan ================= diff --git a/kicad/control.sch b/kicad/control.sch index b3c9b1e..fe73b31 100644 --- a/kicad/control.sch +++ b/kicad/control.sch @@ -717,6 +717,7 @@ F 0 "U201" H 5850 2661 50 0000 C CNN F 1 "STM32F103C8Tx" H 5850 2570 50 0000 C CNN F 2 "Package_QFP:LQFP-48_7x7mm_P0.5mm" H 5300 2850 50 0001 R CNN F 3 "http://www.st.com/st-web-ui/static/active/en/resource/technical/document/datasheet/CD00161566.pdf" H 5900 4250 50 0001 C CNN +F 4 "STM32F103C8T6" H 5900 4250 50 0001 C CNN "MPN" 1 5900 4250 1 0 0 -1 $EndComp diff --git a/kicad/picardy.sch b/kicad/picardy.sch index 431a9b1..b1d41b6 100644 --- a/kicad/picardy.sch +++ b/kicad/picardy.sch @@ -20,8 +20,8 @@ F0 "Control" 50 F1 "control.sch" 50 F2 "CW_TONE" O R 4700 1450 50 F3 "SEQ0n" O R 4700 1700 50 -F4 "SEQ1n" O R 4700 1800 50 -F5 "SEQ2n" O R 4700 1900 50 +F4 "SEQ1" O R 4700 1800 50 +F5 "SEQ2" O R 4700 1900 50 F6 "MIC" O R 4700 2300 50 F7 "MUTE_SPKR" O R 4700 2200 50 F8 "S_METER" I L 3450 2400 50 @@ -464,8 +464,8 @@ F1 "power.sch" 50 F2 "IN_+12V" I L 1400 1550 50 F3 "IN_GND" I L 1400 1650 50 F4 "SWITCH_5V_8V_TXn" I L 1400 2050 50 -F5 "SWITCH_EXTn" I L 1400 2250 50 -F6 "SWITCH_EXT_PAn" I L 1400 2150 50 +F5 "SWITCH_EXT" I L 1400 2250 50 +F6 "SWITCH_EXT_PA" I L 1400 2150 50 $EndSheet $Comp L power:GND #PWR? diff --git a/kicad/power.sch b/kicad/power.sch index 8cc81bd..33ed745 100644 --- a/kicad/power.sch +++ b/kicad/power.sch @@ -811,7 +811,7 @@ F 4 "0" H 1900 5100 50 0001 C CNN "Need_order" -1 0 0 1 $EndComp Text HLabel 1850 4900 0 50 Input ~ 0 -SWITCH_EXTn +SWITCH_EXT $Comp L Device:R R? U 1 1 5E66CC07 @@ -842,7 +842,7 @@ F 3 "" H 3700 5600 50 0001 C CNN 0 1 1 0 $EndComp Text HLabel 3850 4900 0 50 Input ~ 0 -SWITCH_EXT_PAn +SWITCH_EXT_PA Text Notes 5650 6400 0 50 ~ 0 Can switch\n2A $Comp @@ -1121,4 +1121,6 @@ F 3 "" H 8900 1850 50 0001 C CNN 1 8900 1850 1 0 0 -1 $EndComp +Text Notes 6650 3650 0 50 ~ 0 +PCB 07.2020 assembled with\nugly fix to invert like for K301 $EndSCHEMATC diff --git a/sw/picardy/src/main.rs b/sw/picardy/src/main.rs index 71c8475..b1bcf0f 100644 --- a/sw/picardy/src/main.rs +++ b/sw/picardy/src/main.rs @@ -32,7 +32,8 @@ use panic_semihosting as _; use stm32f1xx_hal::{ prelude::*, pac, - i2c::{BlockingI2c, Mode, DutyCycle}, + i2c, + gpio, delay::Delay, timer::{Timer}, }; @@ -45,8 +46,59 @@ pub mod si_clock; use core::fmt::Write; +enum Mode { + VFO, + BFO, +} +struct State { + mode : Mode, + bfo : u32, + bfo_tune_fail : bool, + vfo : u32, + + transmit : bool, +} + +fn update_disp(lcd: &mut HD44780, state: &State, delay: &mut Delay) +{ + let mut string = arrayvec::ArrayString::<[_; 16]>::new(); + + match (state.bfo_tune_fail, &state.mode) { + (true, _) => write!(string, "!").unwrap(), + (false, Mode::BFO) => write!(string, ">").unwrap(), + (false, Mode::VFO) => write!(string, " ").unwrap(), + } + write!(string, "{:<10}", state.bfo).unwrap(); + + if state.transmit { + write!(string, " T").unwrap(); + } + else { + write!(string, " R").unwrap(); + } + + lcd.set_cursor_pos(0, delay).unwrap(); + lcd.write_str(&string, delay).unwrap(); + + string.clear(); + match state.mode { + Mode::BFO => write!(string, " {:<10}", state.vfo).unwrap(), + Mode::VFO => write!(string, ">{:<10}", state.vfo).unwrap(), + } + lcd.set_cursor_pos(40, delay).unwrap(); + lcd.write_str(&string, delay).unwrap(); +} + #[cortex_m_rt::entry] fn main() -> ! { + let mut state = State { + mode : Mode::VFO, + bfo : 4_195_210, + bfo_tune_fail : false, + vfo : 23_000_000, + transmit : false, + }; + let cp = cortex_m::Peripherals::take().unwrap(); let dp = pac::Peripherals::take().unwrap(); @@ -58,23 +110,30 @@ fn main() -> ! { .freeze(&mut flash.acr); let mut delay = Delay::new(cp.SYST, clocks); - let adc1 = dp.ADC1; - // Buttons as analog inputs (multi-level) + let mut gpioa = dp.GPIOA.split(&mut rcc.apb2); let mut gpiob = dp.GPIOB.split(&mut rcc.apb2); + let mut gpioc = dp.GPIOC.split(&mut rcc.apb2); + + // Buttons as analog inputs (multi-level) let pb0 = gpiob.pb0.into_analog(&mut gpiob.crl); let pb1 = gpiob.pb1.into_analog(&mut gpiob.crl); let pb12 = gpiob.pb12.into_pull_up_input(&mut gpiob.crh); let pb13 = gpiob.pb13.into_pull_up_input(&mut gpiob.crh); - let mut gpioc = dp.GPIOC.split(&mut rcc.apb2); let pc15 = gpioc.pc15.into_pull_up_input(&mut gpioc.crh); + let adc1 = dp.ADC1; let mut ui = ui::UI::new(pb0, pb1, adc1, &mut rcc.apb2, &clocks, pb12, pb13, pc15); - let gpioa = dp.GPIOA.split(&mut rcc.apb2); // Configure PB14 as output. (LED) let mut led = gpiob.pb14.into_push_pull_output(&mut gpiob.crh); led.set_low().unwrap(); + let (pa15, pb3, pb4) = afio.mapr.disable_jtag(gpioa.pa15, gpiob.pb3, gpiob.pb4); + let _cw_key_n = pa15.into_push_pull_output_with_state(&mut gpioa.crh, gpio::State::High); // TODO output + let mut seq0n = pb3.into_push_pull_output_with_state(&mut gpiob.crl, gpio::State::High); + let mut _seq1 = pb4.into_push_pull_output_with_state(&mut gpiob.crl, gpio::State::Low); + let mut _seq2 = gpiob.pb5.into_push_pull_output_with_state(&mut gpiob.crl, gpio::State::Low); + let c1 = gpioa.pa6; let c2 = gpioa.pa7; @@ -85,12 +144,12 @@ fn main() -> ! { let scl2 = gpiob.pb10.into_alternate_open_drain(&mut gpiob.crh); let sda2 = gpiob.pb11.into_alternate_open_drain(&mut gpiob.crh); - let i2c2 = BlockingI2c::i2c2( + let i2c2 = i2c::BlockingI2c::i2c2( dp.I2C2, (scl2, sda2), - Mode::Fast { + i2c::Mode::Fast { frequency: 400_000.hz(), - duty_cycle: DutyCycle::Ratio2to1, + duty_cycle: i2c::DutyCycle::Ratio2to1, }, clocks, &mut rcc.apb1, @@ -121,16 +180,15 @@ fn main() -> ! { lcd.write_str("Hello, world!", &mut delay).unwrap(); - /* // Configure I2C1 to be used for Si5351 let scl = gpiob.pb6.into_alternate_open_drain(&mut gpiob.crl); let sda = gpiob.pb7.into_alternate_open_drain(&mut gpiob.crl); - let i2c = BlockingI2c::i2c1( + let i2c = i2c::BlockingI2c::i2c1( dp.I2C1, (scl, sda), &mut afio.mapr, - Mode::Standard { + i2c::Mode::Standard { frequency: 100_000.hz(), }, clocks, @@ -141,47 +199,63 @@ fn main() -> ! { /* data_timeout_us */ 1000, ); let i2c_busmanager = shared_bus::CortexMBusManager::new(i2c); - let mut siclock = si_clock::SiClock::new(i2c_busmanager.acquire()); - */ - lcd.set_cursor_pos(0, &mut delay).unwrap(); - lcd.write_str("Clocks set. ", &mut delay).unwrap(); + let mut siclock = si_clock::SiClock::new(i2c_busmanager.acquire(), state.bfo, state.vfo); - hprintln!("Main loop\n").unwrap(); + update_disp(&mut lcd, &state, &mut delay); let mut last_encoder_count = qei.count(); loop { led.toggle().unwrap(); - let mut string = arrayvec::ArrayString::<[_; 16]>::new(); + let mut update_disp_required = false; + let encoder_count = qei.count(); if encoder_count != last_encoder_count { - let freq = 23_000_000 + encoder_count as u32; - - //siclock.set_vfo(freq); - - write!(string, "{:15}", freq).unwrap(); - lcd.set_cursor_pos(40, &mut delay).unwrap(); - lcd.write_str(&string, &mut delay).unwrap(); + let delta = encoder_count.wrapping_sub(last_encoder_count); + let delta = if delta > 0x7FFF { delta as i32 - 0x10000 } else { delta as i32 }; + + match state.mode { + Mode::VFO => { + state.vfo = (state.vfo as i32 + delta * 500) as u32; + siclock.set_vfo(state.vfo); + }, + Mode::BFO => { + state.bfo = (state.bfo as i32 + delta * 50) as u32; + state.bfo_tune_fail = !siclock.set_bfo(state.bfo).is_ok(); + }, + } + + update_disp_required = true; } if let Some(b) = ui.read_buttons() { - let button = match b { - ui::ButtonPress::A => "A", - ui::ButtonPress::B => "B", - ui::ButtonPress::C => "C", - ui::ButtonPress::D => "D", - ui::ButtonPress::E => "E", - ui::ButtonPress::F => "F", - ui::ButtonPress::G => "G", - ui::ButtonPress::ENC => "X", + match b { + ui::ButtonPress::A => { state.mode = Mode::BFO; }, + ui::ButtonPress::B => { state.mode = Mode::VFO; }, + ui::ButtonPress::C => {}, + ui::ButtonPress::D => {}, + ui::ButtonPress::E => { + state.transmit = false; + + seq0n.set_high().unwrap(); + }, + ui::ButtonPress::F => { + state.transmit = true; + + seq0n.set_low().unwrap(); + }, + ui::ButtonPress::G => {}, + ui::ButtonPress::ENC => {}, }; - lcd.set_cursor_pos(0, &mut delay).unwrap(); - write!(string, "{:15}", button).unwrap(); - lcd.write_str(&string, &mut delay).unwrap(); + update_disp_required = true; } + if update_disp_required { + update_disp(&mut lcd, &state, &mut delay) + }; + last_encoder_count = encoder_count; } } diff --git a/sw/picardy/src/si_clock.rs b/sw/picardy/src/si_clock.rs index 0bce24b..b304461 100644 --- a/sw/picardy/src/si_clock.rs +++ b/sw/picardy/src/si_clock.rs @@ -27,6 +27,7 @@ use si5351::{Si5351, Si5351Device}; use embedded_hal::blocking::i2c::{WriteRead, Write}; const REF_CLOCK : u32 = 25_000_000; +const PLL_A_MULT : u32 = 32; fn gcd(x: u32, y: u32) -> u32 { let mut x = x; @@ -67,6 +68,15 @@ fn clock_settings_with_pll_calculation(freq: u32) -> (u16, u8, u32, u32) { (divider.try_into().unwrap(), mult.try_into().unwrap(), num as u32, denom) } +fn set_bfo(siclock: &mut dyn Si5351, freq: u32) -> Result<(), si5351::Error> +{ + let (a, b, c) = clock_settings_for_pll(freq, PLL_A_MULT * REF_CLOCK); + siclock.setup_multisynth(si5351::Multisynth::MS2, a, b, c, si5351::OutputDivider::Div1)?; + siclock.select_clock_pll(si5351::ClockOutput::Clk2, si5351::PLL::A); + siclock.set_clock_enabled(si5351::ClockOutput::Clk2, true); + siclock.flush_clock_control(si5351::ClockOutput::Clk2) +} + fn set_vfo(siclock: &mut dyn Si5351, freq: u32) { let (div, mult, num, denom) = clock_settings_with_pll_calculation(freq); @@ -86,36 +96,28 @@ impl SiClock where I2C: WriteRead + Write, { - pub fn new(i2c: I2C) -> SiClock { + pub fn new(i2c: I2C, bfo: u32, vfo: u32) -> SiClock { let mut siclock = Si5351Device::new(i2c, false, REF_CLOCK); siclock.init(si5351::CrystalLoad::_10).unwrap(); // See freqplan.py for Si5351 frequency plan // CLK1 = 116MHz - let pll_a_mult = 32; siclock.setup_pll_int(si5351::PLL::A, 32).unwrap(); { let clk1 = 116_000_000; - let (a, b, c) = clock_settings_for_pll(clk1, pll_a_mult * REF_CLOCK); + let (a, b, c) = clock_settings_for_pll(clk1, PLL_A_MULT * REF_CLOCK); siclock.setup_multisynth(si5351::Multisynth::MS1, a, b, c, si5351::OutputDivider::Div1).unwrap(); siclock.select_clock_pll(si5351::ClockOutput::Clk1, si5351::PLL::A); siclock.set_clock_enabled(si5351::ClockOutput::Clk1, true); siclock.flush_clock_control(si5351::ClockOutput::Clk1).unwrap(); } - { - let clk2 = 4_195_210; - let (a, b, c) = clock_settings_for_pll(clk2, pll_a_mult * REF_CLOCK); - siclock.setup_multisynth(si5351::Multisynth::MS2, a, b, c, si5351::OutputDivider::Div1).unwrap(); - siclock.select_clock_pll(si5351::ClockOutput::Clk2, si5351::PLL::A); - siclock.set_clock_enabled(si5351::ClockOutput::Clk2, true); - siclock.flush_clock_control(si5351::ClockOutput::Clk2).unwrap(); - } + set_bfo(&mut siclock, bfo).unwrap(); siclock.reset_pll(si5351::PLL::A).unwrap(); - set_vfo(&mut siclock, 23_000_000); + set_vfo(&mut siclock, vfo); siclock.reset_pll(si5351::PLL::B).unwrap(); @@ -125,6 +127,10 @@ impl SiClock } pub fn set_vfo(&mut self, freq: u32) { - set_vfo(&mut self.siclock, freq); + set_vfo(&mut self.siclock, freq) + } + + pub fn set_bfo(&mut self, freq: u32) -> Result<(), si5351::Error> { + set_bfo(&mut self.siclock, freq) } } diff --git a/sw/pio.txt b/sw/pio.txt index e8c85e8..ef97a1e 100644 --- a/sw/pio.txt +++ b/sw/pio.txt @@ -25,6 +25,13 @@ Microphone switches * SW1 PA3 * SW2 PA4 +## GPIO outputs + + * SEQ0n PB3 + * SEQ1 PB4 + * SEQ2 PB5 + * CW_KEYn PA15 + ## I2C1 for Si5351A-B-GT * SCL PB6 default alternate function -- cgit v1.2.3