diff --git a/Cargo.toml b/Cargo.toml index 53e8dbf..06c7b0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,3 +23,12 @@ pio = "0.2.1" fixed = "1.23.1" +[dev-dependencies] +embassy-executor = { version = "0.5.0", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "integrated-timers"] } +embassy-futures = { version = "0.1.1" } +embassy_serial = { git = "https://gavania.de/hodasemi/embassy_serial" } + +[[example]] +name = "rp-pico-dht22" +path = "example/rp_pico_dht22.rs" + diff --git a/example/pico_usb_serial.rs b/example/pico_usb_serial.rs deleted file mode 100644 index f5c2b91..0000000 --- a/example/pico_usb_serial.rs +++ /dev/null @@ -1,129 +0,0 @@ -use alloc::{ - boxed::Box, - string::{String, ToString}, -}; -use cortex_m::interrupt::free; -use rp_pico::hal::pac; -use rp_pico::hal::pac::interrupt; -use rp_pico::hal::usb::UsbBus; - -use usb_device::{ - class_prelude::UsbBusAllocator, - prelude::{UsbDevice, UsbDeviceBuilder, UsbVidPid}, -}; -use usbd_serial::SerialPort; - -use crate::serial_buffer::SerialBuffer; - -// use crate::{circular_buffer::CircularBuffer, simple_buffer::SimpleBuffer}; - -static WRITE_BUFFER_SIZE: usize = 32; -static mut USB_BUS: Option> = None; -static mut USB_DEVICE: Option> = None; -static mut USB_SERIAL: Option> = None; -static mut USB_BUFFER: Option> = None; - -pub struct PicoUsbSerial {} - -impl PicoUsbSerial { - pub fn init( - bus: UsbBus, - buffer: Box, - manufacturer: &'static str, - product: &'static str, - serial_number: &'static str, - ) -> Result<(), String> { - unsafe { - if USB_BUS.is_some() { - return Err("PicoUsbSerial already initialized.".to_string()); - } - - // Safety: This is safe as interrupts haven't been started yet - USB_BUFFER = Some(buffer); - USB_BUS = Some(UsbBusAllocator::new(bus)); - } - - let bus_ref = unsafe { USB_BUS.as_ref().unwrap() }; - - let serial = SerialPort::new(bus_ref); - let device = UsbDeviceBuilder::new(bus_ref, UsbVidPid(0x2E8A, 0x0005)) - .manufacturer(manufacturer) - .product(product) - .serial_number(serial_number) - .device_class(usbd_serial::USB_CLASS_CDC) - .build(); - - unsafe { - USB_SERIAL = Some(serial); - USB_DEVICE = Some(device); - - // Enable the USB interrupt - pac::NVIC::unmask(pac::Interrupt::USBCTRL_IRQ); - }; - - Ok(()) - } - - pub fn get_serial() -> Result { - unsafe { - if USB_BUS.is_none() { - Err("Serial not initialized.".to_string()) - } else { - Ok(Self {}) - } - } - } - - pub fn write(&self, data: &[u8]) -> usb_device::Result { - free(|_cs| { - let serial = unsafe { USB_SERIAL.as_mut().unwrap() }; - - // let mut wr = data; - let data_chunks = data.chunks(WRITE_BUFFER_SIZE); - - for mut buf in data_chunks { - while !buf.is_empty() { - serial.write(buf).map(|len| { - buf = &buf[len..]; - })?; - } - } - - Ok(data.len()) - }) - } -} - -/// This function is called whenever the USB Hardware generates an Interrupt -/// Request. -/// -/// We do all our USB work under interrupt, so the main thread can continue on -/// knowing nothing about USB. -#[allow(non_snake_case)] -#[interrupt] -unsafe fn USBCTRL_IRQ() { - let buffer = USB_BUFFER.as_mut().unwrap(); - - // Grab the global objects. This is OK as we only access them under interrupt. - let usb_dev = USB_DEVICE.as_mut().unwrap(); - let serial = USB_SERIAL.as_mut().unwrap(); - - // Poll the USB driver with all of our supported USB Classes - if usb_dev.poll(&mut [serial]) { - let mut buf = [0u8; 64]; - match serial.read(&mut buf) { - Err(_e) => { - // Do nothing - } - Ok(0) => { - // Do nothing - } - Ok(count) => { - // Convert to upper case - buf.iter_mut().take(count).for_each(|b| { - buffer.write(b.clone()); - }); - } - } - } -} diff --git a/example/rp_pico_dht22.rs b/example/rp_pico_dht22.rs index dc61ba4..95be12b 100644 --- a/example/rp_pico_dht22.rs +++ b/example/rp_pico_dht22.rs @@ -1,112 +1,89 @@ #![no_std] #![no_main] -extern crate alloc; -extern crate dht_pio; - -use alloc::boxed::Box; -use alloc::format; use core::panic::PanicInfo; -use cortex_m::interrupt::free; -use dht_pio::Dht22; -use embedded_alloc::Heap; -use hal::{clocks::init_clocks_and_plls, clocks::ClockSource, pac, usb::UsbBus, Sio, Watchdog}; -use rp_pico::entry; -use rp_pico::hal; -use rp_pico::hal::pio::PIOExt; +use embassy_executor::Spawner; +use embassy_futures::join::join; +use embassy_rp::{ + bind_interrupts, + gpio::{Level, Output}, + peripherals::{PIN_15, PIO0}, + pio::{InterruptHandler, Pio}, +}; +use embassy_time::Timer; -mod pico_usb_serial; -mod serial_buffer; -mod simple_buffer; -use pico_usb_serial::PicoUsbSerial; -use serial_buffer::SerialBuffer; -use simple_buffer::SimpleBuffer; - -#[global_allocator] -static HEAP: Heap = Heap::empty(); -const HEAP_SIZE: usize = 4069; - -#[entry] -fn main() -> ! { - // Initialize the allocator BEFORE you use it - init_heap(); - - let mut pac = pac::Peripherals::take().unwrap(); - let mut watchdog = Watchdog::new(pac.WATCHDOG); - let clocks = init_clocks_and_plls( - rp_pico::XOSC_CRYSTAL_FREQ, - pac.XOSC, - pac.CLOCKS, - pac.PLL_SYS, - pac.PLL_USB, - &mut pac.RESETS, - &mut watchdog, - ) - .ok() - .unwrap(); - - let sio = Sio::new(pac.SIO); - let pins = rp_pico::Pins::new( - pac.IO_BANK0, - pac.PADS_BANK0, - sio.gpio_bank0, - &mut pac.RESETS, - ); - - let core = pac::CorePeripherals::take().unwrap(); - let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.get_freq().to_Hz()); - - PicoUsbSerial::init( - UsbBus::new( - pac.USBCTRL_REGS, - pac.USBCTRL_DPRAM, - clocks.usb_clock, - true, - &mut pac.RESETS, - ), - Box::new(SimpleBuffer::new(1024)), - "MyCorp", - "Test", - "Serial", - ) - .expect("Failed to init Serial"); - - let serial = PicoUsbSerial::get_serial().expect("Failed to get serial!"); - - let (dht_pio, dht_sm, _, _, _) = pac.PIO0.split(&mut pac.RESETS); - let mut dht = Dht22::new(dht_pio, dht_sm, pins.gpio0.into_function()); - - loop { - free(|_cs| match dht.read(&mut delay) { - Ok(result) => { - serial.write(format!("{:#?}\r\n", result).as_bytes()).ok(); - } - Err(e) => { - serial - .write(format!("DHT Error: {:?}\r\n", e).as_bytes()) - .ok(); - } - }); - - delay.delay_ms(1000); - } -} - -fn init_heap() -> () { - use core::mem::MaybeUninit; - static mut HEAP_MEM: [MaybeUninit; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE]; - unsafe { HEAP.init(HEAP_MEM.as_ptr() as usize, HEAP_SIZE) }; -} +use dht_pio::{Dht22Type2, DhtError}; +use embassy_serial; #[panic_handler] -fn panic(_: &PanicInfo) -> ! { - let ser = PicoUsbSerial::get_serial(); +fn panic(_info: &PanicInfo) -> ! { + loop { + unsafe { + PANIC_LED.as_mut().unwrap().set_high(); + } + } +} - if ser.is_ok() { - let ser = ser.unwrap(); - let _ = ser.write(b"===== PANIC =====\r\n"); +static mut PANIC_LED: Option> = None; + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + + unsafe { + PANIC_LED = Some(Output::new(p.PIN_15, Level::Low)); } - loop {} + // debug: serial port + let (mut serial, usb_future) = + embassy_serial::Serial::new(p.USB, embassy_serial::SerialConfig::new()); + + // pio access + let pio = p.PIO0; + let Pio { + mut common, + + // dht22 state machine + sm1, + .. + } = Pio::new(pio, Irqs); + + // create DHT22 + let mut dht = Dht22Type2::new(&mut common, sm1, p.PIN_0); + + let dht_reading = async { + loop { + match dht.read().await { + Ok(reading) => { + serial.send_msg("temp:\n").await.unwrap(); + serial + .send_number(reading.temperature as u32, 10) + .await + .unwrap(); + serial.send_msg("humid:\n").await.unwrap(); + serial + .send_number(reading.humidity as u32, 10) + .await + .unwrap(); + } + Err(err) => serial + .send_msg(match err { + DhtError::Timeout => "dht timeout error\n\r", + DhtError::CrcMismatch(_, _) => "dht checksum error\n\r", + DhtError::ReadError => "dht read error\n\r", + }) + .await + .unwrap(), + } + + Timer::after_secs(3).await; + } + }; + + join(usb_future, dht_reading).await; } diff --git a/example/serial_buffer.rs b/example/serial_buffer.rs deleted file mode 100644 index aebc70c..0000000 --- a/example/serial_buffer.rs +++ /dev/null @@ -1,10 +0,0 @@ -use alloc::vec::Vec; - -pub trait SerialBuffer { - fn new(buffer_size: usize) -> Self where Self: Sized; - fn write(&mut self, value: u8) -> (); - fn read(&mut self) -> Option; - fn read_all(&mut self) -> Vec; - fn reset(&mut self) -> (); - fn available_to_read(&self) -> usize; -} \ No newline at end of file diff --git a/example/simple_buffer.rs b/example/simple_buffer.rs deleted file mode 100644 index 0929f86..0000000 --- a/example/simple_buffer.rs +++ /dev/null @@ -1,45 +0,0 @@ -use alloc::{collections::VecDeque, vec::Vec}; -use crate::serial_buffer::SerialBuffer; - -pub struct SimpleBuffer{ - buf: VecDeque, -} - -#[allow(unused)] -impl SerialBuffer for SimpleBuffer { - fn new(buffer_size: usize) -> Self { - assert!(buffer_size > 0); - - Self { - buf: VecDeque::with_capacity(buffer_size), - } - } - - fn write(&mut self, value: u8) -> (){ - if self.buf.len() < self.buf.capacity(){ - self.buf.push_back(value); - } - } - - fn read(&mut self) -> Option { - self.buf.pop_front() - } - - fn read_all(&mut self) -> Vec{ - let mut data = Vec::::with_capacity(self.available_to_read()); - - for _ in 0..self.buf.len(){ - data.push(self.buf.pop_front().unwrap_or(0)); - } - - return data; - } - - fn reset(&mut self) -> (){ - self.buf.clear(); - } - - fn available_to_read(&self) -> usize { - return self.buf.len(); - } -}