use crate::pio::{
Common, Config, Direction, FifoJoin, Instance, Irq, LoadedProgram, PioPin, ShiftConfig, ShiftDirection,
StateMachine,
};
use crate::pio_programs::clock_divider::calculate_pio_clock_divider;
use crate::{Peri, dma, interrupt};
pub struct PioHD44780CommandWordProgram<'a, PIO: Instance> {
prg: LoadedProgram<'a, PIO>,
}
impl<'a, PIO: Instance> PioHD44780CommandWordProgram<'a, PIO> {
pub fn new(common: &mut Common<'a, PIO>) -> Self {
let prg = pio::pio_asm!(
r#"
.side_set 1 opt
.origin 20
loop:
out x, 24
delay:
jmp x--, delay
out pins, 4 side 1
out null, 4 side 0
jmp !osre, loop
irq 0
"#,
);
let prg = common.load_program(&prg.program);
Self { prg }
}
}
pub struct PioHD44780CommandSequenceProgram<'a, PIO: Instance> {
prg: LoadedProgram<'a, PIO>,
}
impl<'a, PIO: Instance> PioHD44780CommandSequenceProgram<'a, PIO> {
pub fn new(common: &mut Common<'a, PIO>) -> Self {
let prg = pio::pio_asm!(
r#"
.origin 27
.side_set 1
.wrap_target
pull side 0
out x 1 side 0 ; !rs
out y 7 side 0 ; #data - 1
; rs/rw to e: >= 60ns
; e high time: >= 500ns
; e low time: >= 500ns
; read data valid after e falling: ~5ns
; write data hold after e falling: ~10ns
loop:
pull side 0
jmp !x data side 0
command:
set pins 0b00 side 0
jmp shift side 0
data:
set pins 0b01 side 0
shift:
out pins 4 side 1 [9]
nop side 0 [9]
out pins 4 side 1 [9]
mov osr null side 0 [7]
out pindirs 4 side 0
set pins 0b10 side 0
busy:
nop side 1 [9]
jmp pin more side 0 [9]
mov osr ~osr side 1 [9]
nop side 0 [4]
out pindirs 4 side 0
jmp y-- loop side 0
.wrap
more:
nop side 1 [9]
jmp busy side 0 [9]
"#
);
let prg = common.load_program(&prg.program);
Self { prg }
}
}
pub struct PioHD44780<'l, P: Instance, const S: usize> {
dma: dma::Channel<'l>,
sm: StateMachine<'l, P, S>,
buf: [u8; 40],
}
impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> {
pub async fn new<D: dma::ChannelInstance>(
common: &mut Common<'l, P>,
mut sm: StateMachine<'l, P, S>,
mut irq: Irq<'l, P, S>,
dma: Peri<'l, D>,
dma_irq: impl interrupt::typelevel::Binding<D::Interrupt, dma::InterruptHandler<D>> + 'l,
rs: Peri<'l, impl PioPin>,
rw: Peri<'l, impl PioPin>,
e: Peri<'l, impl PioPin>,
db4: Peri<'l, impl PioPin>,
db5: Peri<'l, impl PioPin>,
db6: Peri<'l, impl PioPin>,
db7: Peri<'l, impl PioPin>,
word_prg: &PioHD44780CommandWordProgram<'l, P>,
seq_prg: &PioHD44780CommandSequenceProgram<'l, P>,
) -> PioHD44780<'l, P, S> {
let mut dma_ch = dma::Channel::new(dma, dma_irq);
let rs = common.make_pio_pin(rs);
let rw = common.make_pio_pin(rw);
let e = common.make_pio_pin(e);
let db4 = common.make_pio_pin(db4);
let db5 = common.make_pio_pin(db5);
let db6 = common.make_pio_pin(db6);
let db7 = common.make_pio_pin(db7);
sm.set_pin_dirs(Direction::Out, &[&rs, &rw, &e, &db4, &db5, &db6, &db7]);
let mut cfg = Config::default();
cfg.use_program(&word_prg.prg, &[&e]);
cfg.clock_divider = calculate_pio_clock_divider(1_000_000);
cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
cfg.shift_out = ShiftConfig {
auto_fill: true,
direction: ShiftDirection::Left,
threshold: 32,
};
cfg.fifo_join = FifoJoin::TxOnly;
sm.set_config(&cfg);
sm.set_enable(true);
sm.tx().push((50000 << 8) | 0x30);
sm.tx().push((5000 << 8) | 0x30);
sm.tx().push((200 << 8) | 0x30);
sm.tx().push((200 << 8) | 0x20);
sm.tx().push((50 << 8) | 0x20);
sm.tx().push(0b1100_0000);
irq.wait().await;
sm.set_enable(false);
let mut cfg = Config::default();
cfg.use_program(&seq_prg.prg, &[&e]);
cfg.clock_divider = calculate_pio_clock_divider(15_600_000);
cfg.set_jmp_pin(&db7);
cfg.set_set_pins(&[&rs, &rw]);
cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
cfg.shift_out.direction = ShiftDirection::Left;
cfg.fifo_join = FifoJoin::TxOnly;
sm.set_config(&cfg);
sm.set_enable(true);
sm.tx().dma_push(&mut dma_ch, &[0x81u8, 0x0f, 1], false).await;
Self {
dma: dma_ch,
sm,
buf: [0x20; 40],
}
}
pub async fn add_line(&mut self, s: &[u8]) {
self.buf[..3].copy_from_slice(&[0x80, 0x80, 15]);
self.buf.copy_within(22..38, 3);
self.buf[19..22].copy_from_slice(&[0x80, 0xc0, 15]);
self.buf[22..38].fill(0x20);
let len = s.len().min(16);
self.buf[22..22 + len].copy_from_slice(&s[0..len]);
self.buf[38..].copy_from_slice(&[0x80, 0xcf]);
self.sm.tx().dma_push(&mut self.dma, &self.buf, false).await;
}
}