-
Notifications
You must be signed in to change notification settings - Fork 8.2k
rp2040: Added PIO support #44316
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
rp2040: Added PIO support #44316
Changes from all commits
f1cdbb2
312212a
93f0104
72d3942
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -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 | ||||||
| =========== | ||||||
|
|
@@ -109,6 +112,17 @@ Default Zephyr Peripheral Mapping: | |||||
| - ADC_CH2 : P28 | ||||||
| - ADC_CH3 : P29 | ||||||
|
|
||||||
| Programmable I/O (PIO) | ||||||
dcpleung marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| ********************** | ||||||
| The RP2040 SoC comes with two PIO periherals. These are two simple | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| 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 | ||||||
| ************************* | ||||||
|
|
||||||
|
|
||||||
| 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) |
| 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 |
| 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
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pretty sure this can be omitted and parameter set to NULL - @gmarull ?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) | ||
| 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) |
| 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 |
| 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] |
| 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"] |
Uh oh!
There was an error while loading. Please reload this page.