Change example to work with embassy
This commit is contained in:
parent
5ef4c23e03
commit
e4e485b832
5 changed files with 86 additions and 284 deletions
|
@ -23,3 +23,12 @@ pio = "0.2.1"
|
||||||
|
|
||||||
fixed = "1.23.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"
|
||||||
|
|
||||||
|
|
|
@ -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<UsbBusAllocator<UsbBus>> = None;
|
|
||||||
static mut USB_DEVICE: Option<UsbDevice<UsbBus>> = None;
|
|
||||||
static mut USB_SERIAL: Option<SerialPort<UsbBus>> = None;
|
|
||||||
static mut USB_BUFFER: Option<Box<dyn SerialBuffer>> = None;
|
|
||||||
|
|
||||||
pub struct PicoUsbSerial {}
|
|
||||||
|
|
||||||
impl PicoUsbSerial {
|
|
||||||
pub fn init(
|
|
||||||
bus: UsbBus,
|
|
||||||
buffer: Box<dyn SerialBuffer>,
|
|
||||||
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<Self, String> {
|
|
||||||
unsafe {
|
|
||||||
if USB_BUS.is_none() {
|
|
||||||
Err("Serial not initialized.".to_string())
|
|
||||||
} else {
|
|
||||||
Ok(Self {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write(&self, data: &[u8]) -> usb_device::Result<usize> {
|
|
||||||
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());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,112 +1,89 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
extern crate alloc;
|
|
||||||
extern crate dht_pio;
|
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
|
||||||
use alloc::format;
|
|
||||||
use core::panic::PanicInfo;
|
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 embassy_executor::Spawner;
|
||||||
use rp_pico::entry;
|
use embassy_futures::join::join;
|
||||||
use rp_pico::hal;
|
use embassy_rp::{
|
||||||
use rp_pico::hal::pio::PIOExt;
|
bind_interrupts,
|
||||||
|
gpio::{Level, Output},
|
||||||
|
peripherals::{PIN_15, PIO0},
|
||||||
|
pio::{InterruptHandler, Pio},
|
||||||
|
};
|
||||||
|
use embassy_time::Timer;
|
||||||
|
|
||||||
mod pico_usb_serial;
|
use dht_pio::{Dht22Type2, DhtError};
|
||||||
mod serial_buffer;
|
use embassy_serial;
|
||||||
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<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
|
|
||||||
unsafe { HEAP.init(HEAP_MEM.as_ptr() as usize, HEAP_SIZE) };
|
|
||||||
}
|
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(_: &PanicInfo) -> ! {
|
fn panic(_info: &PanicInfo) -> ! {
|
||||||
let ser = PicoUsbSerial::get_serial();
|
loop {
|
||||||
|
unsafe {
|
||||||
|
PANIC_LED.as_mut().unwrap().set_high();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ser.is_ok() {
|
static mut PANIC_LED: Option<Output<'static, PIN_15>> = None;
|
||||||
let ser = ser.unwrap();
|
|
||||||
let _ = ser.write(b"===== PANIC =====\r\n");
|
bind_interrupts!(struct Irqs {
|
||||||
|
PIO0_IRQ_0 => InterruptHandler<PIO0>;
|
||||||
|
});
|
||||||
|
|
||||||
|
#[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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<u8>;
|
|
||||||
fn read_all(&mut self) -> Vec<u8>;
|
|
||||||
fn reset(&mut self) -> ();
|
|
||||||
fn available_to_read(&self) -> usize;
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
use alloc::{collections::VecDeque, vec::Vec};
|
|
||||||
use crate::serial_buffer::SerialBuffer;
|
|
||||||
|
|
||||||
pub struct SimpleBuffer{
|
|
||||||
buf: VecDeque<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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<u8> {
|
|
||||||
self.buf.pop_front()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_all(&mut self) -> Vec<u8>{
|
|
||||||
let mut data = Vec::<u8>::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();
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue