rp2040/
pio.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright OxidOS Automotive 2024.
4//
5// Author: Radu Matei <radu.matei.05.21@gmail.com>
6//         Alberto Udrea <albertoudrea4@gmail.com>
7
8//! Programmable Input Output (PIO) hardware.
9//! Refer to the RP2040 Datasheet, Section 3 for more information.
10//! RP2040 Datasheet [1].
11//!
12//! [1]: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf
13
14use core::cell::Cell;
15
16use kernel::utilities::cells::OptionalCell;
17use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
18use kernel::utilities::registers::{register_bitfields, register_structs, ReadOnly, ReadWrite};
19use kernel::utilities::StaticRef;
20use kernel::{debug, ErrorCode};
21
22use crate::gpio::{GpioFunction, RPGpio, RPGpioPin};
23
24const NUMBER_STATE_MACHINES: usize = 4;
25const NUMBER_INSTR_MEMORY_LOCATIONS: usize = 32;
26
27#[repr(C)]
28struct InstrMem {
29    // Write-only access to instruction memory locations 0-31
30    instr_mem: ReadWrite<u32, INSTR_MEMx::Register>,
31}
32
33#[repr(C)]
34struct StateMachineReg {
35    // Clock divisor register for state machine x
36    // Frequency = clock freq / (CLKDIV_INT + CLKDIV_FRAC / 256)
37    clkdiv: ReadWrite<u32, SMx_CLKDIV::Register>,
38    // Execution/behavioural settings for state machine x
39    execctrl: ReadWrite<u32, SMx_EXECCTRL::Register>,
40    // Control behaviour of the input/output shift registers for
41    // state machine x
42    shiftctrl: ReadWrite<u32, SMx_SHIFTCTRL::Register>,
43    // Current instruction address of state machine x
44    addr: ReadOnly<u32, SMx_ADDR::Register>,
45    // Read to see the instruction currently addressed by state
46    // machine x’s program counter Write to execute an instruction
47    // immediately (including jumps) and then resume execution.
48    instr: ReadWrite<u32, SMx_INSTR::Register>,
49    // State machine pin control
50    pinctrl: ReadWrite<u32, SMx_PINCTRL::Register>,
51}
52
53register_structs! {
54PioRegisters {
55        // PIO control register
56        (0x000 => ctrl: ReadWrite<u32, CTRL::Register>),
57        // FIFO status register
58        (0x004 => fstat: ReadOnly<u32, FSTAT::Register>),
59        // FIFO debug register
60        (0x008 => fdebug: ReadWrite<u32, FDEBUG::Register>),
61        // FIFO levels
62        (0x00C => flevel: ReadOnly<u32, FLEVEL::Register>),
63        // Direct write access to the TX FIFO for this state machine. Each
64        // write pushes one word to the FIFO. Attempting to write to a full
65        // FIFO has no effect on the FIFO state or contents, and sets the
66        // sticky FDEBUG_TXOVER error flag for this FIFO.
67        (0x010 => txf: [ReadWrite<u32, TXFx::Register>; 4]),
68        // Direct read access to the RX FIFO for this state machine. Each
69        // read pops one word from the FIFO. Attempting to read from an empty
70        // FIFO has no effect on the FIFO state, and sets the sticky
71        // FDEBUG_RXUNDER error flag for this FIFO. The data returned
72        // to the system on a read from an empty FIFO is undefined.
73        (0x020 => rxf: [ReadOnly<u32, RXFx::Register>; 4]),
74        // State machine IRQ flags register. Write 1 to clear. There are 8
75        // state machine IRQ flags, which can be set, cleared, and waited on
76        // by the state machines. There’s no fixed association between
77        // flags and state machines — any state machine can use any flag.
78        // Any of the 8 flags can be used for timing synchronisation
79        // between state machines, using IRQ and WAIT instructions. The
80        // lower four of these flags are also routed out to system-level
81        // interrupt requests, alongside FIFO status interrupts —
82        // see e.g. IRQ0_INTE.
83        (0x030 => irq: ReadWrite<u32, IRQ::Register>),
84        // Writing a 1 to each of these bits will forcibly assert the
85        // corresponding IRQ. Note this is different to the INTF register:
86        // writing here affects PIO internal state. INTF just asserts the
87        // processor-facing IRQ signal for testing ISRs, and is not visible to
88        // the state machines.
89        (0x034 => irq_force: ReadWrite<u32, IRQ_FORCE::Register>),
90        // There is a 2-flipflop synchronizer on each GPIO input, which
91        // protects PIO logic from metastabilities. This increases input
92        // delay, and for fast synchronous IO (e.g. SPI) these synchronizers
93        // may need to be bypassed. Each bit in this register corresponds
94        // to one GPIO.
95        // 0 → input is synchronized (default)
96        // 1 → synchronizer is bypassed
97        // If in doubt, leave this register as all zeroes.
98        (0x038 => input_sync_bypass: ReadWrite<u32, INPUT_SYNC_BYPASS::Register>),
99        // Read to sample the pad output values PIO is currently driving
100        // to the GPIOs.
101        (0x03C => dbg_padout: ReadOnly<u32, DBG_PADOUT::Register>),
102        // Read to sample the pad output enables (direction) PIO is
103        // currently driving to the GPIOs. On RP2040 there are 30 GPIOs,
104        // so the two most significant bits are hardwired to 0.
105        (0x040 => dbg_padoe: ReadOnly<u32, DBG_PADOE::Register>),
106        // The PIO hardware has some free parameters that may vary
107        // between chip products.
108        (0x044 => dbg_cfginfo: ReadOnly<u32, DBG_CFGINFO::Register>),
109        // Write-only access to instruction memory locations 0-31
110        (0x048 => instr_mem: [InstrMem; NUMBER_INSTR_MEMORY_LOCATIONS]),
111        // State Machines
112        (0x0c8 => sm: [StateMachineReg; NUMBER_STATE_MACHINES]),
113        // Raw Interrupts
114        (0x128 => intr: ReadWrite<u32, INTR::Register>),
115        // Interrupt Enable for irq0
116        (0x12C => irq0_inte: ReadWrite<u32, IRQ0_INTE::Register>),
117        // Interrupt Force for irq0
118        (0x130 => irq0_intf: ReadWrite<u32, IRQ0_INTF::Register>),
119        // Interrupt status after masking & forcing for irq0
120        (0x134 => irq0_ints: ReadWrite<u32, IRQ0_INTS::Register>),
121        // Interrupt Enable for irq1
122        (0x138 => irq1_inte: ReadWrite<u32, IRQ1_INTE::Register>),
123        // Interrupt Force for irq1
124        (0x13C => irq1_intf: ReadWrite<u32, IRQ1_INTF::Register>),
125        // Interrupt status after masking & forcing for irq1
126        (0x140 => irq1_ints: ReadWrite<u32, IRQ1_INTS::Register>),
127        (0x144 => @END),
128    }
129}
130
131register_bitfields![u32,
132CTRL [
133    // Restart a state machine’s clock divider from an initial
134    // phase of 0. Clock dividers are free-running, so once
135    // started, their output (including fractional jitter) is
136    // completely determined by the integer/fractional divisor
137    // configured in SMx_CLKDIV. This means that, if multiple
138    // clock dividers with the same divisor are restarted
139    // simultaneously, by writing multiple 1 bits to this field, the
140    // execution clocks of those state machines will run in
141    // precise lockstep.
142    // - SM_ENABLE does not stop the clock divider from running
143    // - CLKDIV_RESTART can be written to whilst the state machine is running
144    CLKDIV3_RESTART OFFSET(11) NUMBITS(1) [],
145    CLKDIV2_RESTART OFFSET(10) NUMBITS(1) [],
146    CLKDIV1_RESTART OFFSET(9) NUMBITS(1) [],
147    CLKDIV0_RESTART OFFSET(8) NUMBITS(1) [],
148    // Write 1 to instantly clear internal SM state which may be
149    // otherwise difficult to access and will affect future
150    // execution.
151    // Specifically, the following are cleared: input and output
152    // shift counters; the contents of the input shift register; the
153    // delay counter; the waiting-on-IRQ state; any stalled
154    // instruction written to SMx_INSTR or run by OUT/MOV
155    // EXEC; any pin write left asserted due to OUT_STICKY.
156    SM3_RESTART OFFSET(7) NUMBITS(1) [],
157    SM2_RESTART OFFSET(6) NUMBITS(1) [],
158    SM1_RESTART OFFSET(5) NUMBITS(1) [],
159    SM0_RESTART OFFSET(4) NUMBITS(1) [],
160    // Enable/disable each of the four state machines by writing
161    // 1/0 to each of these four bits. When disabled, a state
162    // machine will cease executing instructions, except those
163    // written directly to SMx_INSTR by the system. Multiple bits
164    // can be set/cleared at once to run/halt multiple state
165    // machines simultaneously.
166    SM3_ENABLE OFFSET(3) NUMBITS(1) [],
167    SM2_ENABLE OFFSET(2) NUMBITS(1) [],
168    SM1_ENABLE OFFSET(1) NUMBITS(1) [],
169    SM0_ENABLE OFFSET(0) NUMBITS(1) [],
170],
171FSTAT [
172    // State machine TX FIFO is empty
173    TXEMPTY3 OFFSET(27) NUMBITS(1) [],
174    TXEMPTY2 OFFSET(26) NUMBITS(1) [],
175    TXEMPTY1 OFFSET(25) NUMBITS(1) [],
176    TXEMPTY0 OFFSET(24) NUMBITS(1) [],
177    // State machine TX FIFO is full
178    TXFULL3 OFFSET(19) NUMBITS(1) [],
179    TXFULL2 OFFSET(18) NUMBITS(1) [],
180    TXFULL1 OFFSET(17) NUMBITS(1) [],
181    TXFULL0 OFFSET(16) NUMBITS(1) [],
182    // State machine RX FIFO is empty
183    RXEMPTY3 OFFSET(11) NUMBITS(1) [],
184    RXEMPTY2 OFFSET(10) NUMBITS(1) [],
185    RXEMPTY1 OFFSET(9) NUMBITS(1) [],
186    RXEMPTY0 OFFSET(8) NUMBITS(1) [],
187    // State machine RX FIFO is full
188    RXFULL3 OFFSET(3) NUMBITS(1) [],
189    RXFULL2 OFFSET(2) NUMBITS(1) [],
190    RXFULL1 OFFSET(1) NUMBITS(1) [],
191    RXFULL0 OFFSET(0) NUMBITS(1) []
192],
193FDEBUG [
194    // State machine has stalled on empty TX FIFO during a
195    // blocking PULL, or an OUT with autopull enabled. Write 1 to
196    // clear.
197    TXSTALL OFFSET(24) NUMBITS(4) [],
198    // TX FIFO overflow (i.e. write-on-full by the system) has
199    // occurred. Write 1 to clear. Note that write-on-full does not
200    // alter the state or contents of the FIFO in any way, but the
201    // data that the system attempted to write is dropped, so if
202    // this flag is set, your software has quite likely dropped
203    // some data on the floor.
204    TXOVER OFFSET(16) NUMBITS(4) [],
205    // RX FIFO underflow (i.e. read-on-empty by the system) has
206    // occurred. Write 1 to clear. Note that read-on-empty does
207    // not perturb the state of the FIFO in any way, but the data
208    // returned by reading from an empty FIFO is undefined, so
209    // this flag generally only becomes set due to some kind of
210    // software error.
211    RXUNDER OFFSET(8) NUMBITS(4) [],
212    // State machine has stalled on full RX FIFO during a
213    // blocking PUSH, or an IN with autopush enabled. This flag
214    // is also set when a nonblocking PUSH to a full FIFO took
215    // place, in which case the state machine has dropped data.
216    // Write 1 to clear.
217    RXSTALL OFFSET(0) NUMBITS(4) []
218],
219FLEVEL [
220    RX3 OFFSET(28) NUMBITS(4) [],
221    TX3 OFFSET(24) NUMBITS(4) [],
222    RX2 OFFSET(20) NUMBITS(4) [],
223    TX2 OFFSET(16) NUMBITS(4) [],
224    RX1 OFFSET(12) NUMBITS(4) [],
225    TX1 OFFSET(8) NUMBITS(4) [],
226    RX0 OFFSET(4) NUMBITS(4) [],
227    TX0 OFFSET(0) NUMBITS(4) []
228],
229TXFx [
230    TXF OFFSET(0) NUMBITS(32) []
231],
232RXFx [
233    RXF OFFSET(0) NUMBITS(32) []
234],
235IRQ [
236    IRQ7 OFFSET(7) NUMBITS(1) [],
237    IRQ6 OFFSET(6) NUMBITS(1) [],
238    IRQ5 OFFSET(5) NUMBITS(1) [],
239    IRQ4 OFFSET(4) NUMBITS(1) [],
240    IRQ3 OFFSET(3) NUMBITS(1) [],
241    IRQ2 OFFSET(2) NUMBITS(1) [],
242    IRQ1 OFFSET(1) NUMBITS(1) [],
243    IRQ0 OFFSET(0) NUMBITS(1) []
244],
245IRQ_FORCE [
246    IRQ_FORCE OFFSET(0) NUMBITS(8) []
247],
248INPUT_SYNC_BYPASS [
249    INPUT_SYNC_BYPASS OFFSET(0) NUMBITS(32) []
250],
251DBG_PADOUT [
252    DBG_PADOUT OFFSET(0) NUMBITS(32) []
253],
254DBG_PADOE [
255    DBG_PADOE OFFSET(0) NUMBITS(32) []
256],
257DBG_CFGINFO [
258    // The size of the instruction memory, measured in units of
259    // one instruction
260    IMEM_SIZE OFFSET(16) NUMBITS(6) [],
261    // The number of state machines this PIO instance is
262    // equipped with.
263    SM_COUNT OFFSET(8) NUMBITS(4) [],
264    // The depth of the state machine TX/RX FIFOs, measured in
265    // words.
266    FIFO_DEPTH OFFSET(0) NUMBITS(6) []
267],
268INSTR_MEMx [
269    // Write-only access to instruction memory location x
270    INSTR_MEM OFFSET(0) NUMBITS(16) []
271],
272SMx_CLKDIV [
273    // Effective frequency is sysclk/(int + frac/256).
274    // Value of 0 is interpreted as 65536. If INT is 0, FRAC must
275    // also be 0.
276    INT OFFSET(16) NUMBITS(16) [],
277    // Fractional part of clock divisor
278    FRAC OFFSET(8) NUMBITS(8) []
279],
280SMx_EXECCTRL [
281    // If 1, an instruction written to SMx_INSTR is stalled, and
282    // latched by the state machine. Will clear to 0 once this
283    // instruction completes.
284    EXEC_STALLED OFFSET(31) NUMBITS(1) [],
285    // If 1, the MSB of the Delay/Side-set instruction field is used
286    // as side-set enable, rather than a side-set data bit. This
287    // allows instructions to perform side-set optionally, rather
288    // than on every instruction, but the maximum possible side-
289    // set width is reduced from 5 to 4. Note that the value of
290    // PINCTRL_SIDESET_COUNT is inclusive of this enable bit.
291    SIDE_EN OFFSET(30) NUMBITS(1) [],
292    // If 1, side-set data is asserted to pin directions, instead of
293    // pin values
294    SIDE_PINDIR OFFSET(29) NUMBITS(1) [],
295    // The GPIO number to use as condition for JMP PIN.
296    // Unaffected by input mapping.
297    JMP_PIN OFFSET(24) NUMBITS(5) [],
298    // Which data bit to use for inline OUT enable
299    OUT_EN_SEL OFFSET(19) NUMBITS(5) [],
300    // If 1, use a bit of OUT data as an auxiliary write enable
301    // When used in conjunction with OUT_STICKY, writes with
302    // an enable of 0 will
303    // deassert the latest pin write. This can create useful
304    // masking/override behaviour
305    // due to the priority ordering of state machine pin writes
306    // (SM0 < SM1 < …)
307    INLINE_OUT_EN OFFSET(18) NUMBITS(1) [],
308    // Continuously assert the most recent OUT/SET to the pins
309    OUT_STICKY OFFSET(17) NUMBITS(1) [],
310    // After reaching this address, execution is wrapped to
311    // wrap_bottom.
312    // If the instruction is a jump, and the jump condition is true,
313    // the jump takes priority.
314    WRAP_TOP OFFSET(12) NUMBITS(5) [],
315    // After reaching wrap_top, execution is wrapped to this
316    // address.
317    WRAP_BOTTOM OFFSET(7) NUMBITS(5) [],
318    STATUS_SEL OFFSET(4) NUMBITS(1) [],
319    // Comparison level for the MOV x, STATUS instruction
320    STATUS_N OFFSET(0) NUMBITS(4) []
321],
322SMx_SHIFTCTRL [
323    // When 1, RX FIFO steals the TX FIFO’s storage, and
324    // becomes twice as deep.
325    // TX FIFO is disabled as a result (always reads as both full
326    // and empty).
327    // FIFOs are flushed when this bit is changed.
328    FJOIN_RX OFFSET(31) NUMBITS(1) [],
329    // When 1, TX FIFO steals the RX FIFO’s storage, and
330    // becomes twice as deep.
331    // RX FIFO is disabled as a result (always reads as both full
332    // and empty).
333    // FIFOs are flushed when this bit is changed.
334    FJOIN_TX OFFSET(30) NUMBITS(1) [],
335    // Number of bits shifted out of OSR before autopull, or
336    // conditional pull (PULL IFEMPTY), will take place.
337    // Write 0 for value of 32.
338    PULL_THRESH OFFSET(25) NUMBITS(5) [],
339    // Number of bits shifted into ISR before autopush, or
340    // conditional push (PUSH IFFULL), will take place.
341    // Write 0 for value of 32
342    PUSH_THRESH OFFSET(20) NUMBITS(5) [],
343    OUT_SHIFTDIR OFFSET(19) NUMBITS(1) [
344        ShiftRight = 1,
345        ShiftLeft = 0
346    ],
347    IN_SHIFTDIR OFFSET(18) NUMBITS(1) [
348        ShiftRight = 1,
349        ShiftLeft = 0
350    ],
351    // Pull automatically when the output shift register is
352    // emptied, i.e. on or following an OUT instruction which
353    // causes the output shift counter to reach or exceed
354    // PULL_THRESH.
355    AUTOPULL OFFSET(17) NUMBITS(1) [],
356    // Push automatically when the input shift register is filled,
357    // i.e. on an IN instruction which causes the input shift
358    // counter to reach or exceed PUSH_THRESH.
359    AUTOPUSH OFFSET(16) NUMBITS(1) []
360],
361SMx_ADDR [
362    ADDR OFFSET(0) NUMBITS(5) []
363],
364SMx_INSTR [
365    INSTR OFFSET(0) NUMBITS(16) []
366],
367SMx_PINCTRL [
368    // The number of MSBs of the Delay/Side-set instruction
369    // field which are used for side-set. Inclusive of the enable
370    // bit, if present. Minimum of 0 (all delay bits, no side-set)
371    // and maximum of 5 (all side-set, no delay).
372    SIDESET_COUNT OFFSET(29) NUMBITS(3) [],
373    // The number of pins asserted by a SET. In the range 0 to 5
374    // inclusive.
375    SET_COUNT OFFSET(26) NUMBITS(3) [],
376    // The number of pins asserted by an OUT PINS, OUT
377    // PINDIRS or MOV PINS instruction. In the range 0 to 32
378    // inclusive.
379    OUT_COUNT OFFSET(20) NUMBITS(6) [],
380    // The pin which is mapped to the least-significant bit of a
381    // state machine’s IN data bus. Higher-numbered pins are
382    // mapped to consecutively more-significant data bits, with a
383    // modulo of 32 applied to pin number.
384    IN_BASE OFFSET(15) NUMBITS(5) [],
385    // The lowest-numbered pin that will be affected by a side-
386    // set operation. The MSBs of an instruction’s side-set/delay
387    // field (up to 5, determined by SIDESET_COUNT) are used
388    // for side-set data, with the remaining LSBs used for delay.
389    // The least-significant bit of the side-set portion is the bit
390    // written to this pin, with more-significant bits written to
391    // higher-numbered pins.
392    SIDESET_BASE OFFSET(10) NUMBITS(5) [],
393    // The lowest-numbered pin that will be affected by a SET
394    // PINS or SET PINDIRS instruction. The data written to this
395    // pin is the least-significant bit of the SET data.
396    SET_BASE OFFSET(5) NUMBITS(5) [],
397    // The lowest-numbered pin that will be affected by an OUT
398    // PINS, OUT PINDIRS or MOV PINS instruction. The data
399    // written to this pin will always be the least-significant bit of
400    // the OUT or MOV data.
401    OUT_BASE OFFSET(0) NUMBITS(5) []
402],
403INTR [
404    SM3 OFFSET(11) NUMBITS(1) [],
405    SM2 OFFSET(10) NUMBITS(1) [],
406    SM1 OFFSET(9) NUMBITS(1) [],
407    SM0 OFFSET(8) NUMBITS(1) [],
408    SM3_TXNFULL OFFSET(7) NUMBITS(1) [],
409    SM2_TXNFULL OFFSET(6) NUMBITS(1) [],
410    SM1_TXNFULL OFFSET(5) NUMBITS(1) [],
411    SM0_TXNFULL OFFSET(4) NUMBITS(1) [],
412    SM3_RXNEMPTY OFFSET(3) NUMBITS(1) [],
413    SM2_RXNEMPTY OFFSET(2) NUMBITS(1) [],
414    SM1_RXNEMPTY OFFSET(1) NUMBITS(1) [],
415    SM0_RXNEMPTY OFFSET(0) NUMBITS(1) []
416],
417IRQ0_INTE [
418    SM3 OFFSET(11) NUMBITS(1) [],
419    SM2 OFFSET(10) NUMBITS(1) [],
420    SM1 OFFSET(9) NUMBITS(1) [],
421    SM0 OFFSET(8) NUMBITS(1) [],
422    SM3_TXNFULL OFFSET(7) NUMBITS(1) [],
423    SM2_TXNFULL OFFSET(6) NUMBITS(1) [],
424    SM1_TXNFULL OFFSET(5) NUMBITS(1) [],
425    SM0_TXNFULL OFFSET(4) NUMBITS(1) [],
426    SM3_RXNEMPTY OFFSET(3) NUMBITS(1) [],
427    SM2_RXNEMPTY OFFSET(2) NUMBITS(1) [],
428    SM1_RXNEMPTY OFFSET(1) NUMBITS(1) [],
429    SM0_RXNEMPTY OFFSET(0) NUMBITS(1) []
430],
431IRQ0_INTF [
432    SM3 OFFSET(11) NUMBITS(1) [],
433    SM2 OFFSET(10) NUMBITS(1) [],
434    SM1 OFFSET(9) NUMBITS(1) [],
435    SM0 OFFSET(8) NUMBITS(1) [],
436    SM3_TXNFULL OFFSET(7) NUMBITS(1) [],
437    SM2_TXNFULL OFFSET(6) NUMBITS(1) [],
438    SM1_TXNFULL OFFSET(5) NUMBITS(1) [],
439    SM0_TXNFULL OFFSET(4) NUMBITS(1) [],
440    SM3_RXNEMPTY OFFSET(3) NUMBITS(1) [],
441    SM2_RXNEMPTY OFFSET(2) NUMBITS(1) [],
442    SM1_RXNEMPTY OFFSET(1) NUMBITS(1) [],
443    SM0_RXNEMPTY OFFSET(0) NUMBITS(1) []
444],
445IRQ0_INTS [
446    SM3 OFFSET(11) NUMBITS(1) [],
447    SM2 OFFSET(10) NUMBITS(1) [],
448    SM1 OFFSET(9) NUMBITS(1) [],
449    SM0 OFFSET(8) NUMBITS(1) [],
450    SM3_TXNFULL OFFSET(7) NUMBITS(1) [],
451    SM2_TXNFULL OFFSET(6) NUMBITS(1) [],
452    SM1_TXNFULL OFFSET(5) NUMBITS(1) [],
453    SM0_TXNFULL OFFSET(4) NUMBITS(1) [],
454    SM3_RXNEMPTY OFFSET(3) NUMBITS(1) [],
455    SM2_RXNEMPTY OFFSET(2) NUMBITS(1) [],
456    SM1_RXNEMPTY OFFSET(1) NUMBITS(1) [],
457    SM0_RXNEMPTY OFFSET(0) NUMBITS(1) []
458],
459IRQ1_INTE [
460    SM3 OFFSET(11) NUMBITS(1) [],
461    SM2 OFFSET(10) NUMBITS(1) [],
462    SM1 OFFSET(9) NUMBITS(1) [],
463    SM0 OFFSET(8) NUMBITS(1) [],
464    SM3_TXNFULL OFFSET(7) NUMBITS(1) [],
465    SM2_TXNFULL OFFSET(6) NUMBITS(1) [],
466    SM1_TXNFULL OFFSET(5) NUMBITS(1) [],
467    SM0_TXNFULL OFFSET(4) NUMBITS(1) [],
468    SM3_RXNEMPTY OFFSET(3) NUMBITS(1) [],
469    SM2_RXNEMPTY OFFSET(2) NUMBITS(1) [],
470    SM1_RXNEMPTY OFFSET(1) NUMBITS(1) [],
471    SM0_RXNEMPTY OFFSET(0) NUMBITS(1) []
472],
473IRQ1_INTF [
474    SM3 OFFSET(11) NUMBITS(1) [],
475    SM2 OFFSET(10) NUMBITS(1) [],
476    SM1 OFFSET(9) NUMBITS(1) [],
477    SM0 OFFSET(8) NUMBITS(1) [],
478    SM3_TXNFULL OFFSET(7) NUMBITS(1) [],
479    SM2_TXNFULL OFFSET(6) NUMBITS(1) [],
480    SM1_TXNFULL OFFSET(5) NUMBITS(1) [],
481    SM0_TXNFULL OFFSET(4) NUMBITS(1) [],
482    SM3_RXNEMPTY OFFSET(3) NUMBITS(1) [],
483    SM2_RXNEMPTY OFFSET(2) NUMBITS(1) [],
484    SM1_RXNEMPTY OFFSET(1) NUMBITS(1) [],
485    SM0_RXNEMPTY OFFSET(0) NUMBITS(1) []
486],
487IRQ1_INTS [
488    SM3 OFFSET(11) NUMBITS(1) [],
489    SM2 OFFSET(10) NUMBITS(1) [],
490    SM1 OFFSET(9) NUMBITS(1) [],
491    SM0 OFFSET(8) NUMBITS(1) [],
492    SM3_TXNFULL OFFSET(7) NUMBITS(1) [],
493    SM2_TXNFULL OFFSET(6) NUMBITS(1) [],
494    SM1_TXNFULL OFFSET(5) NUMBITS(1) [],
495    SM0_TXNFULL OFFSET(4) NUMBITS(1) [],
496    SM3_RXNEMPTY OFFSET(3) NUMBITS(1) [],
497    SM2_RXNEMPTY OFFSET(2) NUMBITS(1) [],
498    SM1_RXNEMPTY OFFSET(1) NUMBITS(1) [],
499    SM0_RXNEMPTY OFFSET(0) NUMBITS(1) []
500]
501];
502
503const PIO_0_BASE_ADDRESS: usize = 0x50200000;
504const PIO_1_BASE_ADDRESS: usize = 0x50300000;
505const PIO0_BASE: StaticRef<PioRegisters> =
506    unsafe { StaticRef::new(PIO_0_BASE_ADDRESS as *const PioRegisters) };
507const PIO0_XOR_BASE: StaticRef<PioRegisters> =
508    unsafe { StaticRef::new((PIO_0_BASE_ADDRESS + 0x1000) as *const PioRegisters) };
509const PIO0_SET_BASE: StaticRef<PioRegisters> =
510    unsafe { StaticRef::new((PIO_0_BASE_ADDRESS + 0x2000) as *const PioRegisters) };
511const PIO0_CLEAR_BASE: StaticRef<PioRegisters> =
512    unsafe { StaticRef::new((PIO_0_BASE_ADDRESS + 0x3000) as *const PioRegisters) };
513const PIO1_BASE: StaticRef<PioRegisters> =
514    unsafe { StaticRef::new(PIO_1_BASE_ADDRESS as *const PioRegisters) };
515const PIO1_XOR_BASE: StaticRef<PioRegisters> =
516    unsafe { StaticRef::new((PIO_1_BASE_ADDRESS + 0x1000) as *const PioRegisters) };
517const PIO1_SET_BASE: StaticRef<PioRegisters> =
518    unsafe { StaticRef::new((PIO_1_BASE_ADDRESS + 0x2000) as *const PioRegisters) };
519const PIO1_CLEAR_BASE: StaticRef<PioRegisters> =
520    unsafe { StaticRef::new((PIO_1_BASE_ADDRESS + 0x3000) as *const PioRegisters) };
521
522/// Represents a relocated PIO program.
523///
524/// An [Iterator] that yields the original program except `JMP` instructions have
525/// relocated target addresses based on an origin.
526pub struct RelocatedProgram<'a, I>
527where
528    I: Iterator<Item = &'a u16>,
529{
530    iter: I,
531    origin: usize,
532}
533
534impl<'a, I> RelocatedProgram<'a, I>
535where
536    I: Iterator<Item = &'a u16>,
537{
538    fn new(iter: I, origin: usize) -> Self {
539        Self { iter, origin }
540    }
541}
542
543impl<'a, I> Iterator for RelocatedProgram<'a, I>
544where
545    I: Iterator<Item = &'a u16>,
546{
547    type Item = u16;
548
549    fn next(&mut self) -> Option<Self::Item> {
550        self.iter.next().map(|&instr| {
551            if instr & 0b1110_0000_0000_0000 == 0 {
552                // this is a JMP instruction -> add offset to address
553                let address = instr & 0b1_1111;
554                let address = address.wrapping_add(self.origin as u16) % 32;
555                instr & (!0b11111) | address
556            } else {
557                instr
558            }
559        })
560    }
561}
562
563#[derive(Clone, Copy)]
564pub struct LoadedProgram {
565    used_memory: u32,
566    origin: usize,
567}
568
569#[derive(Clone, Copy, PartialEq, Eq, Debug)]
570pub enum ProgramError {
571    /// Insufficient consecutive free instruction space to load program.
572    InsufficientSpace,
573    /// Loading a program would overwrite the existing one
574    AddrInUse(usize),
575}
576
577/// There are a total of 4 State Machines per PIO.
578#[derive(Clone, Copy, PartialEq, Debug)]
579pub enum SMNumber {
580    SM0 = 0,
581    SM1 = 1,
582    SM2 = 2,
583    SM3 = 3,
584}
585
586/// Array of all SMNumbers, used for convenience in Pio constructor
587const SM_NUMBERS: [SMNumber; 4] = [SMNumber::SM0, SMNumber::SM1, SMNumber::SM2, SMNumber::SM3];
588
589/// There can be 2 PIOs per RP2040.
590#[derive(Clone, Copy, PartialEq)]
591pub enum PIONumber {
592    PIO0 = 0,
593    PIO1 = 1,
594}
595
596/// The FIFO queues can be joined together for twice the length in one direction.
597#[derive(PartialEq)]
598pub enum PioFifoJoin {
599    PioFifoJoinNone = 0,
600    PioFifoJoinTx = 1,
601    PioFifoJoinRx = 2,
602}
603
604/// PIO interrupt source numbers for PIO related interrupts
605#[derive(PartialEq)]
606pub enum InterruptSources {
607    Interrupt0 = 0,
608    Interrupt1 = 1,
609    Interrupt2 = 2,
610    Interrupt3 = 3,
611    Sm0TXNotFull = 4,
612    Sm1TXNotFull = 5,
613    Sm2TXNotFull = 6,
614    Sm3TXNotFull = 7,
615    Sm0RXNotEmpty = 8,
616    Sm1RXNotEmpty = 9,
617    Sm2RXNotEmpty = 10,
618    Sm3RXNotEmpty = 11,
619}
620
621pub trait PioTxClient {
622    fn on_buffer_space_available(&self);
623}
624
625pub trait PioRxClient {
626    fn on_data_received(&self, data: u32);
627}
628
629/// Client for State Machine interrupts fired by the `irq` PIO instruction
630pub trait PioSmClient {
631    fn on_irq(&self);
632}
633
634#[derive(Clone, Copy, Debug, Default)]
635enum StateMachineState {
636    #[default]
637    Ready,
638    Waiting,
639}
640
641pub struct StateMachine {
642    sm_number: SMNumber,
643    registers: StaticRef<PioRegisters>,
644    xor_registers: StaticRef<PioRegisters>,
645    set_registers: StaticRef<PioRegisters>,
646    tx_state: Cell<StateMachineState>,
647    tx_client: OptionalCell<&'static dyn PioTxClient>,
648    rx_state: Cell<StateMachineState>,
649    rx_client: OptionalCell<&'static dyn PioRxClient>,
650    sm_client: OptionalCell<&'static dyn PioSmClient>,
651}
652
653impl StateMachine {
654    fn new(
655        sm_id: SMNumber,
656        registers: StaticRef<PioRegisters>,
657        xor_registers: StaticRef<PioRegisters>,
658        set_registers: StaticRef<PioRegisters>,
659    ) -> StateMachine {
660        StateMachine {
661            sm_number: sm_id,
662            registers,
663            xor_registers,
664            set_registers,
665            tx_state: Cell::new(StateMachineState::Ready),
666            tx_client: OptionalCell::empty(),
667            rx_state: Cell::new(StateMachineState::Ready),
668            sm_client: OptionalCell::empty(),
669            rx_client: OptionalCell::empty(),
670        }
671    }
672
673    /// State machine configuration with any config structure.
674    pub fn config(&self, config: &StateMachineConfiguration) {
675        self.set_in_pins(config.in_pins_base);
676        self.set_out_pins(config.out_pins_base, config.out_pins_count);
677        self.set_set_pins(config.set_pins_base, config.set_pins_count);
678        self.set_side_set_pins(
679            config.side_set_base,
680            config.side_set_bit_count,
681            config.side_set_opt_enable,
682            config.side_set_pindirs,
683        );
684        self.set_in_shift(
685            config.in_shift_direction_right,
686            config.in_autopush,
687            config.in_push_threshold,
688        );
689        self.set_out_shift(
690            config.out_shift_direction_right,
691            config.out_autopull,
692            config.out_pull_threshold,
693        );
694        self.set_jmp_pin(config.jmp_pin);
695        self.set_wrap(config.wrap_to, config.wrap);
696        self.set_mov_status(config.mov_status_sel, config.mov_status_n);
697        self.set_out_special(
698            config.out_special_sticky,
699            config.out_special_has_enable_pin,
700            config.out_special_enable_pin_index,
701        );
702        self.set_clkdiv_int_frac(config.div_int, config.div_frac);
703    }
704
705    /// Set tx client for a state machine.
706    pub fn set_tx_client(&self, client: &'static dyn PioTxClient) {
707        self.tx_client.set(client);
708    }
709
710    /// Set rx client for a state machine.
711    pub fn set_rx_client(&self, client: &'static dyn PioRxClient) {
712        self.rx_client.set(client);
713    }
714
715    /// Set client for a state machine interrupt.
716    pub fn set_sm_client(&self, client: &'static dyn PioSmClient) {
717        self.sm_client.set(client);
718    }
719
720    /// Set every config for the IN pins.
721    ///
722    /// in_base => the starting location for the input pins
723    pub fn set_in_pins(&self, in_base: u32) {
724        self.registers.sm[self.sm_number as usize]
725            .pinctrl
726            .modify(SMx_PINCTRL::IN_BASE.val(in_base));
727    }
728
729    /// Set every config for the SET pins.
730    ///
731    /// set_base => the starting location for the SET pins
732    /// set_count => the number of SET pins
733    pub fn set_set_pins(&self, set_base: u32, set_count: u32) {
734        self.registers.sm[self.sm_number as usize]
735            .pinctrl
736            .modify(SMx_PINCTRL::SET_BASE.val(set_base));
737        self.registers.sm[self.sm_number as usize]
738            .pinctrl
739            .modify(SMx_PINCTRL::SET_COUNT.val(set_count));
740    }
741
742    /// Set every config for the OUT pins.
743    ///
744    /// out_base => the starting location for the OUT pins
745    /// out_count => the number of OUT pins
746    pub fn set_out_pins(&self, out_base: u32, out_count: u32) {
747        self.registers.sm[self.sm_number as usize]
748            .pinctrl
749            .modify(SMx_PINCTRL::OUT_BASE.val(out_base));
750        self.registers.sm[self.sm_number as usize]
751            .pinctrl
752            .modify(SMx_PINCTRL::OUT_COUNT.val(out_count));
753    }
754
755    /// Setup 'in' shifting parameters.
756    ///
757    ///  shift_right => true to shift ISR to right or false to shift to left
758    ///  autopush => true to enable, false to disable
759    ///  push_threshold => threshold in bits to shift in before auto/conditional re-pushing of the ISR
760    pub fn set_in_shift(&self, shift_right: bool, autopush: bool, push_threshold: u32) {
761        self.registers.sm[self.sm_number as usize]
762            .shiftctrl
763            .modify(SMx_SHIFTCTRL::IN_SHIFTDIR.val(shift_right.into()));
764        self.registers.sm[self.sm_number as usize]
765            .shiftctrl
766            .modify(SMx_SHIFTCTRL::AUTOPUSH.val(autopush.into()));
767        self.registers.sm[self.sm_number as usize]
768            .shiftctrl
769            .modify(SMx_SHIFTCTRL::PUSH_THRESH.val(push_threshold));
770    }
771
772    /// Setup 'out' shifting parameters.
773    ///
774    /// shift_right => `true` to shift OSR to right or false to shift to left
775    /// autopull => true to enable, false to disable
776    /// pull_threshold => threshold in bits to shift out before auto/conditional re-pulling of the OSR
777    pub fn set_out_shift(&self, shift_right: bool, autopull: bool, pull_threshold: u32) {
778        self.registers.sm[self.sm_number as usize]
779            .shiftctrl
780            .modify(SMx_SHIFTCTRL::OUT_SHIFTDIR.val(shift_right.into()));
781        self.registers.sm[self.sm_number as usize]
782            .shiftctrl
783            .modify(SMx_SHIFTCTRL::AUTOPULL.val(autopull.into()));
784        self.registers.sm[self.sm_number as usize]
785            .shiftctrl
786            .modify(SMx_SHIFTCTRL::PULL_THRESH.val(pull_threshold));
787    }
788
789    /// Set special OUT operations in a state machine.
790    ///
791    /// sticky
792    /// => true to enable sticky output (rere-asserting most recent OUT/SET pin values on subsequent cycles)
793    /// => false to disable sticky output
794    /// has_enable_pin
795    /// => true to enable auxiliary OUT enable pin
796    /// => false to disable auxiliary OUT enable pin
797    /// enable_pin_index => pin index for auxiliary OUT enable
798    pub fn set_out_special(&self, sticky: bool, has_enable_pin: bool, enable_pin_index: u32) {
799        self.registers.sm[self.sm_number as usize]
800            .execctrl
801            .modify(SMx_EXECCTRL::OUT_STICKY.val(sticky as u32));
802        self.registers.sm[self.sm_number as usize]
803            .execctrl
804            .modify(SMx_EXECCTRL::INLINE_OUT_EN.val(has_enable_pin as u32));
805        self.registers.sm[self.sm_number as usize]
806            .execctrl
807            .modify(SMx_EXECCTRL::OUT_EN_SEL.val(enable_pin_index));
808    }
809
810    /// Set the 'jmp' pin.
811    ///
812    /// pin => the raw GPIO pin number to use as the source for a jmp pin instruction
813    pub fn set_jmp_pin(&self, pin: u32) {
814        self.registers.sm[self.sm_number as usize]
815            .execctrl
816            .modify(SMx_EXECCTRL::JMP_PIN.val(pin));
817    }
818
819    /// Set the clock divider for a state machine.
820    ///
821    /// div_int => Integer part of the divisor
822    /// div_frac => Fractional part in 1/256ths
823    pub fn set_clkdiv_int_frac(&self, div_int: u32, div_frac: u32) {
824        self.registers.sm[self.sm_number as usize]
825            .clkdiv
826            .modify(SMx_CLKDIV::INT.val(div_int));
827        self.registers.sm[self.sm_number as usize]
828            .clkdiv
829            .modify(SMx_CLKDIV::FRAC.val(div_frac));
830    }
831
832    /// Setup the FIFO joining in a state machine.
833    ///
834    /// fifo_join => specifies the join type - see the `PioFifoJoin` type
835    pub fn set_fifo_join(&self, fifo_join: PioFifoJoin) {
836        if fifo_join == PioFifoJoin::PioFifoJoinRx {
837            self.registers.sm[self.sm_number as usize]
838                .shiftctrl
839                .modify(SMx_SHIFTCTRL::FJOIN_RX.val(fifo_join as u32));
840        } else if fifo_join == PioFifoJoin::PioFifoJoinTx {
841            self.registers.sm[self.sm_number as usize]
842                .shiftctrl
843                .modify(SMx_SHIFTCTRL::FJOIN_TX.val(fifo_join as u32));
844        }
845    }
846
847    /// Set every config for the SIDESET pins.
848    ///
849    /// sideset_base => the starting location for the SIDESET pins
850    /// bit_count => number of SIDESET bits per instruction - max 5
851    /// optional
852    /// => true to use the topmost sideset bit as a flag for whether to apply side set on that instruction
853    /// => false to use sideset with every instruction
854    /// pindirs
855    /// => true to affect pin direction
856    /// => false to affect value of a pin
857    pub fn set_side_set_pins(
858        &self,
859        sideset_base: u32,
860        bit_count: u32,
861        optional: bool,
862        pindirs: bool,
863    ) {
864        self.registers.sm[self.sm_number as usize]
865            .pinctrl
866            .modify(SMx_PINCTRL::SIDESET_BASE.val(sideset_base));
867        self.registers.sm[self.sm_number as usize]
868            .pinctrl
869            .modify(SMx_PINCTRL::SIDESET_COUNT.val(bit_count));
870        self.registers.sm[self.sm_number as usize]
871            .execctrl
872            .modify(SMx_EXECCTRL::SIDE_EN.val(optional as u32));
873        self.registers.sm[self.sm_number as usize]
874            .execctrl
875            .modify(SMx_EXECCTRL::SIDE_PINDIR.val(pindirs as u32));
876    }
877
878    /// Use a state machine to set the same pin direction for multiple consecutive pins for the PIO instance.
879    /// This is the pio_sm_set_consecutive_pindirs function from the pico sdk, renamed to be more clear.
880    ///
881    /// pin => starting pin
882    /// count => how many pins (including the base) should be changed
883    /// is_out
884    /// => true to set the pin as OUT
885    /// => false to set the pin as IN
886    pub fn set_pins_dirs(&self, mut pin: u32, mut count: u32, is_out: bool) {
887        // "set pindirs, 0" command created by pioasm
888        let set_pindirs_0: u16 = 0b1110000010000000;
889        self.with_paused(|| {
890            let mut pindir_val: u8 = 0x00;
891            if is_out {
892                pindir_val = 0x1f;
893            }
894            while count > 5 {
895                self.registers.sm[self.sm_number as usize]
896                    .pinctrl
897                    .modify(SMx_PINCTRL::SET_COUNT.val(5));
898                self.registers.sm[self.sm_number as usize]
899                    .pinctrl
900                    .modify(SMx_PINCTRL::SET_BASE.val(pin));
901                self.exec((set_pindirs_0) | (pindir_val as u16));
902                count -= 5;
903                pin = (pin + 5) & 0x1f;
904            }
905            self.registers.sm[self.sm_number as usize]
906                .pinctrl
907                .modify(SMx_PINCTRL::SET_COUNT.val(count));
908            self.registers.sm[self.sm_number as usize]
909                .pinctrl
910                .modify(SMx_PINCTRL::SET_BASE.val(pin));
911            self.exec((set_pindirs_0) | (pindir_val as u16));
912        });
913    }
914
915    /// Sets pin output values. Pauses the state machine to run `SET` commands
916    /// and temporarily unsets the `OUT_STICKY` bit to avoid side effects.
917    ///
918    /// pins => pins to set the value for
919    /// high => true to set the pin high
920    pub fn set_pins(&self, pins: &[&RPGpioPin<'_>], high: bool) {
921        self.with_paused(|| {
922            for pin in pins {
923                self.registers.sm[self.sm_number as usize]
924                    .pinctrl
925                    .modify(SMx_PINCTRL::SET_BASE.val(pin.pin() as u32));
926                self.registers.sm[self.sm_number as usize]
927                    .pinctrl
928                    .modify(SMx_PINCTRL::SET_COUNT.val(1));
929
930                self.exec(0b11100_000_000_00000 | high as u16);
931            }
932        });
933    }
934
935    /// Set the wrap addresses for a state machine.
936    ///
937    /// wrap_target => the instruction memory address to wrap to
938    /// wrap => the instruction memory address after which the program counters wraps to the target
939    pub fn set_wrap(&self, wrap_target: u32, wrap: u32) {
940        self.registers.sm[self.sm_number as usize]
941            .execctrl
942            .modify(SMx_EXECCTRL::WRAP_BOTTOM.val(wrap_target));
943        self.registers.sm[self.sm_number as usize]
944            .execctrl
945            .modify(SMx_EXECCTRL::WRAP_TOP.val(wrap));
946    }
947
948    /// Resets the state machine to a consistent state and configures it.
949    pub fn init(&self) {
950        self.clear_fifos();
951        self.restart();
952        self.clkdiv_restart();
953        self.registers.sm[self.sm_number as usize]
954            .instr
955            .modify(SMx_INSTR::INSTR.val(0));
956    }
957
958    /// Address of the RX FIFO
959    pub fn rx_fifo_addr(&self, pio: PIONumber) -> u32 {
960        let base_addr = match pio {
961            PIONumber::PIO0 => PIO_0_BASE_ADDRESS,
962            PIONumber::PIO1 => PIO_1_BASE_ADDRESS,
963        };
964        (base_addr as u32) + 0x20 + 4 * (self.sm_number as u32)
965    }
966
967    /// Address of the TX FIFO
968    pub fn tx_fifo_addr(&self, pio: PIONumber) -> u32 {
969        let base_addr = match pio {
970            PIONumber::PIO0 => PIO_0_BASE_ADDRESS,
971            PIONumber::PIO1 => PIO_1_BASE_ADDRESS,
972        };
973        (base_addr as u32) + 0x10 + 4 * (self.sm_number as u32)
974    }
975
976    /// Restart a state machine.
977    pub fn restart(&self) {
978        match self.sm_number {
979            SMNumber::SM0 => self.set_registers.ctrl.modify(CTRL::SM0_RESTART::SET),
980            SMNumber::SM1 => self.set_registers.ctrl.modify(CTRL::SM1_RESTART::SET),
981            SMNumber::SM2 => self.set_registers.ctrl.modify(CTRL::SM2_RESTART::SET),
982            SMNumber::SM3 => self.set_registers.ctrl.modify(CTRL::SM3_RESTART::SET),
983        }
984    }
985
986    /// Clear a state machine’s TX and RX FIFOs.
987    pub fn clear_fifos(&self) {
988        self.xor_registers.sm[self.sm_number as usize]
989            .shiftctrl
990            .modify(SMx_SHIFTCTRL::FJOIN_RX::SET);
991        self.xor_registers.sm[self.sm_number as usize]
992            .shiftctrl
993            .modify(SMx_SHIFTCTRL::FJOIN_RX::SET);
994    }
995
996    /// Restart a state machine's clock divider.
997    pub fn clkdiv_restart(&self) {
998        match self.sm_number {
999            SMNumber::SM0 => self.set_registers.ctrl.modify(CTRL::CLKDIV0_RESTART::SET),
1000            SMNumber::SM1 => self.set_registers.ctrl.modify(CTRL::CLKDIV1_RESTART::SET),
1001            SMNumber::SM2 => self.set_registers.ctrl.modify(CTRL::CLKDIV2_RESTART::SET),
1002            SMNumber::SM3 => self.set_registers.ctrl.modify(CTRL::CLKDIV3_RESTART::SET),
1003        }
1004    }
1005
1006    /// Returns true if the TX FIFO is full.
1007    pub fn tx_full(&self) -> bool {
1008        let field = match self.sm_number {
1009            SMNumber::SM0 => FSTAT::TXFULL0,
1010            SMNumber::SM1 => FSTAT::TXFULL1,
1011            SMNumber::SM2 => FSTAT::TXFULL2,
1012            SMNumber::SM3 => FSTAT::TXFULL3,
1013        };
1014        self.registers.fstat.read(field) != 0
1015    }
1016
1017    /// Returns true if the RX FIFO is empty.
1018    pub fn rx_empty(&self) -> bool {
1019        let field = match self.sm_number {
1020            SMNumber::SM0 => FSTAT::RXEMPTY0,
1021            SMNumber::SM1 => FSTAT::RXEMPTY1,
1022            SMNumber::SM2 => FSTAT::RXEMPTY2,
1023            SMNumber::SM3 => FSTAT::RXEMPTY3,
1024        };
1025        self.registers.fstat.read(field) != 0
1026    }
1027
1028    /// Returns true if the TX FIFO is empty.
1029    pub fn tx_empty(&self) -> bool {
1030        let field = match self.sm_number {
1031            SMNumber::SM0 => FSTAT::TXEMPTY0,
1032            SMNumber::SM1 => FSTAT::TXEMPTY1,
1033            SMNumber::SM2 => FSTAT::TXEMPTY2,
1034            SMNumber::SM3 => FSTAT::TXEMPTY3,
1035        };
1036        self.registers.fstat.read(field) != 0
1037    }
1038
1039    /// Immediately execute an instruction on a state machine.
1040    ///
1041    /// => instr: the instruction to execute
1042    /// Implicitly restricted size of instr to u16, cause it's the size pio asm instr
1043    pub fn exec(&self, instr: u16) {
1044        self.registers.sm[self.sm_number as usize]
1045            .instr
1046            .modify(SMx_INSTR::INSTR.val(instr as u32));
1047    }
1048
1049    /// Executes a program on a state machine.
1050    /// Jumps to the instruction at given address and runs the program.
1051    ///
1052    /// => program: a program loaded to PIO
1053    /// => wrap: true to wrap the program, so it runs in loop
1054    pub fn exec_program(&self, program: LoadedProgram, wrap: bool) {
1055        if wrap {
1056            self.set_wrap(
1057                program.origin as u32,
1058                program.origin as u32 + program.used_memory.count_ones(),
1059            );
1060        }
1061        self.exec((program.origin as u16) & 0x1fu16)
1062    }
1063
1064    /// Set source for 'mov status' in a state machine.
1065    ///
1066    /// status_sel => comparison used for the `MOV x, STATUS` instruction
1067    /// status_n => comparison level for the `MOV x, STATUS` instruction
1068    pub fn set_mov_status(&self, status_sel: PioMovStatusType, status_n: u32) {
1069        self.registers.sm[self.sm_number as usize]
1070            .execctrl
1071            .modify(SMx_EXECCTRL::STATUS_SEL.val(status_sel as u32));
1072        self.registers.sm[self.sm_number as usize]
1073            .execctrl
1074            .modify(SMx_EXECCTRL::STATUS_N.val(status_n));
1075    }
1076
1077    /// Set a state machine's state to enabled or to disabled.
1078    ///
1079    /// enabled => true to enable the state machine
1080    pub fn set_enabled(&self, enabled: bool) {
1081        match self.sm_number {
1082            SMNumber::SM0 => self.registers.ctrl.modify(match enabled {
1083                true => CTRL::SM0_ENABLE::SET,
1084                false => CTRL::SM0_ENABLE::CLEAR,
1085            }),
1086            SMNumber::SM1 => self.registers.ctrl.modify(match enabled {
1087                true => CTRL::SM1_ENABLE::SET,
1088                false => CTRL::SM1_ENABLE::CLEAR,
1089            }),
1090            SMNumber::SM2 => self.registers.ctrl.modify(match enabled {
1091                true => CTRL::SM2_ENABLE::SET,
1092                false => CTRL::SM2_ENABLE::CLEAR,
1093            }),
1094            SMNumber::SM3 => self.registers.ctrl.modify(match enabled {
1095                true => CTRL::SM3_ENABLE::SET,
1096                false => CTRL::SM3_ENABLE::CLEAR,
1097            }),
1098        }
1099    }
1100
1101    /// Is state machine enabled.
1102    pub fn is_enabled(&self) -> bool {
1103        let field = match self.sm_number {
1104            SMNumber::SM0 => CTRL::SM0_ENABLE,
1105            SMNumber::SM1 => CTRL::SM1_ENABLE,
1106            SMNumber::SM2 => CTRL::SM2_ENABLE,
1107            SMNumber::SM3 => CTRL::SM3_ENABLE,
1108        };
1109        self.registers.ctrl.read(field) != 0
1110    }
1111
1112    /// Runs function with the state machine paused.
1113    /// Keeps pinctrl and execctrl of the SM the same during execution
1114    fn with_paused(&self, f: impl FnOnce()) {
1115        let enabled = self.is_enabled();
1116        self.set_enabled(false);
1117
1118        let pio_sm = &self.registers.sm[self.sm_number as usize];
1119
1120        let pinctrl = pio_sm.pinctrl.get();
1121        let execctrl = pio_sm.execctrl.get();
1122        // Hold pins value set by latest OUT/SET op
1123        pio_sm.execctrl.modify(SMx_EXECCTRL::OUT_STICKY::CLEAR);
1124
1125        f();
1126
1127        pio_sm.pinctrl.set(pinctrl);
1128        pio_sm.execctrl.set(execctrl);
1129        self.set_enabled(enabled);
1130    }
1131
1132    /// Write a word of data to a state machine’s TX FIFO.
1133    /// If the FIFO is full, the client will be notified when space is available.
1134    ///
1135    /// => data: the data to write to the FIFO
1136    pub fn push(&self, data: u32) -> Result<(), ErrorCode> {
1137        match self.tx_state.get() {
1138            StateMachineState::Ready => {
1139                if self.tx_full() {
1140                    // TX queue is full, set interrupt
1141                    let field = match self.sm_number {
1142                        SMNumber::SM0 => IRQ0_INTE::SM0_TXNFULL::SET,
1143                        SMNumber::SM1 => IRQ0_INTE::SM1_TXNFULL::SET,
1144                        SMNumber::SM2 => IRQ0_INTE::SM2_TXNFULL::SET,
1145                        SMNumber::SM3 => IRQ0_INTE::SM3_TXNFULL::SET,
1146                    };
1147                    self.registers.irq0_inte.modify(field);
1148                    self.tx_state.set(StateMachineState::Waiting);
1149                    Err(ErrorCode::BUSY)
1150                } else {
1151                    self.registers.txf[self.sm_number as usize].set(data);
1152                    Ok(())
1153                }
1154            }
1155            StateMachineState::Waiting => Err(ErrorCode::BUSY),
1156        }
1157    }
1158
1159    /// Wait until a state machine's TX FIFO is empty, then write a word of data to it.
1160    /// If state machine is disabled and there is no space, an error will be returned.
1161    /// If SM is stalled on RX or in loop, this will block forever.
1162    ///
1163    /// => data: the data to write to the FIFO
1164    pub fn push_blocking(&self, data: u32) -> Result<(), ErrorCode> {
1165        if self.tx_full() && !self.is_enabled() {
1166            return Err(ErrorCode::OFF);
1167        }
1168        while self.tx_full() {}
1169        self.registers.txf[self.sm_number as usize].set(data);
1170        Ok(())
1171    }
1172
1173    /// Read a word of data from a state machine’s RX FIFO.
1174    /// If the FIFO is empty, the client will be notified when data is available.
1175    pub fn pull(&self) -> Result<u32, ErrorCode> {
1176        match self.rx_state.get() {
1177            StateMachineState::Ready => {
1178                if self.rx_empty() {
1179                    // RX queue is empty, set interrupt
1180                    let field = match self.sm_number {
1181                        SMNumber::SM0 => IRQ0_INTE::SM0_RXNEMPTY::SET,
1182                        SMNumber::SM1 => IRQ0_INTE::SM1_RXNEMPTY::SET,
1183                        SMNumber::SM2 => IRQ0_INTE::SM2_RXNEMPTY::SET,
1184                        SMNumber::SM3 => IRQ0_INTE::SM3_RXNEMPTY::SET,
1185                    };
1186                    self.registers.irq0_inte.modify(field);
1187                    self.rx_state.set(StateMachineState::Waiting);
1188                    Err(ErrorCode::BUSY)
1189                } else {
1190                    Ok(self.registers.rxf[self.sm_number as usize].read(RXFx::RXF))
1191                }
1192            }
1193            StateMachineState::Waiting => Err(ErrorCode::BUSY),
1194        }
1195    }
1196
1197    /// Reads a word of data from a state machine’s RX FIFO.
1198    /// If state machine is disabled and there is no space, an error will be returned.
1199    /// If SM is stalled on TX or in loop, this will block forever.
1200    pub fn pull_blocking(&self) -> Result<u32, ErrorCode> {
1201        if self.tx_full() && !self.is_enabled() {
1202            return Err(ErrorCode::OFF);
1203        }
1204        while self.rx_empty() {}
1205        Ok(self.registers.rxf[self.sm_number as usize].read(RXFx::RXF))
1206    }
1207
1208    /// Handle a TX interrupt - notify that buffer space is available.
1209    fn handle_tx_interrupt(&self) {
1210        match self.tx_state.get() {
1211            StateMachineState::Waiting => {
1212                // TX queue has emptied, clear interrupt
1213                let field = match self.sm_number {
1214                    SMNumber::SM0 => IRQ0_INTE::SM0_TXNFULL::CLEAR,
1215                    SMNumber::SM1 => IRQ0_INTE::SM1_TXNFULL::CLEAR,
1216                    SMNumber::SM2 => IRQ0_INTE::SM2_TXNFULL::CLEAR,
1217                    SMNumber::SM3 => IRQ0_INTE::SM3_TXNFULL::CLEAR,
1218                };
1219                self.registers.irq0_inte.modify(field);
1220                self.tx_state.set(StateMachineState::Ready);
1221                self.tx_client.map(|client| {
1222                    client.on_buffer_space_available();
1223                });
1224            }
1225            StateMachineState::Ready => {}
1226        }
1227    }
1228
1229    /// Handle an RX interrupt - notify that data has been received.
1230    fn handle_rx_interrupt(&self) {
1231        match self.rx_state.get() {
1232            StateMachineState::Waiting => {
1233                // RX queue has data, clear interrupt
1234                let field = match self.sm_number {
1235                    SMNumber::SM0 => IRQ0_INTE::SM0_RXNEMPTY::CLEAR,
1236                    SMNumber::SM1 => IRQ0_INTE::SM1_RXNEMPTY::CLEAR,
1237                    SMNumber::SM2 => IRQ0_INTE::SM2_RXNEMPTY::CLEAR,
1238                    SMNumber::SM3 => IRQ0_INTE::SM3_RXNEMPTY::CLEAR,
1239                };
1240                self.registers.irq0_inte.modify(field);
1241                self.rx_state.set(StateMachineState::Ready);
1242                self.rx_client.map(|client| {
1243                    client.on_data_received(
1244                        self.registers.rxf[self.sm_number as usize].read(RXFx::RXF),
1245                    );
1246                });
1247            }
1248            StateMachineState::Ready => {}
1249        }
1250    }
1251
1252    /// Handle an `SMx` interrupt. The PIO program got to a `irq` instruction.
1253    fn handle_sm_interrupt(&self) {
1254        let _ = self.sm_client.map(|client| {
1255            client.on_irq();
1256        });
1257    }
1258}
1259
1260pub struct Pio {
1261    registers: StaticRef<PioRegisters>,
1262    pio_number: PIONumber,
1263    sms: [StateMachine; NUMBER_STATE_MACHINES],
1264    instructions_used: Cell<u32>,
1265    _clear_registers: StaticRef<PioRegisters>,
1266}
1267
1268/// 'MOV STATUS' types.
1269#[derive(Clone, Copy)]
1270pub enum PioMovStatusType {
1271    StatusTxLessthan = 0,
1272    StatusRxLessthan = 1,
1273}
1274
1275/// PIO State Machine configuration structure
1276///
1277/// Used to initialize a PIO with all of its state machines.
1278pub struct StateMachineConfiguration {
1279    pub out_pins_count: u32,
1280    pub out_pins_base: u32,
1281    pub set_pins_count: u32,
1282    pub set_pins_base: u32,
1283    pub in_pins_base: u32,
1284    pub side_set_base: u32,
1285    pub side_set_opt_enable: bool,
1286    pub side_set_bit_count: u32,
1287    pub side_set_pindirs: bool,
1288    pub wrap: u32,
1289    pub wrap_to: u32,
1290    pub in_shift_direction_right: bool,
1291    pub in_autopush: bool,
1292    pub in_push_threshold: u32,
1293    pub out_shift_direction_right: bool,
1294    pub out_autopull: bool,
1295    pub out_pull_threshold: u32,
1296    pub jmp_pin: u32,
1297    pub out_special_sticky: bool,
1298    pub out_special_has_enable_pin: bool,
1299    pub out_special_enable_pin_index: u32,
1300    pub mov_status_sel: PioMovStatusType,
1301    pub mov_status_n: u32,
1302    pub div_int: u32,
1303    pub div_frac: u32,
1304}
1305
1306impl Default for StateMachineConfiguration {
1307    fn default() -> Self {
1308        StateMachineConfiguration {
1309            out_pins_count: 32,
1310            out_pins_base: 0,
1311            set_pins_count: 0,
1312            set_pins_base: 0,
1313            in_pins_base: 0,
1314            side_set_base: 0,
1315            side_set_opt_enable: false,
1316            side_set_bit_count: 0,
1317            side_set_pindirs: false,
1318            wrap: 31,
1319            wrap_to: 0,
1320            in_shift_direction_right: true,
1321            in_autopush: false,
1322            in_push_threshold: 32,
1323            out_shift_direction_right: true,
1324            out_autopull: false,
1325            out_pull_threshold: 32,
1326            jmp_pin: 0,
1327            out_special_sticky: false,
1328            out_special_has_enable_pin: false,
1329            out_special_enable_pin_index: 0,
1330            mov_status_sel: PioMovStatusType::StatusTxLessthan,
1331            mov_status_n: 0,
1332            div_int: 0,
1333            div_frac: 0,
1334        }
1335    }
1336}
1337
1338impl Pio {
1339    /// Setup the function select for a GPIO to use output from the given PIO instance.
1340    pub fn gpio_init(&self, pin: &RPGpioPin) {
1341        if self.pio_number == PIONumber::PIO1 {
1342            pin.set_function(GpioFunction::PIO1)
1343        } else {
1344            pin.set_function(GpioFunction::PIO0)
1345        }
1346    }
1347
1348    /// Create a new PIO0 struct.
1349    pub fn new_pio0() -> Self {
1350        Self {
1351            registers: PIO0_BASE,
1352            _clear_registers: PIO0_CLEAR_BASE,
1353            pio_number: PIONumber::PIO0,
1354            sms: SM_NUMBERS.map(|x| StateMachine::new(x, PIO0_BASE, PIO0_XOR_BASE, PIO0_SET_BASE)),
1355            instructions_used: Cell::new(0),
1356        }
1357    }
1358
1359    /// Create a new PIO1 struct.
1360    pub fn new_pio1() -> Self {
1361        Self {
1362            registers: PIO1_BASE,
1363            _clear_registers: PIO1_CLEAR_BASE,
1364            pio_number: PIONumber::PIO1,
1365            sms: SM_NUMBERS.map(|x| StateMachine::new(x, PIO1_BASE, PIO1_XOR_BASE, PIO1_SET_BASE)),
1366            instructions_used: Cell::new(0),
1367        }
1368    }
1369
1370    /// Get the PIO number
1371    pub fn number(&self) -> PIONumber {
1372        self.pio_number
1373    }
1374
1375    /// Get state machine
1376    pub fn sm(&self, sm_number: SMNumber) -> &StateMachine {
1377        &self.sms[sm_number as usize]
1378    }
1379
1380    /// Enable/Disable a single source on a PIO's IRQ index.
1381    pub fn set_irq_source(
1382        &self,
1383        irq_index: u32,
1384        interrupt_source: InterruptSources,
1385        enabled: bool,
1386    ) {
1387        if irq_index == 0 {
1388            match interrupt_source {
1389                InterruptSources::Interrupt0 => self
1390                    .registers
1391                    .irq0_inte
1392                    .modify(IRQ0_INTE::SM0.val(enabled as u32)),
1393                InterruptSources::Interrupt1 => self
1394                    .registers
1395                    .irq0_inte
1396                    .modify(IRQ0_INTE::SM1.val(enabled as u32)),
1397                InterruptSources::Interrupt2 => self
1398                    .registers
1399                    .irq0_inte
1400                    .modify(IRQ0_INTE::SM2.val(enabled as u32)),
1401                InterruptSources::Interrupt3 => self
1402                    .registers
1403                    .irq0_inte
1404                    .modify(IRQ0_INTE::SM3.val(enabled as u32)),
1405                InterruptSources::Sm0TXNotFull => self
1406                    .registers
1407                    .irq0_inte
1408                    .modify(IRQ0_INTE::SM0_TXNFULL.val(enabled as u32)),
1409                InterruptSources::Sm1TXNotFull => self
1410                    .registers
1411                    .irq0_inte
1412                    .modify(IRQ0_INTE::SM1_TXNFULL.val(enabled as u32)),
1413                InterruptSources::Sm2TXNotFull => self
1414                    .registers
1415                    .irq0_inte
1416                    .modify(IRQ0_INTE::SM2_TXNFULL.val(enabled as u32)),
1417                InterruptSources::Sm3TXNotFull => self
1418                    .registers
1419                    .irq0_inte
1420                    .modify(IRQ0_INTE::SM3_TXNFULL.val(enabled as u32)),
1421                InterruptSources::Sm0RXNotEmpty => self
1422                    .registers
1423                    .irq0_inte
1424                    .modify(IRQ0_INTE::SM0_RXNEMPTY.val(enabled as u32)),
1425                InterruptSources::Sm1RXNotEmpty => self
1426                    .registers
1427                    .irq0_inte
1428                    .modify(IRQ0_INTE::SM1_RXNEMPTY.val(enabled as u32)),
1429                InterruptSources::Sm2RXNotEmpty => self
1430                    .registers
1431                    .irq0_inte
1432                    .modify(IRQ0_INTE::SM2_RXNEMPTY.val(enabled as u32)),
1433                InterruptSources::Sm3RXNotEmpty => self
1434                    .registers
1435                    .irq0_inte
1436                    .modify(IRQ0_INTE::SM3_RXNEMPTY.val(enabled as u32)),
1437            }
1438        } else if irq_index == 1 {
1439            match interrupt_source {
1440                InterruptSources::Interrupt0 => self
1441                    .registers
1442                    .irq1_inte
1443                    .modify(IRQ1_INTE::SM0.val(enabled as u32)),
1444                InterruptSources::Interrupt1 => self
1445                    .registers
1446                    .irq1_inte
1447                    .modify(IRQ1_INTE::SM1.val(enabled as u32)),
1448                InterruptSources::Interrupt2 => self
1449                    .registers
1450                    .irq1_inte
1451                    .modify(IRQ1_INTE::SM2.val(enabled as u32)),
1452                InterruptSources::Interrupt3 => self
1453                    .registers
1454                    .irq1_inte
1455                    .modify(IRQ1_INTE::SM3.val(enabled as u32)),
1456                InterruptSources::Sm0TXNotFull => self
1457                    .registers
1458                    .irq1_inte
1459                    .modify(IRQ1_INTE::SM0_TXNFULL.val(enabled as u32)),
1460                InterruptSources::Sm1TXNotFull => self
1461                    .registers
1462                    .irq1_inte
1463                    .modify(IRQ1_INTE::SM1_TXNFULL.val(enabled as u32)),
1464                InterruptSources::Sm2TXNotFull => self
1465                    .registers
1466                    .irq1_inte
1467                    .modify(IRQ1_INTE::SM2_TXNFULL.val(enabled as u32)),
1468                InterruptSources::Sm3TXNotFull => self
1469                    .registers
1470                    .irq1_inte
1471                    .modify(IRQ1_INTE::SM3_TXNFULL.val(enabled as u32)),
1472                InterruptSources::Sm0RXNotEmpty => self
1473                    .registers
1474                    .irq1_inte
1475                    .modify(IRQ1_INTE::SM0_RXNEMPTY.val(enabled as u32)),
1476                InterruptSources::Sm1RXNotEmpty => self
1477                    .registers
1478                    .irq1_inte
1479                    .modify(IRQ1_INTE::SM1_RXNEMPTY.val(enabled as u32)),
1480                InterruptSources::Sm2RXNotEmpty => self
1481                    .registers
1482                    .irq1_inte
1483                    .modify(IRQ1_INTE::SM2_RXNEMPTY.val(enabled as u32)),
1484                InterruptSources::Sm3RXNotEmpty => self
1485                    .registers
1486                    .irq1_inte
1487                    .modify(IRQ1_INTE::SM3_RXNEMPTY.val(enabled as u32)),
1488            }
1489        } else {
1490            debug!("IRQ Index invalid - must be 0 or 1");
1491        }
1492    }
1493
1494    /// Checks if a PIO interrupt is set.
1495    pub fn interrupt_get(&self, irq_num: u32) -> bool {
1496        let mut temp = 0;
1497        match irq_num {
1498            0 => temp = self.registers.irq.read(IRQ::IRQ0),
1499            1 => temp = self.registers.irq.read(IRQ::IRQ1),
1500            2 => temp = self.registers.irq.read(IRQ::IRQ2),
1501            3 => temp = self.registers.irq.read(IRQ::IRQ3),
1502            4 => temp = self.registers.irq.read(IRQ::IRQ4),
1503            5 => temp = self.registers.irq.read(IRQ::IRQ5),
1504            6 => temp = self.registers.irq.read(IRQ::IRQ6),
1505            7 => temp = self.registers.irq.read(IRQ::IRQ7),
1506            _ => debug!("IRQ Number invalid - must be from 0 to 7"),
1507        }
1508        temp != 0
1509    }
1510
1511    /// Clear a PIO interrupt.
1512    pub fn interrupt_clear(&self, irq_num: u32) {
1513        match irq_num {
1514            0 => self.registers.irq.modify(IRQ::IRQ0.val(1)),
1515            1 => self.registers.irq.modify(IRQ::IRQ1.val(1)),
1516            2 => self.registers.irq.modify(IRQ::IRQ2.val(1)),
1517            3 => self.registers.irq.modify(IRQ::IRQ3.val(1)),
1518            4 => self.registers.irq.modify(IRQ::IRQ4.val(1)),
1519            5 => self.registers.irq.modify(IRQ::IRQ5.val(1)),
1520            6 => self.registers.irq.modify(IRQ::IRQ6.val(1)),
1521            7 => self.registers.irq.modify(IRQ::IRQ7.val(1)),
1522            _ => debug!("IRQ Number invalid - must be from 0 to 7"),
1523        }
1524    }
1525
1526    /// Handle interrupts
1527    pub fn handle_interrupt(&self) {
1528        let ints = &self.registers.irq0_ints;
1529
1530        for (sm, irq) in self.sms.iter().zip([
1531            IRQ0_INTS::SM0_TXNFULL,
1532            IRQ0_INTS::SM1_TXNFULL,
1533            IRQ0_INTS::SM2_TXNFULL,
1534            IRQ0_INTS::SM3_TXNFULL,
1535        ]) {
1536            if ints.is_set(irq) {
1537                sm.handle_tx_interrupt();
1538            }
1539        }
1540        for (sm, irq) in self.sms.iter().zip([
1541            IRQ0_INTS::SM0_RXNEMPTY,
1542            IRQ0_INTS::SM1_RXNEMPTY,
1543            IRQ0_INTS::SM2_RXNEMPTY,
1544            IRQ0_INTS::SM3_RXNEMPTY,
1545        ]) {
1546            if ints.is_set(irq) {
1547                sm.handle_rx_interrupt();
1548            }
1549        }
1550        for (sm, irq) in self.sms.iter().zip([
1551            IRQ0_INTS::SM0,
1552            IRQ0_INTS::SM1,
1553            IRQ0_INTS::SM2,
1554            IRQ0_INTS::SM3,
1555        ]) {
1556            if ints.is_set(irq) {
1557                sm.handle_sm_interrupt();
1558            }
1559        }
1560    }
1561
1562    pub fn set_input_sync_bypass(&self, pin: &RPGpioPin, enabled: bool) {
1563        let pin = pin.pin();
1564        let reg_val = self.registers.input_sync_bypass.get();
1565        if enabled {
1566            self.registers.input_sync_bypass.set(reg_val | (1 << pin));
1567        } else {
1568            self.registers
1569                .input_sync_bypass
1570                .set(reg_val & (!(1 << pin)));
1571        }
1572    }
1573
1574    /// Adds a program to PIO.
1575    /// Call this with `add_program(Some(0), include_bytes!("path_to_file"))`.
1576    /// => origin: the address in the PIO instruction memory to start the program at or None to find an empty space
1577    /// => program: the program to load into the PIO
1578    /// Returns `LoadedProgram` which contains information about program location and length.
1579    pub fn add_program(
1580        &self,
1581        origin: Option<usize>,
1582        program: &[u8],
1583    ) -> Result<LoadedProgram, ProgramError> {
1584        let mut program_u16: [u16; NUMBER_INSTR_MEMORY_LOCATIONS / 2] =
1585            [0; NUMBER_INSTR_MEMORY_LOCATIONS / 2];
1586        for (i, chunk) in program.chunks(2).enumerate() {
1587            program_u16[i] = ((chunk[0] as u16) << 8) | (chunk[1] as u16);
1588        }
1589
1590        self.add_program16(origin, &program_u16[0..program.len() / 2])
1591    }
1592
1593    /// Adds a program to PIO.
1594    /// Takes `&[u16]` as input, cause pio-asm operations are 16bit.
1595    /// => origin: the address in the PIO instruction memory to start the program at or None to find an empty space
1596    /// => program: the program to load into the PIO
1597    /// Returns `LoadedProgram` which contains information about program location and size.
1598    pub fn add_program16(
1599        &self,
1600        origin: Option<usize>,
1601        program: &[u16],
1602    ) -> Result<LoadedProgram, ProgramError> {
1603        // if origin is not set, try naively to find an empty space
1604        match origin {
1605            Some(origin) => {
1606                assert!(origin < NUMBER_INSTR_MEMORY_LOCATIONS);
1607                self.try_load_program_at(origin, program)
1608                    .map_err(|_| ProgramError::AddrInUse(origin))
1609            }
1610            None => {
1611                for origin in 0..NUMBER_INSTR_MEMORY_LOCATIONS {
1612                    if let res @ Ok(_) = self.try_load_program_at(origin, program) {
1613                        return res;
1614                    }
1615                }
1616                Err(ProgramError::InsufficientSpace)
1617            }
1618        }
1619    }
1620
1621    /// Try to load program at a specific origin, relocate operations if necessary.
1622    /// Only for internals, use `add_program` or `add_program16` instead.
1623    /// => origin: the address in the PIO instruction memory to start the program at
1624    /// => program: the program to load into the PIO
1625    /// Returns Ok(()) if the program was loaded successfully, otherwise an error.
1626    fn try_load_program_at(
1627        &self,
1628        origin: usize,
1629        program: &[u16],
1630    ) -> Result<LoadedProgram, ProgramError> {
1631        // Relocate program
1632        let program = RelocatedProgram::new(program.iter(), origin);
1633        let mut used_mask = 0;
1634        for (i, instr) in program.enumerate() {
1635            // wrapping around the end of program memory is valid
1636            let addr = (i + origin) % 32;
1637            let mask = 1 << addr;
1638            if (self.instructions_used.get() | used_mask) & mask != 0 {
1639                return Err(ProgramError::AddrInUse(addr));
1640            }
1641            self.registers.instr_mem[addr]
1642                .instr_mem
1643                .modify(INSTR_MEMx::INSTR_MEM.val(instr as u32));
1644            used_mask |= mask;
1645        }
1646        // update the mask of used instructions slots
1647        self.instructions_used
1648            .set(self.instructions_used.get() | used_mask);
1649        Ok(LoadedProgram {
1650            used_memory: used_mask,
1651            origin,
1652        })
1653    }
1654
1655    /// Clears all of a PIO instance's instruction memory.
1656    pub fn clear_instr_registers(&self) {
1657        for i in 0..NUMBER_INSTR_MEMORY_LOCATIONS {
1658            self.registers.instr_mem[i]
1659                .instr_mem
1660                .modify(INSTR_MEMx::INSTR_MEM::CLEAR);
1661        }
1662
1663        // update the mask of used instructions slots
1664        self.instructions_used.set(0);
1665    }
1666
1667    /// Initialize a new PIO with the same default configuration for all four state machines.
1668    pub fn init(&self) {
1669        let default_config: StateMachineConfiguration = StateMachineConfiguration::default();
1670        for state_machine in self.sms.iter() {
1671            state_machine.config(&default_config);
1672        }
1673        self.clear_instr_registers()
1674    }
1675}
1676
1677mod examples {
1678    use kernel::hil::gpio::Configure;
1679
1680    use super::{
1681        debug, Pio, RPGpio, RPGpioPin, Readable, SMNumber, SMx_EXECCTRL, SMx_INSTR, SMx_PINCTRL,
1682        StateMachineConfiguration, DBG_PADOUT, FDEBUG,
1683    };
1684
1685    impl RPGpio {
1686        fn from_u32(value: u32) -> RPGpio {
1687            match value {
1688                0 => RPGpio::GPIO0,
1689                1 => RPGpio::GPIO1,
1690                2 => RPGpio::GPIO2,
1691                3 => RPGpio::GPIO3,
1692                4 => RPGpio::GPIO4,
1693                5 => RPGpio::GPIO5,
1694                6 => RPGpio::GPIO6,
1695                7 => RPGpio::GPIO7,
1696                8 => RPGpio::GPIO8,
1697                9 => RPGpio::GPIO9,
1698                10 => RPGpio::GPIO10,
1699                11 => RPGpio::GPIO11,
1700                12 => RPGpio::GPIO12,
1701                13 => RPGpio::GPIO13,
1702                14 => RPGpio::GPIO14,
1703                15 => RPGpio::GPIO15,
1704                16 => RPGpio::GPIO16,
1705                17 => RPGpio::GPIO17,
1706                18 => RPGpio::GPIO18,
1707                19 => RPGpio::GPIO19,
1708                20 => RPGpio::GPIO20,
1709                21 => RPGpio::GPIO21,
1710                22 => RPGpio::GPIO22,
1711                23 => RPGpio::GPIO23,
1712                24 => RPGpio::GPIO24,
1713                25 => RPGpio::GPIO25,
1714                26 => RPGpio::GPIO26,
1715                27 => RPGpio::GPIO27,
1716                28 => RPGpio::GPIO28,
1717                29 => RPGpio::GPIO29,
1718                _ => panic!(
1719                    "Unknown value for GPIO pin: {} (should be from 0 to 29)",
1720                    value
1721                ),
1722            }
1723        }
1724    }
1725
1726    impl Pio {
1727        // # Examples
1728        /// Used for the examples in the pico explorer base main.rs file.
1729
1730        pub fn blinking_hello_program_init(
1731            &self,
1732            sm_number: SMNumber,
1733            pin: u32,
1734            config: &StateMachineConfiguration,
1735        ) {
1736            let sm = &self.sms[sm_number as usize];
1737            sm.config(config);
1738            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(pin)));
1739            sm.set_enabled(false);
1740            sm.set_pins_dirs(pin, 1, true);
1741            sm.set_set_pins(pin, 1);
1742            sm.init();
1743            sm.set_enabled(true);
1744        }
1745
1746        pub fn blink_program_init(
1747            &self,
1748            sm_number: SMNumber,
1749            pin: u32,
1750            config: &StateMachineConfiguration,
1751        ) {
1752            let sm = &self.sms[sm_number as usize];
1753            sm.config(config);
1754            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(pin)));
1755            sm.set_enabled(false);
1756            sm.set_pins_dirs(pin, 1, true);
1757            sm.set_set_pins(pin, 1);
1758            sm.init();
1759            sm.set_enabled(true);
1760        }
1761
1762        pub fn sideset_program_init(
1763            &self,
1764            sm_number: SMNumber,
1765            pin: u32,
1766            config: &StateMachineConfiguration,
1767        ) {
1768            let sm = &self.sms[sm_number as usize];
1769            sm.config(config);
1770            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(pin)));
1771            self.gpio_init(&RPGpioPin::new(RPGpio::GPIO7));
1772            sm.set_enabled(false);
1773            sm.set_pins_dirs(pin, 1, true);
1774            sm.set_pins_dirs(7, 1, true);
1775            sm.set_set_pins(pin, 1);
1776            sm.set_side_set_pins(7, 1, false, true);
1777            sm.init();
1778            sm.set_enabled(true);
1779        }
1780
1781        pub fn hello_program_init(
1782            &self,
1783            sm_number: SMNumber,
1784            pin1: u32,
1785            pin2: u32,
1786            config: &StateMachineConfiguration,
1787        ) {
1788            let sm = &self.sms[sm_number as usize];
1789            // This is used to turn on specifically GPIOs 6 and 7 - LSB is for GPIO 0, next bit is for GPIO 1 etc.
1790            let turn_on_gpio_6_7 = 0b11000000;
1791            sm.config(config);
1792            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(pin1)));
1793            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(pin2)));
1794            sm.set_enabled(false);
1795            sm.set_pins_dirs(pin1, 1, true);
1796            sm.set_pins_dirs(pin2, 1, true);
1797            sm.init();
1798            sm.set_enabled(true);
1799            let _ = sm.push_blocking(turn_on_gpio_6_7);
1800            let _ = sm.push_blocking(0);
1801        }
1802
1803        pub fn pwm_program_init(
1804            &self,
1805            sm_number: SMNumber,
1806            pin: u32,
1807            pwm_period: u32,
1808            config: &StateMachineConfiguration,
1809        ) {
1810            let sm = &self.sms[sm_number as usize];
1811            // "pull" command created by pioasm
1812            let pull_command = 0x8080_u16;
1813            // "out isr, 32" command created by pioasm
1814            let out_isr_32_command = 0x60c0_u16;
1815            sm.config(config);
1816            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(pin)));
1817            sm.set_enabled(false);
1818            sm.set_pins_dirs(pin, 1, true);
1819            sm.set_side_set_pins(pin, 1, false, true);
1820            sm.init();
1821            let _ = sm.push_blocking(pwm_period);
1822            sm.exec(pull_command);
1823            sm.exec(out_isr_32_command);
1824            sm.set_enabled(true);
1825        }
1826
1827        pub fn spi_program_init(
1828            &self,
1829            sm_number: SMNumber,
1830            clock_pin: u32,
1831            in_pin: u32,
1832            out_pin: u32,
1833            config: &StateMachineConfiguration,
1834        ) {
1835            let sm = &self.sms[sm_number as usize];
1836            sm.config(config);
1837            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(clock_pin)));
1838            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(in_pin)));
1839            self.gpio_init(&RPGpioPin::new(RPGpio::from_u32(out_pin)));
1840            sm.set_enabled(false);
1841
1842            // Important: make the sideset pin an output pin then make it a side set pin
1843            // and make sure to do all of this BEFORE setting the outpin as an outpin
1844            sm.set_out_pins(clock_pin, 1);
1845            sm.set_pins_dirs(clock_pin, 1, true);
1846            sm.set_side_set_pins(clock_pin, 1, false, false); // Do not switch pin dirs again, it will mess with the output settings
1847
1848            sm.set_pins_dirs(out_pin, 1, true);
1849            sm.set_out_pins(out_pin, config.out_pins_count);
1850
1851            sm.init();
1852            sm.clear_fifos();
1853            sm.set_enabled(true);
1854        }
1855
1856        pub fn cyw43_spi_program_init(
1857            &self,
1858            sm_number: SMNumber,
1859            clock_pin: u32,
1860            dio_pin: u32,
1861            config: &StateMachineConfiguration,
1862        ) {
1863            let sm = &self.sms[sm_number as usize];
1864            sm.set_enabled(false);
1865            sm.config(config);
1866            let clock_pin_handle = RPGpioPin::new(RPGpio::from_u32(clock_pin));
1867            let dio_pin_handle = RPGpioPin::new(RPGpio::from_u32(dio_pin));
1868            self.gpio_init(&clock_pin_handle);
1869            self.gpio_init(&dio_pin_handle);
1870
1871            dio_pin_handle.set_floating_state(kernel::hil::gpio::FloatingState::PullNone);
1872            dio_pin_handle.set_schmitt(true);
1873            self.set_input_sync_bypass(&dio_pin_handle, true);
1874            dio_pin_handle.set_drive_strength(crate::gpio::DriveStrength::Drive12ma);
1875            dio_pin_handle.set_slew_rate(crate::gpio::SlewRate::Fast);
1876            dio_pin_handle.activate_pads();
1877
1878            clock_pin_handle.set_drive_strength(crate::gpio::DriveStrength::Drive12ma);
1879            clock_pin_handle.set_slew_rate(crate::gpio::SlewRate::Fast);
1880            clock_pin_handle.set_floating_state(kernel::hil::gpio::FloatingState::PullNone);
1881            clock_pin_handle.set_schmitt(true);
1882            clock_pin_handle.set_slew_rate(crate::gpio::SlewRate::Slow);
1883            clock_pin_handle.activate_pads();
1884
1885            sm.set_pins_dirs(dio_pin, 1, true);
1886            sm.set_pins_dirs(clock_pin, 1, true);
1887
1888            sm.set_pins(&[&clock_pin_handle, &dio_pin_handle], false);
1889
1890            sm.init();
1891            sm.clear_fifos();
1892            sm.set_enabled(true);
1893        }
1894
1895        // # Debugging
1896        /// Returns current instruction running on the state machine.
1897        pub fn read_instr(&self, sm_number: SMNumber) -> u32 {
1898            self.registers.sm[sm_number as usize]
1899                .instr
1900                .read(SMx_INSTR::INSTR)
1901        }
1902
1903        pub fn read_sideset_reg(&self, sm_number: SMNumber) {
1904            debug!(
1905                "{}",
1906                self.registers.sm[sm_number as usize]
1907                    .pinctrl
1908                    .read(SMx_PINCTRL::SIDESET_COUNT)
1909            );
1910            debug!(
1911                "{}",
1912                self.registers.sm[sm_number as usize]
1913                    .execctrl
1914                    .read(SMx_EXECCTRL::SIDE_EN)
1915            );
1916            debug!(
1917                "{}",
1918                self.registers.sm[sm_number as usize]
1919                    .execctrl
1920                    .read(SMx_EXECCTRL::SIDE_PINDIR)
1921            );
1922            debug!(
1923                "{}",
1924                self.registers.sm[sm_number as usize]
1925                    .pinctrl
1926                    .read(SMx_PINCTRL::SIDESET_BASE)
1927            );
1928        }
1929
1930        pub fn read_dbg_padout(&self) -> u32 {
1931            self.registers.dbg_padout.read(DBG_PADOUT::DBG_PADOUT)
1932        }
1933
1934        pub fn read_fdebug(&self, tx: bool, stall: bool) -> u32 {
1935            if tx {
1936                if stall {
1937                    self.registers.fdebug.read(FDEBUG::TXSTALL)
1938                } else {
1939                    self.registers.fdebug.read(FDEBUG::TXOVER)
1940                }
1941            } else if stall {
1942                self.registers.fdebug.read(FDEBUG::RXSTALL)
1943            } else {
1944                self.registers.fdebug.read(FDEBUG::RXUNDER)
1945            }
1946        }
1947    }
1948}