Skip to content
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
14 changes: 14 additions & 0 deletions boards/arm/rpi_pico/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ hardware features:
* - Flash
- :kconfig:option:`CONFIG_FLASH`
- :dtcompatible:`raspberrypi,pico-flash`
* - UART (PIO)
- :kconfig:option:`CONFIG_SERIAL`
- :dtcompatible:`raspberrypi,pico-uart-pio`

Pin Mapping
===========
Expand Down Expand Up @@ -109,6 +112,17 @@ Default Zephyr Peripheral Mapping:
- ADC_CH2 : P28
- ADC_CH3 : P29

Programmable I/O (PIO)
**********************
The RP2040 SoC comes with two PIO periherals. These are two simple
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The RP2040 SoC comes with two PIO periherals. These are two simple
The RP2040 SoC comes with two PIO peripherals. These are two simple

co-processors that are designed for I/O operations. The PIOs run
a custom instruction set, generated from a custom assembly language.
PIO programs are assembled using `pioasm`, a tool provided by Raspberry Pi.

Zephyr does not (currently) assemble PIO programs. Rather, they should be
manually assembled and embedded in source code. An example of how this is done
can be found at `drivers/serial/uart_rpi_pico_pio.c`.

Programming and Debugging
*************************

Expand Down
1 change: 1 addition & 0 deletions drivers/misc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
add_subdirectory_ifdef(CONFIG_ARM_ETHOS_U ethos_u)
add_subdirectory_ifdef(CONFIG_FT800 ft8xx)
add_subdirectory_ifdef(CONFIG_GROVE_LCD_RGB grove_lcd_rgb)
add_subdirectory_ifdef(CONFIG_PIO_RPI_PICO pio_rpi_pico)
1 change: 1 addition & 0 deletions drivers/misc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ menu "Miscellaneous Drivers"

source "drivers/misc/ft8xx/Kconfig"
source "drivers/misc/grove_lcd_rgb/Kconfig"
source "drivers/misc/pio_rpi_pico/Kconfig"

endmenu
6 changes: 6 additions & 0 deletions drivers/misc/pio_rpi_pico/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Copyright (c) 2023 TOKITA Hiroshi <[email protected]>
# SPDX-License-Identifier: Apache-2.0

zephyr_library()

zephyr_library_sources(pio_rpi_pico.c)
9 changes: 9 additions & 0 deletions drivers/misc/pio_rpi_pico/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright (c) 2023 TOKITA Hiroshi <[email protected]>
# SPDX-License-Identifier: Apache-2.0

config PIO_RPI_PICO
bool "RaspberryPi Pico PIO"
default y
depends on DT_HAS_RASPBERRYPI_PICO_PIO_ENABLED
depends on RESET
select PICOSDK_USE_PIO
53 changes: 53 additions & 0 deletions drivers/misc/pio_rpi_pico/pio_rpi_pico.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2023 Tokita, Hiroshi <[email protected]>
* Copyright (c) 2023 Yonatan Schachter
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/device.h>
#include <zephyr/drivers/misc/pio_rpi_pico/pio_rpi_pico.h>
#include <zephyr/drivers/pinctrl.h>

#define DT_DRV_COMPAT raspberrypi_pico_pio

struct pio_rpi_pico_config {
PIO pio;
};

int pio_rpi_pico_allocate_sm(const struct device *dev, size_t *sm)
{
const struct pio_rpi_pico_config *config = dev->config;
int retval;

retval = pio_claim_unused_sm(config->pio, false);
if (retval < 0) {
return -EBUSY;
}

*sm = (size_t)retval;
return 0;
}

PIO pio_rpi_pico_get_pio(const struct device *dev)
{
const struct pio_rpi_pico_config *config = dev->config;

return config->pio;
}

static int pio_rpi_pico_init(const struct device *dev)
{
return 0;
}
Comment on lines +39 to +42
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty sure this can be omitted and parameter set to NULL - @gmarull ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, can be removed


