From 9521f1d54b9c4ea533046cc9b3c7fadd3798c94f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Fri, 26 Jan 2024 13:05:33 +0100 Subject: [PATCH] usbcan: support `ip link set can0 type can bitrate $bitrate` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes Klipper to be a quite functional usb-to-can with externally controllable bitrate. Quite handy, as the bitrate is now configured by the system. Signed-off-by: Kamil TrzciƄski --- src/atsam/fdcan.c | 17 ++++++++++++-- src/atsamd/fdcan.c | 17 ++++++++++++-- src/generic/canbus.h | 2 ++ src/generic/usb_canbus.c | 50 +++++++++++++++++++++++++++++++++++----- src/rp2040/can.c | 16 +++++++++++-- src/stm32/can.c | 20 ++++++++++++++-- src/stm32/fdcan.c | 17 ++++++++++++-- 7 files changed, 123 insertions(+), 16 deletions(-) diff --git a/src/atsam/fdcan.c b/src/atsam/fdcan.c index 20c86b443..a3d31ff73 100644 --- a/src/atsam/fdcan.c +++ b/src/atsam/fdcan.c @@ -296,10 +296,16 @@ can_init(void) gpio_peripheral(GPIO_Rx, CAN_FUNCTION_Rx, 1); gpio_peripheral(GPIO_Tx, CAN_FUNCTION_Tx, 0); + canhw_start(CONFIG_CANBUS_FREQUENCY); +} +DECL_INIT(can_init); +void +canhw_start(uint32_t canbus_frequency) +{ uint32_t pclock = get_pclock_frequency(CANx_GCLK_ID); - uint32_t btr = compute_btr(pclock, CONFIG_CANBUS_FREQUENCY); + uint32_t btr = compute_btr(pclock, canbus_frequency); /*##-1- Configure the CAN #######################################*/ @@ -349,4 +355,11 @@ can_init(void) CANx->MCAN_ILE = MCAN_ILE_EINT0; CANx->MCAN_IE = MCAN_IE_RF0NE | FDCAN_IE_TC | MCAN_IE_PEDE | MCAN_IE_PEAE; } -DECL_INIT(can_init); + +void +canhw_stop(void) +{ + NVIC_DisableIRQ(CANx_IRQn); + CANx->MCAN_ILE &= ~MCAN_ILE_EINT0; + CANx->MCAN_IE &= ~(MCAN_IE_RF0NE | FDCAN_IE_TC); +} diff --git a/src/atsamd/fdcan.c b/src/atsamd/fdcan.c index e8c107654..91c37aa12 100644 --- a/src/atsamd/fdcan.c +++ b/src/atsamd/fdcan.c @@ -311,10 +311,16 @@ can_init(void) gpio_peripheral(GPIO_Rx, CAN_FUNCTION, 1); gpio_peripheral(GPIO_Tx, CAN_FUNCTION, 0); + canhw_start(CONFIG_CANBUS_FREQUENCY); +} +DECL_INIT(can_init); +void +canhw_start(uint32_t canbus_frequency) +{ uint32_t pclock = get_pclock_frequency(CANx_GCLK_ID); - uint32_t btr = compute_btr(pclock, CONFIG_CANBUS_FREQUENCY); + uint32_t btr = compute_btr(pclock, canbus_frequency); /*##-1- Configure the CAN #######################################*/ @@ -356,4 +362,11 @@ can_init(void) CANx->ILE.reg = CAN_ILE_EINT0; CANx->IE.reg = CAN_IE_RF0NE | FDCAN_IE_TC | CAN_IE_PEDE | CAN_IE_PEAE; } -DECL_INIT(can_init); + +void +canhw_stop(void) +{ + NVIC_DisableIRQ(CANx_IRQn); + CANx->ILE.reg &= ~CAN_ILE_EINT0; + CANx->IE.reg &= ~(CAN_IE_RF0NE | FDCAN_IE_TC); +} diff --git a/src/generic/canbus.h b/src/generic/canbus.h index a0a2c2abe..e96e73a0e 100644 --- a/src/generic/canbus.h +++ b/src/generic/canbus.h @@ -28,6 +28,8 @@ enum { }; // callbacks provided by board specific code +void canhw_start(uint32_t frequency); +void canhw_stop(void); int canhw_send(struct canbus_msg *msg); void canhw_set_filter(uint32_t id); void canhw_get_status(struct canbus_status *status); diff --git a/src/generic/usb_canbus.c b/src/generic/usb_canbus.c index 3505717c6..b26567b63 100644 --- a/src/generic/usb_canbus.c +++ b/src/generic/usb_canbus.c @@ -43,6 +43,11 @@ enum gs_usb_breq { GS_USB_BREQ_BT_CONST_EXT, }; +enum gs_can_mode { + GS_CAN_MODE_RESET = 0, + GS_CAN_MODE_START +}; + struct gs_host_config { uint32_t byte_order; } __packed; @@ -134,6 +139,8 @@ enum { HS_TX_LOCAL = 4, }; +uint32_t canbus_frequency = CONFIG_CANBUS_FREQUENCY; + // Send a message to the Linux host static int send_frame(struct canbus_msg *msg) @@ -551,6 +558,7 @@ enum { static void *usb_xfer_data; static uint8_t usb_xfer_size, usb_xfer_flags; +static void (*usb_xfer_complete)(); // Set the USB "stall" condition static void @@ -562,7 +570,8 @@ usb_do_stall(void) // Transfer data on the usb endpoint 0 static void -usb_do_xfer(void *data, uint_fast8_t size, uint_fast8_t flags) +usb_do_xfer2(void *data, uint_fast8_t size, uint_fast8_t flags + , void (*complete)()) { for (;;) { uint_fast8_t xs = size; @@ -590,7 +599,11 @@ usb_do_xfer(void *data, uint_fast8_t size, uint_fast8_t flags) // Must send zero-length-packet continue; usb_xfer_flags = 0; + usb_xfer_complete = NULL; usb_notify_ep0(); + if (complete) { + complete(); + } return; } continue; @@ -600,6 +613,7 @@ usb_do_xfer(void *data, uint_fast8_t size, uint_fast8_t flags) usb_xfer_data = data; usb_xfer_size = size; usb_xfer_flags = flags; + usb_xfer_complete = complete; return; } // Error @@ -608,6 +622,12 @@ usb_do_xfer(void *data, uint_fast8_t size, uint_fast8_t flags) } } +static void +usb_do_xfer(void *data, uint_fast8_t size, uint_fast8_t flags) +{ + usb_do_xfer2(data, size, flags, NULL); +} + static void usb_req_get_descriptor(struct usb_ctrlrequest *req) { @@ -709,20 +729,37 @@ gs_breq_bt_const(struct usb_ctrlrequest *req) struct gs_device_bittiming device_bittiming; +static void +gs_breq_bittiming_complete(void) +{ + uint32_t bit_time = 1 + device_bittiming.prop_seg + + device_bittiming.phase_seg1 + device_bittiming.phase_seg2; + canbus_frequency = bt_const.fclk_can / (device_bittiming.brp * bit_time); +} + static void gs_breq_bittiming(struct usb_ctrlrequest *req) { - // Bit timing is ignored for now - usb_do_xfer(&device_bittiming, sizeof(device_bittiming), UX_READ); + usb_do_xfer2(&device_bittiming, sizeof(device_bittiming), UX_READ + , gs_breq_bittiming_complete); } struct gs_device_mode device_mode; +static void +gs_breq_mode_complete(void) +{ + if (device_mode.mode == GS_CAN_MODE_START) + canhw_start(canbus_frequency); + else if (device_mode.mode == GS_CAN_MODE_RESET) + canhw_stop(); +} + static void gs_breq_mode(struct usb_ctrlrequest *req) { - // Mode is ignored for now - usb_do_xfer(&device_mode, sizeof(device_mode), UX_READ); + usb_do_xfer2(&device_mode, sizeof(device_mode), UX_READ + , gs_breq_mode_complete); } static void @@ -769,7 +806,8 @@ usb_ep0_task(void) if (!sched_check_wake(&usb_ep0_wake)) return; if (usb_xfer_flags) - usb_do_xfer(usb_xfer_data, usb_xfer_size, usb_xfer_flags); + usb_do_xfer2(usb_xfer_data, usb_xfer_size, usb_xfer_flags + , usb_xfer_complete); else usb_state_ready(); } diff --git a/src/rp2040/can.c b/src/rp2040/can.c index 0e62ac3b2..aeeae010e 100644 --- a/src/rp2040/can.c +++ b/src/rp2040/can.c @@ -83,13 +83,25 @@ can_init(void) // Setup canbus can2040_setup(&cbus, 0); can2040_callback_config(&cbus, can2040_cb); + canhw_start(CONFIG_CANBUS_FREQUENCY); +} +DECL_INIT(can_init); +void +canhw_start(uint32_t canbus_frequency) +{ // 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 + can2040_start(&cbus, pclk, canbus_frequency , CONFIG_RPXXXX_CANBUS_GPIO_RX, CONFIG_RPXXXX_CANBUS_GPIO_TX); } -DECL_INIT(can_init); + +void +canhw_stop(void) +{ + can2040_stop(&cbus); + NVIC_DisableIRQ(PIO0_IRQ_0_IRQn); +} diff --git a/src/stm32/can.c b/src/stm32/can.c index 6d35e677b..862d87351 100644 --- a/src/stm32/can.c +++ b/src/stm32/can.c @@ -300,10 +300,16 @@ can_init(void) gpio_peripheral(GPIO_Rx, CAN_FUNCTION, 1); gpio_peripheral(GPIO_Tx, CAN_FUNCTION, 0); + canhw_start(CONFIG_CANBUS_FREQUENCY); +} +DECL_INIT(can_init); +void +canhw_start(uint32_t canbus_frequency) +{ uint32_t pclock = get_pclock_frequency((uint32_t)SOC_CAN); - uint32_t btr = compute_btr(pclock, CONFIG_CANBUS_FREQUENCY); + uint32_t btr = compute_btr(pclock, canbus_frequency); /*##-1- Configure the CAN #######################################*/ @@ -335,4 +341,14 @@ can_init(void) armcm_enable_irq(CAN_IRQHandler, CAN_SCE_IRQn, 0); SOC_CAN->IER = CAN_IER_FMPIE0 | CAN_IER_ERRIE; } -DECL_INIT(can_init); + +void +canhw_stop(void) +{ + NVIC_DisableIRQ(CAN_RX0_IRQn); + if (CAN_RX0_IRQn != CAN_RX1_IRQn) + NVIC_DisableIRQ(CAN_RX1_IRQn); + if (CAN_RX0_IRQn != CAN_TX_IRQn) + NVIC_DisableIRQ(CAN_TX_IRQn); + SOC_CAN->IER &= ~CAN_IER_FMPIE0; +} diff --git a/src/stm32/fdcan.c b/src/stm32/fdcan.c index 8a2d1ab2a..1475e3560 100644 --- a/src/stm32/fdcan.c +++ b/src/stm32/fdcan.c @@ -320,10 +320,16 @@ can_init(void) gpio_peripheral(GPIO_Rx, CAN_FUNCTION, 1); gpio_peripheral(GPIO_Tx, CAN_FUNCTION, 0); + canhw_start(CONFIG_CANBUS_FREQUENCY); +} +DECL_INIT(can_init); +void +canhw_start(uint32_t canbus_frequency) +{ uint32_t pclock = get_pclock_frequency((uint32_t)SOC_CAN); - uint32_t btr = compute_btr(pclock, CONFIG_CANBUS_FREQUENCY); + uint32_t btr = compute_btr(pclock, canbus_frequency); /*##-1- Configure the CAN #######################################*/ @@ -367,4 +373,11 @@ can_init(void) SOC_CAN->ILE = FDCAN_ILE_EINT0; SOC_CAN->IE = FDCAN_IE_RF0NE | FDCAN_IE_TC | FDCAN_IE_PEDE | FDCAN_IE_PEAE; } -DECL_INIT(can_init); + +void +canhw_stop(void) +{ + NVIC_DisableIRQ(CAN_IT0_IRQn); + SOC_CAN->ILE &= ~FDCAN_ILE_EINT0; + SOC_CAN->IE &= ~(FDCAN_IE_RF0NE | FDCAN_IE_TC); +}