Hello :) The default setting for the console on the nRF52840 is over UART0. I can easily print logging messages to the console and I have also implemented a function to parse incoming serial messages. See the code below:
/* * Copyright (c) 2012-2014 Wind River Systems, Inc. * * SPDX-License-Identifier: Apache-2.0 */ #include <zephyr/kernel.h> #include <zephyr/drivers/gpio.h> #include "stdio.h" #include "my_gpio.h" #include "zephyr/drivers/uart.h" #include <zephyr/sys/ring_buffer.h> #define LOG_LEVEL 4 #include <zephyr/logging/log.h> LOG_MODULE_REGISTER(nrf52_learning); #define UART_BUF_SIZE 24 #define UART_RX_TIMEOUT_MS 1000 K_SEM_DEFINE(rx_disabled, 0, 1); // UART RX primary buffers uint8_t uart_double_buffer[2][UART_BUF_SIZE]; uint8_t *uart_buf_next = uart_double_buffer[1]; uint8_t complete_message[UART_BUF_SIZE]; uint8_t complete_message_counter = 0; bool currently_active_buffer = 1; // 0 - uart_double_buffer[0] is active, 1 - uart_double_buffer[1] is active static const struct device *dev_uart; static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data) { switch (evt->type) { case UART_TX_DONE: break; case UART_TX_ABORTED: // do something break; case UART_RX_RDY: LOG_INF("Received %i bytes \n", evt->data.rx.len); LOG_INF("Offset = %i \n", evt->data.rx.offset); if (currently_active_buffer == 0) { // read all characters one by one till new line is found for (int i = 0 + evt->data.rx.offset; i < UART_BUF_SIZE; i++) { complete_message[complete_message_counter] = uart_double_buffer[0][i]; complete_message_counter++; if (uart_double_buffer[0][i] == '\n') { complete_message_counter = 0; LOG_INF("complete_message = %s \n", complete_message); memset(&complete_message, 0, sizeof(complete_message)); // clear out the buffer to prepare for next read. break; } } } if (currently_active_buffer == 1) { // read all characters one by one till new line is found for (int i = 0 + evt->data.rx.offset; i < UART_BUF_SIZE; i++) { complete_message[complete_message_counter] = uart_double_buffer[1][i]; complete_message_counter++; if (uart_double_buffer[1][i] == '\n') { complete_message_counter = 0; LOG_INF("complete_message = %s \n", complete_message); memset(&complete_message, 0, sizeof(complete_message)); // clear out the buffer to prepare for next read. break; } } } break; case UART_RX_BUF_REQUEST: uart_rx_buf_rsp(dev_uart, uart_buf_next, UART_BUF_SIZE); currently_active_buffer = !currently_active_buffer; break; case UART_RX_BUF_RELEASED: uart_buf_next = evt->data.rx_buf.buf; break; case UART_RX_DISABLED: k_sem_give(&rx_disabled); break; case UART_RX_STOPPED: // do something break; default: break; } } void app_uart_init() { dev_uart = DEVICE_DT_GET(DT_NODELABEL(uart0)); if (!device_is_ready(dev_uart)) { return 0; } int err; err = uart_callback_set(dev_uart, uart_cb, NULL); if (err) { return err; } uart_rx_enable(dev_uart, uart_double_buffer[0], UART_BUF_SIZE, UART_RX_TIMEOUT_MS); } int main(void) { app_uart_init(); }
I want to be able to send any messages via the serial terminal to the device and I want the device to be able to parse incomming messages and take any required action. For example. I may want so end a serial command "Turn on LED1" and the device can parse the message and turn on the LED1...
For my application, I want to reconfigure UART0 to communicate with external device instead of logging and console and I want to use USB for this instead.
So the plan is:
UART0 - Communication with external device 1
UART1 - Communication with external device 2
USB - Logging and parsing commands
I have looked at the Console over USB example (zephyr/samples/subsys/usb/console) to check how to setup the console over the USB and I came up with the project below:
https://github.com/krupis/nrf52_learning/tree/USB_debug
The full code:
/* * Copyright (c) 2012-2014 Wind River Systems, Inc. * * SPDX-License-Identifier: Apache-2.0 */ #include <zephyr/kernel.h> #include <zephyr/drivers/gpio.h> #include <zephyr/sys/poweroff.h> #include "stdio.h" #include <zephyr/usb/usb_device.h> #include <zephyr/usb/usbd.h> #include <zephyr/drivers/uart.h> BUILD_ASSERT(DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_console), zephyr_cdc_acm_uart), "Console device is not ACM CDC UART device"); #define LOG_LEVEL 4 #include <zephyr/logging/log.h> LOG_MODULE_REGISTER(nrf52_learning); int main(void) { if (usb_enable(NULL)) { return 0; } while (1) { LOG_INF("Hello"); k_sleep(K_MSEC(1000)); } }
nrf52840dk_nrf52840.overlay:
arduino_serial: &uart1 { status = "okay"; }; / { chosen { zephyr,console = &cdc_acm_uart0; }; }; &zephyr_udc0 { cdc_acm_uart0: cdc_acm_uart0 { compatible = "zephyr,cdc-acm-uart"; label = "CDC_ACM_0"; }; };
prj.conf:
CONFIG_LOG=y CONFIG_LOG_MODE_IMMEDIATE=y CONFIG_USB_DEVICE_STACK=y CONFIG_USB_DEVICE_PRODUCT="Zephyr test" CONFIG_USB_DEVICE_PID=0x0004 CONFIG_USB_DEVICE_MANUFACTURER="Nordic Semiconductor" CONFIG_USB_DEVICE_VID=0x1915 CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n CONFIG_SERIAL=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y
The result:
I can see that the logging via the USB is working as expected. If I connect the USB to the nRF USB port instead of the nRF debug USB, I can see that the logs are coming through:
My questions:
Question 1:
I have read through the USB documentation (https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.2-dev1/zephyr/reference/usb/uds.html) but it is still not fully clear to me how can I implement serial command parsing via the USB. I want to be able to send the commands via the serial terminal and I expect some callback to be triggered that receives the data (Simillarly to how the UART_RX_RDY event is triggered when the data is received using UART ASYNC method) and I can then parse the data accordingly. Could someone point me in the right direction on how to get this implemented as I could not find any relevant example projects to get started with.
Question 2:
I would like to understand how can I change the COM port name that my device appears as. Currently it appears as a USB Serial Device (COM41). Can I change this to any name I want?
Question 3:
What is the purpose of
As they do not seem to show up anywhere?