Initial commit

This commit is contained in:
2025-11-16 15:08:26 +01:00
commit a2bc2232c0
8 changed files with 1467 additions and 0 deletions

231
src/main.rs Normal file
View File

@@ -0,0 +1,231 @@
#![no_std]
#![no_main]
//! # Pinout
//!
//! GP0..GP14 => A0..A14
//! GP15..GP22 => D0..D7
//! GP26 => CE
//! GP27 => OE
use core::cell::Cell;
use cortex_m::{delay::Delay, interrupt::Mutex};
use defmt_rtt as _;
use embedded_hal::digital::OutputPin;
use panic_probe as _;
use pio_proc::pio_asm;
use rp_pico::{
Pins, XOSC_CRYSTAL_FREQ, entry,
hal::{
Sio, Watchdog,
clocks::init_clocks_and_plls,
gpio::{FunctionPio0, PullNone},
pio::{PIO0SM0, PIO0SM3, PIOBuilder, PioIRQ, Rx, ShiftDirection, Tx},
prelude::*,
},
pac::{self, CorePeripherals, Peripherals, interrupt},
};
const ADDRESS_BASE: u8 = 0;
const ADDRESS_PINS: u8 = 15;
const DATA_BASE: u8 = 15;
const DATA_PINS: u8 = 8;
const CE: u8 = 26;
#[allow(unused)]
const OE: u8 = 27;
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));
#[entry]
fn main() -> ! {
let mut pac = Peripherals::take().unwrap();
let core = CorePeripherals::take().unwrap();
let mut watchdog = Watchdog::new(pac.WATCHDOG);
let clocks = init_clocks_and_plls(
XOSC_CRYSTAL_FREQ,
pac.XOSC,
pac.CLOCKS,
pac.PLL_SYS,
pac.PLL_USB,
&mut pac.RESETS,
&mut watchdog,
)
.ok()
.unwrap();
let mut delay = Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
let sio = Sio::new(pac.SIO);
let pins = Pins::new(
pac.IO_BANK0,
pac.PADS_BANK0,
sio.gpio_bank0,
&mut pac.RESETS,
);
let mut led_pin = pins.led.into_push_pull_output();
// set address pins as schmitt-trigger inputs
pins.gpio0
.reconfigure::<FunctionPio0, PullNone>()
.set_schmitt_enabled(true);
pins.gpio1
.reconfigure::<FunctionPio0, PullNone>()
.set_schmitt_enabled(true);
pins.gpio2
.reconfigure::<FunctionPio0, PullNone>()
.set_schmitt_enabled(true);
pins.gpio3
.reconfigure::<FunctionPio0, PullNone>()
.set_schmitt_enabled(true);
pins.gpio4
.reconfigure::<FunctionPio0, PullNone>()
.set_schmitt_enabled(true);
pins.gpio5
.reconfigure::<FunctionPio0, PullNone>()
.set_schmitt_enabled(true);
pins.gpio6
.reconfigure::<FunctionPio0, PullNone>()
.set_schmitt_enabled(true);
pins.gpio7
.reconfigure::<FunctionPio0, PullNone>()
.set_schmitt_enabled(true);
pins.gpio8
.reconfigure::<FunctionPio0, PullNone>()
.set_schmitt_enabled(true);
pins.gpio9
.reconfigure::<FunctionPio0, PullNone>()
.set_schmitt_enabled(true);
pins.gpio10
.reconfigure::<FunctionPio0, PullNone>()
.set_schmitt_enabled(true);
pins.gpio11
.reconfigure::<FunctionPio0, PullNone>()
.set_schmitt_enabled(true);
pins.gpio12
.reconfigure::<FunctionPio0, PullNone>()
.set_schmitt_enabled(true);
pins.gpio13
.reconfigure::<FunctionPio0, PullNone>()
.set_schmitt_enabled(true);
pins.gpio14
.reconfigure::<FunctionPio0, PullNone>()
.set_schmitt_enabled(true);
// set data pins as inputs as we don't know if the output should be enabled yet
pins.gpio15.reconfigure::<FunctionPio0, PullNone>();
pins.gpio16.reconfigure::<FunctionPio0, PullNone>();
pins.gpio17.reconfigure::<FunctionPio0, PullNone>();
pins.gpio18.reconfigure::<FunctionPio0, PullNone>();
pins.gpio19.reconfigure::<FunctionPio0, PullNone>();
pins.gpio20.reconfigure::<FunctionPio0, PullNone>();
pins.gpio21.reconfigure::<FunctionPio0, PullNone>();
pins.gpio22.reconfigure::<FunctionPio0, PullNone>();
// set CE and OE as schmitt-triger inputs
pins.gpio26
.reconfigure::<FunctionPio0, PullNone>()
.set_schmitt_enabled(true);
pins.gpio27
.reconfigure::<FunctionPio0, PullNone>()
.set_schmitt_enabled(true);
// Pull from fifo and write to all data pins
let data = pio_asm!(".wrap_target", "out pins, 8", ".wrap");
// OR CE and OE and set 4 pindirs
let output_enable = pio_asm!(
".origin 0",
".side_set 4 pindirs",
"mov pc, pins side 0xf",
"mov pc, pins side 0x0",
"mov pc, pins side 0x0",
"mov pc, pins side 0x0"
);
// report pin activity to the cpu
let report_data = pio_asm!(
"wait_oe:",
"mov y, pins", // read all pins
"mov osr, y", // move into the osr so we can shift them out
"out null, 26", // skipp all pins until CE
"out x, 2", // put CE and OE into x
"jmp x--, wait_oe", // if any of CE and OE are set go back to the start
"mov isr, y", // put the address into the isr
"push",
".wrap_target",
"mov x, pins", // read all pins
"jmp x!=y wait_oe", // if any pins have changed, restart and check oe again
".wrap"
);
let (mut pio, sm0, sm1, sm2, sm3) = pac.PIO0.split(&mut pac.RESETS);
let data = pio.install(&data.program).unwrap();
let output_enable = pio.install(&output_enable.program).unwrap();
let address = pio.install(&report_data.program).unwrap();
let (data_sm, _, data_tx) = PIOBuilder::from_installed_program(data)
.out_pins(DATA_BASE, DATA_PINS)
.pull_threshold(DATA_PINS)
.autopull(true)
.build(sm0);
let _data_sm = data_sm.start();
cortex_m::interrupt::free(|cs| GLOBAL_DATA_TX.borrow(cs).set(Some(data_tx)));
let (output_enable_low_sm, _, _) =
PIOBuilder::from_installed_program(unsafe { output_enable.share() })
.side_set_pin_base(DATA_BASE)
.in_pin_base(CE)
.build(sm1);
let _output_enable_low_sm = output_enable_low_sm.start();
let (output_enable_high_sm, _, _) = PIOBuilder::from_installed_program(output_enable)
.side_set_pin_base(DATA_BASE + 4)
.in_pin_base(CE)
.build(sm2);
let _output_enable_high_sm = output_enable_high_sm.start();
let (address_sm, address_rx, _) = PIOBuilder::from_installed_program(address)
.in_pin_base(ADDRESS_BASE)
.push_threshold(ADDRESS_PINS)
.autopush(true)
.build(sm3);
let _address_sm = address_sm.start();
address_rx.enable_rx_not_empty_interrupt(PioIRQ::Irq0);
cortex_m::interrupt::free(|cs| GLOBAL_ADDRESS_RX.borrow(cs).set(Some(address_rx)));
unsafe {
pac::NVIC::unmask(pac::interrupt::PIO0_IRQ_0);
}
loop {
led_pin.set_high().unwrap();
delay.delay_ms(500);
led_pin.set_low().unwrap();
delay.delay_ms(500);
}
}
#[interrupt]
fn PIO0_IRQ_0() {
static mut ADDRESS: Option<Rx<PIO0SM3>> = None;
static mut DATA: Option<Tx<PIO0SM0>> = None;
if ADDRESS.is_none() {
*ADDRESS = cortex_m::interrupt::free(|cs| GLOBAL_ADDRESS_RX.borrow(cs).take());
}
if DATA.is_none() {
*DATA = cortex_m::interrupt::free(|cs| GLOBAL_DATA_TX.borrow(cs).take());
}
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));
}
}
}
}