rp2040: Initial support for CANbus

Add support for CANbus on the rp2040 using the can2040 "software
canbus" implementation.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2022-05-23 01:04:32 -04:00
parent f10fd7c2fa
commit a831254e83
4 changed files with 104 additions and 7 deletions

View File

@ -83,6 +83,19 @@ choice
config RP2040_SERIAL_UART0 config RP2040_SERIAL_UART0
bool "Serial (on UART0 GPIO1/GPIO0)" bool "Serial (on UART0 GPIO1/GPIO0)"
select SERIAL select SERIAL
config RP2040_CANBUS
bool "CAN bus"
select CANSERIAL
endchoice endchoice
config RP2040_CANBUS_GPIO_RX
int "CAN RX gpio number" if CANBUS
default 4
range 0 29
config RP2040_CANBUS_GPIO_TX
int "CAN TX gpio number" if CANBUS
default 5
range 0 29
endif endif

View File

@ -3,10 +3,10 @@
# Setup the toolchain # Setup the toolchain
CROSS_PREFIX=arm-none-eabi- CROSS_PREFIX=arm-none-eabi-
dirs-y += src/rp2040 src/generic lib/rp2040/elf2uf2 dirs-y += src/rp2040 src/generic lib/rp2040/elf2uf2 lib/fast-hash lib/can2040
CFLAGS += -mcpu=cortex-m0plus -mthumb -Ilib/cmsis-core CFLAGS += -mcpu=cortex-m0plus -mthumb -Ilib/cmsis-core
CFLAGS += -Ilib/rp2040 -Ilib/rp2040/cmsis_include CFLAGS += -Ilib/rp2040 -Ilib/rp2040/cmsis_include -Ilib/fast-hash -Ilib/can2040
CFLAGS_klipper.elf += --specs=nano.specs --specs=nosys.specs CFLAGS_klipper.elf += --specs=nano.specs --specs=nosys.specs
CFLAGS_klipper.elf += -T $(OUT)src/rp2040/rp2040_link.ld CFLAGS_klipper.elf += -T $(OUT)src/rp2040/rp2040_link.ld
@ -19,6 +19,9 @@ src-y += generic/timer_irq.c rp2040/timer.c rp2040/bootrom.c
src-$(CONFIG_USBSERIAL) += rp2040/usbserial.c generic/usb_cdc.c src-$(CONFIG_USBSERIAL) += rp2040/usbserial.c generic/usb_cdc.c
src-$(CONFIG_USBSERIAL) += rp2040/chipid.c src-$(CONFIG_USBSERIAL) += rp2040/chipid.c
src-$(CONFIG_SERIAL) += rp2040/serial.c generic/serial_irq.c src-$(CONFIG_SERIAL) += rp2040/serial.c generic/serial_irq.c
src-$(CONFIG_CANSERIAL) += rp2040/can.c rp2040/chipid.c ../lib/can2040/can2040.c
src-$(CONFIG_CANSERIAL) += generic/canserial.c generic/canbus.c
src-$(CONFIG_CANSERIAL) += ../lib/fast-hash/fasthash.c
src-$(CONFIG_HAVE_GPIO_HARD_PWM) += rp2040/hard_pwm.c src-$(CONFIG_HAVE_GPIO_HARD_PWM) += rp2040/hard_pwm.c
src-$(CONFIG_HAVE_GPIO_SPI) += rp2040/spi.c src-$(CONFIG_HAVE_GPIO_SPI) += rp2040/spi.c
src-$(CONFIG_HAVE_GPIO_I2C) += rp2040/i2c.c src-$(CONFIG_HAVE_GPIO_I2C) += rp2040/i2c.c

78
src/rp2040/can.c Normal file
View File

