I am trying to connect a nrf5340dk to a Jetson. For now I am testing with an Arduino. I am trying to run the CanCounter example with a device tree overlay file. Also I would like to connect this to a Jetson Orin in the future. This is my current setup and below is my code.
I am using
2x I2C Logic Level Converter (because of the different voltage levels)
2x MCP2515 CAN Bus Shield AZDelivery
And I am powering the nrf5340dk using the J2 USB connector
Is there anything I am doing incorrectly?
I am able to build and flash to the nrf board but I get the following error message;
uart:~$ *** Booting nRF Connect SDK v3.5.99-ncs1-1 ***
Error starting CAN controller [-5]
nrf5340dk_nrf5340_cpuapp.overlay:
&spi4 { status = "okay"; cs-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; pinctrl-0 = <&spi4_default>; //pinctrl-names = "default"; canbus:mcp2515@0 { compatible = "microchip,mcp2515"; spi-max-frequency = <1000000>; int-gpios = <&gpio1 10 (GPIO_ACTIVE_LOW)>; status = "okay"; label = "CAN_1"; reg = <0x0>; osc-freq = <16000000>; bus-speed = <500000>; sjw = <1>; prop-seg = <2>; phase-seg1 = <7>; phase-seg2 = <6>; #address-cells = <1>; #size-cells = <0>; }; }; / { chosen { zephyr,canbus = &canbus; }; };
proj.conf:
CONFIG_POLL=y CONFIG_CAN=y CONFIG_CAN_INIT_PRIORITY=80 #CONFIG_CAN_MAX_FILTER=5 CONFIG_SHELL=y CONFIG_CAN_SHELL=y CONFIG_DEVICE_SHELL=y CONFIG_GPIO=y CONFIG_STATS=y CONFIG_STATS_NAMES=y CONFIG_STATS_SHELL=y CONFIG_CAN_STATS=y
main.cpp:
/* * Copyright (c) 2018 Alexander Wachter * * SPDX-License-Identifier: Apache-2.0 */ #include <stdio.h> #include <zephyr/kernel.h> #include <zephyr/sys/printk.h> #include <zephyr/device.h> #include <zephyr/drivers/can.h> #include <zephyr/drivers/gpio.h> #include <zephyr/sys/byteorder.h> #define RX_THREAD_STACK_SIZE 512 #define RX_THREAD_PRIORITY 2 #define STATE_POLL_THREAD_STACK_SIZE 512 #define STATE_POLL_THREAD_PRIORITY 2 #define LED_MSG_ID 0x10 #define COUNTER_MSG_ID 0x12345 #define SET_LED 1 #define RESET_LED 0 #define SLEEP_TIME K_MSEC(250) K_THREAD_STACK_DEFINE(rx_thread_stack, RX_THREAD_STACK_SIZE); K_THREAD_STACK_DEFINE(poll_state_stack, STATE_POLL_THREAD_STACK_SIZE); const struct device *const can_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_canbus)); struct gpio_dt_spec led = GPIO_DT_SPEC_GET_OR(DT_ALIAS(led0), gpios, {0}); struct k_thread rx_thread_data; struct k_thread poll_state_thread_data; struct k_work_poll change_led_work; struct k_work state_change_work; enum can_state current_state; struct can_bus_err_cnt current_err_cnt; CAN_MSGQ_DEFINE(change_led_msgq, 2); CAN_MSGQ_DEFINE(counter_msgq, 2); static struct k_poll_event change_led_events[1] = { K_POLL_EVENT_STATIC_INITIALIZER(K_POLL_TYPE_MSGQ_DATA_AVAILABLE, K_POLL_MODE_NOTIFY_ONLY, &change_led_msgq, 0) }; void tx_irq_callback(const struct device *dev, int error, void *arg) { char *sender = (char *)arg; ARG_UNUSED(dev); if (error != 0) { printf("Callback! error-code: %d\nSender: %s\n", error, sender); } } void rx_thread(void *arg1, void *arg2, void *arg3) { ARG_UNUSED(arg1); ARG_UNUSED(arg2); ARG_UNUSED(arg3); const struct can_filter filter = { .flags = CAN_FILTER_DATA | CAN_FILTER_IDE, .id = COUNTER_MSG_ID, .mask = CAN_EXT_ID_MASK }; struct can_frame frame; int filter_id; filter_id = can_add_rx_filter_msgq(can_dev, &counter_msgq, &filter); printf("Counter filter id: %d\n", filter_id); while (1) { k_msgq_get(&counter_msgq, &frame, K_FOREVER); if (frame.dlc != 2U) { printf("Wrong data length: %u\n", frame.dlc); continue; } printf("Counter received: %u\n", sys_be16_to_cpu(UNALIGNED_GET((uint16_t *)&frame.data))); } } void change_led_work_handler(struct k_work *work) { struct can_frame frame; int ret; while (k_msgq_get(&change_led_msgq, &frame, K_NO_WAIT) == 0) { if (led.port == NULL) { printf("LED %s\n", frame.data[0] == SET_LED ? "ON" : "OFF"); } else { gpio_pin_set(led.port, led.pin, frame.data[0] == SET_LED ? 1 : 0); } } ret = k_work_poll_submit(&change_led_work, change_led_events, ARRAY_SIZE(change_led_events), K_FOREVER); if (ret != 0) { printf("Failed to resubmit msgq polling: %d", ret); } } char *state_to_str(enum can_state state) { switch (state) { case CAN_STATE_ERROR_ACTIVE: return "error-active"; case CAN_STATE_ERROR_WARNING: return "error-warning"; case CAN_STATE_ERROR_PASSIVE: return "error-passive"; case CAN_STATE_BUS_OFF: return "bus-off"; case CAN_STATE_STOPPED: return "stopped"; default: return "unknown"; } } void poll_state_thread(void *unused1, void *unused2, void *unused3) { struct can_bus_err_cnt err_cnt = {0, 0}; struct can_bus_err_cnt err_cnt_prev = {0, 0}; enum can_state state_prev = CAN_STATE_ERROR_ACTIVE; enum can_state state; int err; while (1) { err = can_get_state(can_dev, &state, &err_cnt); if (err != 0) { printf("Failed to get CAN controller state: %d", err); k_sleep(K_MSEC(100)); continue; } if (err_cnt.tx_err_cnt != err_cnt_prev.tx_err_cnt || err_cnt.rx_err_cnt != err_cnt_prev.rx_err_cnt || state_prev != state) { err_cnt_prev.tx_err_cnt = err_cnt.tx_err_cnt; err_cnt_prev.rx_err_cnt = err_cnt.rx_err_cnt; state_prev = state; printf("state: %s\n" "rx error count: %d\n" "tx error count: %d\n", state_to_str(state), err_cnt.rx_err_cnt, err_cnt.tx_err_cnt); } else { k_sleep(K_MSEC(100)); } } } void state_change_work_handler(struct k_work *work) { printf("State Change ISR\nstate: %s\n" "rx error count: %d\n" "tx error count: %d\n", state_to_str(current_state), current_err_cnt.rx_err_cnt, current_err_cnt.tx_err_cnt); #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY if (current_state == CAN_STATE_BUS_OFF) { printf("Recover from bus-off\n"); if (can_recover(can_dev, K_MSEC(100)) != 0) { printf("Recovery timed out\n"); } } #endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ } void state_change_callback(const struct device *dev, enum can_state state, struct can_bus_err_cnt err_cnt, void *user_data) { struct k_work *work = (struct k_work *)user_data; ARG_UNUSED(dev); current_state = state; current_err_cnt = err_cnt; k_work_submit(work); } int main(void) { const struct can_filter change_led_filter = { .flags = CAN_FILTER_DATA, .id = LED_MSG_ID, .mask = CAN_STD_ID_MASK }; struct can_frame change_led_frame = { .flags = 0, .id = LED_MSG_ID, .dlc = 1 }; struct can_frame counter_frame = { .flags = CAN_FRAME_IDE, .id = COUNTER_MSG_ID, .dlc = 2 }; uint8_t toggle = 1; uint16_t counter = 0; k_tid_t rx_tid, get_state_tid; int ret; if (!device_is_ready(can_dev)) { printf("CAN: Device %s not ready.\n", can_dev->name); return 0; } #ifdef CONFIG_LOOPBACK_MODE ret = can_set_mode(can_dev, CAN_MODE_LOOPBACK); if (ret != 0) { printf("Error setting CAN mode [%d]", ret); return 0; } #endif ret = can_start(can_dev); if (ret != 0) { printf("Error starting CAN controller [%d]", ret); return 0; } if (led.port != NULL) { if (!device_is_ready(led.port)) { printf("LED: Device %s not ready.\n", led.port->name); return 0; } ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_HIGH); if (ret < 0) { printf("Error setting LED pin to output mode [%d]", ret); led.port = NULL; } } k_work_init(&state_change_work, state_change_work_handler); k_work_poll_init(&change_led_work, change_led_work_handler); ret = can_add_rx_filter_msgq(can_dev, &change_led_msgq, &change_led_filter); if (ret == -ENOSPC) { printf("Error, no filter available!\n"); return 0; } printf("Change LED filter ID: %d\n", ret); ret = k_work_poll_submit(&change_led_work, change_led_events, ARRAY_SIZE(change_led_events), K_FOREVER); if (ret != 0) { printf("Failed to submit msgq polling: %d", ret); return 0; } rx_tid = k_thread_create(&rx_thread_data, rx_thread_stack, K_THREAD_STACK_SIZEOF(rx_thread_stack), rx_thread, NULL, NULL, NULL, RX_THREAD_PRIORITY, 0, K_NO_WAIT); if (!rx_tid) { printf("ERROR spawning rx thread\n"); } get_state_tid = k_thread_create(&poll_state_thread_data, poll_state_stack, K_THREAD_STACK_SIZEOF(poll_state_stack), poll_state_thread, NULL, NULL, NULL, STATE_POLL_THREAD_PRIORITY, 0, K_NO_WAIT); if (!get_state_tid) { printf("ERROR spawning poll_state_thread\n"); } can_set_state_change_callback(can_dev, state_change_callback, &state_change_work); printf("Finished init.\n"); while (1) { change_led_frame.data[0] = toggle++ & 0x01 ? SET_LED : RESET_LED; /* This sending call is none blocking. */ can_send(can_dev, &change_led_frame, K_FOREVER, tx_irq_callback, "LED change"); k_sleep(SLEEP_TIME); UNALIGNED_PUT(sys_cpu_to_be16(counter), (uint16_t *)&counter_frame.data[0]); counter++; /* This sending call is blocking until the message is sent. */ can_send(can_dev, &counter_frame, K_MSEC(100), NULL, NULL); k_sleep(SLEEP_TIME); } }
arduino_code.ino:
#include <SPI.h> #include <mcp2515_can.h> const int spiCSPin = 10; // Set the CS pin for MCP2515 CAN shield const int ledPin = 13; // Use the built-in LED on pin 13 mcp2515_can CAN(spiCSPin); void setup() { Serial.begin(115200); pinMode(ledPin, OUTPUT); // Initialize CAN bus at 500kbps while (CAN_OK != CAN.begin(CAN_500KBPS)) { Serial.println("CAN BUS init Failed"); delay(100); } Serial.println("CAN BUS Shield Init OK!"); } void loop() { unsigned char len = 0; unsigned char buf[8]; if (CAN_MSGAVAIL == CAN.checkReceive()) { CAN.readMsgBuf(&len, buf); // Check the message ID unsigned long canId = CAN.getCanId(); if (canId == 0x10) { // LED control message if (buf[0] == 1) { digitalWrite(ledPin, HIGH); Serial.println("LED ON"); } else if (buf[0] == 0) { digitalWrite(ledPin, LOW); Serial.println("LED OFF"); } } else if (canId == 0x12345) { // Counter message if (len == 2) { uint16_t counterValue = (buf[0] << 8) | buf[1]; Serial.print("Counter received: "); Serial.println(counterValue); } else { Serial.println("Wrong data length for counter message"); } } } }