added usb - can bridge (loopback)
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.debug
|
||||
.vscode
|
||||
build
|
||||
9
CMakeLists.txt
Normal file
9
CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
SET(CMAKE_CXX_COMPILER /opt/zephyr-sdk/arm-zephyr-eabi/bin/arm-zephyr-eabi-gcc)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
|
||||
project(usb_cdc_can_fd_bridge C CXX)
|
||||
|
||||
add_subdirectory(src)
|
||||
33
boards/nucleo_h755zi_q_stm32h755xx_m7.overlay
Normal file
33
boards/nucleo_h755zi_q_stm32h755xx_m7.overlay
Normal file
@@ -0,0 +1,33 @@
|
||||
/ {
|
||||
|
||||
};
|
||||
|
||||
&zephyr_udc0 {
|
||||
status = "okay";
|
||||
|
||||
cdc_acm_uart0: cdc_acm_uart0 {
|
||||
compatible = "zephyr,cdc-acm-uart";
|
||||
label = "CDC_ACM_0";
|
||||
};
|
||||
|
||||
cdc_acm_uart1: cdc_acm_uart1 {
|
||||
compatible = "zephyr,cdc-acm-uart";
|
||||
label = "CDC_ACM_1";
|
||||
};
|
||||
|
||||
cdc_acm_uart2: cdc_acm_uart2 {
|
||||
compatible = "zephyr,cdc-acm-uart";
|
||||
label = "CDC_ACM_2";
|
||||
};
|
||||
|
||||
cdc_acm_uart3: cdc_acm_uart3 {
|
||||
compatible = "zephyr,cdc-acm-uart";
|
||||
label = "CDC_ACM_3";
|
||||
};
|
||||
};
|
||||
|
||||
&fdcan1 {
|
||||
bitrate = <1000000>;
|
||||
bitrate-data = <4000000>;
|
||||
status = "okay";
|
||||
};
|
||||
15
config.yml
Normal file
15
config.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
sample:
|
||||
description: USB CDC - CAN FD Bridge
|
||||
name: ros2_node
|
||||
common:
|
||||
min_ram: 2
|
||||
min_flash: 16
|
||||
tags: usb_cdc
|
||||
integration_platforms:
|
||||
- nucleo_h563zi
|
||||
- nucleo_h755zi_q
|
||||
harness: console
|
||||
harness_config:
|
||||
type: one_line
|
||||
regex:
|
||||
- "Hello World! (.*)"
|
||||
43
prj.conf
Normal file
43
prj.conf
Normal file
@@ -0,0 +1,43 @@
|
||||
# c version
|
||||
CONFIG_MAIN_STACK_SIZE=32768
|
||||
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=8192
|
||||
CONFIG_ISR_STACK_SIZE=2048
|
||||
CONFIG_USBD_THREAD_STACK_SIZE=4096
|
||||
CONFIG_CPP=y
|
||||
CONFIG_NEWLIB_LIBC=y
|
||||
CONFIG_NEWLIB_LIBC_NANO=n
|
||||
CONFIG_PICOLIBC=n
|
||||
CONFIG_MINIMAL_LIBC=n
|
||||
CONFIG_POSIX_API=y
|
||||
|
||||
#threads
|
||||
CONFIG_INIT_STACKS=y
|
||||
CONFIG_THREAD_STACK_INFO=y
|
||||
CONFIG_DEBUG=y
|
||||
CONFIG_DEBUG_THREAD_INFO=y
|
||||
|
||||
CONFIG_CONSOLE=y
|
||||
|
||||
# logging
|
||||
CONFIG_LOG=y
|
||||
CONFIG_LOG_MODE_IMMEDIATE=y
|
||||
CONFIG_STDOUT_CONSOLE=y
|
||||
CONFIG_PRINTK=y
|
||||
CONFIG_LOG_DEFAULT_LEVEL=3
|
||||
|
||||
# Enable CDC ACM (virtual COM port)
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_UART_LINE_CTRL=y
|
||||
CONFIG_USBD_CDC_ACM_CLASS=y
|
||||
CONFIG_USB_DEVICE_STACK_NEXT=y
|
||||
CONFIG_USBD_CDC_ACM_WORKQUEUE=y
|
||||
CONFIG_UDC_WORKQUEUE=y
|
||||
CONFIG_UDC_STM32=y
|
||||
CONFIG_UDC_STM32_STACK_SIZE=2048
|
||||
CONFIG_UDC_WORKQUEUE_STACK_SIZE=2048
|
||||
|
||||
# can FD
|
||||
CONFIG_CAN=y
|
||||
CONFIG_CAN_FD_MODE=y
|
||||
CONFIG_CAN_STM32_FDCAN=y
|
||||
|
||||
12
src/CMakeLists.txt
Normal file
12
src/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
target_include_directories(app PRIVATE ./)
|
||||
|
||||
add_subdirectory(./bridges)
|
||||
add_subdirectory(./canfd)
|
||||
add_subdirectory(./devices)
|
||||
add_subdirectory(./usb)
|
||||
|
||||
target_sources(app PRIVATE
|
||||
main.cpp
|
||||
)
|
||||
7
src/bridges/CMakeLists.txt
Normal file
7
src/bridges/CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
target_include_directories(app PRIVATE ./)
|
||||
|
||||
target_sources(app PRIVATE
|
||||
bridge_usb_cdc_acm_canfd.cpp
|
||||
)
|
||||
175
src/bridges/bridge_usb_cdc_acm_canfd.cpp
Normal file
175
src/bridges/bridge_usb_cdc_acm_canfd.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
#include <zephyr/drivers/uart.h>
|
||||
#include <zephyr/drivers/can.h>
|
||||
|
||||
#include "bridge_usb_cdc_acm_canfd.hpp"
|
||||
#include "devices.hpp"
|
||||
|
||||
#define USB_THREAD_STACK_SIZE 1024
|
||||
K_THREAD_STACK_DEFINE(bridge_stack, USB_THREAD_STACK_SIZE);
|
||||
struct k_thread bridge_thread_data;
|
||||
K_FIFO_DEFINE(usb_fifo_0);
|
||||
K_FIFO_DEFINE(usb_fifo_1);
|
||||
K_FIFO_DEFINE(usb_fifo_2);
|
||||
K_FIFO_DEFINE(usb_fifo_3);
|
||||
|
||||
struct uart_msg {
|
||||
void *fifo_reserved;
|
||||
uint8_t len;
|
||||
uint8_t *data;
|
||||
};
|
||||
|
||||
uint8_t get_can_id_from_usb_dev(const struct device *dev) {
|
||||
if (dev == cdc0) {
|
||||
return 0x10;
|
||||
}
|
||||
|
||||
if (dev == cdc1) {
|
||||
return 0x20;
|
||||
}
|
||||
|
||||
if (dev == cdc2) {
|
||||
return 0x30;
|
||||
}
|
||||
|
||||
if (dev == cdc3) {
|
||||
return 0x40;
|
||||
}
|
||||
|
||||
return 0x80;
|
||||
}
|
||||
|
||||
struct k_fifo *get_fifo_from_dev(const struct device *dev) {
|
||||
if (dev == cdc0) {
|
||||
return &usb_fifo_0;
|
||||
}
|
||||
|
||||
if (dev == cdc1) {
|
||||
return &usb_fifo_1;
|
||||
}
|
||||
|
||||
if (dev == cdc2) {
|
||||
return &usb_fifo_2;
|
||||
}
|
||||
|
||||
if (dev == cdc3) {
|
||||
return &usb_fifo_3;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct device *get_usb_dev_from_can_id(uint8_t can_id) {
|
||||
switch (can_id) {
|
||||
case 0x10:
|
||||
return cdc0;
|
||||
case 0x21:
|
||||
return cdc1;
|
||||
case 0x31:
|
||||
return cdc2;
|
||||
case 0x41:
|
||||
return cdc3;
|
||||
default:
|
||||
return NULL; // unknown
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t get_lenght_from_dlc(uint8_t dlc) {
|
||||
static const uint8_t dlc_to_len[16] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64
|
||||
};
|
||||
|
||||
if (dlc < 16) {
|
||||
return dlc_to_len[dlc];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void uart_rx_handler(const struct device *dev, void *user_data)
|
||||
{
|
||||
ARG_UNUSED(user_data);
|
||||
|
||||
while (uart_irq_update(dev) && uart_irq_is_pending(dev)) {
|
||||
printk("tx: %i, rx: %i\r\n", uart_irq_tx_ready(dev), uart_irq_rx_ready(dev));
|
||||
if (uart_irq_rx_ready(dev)) {
|
||||
uint8_t buffer[64] = {0};
|
||||
|
||||
int recv_len = uart_fifo_read(dev, buffer, 64);
|
||||
if (recv_len > 0) {
|
||||
struct can_frame counter_frame = {
|
||||
.id = get_can_id_from_usb_dev(dev),
|
||||
.dlc = can_bytes_to_dlc(recv_len),
|
||||
.flags = CAN_FRAME_FDF | CAN_FRAME_BRS,
|
||||
.data = {0},
|
||||
};
|
||||
memcpy(counter_frame.data, buffer, recv_len);
|
||||
|
||||
can_send(fdcan1, &counter_frame, K_NO_WAIT, NULL, NULL);
|
||||
}
|
||||
}
|
||||
if (uart_irq_tx_ready(dev) >= 64) {
|
||||
k_fifo* fifo = get_fifo_from_dev(dev);
|
||||
if (fifo == NULL) {
|
||||
uart_irq_tx_disable(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
struct uart_msg *msg = (uart_msg*) k_fifo_get(fifo, K_MSEC(10));
|
||||
if(msg){
|
||||
printk("sending to UART: %s / %i\n\r", msg->data, msg->len);
|
||||
uart_fifo_fill(dev, msg->data, msg->len);
|
||||
k_free(msg->data);
|
||||
k_free(msg);
|
||||
}
|
||||
else {
|
||||
printk("Nothing to do\n\r");
|
||||
uart_irq_tx_disable(dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void can_rx_handler(const struct device *dev, struct can_frame *frame, void *user_data)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
ARG_UNUSED(user_data);
|
||||
|
||||
const struct device *uart_dev = get_usb_dev_from_can_id(frame->id);
|
||||
if (!uart_dev) return;
|
||||
|
||||
struct uart_msg *msg = (uart_msg*)k_malloc(sizeof(uart_msg));
|
||||
if (!msg) return;
|
||||
|
||||
msg->len = get_lenght_from_dlc(frame->dlc);
|
||||
printk("msg size: %i / %i\n\r", msg->len, frame->dlc);
|
||||
|
||||
msg->data = (uint8_t*)k_malloc(sizeof(uint8_t) * msg->len);
|
||||
if (!msg->data) return;
|
||||
|
||||
memset(msg->data, 0, msg->len);
|
||||
memcpy(msg->data, frame->data, msg->len);
|
||||
|
||||
printk("sending to Queue: %s / %s / %i / %i\n\r", frame->data, msg->data, msg->len, frame->dlc);
|
||||
k_fifo_put(get_fifo_from_dev(uart_dev), msg);
|
||||
uart_irq_tx_enable(uart_dev);
|
||||
}
|
||||
|
||||
|
||||
void bridges_init() {
|
||||
uart_irq_callback_set(cdc0, uart_rx_handler);
|
||||
uart_irq_rx_enable(cdc0);
|
||||
uart_irq_callback_set(cdc1, uart_rx_handler);
|
||||
uart_irq_rx_enable(cdc1);
|
||||
uart_irq_callback_set(cdc2, uart_rx_handler);
|
||||
uart_irq_rx_enable(cdc2);
|
||||
uart_irq_callback_set(cdc3, uart_rx_handler);
|
||||
uart_irq_rx_enable(cdc3);
|
||||
|
||||
struct can_filter filter = {
|
||||
.id = 0, // match all IDs
|
||||
.mask = 0, // accept everything
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
can_add_rx_filter(fdcan1, can_rx_handler, NULL, &filter);
|
||||
}
|
||||
3
src/bridges/bridge_usb_cdc_acm_canfd.hpp
Normal file
3
src/bridges/bridge_usb_cdc_acm_canfd.hpp
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void bridges_init(void);
|
||||
7
src/canfd/CMakeLists.txt
Normal file
7
src/canfd/CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
target_include_directories(app PRIVATE ./)
|
||||
|
||||
target_sources(app PRIVATE
|
||||
can_fd.cpp
|
||||
)
|
||||
15
src/canfd/can_fd.cpp
Normal file
15
src/canfd/can_fd.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#include <zephyr/drivers/can.h>
|
||||
|
||||
#include "can_fd.hpp"
|
||||
#include "devices.hpp"
|
||||
|
||||
|
||||
void canfd_init() {
|
||||
if (!can_set_mode(fdcan1, CAN_MODE_LOOPBACK | CAN_MODE_FD)) {
|
||||
printk("CAN0 set to CAN FD\n");
|
||||
}
|
||||
|
||||
if (can_start(fdcan1) < 0) {
|
||||
printk("CAN0 not enabled\n");
|
||||
}
|
||||
}
|
||||
3
src/canfd/can_fd.hpp
Normal file
3
src/canfd/can_fd.hpp
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void canfd_init(void);
|
||||
7
src/devices/CMakeLists.txt
Normal file
7
src/devices/CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
target_include_directories(app PRIVATE ./)
|
||||
|
||||
target_sources(app PRIVATE
|
||||
devices.cpp
|
||||
)
|
||||
40
src/devices/devices.cpp
Normal file
40
src/devices/devices.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "devices.hpp"
|
||||
|
||||
const struct device *cdc0 = DEVICE_DT_GET(DT_NODELABEL(cdc_acm_uart0));
|
||||
const struct device *cdc1 = DEVICE_DT_GET(DT_NODELABEL(cdc_acm_uart1));
|
||||
const struct device *cdc2 = DEVICE_DT_GET(DT_NODELABEL(cdc_acm_uart2));
|
||||
const struct device *cdc3 = DEVICE_DT_GET(DT_NODELABEL(cdc_acm_uart3));
|
||||
|
||||
const struct device *fdcan1 = DEVICE_DT_GET(DT_NODELABEL(fdcan1));
|
||||
|
||||
|
||||
bool verify_are_devices_available(void) {
|
||||
bool devices_ready = true;
|
||||
|
||||
if (!device_is_ready(cdc0)) {
|
||||
printk("cdc0 not ready\n");
|
||||
devices_ready = false;
|
||||
}
|
||||
|
||||
if (!device_is_ready(cdc1)) {
|
||||
printk("cdc1 not ready\n");
|
||||
devices_ready = false;
|
||||
}
|
||||
|
||||
if (!device_is_ready(cdc2)) {
|
||||
printk("cdc2 not ready\n");
|
||||
devices_ready = false;
|
||||
}
|
||||
|
||||
if (!device_is_ready(cdc3)) {
|
||||
printk("cdc3 not ready\n");
|
||||
devices_ready = false;
|
||||
}
|
||||
|
||||
if (!device_is_ready(fdcan1)) {
|
||||
printk("fdcan1 not ready\n");
|
||||
devices_ready = false;
|
||||
}
|
||||
|
||||
return devices_ready;
|
||||
}
|
||||
15
src/devices/devices.hpp
Normal file
15
src/devices/devices.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/devicetree.h>
|
||||
|
||||
|
||||
extern const struct device *cdc0;
|
||||
extern const struct device *cdc1;
|
||||
extern const struct device *cdc2;
|
||||
extern const struct device *cdc3;
|
||||
|
||||
extern const struct device *fdcan1;
|
||||
|
||||
|
||||
bool verify_are_devices_available(void);
|
||||
20
src/main.cpp
Normal file
20
src/main.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
#include "devices.hpp"
|
||||
#include "can_fd.hpp"
|
||||
#include "usb_cdc_acm.hpp"
|
||||
#include "bridge_usb_cdc_acm_canfd.hpp"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
if (!verify_are_devices_available()) {
|
||||
printk("Not all devices ready. Aborting ...\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
canfd_init();
|
||||
usb_init();
|
||||
bridges_init();
|
||||
|
||||
k_thread_suspend(k_current_get());
|
||||
}
|
||||
7
src/usb/CMakeLists.txt
Normal file
7
src/usb/CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
target_include_directories(app PRIVATE ./)
|
||||
|
||||
target_sources(app PRIVATE
|
||||
usb_cdc_acm.cpp
|
||||
)
|
||||
38
src/usb/usb_cdc_acm.cpp
Normal file
38
src/usb/usb_cdc_acm.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#include <zephyr/usb/usbd.h>
|
||||
|
||||
#include "usb_cdc_acm.hpp"
|
||||
|
||||
USBD_DEVICE_DEFINE(usb0, DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)), 0x2fe3, 0xffff);
|
||||
USBD_DESC_LANG_DEFINE(usb0_lang);
|
||||
USBD_DESC_MANUFACTURER_DEFINE(usb0_mfr, "Ohmman & Co. KG");
|
||||
USBD_DESC_PRODUCT_DEFINE(usb0_prod, "USB Test");
|
||||
|
||||
USBD_DESC_CONFIG_DEFINE(fs_cfg_desc, "FS Configuration");
|
||||
USBD_CONFIGURATION_DEFINE(usb0_conf, USB_SCD_SELF_POWERED, 100, &fs_cfg_desc);
|
||||
|
||||
static const char *const usb0_blocklist[] = {
|
||||
"dfu_dfu",
|
||||
NULL,
|
||||
};
|
||||
|
||||
void usb_init(void) {
|
||||
usbd_add_descriptor(&usb0, &usb0_lang);
|
||||
usbd_add_descriptor(&usb0, &usb0_mfr);
|
||||
usbd_add_descriptor(&usb0, &usb0_prod);
|
||||
//usbd_add_descriptor(&usb0, &usb0_sn);
|
||||
|
||||
if (usbd_add_configuration(&usb0, USBD_SPEED_FS, &usb0_conf)) {
|
||||
printk("Failed to add Full-Speed configuration\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (usbd_register_all_classes(&usb0, USBD_SPEED_FS, 1, usb0_blocklist)) {
|
||||
printk("Failed to register usb classes\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
usbd_device_set_code_triple(&usb0, USBD_SPEED_FS, USB_BCC_APPLICATION, 0x02, 0x01);
|
||||
|
||||
usbd_init(&usb0);
|
||||
usbd_enable(&usb0);
|
||||
}
|
||||
3
src/usb/usb_cdc_acm.hpp
Normal file
3
src/usb/usb_cdc_acm.hpp
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void usb_init(void);
|
||||
Reference in New Issue
Block a user