@ -0,0 +1,78 @@
// Serial over CAN emulation for rp2040 using can2040 software canbus
//
// Copyright (C) 2022 Kevin O'Connor <kevin@koconnor.net>
//
// This file may be distributed under the terms of the GNU GPLv3 license.
#include <stdint.h> // uint32_t
#include <string.h> // memcpy
#include "autoconf.h" // CONFIG_CANBUS_FREQUENCY
#include "board/armcm_boot.h" // armcm_enable_irq
#include "board/io.h" // readl
#include "can2040.h" // can2040_setup
#include "command.h" // DECL_CONSTANT_STR
#include "fasthash.h" // fasthash64
#include "generic/canbus.h" // canbus_notify_tx
#include "generic/canserial.h" // CANBUS_ID_ADMIN
#include "hardware/structs/resets.h" // RESETS_RESET_PIO0_BITS
#include "internal.h" // DMA_IRQ_0_IRQn
#include "sched.h" // DECL_INIT
#define GPIO_STR_CAN_RX "gpio" __stringify(CONFIG_RP2040_CANBUS_GPIO_RX)
#define GPIO_STR_CAN_TX "gpio" __stringify(CONFIG_RP2040_CANBUS_GPIO_TX)
DECL_CONSTANT_STR("RESERVE_PINS_CAN", GPIO_STR_CAN_RX "," GPIO_STR_CAN_TX);
static struct can2040 cbus;
// Transmit a packet
int
canbus_send(struct canbus_msg *msg)
{
int ret = can2040_transmit(&cbus, (void*)msg);
if (ret < 0)
return -1;
return CANMSG_DATA_LEN(msg);
}
// Setup the receive packet filter
void
canbus_set_filter(uint32_t id)
{
// Filter not implemented (and not necessary)
}
// can2040 callback function - handle rx and tx notifications
static void
can2040_cb(struct can2040 *cd, uint32_t notify, struct can2040_msg *msg)
{
if (notify & CAN2040_NOTIFY_TX) {
canbus_notify_tx();
return;
}
if (notify & CAN2040_NOTIFY_RX)
canbus_process_data((void*)msg);
}
// Main PIO irq handler
void
PIOx_IRQHandler(void)
{
can2040_pio_irq_handler(&cbus);
}
void
can_init(void)
{
// Setup canbus
can2040_setup(&cbus, 0);
can2040_callback_config(&cbus, can2040_cb);
// Enable irqs
armcm_enable_irq(PIOx_IRQHandler, PIO0_IRQ_0_IRQn, 1);
// Start canbus
uint32_t pclk = get_pclock_frequency(RESETS_RESET_PIO0_RESET);
can2040_start(&cbus, pclk, CONFIG_CANBUS_FREQUENCY
, CONFIG_RP2040_CANBUS_GPIO_RX, CONFIG_RP2040_CANBUS_GPIO_TX);
}
DECL_INIT(can_init);

View File

@ -4,11 +4,10 @@
// //
// This file may be distributed under the terms of the GNU GPLv3 license. // This file may be distributed under the terms of the GNU GPLv3 license.
#define CHIP_UID_LEN 8
#include <string.h> // memcpy #include <string.h> // memcpy
#include "autoconf.h" // CONFIG_USB_SERIAL_NUMBER_CHIPID #include "autoconf.h" // CONFIG_USB_SERIAL_NUMBER_CHIPID
#include "board/irq.h" // irq_disable, irq_enable #include "board/irq.h" // irq_disable, irq_enable
#include "board/canserial.h" // canserial_set_uuid
#include "generic/usb_cdc.h" // usb_fill_serial #include "generic/usb_cdc.h" // usb_fill_serial
#include "generic/usbstd.h" // usb_string_descriptor #include "generic/usbstd.h" // usb_string_descriptor
#include "sched.h" // DECL_INIT #include "sched.h" // DECL_INIT
@ -16,6 +15,8 @@
#include "hardware/structs/ssi.h" // ssi_hw #include "hardware/structs/ssi.h" // ssi_hw
#include "internal.h" #include "internal.h"
#define CHIP_UID_LEN 8
static struct { static struct {
struct usb_string_descriptor desc; struct usb_string_descriptor desc;
uint16_t data[CHIP_UID_LEN * 2]; uint16_t data[CHIP_UID_LEN * 2];
@ -120,13 +121,15 @@ read_unique_id(uint8_t *out)
void void
chipid_init(void) chipid_init(void)
{ {
if (!CONFIG_USB_SERIAL_NUMBER_CHIPID) if (!(CONFIG_USB_SERIAL_NUMBER_CHIPID || CONFIG_CANBUS))
return; return;
uint8_t data[8] = {0}; uint8_t data[8] = {0};
read_unique_id(data); read_unique_id(data);
usb_fill_serial(&cdc_chipid.desc, ARRAY_SIZE(cdc_chipid.data) if (CONFIG_USB_SERIAL_NUMBER_CHIPID)
, data); usb_fill_serial(&cdc_chipid.desc, ARRAY_SIZE(cdc_chipid.data), data);
if (CONFIG_CANBUS)
canserial_set_uuid(data, CHIP_UID_LEN);
} }
DECL_INIT(chipid_init); DECL_INIT(chipid_init);