From e164c5097059badfc67cb7c6de65db69e58879e0 Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Fri, 13 Dec 2024 14:16:43 -0500 Subject: [PATCH] can2040: Program gpiobase register on rp2350 Allow gpio pins above gpio31 to be used. Signed-off-by: Kevin O'Connor --- docs/API.md | 20 +++++++++++++------- docs/Features.md | 3 ++- src/can2040.c | 33 ++++++++++++++++++++++++++------- 3 files changed, 41 insertions(+), 15 deletions(-) diff --git a/docs/API.md b/docs/API.md index 276aee6..b787e90 100644 --- a/docs/API.md +++ b/docs/API.md @@ -163,13 +163,19 @@ The `sys_clock` parameter specifies the system clock rate (for example The `bitrate` parameter specifies the CAN bus speed (for example `500000` for a 500Kbit/s CAN bus). -The `gpio_rx` parameter specifies the rp2040/rp2350 gpio number that -is routed to the "CAN RX" pin of the CAN bus transceiver. It should -be between 0 and 29 (for GPIO0 to GPIO29). - -The `gpio_tx` parameter specifies the rp2040/rp2340 gpio number that -is routed to the "CAN TX" pin of the CAN bus transceiver. It should -be between 0 and 29 (for GPIO0 to GPIO29). +The `gpio_rx` parameter specifies the gpio number that is routed to +the "CAN RX" pin of the CAN bus transceiver. On rp2040 it should be +between 0 and 29 (for GPIO0 to GPIO29). On the rp2350 chips it may be +between 0 and 31 (for GPIO0 to GPIO31), or alternatively between 16 +and 47 (for GPIO16 to GPIO47) if both `gpio_rx` and `gpio_tx` are +between 16 and 47. + +The `gpio_tx` parameter specifies the gpio number that is routed to +the "CAN TX" pin of the CAN bus transceiver. On rp2040 chips it +should be between 0 and 29 (for GPIO0 to GPIO29). On the rp2350 chips +it may be between 0 and 31 (for GPIO0 to GPIO31), or alternatively +between 16 and 47 (for GPIO16 to GPIO47) if both `gpio_rx` and +`gpio_tx` are between 16 and 47. After calling this function, activity on the CAN bus may result in the user specified `can2040_rx_cb` callback being invoked. diff --git a/docs/Features.md b/docs/Features.md index a36a2ed..39bfb33 100644 --- a/docs/Features.md +++ b/docs/Features.md @@ -19,7 +19,8 @@ bus implementation. * Works with standard CAN bus transceivers. On the rp2040, any two gpio pins may be used for the "can rx" and "can tx" wires. On the - rp2350, any two gpio pins from GPIO0 to GPIO31 may be used. + rp2350, any two gpio pins from GPIO0 to GPIO31 or any two pins from + GPIO16 to GPIO47 may be used. # Protocol details diff --git a/src/can2040.c b/src/can2040.c index b256fd3..f11b381 100644 --- a/src/can2040.c +++ b/src/can2040.c @@ -130,19 +130,29 @@ static const uint16_t can2040_program_instructions[] = { #define SI_RX_DATA PIO_IRQ0_INTE_SM1_RXNEMPTY_BITS #define SI_TXPENDING PIO_IRQ0_INTE_SM1_BITS // Misc bit manually forced +// Return the gpio bank offset (on rp2350 chips) +static uint32_t +pio_gpiobase(struct can2040 *cd) +{ + if (!IS_RP2350) + return 0; + return (cd->gpio_rx > 31 || cd->gpio_tx > 31) ? 16 : 0; +} + // Setup PIO "sync" state machine (state machine 0) static void pio_sync_setup(struct can2040 *cd) { pio_hw_t *pio_hw = cd->pio_hw; pio_sm_hw_t *sm = &pio_hw->sm[0]; + uint32_t gpio_rx = (cd->gpio_rx - pio_gpiobase(cd)) & 0x1f; sm->execctrl = ( - cd->gpio_rx << PIO_SM0_EXECCTRL_JMP_PIN_LSB + gpio_rx << PIO_SM0_EXECCTRL_JMP_PIN_LSB | (can2040_offset_sync_end - 1) << PIO_SM0_EXECCTRL_WRAP_TOP_LSB | can2040_offset_sync_signal_start << PIO_SM0_EXECCTRL_WRAP_BOTTOM_LSB); sm->pinctrl = ( 1 << PIO_SM0_PINCTRL_SET_COUNT_LSB - | cd->gpio_rx << PIO_SM0_PINCTRL_SET_BASE_LSB); + | gpio_rx << PIO_SM0_PINCTRL_SET_BASE_LSB); sm->instr = 0xe080; // set pindirs, 0 sm->pinctrl = 0; pio_hw->txf[0] = 9 + 6 * PIO_CLOCK_PER_BIT / 2; @@ -156,10 +166,11 @@ pio_rx_setup(struct can2040 *cd) { pio_hw_t *pio_hw = cd->pio_hw; pio_sm_hw_t *sm = &pio_hw->sm[1]; + uint32_t gpio_rx = (cd->gpio_rx - pio_gpiobase(cd)) & 0x1f; sm->execctrl = ( (can2040_offset_shared_rx_end - 1) << PIO_SM0_EXECCTRL_WRAP_TOP_LSB | can2040_offset_shared_rx_read << PIO_SM0_EXECCTRL_WRAP_BOTTOM_LSB); - sm->pinctrl = cd->gpio_rx << PIO_SM0_PINCTRL_IN_BASE_LSB; + sm->pinctrl = gpio_rx << PIO_SM0_PINCTRL_IN_BASE_LSB; sm->shiftctrl = 0; // flush fifo on a restart sm->shiftctrl = (PIO_SM0_SHIFTCTRL_FJOIN_RX_BITS | PIO_RX_WAKE_BITS << PIO_SM0_SHIFTCTRL_PUSH_THRESH_LSB @@ -176,7 +187,8 @@ pio_match_setup(struct can2040 *cd) sm->execctrl = ( (can2040_offset_match_end - 1) << PIO_SM0_EXECCTRL_WRAP_TOP_LSB | can2040_offset_shared_rx_read << PIO_SM0_EXECCTRL_WRAP_BOTTOM_LSB); - sm->pinctrl = cd->gpio_rx << PIO_SM0_PINCTRL_IN_BASE_LSB; + uint32_t gpio_rx = (cd->gpio_rx - pio_gpiobase(cd)) & 0x1f; + sm->pinctrl = gpio_rx << PIO_SM0_PINCTRL_IN_BASE_LSB; sm->shiftctrl = 0; sm->instr = 0xe040; // set y, 0 sm->instr = 0xa0e2; // mov osr, y @@ -190,16 +202,18 @@ pio_tx_setup(struct can2040 *cd) { pio_hw_t *pio_hw = cd->pio_hw; pio_sm_hw_t *sm = &pio_hw->sm[3]; + uint32_t gpio_rx = (cd->gpio_rx - pio_gpiobase(cd)) & 0x1f; + uint32_t gpio_tx = (cd->gpio_tx - pio_gpiobase(cd)) & 0x1f; sm->execctrl = ( - cd->gpio_rx << PIO_SM0_EXECCTRL_JMP_PIN_LSB + gpio_rx << PIO_SM0_EXECCTRL_JMP_PIN_LSB | can2040_offset_tx_conflict << PIO_SM0_EXECCTRL_WRAP_TOP_LSB | can2040_offset_tx_conflict << PIO_SM0_EXECCTRL_WRAP_BOTTOM_LSB); sm->shiftctrl = (PIO_SM0_SHIFTCTRL_FJOIN_TX_BITS | PIO_SM0_SHIFTCTRL_AUTOPULL_BITS); sm->pinctrl = (1 << PIO_SM0_PINCTRL_SET_COUNT_LSB | 1 << PIO_SM0_PINCTRL_OUT_COUNT_LSB - | cd->gpio_tx << PIO_SM0_PINCTRL_SET_BASE_LSB - | cd->gpio_tx << PIO_SM0_PINCTRL_OUT_BASE_LSB); + | gpio_tx << PIO_SM0_PINCTRL_SET_BASE_LSB + | gpio_tx << PIO_SM0_PINCTRL_OUT_BASE_LSB); sm->instr = 0xe001; // set pins, 1 sm->instr = 0xe081; // set pindirs, 1 } @@ -402,6 +416,11 @@ pio_setup(struct can2040 *cd, uint32_t sys_clock, uint32_t bitrate) for (i=0; i<4; i++) pio_hw->sm[i].clkdiv = div << PIO_SM0_CLKDIV_FRAC_LSB; + // Configure gpiobase (on rp2350) +#if IS_RP2350 + pio_hw->gpiobase = pio_gpiobase(cd); +#endif + // Configure state machines pio_sm_setup(cd);