#define RPI_PICO_PIO_INIT(idx) \
static const struct pio_rpi_pico_config pio_rpi_pico_config_##idx = { \
.pio = (PIO)DT_INST_REG_ADDR(idx), \
}; \
\
DEVICE_DT_INST_DEFINE(idx, &pio_rpi_pico_init, NULL, NULL, \
&pio_rpi_pico_config_##idx, PRE_KERNEL_2, \
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, NULL);

DT_INST_FOREACH_STATUS_OKAY(RPI_PICO_PIO_INIT)
1 change: 1 addition & 0 deletions drivers/serial/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_PL011 uart_pl011.c)
zephyr_library_sources_ifdef(CONFIG_UART_QUICKLOGIC_USBSERIALPORT_S3B uart_ql_usbserialport_s3b.c)
zephyr_library_sources_ifdef(CONFIG_UART_RV32M1_LPUART uart_rv32m1_lpuart.c)
zephyr_library_sources_ifdef(CONFIG_UART_RPI_PICO uart_rpi_pico.c)
zephyr_library_sources_ifdef(CONFIG_UART_RPI_PICO_PIO uart_rpi_pico_pio.c)
zephyr_library_sources_ifdef(CONFIG_UART_LITEUART uart_liteuart.c)
zephyr_library_sources_ifdef(CONFIG_UART_RTT_DRIVER uart_rtt.c)
zephyr_library_sources_ifdef(CONFIG_UART_XLNX_PS uart_xlnx_ps.c)
Expand Down
9 changes: 9 additions & 0 deletions drivers/serial/Kconfig.rpi_pico
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,12 @@ config UART_RPI_PICO
select PICOSDK_USE_UART
select SERIAL_SUPPORT_INTERRUPT
depends on RESET

config UART_RPI_PICO_PIO
bool "Raspberry Pi PIO UART driver"
default y
depends on DT_HAS_RASPBERRYPI_PICO_UART_PIO_ENABLED
select SERIAL_HAS_DRIVER
select PICOSDK_USE_PIO
select PICOSDK_USE_CLAIM
depends on RESET
200 changes: 200 additions & 0 deletions drivers/serial/uart_rpi_pico_pio.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
/*
* Copyright (c) 2022, Yonatan Schachter
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/drivers/pinctrl.h>
#include <zephyr/drivers/uart.h>

#include <zephyr/drivers/misc/pio_rpi_pico/pio_rpi_pico.h>

#include <hardware/pio.h>
#include <hardware/clocks.h>

#define DT_DRV_COMPAT raspberrypi_pico_uart_pio

#define CYCLES_PER_BIT 8
#define SIDESET_BIT_COUNT 2

struct pio_uart_config {
const struct device *piodev;
const struct pinctrl_dev_config *pcfg;
const uint32_t tx_pin;
const uint32_t rx_pin;
uint32_t baudrate;
};

struct pio_uart_data {
size_t tx_sm;
size_t rx_sm;
};

RPI_PICO_PIO_DEFINE_PROGRAM(uart_tx, 0, 3,
/* .wrap_target */
0x9fa0, /* 0: pull block side 1 [7] */
0xf727, /* 1: set x, 7 side 0 [7] */
0x6001, /* 2: out pins, 1 */
0x0642, /* 3: jmp x--, 2 [6] */
/* .wrap */
);

RPI_PICO_PIO_DEFINE_PROGRAM(uart_rx, 0, 8,
/* .wrap_target */
0x2020, /* 0: wait 0 pin, 0 */
0xea27, /* 1: set x, 7 [10] */
0x4001, /* 2: in pins, 1 */
0x0642, /* 3: jmp x--, 2 [6] */
0x00c8, /* 4: jmp pin, 8 */
0xc014, /* 5: irq nowait 4 rel */
0x20a0, /* 6: wait 1 pin, 0 */
0x0000, /* 7: jmp 0 */
0x8020, /* 8: push block */
/* .wrap */
);

