Skip to content

Commit b5a7949

Browse files
yonschcarlescufi
authored andcommitted
drivers: serial: Added rpi_pico driver over PIO
Implements a UART driver using PIO. Both PIOs are supported. Only polling API is supported. Only 8N1 mode is supported. Signed-off-by: Yonatan Schachter <yonatan.schachter@gmail.com>
1 parent 5abb1b1 commit b5a7949

File tree

5 files changed

+218
-0
lines changed

5 files changed

+218
-0
lines changed

boards/arm/rpi_pico/doc/index.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ hardware features:
8181
* - Flash
8282
- :kconfig:option:`CONFIG_FLASH`
8383
- :dtcompatible:`raspberrypi,pico-flash`
84+
* - UART (PIO)
85+
- :kconfig:option:`CONFIG_SERIAL`
86+
- :dtcompatible:`raspberrypi,pico-uart-pio`
8487

8588
Pin Mapping
8689
===========

drivers/serial/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_PL011 uart_pl011.c)
3636
zephyr_library_sources_ifdef(CONFIG_UART_QUICKLOGIC_USBSERIALPORT_S3B uart_ql_usbserialport_s3b.c)
3737
zephyr_library_sources_ifdef(CONFIG_UART_RV32M1_LPUART uart_rv32m1_lpuart.c)
3838
zephyr_library_sources_ifdef(CONFIG_UART_RPI_PICO uart_rpi_pico.c)
39+
zephyr_library_sources_ifdef(CONFIG_UART_RPI_PICO_PIO uart_rpi_pico_pio.c)
3940
zephyr_library_sources_ifdef(CONFIG_UART_LITEUART uart_liteuart.c)
4041
zephyr_library_sources_ifdef(CONFIG_UART_RTT_DRIVER uart_rtt.c)
4142
zephyr_library_sources_ifdef(CONFIG_UART_XLNX_PS uart_xlnx_ps.c)

drivers/serial/Kconfig.rpi_pico

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,12 @@ config UART_RPI_PICO
99
select PICOSDK_USE_UART
1010
select SERIAL_SUPPORT_INTERRUPT
1111
depends on RESET
12+
13+
config UART_RPI_PICO_PIO
14+
bool "Raspberry Pi PIO UART driver"
15+
default y
16+
depends on DT_HAS_RASPBERRYPI_PICO_UART_PIO_ENABLED
17+
select SERIAL_HAS_DRIVER
18+
select PICOSDK_USE_PIO
19+
select PICOSDK_USE_CLAIM
20+
depends on RESET

