Skip to content

Commit abb9562

Browse files
committed
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 362f676 commit abb9562

File tree

7 files changed

+113
-72
lines changed

7 files changed

+113
-72
lines changed

pio/hello_pio/hello.c

Lines changed: 5 additions & 0 deletions
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

Lines changed: 18 additions & 3 deletions
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,17 @@ 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 so we can address gpios >= 32 if needed and supported by the hardware
56+
bool success = pio_claim_free_sm_and_add_program_for_gpio_range(&uart_rx_program, &pio, &sm, &offset, PIO_RX_PIN, 1, true);
57+
hard_assert(success);
58+
4859
uart_rx_program_init(pio, sm, offset, PIO_RX_PIN, SERIAL_BAUD);
60+
//uart_rx_mini_program_init(pio, sm, offset, PIO_RX_PIN, SERIAL_BAUD);
4961

5062
// Tell core 1 to print some text to uart1 as fast as it can
5163
multicore_launch_core1(core1_main);
@@ -57,4 +69,7 @@ int main() {
5769
char c = uart_rx_program_getc(pio, sm);
5870
putchar(c);
5971
}
72+
73+
// This will free resources and unload our program
74+
pio_remove_program_and_unclaim_sm(&uart_rx_program, pio, sm, offset);
6075
}

pio/uart_rx/uart_rx_intr.c

Lines changed: 16 additions & 35 deletions
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,15 @@ 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 so we can address gpios >= 32 if needed and supported by the hardware
112+
bool success = pio_claim_free_sm_and_add_program_for_gpio_range(&uart_rx_program, &pio, &sm, &offset, PIO_RX_PIN, 1, true);
113+
hard_assert(success);
114+
131115
uart_rx_program_init(pio, sm, offset, PIO_RX_PIN, SERIAL_BAUD);
132116

133117
// 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;
118+
pio_irq = pio_get_irq_num(pio, 0);
136119
if (irq_get_exclusive_handler(pio_irq)) {
137120
pio_irq++;
138121
if (irq_get_exclusive_handler(pio_irq)) {
@@ -143,8 +126,8 @@ int main() {
143126
// Enable interrupt
144127
irq_add_shared_handler(pio_irq, pio_irq_func, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY); // Add a shared IRQ handler
145128
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
129+
const uint irq_index = pio_irq - pio_get_irq_num(pio, 0); // Get index of the IRQ
130+
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
148131

149132
// Tell core 1 to print text to uart1
150133
multicore_launch_core1(core1_main);
@@ -160,14 +143,12 @@ int main() {
160143
}
161144

162145
// Disable interrupt
163-
pio_set_irqn_source_enabled(pio, irq_index, pis_sm0_rx_fifo_not_empty + sm, false);
146+
pio_set_irqn_source_enabled(pio, irq_index, pio_get_rx_fifo_not_empty_interrupt_source(sm), false);
164147
irq_set_enabled(pio_irq, false);
165148
irq_remove_handler(pio_irq, pio_irq_func);
166149

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);
150+
// This will free resources and unload our program
151+
pio_remove_program_and_unclaim_sm(&uart_rx_program, pio, sm, offset);
171152

172153
async_context_remove_when_pending_worker(&async_context.core, &worker);
173154
async_context_deinit(&async_context.core);

pio/uart_tx/uart_tx.c

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,35 @@
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 so we can address gpios >= 32 if needed and supported by the hardware
30+
bool success = pio_claim_free_sm_and_add_program_for_gpio_range(&uart_tx_program, &pio, &sm, &offset, PIO_TX_PIN, 1, true);
31+
hard_assert(success);
32+
33+
uart_tx_program_init(pio, sm, offset, PIO_TX_PIN, SERIAL_BAUD);
2234

2335
while (true) {
24-
uart_tx_program_puts(pio, sm, "Hello, world! (from PIO!)\n");
36+
uart_tx_program_puts(pio, sm, "Hello, world! (from PIO!)\r\n");
2537
sleep_ms(1000);
2638
}
39+
40+
// This will free resources and unload our program
41+
pio_remove_program_and_unclaim_sm(&uart_tx_program, pio, sm, offset);
2742
}

pio/uart_tx/uart_tx.pio

Lines changed: 2 additions & 2 deletions
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

Lines changed: 32 additions & 19 deletions
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,17 @@ 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 so we can address gpios >= 32 if needed and supported by the hardware
122+
bool success = pio_claim_free_sm_and_add_program_for_gpio_range(&ws2812_program, &pio, &sm, &offset, WS2812_PIN, 1, true);
123+
hard_assert(success);
114124

115125
ws2812_program_init(pio, sm, offset, WS2812_PIN, 800000, IS_RGBW);
116126

@@ -121,9 +131,12 @@ int main() {
121131
puts(pattern_table[pat].name);
122132
puts(dir == 1 ? "(forward)" : "(backward)");
123133
for (int i = 0; i < 1000; ++i) {
124-
pattern_table[pat].pat(NUM_PIXELS, t);
134+
pattern_table[pat].pat(pio, sm, NUM_PIXELS, t);
125135
sleep_ms(10);
126136
t += dir;
127137
}
128138
}
139+
140+
// This will free resources and unload our program
141+
pio_remove_program_and_unclaim_sm(&ws2812_program, pio, sm, offset);
129142
}

pio/ws2812/ws2812_parallel.c

Lines changed: 17 additions & 5 deletions
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,16 @@ 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 so we can address gpios >= 32 if needed and supported by the hardware
294+
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);
295+
hard_assert(success);
287296

288297
ws2812_parallel_program_init(pio, sm, offset, WS2812_PIN_BASE, count_of(strips), 800000);
289298

@@ -318,4 +327,7 @@ int main() {
318327
}
319328
memset(&states, 0, sizeof(states)); // clear out errors
320329
}
330+
331+
// This will free resources and unload our program
332+
pio_remove_program_and_unclaim_sm(&ws2812_parallel_program, pio, sm, offset);
321333
}

0 commit comments

Comments
 (0)