static int pio_uart_tx_init(PIO pio, uint32_t sm, uint32_t tx_pin, float div)
{
uint32_t offset;
pio_sm_config sm_config;

if (!pio_can_add_program(pio, RPI_PICO_PIO_GET_PROGRAM(uart_tx))) {
return -EBUSY;
}

offset = pio_add_program(pio, RPI_PICO_PIO_GET_PROGRAM(uart_tx));
sm_config = pio_get_default_sm_config();

sm_config_set_sideset(&sm_config, SIDESET_BIT_COUNT, true, false);
sm_config_set_out_shift(&sm_config, true, false, 0);
sm_config_set_out_pins(&sm_config, tx_pin, 1);
sm_config_set_sideset_pins(&sm_config, tx_pin);
sm_config_set_fifo_join(&sm_config, PIO_FIFO_JOIN_TX);
sm_config_set_clkdiv(&sm_config, div);
sm_config_set_wrap(&sm_config,
offset + RPI_PICO_PIO_GET_WRAP_TARGET(uart_tx),
offset + RPI_PICO_PIO_GET_WRAP(uart_tx));

pio_sm_set_pins_with_mask(pio, sm, BIT(tx_pin), BIT(tx_pin));
pio_sm_set_pindirs_with_mask(pio, sm, BIT(tx_pin), BIT(tx_pin));
pio_sm_init(pio, sm, offset, &sm_config);
pio_sm_set_enabled(pio, sm, true);

return 0;
}

static int pio_uart_rx_init(PIO pio, uint32_t sm, uint32_t rx_pin, float div)
{
pio_sm_config sm_config;
uint32_t offset;

if (!pio_can_add_program(pio, RPI_PICO_PIO_GET_PROGRAM(uart_rx))) {
return -EBUSY;
}

offset = pio_add_program(pio, RPI_PICO_PIO_GET_PROGRAM(uart_rx));
sm_config = pio_get_default_sm_config();

pio_sm_set_consecutive_pindirs(pio, sm, rx_pin, 1, false);
sm_config_set_in_pins(&sm_config, rx_pin);
sm_config_set_jmp_pin(&sm_config, rx_pin);
sm_config_set_in_shift(&sm_config, true, false, 0);
sm_config_set_fifo_join(&sm_config, PIO_FIFO_JOIN_RX);
sm_config_set_clkdiv(&sm_config, div);
sm_config_set_wrap(&sm_config,
offset + RPI_PICO_PIO_GET_WRAP_TARGET(uart_rx),
offset + RPI_PICO_PIO_GET_WRAP(uart_rx));

pio_sm_init(pio, sm, offset, &sm_config);
pio_sm_set_enabled(pio, sm, true);

return 0;
}

static int pio_uart_poll_in(const struct device *dev, unsigned char *c)
{
const struct pio_uart_config *config = dev->config;
PIO pio = pio_rpi_pico_get_pio(config->piodev);
struct pio_uart_data *data = dev->data;
io_rw_8 *uart_rx_fifo_msb;

/*
* The rx FIFO is 4 bytes wide, add 3 to get the most significant
* byte.
*/
uart_rx_fifo_msb = (io_rw_8 *)&pio->rxf[data->rx_sm] + 3;
if (pio_sm_is_rx_fifo_empty(pio, data->rx_sm)) {
return -1;
}

/* Accessing the FIFO pops the read word from it */
*c = (char)*uart_rx_fifo_msb;
return 0;
}

static void pio_uart_poll_out(const struct device *dev, unsigned char c)
{
const struct pio_uart_config *config = dev->config;
struct pio_uart_data *data = dev->data;

pio_sm_put_blocking(pio_rpi_pico_get_pio(config->piodev), data->tx_sm, (uint32_t)c);
}

