From 20377d4522d513b66406d4ef8231a7cdbfedc157 Mon Sep 17 00:00:00 2001 From: Brian Cully Date: Sun, 6 Nov 2022 16:34:44 -0500 Subject: cargo: rejigger crate type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .cargo/config.toml | 5 +- Cargo.toml | 4 ++ src/bin/luchie.rs | 188 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 18 +++++ src/log.rs | 52 --------------- src/logger.rs | 52 +++++++++++++++ src/main.rs | 188 ----------------------------------------------------- 7 files changed, 266 insertions(+), 241 deletions(-) create mode 100755 src/bin/luchie.rs create mode 100755 src/lib.rs delete mode 100644 src/log.rs create mode 100644 src/logger.rs delete mode 100755 src/main.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index 4339ec3..68eea01 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,8 +1,11 @@ +[alias] +t = "test --target x86_64-unknown-linux-gnu" + [build] target = "thumbv7em-none-eabihf" [target.thumbv7em-none-eabihf] -runner = "arm-none-eabi-gdb" +runner = "arm-none-eabi-gdb -i=mi" rustflags = [ "-C", "link-arg=-Tlink.x", ] diff --git a/Cargo.toml b/Cargo.toml index b8cb657..0af2751 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,5 +35,9 @@ name = "luchie" test = false bench = false +[lib] +test = true +bench = true + [patch.crates-io] #usb-device = { path = "../usb-device" } 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(); + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100755 index 0000000..821bdeb --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,18 @@ +#![no_std] + +pub mod cirque; +pub mod logger; + +#[cfg(test)] +mod tests { + #[test] + fn pass() { + assert!(0 == 0); + } + + #[test] + #[should_panic] + fn fail() { + assert!(1 == 0); + } +} diff --git a/src/log.rs b/src/log.rs deleted file mode 100644 index ccc9ebc..0000000 --- a/src/log.rs +++ /dev/null @@ -1,52 +0,0 @@ -use core::{ - cell::RefCell, - fmt::{write, Arguments}, -}; - -use cortex_m::interrupt::{self, Mutex}; - -#[macro_export] -macro_rules! log { - ($($args:tt)+) => { - $crate::log::log_args(core::format_args!($($args)+)) - } -} - -#[macro_export] -macro_rules! logln { - () => ({ kprint!("\r\n") }); - ($fmt: literal $(, $($arg: tt)+)?) => { - log!(concat!($fmt, "\n") $(, $($arg)+)?) - } -} - -static TX: Mutex>> = Mutex::new(RefCell::new(None)); - -pub fn init(tx: arch::Writer) { - interrupt::free(|cs| { - TX.borrow(cs).replace(Some(tx)); - }); -} - -pub fn log_args(args: Arguments) { - interrupt::free(|cs| { - TX.borrow(cs) - .borrow_mut() - .as_mut() - .map(|tx| write(tx, args)); - }); -} - -/* - * Because the logger needs to have a size in order to be allocated - * statically, we need to pull in architecture-specific details about - * the implementation. - * - * By putting everything in an `arch` module, we can more easily swap - * things out at compile time with feature flags, or a similar - * mechanism. - */ -mod arch { - use stm32f1xx_hal::{pac::USART1, serial::Tx}; - pub type Writer = Tx; -} diff --git a/src/logger.rs b/src/logger.rs new file mode 100644 index 0000000..453e268 --- /dev/null +++ b/src/logger.rs @@ -0,0 +1,52 @@ +use core::{ + cell::RefCell, + fmt::{write, Arguments}, +}; + +use cortex_m::interrupt::{self, Mutex}; + +#[macro_export] +macro_rules! log { + ($($args:tt)+) => { + $crate::logger::log_args(core::format_args!($($args)+)) + } +} + +#[macro_export] +macro_rules! logln { + () => ({ kprint!("\r\n") }); + ($fmt: literal $(, $($arg: tt)+)?) => { + log!(concat!($fmt, "\n") $(, $($arg)+)?) + } +} + +static TX: Mutex>> = Mutex::new(RefCell::new(None)); + +pub fn init(tx: arch::Writer) { + interrupt::free(|cs| { + TX.borrow(cs).replace(Some(tx)); + }); +} + +pub fn log_args(args: Arguments) { + interrupt::free(|cs| { + TX.borrow(cs) + .borrow_mut() + .as_mut() + .map(|tx| write(tx, args)); + }); +} + +/* + * Because the logger needs to have a size in order to be allocated + * statically, we need to pull in architecture-specific details about + * the implementation. + * + * By putting everything in an `arch` module, we can more easily swap + * things out at compile time with feature flags, or a similar + * mechanism. + */ +mod arch { + use stm32f1xx_hal::{pac::USART1, serial::Tx}; + pub type Writer = Tx; +} diff --git a/src/main.rs b/src/main.rs deleted file mode 100755 index 9797da5..0000000 --- a/src/main.rs +++ /dev/null @@ -1,188 +0,0 @@ -#![no_std] -#![no_main] - -//extern crate panic_semihosting; - -mod cirque; -mod log; - -use cirque::Cirque; - -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(); - - log::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(); - } -} -- cgit v1.2.3