diff options
author | Brian Cully <bjc@kublai.com> | 2022-11-06 16:34:44 -0500 |
---|---|---|
committer | Brian Cully <bjc@kublai.com> | 2022-11-06 16:37:38 -0500 |
commit | 20377d4522d513b66406d4ef8231a7cdbfedc157 (patch) | |
tree | 3b391f48c056c8a0fadbb3915dac11984a8b814d /src/bin | |
parent | a484a97111d0897ac6e0e291c4432a91ebdee416 (diff) | |
download | luchie-20377d4522d513b66406d4ef8231a7cdbfedc157.tar.gz luchie-20377d4522d513b66406d4ef8231a7cdbfedc157.zip |
cargo: rejigger crate type
convert to hybrid crate, with arch-dependent stuff as a ‘bin’ crate,
with the underlying support in ‘lib’.
the reason for this change is to allow for automated unit-testing on
the device-independent bits. to facilitate this, a ‘t’ alias is
provided which will run the unit tests. this target assumes you're on
a linux system, but you can't have everything.
Diffstat (limited to 'src/bin')
-rwxr-xr-x | src/bin/luchie.rs | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/src/bin/luchie.rs b/src/bin/luchie.rs new file mode 100755 index 0000000..7dedc8d --- /dev/null +++ b/src/bin/luchie.rs @@ -0,0 +1,188 @@ +#![no_std] +#![no_main] + +//extern crate panic_semihosting; + +use luchie::{ + cirque::Cirque, + log, logger, logln, +}; + +use cortex_m::{ + asm::{bkpt, wfi}, + interrupt, +}; +use cortex_m_rt::entry; +use embedded_hal::spi; +use stm32f1xx_hal::{ + pac, + prelude::*, + serial::{Config, Serial, StopBits, WordLength}, + spi::Spi, + usb::{self, UsbBus}, +}; +use usb_device::prelude::*; +use usbd_serial::{SerialPort, USB_CLASS_CDC}; + +#[entry] +fn main() -> ! { + let dp = pac::Peripherals::take().unwrap(); + + let mut flash = dp.FLASH.constrain(); + let rcc = dp.RCC.constrain(); + + let clocks = rcc + .cfgr + .use_hse(8.MHz()) + .sysclk(72.MHz()) // TODO: gd32 can get up to 120MHz + // .pclk1(24.MHz()) // TODO: causes issues with gd32 usb (dropped packets) and garbled usart1 output + .freeze(&mut flash.acr); + + assert!(clocks.usbclk_valid()); + + let mut gpiob = dp.GPIOB.split(); + let mut led = gpiob.pb2.into_push_pull_output(&mut gpiob.crl); + led.set_low(); + + let mut afio = dp.AFIO.constrain(); + let mut gpioa = dp.GPIOA.split(); + + let tx_pin = gpioa.pa9.into_alternate_push_pull(&mut gpioa.crh); + let rx_pin = gpioa.pa10; + let serial = Serial::usart1( + dp.USART1, + (tx_pin, rx_pin), + &mut afio.mapr, + Config::default() + .baudrate(115200.bps()) + .wordlength(WordLength::Bits8) + .parity_none() + .stopbits(StopBits::STOP1), + clocks, + ); + let (tx, _) = serial.split(); + + logger::init(tx); + + logln!("🐁 luchie starting…"); + + // cirque spi connections to spi1: + // + // pb0 - dr + // pa4 - ss1 + // pa5 - clk1 + // pa6 - miso1 + // pa7 - mosi1 + + logln!("👆 init trackpad"); + // TODO: hook an interrupt up to the dr pin to trigger a poll. + //let dr_pin = gpiob.pb1.into_pull_down_input(&mut gpiob.crl); + let sck_pin = gpioa.pa5.into_alternate_push_pull(&mut gpioa.crl); + let miso_pin = gpioa.pa6; + let mosi_pin = gpioa.pa7.into_alternate_push_pull(&mut gpioa.crl); + let cs_pin = gpioa.pa4.into_push_pull_output(&mut gpioa.crl); + let mut spi = Spi::spi1( + dp.SPI1, + (sck_pin, miso_pin, mosi_pin), + &mut afio.mapr, + spi::MODE_1, + 1_000_000.Hz(), // pinnacle supports up to 13mhz + clocks, + ); + let mut cirque = match Cirque::new(cs_pin, &mut spi, clocks.sysclk().raw()) { + Ok(c) => c, + Err(e) => { + logln!("err: {:?}", e); + panic!(); + } + }; + + logln!("🖥️ init usb"); + // BluePill board has a pull-up resistor on the D+ line. + // Pull the D+ pin down to send a RESET condition to the USB bus. + // This forced reset is needed only for development, without it host + // will not reset your device when you upload new firmware. + let mut usb_dp = gpioa.pa12.into_push_pull_output(&mut gpioa.crh); + usb_dp.set_low(); + // let mut delay = dp.TIM2.delay_us(&clocks); + // delay.delay_ms(10u8); + cortex_m::asm::delay(clocks.sysclk().raw() / 100); + + let usb = usb::Peripheral { + usb: dp.USB, + pin_dm: gpioa.pa11, + pin_dp: usb_dp.into_floating_input(&mut gpioa.crh), + }; + let usb_bus = UsbBus::new(usb); + + let mut serial = SerialPort::new(&usb_bus); + + let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0xdead, 0xbeef)) + .manufacturer("Fake company") + .product("Serial port") + .serial_number("TEST") + .device_class(USB_CLASS_CDC) + .build(); + + logln!("🎉 luchie started!"); + loop { + // logln!("."); + if let Ok(mut td) = cirque.poll(&mut spi) { + td.scale_to(1920, 1080); + logln!("td: {:?}", td); + } + + if !usb_dev.poll(&mut [&mut serial]) { + continue; + } + + let mut buf = [0u8; 64]; + + match serial.read(&mut buf) { + Ok(count) if count > 0 => { + led.set_high(); + + // Echo back in upper case + for c in buf[0..count].iter_mut() { + if 0x61 <= *c && *c <= 0x7a { + *c &= !0x20; + } + } + + let mut write_offset = 0; + while write_offset < count { + match serial.write(&buf[write_offset..count]) { + Ok(len) if len > 0 => { + write_offset += len; + } + _ => {} + } + } + led.set_low(); + } + _ => {} + } + } +} + +#[panic_handler] +fn panic(info: &core::panic::PanicInfo) -> ! { + interrupt::free(|_cs| { + log!("!!! panic "); + if let Some(loc) = info.location() { + log!("in {}:{} ", loc.file(), loc.line()); + } + if let Some(msg) = info.payload().downcast_ref::<&str>() { + log!("⇒ {} ", msg); + } + logln!("!!!"); + }); + spin(); +} + +fn spin() -> ! { + bkpt(); + loop { + wfi(); + } +} |