diff --git a/applications/motor_controller/debug.conf b/applications/motor_controller/debug.conf index a6bcef8..f1fa7e9 100644 --- a/applications/motor_controller/debug.conf +++ b/applications/motor_controller/debug.conf @@ -1,5 +1,19 @@ -# compiler -CONFIG_DEBUG_OPTIMIZATIONS=y +# No compiler section. +# +# This used to set CONFIG_DEBUG_OPTIMIZATIONS=y, which switches -Os to -Og and +# adds ~56 KB to an image that already fills 99% of the SAMD21's 232 KB. It has +# never linked on any revision of this app -- it only looked green because +# twister aborted earlier, on the legacy USB stack's deprecation warnings. +# +# Nothing is needed to replace it: the normal build already compiles with +# -gdwarf-4, so gdb has full symbols and line tables at -Os today. Stepping +# through -Os is less pleasant than -Og, and on a part this full that is simply +# the trade. If you need -Og, drop LVGL or the display from the build first. +# +# CONFIG_DEBUG_THREAD_INFO (RTOS-aware debugging) is deliberately not set here +# either: it selects THREAD_MONITOR, which prj.conf turns off to make room for +# the USB stack. Enable both together locally if you need thread awareness, and +# expect to give up something else. # console CONFIG_CONSOLE=y diff --git a/applications/motor_controller/prj.conf b/applications/motor_controller/prj.conf index ce20d2c..9ab6304 100644 --- a/applications/motor_controller/prj.conf +++ b/applications/motor_controller/prj.conf @@ -8,14 +8,31 @@ CONFIG_LOG_MODE_DEFERRED=y CONFIG_LOG_PRINTK=y # Shell +# +# Trimmed to make room for the new USB device stack, which costs ~13 KB flash +# and ~3.2 KB RAM more than the deprecated legacy one on a part that was +# already at 98.9% flash / 99.5% RAM (160 bytes of RAM free). These were the +# cheapest ~7.5 KB of flash available: the introspection shells and the thread +# instrumentation they depend on. SHELL_HELP is pure help strings -- every +# command still works, it just cannot describe itself. +# +# Restoring any of these means finding the flash elsewhere first. Do not +# re-enable one without re-checking the size report. +# NB: these need an explicit =n. KERNEL_SHELL, DEVICE_SHELL, INIT_STACKS, +# THREAD_MONITOR and THREAD_STACK_INFO all default to y once SHELL is on, so +# simply deleting the lines leaves them enabled and costs ~7.5 KB of flash. CONFIG_SHELL=y -CONFIG_INIT_STACKS=y -CONFIG_THREAD_STACK_INFO=y -CONFIG_KERNEL_SHELL=y -CONFIG_THREAD_MONITOR=y +CONFIG_SHELL_HELP=n +CONFIG_SHELL_HISTORY=n +CONFIG_SHELL_TAB=n +CONFIG_SHELL_TAB_AUTOCOMPLETION=n +CONFIG_KERNEL_SHELL=n +CONFIG_DEVICE_SHELL=n +CONFIG_I2C_SHELL=n +CONFIG_THREAD_MONITOR=n +CONFIG_INIT_STACKS=n +CONFIG_THREAD_STACK_INFO=n CONFIG_THREAD_NAME=y -CONFIG_DEVICE_SHELL=y -CONFIG_I2C_SHELL=y # Drivers CONFIG_I2C=y @@ -26,7 +43,8 @@ CONFIG_MFD_ADAFRUIT_SEESAW=y CONFIG_ADC_ADAFRUIT_SEESAW=y CONFIG_LED_STRIP_ADAFRUIT_SEESAW=y CONFIG_ADAFRUIT_SEESAW_ENCODER=y -CONFIG_DYNAMIXEL_LOG_LEVEL_DBG=y +# DYNAMIXEL_LOG_LEVEL_DBG was on here; its debug strings are flash this board +# no longer has. Re-enable it locally when debugging the bus, not in-tree. # Actuator subsystem CONFIG_ACTUATOR=y @@ -34,21 +52,21 @@ CONFIG_ACTUATOR_DXL=y CONFIG_PICOLIBC_IO_FLOAT=y # USB -CONFIG_USB_DEVICE_STACK=y -CONFIG_USB_DEVICE_VID=0x2F5D -CONFIG_USB_DEVICE_PID=0x2202 -CONFIG_USB_DEVICE_MANUFACTURER="ROBOTIS" -CONFIG_USB_DEVICE_PRODUCT="OpenRB-150" -CONFIG_USB_MAX_POWER=250 -CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=y - -# USB Next -# CONFIG_USB_DEVICE_STACK_NEXT=y -# CONFIG_USBD_SHELL=y -# CONFIG_USBD_CDC_ACM_CLASS=y -# CONFIG_USBD_LOG_LEVEL_WRN=y -# CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y -# CONFIG_USBD_CDC_ACM_LOG_LEVEL_ERR=y +# +# The new device stack. The legacy CONFIG_USB_DEVICE_STACK selects DEPRECATED +# and is built entirely from __deprecated APIs, so it cannot survive a -Werror +# build (twister). VID/PID and the descriptor strings are no longer Kconfig; +# they live in src/usb.c, which also reimplements the BOSSA 1200-baud reset +# that soc/atmel/sam0/common/bossa.c only provides for the legacy stack. +CONFIG_USB_DEVICE_STACK_NEXT=y +CONFIG_USBD_CDC_ACM_CLASS=y +CONFIG_USBD_LOG_LEVEL_WRN=y +CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y +# Must be OFF, not ERR: cdc_acm_uart0 is zephyr,shell-uart, so with +# SHELL_LOG_BACKEND the CDC ACM driver logging about the transport it is +# logging over recurses. usbd_cdc_acm.c makes this a hard #warning, which +# -Werror turns into a build failure. +CONFIG_USBD_CDC_ACM_LOG_LEVEL_OFF=y # CONFIG_SHELL_BACKEND_SERIAL_CHECK_DTR=y CONFIG_UART_LINE_CTRL=y @@ -104,4 +122,11 @@ CONFIG_LV_Z_BITS_PER_PIXEL=16 CONFIG_LV_COLOR_DEPTH_16=y CONFIG_LV_COLOR_16_SWAP=y +# Rendering buffer, as a percentage of the 240x135x16bpp panel (64,800 B full). +# The default 10% is ~6.5 KB and was the single largest RAM consumer; the new +# USB stack needs ~2.7 KB of it. 5% is ~3.2 KB, still ~13 display lines per +# flush (one line is 480 B), so this costs redraw cycles, not correctness or +# any feature. It is the RAM knob to turn first if something else needs space. +CONFIG_LV_Z_VDB_SIZE=5 + # CONFIG_LV_Z_MEM_POOL_SIZE=2048 diff --git a/applications/motor_controller/src/usb.c b/applications/motor_controller/src/usb.c index b8bb97b..476de3e 100644 --- a/applications/motor_controller/src/usb.c +++ b/applications/motor_controller/src/usb.c @@ -31,43 +31,51 @@ static const struct usb_bos_capability_lpm bos_cap_lpm = { USBD_DESC_BOS_DEFINE(app_usbext, sizeof(bos_cap_lpm), &bos_cap_lpm); /* + * BOSSA 1200-baud touch reset. + * + * The legacy USB stack got this for free from soc/atmel/sam0/common/bossa.c, + * which hangs off CDC_ACM_DTE_RATE_CALLBACK_SUPPORT -- a legacy-stack-only + * symbol. Under the new stack BOOTLOADER_BOSSA_DEVICE_NAME is unsatisfiable, + * so bossa.c compiles to nothing and the behaviour has to live here instead. + * + * Without it `west flash` (bossac) cannot put the board into its bootloader, + * and every flash needs a manual double-tap of the reset button. + * + * The magic value and its SRAM location are a contract with the bootloader: + * keep them identical to bossa.c. + */ +#if defined(CONFIG_BOOTLOADER_BOSSA_ADAFRUIT_UF2) +#define BOSSA_DOUBLE_TAP_MAGIC 0xf01669ef +#elif defined(CONFIG_BOOTLOADER_BOSSA_ARDUINO) +#define BOSSA_DOUBLE_TAP_MAGIC 0x07738135 +#endif + static void usb_msg_cb(struct usbd_context *const ctx, const struct usbd_msg *msg) { - LOG_INF("USBD message: %s", usbd_msg_type_string(msg->type)); - - if (usbd_can_detect_vbus(ctx)) { - if (msg->type == USBD_MSG_VBUS_READY) { - if (usbd_enable(ctx)) { - LOG_ERR("Failed to enable device support"); - } - } - - if (msg->type == USBD_MSG_VBUS_REMOVED) { - if (usbd_disable(ctx)) { - LOG_ERR("Failed to disable device support"); - } - } + if (msg->type != USBD_MSG_CDC_ACM_LINE_CODING) { + return; } - if (msg->type == USBD_MSG_CDC_ACM_CONTROL_LINE_STATE) { - uint32_t dtr = 0U; +#if defined(BOSSA_DOUBLE_TAP_MAGIC) + uint32_t baudrate = 0U; - uart_line_ctrl_get(msg->dev, UART_LINE_CTRL_DTR, &dtr); - if (dtr) { - LOG_INF("Got DTR from USB"); - } + if (uart_line_ctrl_get(msg->dev, UART_LINE_CTRL_BAUD_RATE, &baudrate)) { + return; } - if (msg->type == USBD_MSG_CDC_ACM_LINE_CODING) { - uint32_t baudrate = 0U; + if (baudrate == 1200) { + uint32_t *top = (uint32_t *)(DT_REG_ADDR(DT_NODELABEL(sram0)) + + DT_REG_SIZE(DT_NODELABEL(sram0))); - uart_line_ctrl_get(msg->dev, UART_LINE_CTRL_BAUD_RATE, &baudrate); - if (baudrate) { - LOG_INF("Baudrate %u", baudrate); - } + /* Detach before resetting, as bossa.c did, so the host sees the + * device go away rather than stop responding mid-enumeration. */ + (void)usbd_disable(ctx); + top[-1] = BOSSA_DOUBLE_TAP_MAGIC; + NVIC_SystemReset(); } +#endif } -*/ + static int app_usb_init(void) { int err; @@ -87,7 +95,7 @@ static int app_usb_init(void) return err; } - err = usbd_register_all_classes(&app_usbd, USBD_SPEED_FS, 1); + err = usbd_register_all_classes(&app_usbd, USBD_SPEED_FS, 1, NULL); if (err) { LOG_ERR("Failed to add register classes"); return err; @@ -98,13 +106,13 @@ static int app_usb_init(void) * available, use an appropriate triple to indicate it. */ usbd_device_set_code_triple(&app_usbd, USBD_SPEED_FS, USB_BCC_MISCELLANEOUS, 0x02, 0x01); - /* - err = usbd_msg_register_cb(&app_usbd, &usb_msg_cb); - if (err) { - LOG_ERR("Failed to register message callback"); - return err; - } - */ + + err = usbd_msg_register_cb(&app_usbd, &usb_msg_cb); + if (err) { + LOG_ERR("Failed to register message callback"); + return err; + } + (void)usbd_device_set_bcd_usb(&app_usbd, USBD_SPEED_FS, 0x0201); err = usbd_add_descriptor(&app_usbd, &app_usbext); diff --git a/applications/motor_controller/tests.yaml b/applications/motor_controller/tests.yaml index 083d390..6110f66 100644 --- a/applications/motor_controller/tests.yaml +++ b/applications/motor_controller/tests.yaml @@ -6,6 +6,13 @@ sample: name: motor-controller-application common: build_only: true + # The app is board-specific: it needs the motor0/seesaw/display nodes from + # boards/robotis_openrb_150.overlay, and mise's `app` task allows no other + # board. Without this, twister fans out over ~60 unrelated platforms and + # reports failures ("'__device_dts_ord_..._motor0_ORD' undeclared") that only + # mean "this app was never meant to build there". + platform_allow: + - robotis_openrb_150 integration_platforms: - robotis_openrb_150 tests: