diff --git a/boards/arm/rpi_pico/doc/index.rst b/boards/arm/rpi_pico/doc/index.rst index 69cb6acd2ce9e..d242196e3f4c0 100644 --- a/boards/arm/rpi_pico/doc/index.rst +++ b/boards/arm/rpi_pico/doc/index.rst @@ -136,7 +136,7 @@ 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 +Zephyr does not 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`. diff --git a/drivers/misc/pio_rpi_pico/CMakeLists.txt b/drivers/misc/pio_rpi_pico/CMakeLists.txt index ba762d907a81c..af4e8edc7b1a5 100644 --- a/drivers/misc/pio_rpi_pico/CMakeLists.txt +++ b/drivers/misc/pio_rpi_pico/CMakeLists.txt @@ -1,3 +1,4 @@ +# Copyright (c) 2023 Ionut Pavel # Copyright (c) 2023 TOKITA Hiroshi # SPDX-License-Identifier: Apache-2.0 diff --git a/drivers/misc/pio_rpi_pico/Kconfig b/drivers/misc/pio_rpi_pico/Kconfig index ff312cb81ebef..efe19daad34a7 100644 --- a/drivers/misc/pio_rpi_pico/Kconfig +++ b/drivers/misc/pio_rpi_pico/Kconfig @@ -1,3 +1,4 @@ +# Copyright (c) 2023 Ionut Pavel # Copyright (c) 2023 TOKITA Hiroshi # SPDX-License-Identifier: Apache-2.0 @@ -5,5 +6,19 @@ 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 + +if PIO_RPI_PICO + +module = PIO_RPI_PICO +module-str = pio_rpi_pico +source "subsys/logging/Kconfig.template.log_config" + +config PIO_RPI_PICO_INSTR_COUNT + int "Number of Program Instructions for each PIO" + default 32 if SOC_RP2040 + +config PIO_RPI_PICO_SM_COUNT + int "Number of State Machine instances for each PIO" + default 4 if SOC_RP2040 + +endif diff --git a/drivers/misc/pio_rpi_pico/pio_rpi_pico.c b/drivers/misc/pio_rpi_pico/pio_rpi_pico.c index 03a03e824c20b..cdae9604dbd52 100644 --- a/drivers/misc/pio_rpi_pico/pio_rpi_pico.c +++ b/drivers/misc/pio_rpi_pico/pio_rpi_pico.c @@ -1,53 +1,230 @@ -/* +/** + * Copyright (c) 2023, Ionut Pavel * Copyright (c) 2023 Tokita, Hiroshi * Copyright (c) 2023 Yonatan Schachter * * SPDX-License-Identifier: Apache-2.0 */ +#include +#include #include +#include #include -#include -#define DT_DRV_COMPAT raspberrypi_pico_pio +#include +LOG_MODULE_REGISTER(pio_rpi_pico, CONFIG_PIO_RPI_PICO_LOG_LEVEL); + +#define DT_DRV_COMPAT raspberrypi_pico_pio + +typedef void (*pio_rpi_pico_irq_config_func_t)(void); + +struct pio_rpi_pico_irq_config { + pio_rpi_pico_irq_config_func_t irq_config; + uint irq_map; +}; struct pio_rpi_pico_config { - PIO pio; + const struct pio_rpi_pico_irq_config *irq_configs; + sys_slist_t *irq_lists; + uint8_t irq_cnt; }; -int pio_rpi_pico_allocate_sm(const struct device *dev, size_t *sm) +struct pio_rpi_pico_data { + /** + * The maximum shared instruction scheme is SM count dependent. + */ + const char *shared_key[CONFIG_PIO_RPI_PICO_SM_COUNT / 2]; + uint8_t shared_instr[CONFIG_PIO_RPI_PICO_SM_COUNT / 2]; + + uint8_t alloc_sm; + uint8_t alloc_instr; +}; + +int pio_rpi_pico_alloc_sm(const struct device *dev, size_t count, uint8_t *sm) { - const struct pio_rpi_pico_config *config = dev->config; - int retval; + struct pio_rpi_pico_data *data = dev->data; + size_t available; - retval = pio_claim_unused_sm(config->pio, false); - if (retval < 0) { - return -EBUSY; + __ASSERT_NO_MSG(sm); + __ASSERT_NO_MSG(count); + + available = CONFIG_PIO_RPI_PICO_SM_COUNT - data->alloc_sm; + + if (available < count) { + return -EIO; } - *sm = (size_t)retval; + *sm = data->alloc_sm; + data->alloc_sm += (uint8_t)count; + return 0; } -PIO pio_rpi_pico_get_pio(const struct device *dev) +int pio_rpi_pico_alloc_instr(const struct device *dev, size_t count, uint8_t *instr) +{ + struct pio_rpi_pico_data *data = dev->data; + size_t available; + + __ASSERT_NO_MSG(instr); + __ASSERT_NO_MSG(count); + + available = CONFIG_PIO_RPI_PICO_INSTR_COUNT - data->alloc_instr; + + if (available < count) { + return -ENOMEM; + } + + *instr = data->alloc_instr; + data->alloc_instr += (uint8_t)count; + + return 0; +} + +int pio_rpi_pico_alloc_shared_instr(const struct device *dev, const char *key, + size_t count, uint8_t *instr) +{ + struct pio_rpi_pico_data *data = dev->data; + uint8_t i; + int rc; + + __ASSERT_NO_MSG(dev); + __ASSERT_NO_MSG(key); + __ASSERT_NO_MSG(instr); + __ASSERT_NO_MSG(count); + + for (i = 0u; i < (CONFIG_PIO_RPI_PICO_SM_COUNT / 2); i++) { + + if (!data->shared_key[i]) { + rc = pio_rpi_pico_alloc_instr(dev, count, instr); + if (rc < 0) { + return rc; + } + + data->shared_instr[i] = *instr; + data->shared_key[i] = key; + return 0; + + } else if (strcmp(data->shared_key[i], key) == 0) { + *instr = data->shared_instr[i]; + return -EALREADY; + } + } + + return -ENOMEM; +} + +void pio_rpi_pico_irq_register(const struct device *dev, struct pio_rpi_pico_irq_cfg *cfg) { const struct pio_rpi_pico_config *config = dev->config; - return config->pio; + __ASSERT_NO_MSG(dev); + __ASSERT_NO_MSG(cfg); + __ASSERT_NO_MSG(cfg->irq_idx < config->irq_cnt); + + sys_slist_append(&config->irq_lists[cfg->irq_idx], (sys_snode_t *)cfg); +} + +void pio_rpi_pico_irq_enable(const struct device *dev, struct pio_rpi_pico_irq_cfg *cfg) +{ + const struct pio_rpi_pico_config *config = dev->config; + + __ASSERT_NO_MSG(dev); + __ASSERT_NO_MSG(cfg); + __ASSERT_NO_MSG(cfg->irq_idx < config->irq_cnt); + + cfg->enabled = true; + + /* Just enable the line. Doesn't really matter if already enabled */ + irq_enable(config->irq_configs[cfg->irq_idx].irq_map); +} + +void pio_rpi_pico_irq_disable(const struct device *dev, struct pio_rpi_pico_irq_cfg *cfg) +{ + const struct pio_rpi_pico_config *config = dev->config; + struct pio_rpi_pico_irq_cfg *irq_cfg; + sys_snode_t *pnode; + + __ASSERT_NO_MSG(dev); + __ASSERT_NO_MSG(cfg); + __ASSERT_NO_MSG(cfg->irq_idx < config->irq_cnt); + + cfg->enabled = false; + + /* Return if not last one */ + SYS_SLIST_FOR_EACH_NODE(&config->irq_lists[cfg->irq_idx], pnode) { + irq_cfg = CONTAINER_OF(pnode, struct pio_rpi_pico_irq_cfg, node); + if ((irq_cfg != cfg) && irq_cfg->enabled) { + return; + } + } + + irq_disable(config->irq_configs[cfg->irq_idx].irq_map); } static int pio_rpi_pico_init(const struct device *dev) { + const struct pio_rpi_pico_config *config = dev->config; + uint8_t i; + + for (i = 0u; i < config->irq_cnt; i++) { + sys_slist_init(&config->irq_lists[i]); + config->irq_configs[i].irq_config(); + } + return 0; } -#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); +static void pio_rpi_pico_irq(sys_slist_t *irq_list) +{ + struct pio_rpi_pico_irq_cfg *irq_cfg; + sys_snode_t *pnode; + + SYS_SLIST_FOR_EACH_NODE(irq_list, pnode) { + irq_cfg = CONTAINER_OF(pnode, struct pio_rpi_pico_irq_cfg, node); + if (irq_cfg->enabled) { + irq_cfg->irq_func(irq_cfg->irq_param); + } + } +} + +#define PIO_RPI_PICO_IRQ_CONFIG_FUNC(idx, inst) \ +static void pio_rpi_pico_irq_config##inst##_##idx(void) \ +{ \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(inst, idx, irq), \ + DT_INST_IRQ_BY_IDX(inst, idx, priority), \ + pio_rpi_pico_irq, \ + &pio_rpi_pico_irq_data##inst[idx], (0)); \ +} + +#define PIO_RPI_PICO_IRQ_CONFIG_DATA(idx, inst) \ + { \ + .irq_config = pio_rpi_pico_irq_config##inst##_##idx, \ + .irq_map = DT_INST_IRQ_BY_IDX(inst, idx, irq), \ + } + +#define PIO_RPI_PICO_INIT(inst) \ + static sys_slist_t pio_rpi_pico_irq_data##inst[DT_NUM_IRQS(DT_DRV_INST(inst))]; \ + LISTIFY(DT_NUM_IRQS(DT_DRV_INST(inst)), PIO_RPI_PICO_IRQ_CONFIG_FUNC, (), inst) \ + \ + static struct pio_rpi_pico_data pio_rpi_pico_data##inst; \ + \ + static const struct pio_rpi_pico_irq_config \ + pio_rpi_pico_irq_config##inst[DT_NUM_IRQS(DT_DRV_INST(inst))] = \ + {LISTIFY(DT_NUM_IRQS(DT_DRV_INST(inst)), PIO_RPI_PICO_IRQ_CONFIG_DATA, (,), inst)}; \ + \ + static const struct pio_rpi_pico_config pio_rpi_pico_config##inst = { \ + .irq_configs = pio_rpi_pico_irq_config##inst, \ + .irq_lists = pio_rpi_pico_irq_data##inst, \ + .irq_cnt = DT_NUM_IRQS(DT_DRV_INST(inst)), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, &pio_rpi_pico_init, \ + NULL, \ + &pio_rpi_pico_data##inst, \ + &pio_rpi_pico_config##inst, \ + PRE_KERNEL_1, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + NULL); -DT_INST_FOREACH_STATUS_OKAY(RPI_PICO_PIO_INIT) +DT_INST_FOREACH_STATUS_OKAY(PIO_RPI_PICO_INIT); diff --git a/drivers/serial/Kconfig.rpi_pico b/drivers/serial/Kconfig.rpi_pico index 0465570f704d0..aefc217014753 100644 --- a/drivers/serial/Kconfig.rpi_pico +++ b/drivers/serial/Kconfig.rpi_pico @@ -15,6 +15,5 @@ config UART_RPI_PICO_PIO default y depends on DT_HAS_RASPBERRYPI_PICO_UART_PIO_ENABLED select SERIAL_HAS_DRIVER - select PICOSDK_USE_PIO - select PICOSDK_USE_CLAIM + select SERIAL_SUPPORT_INTERRUPT depends on RESET diff --git a/drivers/serial/uart_rpi_pico_pio.c b/drivers/serial/uart_rpi_pico_pio.c index 8efb725b44ab3..5ed37d401714e 100644 --- a/drivers/serial/uart_rpi_pico_pio.c +++ b/drivers/serial/uart_rpi_pico_pio.c @@ -1,200 +1,766 @@ /* + * Copyright (c) 2023, Ionut Pavel * Copyright (c) 2022, Yonatan Schachter * * SPDX-License-Identifier: Apache-2.0 */ -#include +#include +#include +#include +#include #include - +#include #include +#include -#include -#include - -#define DT_DRV_COMPAT raspberrypi_pico_uart_pio +/* PIO registers */ +#include -#define CYCLES_PER_BIT 8 -#define SIDESET_BIT_COUNT 2 +#define DT_DRV_COMPAT raspberrypi_pico_uart_pio struct pio_uart_config { - const struct device *piodev; + const struct device *parent; const struct pinctrl_dev_config *pcfg; - const uint32_t tx_pin; - const uint32_t rx_pin; - uint32_t baudrate; + pio_hw_t *pio_regs; + uint32_t clock_frequency; +#if CONFIG_UART_INTERRUPT_DRIVEN + uart_irq_config_func_t irq_config; + uint8_t irq_idx; +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + uint8_t tx_gpio; + uint8_t rx_gpio; }; struct pio_uart_data { - size_t tx_sm; - size_t rx_sm; +#if CONFIG_UART_INTERRUPT_DRIVEN + uart_irq_callback_user_data_t irq_cb; + void *irq_cb_data; +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + struct uart_config uart_config; + uint8_t tx_sm; + uint8_t tx_sm_mask; + uint8_t tx_prg; + uint8_t rx_sm; + uint8_t rx_sm_mask; + uint8_t rx_shift; + uint8_t rx_prg; +}; + +/* Number of bits to shift */ +#define PIO_UART_TXRX_BITS_CNT(bits) ((bits) - 1) + +/** + * 8N1 initial configuration + * OUT pin 0 and side-set pin 0 mapped to the TX pin + * Scratch Y for number of bits to shift (-1) + * SMx TXNFULL IRQ for signalling + * SMx clk_div = baud * 4 + */ + +/* .side_set 1 opt */ +#define PIO_UART_TX_DSS(opt, ss, delay) PIO_ASM_SIDE(1, opt, 2, ss, delay) + +/* Patching parameters */ +#define PIO_UART_TX_STOP_OFFSET 0 +#define PIO_UART_TX_STOP_0_5 1 +#define PIO_UART_TX_STOP_1 3 +#define PIO_UART_TX_STOP_1_5 5 +#define PIO_UART_TX_STOP_2 7 + +/* TX instructions */ +static const uint16_t pio_uart_tx_prg[] = { + /* wrap_bot */ + /* [stop bits : delay] => [0.5 : 1], [1 : 3], [1.5 : 5], [2 : 7]*/ + /* pull side 1 [2] */ + PIO_ASM_PULL(0, 1, PIO_UART_TX_DSS(1, 1, 3)), + /* mov x, y side 0 [3] */ + PIO_ASM_MOV(PIO_ASM_MOV_DST_X, PIO_ASM_MOV_OP_NONE, PIO_ASM_MOV_SRC_Y, + PIO_UART_TX_DSS(1, 0, 3)), + /* loop: */ + /* out pins, 1 */ + PIO_ASM_OUT(PIO_ASM_OUT_DST_PINS, 1, PIO_UART_TX_DSS(0, 0, 0)), + /* jmp x-- loop [2] */ + PIO_ASM_JMP(PIO_ASM_JMP_COND_DECX, PIO_ASM_ADDR(0, 2), PIO_UART_TX_DSS(0, 0, 2)), + /* wrap_top */ }; -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); +/** + * 8N1 initial configuration + * IN pin 0 and JMP pin mapped to the RX pin + * Scratch Y for number of bits to shift (-1) + * SMx IRQ for framing error + * SMx RXNEMPTY IRQ for signalling + * SMx clk_div = baud * 8 + */ + +/* Shift count due to right alignment */ +#define PIO_UART_RX_SHIFT_CNT(bits) (16 - (bits)) + +/* Default */ +#define PIO_UART_RX_DSS(delay) PIO_ASM_SIDE(0, 0, 0, 0, delay) + +/* RX program */ +static const uint16_t pio_uart_rx_prg[] = { + /* wrap bot */ + /* start: */ + /* wait 0 pin 0 */ + PIO_ASM_WAIT(0, PIO_ASM_WAIT_SRC_PIN, 0, PIO_UART_RX_DSS(0)), + /* mov x, y [10] */ + PIO_ASM_MOV(PIO_ASM_MOV_DST_X, PIO_ASM_MOV_OP_NONE, PIO_ASM_MOV_SRC_Y, PIO_UART_RX_DSS(10)), + /* bitloop: */ + /* in pins, 1 */ + PIO_ASM_IN(PIO_ASM_IN_SRC_PINS, 1, PIO_UART_RX_DSS(0)), + /* jmp x--, bitloop [6] */ + PIO_ASM_JMP(PIO_ASM_JMP_COND_DECX, PIO_ASM_ADDR(0, 2), PIO_UART_RX_DSS(6)), + /* jmp pin, stop */ + PIO_ASM_JMP(PIO_ASM_JMP_COND_PIN, PIO_ASM_ADDR(0, 8), PIO_UART_RX_DSS(0)), + /* irq 0 rel */ + PIO_ASM_IRQ(0, 0, PIO_ASM_INDEX(true, 0), PIO_UART_RX_DSS(0)), + /* wait 1 pin 0 */ + PIO_ASM_WAIT(1, PIO_ASM_WAIT_SRC_PIN, 0, PIO_UART_RX_DSS(0)), + /* jmp start */ + PIO_ASM_JMP(PIO_ASM_JMP_COND_ALWAYS, PIO_ASM_ADDR(0, 0), PIO_UART_RX_DSS(0)), + /* stop: */ + /* push */ + PIO_ASM_PUSH(0, 0, PIO_UART_RX_DSS(0)), + /* wrap top */ +}; + +static int pio_uart_init_tx(const struct device *dev) +{ + const struct pio_uart_config *config = dev->config; + struct pio_uart_data *data = dev->data; + pio_hw_t *pio_hw = config->pio_regs; + pio_sm_hw_t *pio_sm; + int rc; + + /* Allocate state machine */ + rc = pio_rpi_pico_alloc_sm(config->parent, 1, &data->tx_sm); + if (rc < 0) { + return rc; + } + + pio_sm = &pio_hw->sm[data->tx_sm]; + data->tx_sm_mask = BIT(data->tx_sm); + + /* Allocate instructions */ + rc = pio_rpi_pico_alloc_instr(config->parent, ARRAY_SIZE(pio_uart_tx_prg), &data->tx_prg); + if (rc < 0) { + return rc; + } + + /* Load initial program */ + pio_rpi_pico_util_load_prg(pio_hw->instr_mem, data->tx_prg, + pio_uart_tx_prg, ARRAY_SIZE(pio_uart_tx_prg)); + + /** + * 2 side set count (1 extra for enable) + * 1 set count + * 1 out count + * tx_gpio sideset base + * tx_gpio set base + * tx_gpio out base + */ + pio_sm->pinctrl = (2u << PIO_SM0_PINCTRL_SIDESET_COUNT_LSB) + | (1u << PIO_SM0_PINCTRL_SET_COUNT_LSB) + | (1u << PIO_SM0_PINCTRL_OUT_COUNT_LSB) + | (config->tx_gpio << PIO_SM0_PINCTRL_SIDESET_BASE_LSB) + | (config->tx_gpio << PIO_SM0_PINCTRL_SET_BASE_LSB) + | (config->tx_gpio << PIO_SM0_PINCTRL_OUT_BASE_LSB); + + /* Force pin to 1 */ + pio_sm->instr = PIO_ASM_SET(PIO_ASM_SET_DST_PINS, 1, PIO_UART_TX_DSS(0, 0, 0)); + + /* Force direction to output */ + pio_sm->instr = PIO_ASM_SET(PIO_ASM_SET_DST_PINDIRS, 1, PIO_UART_TX_DSS(0, 0, 0)); + + /** + * Enable side bit + * Set wraps + */ + pio_sm->execctrl = PIO_SM0_EXECCTRL_SIDE_EN_BITS + | (data->tx_prg << PIO_SM0_EXECCTRL_WRAP_BOTTOM_LSB) + | ((data->tx_prg + ARRAY_SIZE(pio_uart_tx_prg) - 1) + << PIO_SM0_EXECCTRL_WRAP_TOP_LSB); + + /** + * Join TX + * Out right shift + */ + pio_sm->shiftctrl = PIO_SM0_SHIFTCTRL_FJOIN_TX_BITS + | PIO_SM0_SHIFTCTRL_OUT_SHIFTDIR_BITS; return 0; } -static int pio_uart_rx_init(PIO pio, uint32_t sm, uint32_t rx_pin, float div) +static int pio_uart_init_rx(const struct device *dev) { - pio_sm_config sm_config; - uint32_t offset; + const struct pio_uart_config *config = dev->config; + struct pio_uart_data *data = dev->data; + pio_hw_t *pio_hw = config->pio_regs; + pio_sm_hw_t *pio_sm; + int rc; + + /* Allocate state machine */ + rc = pio_rpi_pico_alloc_sm(config->parent, 1, &data->rx_sm); + if (rc < 0) { + return rc; + } - if (!pio_can_add_program(pio, RPI_PICO_PIO_GET_PROGRAM(uart_rx))) { - return -EBUSY; + pio_sm = &pio_hw->sm[data->rx_sm]; + data->rx_sm_mask = BIT(data->rx_sm); + + /* Allocate shared instructions */ + rc = pio_rpi_pico_alloc_shared_instr(config->parent, STRINGIFY(DT_DRV_COMPAT), + ARRAY_SIZE(pio_uart_rx_prg), &data->rx_prg); + if ((rc < 0) && (rc != -EALREADY)) { + return rc; } - offset = pio_add_program(pio, RPI_PICO_PIO_GET_PROGRAM(uart_rx)); - sm_config = pio_get_default_sm_config(); + if (rc != -EALREADY) { + /* Load initial program */ + pio_rpi_pico_util_load_prg(pio_hw->instr_mem, data->rx_prg, + pio_uart_rx_prg, ARRAY_SIZE(pio_uart_rx_prg)); + } - 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)); + /** + * rx_gpio in base + * rx_gpio set base + */ + pio_sm->pinctrl = (1u << PIO_SM0_PINCTRL_SET_COUNT_LSB) + | (config->rx_gpio << PIO_SM0_PINCTRL_SET_BASE_LSB) + | (config->rx_gpio << PIO_SM0_PINCTRL_IN_BASE_LSB); - pio_sm_init(pio, sm, offset, &sm_config); - pio_sm_set_enabled(pio, sm, true); + /* Force direction to input */ + pio_sm->instr = PIO_ASM_SET(PIO_ASM_SET_DST_PINDIRS, 0, PIO_UART_RX_DSS(0)); + + /** + * Set JMP pin + * Set wraps + */ + pio_sm->execctrl = (config->rx_gpio << PIO_SM0_EXECCTRL_JMP_PIN_LSB) + | (data->rx_prg << PIO_SM0_EXECCTRL_WRAP_BOTTOM_LSB) + | ((data->rx_prg + ARRAY_SIZE(pio_uart_rx_prg) - 1) + << PIO_SM0_EXECCTRL_WRAP_TOP_LSB); + + /** + * Join RX + * In right shift + */ + pio_sm->shiftctrl = PIO_SM0_SHIFTCTRL_FJOIN_RX_BITS + | PIO_SM0_SHIFTCTRL_IN_SHIFTDIR_BITS; return 0; } -static int pio_uart_poll_in(const struct device *dev, unsigned char *c) +static int pio_uart_configure_txrx(const struct device *dev, const struct uart_config *cfg) { 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; + pio_hw_t *pio_hw = config->pio_regs; + pio_sm_hw_t *tx_sm = &pio_hw->sm[data->tx_sm]; + pio_sm_hw_t *rx_sm = &pio_hw->sm[data->rx_sm]; + uint32_t scratch_y, tx_delay, patch; + uint8_t rx_shift; + + /* Flow control not supported */ + if (cfg->flow_ctrl != UART_CFG_FLOW_CTRL_NONE) { + return -ENOTSUP; + } - /* - * 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; + /* Check parity */ + switch (cfg->parity) { + case UART_CFG_PARITY_NONE: + break; + + default: + return -ENOTSUP; } - /* Accessing the FIFO pops the read word from it */ - *c = (char)*uart_rx_fifo_msb; + /* Baud cannot be 0 */ + if (cfg->baudrate == 0) { + return -EINVAL; + } + + /* Check and set data bits (see program description) */ + switch (cfg->data_bits) { + case UART_CFG_DATA_BITS_5: + scratch_y = PIO_UART_TXRX_BITS_CNT(5); + rx_shift = PIO_UART_RX_SHIFT_CNT(5); + break; + + case UART_CFG_DATA_BITS_6: + scratch_y = PIO_UART_TXRX_BITS_CNT(6); + rx_shift = PIO_UART_RX_SHIFT_CNT(6); + break; + + case UART_CFG_DATA_BITS_7: + scratch_y = PIO_UART_TXRX_BITS_CNT(7); + rx_shift = PIO_UART_RX_SHIFT_CNT(7); + break; + + case UART_CFG_DATA_BITS_8: + scratch_y = PIO_UART_TXRX_BITS_CNT(8); + rx_shift = PIO_UART_RX_SHIFT_CNT(8); + break; + + default: + return -ENOTSUP; + } + + /* Check and set stop bits (see program description) */ + switch (cfg->stop_bits) { + case UART_CFG_STOP_BITS_0_5: + tx_delay = PIO_UART_TX_STOP_0_5; + break; + + case UART_CFG_STOP_BITS_1: + tx_delay = PIO_UART_TX_STOP_1; + break; + + case UART_CFG_STOP_BITS_1_5: + tx_delay = PIO_UART_TX_STOP_1_5; + break; + + case UART_CFG_STOP_BITS_2: + tx_delay = PIO_UART_TX_STOP_2; + break; + + default: + return -ENOTSUP; + } + + /* TX configuration (including stop bits patch) */ + tx_sm->clkdiv = PIO_SM_CLKDIV(config->clock_frequency, (cfg->baudrate * 4)); + tx_sm->instr = PIO_ASM_SET(PIO_ASM_SET_DST_Y, scratch_y, PIO_UART_TX_DSS(0, 0, 0)); + patch = PIO_ASM_PULL(0, 1, PIO_UART_TX_DSS(1, 1, tx_delay)); + pio_hw->instr_mem[PIO_UART_TX_STOP_OFFSET + data->tx_prg] = patch; + + /* RX configuration */ + rx_sm->clkdiv = PIO_SM_CLKDIV(config->clock_frequency, (cfg->baudrate * 8)); + rx_sm->instr = PIO_ASM_SET(PIO_ASM_SET_DST_Y, scratch_y, PIO_UART_RX_DSS(0)); + data->rx_shift = rx_shift; + return 0; } +static void pio_uart_enable_txrx(const struct device *dev) +{ + const struct pio_uart_config *config = dev->config; + struct pio_uart_data *data = dev->data; + pio_hw_t *pio_hw = config->pio_regs; + pio_sm_hw_t *tx_sm = &pio_hw->sm[data->tx_sm]; + pio_sm_hw_t *rx_sm = &pio_hw->sm[data->rx_sm]; + uint32_t mask = data->tx_sm_mask | data->rx_sm_mask; + + /* Go to start */ + tx_sm->instr = PIO_ASM_JMP(PIO_ASM_JMP_COND_ALWAYS, data->tx_prg, PIO_UART_TX_DSS(0, 0, 0)); + rx_sm->instr = PIO_ASM_JMP(PIO_ASM_JMP_COND_ALWAYS, data->rx_prg, PIO_UART_RX_DSS(0)); + + /* Restart clocks */ + PIO_ATOMIC_SET(pio_hw->ctrl, mask << PIO_CTRL_CLKDIV_RESTART_LSB); + + /* Restart SMs */ + PIO_ATOMIC_SET(pio_hw->ctrl, mask << PIO_CTRL_SM_RESTART_LSB); + + /* Enable SMs */ + PIO_ATOMIC_SET(pio_hw->ctrl, mask << PIO_CTRL_SM_ENABLE_LSB); +} + +static void pio_uart_disable_txrx(const struct device *dev) +{ + const struct pio_uart_config *config = dev->config; + struct pio_uart_data *data = dev->data; + pio_hw_t *pio_hw = config->pio_regs; + uint32_t mask = data->tx_sm_mask | data->rx_sm_mask; + + /* Disable SMs */ + PIO_ATOMIC_CLR(pio_hw->ctrl, mask << PIO_CTRL_SM_ENABLE_LSB); +} + +#if CONFIG_UART_INTERRUPT_DRIVEN +static int pio_uart_fifo_fill(const struct device *dev, const uint8_t *tx_data, int len) +{ + const struct pio_uart_config *config = dev->config; + struct pio_uart_data *data = dev->data; + pio_hw_t *pio_hw = config->pio_regs; + uint32_t fmask = (uint32_t)data->tx_sm_mask << PIO_FSTAT_TXFULL_LSB; + int cnt = 0; + + while (((len - cnt) > 0) && !(pio_hw->fstat & fmask)) { + pio_hw->txf[data->tx_sm] = (uint32_t)tx_data[cnt++]; + } + + return cnt; +} + +static int pio_uart_fifo_read(const struct device *dev, uint8_t *rx_data, const int len) +{ + const struct pio_uart_config *config = dev->config; + struct pio_uart_data *data = dev->data; + pio_hw_t *pio_hw = config->pio_regs; + uint32_t fmask = (uint32_t)data->rx_sm_mask << PIO_FSTAT_RXEMPTY_LSB; + io_ro_16 *fifo = (io_ro_16 *)&pio_hw->rxf[data->rx_sm] + 1; /* Upper 16 bits */ + int cnt = 0; + + while (((len - cnt) > 0) && !(pio_hw->fstat & fmask)) { + rx_data[cnt++] = (unsigned char)(*fifo >> data->rx_shift); + } + + return cnt; +} + +static inline void pio_uart_irq_generic_enable(const struct device *dev, uint32_t mask) +{ + const struct pio_uart_config *config = dev->config; + struct pio_irq_hw *irq_hw = PIO_IRQ_HW_INDEX(config->pio_regs, config->irq_idx); + + PIO_ATOMIC_SET(irq_hw->inte, mask); +} + +static inline void pio_uart_irq_generic_disable(const struct device *dev, uint32_t mask) +{ + const struct pio_uart_config *config = dev->config; + struct pio_irq_hw *irq_hw = PIO_IRQ_HW_INDEX(config->pio_regs, config->irq_idx); + + PIO_ATOMIC_CLR(irq_hw->inte, mask); +} + +static void pio_uart_irq_tx_enable(const struct device *dev) +{ + struct pio_uart_data *data = dev->data; + uint32_t mask = (uint32_t)data->tx_sm_mask << PIO_IRQ0_INTE_SM0_TXNFULL_LSB; + + pio_uart_irq_generic_enable(dev, mask); +} + +static void pio_uart_irq_rx_enable(const struct device *dev) +{ + struct pio_uart_data *data = dev->data; + uint32_t mask = (uint32_t)data->rx_sm_mask << PIO_IRQ0_INTE_SM0_RXNEMPTY_LSB; + + pio_uart_irq_generic_enable(dev, mask); +} + +static void pio_uart_irq_error_enable(const struct device *dev) +{ + struct pio_uart_data *data = dev->data; + uint32_t mask = (uint32_t)data->rx_sm_mask << PIO_IRQ0_INTE_SM0_LSB; + + pio_uart_irq_generic_enable(dev, mask); +} + +static void pio_uart_irq_tx_disable(const struct device *dev) +{ + struct pio_uart_data *data = dev->data; + uint32_t mask = (uint32_t)data->tx_sm_mask << PIO_IRQ0_INTE_SM0_TXNFULL_LSB; + + pio_uart_irq_generic_disable(dev, mask); +} + +static void pio_uart_irq_rx_disable(const struct device *dev) +{ + struct pio_uart_data *data = dev->data; + uint32_t mask = (uint32_t)data->rx_sm_mask << PIO_IRQ0_INTE_SM0_RXNEMPTY_LSB; + + pio_uart_irq_generic_disable(dev, mask); +} + +static void pio_uart_irq_error_disable(const struct device *dev) +{ + struct pio_uart_data *data = dev->data; + uint32_t mask = (uint32_t)data->rx_sm_mask << PIO_IRQ0_INTE_SM0_LSB; + + pio_uart_irq_generic_disable(dev, mask); +} + +static int pio_uart_irq_tx_ready(const struct device *dev) +{ + const struct pio_uart_config *config = dev->config; + struct pio_uart_data *data = dev->data; + pio_hw_t *pio_hw = config->pio_regs; + struct pio_irq_hw *irq_hw = PIO_IRQ_HW_INDEX(config->pio_regs, config->irq_idx); + uint32_t imask = (uint32_t)data->tx_sm_mask << PIO_IRQ0_INTE_SM0_TXNFULL_LSB; + uint32_t fmask = (uint32_t)data->tx_sm_mask << PIO_FSTAT_TXFULL_LSB; + + /* True only if interrupts enabled and fifo not full */ + return ((irq_hw->inte & imask) && !(pio_hw->fstat & fmask)) ? 1 : 0; +} + +static int pio_uart_irq_rx_ready(const struct device *dev) +{ + const struct pio_uart_config *config = dev->config; + struct pio_uart_data *data = dev->data; + pio_hw_t *pio_hw = config->pio_regs; + uint32_t fmask = (uint32_t)data->rx_sm_mask << PIO_FSTAT_RXEMPTY_LSB; + + /* True if fifo not empty */ + return !(pio_hw->fstat & fmask) ? 1 : 0; +} + +static int pio_uart_irq_tx_complete(const struct device *dev) +{ + const struct pio_uart_config *config = dev->config; + struct pio_uart_data *data = dev->data; + pio_hw_t *pio_hw = config->pio_regs; + uint32_t mask = (uint32_t)data->tx_sm_mask << PIO_FSTAT_TXEMPTY_LSB; + + /* True if fifo empty */ + return (pio_hw->fstat & mask) ? 1 : 0; +} + +static int pio_uart_irq_is_pending(const struct device *dev) +{ + const struct pio_uart_config *config = dev->config; + struct pio_uart_data *data = dev->data; + pio_hw_t *pio_hw = config->pio_regs; + uint32_t mask; + + mask = (uint32_t)data->tx_sm_mask << PIO_INTR_SM0_TXNFULL_LSB + | (uint32_t)data->rx_sm_mask << PIO_INTR_SM0_RXNEMPTY_LSB + | (uint32_t)data->rx_sm_mask << PIO_INTR_SM0_LSB; + + /* True if any IRQ is pending */ + return (pio_hw->intr & mask) ? 1 : 0; +} + +static int pio_uart_irq_update(const struct device *dev) +{ + return 1; +} + +static void pio_uart_irq_callback_set(const struct device *dev, + uart_irq_callback_user_data_t cb, + void *cb_data) +{ + struct pio_uart_data *data = dev->data; + + data->irq_cb = cb; + data->irq_cb_data = cb_data; +} + +static void pio_uart_irq(const struct device *dev) +{ + const struct pio_uart_config *config = dev->config; + struct pio_uart_data *data = dev->data; + pio_hw_t *pio_hw = config->pio_regs; + uint32_t mask; + + /* Filter events */ + mask = (uint32_t)data->tx_sm_mask << PIO_INTR_SM0_TXNFULL_LSB + | (uint32_t)data->rx_sm_mask << PIO_INTR_SM0_RXNEMPTY_LSB + | (uint32_t)data->rx_sm_mask << PIO_INTR_SM0_LSB; + + if ((pio_hw->intr & mask) && (data->irq_cb)) { + data->irq_cb(dev, data->irq_cb_data); + } +} +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +#if CONFIG_UART_USE_RUNTIME_CONFIGURE +static int pio_uart_configure(const struct device *dev, const struct uart_config *cfg) +{ + struct pio_uart_data *data = dev->data; + int rc; + + __ASSERT_NO_MSG(cfg); + + /* No point if no changes */ + rc = memcmp(cfg, &data->uart_config, sizeof(struct uart_config)); + if (rc != 0) { + /* Disable / config / enable. Will retain current config if invalid */ + pio_uart_disable_txrx(dev); + rc = pio_uart_configure_txrx(dev, cfg); + if (rc == 0) { + data->uart_config = *cfg; + } + pio_uart_enable_txrx(dev); + } + + return rc; +} + +static int pio_uart_config_get(const struct device *dev, struct uart_config *cfg) +{ + struct pio_uart_data *data = dev->data; + + *cfg = data->uart_config; + + return 0; +} +#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ + +static int pio_uart_err_check(const struct device *dev) +{ + const struct pio_uart_config *config = dev->config; + struct pio_uart_data *data = dev->data; + pio_hw_t *pio_hw = config->pio_regs; + int err = 0; + + if (pio_hw->fdebug & ((uint32_t)data->rx_sm_mask << PIO_FDEBUG_RXSTALL_LSB)) { + pio_hw->fdebug = (uint32_t)data->rx_sm_mask << PIO_FDEBUG_RXSTALL_LSB; + err |= UART_ERROR_OVERRUN; + } + + if (pio_hw->irq & data->rx_sm_mask) { + pio_hw->irq = data->rx_sm_mask; + err |= UART_ERROR_FRAMING; + } + + return err; +} + 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_hw_t *pio_hw = config->pio_regs; + + while (pio_hw->fstat & ((uint32_t)data->tx_sm_mask << PIO_FSTAT_TXFULL_LSB)) { + } - pio_sm_put_blocking(pio_rpi_pico_get_pio(config->piodev), data->tx_sm, (uint32_t)c); + pio_hw->txf[data->tx_sm] = (uint32_t)c; } -static int pio_uart_init(const struct device *dev) +static int pio_uart_poll_in(const struct device *dev, unsigned char *c) { 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_hw_t *pio_hw = config->pio_regs; + io_ro_16 *fifo = (io_ro_16 *)&pio_hw->rxf[data->rx_sm] + 1; /* Upper 16 bits */ - pio = pio_rpi_pico_get_pio(config->piodev); - sm_clock_div = (float)clock_get_hz(clk_sys) / (CYCLES_PER_BIT * config->baudrate); + if (pio_hw->fstat & ((uint32_t)data->rx_sm_mask << PIO_FSTAT_RXEMPTY_LSB)) { + return -1; + } - retval = pio_rpi_pico_allocate_sm(config->piodev, &tx_sm); - retval |= pio_rpi_pico_allocate_sm(config->piodev, &rx_sm); + *c = (unsigned char)(*fifo >> data->rx_shift); - if (retval < 0) { - return retval; + return 0; +} + +static int pio_uart_init(const struct device *dev) +{ + const struct pio_uart_config *config = dev->config; + struct pio_uart_data *data = dev->data; + int rc; + + if (!device_is_ready(config->parent)) { + return -ENODEV; } - data->tx_sm = tx_sm; - data->rx_sm = rx_sm; + rc = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (rc < 0) { + return rc; + } + + rc = pio_uart_init_tx(dev); + if (rc < 0) { + return rc; + } - retval = pio_uart_tx_init(pio, tx_sm, config->tx_pin, sm_clock_div); - if (retval < 0) { - return retval; + rc = pio_uart_init_rx(dev); + if (rc < 0) { + return rc; } - retval = pio_uart_rx_init(pio, rx_sm, config->rx_pin, sm_clock_div); - if (retval < 0) { - return retval; + rc = pio_uart_configure_txrx(dev, &data->uart_config); + if (rc < 0) { + return rc; } - return pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); +#if CONFIG_UART_INTERRUPT_DRIVEN + config->irq_config(dev); +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + + pio_uart_enable_txrx(dev); + + return 0; } static const struct uart_driver_api pio_uart_driver_api = { .poll_in = pio_uart_poll_in, .poll_out = pio_uart_poll_out, + .err_check = pio_uart_err_check, +#if CONFIG_UART_USE_RUNTIME_CONFIGURE + .configure = pio_uart_configure, + .config_get = pio_uart_config_get, +#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ +#if CONFIG_UART_INTERRUPT_DRIVEN + .fifo_fill = pio_uart_fifo_fill, + .fifo_read = pio_uart_fifo_read, + .irq_tx_enable = pio_uart_irq_tx_enable, + .irq_tx_disable = pio_uart_irq_tx_disable, + .irq_tx_ready = pio_uart_irq_tx_ready, + .irq_rx_enable = pio_uart_irq_rx_enable, + .irq_rx_disable = pio_uart_irq_rx_disable, + .irq_tx_complete = pio_uart_irq_tx_complete, + .irq_rx_ready = pio_uart_irq_rx_ready, + .irq_err_enable = pio_uart_irq_error_enable, + .irq_err_disable = pio_uart_irq_error_disable, + .irq_is_pending = pio_uart_irq_is_pending, + .irq_update = pio_uart_irq_update, + .irq_callback_set = pio_uart_irq_callback_set, +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ }; -#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), \ +#if CONFIG_UART_INTERRUPT_DRIVEN +#define PIO_UART_IRQ_CONFIG(inst) \ +static void pio_uart_irq_config##inst(const struct device *dev) \ +{ \ + ARG_UNUSED(dev); \ + static struct pio_rpi_pico_irq_cfg pio_uart_irq_cfg##inst = { \ + .irq_func = pio_uart_irq, \ + .irq_param = DEVICE_DT_GET(DT_DRV_INST(inst)), \ + .irq_idx = DT_INST_PROP_BY_IDX(inst, pio_interrupts, 0), \ + }; \ + pio_rpi_pico_irq_register(DEVICE_DT_GET(DT_INST_PARENT(inst)), &pio_uart_irq_cfg##inst);\ + pio_rpi_pico_irq_enable(DEVICE_DT_GET(DT_INST_PARENT(inst)), &pio_uart_irq_cfg##inst); \ +} + +#define PIO_UART_GEN_IRQ_CONFIG(inst) \ + .irq_config = pio_uart_irq_config##inst, \ + .irq_idx = DT_INST_PROP_BY_IDX(inst, pio_interrupts, 0), + +#else +#define PIO_UART_IRQ_CONFIG(inst) +#define PIO_UART_GEN_IRQ_CONFIG(inst) +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +#define PIO_UART_INIT(inst) \ + BUILD_ASSERT(DT_INST_ON_BUS(inst, pio_rpi_pico), \ + "node " DT_NODE_PATH(DT_DRV_INST(inst)) " is not assigned to a PIO instance"); \ + \ + PIO_UART_IRQ_CONFIG(inst) \ + \ + PINCTRL_DT_INST_DEFINE(inst); \ + \ + static struct pio_uart_data pio_uart_data##inst = { \ + .uart_config = { \ + .baudrate = DT_INST_PROP_OR(inst, current_speed, 115200), \ + .parity = DT_INST_ENUM_IDX_OR(inst, parity, UART_CFG_PARITY_NONE), \ + .stop_bits = DT_INST_ENUM_IDX_OR(inst, stop_bits, UART_CFG_STOP_BITS_1),\ + .data_bits = DT_INST_ENUM_IDX_OR(inst, data_bits, UART_CFG_DATA_BITS_8),\ + .flow_ctrl = 0, \ + }, \ + }; \ + \ + static const struct pio_uart_config pio_uart_config##inst = { \ + .parent = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ + .pio_regs = (pio_hw_t *)DT_INST_PIO_RPI_PICO_REG_ADDR(inst), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + .clock_frequency = DT_INST_PIO_RPI_PICO_CLOCK_FREQ_HZ(inst), \ + .tx_gpio = DT_INST_PIO_RPI_PICO_PIN_BY_NAME(inst, default, 0, tx_gpio, 0), \ + .rx_gpio = DT_INST_PIO_RPI_PICO_PIN_BY_NAME(inst, default, 0, rx_gpio, 0), \ + PIO_UART_GEN_IRQ_CONFIG(inst) \ }; \ - 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); + DEVICE_DT_INST_DEFINE(inst, &pio_uart_init, \ + NULL, \ + &pio_uart_data##inst, \ + &pio_uart_config##inst, \ + PRE_KERNEL_1, \ + CONFIG_SERIAL_INIT_PRIORITY, \ + &pio_uart_driver_api); DT_INST_FOREACH_STATUS_OKAY(PIO_UART_INIT) diff --git a/dts/arm/rpi_pico/rp2040.dtsi b/dts/arm/rpi_pico/rp2040.dtsi index 24c0a3e7bae01..644106d1f44f6 100644 --- a/dts/arm/rpi_pico/rp2040.dtsi +++ b/dts/arm/rpi_pico/rp2040.dtsi @@ -213,6 +213,9 @@ reg = <0x50200000 DT_SIZE_K(4)>; clocks = <&system_clk>; resets = <&reset RPI_PICO_RESETS_RESET_PIO0>; + interrupts = <7 RPI_PICO_DEFAULT_IRQ_PRIORITY>, \ + <8 RPI_PICO_DEFAULT_IRQ_PRIORITY>; + interrupt-names = "pio00", "pio01"; status = "disabled"; }; @@ -221,6 +224,9 @@ reg = <0x50300000 DT_SIZE_K(4)>; clocks = <&system_clk>; resets = <&reset RPI_PICO_RESETS_RESET_PIO1>; + interrupts = <9 RPI_PICO_DEFAULT_IRQ_PRIORITY>, \ + <10 RPI_PICO_DEFAULT_IRQ_PRIORITY>; + interrupt-names = "pio10", "pio11"; status = "disabled"; }; }; diff --git a/dts/bindings/misc/raspberrypi,pico-pio-device.yaml b/dts/bindings/misc/raspberrypi,pico-pio-device.yaml index a75a59107c73d..09dfff5a79f63 100644 --- a/dts/bindings/misc/raspberrypi,pico-pio-device.yaml +++ b/dts/bindings/misc/raspberrypi,pico-pio-device.yaml @@ -1,9 +1,17 @@ +# Copyright (c) 2023 Ionut Pavel # 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" +on-bus: pio-rpi-pico -include: pinctrl-device.yaml +properties: + pio,interrupts: + type: array + description: Shared PIO interrupts for device + + pio,interrupt-names: + type: string-array + description: Name of each shared PIO interrupt diff --git a/dts/bindings/misc/raspberrypi,pico-pio.yaml b/dts/bindings/misc/raspberrypi,pico-pio.yaml index 0bdbd8ab65898..73f3000cd5301 100644 --- a/dts/bindings/misc/raspberrypi,pico-pio.yaml +++ b/dts/bindings/misc/raspberrypi,pico-pio.yaml @@ -1,3 +1,4 @@ +# Copyright (c) 2023 Ionut Pavel # Copyright (c) 2023, TOKITA Hiroshi # SPDX-License-Identifier: Apache-2.0 @@ -6,3 +7,15 @@ description: Raspberry Pi Pico PIO compatible: "raspberrypi,pico-pio" include: [base.yaml, reset-device.yaml] + +bus: pio-rpi-pico + +properties: + reg: + required: true + + interrupts: + required: true + + clocks: + required: true diff --git a/dts/bindings/serial/raspberrypi,pico-uart-pio.yaml b/dts/bindings/serial/raspberrypi,pico-uart-pio.yaml index bedbf4f590124..81ea3f0d1130e 100644 --- a/dts/bindings/serial/raspberrypi,pico-uart-pio.yaml +++ b/dts/bindings/serial/raspberrypi,pico-uart-pio.yaml @@ -2,4 +2,4 @@ description: Raspberry Pi Pico PIO UART compatible: "raspberrypi,pico-uart-pio" -include: [uart-controller.yaml, "raspberrypi,pico-pio-device.yaml"] +include: ["raspberrypi,pico-pio-device.yaml", uart-controller.yaml, pinctrl-device.yaml] diff --git a/include/zephyr/drivers/misc/pio_rpi_pico/pio_rpi_pico.h b/include/zephyr/drivers/misc/pio_rpi_pico/pio_rpi_pico.h index 9c6cefb81ac61..4fb039455c8f5 100644 --- a/include/zephyr/drivers/misc/pio_rpi_pico/pio_rpi_pico.h +++ b/include/zephyr/drivers/misc/pio_rpi_pico/pio_rpi_pico.h @@ -1,59 +1,55 @@ /* + * Copyright (c) 2023 Ionut Pavel * Copyright (c) 2023 Tokita, Hiroshi * Copyright (c) 2023 Yonatan Schachter - * Copyright (c) 2023 Ionut Pavel * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_DRIVERS_MISC_PIO_PICO_RPI_PIO_PICO_RPI_H_ -#define ZEPHYR_DRIVERS_MISC_PIO_PICO_RPI_PIO_PICO_RPI_H_ +#ifndef ZEPHYR_DRIVERS_MISC_PIO_RPI_PICO_H_ +#define ZEPHYR_DRIVERS_MISC_PIO_RPI_PICO_H_ +#include +#include #include - -#include +#include /** - * @brief Utility macro to define a PIO program. The program is a list - * of 16 bit instructions, generated by the pioasm tool. + * @brief Get the clock frequency of the associated PIO instance * - * @param name Name of the program. - * @param wrap_target Wrap target as specified by the PIO program. - * @param wrap Wrap source as specified by the PIO program. - * @param ... Comma separated list of PIO instructions. - */ -#define RPI_PICO_PIO_DEFINE_PROGRAM(name, wrap_target, wrap, ...) \ - static const uint32_t name ## _wrap_target = wrap_target; \ - static const uint32_t name ## _wrap = wrap; \ - static const uint16_t name ## _program_instructions[] = { \ - __VA_ARGS__ \ - }; \ - static const struct pio_program name ## _program = { \ - .instructions = name ## _program_instructions, \ - .length = ARRAY_SIZE(name ## _program_instructions), \ - .origin = -1, \ - } - -/** - * @brief Utility macro to get the wrap target of a program. + * Example devicetree fragment: * - * @param name Name of the program. - */ -#define RPI_PICO_PIO_GET_WRAP_TARGET(name) name ## _wrap_target - -/** - * @brief Utility macro to get the wrap source of a program. + * @code{.dts} + * pio { + * status = "okay"; + * clocks = <&system_clk>; // 125000000 + * c: child {}; + * }; + * @endcode * - * @param name Name of the program. + * Example usage: + * + * @code{.c} + * // child.c + * DT_PIO_RPI_PICO_CLOCK_FREQ_HZ(node, 0) // 125000000 + * @endcode + * + * @param node_id node identifier + * @return the parent's clock frequency */ -#define RPI_PICO_PIO_GET_WRAP(name) name ## _wrap +#define DT_PIO_RPI_PICO_CLOCK_FREQ_HZ(node_id) \ + DT_PROP(DT_CLOCKS_CTLR(DT_PARENT(node_id)), clock_frequency) /** - * @brief Utility macro to get a pointer to a PIO program. + * @brief Get the clock frequency of the associated PIO instance + * + * @param inst instance number + * @return the parent's clock frequency * - * @param name Name of the program. + * @see DT_PIO_RPI_PICO_CLOCK_FREQ_HZ */ -#define RPI_PICO_PIO_GET_PROGRAM(name) &name ## _program +#define DT_INST_PIO_RPI_PICO_CLOCK_FREQ_HZ(inst) \ + DT_PIO_RPI_PICO_CLOCK_FREQ_HZ(DT_DRV_INST(inst)) /** * @brief Get a pin number from a pinctrl / group name and index @@ -88,9 +84,9 @@ * Example usage: * * @code{.c} - * DT_RPI_PICO_PIO_PIN_BY_NAME(node, default, 0, tx_gpio, 0) // 0 - * DT_RPI_PICO_PIO_PIN_BY_NAME(node, default, 0, tx_gpio, 1) // 2 - * DT_RPI_PICO_PIO_PIN_BY_NAME(node, default, 0, rx_gpio, 0) // 1 + * DT_PIO_RPI_PICO_PIN_BY_NAME(node, default, 0, tx_gpio, 0) // 0 + * DT_PIO_RPI_PICO_PIN_BY_NAME(node, default, 0, tx_gpio, 1) // 2 + * DT_PIO_RPI_PICO_PIN_BY_NAME(node, default, 0, rx_gpio, 0) // 1 * @endcode * * @param node_id node identifier @@ -100,7 +96,7 @@ * @param g_idx group index * @return pin number */ -#define DT_RPI_PICO_PIO_PIN_BY_NAME(node_id, p_name, p_idx, g_name, g_idx) \ +#define DT_PIO_RPI_PICO_PIN_BY_NAME(node_id, p_name, p_idx, g_name, g_idx) \ RP2_GET_PIN_NUM(DT_PROP_BY_IDX( \ DT_CHILD(DT_PINCTRL_BY_NAME(node_id, p_name, p_idx), g_name), pinmux, g_idx)) @@ -114,36 +110,115 @@ * @param g_idx group index * @return pin number * - * @see DT_RPI_PICO_PIO_PIN_BY_NAME + * @see DT_PIO_RPI_PICO_PIN_BY_NAME */ -#define DT_INST_RPI_PICO_PIO_PIN_BY_NAME(inst, p_name, p_idx, g_name, g_idx) \ - DT_RPI_PICO_PIO_PIN_BY_NAME(DT_DRV_INST(inst), p_name, p_idx, g_name, g_idx) +#define DT_INST_PIO_RPI_PICO_PIN_BY_NAME(inst, p_name, p_idx, g_name, g_idx) \ + DT_PIO_RPI_PICO_PIN_BY_NAME(DT_DRV_INST(inst), p_name, p_idx, g_name, g_idx) /** - * @brief Get the pin number of a pin by its name. + * @brief Get assigned PIO base address + * + * @param node_id node identifier + * @return base address + */ +#define DT_PIO_RPI_PICO_REG_ADDR(node_id) \ + DT_REG_ADDR(DT_PARENT(node_id)) + +/** + * @brief Get assigned PIO base address * * @param inst instance number - * @param name name of the pin (e.g. tx, rx, sck). + * @return base address + * + * @see DT_PIO_RPI_PICO_REG_ADDR */ -#define DT_INST_PIO_PIN_BY_NAME(inst, name) \ - DT_PIO_PIN_BY_NAME(DT_DRV_INST(inst), name) +#define DT_INST_PIO_RPI_PICO_REG_ADDR(inst) \ + DT_PIO_RPI_PICO_REG_ADDR(DT_DRV_INST(inst)) /** - * Get PIO object + * @brief PIO shared IRQ handler type * - * @param dev Pointer to device structure for rpi_pio device instance - * @return PIO object + * @param dev Pointer to registered device */ -PIO pio_rpi_pico_get_pio(const struct device *dev); +typedef void (*pio_rpi_pico_irq_t)(const struct device *dev); /** - * Allocate a state machine. + * @brief PIO shared IRQ configuration data + */ +struct pio_rpi_pico_irq_cfg { + /* Device node */ + sys_snode_t node; + + /* IRQ callback */ + pio_rpi_pico_irq_t irq_func; + + /* Callback parameter */ + const void *irq_param; + + /* Shared IRQ index */ + uint8_t irq_idx; + + /* IRQ status */ + bool enabled; +}; + +/** + * @brief Register a shared IRQ + * + * @param dev Pointer to the parent device + * @param cfg Pointer to the IRQ configuration + */ +void pio_rpi_pico_irq_register(const struct device *dev, struct pio_rpi_pico_irq_cfg *cfg); + +/** + * @brief Enable a shared IRQ + * + * @param dev Pointer to the parent device + * @param cfg Pointer to the IRQ configuration + */ +void pio_rpi_pico_irq_enable(const struct device *dev, struct pio_rpi_pico_irq_cfg *cfg); + +/** + * @brief Disable a shared IRQ + * + * @param dev Pointer to the parent device + * @param cfg Pointer to the IRQ configuration + */ +void pio_rpi_pico_irq_disable(const struct device *dev, struct pio_rpi_pico_irq_cfg *cfg); + +/** + * @brief Dynamic state machine allocator + * + * @param dev Pointer to the PIO device structure + * @param count State machines to allocate + * @param sm Output pointer for the first allocated state machine + * @return -EIO on error + */ +int pio_rpi_pico_alloc_sm(const struct device *dev, size_t count, uint8_t *sm); + +/** + * @brief Dynamic instruction allocator + * + * @param dev Pointer to the PIO device structure + * @param count Instructions to allocate + * @param instr Output pointer for the first allocated instruction + * @return -ENOMEM on error + */ +int pio_rpi_pico_alloc_instr(const struct device *dev, size_t count, uint8_t *instr); + +/** + * @brief Dynamic shared instruction allocator + * + * @param dev Pointer to the PIO device structure + * @param key String key to identify the shared section + * @param count Instructions to allocate + * @param instr Output pointer for the first allocated instruction + * @return -ENOMEM on error + * @return -EALREADY if the section was already allocated * - * @param dev Pointer to device structure for rpi_pio device instance - * @param sm Pointer to store allocated state machine - * @retval 0 on success - * @retval -EBUSY if no state machines were available + * @note in case of -EALREADY, instr will contain the previous allocated instruction */ -int pio_rpi_pico_allocate_sm(const struct device *dev, size_t *sm); +int pio_rpi_pico_alloc_shared_instr(const struct device *dev, const char *key, + size_t count, uint8_t *instr); -#endif /* ZEPHYR_DRIVERS_MISC_PIO_PICO_RPI_PIO_PICO_RPI_H_ */ +#endif /* ZEPHYR_DRIVERS_MISC_PIO_RPI_PICO_H_ */ diff --git a/include/zephyr/drivers/misc/pio_rpi_pico/pio_rpi_pico_util.h b/include/zephyr/drivers/misc/pio_rpi_pico/pio_rpi_pico_util.h new file mode 100644 index 0000000000000..ae5f05df4973a --- /dev/null +++ b/include/zephyr/drivers/misc/pio_rpi_pico/pio_rpi_pico_util.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2023 Ionut Pavel + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_MISC_PIO_RPI_PICO_UTIL_H_ +#define ZEPHYR_DRIVERS_MISC_PIO_RPI_PICO_UTIL_H_ + +#include +#include + +/* PIO registers */ +#include + +/** Indexed interrupt access macros TODO: should be indexed in HW structs */ + +struct pio_irq_hw { + io_rw_32 inte; + io_rw_32 intf; + io_ro_32 ints; +}; + +#define PIO_IRQ_HW_INDEX(hw, index) \ + (&(((struct pio_irq_hw *)&((hw)->inte0))[(index)])) + +/** Shared registers atomic bit ops */ + +#define PIO_ATOMIC_SET(reg, mask) \ + (*((io_wo_32 *)(((io_wo_8 *)(&(reg))) + REG_ALIAS_SET_BITS)) = (mask)) + +#define PIO_ATOMIC_CLR(reg, mask) \ + (*((io_wo_32 *)(((io_wo_8 *)(&(reg))) + REG_ALIAS_CLR_BITS)) = (mask)) + +#define PIO_ATOMIC_XOR(reg, mask) \ + (*((io_wo_32 *)(((io_wo_8 *)(&(reg))) + REG_ALIAS_XOR_BITS)) = (mask)) + +/** Instruction macros */ + +#define PIO_ISTR_IS_JMP(instr) \ + (((instr) >> 13) == 0x00u) + +/** Prescaler macros */ + +#define PIO_SM_CLKDIV(fin, fout) \ + (uint32_t)(((((uint64_t)(fin)) * 65536u) / (fout)) & 0xFFFFFF00u) + +/** Index macros */ + +#define PIO_ASM_INDEX(rel, idx) \ + ((!!(rel) ? BIT(4) : 0) | ((idx) & BIT_MASK(4))) + +/** Bit count macros */ + +#define PIO_ASM_BITCOUNT(count) \ + ((count) & BIT_MASK(5)) + +/** Address macros */ + +#define PIO_ASM_ADDR(base, offs) \ + (((base) + (offs)) & BIT_MASK(5)) + +/** Side set macros */ + +#define PIO_ASM_SIDE(opt, opt_val, ss_cnt, ss_val, delay) \ + (((!!(opt) ? ( \ + ((opt_val) << ((ss_cnt) - 1)) | ((ss_val) & BIT_MASK((ss_cnt) - 1)) \ + ) : ( \ + (ss_val) & BIT_MASK((ss_cnt)) \ + )) << (5 - (ss_cnt))) | ((delay) & BIT_MASK(5 - (ss_cnt)))) + +/** JMP Instruction macros */ + +#define PIO_ASM_JMP_COND_ALWAYS 0u +#define PIO_ASM_JMP_COND_NOTX 1u +#define PIO_ASM_JMP_COND_DECX 2u +#define PIO_ASM_JMP_COND_NOTY 3u +#define PIO_ASM_JMP_COND_DECY 4u +#define PIO_ASM_JMP_COND_XNOTEQY 5u +#define PIO_ASM_JMP_COND_PIN 6u +#define PIO_ASM_JMP_COND_NOTOSRE 7u + +#define PIO_ASM_JMP(cond, addr, dss) \ + (uint16_t)((0x0u << 13) \ + | (((dss) & BIT_MASK(5)) << 8) \ + | (((cond) & BIT_MASK(3)) << 5) \ + | (((addr) & BIT_MASK(5)) << 0)) + +/** WAIT Instruction macros */ + +#define PIO_ASM_WAIT_SRC_GPIO 0u +#define PIO_ASM_WAIT_SRC_PIN 1u +#define PIO_ASM_WAIT_SRC_IRQ 2u + +#define PIO_ASM_WAIT(pol, src, ind, dss) \ + (uint16_t)((0x1u << 13) \ + | (((dss) & BIT_MASK(5)) << 8) \ + | (((pol) & BIT_MASK(1)) << 7) \ + | (((src) & BIT_MASK(2)) << 5) \ + | (((ind) & BIT_MASK(5)) << 0)) + +/** IN Instruction macros */ + +#define PIO_ASM_IN_SRC_PINS 0u +#define PIO_ASM_IN_SRC_X 1u +#define PIO_ASM_IN_SRC_Y 2u +#define PIO_ASM_IN_SRC_NULL 3u +#define PIO_ASM_IN_SRC_ISR 6u +#define PIO_ASM_IN_SRC_OSR 7u + +#define PIO_ASM_IN(src, bcnt, dss) \ + (uint16_t)((0x2u << 13) \ + | (((dss) & BIT_MASK(5)) << 8) \ + | (((src) & BIT_MASK(3)) << 5) \ + | (((bcnt) & BIT_MASK(5)) << 0)) + +/** OUT Instruction macros */ + +#define PIO_ASM_OUT_DST_PINS 0u +#define PIO_ASM_OUT_DST_X 1u +#define PIO_ASM_OUT_DST_Y 2u +#define PIO_ASM_OUT_DST_NULL 3u +#define PIO_ASM_OUT_DST_PINDIRS 4u +#define PIO_ASM_OUT_DST_PC 5u +#define PIO_ASM_OUT_DST_ISR 6u +#define PIO_ASM_OUT_DST_EXEC 7u + +#define PIO_ASM_OUT(dst, bcnt, dss) \ + (uint16_t)((0x3u << 13) \ + | (((dss) & BIT_MASK(5)) << 8) \ + | (((dst) & BIT_MASK(3)) << 5) \ + | (((bcnt) & BIT_MASK(5)) << 0)) + +/** PUSH Instruction macros */ + +#define PIO_ASM_PUSH(iff, blk, dss) \ + (uint16_t)((0x4u << 13) \ + | (((dss) & BIT_MASK(5)) << 8) \ + | (((0u) & BIT_MASK(1)) << 7) \ + | (((iff) & BIT_MASK(1)) << 6) \ + | (((blk) & BIT_MASK(1)) << 5) \ + | (((0u) & BIT_MASK(5)) << 0)) + +/** PULL Instruction macros */ + +#define PIO_ASM_PULL(ife, blk, dss) \ + (uint16_t)((0x4u << 13) \ + | (((dss) & BIT_MASK(5)) << 8) \ + | (((1u) & BIT_MASK(1)) << 7) \ + | (((ife) & BIT_MASK(1)) << 6) \ + | (((blk) & BIT_MASK(1)) << 5) \ + | (((0u) & BIT_MASK(5)) << 0)) + +/** MOV Instruction macros */ + +#define PIO_ASM_MOV_DST_PINS 0u +#define PIO_ASM_MOV_DST_X 1u +#define PIO_ASM_MOV_DST_Y 2u +#define PIO_ASM_MOV_DST_EXEC 4u +#define PIO_ASM_MOV_DST_PC 5u +#define PIO_ASM_MOV_DST_ISR 6u +#define PIO_ASM_MOV_DST_OSR 7u + +#define PIO_ASM_MOV_OP_NONE 0u +#define PIO_ASM_MOV_OP_INVERT 1u +#define PIO_ASM_MOV_OP_BITREVERSE 2u + +#define PIO_ASM_MOV_SRC_PINS 0u +#define PIO_ASM_MOV_SRC_X 1u +#define PIO_ASM_MOV_SRC_Y 2u +#define PIO_ASM_MOV_SRC_NULL 3u +#define PIO_ASM_MOV_SRC_STATUS 5u +#define PIO_ASM_MOV_SRC_ISR 6u +#define PIO_ASM_MOV_SRC_OSR 7u + +#define PIO_ASM_MOV(dst, op, src, dss) \ + (uint16_t)((0x5u << 13) \ + | (((dss) & BIT_MASK(5)) << 8) \ + | (((dst) & BIT_MASK(3)) << 5) \ + | (((op) & BIT_MASK(2)) << 3) \ + | (((src) & BIT_MASK(3)) << 0)) + +/** IRQ Instruction macros */ + +#define PIO_ASM_IRQ(clr, wait, ind, dss) \ + (uint16_t)((0x6u << 13) \ + | (((dss) & BIT_MASK(5)) << 8) \ + | (((0u) & BIT_MASK(1)) << 7) \ + | (((clr) & BIT_MASK(1)) << 6) \ + | (((wait) & BIT_MASK(1)) << 5) \ + | (((ind) & BIT_MASK(5)) << 0)) + +/** SET Instruction macros */ + +#define PIO_ASM_SET_DST_PINS 0u +#define PIO_ASM_SET_DST_X 1u +#define PIO_ASM_SET_DST_Y 2u +#define PIO_ASM_SET_DST_PINDIRS 4u + +#define PIO_ASM_SET(dst, data, dss) \ + (uint16_t)((0x7u << 13) \ + | (((dss) & BIT_MASK(5)) << 8) \ + | (((dst) & BIT_MASK(3)) << 5) \ + | (((data) & BIT_MASK(5)) << 0)) + +/** + * @brief Load and patch program + * + * @param imem Pointer to the instruction memory + * @param base Base address + * @param src Pointer to the source data + * @param size Source data size + * + * @note User should assure no overflow will happen + */ +static inline void pio_rpi_pico_util_load_prg(io_wo_32 *imem, uint8_t base, + const uint16_t *src, size_t size) +{ + io_wo_32 *dst = &imem[base]; + uint16_t instr; + size_t i; + + for (i = 0u; i < size; i++) { + instr = src[i]; + if (PIO_ISTR_IS_JMP(instr)) { + instr += base; + } + dst[i] = instr; + } +} + +#endif /* ZEPHYR_DRIVERS_MISC_PIO_RPI_PICO_UTIL_H_ */ diff --git a/modules/hal_rpi_pico/CMakeLists.txt b/modules/hal_rpi_pico/CMakeLists.txt index c085785a09366..9db2b66e4d94f 100644 --- a/modules/hal_rpi_pico/CMakeLists.txt +++ b/modules/hal_rpi_pico/CMakeLists.txt @@ -122,14 +122,4 @@ if(CONFIG_HAS_RPI_PICO) COMPILE_FLAGS $ ) - zephyr_library_sources_ifdef(CONFIG_PICOSDK_USE_PIO - ${rp2_common_dir}/hardware_pio/pio.c) - zephyr_include_directories_ifdef(CONFIG_PICOSDK_USE_PIO - ${rp2_common_dir}/hardware_pio/include) - - zephyr_library_sources_ifdef(CONFIG_PICOSDK_USE_CLAIM - ${rp2_common_dir}/hardware_claim/claim.c) - zephyr_include_directories_ifdef(CONFIG_PICOSDK_USE_CLAIM - ${rp2_common_dir}/hardware_claim/include) - endif() diff --git a/modules/hal_rpi_pico/Kconfig b/modules/hal_rpi_pico/Kconfig index 4baf11dd406d2..ecb4c4993c6af 100644 --- a/modules/hal_rpi_pico/Kconfig +++ b/modules/hal_rpi_pico/Kconfig @@ -34,12 +34,6 @@ config PICOSDK_USE_DMA help Use the DMA driver from pico-sdk -config PICOSDK_USE_PIO - bool - select PICOSDK_USE_CLAIM - help - Use the PIO driver from pico-sdk - config PICOSDK_USE_CLAIM bool help diff --git a/samples/boards/rpi_pico/uart_pio/CMakeLists.txt b/samples/boards/rpi_pico/uart_pio/CMakeLists.txt index 56520b0d85de7..011872491e85d 100644 --- a/samples/boards/rpi_pico/uart_pio/CMakeLists.txt +++ b/samples/boards/rpi_pico/uart_pio/CMakeLists.txt @@ -1,7 +1,5 @@ -# SPDX-License-Identifier: Apache-2.0 - -cmake_minimum_required(VERSION 3.20.0) +cmake_minimum_required(VERSION 3.15.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(uart_pio) +project(pio_shell_uart) target_sources(app PRIVATE src/main.c) diff --git a/samples/boards/rpi_pico/uart_pio/app-pinctrl.dtsi b/samples/boards/rpi_pico/uart_pio/app-pinctrl.dtsi new file mode 100644 index 0000000000000..8b6387f85f1f2 --- /dev/null +++ b/samples/boards/rpi_pico/uart_pio/app-pinctrl.dtsi @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023, Ionut Pavel + * Copyright (c) 2023 Yonatan Schachter + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + pio0_uart0_default: pio0_uart0_default { + tx_gpio { + pinmux = ; + }; + + rx_gpio { + pinmux = ; + input-enable; + bias-pull-up; + }; + }; +}; diff --git a/samples/boards/rpi_pico/uart_pio/app.overlay b/samples/boards/rpi_pico/uart_pio/app.overlay new file mode 100644 index 0000000000000..345345cdd13b1 --- /dev/null +++ b/samples/boards/rpi_pico/uart_pio/app.overlay @@ -0,0 +1,30 @@ +#include "app-pinctrl.dtsi" + +/ { + chosen { + zephyr,console = &pio0_uart0; + zephyr,shell-uart = &pio0_uart0; + }; +}; + +&uart0 { + status = "disabled"; +}; + +&pio0 { + status = "okay"; + + pio0_uart0: pio0_uart0 { + compatible = "raspberrypi,pico-uart-pio"; + + status = "okay"; + + pio,interrupts = <0>; + pio,interrupt-names = "shared"; + + pinctrl-0 = <&pio0_uart0_default>; + pinctrl-names = "default"; + + current-speed = <115200>; + }; +}; diff --git a/samples/boards/rpi_pico/uart_pio/boards/rpi_pico.overlay b/samples/boards/rpi_pico/uart_pio/boards/rpi_pico.overlay deleted file mode 100644 index 3b18c49d56cda..0000000000000 --- a/samples/boards/rpi_pico/uart_pio/boards/rpi_pico.overlay +++ /dev/null @@ -1,45 +0,0 @@ -&pinctrl { - pio1_uart0_default: pio1_uart0_default { - rx_pins { - pinmux = ; - input-enable; - bias-pull-up; - }; - tx_pins { - pinmux = ; - }; - }; - - pio1_uart1_default: pio1_uart1_default { - rx_pins { - pinmux = ; - input-enable; - bias-pull-up; - }; - tx_pins { - pinmux = ; - }; - }; -}; - -&pio1 { - status = "okay"; - - pio1_uart0: uart0 { - pinctrl-0 = <&pio1_uart0_default>; - pinctrl-names = "default"; - - compatible = "raspberrypi,pico-uart-pio"; - current-speed = <115200>; - status = "okay"; - }; - - pio1_uart1: uart1 { - pinctrl-0 = <&pio1_uart1_default>; - pinctrl-names = "default"; - - compatible = "raspberrypi,pico-uart-pio"; - current-speed = <115200>; - status = "okay"; - }; -}; diff --git a/samples/boards/rpi_pico/uart_pio/prj.conf b/samples/boards/rpi_pico/uart_pio/prj.conf index b2a4ba591044e..95f17cdfc6c02 100644 --- a/samples/boards/rpi_pico/uart_pio/prj.conf +++ b/samples/boards/rpi_pico/uart_pio/prj.conf @@ -1 +1,5 @@ -# nothing here +CONFIG_LOG=y +CONFIG_SHELL=y +CONFIG_SERIAL=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_UART_CONSOLE=y diff --git a/samples/boards/rpi_pico/uart_pio/src/main.c b/samples/boards/rpi_pico/uart_pio/src/main.c index 6e3fdd727991d..776d16bacc4f7 100644 --- a/samples/boards/rpi_pico/uart_pio/src/main.c +++ b/samples/boards/rpi_pico/uart_pio/src/main.c @@ -1,36 +1,19 @@ /* + * Copyright (c) 2023 Ionut Pavel * Copyright (c) 2023 Yonatan Schachter * * SPDX-License-Identifier: Apache-2.0 */ #include -#include -#include -int main(void) -{ - char data; - const struct device *uart0 = DEVICE_DT_GET(DT_NODELABEL(pio1_uart0)); - const struct device *uart1 = DEVICE_DT_GET(DT_NODELABEL(pio1_uart1)); - - if (!device_is_ready(uart0)) { - return 0; - } - - if (!device_is_ready(uart1)) { - return 0; - } +#include +LOG_MODULE_REGISTER(main); +void main(void) +{ while (1) { - if (!uart_poll_in(uart0, &data)) { - uart_poll_out(uart0, data); - } - - if (!uart_poll_in(uart1, &data)) { - uart_poll_out(uart1, data); - } + k_msleep(1000); + LOG_INF("One second passed..."); } - - return 0; }