aboutsummaryrefslogtreecommitdiffstats
path: root/sw/picardy/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'sw/picardy/src/main.rs')
-rw-r--r--sw/picardy/src/main.rs188
1 files changed, 188 insertions, 0 deletions
diff --git a/sw/picardy/src/main.rs b/sw/picardy/src/main.rs
new file mode 100644
index 0000000..b7b2dad
--- /dev/null
+++ b/sw/picardy/src/main.rs
@@ -0,0 +1,188 @@
+/*
+ The MIT License (MIT)
+
+ Copyright (c) 2020 Matthias P. Braendli
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+#![no_main]
+#![no_std]
+
+use cortex_m_rt::ExceptionFrame;
+use cortex_m_semihosting::hprintln;
+use panic_semihosting as _;
+
+use stm32f1xx_hal::{
+ prelude::*,
+ pac,
+ i2c::{BlockingI2c, Mode},
+ delay::Delay,
+ timer::{Timer},
+};
+
+use embedded_hal::digital::v2::{OutputPin, ToggleableOutputPin};
+use hd44780_driver::{Cursor, CursorBlink, Display, DisplayMode, HD44780};
+
+pub mod ui;
+pub mod si_clock;
+
+use core::fmt::Write;
+
+#[cortex_m_rt::entry]
+fn main() -> ! {
+ let cp = cortex_m::Peripherals::take().unwrap();
+ let dp = pac::Peripherals::take().unwrap();
+
+ let mut flash = dp.FLASH.constrain();
+ let mut rcc = dp.RCC.constrain();
+ let mut afio = dp.AFIO.constrain(&mut rcc.apb2);
+ let clocks = rcc.cfgr
+ .adcclk(2.mhz())
+ .freeze(&mut flash.acr);
+ let mut delay = Delay::new(cp.SYST, clocks);
+
+ let adc1 = dp.ADC1;
+ // Buttons as analog inputs (multi-level)
+ let mut gpiob = dp.GPIOB.split(&mut rcc.apb2);
+ 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 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();
+
+ loop {
+ led.toggle().unwrap();
+ delay.delay_ms(500u16);
+ }
+
+ let c1 = gpioa.pa6;
+ let c2 = gpioa.pa7;
+
+ let qei = Timer::tim3(dp.TIM3, &clocks, &mut rcc.apb1)
+ .qei((c1, c2), &mut afio.mapr);
+
+ // Configure I2C1 to be used for Si5351 and display
+ 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(
+ dp.I2C1,
+ (scl, sda),
+ &mut afio.mapr,
+ Mode::Standard {
+ frequency: 100_000.hz(),
+ },
+ clocks,
+ &mut rcc.apb1,
+ /* start_timeout_us */ 1000,
+ /* start_retries */ 10,
+ /* addr_timeout_us */ 1000,
+ /* data_timeout_us */ 1000,
+ );
+
+ let i2c_busmanager = shared_bus::CortexMBusManager::new(i2c);
+
+ const I2C_ADDRESS: u8 = 0b010_0000; // MCP23008, depending on solder bridges
+ let mut lcd = match HD44780::new_i2c_mcp23008(i2c_busmanager.acquire(), I2C_ADDRESS, &mut delay) {
+ Ok(lcd) => lcd,
+ Err(_) => panic!("HD44780 init fail"),
+ };
+
+ lcd.reset(&mut delay).unwrap();
+ lcd.clear(&mut delay).unwrap();
+ lcd.set_display_mode(
+ DisplayMode {
+ display: Display::On,
+ cursor_visibility: Cursor::Invisible,
+ cursor_blink: CursorBlink::Off,
+ },
+ &mut delay).unwrap();
+ lcd.set_cursor_pos(0, &mut delay).unwrap();
+ lcd.write_str("Hello, world!", &mut delay).unwrap();
+
+ //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();
+
+ hprintln!("Main loop\n").unwrap();
+
+ let mut last_encoder_count = qei.count();
+ loop {
+ led.toggle().unwrap();
+
+ let mut string = arrayvec::ArrayString::<[_; 16]>::new();
+ 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();
+ }
+
+ 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",
+ };
+
+ lcd.set_cursor_pos(0, &mut delay).unwrap();
+ write!(string, "{:15}", button).unwrap();
+ lcd.write_str(&string, &mut delay).unwrap();
+ }
+
+ last_encoder_count = encoder_count;
+ }
+}
+
+#[cortex_m_rt::exception]
+fn HardFault(ef: &ExceptionFrame) -> ! {
+ let periph = unsafe { cortex_m::Peripherals::steal() };
+ let hfsr = periph.SCB.hfsr.read();
+ let cfsr = periph.SCB.cfsr.read();
+
+ hprintln!("Hardfault {:x} {:x} at {:x}\n", hfsr, cfsr, ef.pc).unwrap();
+ cortex_m::asm::bkpt();
+ loop { }
+}
+
+#[cortex_m_rt::exception]
+fn DefaultHandler(irqn: i16) {
+ hprintln!("Unhandled exception (IRQn = {})", irqn).unwrap();
+ cortex_m::asm::bkpt();
+ loop { }
+}