Select one of the symbols to view example projects that use it.
 
Outline
#include <stdio.h>
#include <stdlib.h>
#include "pico/stdlib.h"
#include "pico/multicore.h"
#include "pico/util/queue.h"
#include "pico/async_context_threadsafe_background.h"
#include "hardware/pio.h"
#include "hardware/uart.h"
#include "uart_rx.pio.h"
#define SERIAL_BAUD
#define HARD_UART_INST
#define HARD_UART_TX_PIN
#define PIO_RX_PIN
#define FIFO_SIZE
#define MAX_COUNTER
pio
sm
pio_irq
fifo
offset
counter
work_done
core1_main()
async_context
worker
pio_irq_func()
async_worker_func(async_context_t *, async_when_pending_worker_t *)
init_pio(const pio_program_t *, PIO *, uint *, uint *)
main()
Files
loading...
SourceVuRaspberry Pi Pico SDK and Examplesuart_rx sampleuart_rx_intr.c
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/** * Copyright (c) 2023 Raspberry Pi (Trading) Ltd. * * SPDX-License-Identifier: BSD-3-Clause *//* ... */ #include <stdio.h> #include <stdlib.h> #include "pico/stdlib.h" #include "pico/multicore.h" #include "pico/util/queue.h" #include "pico/async_context_threadsafe_background.h" #include "hardware/pio.h" #include "hardware/uart.h" #include "uart_rx.pio.h" 9 includes // This program // - Uses UART1 (the spare UART, by default) to transmit some text // - Uses a PIO state machine to receive that text // - Use an interrupt to determine when the PIO FIFO has some data // - Saves characters in a queue // - Uses an async context to perform work when notified by the irq // - Prints out the received text to the default console (UART0) // This might require some reconfiguration on boards where UART1 is the // default UART. #define SERIAL_BAUD PICO_DEFAULT_UART_BAUD_RATE #define HARD_UART_INST uart1 // You'll need a wire from GPIO4 -> GPIO3 #define HARD_UART_TX_PIN 4 #define PIO_RX_PIN 3 #define FIFO_SIZE 64 #define MAX_COUNTER 10 6 defines static PIO pio; static uint sm; static int8_t pio_irq; static queue_t fifo; static uint offset; static uint32_t counter; static bool work_done; // Ask core 1 to print a string, to make things easier on core 0 static void core1_main() { while(counter < MAX_COUNTER) { sleep_ms(1000 + (rand() % 1000)); static char text[64]; sprintf(text, "Hello, world from PIO with interrupts! %u\n", counter++); uart_puts(HARD_UART_INST, text); }while (counter < MAX_COUNTER) { ... } }{ ... } static void async_worker_func(async_context_t *async_context, async_when_pending_worker_t *worker); // An async context is notified by the irq to "do some work" static async_context_threadsafe_background_t async_context; static async_when_pending_worker_t worker = { .do_work = async_worker_func }; // IRQ called when the pio fifo is not empty, i.e. there are some characters on the uart // This needs to run as quickly as possible or else you will lose characters (in particular don't printf!) static void pio_irq_func(void) { while(!pio_sm_is_rx_fifo_empty(pio, sm)) { char c = uart_rx_program_getc(pio, sm); if (!queue_try_add(&fifo, &c)) { panic("fifo full"); }if (!queue_try_add(&fifo, &c)) { ... } }while (!pio_sm_is_rx_fifo_empty(pio, sm)) { ... } // Tell the async worker that there are some characters waiting for us async_context_set_work_pending(&async_context.core, &worker); }{ ... } // Process characters static void async_worker_func(__unused async_context_t *async_context, __unused async_when_pending_worker_t *worker) { work_done = true; while(!queue_is_empty(&fifo)) { char c; if (!queue_try_remove(&fifo, &c)) { panic("fifo empty"); }if (!queue_try_remove(&fifo, &c)) { ... } putchar(c); // Display character in the console }while (!queue_is_empty(&fifo)) { ... } }{ ... } // 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; }if (!pio_can_add_program(*pio_hw, program)) { ... } }if (!pio_can_add_program(*pio_hw, program)) { ... } *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; }if (*sm < 0) { ... } return true; }{ ... } int main() { // Console output (also a UART, yes it's confusing) setup_default_uart(); printf("Starting PIO UART RX interrupt example\n"); // Set up the hard UART we're going to use to print characters uart_init(HARD_UART_INST, SERIAL_BAUD); gpio_set_function(HARD_UART_TX_PIN, GPIO_FUNC_UART); // create a queue so the irq can save the data somewhere queue_init(&fifo, 1, FIFO_SIZE); // Setup an async context and worker to perform work when needed if (!async_context_threadsafe_background_init_with_defaults(&async_context)) { panic("failed to setup context"); }if (!async_context_threadsafe_background_init_with_defaults(&async_context)) { ... } 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"); }if (!init_pio(&uart_rx_program, &pio, &sm, &offset)) { ... } 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; if (irq_get_exclusive_handler(pio_irq)) { pio_irq++; if (irq_get_exclusive_handler(pio_irq)) { panic("All IRQs are in use"); }if (irq_get_exclusive_handler(pio_irq)) { ... } }if (irq_get_exclusive_handler(pio_irq)) { ... } // 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 // Tell core 1 to print text to uart1 multicore_launch_core1(core1_main); // Echo characters received from PIO to the console while (counter < MAX_COUNTER || work_done) { // Note that we could just sleep here as we're using "threadsafe_background" that uses a low priority interrupt // But if we changed to use a "polling" context that wouldn't work. The following works for both types of context. // When using "threadsafe_background" the poll does nothing. This loop is just preventing main from exiting! work_done = false; async_context_poll(&async_context.core); async_context_wait_for_work_ms(&async_context.core, 2000); }while (counter < MAX_COUNTER || work_done) { ... } // Disable interrupt pio_set_irqn_source_enabled(pio, irq_index, pis_sm0_rx_fifo_not_empty + 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); async_context_remove_when_pending_worker(&async_context.core, &worker); async_context_deinit(&async_context.core); queue_free(&fifo); uart_deinit(HARD_UART_INST); printf("Test complete\n"); sleep_ms(100); return 0; }{ ... }
Details
Show:
from
Types: Columns:
This file uses the notable symbols shown below. Click anywhere in the file to view more details.