diff options
Diffstat (limited to 'sw/picardy/src/main.rs')
-rw-r--r-- | sw/picardy/src/main.rs | 188 |
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 { } +} |