diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-06-29 03:26:50 -0600 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-07-03 08:07:29 -0600 |
commit | 918a80577c2f28ac88b10b199d4c799343e91434 (patch) | |
tree | 26e35ff803fd2d2e9f484addcc8e67b25020bee1 /libhw_cr | |
parent | 1d5a211e1ae3645e9c13163b76fea0a3c87f46f1 (diff) |
wip pio spilukeshu/pio-spi
Diffstat (limited to 'libhw_cr')
-rw-r--r-- | libhw_cr/rp2040_piospi.c | 54 | ||||
-rw-r--r-- | libhw_cr/rp2040_piospi.pio | 41 |
2 files changed, 95 insertions, 0 deletions
diff --git a/libhw_cr/rp2040_piospi.c b/libhw_cr/rp2040_piospi.c new file mode 100644 index 0000000..8bd34fb --- /dev/null +++ b/libhw_cr/rp2040_piospi.c @@ -0,0 +1,54 @@ +/* libhw_cr/rp2040_piospi.c - <libhw/generic/spi.h> implementation for the RP2040's PIO + * + * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +void _rp2040_piospi_init(struct rp2040_piospi *self, + enum spi_mode mode, + uint baudrate_hz, + uint64_t min_delay_ns, + uint8_t bogus_data, + uint pin_miso, + uint pin_mosi, + uint pin_clk, + uint pin_cs, + uint dma1, + uint dma2, + uint dma3, + uint dma4) { + x +} + +/** + * At a maximum rate of sys_clk/4 bps. + * + */ + +/** + * + * 2^32 b = 512 MiB + */ +size_t_and_error rp2040_piospi_readwritev(struct rp2040_piospi *self, const struct duplex_iovec *iov, int iovcnt) { + assert(self); + assert(iov); + assert(iovcnt > 0); + + /* - The .pio file transfers data at a rate of 1/4 bit/cycle. + * + * - Even at the slow DMA_SIZE_8 (which allows us to not have + * to worry about alignment) goes at 8 bit/cycle; plenty + * fast. + * - If the PIO push/pull-size is 32 bits, then that gives us + * 32 cycles for DMA changeovers; plenty of time for + * separate ctrl and data channel changeovers (we don't + * need the complexity of toggling between 2 data channels + * for instaneous changeovers). + */ + + [[gnu::cleanup(heap_cleanup)]] struct dma_alias1 *tx_data_blocks = heap_alloc(pruned_iovcnt+1, struct dma_alias1); + [[gnu::cleanup(heap_cleanup)]] struct dma_alias0 *rx_data_blocks = heap_alloc(pruned_iovcnt+1, struct dma_alias0); + static_assert(!DMA_IS_TRIGGER(typeof(tx_data_blocks[0]), ctrl)); + static_assert(DMA_IS_TRIGGER(typeof(rx_data_blocks[0]), ctrl)); + +} diff --git a/libhw_cr/rp2040_piospi.pio b/libhw_cr/rp2040_piospi.pio new file mode 100644 index 0000000..6307c9b --- /dev/null +++ b/libhw_cr/rp2040_piospi.pio @@ -0,0 +1,41 @@ +;;; libhw_cr/rp2040_piospi.pio - <libhw/generic/spi.h> implementation for the RP2040's PIO +;;; +;;; Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> +;;; SPDX-License-Identifier: AGPL-3.0-or-later + +;;; First read a u32 bit-count, then transfer that many bits (full-duplex). +;;; +;;; Pin assignments: +;;; - MOSI ; OUT pin 0 +;;; - MISO ; IN pin 0 +;;; - CLK ; SIDE pin 0 +;;; - CS ; SIDE pin 1 (low active, high idle)) + +;;; This is all written as if clk_polarity=0 (idle low); if that is +;;; not the case, then the clk pin can be flipped in the GPIO mux. + +;;; clk_phase=0 (sample on clock transition-to-active; written as "rise" here) +;;; shift on CS fall and clock fall +.program rp2040_piospi_mode0 +.side_set 2 +idle: + pull side 0b10 ; osr=(32 bits) cs=high clk=low + mov x osr side 0b10 ; x=osr cs=high clk=low +active: + ;; 2 cycles low, 2 cycles high + out pins 1 side 0b00 [1] ; mosi=(1 bit) cs=low clk=low [wait=1] ; CS fall/clock fall = shift + in pins 1 side 0b01 ; miso=(1 bit) cs=low clk=high ; clock rise = sample + jmp x-- active side 0b01 ; cs=low clk=high + +;;; clk_phase=1 (sample on transition-to-idle +;;; shift on clock rise +.program rp2040_piospi_mode0 +.side_set 2 +idle: + pull side 0b10 ; osr=(32 bits) cs=high clk=low + mov x osr side 0b10 ; x=osr cs=high clk=low +active: + ;; 2 cycles high, 2 cycles low + out pins 1 side 0b01 [1] ; mosi=(1 bit) cs=low clk=high [wait=1] ; clock rise = shift + in pins 1 side 0b00 ; miso=(1 bit) cs=low clk=low ; clock fall = sample + jmp x-- active side 0b00 ; cs=low clk=low |