aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorMichael van Niekerk <[email protected]>2023-07-24 22:20:00 +0200
committerMichael van Niekerk <[email protected]>2023-07-24 22:20:00 +0200
commita60d92cfbbacc909ba781802cad04fe00e849026 (patch)
tree90763431421f9fedde70727a9260453b50e9739b /examples
parent18b9b6c780b46165ead1de59ce258bd78786bdcb (diff)
Tx and Rx setup
Diffstat (limited to 'examples')
-rw-r--r--examples/rp/.idea/.gitignore8
-rw-r--r--examples/rp/.idea/modules.xml8
-rw-r--r--examples/rp/.idea/rp.iml12
-rw-r--r--examples/rp/.idea/vcs.xml6
-rw-r--r--examples/rp/src/bin/pio_uart.rs262
5 files changed, 296 insertions, 0 deletions
diff --git a/examples/rp/.idea/.gitignore b/examples/rp/.idea/.gitignore
new file mode 100644
index 000000000..13566b81b
--- /dev/null
+++ b/examples/rp/.idea/.gitignore
@@ -0,0 +1,8 @@
1# Default ignored files
2/shelf/
3/workspace.xml
4# Editor-based HTTP Client requests
5/httpRequests/
6# Datasource local storage ignored files
7/dataSources/
8/dataSources.local.xml
diff --git a/examples/rp/.idea/modules.xml b/examples/rp/.idea/modules.xml
new file mode 100644
index 000000000..06ff4b23d
--- /dev/null
+++ b/examples/rp/.idea/modules.xml
@@ -0,0 +1,8 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<project version="4">
3 <component name="ProjectModuleManager">
4 <modules>
5 <module fileurl="file://$PROJECT_DIR$/.idea/rp.iml" filepath="$PROJECT_DIR$/.idea/rp.iml" />
6 </modules>
7 </component>
8</project> \ No newline at end of file
diff --git a/examples/rp/.idea/rp.iml b/examples/rp/.idea/rp.iml
new file mode 100644
index 000000000..9b4cf845b
--- /dev/null
+++ b/examples/rp/.idea/rp.iml
@@ -0,0 +1,12 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<module type="JAVA_MODULE" version="4">
3 <component name="NewModuleRootManager" inherit-compiler-output="true">
4 <exclude-output />
5 <content url="file://$MODULE_DIR$">
6 <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
7 <excludeFolder url="file://$MODULE_DIR$/target" />
8 </content>
9 <orderEntry type="inheritedJdk" />
10 <orderEntry type="sourceFolder" forTests="false" />
11 </component>
12</module> \ No newline at end of file
diff --git a/examples/rp/.idea/vcs.xml b/examples/rp/.idea/vcs.xml
new file mode 100644
index 000000000..b2bdec2d7
--- /dev/null
+++ b/examples/rp/.idea/vcs.xml
@@ -0,0 +1,6 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<project version="4">
3 <component name="VcsDirectoryMappings">
4 <mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
5 </component>
6</project> \ No newline at end of file
diff --git a/examples/rp/src/bin/pio_uart.rs b/examples/rp/src/bin/pio_uart.rs
new file mode 100644
index 000000000..14d05f4db
--- /dev/null
+++ b/examples/rp/src/bin/pio_uart.rs
@@ -0,0 +1,262 @@
1//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip.
2//!
3//! This creates a USB serial port that echos.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use defmt::{info, panic};
10use embassy_executor::Spawner;
11use embassy_futures::join::join;
12use embassy_rp::bind_interrupts;
13use embassy_rp::peripherals::{PIO0, USB};
14use embassy_rp::usb::{Driver, Instance, InterruptHandler};
15use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
16use embassy_usb::driver::EndpointError;
17use embassy_usb::{Builder, Config};
18use embassy_rp::pio::{InterruptHandler as PioInterruptHandler};
19use {defmt_rtt as _, panic_probe as _};
20
21bind_interrupts!(struct UsbIrqs {
22 USBCTRL_IRQ => InterruptHandler<USB>;
23});
24
25bind_interrupts!(struct PioIrqs {
26 PIO0_IRQ_0 => PioInterruptHandler<PIO0>;
27});
28
29#[embassy_executor::main]
30async fn main(_spawner: Spawner) {
31 info!("Hello there!");
32
33 let p = embassy_rp::init(Default::default());
34
35 // Create the driver, from the HAL.
36 let driver = Driver::new(p.USB, UsbIrqs);
37
38 // Create embassy-usb Config
39 let mut config = Config::new(0xc0de, 0xcafe);
40 config.manufacturer = Some("Embassy");
41 config.product = Some("PIO UART example");
42 config.serial_number = Some("12345678");
43 config.max_power = 100;
44 config.max_packet_size_0 = 64;
45
46 // Required for windows compatibility.
47 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
48 config.device_class = 0xEF;
49 config.device_sub_class = 0x02;
50 config.device_protocol = 0x01;
51 config.composite_with_iads = true;
52
53 // Create embassy-usb DeviceBuilder using the driver and config.
54 // It needs some buffers for building the descriptors.
55 let mut device_descriptor = [0; 256];
56 let mut config_descriptor = [0; 256];
57 let mut bos_descriptor = [0; 256];
58 let mut control_buf = [0; 64];
59
60 let mut state = State::new();
61
62 let mut builder = Builder::new(
63 driver,
64 config,
65 &mut device_descriptor,
66 &mut config_descriptor,
67 &mut bos_descriptor,
68 &mut control_buf,
69 );
70
71 // Create classes on the builder.
72 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
73
74 // Build the builder.
75 let mut usb = builder.build();
76
77 // Run the USB device.
78 let usb_fut = usb.run();
79
80 // Do stuff with the class!
81 let echo_fut = async {
82 loop {
83 class.wait_connection().await;
84 info!("Connected");
85 let _ = echo(&mut class).await;
86 info!("Disconnected");
87 }
88 };
89
90 // Run everything concurrently.
91 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
92 join(usb_fut, echo_fut).await;
93}
94
95struct Disconnected {}
96
97impl From<EndpointError> for Disconnected {
98 fn from(val: EndpointError) -> Self {
99 match val {
100 EndpointError::BufferOverflow => panic!("Buffer overflow"),
101 EndpointError::Disabled => Disconnected {},
102 }
103 }
104}
105
106async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
107 let mut buf = [0; 64];
108 loop {
109 let n = class.read_packet(&mut buf).await?;
110 let data = &buf[..n];
111 info!("data: {:x}", data);
112 class.write_packet(data).await?;
113 }
114}
115
116mod uart {
117 use embassy_rp::peripherals::PIO0;
118 use embassy_rp::pio::{Common, Pio, PioPin, StateMachine};
119 use embassy_rp::Peripheral;
120
121 use crate::PioIrqs;
122
123 pub struct PioUart<'a> {
124 baud: u64,
125 pio: Common<'a, PIO0>,
126 sm0: StateMachine<'a, PIO0, 0>,
127 sm1: StateMachine<'a, PIO0, 1>,
128 }
129
130 impl<'a> PioUart<'a> {
131 pub async fn new(
132 baud: u64,
133 pio: impl Peripheral<P = PIO0> + 'a,
134 tx_pin: impl PioPin,
135 rx_pin: impl PioPin,
136 ) -> PioUart<'a> {
137 let Pio {
138 mut common,
139 mut sm0,
140 mut sm1,
141 ..
142 } = Pio::new(pio, PioIrqs);
143
144 crate::uart_tx::setup_uart_tx_on_sm0(&mut common, &mut sm0, tx_pin, baud);
145 crate::uart_rx::setup_uart_rx_on_sm1(&mut common, &mut sm1, rx_pin, baud);
146
147 PioUart {
148 baud,
149 pio: common,
150 sm0,
151 sm1,
152 }
153 }
154 }
155}
156
157mod uart_tx {
158 use embassy_rp::gpio::Level;
159 use embassy_rp::peripherals::PIO0;
160 use embassy_rp::pio::{Common, Config, Direction, FifoJoin, PioPin, ShiftDirection, StateMachine};
161 use embassy_rp::relocate::RelocatedProgram;
162 use fixed::traits::ToFixed;
163 use fixed_macro::types::U56F8;
164
165 pub fn setup_uart_tx_on_sm0<'a>(
166 common: &mut Common<'a, PIO0>,
167 sm_tx: &mut StateMachine<'a, PIO0, 0>,
168 tx_pin: impl PioPin,
169 baud: u64,
170 ) {
171 let prg = pio_proc::pio_asm!(
172 r#"
173 ;.program uart_tx
174 .side_set 1 opt
175
176 ; An 8n1 UART transmit program.
177 ; OUT pin 0 and side-set pin 0 are both mapped to UART TX pin.
178
179 pull side 1 [7] ; Assert stop bit, or stall with line in idle state
180 set x, 7 side 0 [7] ; Preload bit counter, assert start bit for 8 clocks
181 bitloop: ; This loop will run 8 times (8n1 UART)
182 out pins, 1 ; Shift 1 bit from OSR to the first OUT pin
183 jmp x-- bitloop [6] ; Each loop iteration is 8 cycles.
184 "#
185 );
186 let tx_pin = common.make_pio_pin(tx_pin);
187 sm_tx.set_pins(Level::High, &[&tx_pin]);
188 sm_tx.set_pin_dirs(Direction::Out, &[&tx_pin]);
189
190 let relocated = RelocatedProgram::new(&prg.program);
191 let mut cfg = Config::default();
192
193 cfg.use_program(&common.load_program(&relocated), &[&tx_pin]);
194 cfg.clock_divider = (U56F8!(125_000_000) / (8 * baud)).to_fixed();
195 cfg.shift_out.auto_fill = false;
196 cfg.shift_out.direction = ShiftDirection::Right;
197 cfg.fifo_join = FifoJoin::TxOnly;
198 cfg.set_out_pins(&[&tx_pin]);
199 cfg.set_set_pins(&[&tx_pin]);
200 sm_tx.set_config(&cfg);
201 sm_tx.set_enable(true)
202 }
203}
204
205mod uart_rx {
206 use embassy_rp::gpio::Level;
207 use embassy_rp::peripherals::PIO0;
208 use embassy_rp::pio::{Common, Config, Direction, FifoJoin, PioPin, ShiftDirection, StateMachine};
209 use embassy_rp::relocate::RelocatedProgram;
210 use fixed::traits::ToFixed;
211 use fixed_macro::types::U56F8;
212
213 pub fn setup_uart_rx_on_sm1<'a>(
214 common: &mut Common<'a, PIO0>,
215 sm_rx: &mut StateMachine<'a, PIO0, 1>,
216 rx_pin: impl PioPin,
217 baud: u64,
218 ) {
219 let prg = pio_proc::pio_asm!(
220 r#"
221 ;.program uart_rx
222
223 ; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and
224 ; break conditions more gracefully.
225 ; IN pin 0 and JMP pin are both mapped to the GPIO used as UART RX.
226
227 start:
228 wait 0 pin 0 ; Stall until start bit is asserted
229 set x, 7 [10] ; Preload bit counter, then delay until halfway through
230 bitloop: ; the first data bit (12 cycles incl wait, set).
231 in pins, 1 ; Shift data bit into ISR
232 jmp x-- bitloop [6] ; Loop 8 times, each loop iteration is 8 cycles
233 jmp pin good_stop ; Check stop bit (should be high)
234
235 irq 4 rel ; Either a framing error or a break. Set a sticky flag,
236 wait 1 pin 0 ; and wait for line to return to idle state.
237 jmp start ; Don't push data if we didn't see good framing.
238
239 good_stop: ; No delay before returning to start; a little slack is
240 push ; important in case the TX clock is slightly too fast.
241 "#
242 );
243
244 let rx_pin = common.make_pio_pin(rx_pin);
245 sm_rx.set_pins(Level::High, &[&rx_pin]);
246 sm_rx.set_pin_dirs(Direction::In, &[&rx_pin]);
247
248 let relocated = RelocatedProgram::new(&prg.program);
249 let mut cfg = Config::default();
250
251 cfg.use_program(&common.load_program(&relocated), &[&rx_pin]);
252 cfg.clock_divider = (U56F8!(125_000_000) / (8 * baud)).to_fixed();
253 cfg.shift_out.auto_fill = false;
254 cfg.shift_out.direction = ShiftDirection::Right;
255 cfg.fifo_join = FifoJoin::RxOnly;
256 cfg.set_in_pins(&[&rx_pin]);
257 cfg.set_jmp_pin(&rx_pin);
258 // cfg.set_set_pins(&[&rx_pin]);
259 sm_rx.set_config(&cfg);
260 sm_rx.set_enable(true)
261 }
262}