Merge #1434
1434: rp pio IV (the voyage home) r=Dirbaio a=pennae this should hopefully be the last entry in this series. after this we'll have a reasonably safe interface to pio, both for configuration and at runtime. pio now looks very much like the other peripherals (though not exactly, seeing how state machines can't be constructed from a config but only have it applied to them later). the generated code for `StateMachine::set_config` is still larger than we'd like (almost 300 bytes at Oz), but it's a great step up in safety from the previous interface at approximately the same code space cost. Co-authored-by: pennae <github@quasiparticle.net>
This commit is contained in:
commit
79c60f4a7d
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,8 @@
|
|||||||
use pio::{InSource, InstructionOperands, JmpCondition, OutDestination, SetDestination};
|
use pio::{InSource, InstructionOperands, JmpCondition, OutDestination, SetDestination};
|
||||||
|
|
||||||
use crate::pio::{PioInstance, PioStateMachine};
|
use crate::pio::{Instance, StateMachine};
|
||||||
|
|
||||||
pub fn set_x<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>, value: u32) {
|
pub unsafe fn set_x<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, value: u32) {
|
||||||
const OUT: u16 = InstructionOperands::OUT {
|
const OUT: u16 = InstructionOperands::OUT {
|
||||||
destination: OutDestination::X,
|
destination: OutDestination::X,
|
||||||
bit_count: 32,
|
bit_count: 32,
|
||||||
@ -12,7 +12,7 @@ pub fn set_x<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM
|
|||||||
sm.exec_instr(OUT);
|
sm.exec_instr(OUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_x<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>) -> u32 {
|
pub unsafe fn get_x<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>) -> u32 {
|
||||||
const IN: u16 = InstructionOperands::IN {
|
const IN: u16 = InstructionOperands::IN {
|
||||||
source: InSource::X,
|
source: InSource::X,
|
||||||
bit_count: 32,
|
bit_count: 32,
|
||||||
@ -22,7 +22,7 @@ pub fn get_x<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM
|
|||||||
sm.rx().pull()
|
sm.rx().pull()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_y<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>, value: u32) {
|
pub unsafe fn set_y<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, value: u32) {
|
||||||
const OUT: u16 = InstructionOperands::OUT {
|
const OUT: u16 = InstructionOperands::OUT {
|
||||||
destination: OutDestination::Y,
|
destination: OutDestination::Y,
|
||||||
bit_count: 32,
|
bit_count: 32,
|
||||||
@ -32,7 +32,7 @@ pub fn set_y<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM
|
|||||||
sm.exec_instr(OUT);
|
sm.exec_instr(OUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_y<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>) -> u32 {
|
pub unsafe fn get_y<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>) -> u32 {
|
||||||
const IN: u16 = InstructionOperands::IN {
|
const IN: u16 = InstructionOperands::IN {
|
||||||
source: InSource::Y,
|
source: InSource::Y,
|
||||||
bit_count: 32,
|
bit_count: 32,
|
||||||
@ -43,7 +43,7 @@ pub fn get_y<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM
|
|||||||
sm.rx().pull()
|
sm.rx().pull()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_pindir<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>, data: u8) {
|
pub unsafe fn set_pindir<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u8) {
|
||||||
let set: u16 = InstructionOperands::SET {
|
let set: u16 = InstructionOperands::SET {
|
||||||
destination: SetDestination::PINDIRS,
|
destination: SetDestination::PINDIRS,
|
||||||
data,
|
data,
|
||||||
@ -52,7 +52,7 @@ pub fn set_pindir<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PI
|
|||||||
sm.exec_instr(set);
|
sm.exec_instr(set);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_pin<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>, data: u8) {
|
pub unsafe fn set_pin<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u8) {
|
||||||
let set: u16 = InstructionOperands::SET {
|
let set: u16 = InstructionOperands::SET {
|
||||||
destination: SetDestination::PINS,
|
destination: SetDestination::PINS,
|
||||||
data,
|
data,
|
||||||
@ -61,7 +61,7 @@ pub fn set_pin<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO,
|
|||||||
sm.exec_instr(set);
|
sm.exec_instr(set);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_out_pin<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>, data: u32) {
|
pub unsafe fn set_out_pin<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u32) {
|
||||||
const OUT: u16 = InstructionOperands::OUT {
|
const OUT: u16 = InstructionOperands::OUT {
|
||||||
destination: OutDestination::PINS,
|
destination: OutDestination::PINS,
|
||||||
bit_count: 32,
|
bit_count: 32,
|
||||||
@ -70,7 +70,7 @@ pub fn set_out_pin<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<P
|
|||||||
sm.tx().push(data);
|
sm.tx().push(data);
|
||||||
sm.exec_instr(OUT);
|
sm.exec_instr(OUT);
|
||||||
}
|
}
|
||||||
pub fn set_out_pindir<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>, data: u32) {
|
pub unsafe fn set_out_pindir<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, data: u32) {
|
||||||
const OUT: u16 = InstructionOperands::OUT {
|
const OUT: u16 = InstructionOperands::OUT {
|
||||||
destination: OutDestination::PINDIRS,
|
destination: OutDestination::PINDIRS,
|
||||||
bit_count: 32,
|
bit_count: 32,
|
||||||
@ -80,7 +80,7 @@ pub fn set_out_pindir<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachin
|
|||||||
sm.exec_instr(OUT);
|
sm.exec_instr(OUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exec_jmp<PIO: PioInstance, const SM: usize>(sm: &mut PioStateMachine<PIO, SM>, to_addr: u8) {
|
pub unsafe fn exec_jmp<PIO: Instance, const SM: usize>(sm: &mut StateMachine<PIO, SM>, to_addr: u8) {
|
||||||
let jmp: u16 = InstructionOperands::JMP {
|
let jmp: u16 = InstructionOperands::JMP {
|
||||||
address: to_addr,
|
address: to_addr,
|
||||||
condition: JmpCondition::Always,
|
condition: JmpCondition::Always,
|
||||||
|
@ -26,11 +26,7 @@ where
|
|||||||
Some(if instr & 0b1110_0000_0000_0000 == 0 {
|
Some(if instr & 0b1110_0000_0000_0000 == 0 {
|
||||||
// this is a JMP instruction -> add offset to address
|
// this is a JMP instruction -> add offset to address
|
||||||
let address = (instr & 0b1_1111) as u8;
|
let address = (instr & 0b1_1111) as u8;
|
||||||
let address = address + self.offset;
|
let address = address.wrapping_add(self.offset) % 32;
|
||||||
assert!(
|
|
||||||
address < pio::RP2040_MAX_PROGRAM_SIZE as u8,
|
|
||||||
"Invalid JMP out of the program after offset addition"
|
|
||||||
);
|
|
||||||
instr & (!0b11111) | address as u16
|
instr & (!0b11111) | address as u16
|
||||||
} else {
|
} else {
|
||||||
instr
|
instr
|
||||||
@ -62,8 +58,8 @@ impl<'a, const PROGRAM_SIZE: usize> RelocatedProgram<'a, PROGRAM_SIZE> {
|
|||||||
let wrap = self.program.wrap;
|
let wrap = self.program.wrap;
|
||||||
let origin = self.origin;
|
let origin = self.origin;
|
||||||
Wrap {
|
Wrap {
|
||||||
source: wrap.source + origin,
|
source: wrap.source.wrapping_add(origin) % 32,
|
||||||
target: wrap.target + origin,
|
target: wrap.target.wrapping_add(origin) % 32,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,8 @@ lorawan = { version = "0.7.3", default-features = false, features = ["default-cr
|
|||||||
|
|
||||||
defmt = "0.3"
|
defmt = "0.3"
|
||||||
defmt-rtt = "0.4"
|
defmt-rtt = "0.4"
|
||||||
|
fixed = "1.23.1"
|
||||||
|
fixed-macro = "1.2"
|
||||||
|
|
||||||
#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
|
#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
|
||||||
cortex-m = { version = "0.7.6", features = ["inline-asm"] }
|
cortex-m = { version = "0.7.6", features = ["inline-asm"] }
|
||||||
|
@ -2,14 +2,16 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
use defmt::info;
|
use defmt::info;
|
||||||
|
use embassy_embedded_hal::SetConfig;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_rp::peripherals::PIO0;
|
use embassy_rp::peripherals::PIO0;
|
||||||
use embassy_rp::pio::{Pio, PioCommon, PioIrq, PioPin, PioStateMachine, ShiftDirection};
|
use embassy_rp::pio::{Common, Config, Irq, Pio, PioPin, ShiftDirection, StateMachine};
|
||||||
use embassy_rp::pio_instr_util;
|
|
||||||
use embassy_rp::relocate::RelocatedProgram;
|
use embassy_rp::relocate::RelocatedProgram;
|
||||||
|
use fixed::traits::ToFixed;
|
||||||
|
use fixed_macro::types::U56F8;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
fn setup_pio_task_sm0(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachine<PIO0, 0>, pin: impl PioPin) {
|
fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 0>, pin: impl PioPin) {
|
||||||
// Setup sm0
|
// Setup sm0
|
||||||
|
|
||||||
// Send data serially to pin
|
// Send data serially to pin
|
||||||
@ -22,22 +24,18 @@ fn setup_pio_task_sm0(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachine<PIO0,
|
|||||||
);
|
);
|
||||||
|
|
||||||
let relocated = RelocatedProgram::new(&prg.program);
|
let relocated = RelocatedProgram::new(&prg.program);
|
||||||
|
let mut cfg = Config::default();
|
||||||
|
cfg.use_program(&pio.load_program(&relocated), &[]);
|
||||||
let out_pin = pio.make_pio_pin(pin);
|
let out_pin = pio.make_pio_pin(pin);
|
||||||
let pio_pins = [&out_pin];
|
cfg.set_out_pins(&[&out_pin]);
|
||||||
sm.set_out_pins(&pio_pins);
|
cfg.set_set_pins(&[&out_pin]);
|
||||||
pio.write_instr(relocated.origin() as usize, relocated.code());
|
cfg.clock_divider = (U56F8!(125_000_000) / 20 / 200).to_fixed();
|
||||||
pio_instr_util::exec_jmp(sm, relocated.origin());
|
cfg.shift_out.auto_fill = true;
|
||||||
sm.set_clkdiv((125e6 / 20.0 / 2e2 * 256.0) as u32);
|
sm.set_config(&cfg);
|
||||||
sm.set_set_range(0, 1);
|
|
||||||
let pio::Wrap { source, target } = relocated.wrap();
|
|
||||||
sm.set_wrap(source, target);
|
|
||||||
|
|
||||||
sm.set_autopull(true);
|
|
||||||
sm.set_out_shift_dir(ShiftDirection::Left);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn pio_task_sm0(mut sm: PioStateMachine<'static, PIO0, 0>) {
|
async fn pio_task_sm0(mut sm: StateMachine<'static, PIO0, 0>) {
|
||||||
sm.set_enable(true);
|
sm.set_enable(true);
|
||||||
|
|
||||||
let mut v = 0x0f0caffa;
|
let mut v = 0x0f0caffa;
|
||||||
@ -48,26 +46,23 @@ async fn pio_task_sm0(mut sm: PioStateMachine<'static, PIO0, 0>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_pio_task_sm1(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachine<PIO0, 1>) {
|
fn setup_pio_task_sm1<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 1>) {
|
||||||
// Setupm sm1
|
// Setupm sm1
|
||||||
|
|
||||||
// Read 0b10101 repeatedly until ISR is full
|
// Read 0b10101 repeatedly until ISR is full
|
||||||
let prg = pio_proc::pio_asm!(".origin 8", "set x, 0x15", ".wrap_target", "in x, 5 [31]", ".wrap",);
|
let prg = pio_proc::pio_asm!(".origin 8", "set x, 0x15", ".wrap_target", "in x, 5 [31]", ".wrap",);
|
||||||
|
|
||||||
let relocated = RelocatedProgram::new(&prg.program);
|
let relocated = RelocatedProgram::new(&prg.program);
|
||||||
pio.write_instr(relocated.origin() as usize, relocated.code());
|
let mut cfg = Config::default();
|
||||||
pio_instr_util::exec_jmp(sm, relocated.origin());
|
cfg.use_program(&pio.load_program(&relocated), &[]);
|
||||||
sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32);
|
cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed();
|
||||||
sm.set_set_range(0, 0);
|
cfg.shift_in.auto_fill = true;
|
||||||
let pio::Wrap { source, target } = relocated.wrap();
|
cfg.shift_in.direction = ShiftDirection::Right;
|
||||||
sm.set_wrap(source, target);
|
sm.set_config(&cfg);
|
||||||
|
|
||||||
sm.set_autopush(true);
|
|
||||||
sm.set_in_shift_dir(ShiftDirection::Right);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn pio_task_sm1(mut sm: PioStateMachine<'static, PIO0, 1>) {
|
async fn pio_task_sm1(mut sm: StateMachine<'static, PIO0, 1>) {
|
||||||
sm.set_enable(true);
|
sm.set_enable(true);
|
||||||
loop {
|
loop {
|
||||||
let rx = sm.rx().wait_pull().await;
|
let rx = sm.rx().wait_pull().await;
|
||||||
@ -75,7 +70,7 @@ async fn pio_task_sm1(mut sm: PioStateMachine<'static, PIO0, 1>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_pio_task_sm2(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachine<PIO0, 2>) {
|
fn setup_pio_task_sm2<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 2>) {
|
||||||
// Setup sm2
|
// Setup sm2
|
||||||
|
|
||||||
// Repeatedly trigger IRQ 3
|
// Repeatedly trigger IRQ 3
|
||||||
@ -89,17 +84,14 @@ fn setup_pio_task_sm2(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachine<PIO0,
|
|||||||
".wrap",
|
".wrap",
|
||||||
);
|
);
|
||||||
let relocated = RelocatedProgram::new(&prg.program);
|
let relocated = RelocatedProgram::new(&prg.program);
|
||||||
pio.write_instr(relocated.origin() as usize, relocated.code());
|
let mut cfg = Config::default();
|
||||||
|
cfg.use_program(&pio.load_program(&relocated), &[]);
|
||||||
let pio::Wrap { source, target } = relocated.wrap();
|
cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed();
|
||||||
sm.set_wrap(source, target);
|
sm.set_config(&cfg);
|
||||||
|
|
||||||
pio_instr_util::exec_jmp(sm, relocated.origin());
|
|
||||||
sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn pio_task_sm2(mut irq: PioIrq<'static, PIO0, 3>, mut sm: PioStateMachine<'static, PIO0, 2>) {
|
async fn pio_task_sm2(mut irq: Irq<'static, PIO0, 3>, mut sm: StateMachine<'static, PIO0, 2>) {
|
||||||
sm.set_enable(true);
|
sm.set_enable(true);
|
||||||
loop {
|
loop {
|
||||||
irq.wait().await;
|
irq.wait().await;
|
||||||
|
@ -2,11 +2,14 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
use defmt::info;
|
use defmt::info;
|
||||||
|
use embassy_embedded_hal::SetConfig;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_futures::join::join;
|
use embassy_futures::join::join;
|
||||||
use embassy_rp::pio::{Pio, ShiftDirection};
|
use embassy_rp::pio::{Config, Pio, ShiftConfig, ShiftDirection};
|
||||||
use embassy_rp::relocate::RelocatedProgram;
|
use embassy_rp::relocate::RelocatedProgram;
|
||||||
use embassy_rp::{pio_instr_util, Peripheral};
|
use embassy_rp::Peripheral;
|
||||||
|
use fixed::traits::ToFixed;
|
||||||
|
use fixed_macro::types::U56F8;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
fn swap_nibbles(v: u32) -> u32 {
|
fn swap_nibbles(v: u32) -> u32 {
|
||||||
@ -38,18 +41,21 @@ async fn main(_spawner: Spawner) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let relocated = RelocatedProgram::new(&prg.program);
|
let relocated = RelocatedProgram::new(&prg.program);
|
||||||
common.write_instr(relocated.origin() as usize, relocated.code());
|
let mut cfg = Config::default();
|
||||||
pio_instr_util::exec_jmp(&mut sm, relocated.origin());
|
cfg.use_program(&common.load_program(&relocated), &[]);
|
||||||
sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32);
|
cfg.clock_divider = (U56F8!(125_000_000) / U56F8!(10_000)).to_fixed();
|
||||||
let pio::Wrap { source, target } = relocated.wrap();
|
cfg.shift_in = ShiftConfig {
|
||||||
sm.set_wrap(source, target);
|
auto_fill: true,
|
||||||
sm.set_autopull(true);
|
threshold: 32,
|
||||||
sm.set_autopush(true);
|
direction: ShiftDirection::Left,
|
||||||
sm.set_pull_threshold(32);
|
};
|
||||||
sm.set_push_threshold(32);
|
cfg.shift_out = ShiftConfig {
|
||||||
sm.set_out_shift_dir(ShiftDirection::Right);
|
auto_fill: true,
|
||||||
sm.set_in_shift_dir(ShiftDirection::Left);
|
threshold: 32,
|
||||||
|
direction: ShiftDirection::Right,
|
||||||
|
};
|
||||||
|
|
||||||
|
sm.set_config(&cfg);
|
||||||
sm.set_enable(true);
|
sm.set_enable(true);
|
||||||
|
|
||||||
let mut dma_out_ref = p.DMA_CH0.into_ref();
|
let mut dma_out_ref = p.DMA_CH0.into_ref();
|
||||||
|
@ -4,11 +4,12 @@
|
|||||||
|
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
|
|
||||||
|
use embassy_embedded_hal::SetConfig;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_rp::dma::{AnyChannel, Channel};
|
use embassy_rp::dma::{AnyChannel, Channel};
|
||||||
use embassy_rp::peripherals::PIO0;
|
use embassy_rp::peripherals::PIO0;
|
||||||
use embassy_rp::pio::{FifoJoin, Pio, PioPin, PioStateMachine, ShiftDirection};
|
use embassy_rp::pio::{Config, Direction, FifoJoin, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine};
|
||||||
use embassy_rp::pwm::{Config, Pwm};
|
use embassy_rp::pwm::{self, Pwm};
|
||||||
use embassy_rp::relocate::RelocatedProgram;
|
use embassy_rp::relocate::RelocatedProgram;
|
||||||
use embassy_rp::{into_ref, Peripheral, PeripheralRef};
|
use embassy_rp::{into_ref, Peripheral, PeripheralRef};
|
||||||
use embassy_time::{Duration, Instant, Timer};
|
use embassy_time::{Duration, Instant, Timer};
|
||||||
@ -29,7 +30,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
let p = embassy_rp::init(Default::default());
|
let p = embassy_rp::init(Default::default());
|
||||||
|
|
||||||
let _pwm = Pwm::new_output_b(p.PWM_CH7, p.PIN_15, {
|
let _pwm = Pwm::new_output_b(p.PWM_CH7, p.PIN_15, {
|
||||||
let mut c = Config::default();
|
let mut c = pwm::Config::default();
|
||||||
c.divider = 125.into();
|
c.divider = 125.into();
|
||||||
c.top = 100;
|
c.top = 100;
|
||||||
c.compare_b = 50;
|
c.compare_b = 50;
|
||||||
@ -64,7 +65,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
|
|
||||||
pub struct HD44780<'l> {
|
pub struct HD44780<'l> {
|
||||||
dma: PeripheralRef<'l, AnyChannel>,
|
dma: PeripheralRef<'l, AnyChannel>,
|
||||||
sm: PioStateMachine<'l, PIO0, 0>,
|
sm: StateMachine<'l, PIO0, 0>,
|
||||||
|
|
||||||
buf: [u8; 40],
|
buf: [u8; 40],
|
||||||
}
|
}
|
||||||
@ -83,7 +84,6 @@ impl<'l> HD44780<'l> {
|
|||||||
) -> HD44780<'l> {
|
) -> HD44780<'l> {
|
||||||
into_ref!(dma);
|
into_ref!(dma);
|
||||||
|
|
||||||
let db7pin = db7.pin();
|
|
||||||
let Pio {
|
let Pio {
|
||||||
mut common,
|
mut common,
|
||||||
mut irq0,
|
mut irq0,
|
||||||
@ -95,6 +95,7 @@ impl<'l> HD44780<'l> {
|
|||||||
let prg = pio_proc::pio_asm!(
|
let prg = pio_proc::pio_asm!(
|
||||||
r#"
|
r#"
|
||||||
.side_set 1 opt
|
.side_set 1 opt
|
||||||
|
.origin 20
|
||||||
|
|
||||||
loop:
|
loop:
|
||||||
out x, 24
|
out x, 24
|
||||||
@ -115,27 +116,20 @@ impl<'l> HD44780<'l> {
|
|||||||
let db6 = common.make_pio_pin(db6);
|
let db6 = common.make_pio_pin(db6);
|
||||||
let db7 = common.make_pio_pin(db7);
|
let db7 = common.make_pio_pin(db7);
|
||||||
|
|
||||||
sm0.set_set_pins(&[&rs, &rw]);
|
sm0.set_pin_dirs(Direction::Out, &[&rs, &rw, &e, &db4, &db5, &db6, &db7]);
|
||||||
embassy_rp::pio_instr_util::set_pindir(&mut sm0, 0b11);
|
|
||||||
sm0.set_set_pins(&[&e]);
|
|
||||||
embassy_rp::pio_instr_util::set_pindir(&mut sm0, 0b1);
|
|
||||||
sm0.set_set_pins(&[&db4, &db5, &db6, &db7]);
|
|
||||||
embassy_rp::pio_instr_util::set_pindir(&mut sm0, 0b11111);
|
|
||||||
|
|
||||||
let relocated = RelocatedProgram::new(&prg.program);
|
let relocated = RelocatedProgram::new(&prg.program);
|
||||||
common.write_instr(relocated.origin() as usize, relocated.code());
|
let mut cfg = Config::default();
|
||||||
embassy_rp::pio_instr_util::exec_jmp(&mut sm0, relocated.origin());
|
cfg.use_program(&common.load_program(&relocated), &[&e]);
|
||||||
sm0.set_clkdiv(125 * 256);
|
cfg.clock_divider = 125u8.into();
|
||||||
let pio::Wrap { source, target } = relocated.wrap();
|
cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
|
||||||
sm0.set_wrap(source, target);
|
cfg.shift_out = ShiftConfig {
|
||||||
sm0.set_side_enable(true);
|
auto_fill: true,
|
||||||
sm0.set_out_pins(&[&db4, &db5, &db6, &db7]);
|
direction: ShiftDirection::Left,
|
||||||
sm0.set_sideset_base_pin(&e);
|
threshold: 32,
|
||||||
sm0.set_sideset_count(2);
|
};
|
||||||
sm0.set_out_shift_dir(ShiftDirection::Left);
|
cfg.fifo_join = FifoJoin::TxOnly;
|
||||||
sm0.set_fifo_join(FifoJoin::TxOnly);
|
sm0.set_config(&cfg);
|
||||||
sm0.set_autopull(true);
|
|
||||||
sm0.set_pull_threshold(32);
|
|
||||||
|
|
||||||
sm0.set_enable(true);
|
sm0.set_enable(true);
|
||||||
// init to 8 bit thrice
|
// init to 8 bit thrice
|
||||||
@ -155,7 +149,7 @@ impl<'l> HD44780<'l> {
|
|||||||
// many side sets are only there to free up a delay bit!
|
// many side sets are only there to free up a delay bit!
|
||||||
let prg = pio_proc::pio_asm!(
|
let prg = pio_proc::pio_asm!(
|
||||||
r#"
|
r#"
|
||||||
.origin 7
|
.origin 27
|
||||||
.side_set 1
|
.side_set 1
|
||||||
|
|
||||||
.wrap_target
|
.wrap_target
|
||||||
@ -199,19 +193,15 @@ impl<'l> HD44780<'l> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let relocated = RelocatedProgram::new(&prg.program);
|
let relocated = RelocatedProgram::new(&prg.program);
|
||||||
common.write_instr(relocated.origin() as usize, relocated.code());
|
let mut cfg = Config::default();
|
||||||
embassy_rp::pio_instr_util::exec_jmp(&mut sm0, relocated.origin());
|
cfg.use_program(&common.load_program(&relocated), &[&e]);
|
||||||
let pio::Wrap { source, target } = relocated.wrap();
|
cfg.clock_divider = 8u8.into(); // ~64ns/insn
|
||||||
sm0.set_clkdiv(8 * 256); // ~64ns/insn
|
cfg.set_jmp_pin(&db7);
|
||||||
sm0.set_side_enable(false);
|
cfg.set_set_pins(&[&rs, &rw]);
|
||||||
sm0.set_jmp_pin(db7pin);
|
cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
|
||||||
sm0.set_wrap(source, target);
|
cfg.shift_out.direction = ShiftDirection::Left;
|
||||||
sm0.set_set_pins(&[&rs, &rw]);
|
cfg.fifo_join = FifoJoin::TxOnly;
|
||||||
sm0.set_out_pins(&[&db4, &db5, &db6, &db7]);
|
sm0.set_config(&cfg);
|
||||||
sm0.set_sideset_base_pin(&e);
|
|
||||||
sm0.set_sideset_count(1);
|
|
||||||
sm0.set_out_shift_dir(ShiftDirection::Left);
|
|
||||||
sm0.set_fifo_join(FifoJoin::TxOnly);
|
|
||||||
|
|
||||||
sm0.set_enable(true);
|
sm0.set_enable(true);
|
||||||
|
|
||||||
|
@ -3,19 +3,20 @@
|
|||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
|
use embassy_embedded_hal::SetConfig;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_rp::pio::{FifoJoin, Pio, PioCommon, PioInstance, PioPin, PioStateMachine, ShiftDirection};
|
use embassy_rp::pio::{Common, Config, FifoJoin, Instance, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine};
|
||||||
use embassy_rp::pio_instr_util;
|
|
||||||
use embassy_rp::relocate::RelocatedProgram;
|
use embassy_rp::relocate::RelocatedProgram;
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
|
use fixed_macro::fixed;
|
||||||
use smart_leds::RGB8;
|
use smart_leds::RGB8;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
pub struct Ws2812<'d, P: PioInstance, const S: usize> {
|
pub struct Ws2812<'d, P: Instance, const S: usize> {
|
||||||
sm: PioStateMachine<'d, P, S>,
|
sm: StateMachine<'d, P, S>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, P: PioInstance, const S: usize> Ws2812<'d, P, S> {
|
impl<'d, P: Instance, const S: usize> Ws2812<'d, P, S> {
|
||||||
pub fn new(mut pio: PioCommon<'d, P>, mut sm: PioStateMachine<'d, P, S>, pin: impl PioPin) -> Self {
|
pub fn new(mut pio: Common<'d, P>, mut sm: StateMachine<'d, P, S>, pin: impl PioPin) -> Self {
|
||||||
// Setup sm0
|
// Setup sm0
|
||||||
|
|
||||||
// prepare the PIO program
|
// prepare the PIO program
|
||||||
@ -44,41 +45,30 @@ impl<'d, P: PioInstance, const S: usize> Ws2812<'d, P, S> {
|
|||||||
a.bind(&mut wrap_source);
|
a.bind(&mut wrap_source);
|
||||||
|
|
||||||
let prg = a.assemble_with_wrap(wrap_source, wrap_target);
|
let prg = a.assemble_with_wrap(wrap_source, wrap_target);
|
||||||
|
let mut cfg = Config::default();
|
||||||
let relocated = RelocatedProgram::new(&prg);
|
|
||||||
pio.write_instr(relocated.origin() as usize, relocated.code());
|
|
||||||
pio_instr_util::exec_jmp(&mut sm, relocated.origin());
|
|
||||||
|
|
||||||
// Pin config
|
// Pin config
|
||||||
let out_pin = pio.make_pio_pin(pin);
|
let out_pin = pio.make_pio_pin(pin);
|
||||||
sm.set_set_pins(&[&out_pin]);
|
|
||||||
sm.set_sideset_base_pin(&out_pin);
|
|
||||||
sm.set_sideset_count(1);
|
|
||||||
|
|
||||||
// Clock config
|
let relocated = RelocatedProgram::new(&prg);
|
||||||
|
cfg.use_program(&pio.load_program(&relocated), &[&out_pin]);
|
||||||
|
|
||||||
|
// Clock config, measured in kHz to avoid overflows
|
||||||
// TODO CLOCK_FREQ should come from embassy_rp
|
// TODO CLOCK_FREQ should come from embassy_rp
|
||||||
const CLOCK_FREQ: u32 = 125_000_000;
|
let clock_freq = fixed!(125_000: U24F8);
|
||||||
const WS2812_FREQ: u32 = 800_000;
|
let ws2812_freq = fixed!(800: U24F8);
|
||||||
|
let bit_freq = ws2812_freq * CYCLES_PER_BIT;
|
||||||
let bit_freq = WS2812_FREQ * CYCLES_PER_BIT;
|
cfg.clock_divider = clock_freq / bit_freq;
|
||||||
let mut int = CLOCK_FREQ / bit_freq;
|
|
||||||
let rem = CLOCK_FREQ - (int * bit_freq);
|
|
||||||
let frac = (rem * 256) / bit_freq;
|
|
||||||
// 65536.0 is represented as 0 in the pio's clock divider
|
|
||||||
if int == 65536 {
|
|
||||||
int = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sm.set_clkdiv((int << 8) | frac);
|
|
||||||
let pio::Wrap { source, target } = relocated.wrap();
|
|
||||||
sm.set_wrap(source, target);
|
|
||||||
|
|
||||||
// FIFO config
|
// FIFO config
|
||||||
sm.set_autopull(true);
|
cfg.fifo_join = FifoJoin::TxOnly;
|
||||||
sm.set_fifo_join(FifoJoin::TxOnly);
|
cfg.shift_out = ShiftConfig {
|
||||||
sm.set_pull_threshold(24);
|
auto_fill: true,
|
||||||
sm.set_out_shift_dir(ShiftDirection::Left);
|
threshold: 24,
|
||||||
|
direction: ShiftDirection::Left,
|
||||||
|
};
|
||||||
|
|
||||||
|
sm.set_config(&cfg);
|
||||||
sm.set_enable(true);
|
sm.set_enable(true);
|
||||||
|
|
||||||
Self { sm }
|
Self { sm }
|
||||||
|
Loading…
Reference in New Issue
Block a user