drivers/serial/uart_rpi_pico_pio.c

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
/*
2+
* Copyright (c) 2022, Yonatan Schachter
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/drivers/pinctrl.h>
8+
#include <zephyr/drivers/uart.h>
9+
10+
#include <zephyr/drivers/misc/pio_rpi_pico/pio_rpi_pico.h>
11+
12+
#include <hardware/pio.h>
13+
#include <hardware/clocks.h>
14+
15+
#define DT_DRV_COMPAT raspberrypi_pico_uart_pio
16+
17+
#define CYCLES_PER_BIT 8
18+
#define SIDESET_BIT_COUNT 2
19+
20+
struct pio_uart_config {
21+
const struct device *piodev;
22+
const struct pinctrl_dev_config *pcfg;
23+
const uint32_t tx_pin;
24+
const uint32_t rx_pin;
25+
uint32_t baudrate;
26+
};
27+
28+
struct pio_uart_data {
29+
size_t tx_sm;
30+
size_t rx_sm;
31+
};
32+
33+
RPI_PICO_PIO_DEFINE_PROGRAM(uart_tx, 0, 3,
34+
/* .wrap_target */
35+
0x9fa0, /* 0: pull block side 1 [7] */
36+
0xf727, /* 1: set x, 7 side 0 [7] */
37+
0x6001, /* 2: out pins, 1 */
38+
0x0642, /* 3: jmp x--, 2 [6] */
39+
/* .wrap */
40+
);
41+
42+
RPI_PICO_PIO_DEFINE_PROGRAM(uart_rx, 0, 8,
43+
/* .wrap_target */
44+
0x2020, /* 0: wait 0 pin, 0 */
45+
0xea27, /* 1: set x, 7 [10] */
46+
0x4001, /* 2: in pins, 1 */
47+
0x0642, /* 3: jmp x--, 2 [6] */
48+
0x00c8, /* 4: jmp pin, 8 */
49+
0xc014, /* 5: irq nowait 4 rel */
50+
0x20a0, /* 6: wait 1 pin, 0 */
51+
0x0000, /* 7: jmp 0 */
52+
0x8020, /* 8: push block */
53+
/* .wrap */
54+
);
55+
56+
static int pio_uart_tx_init(PIO pio, uint32_t sm, uint32_t tx_pin, float div)
57+
{
58+
uint32_t offset;
59+
pio_sm_config sm_config;
60+
61+
if (!pio_can_add_program(pio, RPI_PICO_PIO_GET_PROGRAM(uart_tx))) {
62+
return -EBUSY;
63+
}
64+
65+
offset = pio_add_program(pio, RPI_PICO_PIO_GET_PROGRAM(uart_tx));
66+
sm_config = pio_get_default_sm_config();
67+
68+
sm_config_set_sideset(&sm_config, SIDESET_BIT_COUNT, true, false);
69+
sm_config_set_out_shift(&sm_config, true, false, 0);
70+
sm_config_set_out_pins(&sm_config, tx_pin, 1);
71+
sm_config_set_sideset_pins(&sm_config, tx_pin);
72+
sm_config_set_fifo_join(&sm_config, PIO_FIFO_JOIN_TX);
73+
sm_config_set_clkdiv(&sm_config, div);
74+
sm_config_set_wrap(&sm_config,
75+
offset + RPI_PICO_PIO_GET_WRAP_TARGET(uart_tx),
76+
offset + RPI_PICO_PIO_GET_WRAP(uart_tx));
77+
78+
pio_sm_set_pins_with_mask(pio, sm, BIT(tx_pin), BIT(tx_pin));
79+
pio_sm_set_pindirs_with_mask(pio, sm, BIT(tx_pin), BIT(tx_pin));
80+
pio_sm_init(pio, sm, offset, &sm_config);
81+
pio_sm_set_enabled(pio, sm, true);
82+
83+
return 0;
84+
}
85+
86+
static int pio_uart_rx_init(PIO pio, uint32_t sm, uint32_t rx_pin, float div)
87+
{
88+
pio_sm_config sm_config;
89+
uint32_t offset;
90+
91+
if (!pio_can_add_program(pio, RPI_PICO_PIO_GET_PROGRAM(uart_rx))) {
92+
return -EBUSY;
93+
}
94+
95+
offset = pio_add_program(pio, RPI_PICO_PIO_GET_PROGRAM(uart_rx));
96+
sm_config = pio_get_default_sm_config();
97+
98+
pio_sm_set_consecutive_pindirs(pio, sm, rx_pin, 1, false);
99+
sm_config_set_in_pins(&sm_config, rx_pin);
100+
sm_config_set_jmp_pin(&sm_config, rx_pin);
101+
sm_config_set_in_shift(&sm_config, true, false, 0);
102+
sm_config_set_fifo_join(&sm_config, PIO_FIFO_JOIN_RX);
103+
sm_config_set_clkdiv(&sm_config, div);
104+
sm_config_set_wrap(&sm_config,
105+
offset + RPI_PICO_PIO_GET_WRAP_TARGET(uart_rx),
106+
offset + RPI_PICO_PIO_GET_WRAP(uart_rx));
107+
108+
pio_sm_init(pio, sm, offset, &sm_config);
109+
pio_sm_set_enabled(pio, sm, true);
110+
111+
return 0;
112+
}
113+
114+
static int pio_uart_poll_in(const struct device *dev, unsigned char *c)
115+
{
116+
const struct pio_uart_config *config = dev->config;
117+
PIO pio = pio_rpi_pico_get_pio(config->piodev);
118+
struct pio_uart_data *data = dev->data;
119+
io_rw_8 *uart_rx_fifo_msb;
120+
121+
/*
122+
* The rx FIFO is 4 bytes wide, add 3 to get the most significant
123+
* byte.
124+
*/
125+
uart_rx_fifo_msb = (io_rw_8 *)&pio->rxf[data->rx_sm] + 3;
126+
if (pio_sm_is_rx_fifo_empty(pio, data->rx_sm)) {
127+
return -1;
128+
}
129+
130+
/* Accessing the FIFO pops the read word from it */
131+
*c = (char)*uart_rx_fifo_msb;
132+
return 0;
133+
}
134+
135+
static void pio_uart_poll_out(const struct device *dev, unsigned char c)
136+
{
137+
const struct pio_uart_config *config = dev->config;
138+
struct pio_uart_data *data = dev->data;
139+
140+
pio_sm_put_blocking(pio_rpi_pico_get_pio(config->piodev), data->tx_sm, (uint32_t)c);
141+
}
142+
143+
static int pio_uart_init(const struct device *dev)
144+
{
145+
const struct pio_uart_config *config = dev->config;
146+
struct pio_uart_data *data = dev->data;
147+
float sm_clock_div;
148+
size_t tx_sm;
149+
size_t rx_sm;
150+
int retval;
151+
PIO pio;
152+
153+
pio = pio_rpi_pico_get_pio(config->piodev);
154+
sm_clock_div = (float)clock_get_hz(clk_sys) / (CYCLES_PER_BIT * config->baudrate);
155+
156+
retval = pio_rpi_pico_allocate_sm(config->piodev, &tx_sm);
157+
retval |= pio_rpi_pico_allocate_sm(config->piodev, &rx_sm);
158+
159+
if (retval < 0) {
160+
return retval;
161+
}
162+
163+
data->tx_sm = tx_sm;
164+
data->rx_sm = rx_sm;
165+
166+
retval = pio_uart_tx_init(pio, tx_sm, config->tx_pin, sm_clock_div);
167+
if (retval < 0) {
168+
return retval;
169+
}
170+
171+
retval = pio_uart_rx_init(pio, rx_sm, config->rx_pin, sm_clock_div);
172+
if (retval < 0) {
173+
return retval;
174+
}
175+
176+
return pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
177+
}
178+
179+
static const struct uart_driver_api pio_uart_driver_api = {
180+
.poll_in = pio_uart_poll_in,
181+
.poll_out = pio_uart_poll_out,
182+
};
183+
184+
#define PIO_UART_INIT(idx) \
185+
PINCTRL_DT_INST_DEFINE(idx); \
186+
static const struct pio_uart_config pio_uart##idx##_config = { \
187+
.piodev = DEVICE_DT_GET(DT_INST_PARENT(idx)), \
188+
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \
189+
.tx_pin = DT_INST_RPI_PICO_PIO_PIN_BY_NAME(idx, default, 0, tx_pins, 0), \
190+
.rx_pin = DT_INST_RPI_PICO_PIO_PIN_BY_NAME(idx, default, 0, rx_pins, 0), \
191+
.baudrate = DT_INST_PROP(idx, current_speed), \
192+
}; \
193+
static struct pio_uart_data pio_uart##idx##_data; \
194+
\
195+
DEVICE_DT_INST_DEFINE(idx, &pio_uart_init, NULL, &pio_uart##idx##_data, \
196+
&pio_uart##idx##_config, POST_KERNEL, \
197+
CONFIG_SERIAL_INIT_PRIORITY, \
198+
&pio_uart_driver_api);
199+
200+
DT_INST_FOREACH_STATUS_OKAY(PIO_UART_INIT)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
description: Raspberry Pi Pico PIO UART
2+
3+
compatible: "raspberrypi,pico-uart-pio"
4+
5+
include: [uart-controller.yaml, "raspberrypi,pico-pio-device.yaml"]

0 commit comments

Comments
 (0)