static int pio_uart_init(const struct device *dev)
{
const struct pio_uart_config *config = dev->config;
struct pio_uart_data *data = dev->data;
float sm_clock_div;
size_t tx_sm;
size_t rx_sm;
int retval;
PIO pio;

pio = pio_rpi_pico_get_pio(config->piodev);
sm_clock_div = (float)clock_get_hz(clk_sys) / (CYCLES_PER_BIT * config->baudrate);

retval = pio_rpi_pico_allocate_sm(config->piodev, &tx_sm);
retval |= pio_rpi_pico_allocate_sm(config->piodev, &rx_sm);

if (retval < 0) {
return retval;
}

data->tx_sm = tx_sm;
data->rx_sm = rx_sm;

retval = pio_uart_tx_init(pio, tx_sm, config->tx_pin, sm_clock_div);
if (retval < 0) {
return retval;
}

retval = pio_uart_rx_init(pio, rx_sm, config->rx_pin, sm_clock_div);
if (retval < 0) {
return retval;
}

return pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
}

static const struct uart_driver_api pio_uart_driver_api = {
.poll_in = pio_uart_poll_in,
.poll_out = pio_uart_poll_out,
};

#define PIO_UART_INIT(idx) \
PINCTRL_DT_INST_DEFINE(idx); \
static const struct pio_uart_config pio_uart##idx##_config = { \
.piodev = DEVICE_DT_GET(DT_INST_PARENT(idx)), \
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \
.tx_pin = DT_INST_RPI_PICO_PIO_PIN_BY_NAME(idx, default, 0, tx_pins, 0), \
.rx_pin = DT_INST_RPI_PICO_PIO_PIN_BY_NAME(idx, default, 0, rx_pins, 0), \
.baudrate = DT_INST_PROP(idx, current_speed), \
}; \
static struct pio_uart_data pio_uart##idx##_data; \
\
DEVICE_DT_INST_DEFINE(idx, &pio_uart_init, NULL, &pio_uart##idx##_data, \
&pio_uart##idx##_config, POST_KERNEL, \
CONFIG_SERIAL_INIT_PRIORITY, \
&pio_uart_driver_api);

DT_INST_FOREACH_STATUS_OKAY(PIO_UART_INIT)
16 changes: 16 additions & 0 deletions dts/arm/rpi_pico/rp2040.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,22 @@
raspberrypi,brown-out-detection;
raspberrypi,brown-out-threshold = <860000>;
};

pio0: pio@50200000 {
compatible = "raspberrypi,pico-pio";
reg = <0x50200000 DT_SIZE_K(4)>;
clocks = <&system_clk>;
resets = <&reset RPI_PICO_RESETS_RESET_PIO0>;
status = "disabled";
};

pio1: pio@50300000 {
compatible = "raspberrypi,pico-pio";
reg = <0x50300000 DT_SIZE_K(4)>;
clocks = <&system_clk>;
resets = <&reset RPI_PICO_RESETS_RESET_PIO1>;
status = "disabled";
};
};

pinctrl: pin-controller {
Expand Down
9 changes: 9 additions & 0 deletions dts/bindings/misc/raspberrypi,pico-pio-device.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright (c) 2023, TOKITA Hiroshi
# Copyright (c) 2023, Yonatan Schachter
# SPDX-License-Identifier: Apache-2.0

description: Raspberry Pi Pico PIO device

compatible: "raspberrypi,pico-pio-device"

include: pinctrl-device.yaml
8 changes: 8 additions & 0 deletions dts/bindings/misc/raspberrypi,pico-pio.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) 2023, TOKITA Hiroshi
# SPDX-License-Identifier: Apache-2.0

description: Raspberry Pi Pico PIO

compatible: "raspberrypi,pico-pio"

include: [base.yaml, reset-device.yaml]
5 changes: 5 additions & 0 deletions dts/bindings/serial/raspberrypi,pico-uart-pio.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
description: Raspberry Pi Pico PIO UART

compatible: "raspberrypi,pico-uart-pio"

include: [uart-controller.yaml, "raspberrypi,pico-pio-device.yaml"]
Loading