Skip to content
Open
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
20 changes: 14 additions & 6 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ their callback function.

## can2040_start

`void can2040_start(struct can2040 *cd, uint32_t sys_clock, uint32_t bitrate, uint32_t gpio_rx, uint32_t gpio_tx)`
`void can2040_start(struct can2040 *cd, uint32_t sys_clock, uint32_t bitrate, int32_t gpio_rx, int32_t gpio_tx)`

This function starts the main can2040 CAN bus implementation. The
provided GPIO pins will be configured and associated with the
Expand All @@ -176,11 +176,19 @@ 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.
the "CAN TX" pin of the CAN bus transceiver (or to `-1` to disable
transmissions). 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.

If `gpio_tx` is set to a `-1` then can2040 will run in a "silent
mode". That is, it will not transmit or acknowledge messages, but it
can still report messages successfully sent, received, and
acknowledged by other nodes on the bus. If this facility is used, it
is the caller's responsibility to ensure the canbus transceiver
hardware is in a recessive transmit state (ie, the actual "gpio_tx"
wire going to the canbus transceiver should be set to a "high" state).

After calling this function, activity on the CAN bus may result in the
user specified `can2040_rx_cb` callback being invoked.
Expand Down
21 changes: 14 additions & 7 deletions src/can2040.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Software CANbus implementation for rp2040
// Software CANbus implementation for rp2040/rp2350
//
// Copyright (C) 2022-2025 Kevin O'Connor <kevin@koconnor.net>
// Copyright (C) 2022-2026 Kevin O'Connor <kevin@koconnor.net>
//
// This file may be distributed under the terms of the GNU GPLv3 license.

Expand Down Expand Up @@ -213,10 +213,13 @@ pio_tx_setup(struct can2040 *cd)
| 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
uint32_t pinctrl = 0;
if (cd->gpio_tx >= 0)
pinctrl = (1 << PIO_SM0_PINCTRL_SET_COUNT_LSB
| 1 << PIO_SM0_PINCTRL_OUT_COUNT_LSB
| gpio_tx << PIO_SM0_PINCTRL_SET_BASE_LSB
| gpio_tx << PIO_SM0_PINCTRL_OUT_BASE_LSB);
sm->pinctrl = pinctrl;
sm->instr = 0xe001; // set pins, 1
sm->instr = 0xe081; // set pindirs, 1
}
Expand Down Expand Up @@ -430,7 +433,8 @@ pio_setup(struct can2040 *cd, uint32_t sys_clock, uint32_t bitrate)
// Map Rx/Tx gpios
uint32_t pio_func = 6 + cd->pio_num;
rp2040_gpio_peripheral(cd->gpio_rx, pio_func, 1);
rp2040_gpio_peripheral(cd->gpio_tx, pio_func, 0);
if (cd->gpio_tx >= 0)
rp2040_gpio_peripheral(cd->gpio_tx, pio_func, 0);
}


Expand Down Expand Up @@ -1349,7 +1353,7 @@ can2040_check_transmit(struct can2040 *cd)
uint32_t tx_pull_pos = readl(&cd->tx_pull_pos);
uint32_t tx_push_pos = cd->tx_push_pos;
uint32_t pending = tx_push_pos - tx_pull_pos;
return pending < ARRAY_SIZE(cd->tx_queue);
return pending < ARRAY_SIZE(cd->tx_queue) && cd->gpio_tx >= 0;
}

// API function to transmit a message
Expand All @@ -1359,7 +1363,7 @@ can2040_transmit(struct can2040 *cd, struct can2040_msg *msg)
uint32_t tx_pull_pos = readl(&cd->tx_pull_pos);
uint32_t tx_push_pos = cd->tx_push_pos;
uint32_t pending = tx_push_pos - tx_pull_pos;
if (pending >= ARRAY_SIZE(cd->tx_queue))
if (pending >= ARRAY_SIZE(cd->tx_queue) || cd->gpio_tx < 0)
// Tx queue full
return -1;

Expand Down Expand Up @@ -1448,8 +1452,11 @@ can2040_callback_config(struct can2040 *cd, can2040_rx_cb rx_cb)
// API function to start CANbus interface
void
can2040_start(struct can2040 *cd, uint32_t sys_clock, uint32_t bitrate
, uint32_t gpio_rx, uint32_t gpio_tx)
, int32_t gpio_rx, int32_t gpio_tx)
{
if (IS_RP2350 && ((gpio_rx < 16 && gpio_tx > 31)
|| (gpio_rx > 31 && gpio_tx < 16)))
gpio_tx = -1;
cd->gpio_rx = gpio_rx;
cd->gpio_tx = gpio_tx;
data_state_clear_bits(cd);
Expand Down
4 changes: 2 additions & 2 deletions src/can2040.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ struct can2040_stats {
void can2040_setup(struct can2040 *cd, uint32_t pio_num);
void can2040_callback_config(struct can2040 *cd, can2040_rx_cb rx_cb);
void can2040_start(struct can2040 *cd, uint32_t sys_clock, uint32_t bitrate
, uint32_t gpio_rx, uint32_t gpio_tx);
, int32_t gpio_rx, int32_t gpio_tx);
void can2040_stop(struct can2040 *cd);
void can2040_get_statistics(struct can2040 *cd, struct can2040_stats *stats);
void can2040_pio_irq_handler(struct can2040 *cd);
Expand All @@ -61,7 +61,7 @@ struct can2040 {
// Setup
uint32_t pio_num;
void *pio_hw;
uint32_t gpio_rx, gpio_tx;
int32_t gpio_rx, gpio_tx;
can2040_rx_cb rx_cb;
struct can2040_stats stats;

Expand Down