YAHAL
Yet Another Hardware Abstraction Library
Loading...
Searching...
No Matches
pio_rp2040.h
1/*
2 * pio_rp2040.h
3 *
4 * Created on: 25.12.2022
5 * Author: andreas
6 */
7
8#ifndef _PIO_RP2040_H_
9#define _PIO_RP2040_H_
10
11#include "RP2040.h"
12using namespace _PIO0_;
13
14#include <cstdint>
15#include <functional>
16using std::function;
17
18// enums and methods to generate state machine instructions
19
21// JMP //
23enum class jmp_cond_t : uint16_t {
24 always = 0,
25 Xzero = 1,
26 Xdec = 2,
27 Yzero = 3,
28 Ydec = 4,
29 XnotY = 5,
30 PIN = 6,
31 OSRnot_empty = 7
32};
33
34inline uint16_t op_JMP(uint8_t delay_sideset,
35 jmp_cond_t cond,
36 uint8_t addr) {
37 return 0x0000 |
38 ((delay_sideset & 0x1f) << 8) |
39 (static_cast<uint16_t>(cond) << 5) |
40 (addr & 0x1f);
41}
42
43inline bool is_JMP(uint16_t opcode) {
44 return (opcode & 0xe000) == 0;
45}
46
48// WAIT //
50enum class wait_pol_t : uint16_t {
51 wait_for_1 = 1,
52 wait_for_0 = 0
53};
54
55enum class wait_src_t : uint16_t {
56 GPIO = 0,
57 PIN = 1,
58 IRQ = 2
59};
60
61inline uint16_t op_WAIT(uint8_t delay_sideset,
62 wait_pol_t polarity,
63 wait_src_t source,
64 uint8_t index) {
65 return 0x2000 |
66 ((delay_sideset & 0x1f) << 8) |
67 (static_cast<uint16_t>(polarity) << 7) |
68 (static_cast<uint16_t>(source) << 5) |
69 (index & 0x1f);
70}
71
73// IN //
75enum class in_src_t : uint16_t {
76 PINS = 0,
77 X = 1,
78 Y = 2,
79 ZEROS = 3,
80 ISR = 6,
81 OSR = 7
82};
83
84inline uint16_t op_IN(uint8_t delay_sideset,
85 in_src_t src,
86 uint8_t bitcount) {
87 return 0x4000 |
88 ((delay_sideset & 0x1f) << 8) |
89 (static_cast<uint16_t>(src) << 5) |
90 (bitcount & 0x1f);
91}
92
94// OUT //
96enum class out_dest_t : uint16_t {
97 PINS = 0,
98 X = 1,
99 Y = 2,
100 ZEROS = 3,
101 PINDIRS = 4,
102 PC = 5,
103 ISR = 6,
104 EXEC = 7
105};
106
107inline uint16_t op_OUT(uint8_t delay_sideset,
108 out_dest_t dest,
109 uint8_t bitcount) {
110 return 0x6000 |
111 ((delay_sideset & 0x1f) << 8) |
112 (static_cast<uint16_t>(dest) << 5) |
113 (bitcount & 0x1f);
114}
115
117// PUSH //
119const uint16_t IFFULL = 0x40;
120const uint16_t BLOCK = 0x20;
121
122inline uint16_t op_PUSH(uint8_t delay_sideset,
123 uint16_t flags) {
124 return 0x8000 |
125 ((delay_sideset & 0x1f) << 8) |
126 flags;
127}
128
130// PULL //
132inline uint16_t op_PULL(uint8_t delay_sideset,
133 uint16_t flags) {
134 return 0x8080 |
135 ((delay_sideset & 0x1f) << 8) |
136 flags;
137}
138
140// MOV //
142enum class mov_dest_t : uint16_t {
143 PINS = 0,
144 X = 1,
145 Y = 2,
146 EXEC = 4,
147 PC = 5,
148 ISR = 6,
149 OSR = 7
150};
151
152enum class mov_op_t : uint16_t {
153 NONE = 0,
154 INVERT = 1,
155 BIT_REVERSE = 2
156};
157
158enum class mov_src_t : uint16_t {
159 PINS = 0,
160 X = 1,
161 Y = 2,
162 ZEROS = 3,
163 STATUS = 5,
164 ISR = 6,
165 OSR = 7
166};
167
168inline uint16_t op_MOV(uint8_t delay_sideset,
169 mov_dest_t dest,
170 mov_op_t op,
171 mov_src_t src) {
172 return 0xa000 |
173 ((delay_sideset & 0x1f) << 8) |
174 (static_cast<uint16_t>(dest) << 5) |
175 (static_cast<uint16_t>(op) << 3) |
176 (static_cast<uint16_t>(src));
177}
178
180// IRQ //
182const uint32_t CLR = 0x40;
183const uint32_t WAIT = 0x20;
184
185inline uint16_t op_IRQ(uint8_t delay_sideset,
186 uint16_t flags,
187 uint8_t index) {
188 return 0xc000 |
189 ((delay_sideset & 0x1f) << 8) |
190 flags |
191 (index & 0x1f);
192}
193
195// SET //
197enum class set_dest_t : uint16_t {
198 PINS = 0,
199 X = 1,
200 Y = 2,
201 PINDIRS = 4
202};
203
204inline uint16_t op_SET(uint8_t delay_sideset,
205 set_dest_t dest,
206 uint8_t data) {
207 return 0xe000 |
208 ((delay_sideset & 0x1f) << 8) |
209 (static_cast<uint16_t>(dest) << 5) |
210 (data & 0x1f);
211}
212
213// Struct to mirror the registers of a single SM.
214// Will be used inside the SM struct (see below).
215struct SM_regs {
216 SM_CLKDIV_t SM_CLKDIV;
217 SM_EXECCTRL_t SM_EXECCTRL;
218 SM_SHIFTCTRL_t SM_SHIFTCTRL;
219 SM_ADDR_t SM_ADDR;
220 SM_INSTR_t SM_INSTR;
221 SM_PINCTRL_t SM_PINCTRL;
222 // Initialize SM registers with reset values;
223 void init();
224};
225
226// Struct for a single SM.
227struct SM {
228 PIO0_t & pio;
229 PIO0_t & pio_set;
230 PIO0_t & pio_clr;
231 uint8_t pio_index;
232 uint8_t sm_index;
233 uint8_t load_addr;
234 SM_regs & regs;
235
236 SM(PIO0_t & p, PIO0_t & ps, PIO0_t & pc, uint8_t pi,
237 uint8_t smi, uint8_t l, SM_regs & r)
238 : pio(p), pio_set(ps), pio_clr(pc), pio_index(pi),
239 sm_index(smi), load_addr(l), regs(r) {
240 regs.init();
241 }
242
243 // Execute a single PIO instruction
244 inline void execute(uint16_t instruction) {
245 regs.SM_INSTR = instruction;
246 }
247
248 // Set a PIO register. Default is to write a 32-bit word,
249 // but offset and size can be specified to only change
250 // specific bits. Any register which is handled by the
251 // OUT instruction can be used.
252 void setRegister(out_dest_t reg, uint32_t val,
253 uint8_t offset = 0, uint8_t size = 32);
254
255 // Set the PIO clock
256 void setClock(uint32_t hz);
257
258 // Check if TX FIFO is full.
259 inline bool TxFifoFull() const {
260 return pio.FSTAT.TXFULL & (1 << sm_index);
261 }
262
263 // Check if TX FIFO is empty.
264 inline bool TxFifoEmpty() const {
265 return pio.FSTAT.TXEMPTY & (1 << sm_index);
266 }
267
268 // Check if RX FIFO is empty.
269 inline bool RxFifoEmpty() const {
270 return pio.FSTAT.RXEMPTY & (1 << sm_index);
271 }
272
273 // Write a 32 bit value to the TX FIFO
274 inline void writeTxFifo(uint32_t val) {
275 while(TxFifoFull()) ;
276 pio.TXF[sm_index] = val;
277 }
278
279 // Read a 32 bit value from the RX FIFO
280 inline uint32_t readRxFifo() {
281 while(RxFifoEmpty()) ;
282 return pio.RXF[sm_index];
283 }
284
285 // Set the WRAP addresses. Parameters are relative to
286 // the load address!
287 inline void setWrap(uint8_t bottom, uint8_t top) {
288 regs.SM_EXECCTRL.WRAP_BOTTOM = bottom + load_addr;
289 regs.SM_EXECCTRL.WRAP_TOP = top + load_addr;
290 }
291
292 // Enable the SM
293 inline void enable() {
294 pio_set.CTRL.SM_ENABLE = (1 << sm_index);
295 }
296
297 // Disable the SM
298 inline void disable() {
299 pio_clr.CTRL.SM_ENABLE = (1 << sm_index);
300 }
301
302 // Check if SM is enabled
303 inline bool isEnabled() const {
304 return pio.CTRL.SM_ENABLE & (1 << sm_index);
305 }
306
307 inline bool isStalled() {
308 // Clear old stall-status
309 pio.FDEBUG.TXSTALL = (1 << sm_index);
310 pio.FDEBUG.RXSTALL = (1 << sm_index);
311 return (pio.FDEBUG.TXSTALL & (1 << sm_index)) ||
312 (pio.FDEBUG.RXSTALL & (1 << sm_index));
313 }
314
315 void attachIrq(function<void()> handler);
316 void enableIrq();
317 void disableIrq();
318
319 void attachTXNFULLIrq(function<void()> handler);
320 void enableTXNFULLIrq();
321 void disableTXNFULLIrq();
322
323 void attachRXNEMPTYIrq(function<void()> handler);
324 void enableRXNEMPTYIrq();
325 void disableRXNEMPTYIrq();
326};
327
328// Struct for a PIO programm (used in the generated code
329// of the PIO assembler)
331 const uint16_t *instructions;
332 uint8_t length;
333 int8_t origin; // required instruction memory origin or -1
334};
335
336// PIO control class
338public:
339 virtual ~pio_rp2040();
340
341 // The two static PIO singletons
342 static pio_rp2040 pio0;
343 static pio_rp2040 pio1;
344
345 SM* loadProgram(const pio_program & prgm);
346
347 static function<void()> _handler_pio0[12];
348 static function<void()> _handler_pio1[12];
349
350private:
351 pio_rp2040(PIO0_t & pio, uint8_t pio_index);
352 PIO0_t & _pio;
353 PIO0_t & _pio_xor;
354 PIO0_t & _pio_set;
355 PIO0_t & _pio_clr;
356 uint8_t _pio_index;
357 uint8_t _next_free_addr;
358 SM_regs * _sm_regbanks;
359 bool _in_use[4];
360
361};
362
363#endif // _PIO_RP2040_H_
CMSIS-Core(M) Device Peripheral Access Layer Header File for Device RP2040.