simple picorom interface
This commit is contained in:
137
src/main.rs
137
src/main.rs
@@ -8,9 +8,14 @@
|
||||
//! GP26 => CE
|
||||
//! GP27 => OE
|
||||
|
||||
use core::cell::Cell;
|
||||
mod serial;
|
||||
|
||||
use cortex_m::{delay::Delay, interrupt::Mutex};
|
||||
use core::{
|
||||
cell::Cell,
|
||||
sync::atomic::{AtomicU8, Ordering},
|
||||
};
|
||||
|
||||
use cortex_m::{delay::Delay, interrupt::Mutex, singleton};
|
||||
use defmt_rtt as _;
|
||||
use embedded_hal::digital::OutputPin;
|
||||
use panic_probe as _;
|
||||
@@ -21,11 +26,16 @@ use rp_pico::{
|
||||
Sio, Watchdog,
|
||||
clocks::init_clocks_and_plls,
|
||||
gpio::{FunctionPio0, PullNone},
|
||||
pio::{PIO0SM0, PIO0SM3, PIOBuilder, PioIRQ, Rx, ShiftDirection, Tx},
|
||||
pio::{PIO0SM0, PIO0SM3, PIOBuilder, PioIRQ, Rx, Tx},
|
||||
prelude::*,
|
||||
usb::UsbBus,
|
||||
},
|
||||
pac::{self, CorePeripherals, Peripherals, interrupt},
|
||||
};
|
||||
use usb_device::{class_prelude::*, prelude::*};
|
||||
use usbd_serial::SerialPort;
|
||||
|
||||
use crate::serial::{Link, PacketBuilder};
|
||||
|
||||
const ADDRESS_BASE: u8 = 0;
|
||||
const ADDRESS_PINS: u8 = 15;
|
||||
@@ -35,13 +45,19 @@ const CE: u8 = 26;
|
||||
#[allow(unused)]
|
||||
const OE: u8 = 27;
|
||||
|
||||
const ROM_SIZE: usize = 1024 * 32;
|
||||
|
||||
static GLOBAL_ADDRESS_RX: Mutex<Cell<Option<Rx<PIO0SM3>>>> = Mutex::new(Cell::new(None));
|
||||
static GLOBAL_DATA_TX: Mutex<Cell<Option<Tx<PIO0SM0>>>> = Mutex::new(Cell::new(None));
|
||||
static ROM_DATA: [AtomicU8; ROM_SIZE] = [const { AtomicU8::new(0) }; ROM_SIZE];
|
||||
|
||||
static GLOBAL_USB_DEVICE: Mutex<Cell<Option<UsbDevice<UsbBus>>>> = Mutex::new(Cell::new(None));
|
||||
static GLOBAL_USB_SERIAL: Mutex<Cell<Option<SerialPort<UsbBus>>>> = Mutex::new(Cell::new(None));
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
let mut pac = Peripherals::take().unwrap();
|
||||
let core = CorePeripherals::take().unwrap();
|
||||
let mut core = CorePeripherals::take().unwrap();
|
||||
|
||||
let mut watchdog = Watchdog::new(pac.WATCHDOG);
|
||||
|
||||
@@ -195,8 +211,37 @@ fn main() -> ! {
|
||||
address_rx.enable_rx_not_empty_interrupt(PioIRQ::Irq0);
|
||||
cortex_m::interrupt::free(|cs| GLOBAL_ADDRESS_RX.borrow(cs).set(Some(address_rx)));
|
||||
|
||||
let usbctrl_regs = pac.USBCTRL_REGS;
|
||||
let usbctrl_dpram = pac.USBCTRL_DPRAM;
|
||||
let resets = &mut pac.RESETS;
|
||||
let usb_bus = singleton!(: UsbBusAllocator<UsbBus> = UsbBusAllocator::new(UsbBus::new(
|
||||
usbctrl_regs,
|
||||
usbctrl_dpram,
|
||||
clocks.usb_clock,
|
||||
true,
|
||||
resets,
|
||||
)))
|
||||
.unwrap();
|
||||
let serial = SerialPort::new(usb_bus);
|
||||
cortex_m::interrupt::free(|cs| GLOBAL_USB_SERIAL.borrow(cs).set(Some(serial)));
|
||||
|
||||
let usb_dev = UsbDeviceBuilder::new(usb_bus, UsbVidPid(0x2e8a, 0x000a))
|
||||
.strings(&[StringDescriptors::default()
|
||||
.manufacturer("Max Känner")
|
||||
.product("PicoROM.rs")
|
||||
.serial_number("1")])
|
||||
.unwrap()
|
||||
.device_class(2)
|
||||
.build();
|
||||
cortex_m::interrupt::free(|cs| GLOBAL_USB_DEVICE.borrow(cs).set(Some(usb_dev)));
|
||||
|
||||
unsafe {
|
||||
// Highest priority for pio
|
||||
core.NVIC.set_priority(pac::interrupt::PIO0_IRQ_0, 0x00);
|
||||
// lowest priority for usb
|
||||
core.NVIC.set_priority(pac::interrupt::USBCTRL_IRQ, 0xFF);
|
||||
pac::NVIC::unmask(pac::interrupt::PIO0_IRQ_0);
|
||||
pac::NVIC::unmask(pac::interrupt::USBCTRL_IRQ);
|
||||
}
|
||||
|
||||
loop {
|
||||
@@ -220,12 +265,86 @@ fn PIO0_IRQ_0() {
|
||||
}
|
||||
|
||||
if let Some(address) = ADDRESS {
|
||||
while let Some(address) = address.read() {
|
||||
let address = (address & 0x7fff) as u16;
|
||||
if let Some(data) = DATA {
|
||||
defmt::trace!("replying with {:#04x} @ {:#06x}", address as u8, address);
|
||||
data.write(u32::from(address));
|
||||
while let Some(rx) = address.read() {
|
||||
let address = (rx & 0x7fff) as u16;
|
||||
if let Some(tx) = DATA {
|
||||
let data = ROM_DATA[usize::from(address)].load(Ordering::Relaxed);
|
||||
defmt::trace!("replying with {:#04x} @ {:#06x}", data, address);
|
||||
tx.write(u32::from(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
fn USBCTRL_IRQ() {
|
||||
static mut USB_DEVICE: Option<UsbDevice<UsbBus>> = None;
|
||||
static mut USB_SERIAL: Option<SerialPort<UsbBus>> = None;
|
||||
static mut DO_PREAMBLE: bool = true;
|
||||
static mut PACKET_BUILDER: PacketBuilder = PacketBuilder::new();
|
||||
static mut LINK: Link = Link::new();
|
||||
const PREAMBLE: &[u8] = b"PicoROM Hello";
|
||||
|
||||
if USB_DEVICE.is_none() {
|
||||
*USB_DEVICE = cortex_m::interrupt::free(|cs| GLOBAL_USB_DEVICE.borrow(cs).take());
|
||||
}
|
||||
|
||||
if USB_SERIAL.is_none() {
|
||||
*USB_SERIAL = cortex_m::interrupt::free(|cs| GLOBAL_USB_SERIAL.borrow(cs).take());
|
||||
}
|
||||
|
||||
let Some(usb_dev) = USB_DEVICE else { return };
|
||||
let Some(serial) = USB_SERIAL else { return };
|
||||
|
||||
if !serial.rts() {
|
||||
*DO_PREAMBLE = true;
|
||||
}
|
||||
if *DO_PREAMBLE && serial.rts() {
|
||||
match serial.write(PREAMBLE) {
|
||||
Ok(count) if count == PREAMBLE.len() => {
|
||||
*DO_PREAMBLE = false;
|
||||
defmt::info!("Send Preamble")
|
||||
}
|
||||
Ok(count) => {
|
||||
defmt::warn!(
|
||||
"Unable to write the whole preamble. Only wrote {} Bytes",
|
||||
count
|
||||
);
|
||||
}
|
||||
Err(UsbError::WouldBlock) => (),
|
||||
Err(e) => {
|
||||
defmt::error!("Unable to write preamble: {}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if usb_dev.poll(&mut [serial]) {
|
||||
let mut buf = [0u8; 64];
|
||||
match serial.read(&mut buf) {
|
||||
Ok(0) => {}
|
||||
Ok(count) => {
|
||||
for byte in buf.into_iter().take(count) {
|
||||
if let Some(packet) = PACKET_BUILDER.push(byte) {
|
||||
defmt::debug!("Got packet: {}", packet);
|
||||
if let Some(response) = LINK.handle_packet(&packet) {
|
||||
defmt::info!("Sending Response: {}", response);
|
||||
if let Err(e) = response.send(serial)
|
||||
&& e != UsbError::WouldBlock
|
||||
{
|
||||
defmt::error!("Unable to send response: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(UsbError::WouldBlock) => (),
|
||||
Err(e) => {
|
||||
defmt::error!("USB Error: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if usb_dev.state() == UsbDeviceState::Default {
|
||||
*DO_PREAMBLE = true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user