Skip to content

Commit ee332b5

Browse files
Fix some pio examples to work with gpios >= 32 (#577)
* Fix some pio examples to work with gpios >= 32 Use pio_claim_free_sm_and_add_program_for_gpio_range as a good example of how you should find a free pio and state machine that's compatible with a particular gpio.
1 parent da4e50d commit ee332b5

File tree

7 files changed

+118
-72
lines changed

7 files changed

+118
-72
lines changed

pio/hello_pio/hello.c

+5
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@
1717
#define HELLO_PIO_LED_PIN PICO_DEFAULT_LED_PIN
1818
#endif
1919

20+
// Check the pin is compatible with the platform
21+
#if HELLO_PIO_LED_PIN >= NUM_BANK0_GPIOS
22+
#error Attempting to use a pin>=32 on a platform that does not support it
23+
#endif
24+
2025
int main() {
2126
#ifndef HELLO_PIO_LED_PIN
2227
#warning pio/hello_pio example requires a board with a regular LED

pio/uart_rx/uart_rx.c

+19-3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
#define HARD_UART_TX_PIN 4
2727
#define PIO_RX_PIN 3
2828

29+
// Check the pin is compatible with the platform
30+
#if PIO_RX_PIN >= NUM_BANK0_GPIOS
31+
#error Attempting to use a pin>=32 on a platform that does not support it
32+
#endif
33+
2934
// Ask core 1 to print a string, to make things easier on core 0
3035
void core1_main() {
3136
const char *s = (const char *) multicore_fifo_pop_blocking();
@@ -42,10 +47,18 @@ int main() {
4247
gpio_set_function(HARD_UART_TX_PIN, GPIO_FUNC_UART);
4348

4449
// Set up the state machine we're going to use to receive them.
45-
PIO pio = pio0;
46-
uint sm = 0;
47-
uint offset = pio_add_program(pio, &uart_rx_program);
50+
PIO pio;
51+
uint sm;
52+
uint offset;
53+
54+
// This will find a free pio and state machine for our program and load it for us
55+
// We use pio_claim_free_sm_and_add_program_for_gpio_range (for_gpio_range variant)
56+
// so we will get a PIO instance suitable for addressing gpios >= 32 if needed and supported by the hardware
57+
bool success = pio_claim_free_sm_and_add_program_for_gpio_range(&uart_rx_program, &pio, &sm, &offset, PIO_RX_PIN, 1, true);
58+
hard_assert(success);
59+
4860
uart_rx_program_init(pio, sm, offset, PIO_RX_PIN, SERIAL_BAUD);
61+
//uart_rx_mini_program_init(pio, sm, offset, PIO_RX_PIN, SERIAL_BAUD);
4962

5063
// Tell core 1 to print some text to uart1 as fast as it can
5164
multicore_launch_core1(core1_main);
@@ -57,4 +70,7 @@ int main() {
5770
char c = uart_rx_program_getc(pio, sm);
5871
putchar(c);
5972
}
73+
74+
// This will free resources and unload our program
75+
pio_remove_program_and_unclaim_sm(&uart_rx_program, pio, sm, offset);
6076
}

pio/uart_rx/uart_rx_intr.c

+17-35
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@
3535
#define FIFO_SIZE 64
3636
#define MAX_COUNTER 10
3737

38+
// Check the pin is compatible with the platform
39+
#if PIO_RX_PIN >= NUM_BANK0_GPIOS
40+
#error Attempting to use a pin>=32 on a platform that does not support it
41+
#endif
42+
3843
static PIO pio;
3944
static uint sm;
4045
static int8_t pio_irq;
@@ -84,27 +89,6 @@ static void async_worker_func(__unused async_context_t *async_context, __unused
8489
}
8590
}
8691

87-
// Find a free pio and state machine and load the program into it.
88-
// Returns false if this fails
89-
static bool init_pio(const pio_program_t *program, PIO *pio_hw, uint *sm, uint *offset) {
90-
// Find a free pio
91-
*pio_hw = pio1;
92-
if (!pio_can_add_program(*pio_hw, program)) {
93-
*pio_hw = pio0;
94-
if (!pio_can_add_program(*pio_hw, program)) {
95-
*offset = -1;
96-
return false;
97-
}
98-
}
99-
*offset = pio_add_program(*pio_hw, program);
100-
// Find a state machine
101-
*sm = (int8_t)pio_claim_unused_sm(*pio_hw, false);
102-
if (*sm < 0) {
103-
return false;
104-
}
105-
return true;
106-
}
107-
10892
int main() {
10993
// Console output (also a UART, yes it's confusing)
11094
setup_default_uart();
@@ -123,16 +107,16 @@ int main() {
123107
}
124108
async_context_add_when_pending_worker(&async_context.core, &worker);
125109

126-
// Set up the state machine we're going to use to receive them.
127-
// In real code you need to find a free pio and state machine in case pio resources are used elsewhere
128-
if (!init_pio(&uart_rx_program, &pio, &sm, &offset)) {
129-
panic("failed to setup pio");
130-
}
110+
// This will find a free pio and state machine for our program and load it for us
111+
// We use pio_claim_free_sm_and_add_program_for_gpio_range (for_gpio_range variant)
112+
// so we will get a PIO instance suitable for addressing gpios >= 32 if needed and supported by the hardware
113+
bool success = pio_claim_free_sm_and_add_program_for_gpio_range(&uart_rx_program, &pio, &sm, &offset, PIO_RX_PIN, 1, true);
114+
hard_assert(success);
115+
131116
uart_rx_program_init(pio, sm, offset, PIO_RX_PIN, SERIAL_BAUD);
132117

133118
// Find a free irq
134-
static_assert(PIO0_IRQ_1 == PIO0_IRQ_0 + 1 && PIO1_IRQ_1 == PIO1_IRQ_0 + 1, "");
135-
pio_irq = (pio == pio0) ? PIO0_IRQ_0 : PIO1_IRQ_0;
119+
pio_irq = pio_get_irq_num(pio, 0);
136120
if (irq_get_exclusive_handler(pio_irq)) {
137121
pio_irq++;
138122
if (irq_get_exclusive_handler(pio_irq)) {
@@ -143,8 +127,8 @@ int main() {
143127
// Enable interrupt
144128
irq_add_shared_handler(pio_irq, pio_irq_func, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY); // Add a shared IRQ handler
145129
irq_set_enabled(pio_irq, true); // Enable the IRQ
146-
const uint irq_index = pio_irq - ((pio == pio0) ? PIO0_IRQ_0 : PIO1_IRQ_0); // Get index of the IRQ
147-
pio_set_irqn_source_enabled(pio, irq_index, pis_sm0_rx_fifo_not_empty + sm, true); // Set pio to tell us when the FIFO is NOT empty
130+
const uint irq_index = pio_irq - pio_get_irq_num(pio, 0); // Get index of the IRQ
131+
pio_set_irqn_source_enabled(pio, irq_index, pio_get_rx_fifo_not_empty_interrupt_source(sm), true); // Set pio to tell us when the FIFO is NOT empty
148132

149133
// Tell core 1 to print text to uart1
150134
multicore_launch_core1(core1_main);
@@ -160,14 +144,12 @@ int main() {
160144
}
161145

162146
// Disable interrupt
163-
pio_set_irqn_source_enabled(pio, irq_index, pis_sm0_rx_fifo_not_empty + sm, false);
147+
pio_set_irqn_source_enabled(pio, irq_index, pio_get_rx_fifo_not_empty_interrupt_source(sm), false);
164148
irq_set_enabled(pio_irq, false);
165149
irq_remove_handler(pio_irq, pio_irq_func);
166150

167-
// Cleanup pio
168-
pio_sm_set_enabled(pio, sm, false);
169-
pio_remove_program(pio, &uart_rx_program, offset);
170-
pio_sm_unclaim(pio, sm);
151+
// This will free resources and unload our program
152+
pio_remove_program_and_unclaim_sm(&uart_rx_program, pio, sm, offset);
171153

172154
async_context_remove_when_pending_worker(&async_context.core, &worker);
173155
async_context_deinit(&async_context.core);

pio/uart_tx/uart_tx.c

+24-8
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,36 @@
88
#include "hardware/pio.h"
99
#include "uart_tx.pio.h"
1010

11+
// We're going to use PIO to print "Hello, world!" on the same GPIO which we
12+
// normally attach UART0 to.
13+
#define PIO_TX_PIN 0
14+
15+
// Check the pin is compatible with the platform
16+
#if PIO_TX_PIN >= NUM_BANK0_GPIOS
17+
#error Attempting to use a pin>=32 on a platform that does not support it
18+
#endif
19+
1120
int main() {
12-
// We're going to use PIO to print "Hello, world!" on the same GPIO which we
13-
// normally attach UART0 to.
14-
const uint PIN_TX = 0;
1521
// This is the same as the default UART baud rate on Pico
1622
const uint SERIAL_BAUD = 115200;
1723

18-
PIO pio = pio0;
19-
uint sm = 0;
20-
uint offset = pio_add_program(pio, &uart_tx_program);
21-
uart_tx_program_init(pio, sm, offset, PIN_TX, SERIAL_BAUD);
24+
PIO pio;
25+
uint sm;
26+
uint offset;
27+
28+
// This will find a free pio and state machine for our program and load it for us
29+
// We use pio_claim_free_sm_and_add_program_for_gpio_range (for_gpio_range variant)
30+
// so we will get a PIO instance suitable for addressing gpios >= 32 if needed and supported by the hardware
31+
bool success = pio_claim_free_sm_and_add_program_for_gpio_range(&uart_tx_program, &pio, &sm, &offset, PIO_TX_PIN, 1, true);
32+
hard_assert(success);
33+
34+
uart_tx_program_init(pio, sm, offset, PIO_TX_PIN, SERIAL_BAUD);
2235

2336
while (true) {
24-
uart_tx_program_puts(pio, sm, "Hello, world! (from PIO!)\n");
37+
uart_tx_program_puts(pio, sm, "Hello, world! (from PIO!)\r\n");
2538
sleep_ms(1000);
2639
}
40+
41+
// This will free resources and unload our program
42+
pio_remove_program_and_unclaim_sm(&uart_tx_program, pio, sm, offset);
2743
}

pio/uart_tx/uart_tx.pio

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ bitloop: ; This loop will run 8 times (8n1 UART)
2424
static inline void uart_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx, uint baud) {
2525
// Tell PIO to initially drive output-high on the selected pin, then map PIO
2626
// onto that pin with the IO muxes.
27-
pio_sm_set_pins_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
28-
pio_sm_set_pindirs_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
27+
pio_sm_set_pins_with_mask64(pio, sm, 1ull << pin_tx, 1ull << pin_tx);
28+
pio_sm_set_pindirs_with_mask64(pio, sm, 1ull << pin_tx, 1ull << pin_tx);
2929
pio_gpio_init(pio, pin_tx);
3030

3131
pio_sm_config c = uart_tx_program_get_default_config(offset);

pio/ws2812/ws2812.c

+33-19
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,13 @@
3535
#define WS2812_PIN 2
3636
#endif
3737

38-
static inline void put_pixel(uint32_t pixel_grb) {
39-
pio_sm_put_blocking(pio0, 0, pixel_grb << 8u);
38+
// Check the pin is compatible with the platform
39+
#if WS2812_PIN >= NUM_BANK0_GPIOS
40+
#error Attempting to use a pin>=32 on a platform that does not support it
41+
#endif
42+
43+
static inline void put_pixel(PIO pio, uint sm, uint32_t pixel_grb) {
44+
pio_sm_put_blocking(pio, sm, pixel_grb << 8u);
4045
}
4146

4247
static inline uint32_t urgb_u32(uint8_t r, uint8_t g, uint8_t b) {
@@ -54,44 +59,44 @@ static inline uint32_t urgbw_u32(uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
5459
(uint32_t) (b);
5560
}
5661

57-
void pattern_snakes(uint len, uint t) {
62+
void pattern_snakes(PIO pio, uint sm, uint len, uint t) {
5863
for (uint i = 0; i < len; ++i) {
5964
uint x = (i + (t >> 1)) % 64;
6065
if (x < 10)
61-
put_pixel(urgb_u32(0xff, 0, 0));
66+
put_pixel(pio, sm, urgb_u32(0xff, 0, 0));
6267
else if (x >= 15 && x < 25)
63-
put_pixel(urgb_u32(0, 0xff, 0));
68+
put_pixel(pio, sm, urgb_u32(0, 0xff, 0));
6469
else if (x >= 30 && x < 40)
65-
put_pixel(urgb_u32(0, 0, 0xff));
70+
put_pixel(pio, sm, urgb_u32(0, 0, 0xff));
6671
else
67-
put_pixel(0);
72+
put_pixel(pio, sm, 0);
6873
}
6974
}
7075

71-
void pattern_random(uint len, uint t) {
76+
void pattern_random(PIO pio, uint sm, uint len, uint t) {
7277
if (t % 8)
7378
return;
7479
for (uint i = 0; i < len; ++i)
75-
put_pixel(rand());
80+
put_pixel(pio, sm, rand());
7681
}
7782

78-
void pattern_sparkle(uint len, uint t) {
83+
void pattern_sparkle(PIO pio, uint sm, uint len, uint t) {
7984
if (t % 8)
8085
return;
8186
for (uint i = 0; i < len; ++i)
82-
put_pixel(rand() % 16 ? 0 : 0xffffffff);
87+
put_pixel(pio, sm, rand() % 16 ? 0 : 0xffffffff);
8388
}
8489

85-
void pattern_greys(uint len, uint t) {
90+
void pattern_greys(PIO pio, uint sm, uint len, uint t) {
8691
uint max = 100; // let's not draw too much current!
8792
t %= max;
8893
for (uint i = 0; i < len; ++i) {
89-
put_pixel(t * 0x10101);
94+
put_pixel(pio, sm, t * 0x10101);
9095
if (++t >= max) t = 0;
9196
}
9297
}
9398

94-
typedef void (*pattern)(uint len, uint t);
99+
typedef void (*pattern)(PIO pio, uint sm, uint len, uint t);
95100
const struct {
96101
pattern pat;
97102
const char *name;
@@ -105,12 +110,18 @@ const struct {
105110
int main() {
106111
//set_sys_clock_48();
107112
stdio_init_all();
108-
printf("WS2812 Smoke Test, using pin %d", WS2812_PIN);
113+
printf("WS2812 Smoke Test, using pin %d\n", WS2812_PIN);
109114

110115
// todo get free sm
111-
PIO pio = pio0;
112-
int sm = 0;
113-
uint offset = pio_add_program(pio, &ws2812_program);
116+
PIO pio;
117+
uint sm;
118+
uint offset;
119+
120+
// This will find a free pio and state machine for our program and load it for us
121+
// We use pio_claim_free_sm_and_add_program_for_gpio_range (for_gpio_range variant)
122+
// so we will get a PIO instance suitable for addressing gpios >= 32 if needed and supported by the hardware
123+
bool success = pio_claim_free_sm_and_add_program_for_gpio_range(&ws2812_program, &pio, &sm, &offset, WS2812_PIN, 1, true);
124+
hard_assert(success);
114125

115126
ws2812_program_init(pio, sm, offset, WS2812_PIN, 800000, IS_RGBW);
116127

@@ -121,9 +132,12 @@ int main() {
121132
puts(pattern_table[pat].name);
122133
puts(dir == 1 ? "(forward)" : "(backward)");
123134
for (int i = 0; i < 1000; ++i) {
124-
pattern_table[pat].pat(NUM_PIXELS, t);
135+
pattern_table[pat].pat(pio, sm, NUM_PIXELS, t);
125136
sleep_ms(10);
126137
t += dir;
127138
}
128139
}
140+
141+
// This will free resources and unload our program
142+
pio_remove_program_and_unclaim_sm(&ws2812_program, pio, sm, offset);
129143
}

pio/ws2812/ws2812_parallel.c

+18-5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
#define NUM_PIXELS 64
2020
#define WS2812_PIN_BASE 2
2121

22+
// Check the pin is compatible with the platform
23+
#if WS2812_PIN_BASE >= NUM_BANK0_GPIOS
24+
#error Attempting to use a pin>=32 on a platform that does not support it
25+
#endif
26+
2227
// horrible temporary hack to avoid changing pattern code
2328
static uint8_t *current_strip_out;
2429
static bool current_strip_4color;
@@ -278,12 +283,17 @@ void output_strips_dma(value_bits_t *bits, uint value_length) {
278283
int main() {
279284
//set_sys_clock_48();
280285
stdio_init_all();
281-
puts("WS2812 parallel");
286+
printf("WS2812 parallel using pin %d\n", WS2812_PIN_BASE);
287+
288+
PIO pio;
289+
uint sm;
290+
uint offset;
282291

283-
// todo get free sm
284-
PIO pio = pio0;
285-
int sm = 0;
286-
uint offset = pio_add_program(pio, &ws2812_parallel_program);
292+
// This will find a free pio and state machine for our program and load it for us
293+
// We use pio_claim_free_sm_and_add_program_for_gpio_range (for_gpio_range variant)
294+
// so we will get a PIO instance suitable for addressing gpios >= 32 if needed and supported by the hardware
295+
bool success = pio_claim_free_sm_and_add_program_for_gpio_range(&ws2812_parallel_program, &pio, &sm, &offset, WS2812_PIN_BASE, count_of(strips), true);
296+
hard_assert(success);
287297

288298
ws2812_parallel_program_init(pio, sm, offset, WS2812_PIN_BASE, count_of(strips), 800000);
289299

@@ -318,4 +328,7 @@ int main() {
318328
}
319329
memset(&states, 0, sizeof(states)); // clear out errors
320330
}
331+
332+
// This will free resources and unload our program
333+
pio_remove_program_and_unclaim_sm(&ws2812_parallel_program, pio, sm, offset);
321334
}

0 commit comments

Comments
 (0)