Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix some pio examples to work with gpios >= 32 #577

Merged
merged 3 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions pio/hello_pio/hello.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
#define HELLO_PIO_LED_PIN PICO_DEFAULT_LED_PIN
#endif

// Check the pin is compatible with the platform
#if HELLO_PIO_LED_PIN >= NUM_BANK0_GPIOS
#error Attempting to use a pin>=32 on a platform that does not support it
#endif

int main() {
#ifndef HELLO_PIO_LED_PIN
#warning pio/hello_pio example requires a board with a regular LED
Expand Down
22 changes: 19 additions & 3 deletions pio/uart_rx/uart_rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
#define HARD_UART_TX_PIN 4
#define PIO_RX_PIN 3

// Check the pin is compatible with the platform
#if PIO_RX_PIN >= NUM_BANK0_GPIOS
#error Attempting to use a pin>=32 on a platform that does not support it
#endif

// Ask core 1 to print a string, to make things easier on core 0
void core1_main() {
const char *s = (const char *) multicore_fifo_pop_blocking();
Expand All @@ -42,10 +47,18 @@ int main() {
gpio_set_function(HARD_UART_TX_PIN, GPIO_FUNC_UART);

// Set up the state machine we're going to use to receive them.
PIO pio = pio0;
uint sm = 0;
uint offset = pio_add_program(pio, &uart_rx_program);
PIO pio;
uint sm;
uint offset;

// This will find a free pio and state machine for our program and load it for us
// We use pio_claim_free_sm_and_add_program_for_gpio_range (for_gpio_range variant)
// so we will get a PIO instance suitable for addressing gpios >= 32 if needed and supported by the hardware
bool success = pio_claim_free_sm_and_add_program_for_gpio_range(&uart_rx_program, &pio, &sm, &offset, PIO_RX_PIN, 1, true);
hard_assert(success);

uart_rx_program_init(pio, sm, offset, PIO_RX_PIN, SERIAL_BAUD);
//uart_rx_mini_program_init(pio, sm, offset, PIO_RX_PIN, SERIAL_BAUD);

// Tell core 1 to print some text to uart1 as fast as it can
multicore_launch_core1(core1_main);
Expand All @@ -57,4 +70,7 @@ int main() {
char c = uart_rx_program_getc(pio, sm);
putchar(c);
}

// This will free resources and unload our program
pio_remove_program_and_unclaim_sm(&uart_rx_program, pio, sm, offset);
}
52 changes: 17 additions & 35 deletions pio/uart_rx/uart_rx_intr.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@
#define FIFO_SIZE 64
#define MAX_COUNTER 10

// Check the pin is compatible with the platform
#if PIO_RX_PIN >= NUM_BANK0_GPIOS
#error Attempting to use a pin>=32 on a platform that does not support it
#endif

static PIO pio;
static uint sm;
static int8_t pio_irq;
Expand Down Expand Up @@ -84,27 +89,6 @@ static void async_worker_func(__unused async_context_t *async_context, __unused
}
}

// Find a free pio and state machine and load the program into it.
// Returns false if this fails
static bool init_pio(const pio_program_t *program, PIO *pio_hw, uint *sm, uint *offset) {
// Find a free pio
*pio_hw = pio1;
if (!pio_can_add_program(*pio_hw, program)) {
*pio_hw = pio0;
if (!pio_can_add_program(*pio_hw, program)) {
*offset = -1;
return false;
}
}
*offset = pio_add_program(*pio_hw, program);
// Find a state machine
*sm = (int8_t)pio_claim_unused_sm(*pio_hw, false);
if (*sm < 0) {
return false;
}
return true;
}

int main() {
// Console output (also a UART, yes it's confusing)
setup_default_uart();
Expand All @@ -123,16 +107,16 @@ int main() {
}
async_context_add_when_pending_worker(&async_context.core, &worker);

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

uart_rx_program_init(pio, sm, offset, PIO_RX_PIN, SERIAL_BAUD);

// Find a free irq
static_assert(PIO0_IRQ_1 == PIO0_IRQ_0 + 1 && PIO1_IRQ_1 == PIO1_IRQ_0 + 1, "");
pio_irq = (pio == pio0) ? PIO0_IRQ_0 : PIO1_IRQ_0;
pio_irq = pio_get_irq_num(pio, 0);
if (irq_get_exclusive_handler(pio_irq)) {
pio_irq++;
if (irq_get_exclusive_handler(pio_irq)) {
Expand All @@ -143,8 +127,8 @@ int main() {
// Enable interrupt
irq_add_shared_handler(pio_irq, pio_irq_func, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY); // Add a shared IRQ handler
irq_set_enabled(pio_irq, true); // Enable the IRQ
const uint irq_index = pio_irq - ((pio == pio0) ? PIO0_IRQ_0 : PIO1_IRQ_0); // Get index of the IRQ
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
const uint irq_index = pio_irq - pio_get_irq_num(pio, 0); // Get index of the IRQ
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

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

// Disable interrupt
pio_set_irqn_source_enabled(pio, irq_index, pis_sm0_rx_fifo_not_empty + sm, false);
pio_set_irqn_source_enabled(pio, irq_index, pio_get_rx_fifo_not_empty_interrupt_source(sm), false);
irq_set_enabled(pio_irq, false);
irq_remove_handler(pio_irq, pio_irq_func);

// Cleanup pio
pio_sm_set_enabled(pio, sm, false);
pio_remove_program(pio, &uart_rx_program, offset);
pio_sm_unclaim(pio, sm);
// This will free resources and unload our program
pio_remove_program_and_unclaim_sm(&uart_rx_program, pio, sm, offset);

async_context_remove_when_pending_worker(&async_context.core, &worker);
async_context_deinit(&async_context.core);
Expand Down
32 changes: 24 additions & 8 deletions pio/uart_tx/uart_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,36 @@
#include "hardware/pio.h"
#include "uart_tx.pio.h"

// We're going to use PIO to print "Hello, world!" on the same GPIO which we
// normally attach UART0 to.
#define PIO_TX_PIN 0

// Check the pin is compatible with the platform
#if PIO_TX_PIN >= NUM_BANK0_GPIOS
#error Attempting to use a pin>=32 on a platform that does not support it
#endif

int main() {
// We're going to use PIO to print "Hello, world!" on the same GPIO which we
// normally attach UART0 to.
const uint PIN_TX = 0;
// This is the same as the default UART baud rate on Pico
const uint SERIAL_BAUD = 115200;

PIO pio = pio0;
uint sm = 0;
uint offset = pio_add_program(pio, &uart_tx_program);
uart_tx_program_init(pio, sm, offset, PIN_TX, SERIAL_BAUD);
PIO pio;
uint sm;
uint offset;

// This will find a free pio and state machine for our program and load it for us
// We use pio_claim_free_sm_and_add_program_for_gpio_range (for_gpio_range variant)
// so we will get a PIO instance suitable for addressing gpios >= 32 if needed and supported by the hardware
bool success = pio_claim_free_sm_and_add_program_for_gpio_range(&uart_tx_program, &pio, &sm, &offset, PIO_TX_PIN, 1, true);
hard_assert(success);

uart_tx_program_init(pio, sm, offset, PIO_TX_PIN, SERIAL_BAUD);

while (true) {
uart_tx_program_puts(pio, sm, "Hello, world! (from PIO!)\n");
uart_tx_program_puts(pio, sm, "Hello, world! (from PIO!)\r\n");
sleep_ms(1000);
}

// This will free resources and unload our program
pio_remove_program_and_unclaim_sm(&uart_tx_program, pio, sm, offset);
}
4 changes: 2 additions & 2 deletions pio/uart_tx/uart_tx.pio
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ bitloop: ; This loop will run 8 times (8n1 UART)
static inline void uart_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx, uint baud) {
// Tell PIO to initially drive output-high on the selected pin, then map PIO
// onto that pin with the IO muxes.
pio_sm_set_pins_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
pio_sm_set_pindirs_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
pio_sm_set_pins_with_mask64(pio, sm, 1ull << pin_tx, 1ull << pin_tx);
pio_sm_set_pindirs_with_mask64(pio, sm, 1ull << pin_tx, 1ull << pin_tx);
pio_gpio_init(pio, pin_tx);

pio_sm_config c = uart_tx_program_get_default_config(offset);
Expand Down
52 changes: 33 additions & 19 deletions pio/ws2812/ws2812.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,13 @@
#define WS2812_PIN 2
#endif

static inline void put_pixel(uint32_t pixel_grb) {
pio_sm_put_blocking(pio0, 0, pixel_grb << 8u);
// Check the pin is compatible with the platform
#if WS2812_PIN >= NUM_BANK0_GPIOS
#error Attempting to use a pin>=32 on a platform that does not support it
#endif

static inline void put_pixel(PIO pio, uint sm, uint32_t pixel_grb) {
pio_sm_put_blocking(pio, sm, pixel_grb << 8u);
}

static inline uint32_t urgb_u32(uint8_t r, uint8_t g, uint8_t b) {
Expand All @@ -54,44 +59,44 @@ static inline uint32_t urgbw_u32(uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
(uint32_t) (b);
}

void pattern_snakes(uint len, uint t) {
void pattern_snakes(PIO pio, uint sm, uint len, uint t) {
for (uint i = 0; i < len; ++i) {
uint x = (i + (t >> 1)) % 64;
if (x < 10)
put_pixel(urgb_u32(0xff, 0, 0));
put_pixel(pio, sm, urgb_u32(0xff, 0, 0));
else if (x >= 15 && x < 25)
put_pixel(urgb_u32(0, 0xff, 0));
put_pixel(pio, sm, urgb_u32(0, 0xff, 0));
else if (x >= 30 && x < 40)
put_pixel(urgb_u32(0, 0, 0xff));
put_pixel(pio, sm, urgb_u32(0, 0, 0xff));
else
put_pixel(0);
put_pixel(pio, sm, 0);
}
}

void pattern_random(uint len, uint t) {
void pattern_random(PIO pio, uint sm, uint len, uint t) {
if (t % 8)
return;
for (uint i = 0; i < len; ++i)
put_pixel(rand());
put_pixel(pio, sm, rand());
}

void pattern_sparkle(uint len, uint t) {
void pattern_sparkle(PIO pio, uint sm, uint len, uint t) {
if (t % 8)
return;
for (uint i = 0; i < len; ++i)
put_pixel(rand() % 16 ? 0 : 0xffffffff);
put_pixel(pio, sm, rand() % 16 ? 0 : 0xffffffff);
}

void pattern_greys(uint len, uint t) {
void pattern_greys(PIO pio, uint sm, uint len, uint t) {
uint max = 100; // let's not draw too much current!
t %= max;
for (uint i = 0; i < len; ++i) {
put_pixel(t * 0x10101);
put_pixel(pio, sm, t * 0x10101);
if (++t >= max) t = 0;
}
}

typedef void (*pattern)(uint len, uint t);
typedef void (*pattern)(PIO pio, uint sm, uint len, uint t);
const struct {
pattern pat;
const char *name;
Expand All @@ -105,12 +110,18 @@ const struct {
int main() {
//set_sys_clock_48();
stdio_init_all();
printf("WS2812 Smoke Test, using pin %d", WS2812_PIN);
printf("WS2812 Smoke Test, using pin %d\n", WS2812_PIN);

// todo get free sm
PIO pio = pio0;
int sm = 0;
uint offset = pio_add_program(pio, &ws2812_program);
PIO pio;
uint sm;
uint offset;

// This will find a free pio and state machine for our program and load it for us
// We use pio_claim_free_sm_and_add_program_for_gpio_range (for_gpio_range variant)
// so we will get a PIO instance suitable for addressing gpios >= 32 if needed and supported by the hardware
bool success = pio_claim_free_sm_and_add_program_for_gpio_range(&ws2812_program, &pio, &sm, &offset, WS2812_PIN, 1, true);
hard_assert(success);

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

Expand All @@ -121,9 +132,12 @@ int main() {
puts(pattern_table[pat].name);
puts(dir == 1 ? "(forward)" : "(backward)");
for (int i = 0; i < 1000; ++i) {
pattern_table[pat].pat(NUM_PIXELS, t);
pattern_table[pat].pat(pio, sm, NUM_PIXELS, t);
sleep_ms(10);
t += dir;
}
}

// This will free resources and unload our program
pio_remove_program_and_unclaim_sm(&ws2812_program, pio, sm, offset);
}
23 changes: 18 additions & 5 deletions pio/ws2812/ws2812_parallel.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
#define NUM_PIXELS 64
#define WS2812_PIN_BASE 2

// Check the pin is compatible with the platform
#if WS2812_PIN_BASE >= NUM_BANK0_GPIOS
#error Attempting to use a pin>=32 on a platform that does not support it
#endif

// horrible temporary hack to avoid changing pattern code
static uint8_t *current_strip_out;
static bool current_strip_4color;
Expand Down Expand Up @@ -278,12 +283,17 @@ void output_strips_dma(value_bits_t *bits, uint value_length) {
int main() {
//set_sys_clock_48();
stdio_init_all();
puts("WS2812 parallel");
printf("WS2812 parallel using pin %d\n", WS2812_PIN_BASE);

PIO pio;
uint sm;
uint offset;

// todo get free sm
PIO pio = pio0;
int sm = 0;
uint offset = pio_add_program(pio, &ws2812_parallel_program);
// This will find a free pio and state machine for our program and load it for us
// We use pio_claim_free_sm_and_add_program_for_gpio_range (for_gpio_range variant)
// so we will get a PIO instance suitable for addressing gpios >= 32 if needed and supported by the hardware
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);
hard_assert(success);

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

Expand Down Expand Up @@ -318,4 +328,7 @@ int main() {
}
memset(&states, 0, sizeof(states)); // clear out errors
}

// This will free resources and unload our program
pio_remove_program_and_unclaim_sm(&ws2812_parallel_program, pio, sm, offset);
}
Loading