aboutsummaryrefslogtreecommitdiffstats
path: root/sw
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2020-07-24 09:56:30 +0200
committerMatthias P. Braendli <matthias.braendli@mpb.li>2020-07-24 09:56:30 +0200
commitc387565f0c3280d8024c301d4142230fc586d170 (patch)
tree07397aa2a447186a0be13d296ff285317f0e9a0c /sw
parent9cefc67cb28d1d641dad08af03ed42c625676d0f (diff)
downloadpicardy-c387565f0c3280d8024c301d4142230fc586d170.tar.gz
picardy-c387565f0c3280d8024c301d4142230fc586d170.tar.bz2
picardy-c387565f0c3280d8024c301d4142230fc586d170.zip
Connect voltage switch relay
Diffstat (limited to 'sw')
-rw-r--r--sw/picardy/src/main.rs146
-rw-r--r--sw/picardy/src/si_clock.rs32
-rw-r--r--sw/pio.txt7
3 files changed, 136 insertions, 49 deletions
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<T: hd44780_driver::bus::DataBus>(lcd: &mut HD44780<T>, 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<I2C, E> SiClock<I2C>
where
I2C: WriteRead<Error = E> + Write<Error = E>,
{
- pub fn new(i2c: I2C) -> SiClock<I2C> {
+ pub fn new(i2c: I2C, bfo: u32, vfo: u32) -> SiClock<I2C> {
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<I2C, E> SiClock<I2C>
}
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