Add example

This commit is contained in:
Jonathan BAUDIN 2023-09-21 18:45:47 +02:00
parent b0ecfd37a3
commit 84f57e00e8
6 changed files with 335 additions and 0 deletions

View file

@ -21,3 +21,16 @@ rp2040-boot2 = "0.2.1"
rp2040-hal = { version = "0.9.0", features = ["rp2040-e5"] } rp2040-hal = { version = "0.9.0", features = ["rp2040-e5"] }
pio-proc = "0.2.2" pio-proc = "0.2.2"
pio = "0.2.1" pio = "0.2.1"
[dev-dependencies]
rp-pico = { version = "0.8.0", features = ["rp2040-e5"] }
embedded-hal = { version = "0.2.5", features = ["unproven"] }
embedded-alloc = "0.5.0"
cortex-m = { version = "0.7.6"}
cortex-m-rt = "0.7.3"
usb-device = "0.2.9"
usbd-serial = "0.1.1"
[[example]]
name = "rp-pico-dht22"
path = "example/rp_pico_dht22.rs"

140
example/pico_usb_serial.rs Normal file
View file

@ -0,0 +1,140 @@
use alloc::{
boxed::Box,
string::{String, ToString},
vec::Vec,
};
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 available_data(&self) -> usize {
unsafe {
return USB_BUFFER.as_ref().unwrap().available_to_read();
};
}
pub fn read(&self) -> u8 {
free(|_cs| unsafe { USB_BUFFER.as_mut().unwrap().read().unwrap_or(0) })
}
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());
});
}
}
}
}

112
example/rp_pico_dht22.rs Normal file
View file

@ -0,0 +1,112 @@
#![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;
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<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
unsafe { HEAP.init(HEAP_MEM.as_ptr() as usize, HEAP_SIZE) };
}
#[panic_handler]
fn panic(_: &PanicInfo) -> ! {
let ser = PicoUsbSerial::get_serial();
if ser.is_ok() {
let ser = ser.unwrap();
let _ = ser.write(b"===== PANIC =====\r\n");
}
loop {}
}

10
example/serial_buffer.rs Normal file
View file

@ -0,0 +1,10 @@
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;
}

45
example/simple_buffer.rs Normal file
View file

@ -0,0 +1,45 @@
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();
}
}

15
memory.x Normal file
View file

@ -0,0 +1,15 @@
MEMORY {
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
RAM : ORIGIN = 0x20000000, LENGTH = 256K
}
EXTERN(BOOT2_FIRMWARE)
SECTIONS {
/* ### Boot loader */
.boot2 ORIGIN(BOOT2) :
{
KEEP(*(.boot2));
} > BOOT2
} INSERT BEFORE .text;