nmaggioni commented on issue #16271: URL: https://github.com/apache/nuttx/issues/16271#issuecomment-3263701404
> @linguini1 Have a bootloader that puts the RP2040 into BOOTSEL when it detects something like 1200 baud on a UART line In my RP2040 board I have implemented this over USB CDC-ACM instead of UART. This comes at the cost of having a background demon that listens for LINE_CODING events (let me improperly call them "baud rate changes"), though. <details> <summary>Example code, ran as part of bringup</summary> Note: I have removed all error handling, comments, and mangled the control structure of this code for maximum brevity. Consider it pseudocode at this point :) The `BOARDIOC_RESET_BOOTSEL` ioctl does what the name suggests and is backed by a ROM lookup like in pico-sdk. ```c static sem_t g_board_bootsel_on_baudrate_change_daemon_sem; static void cdcacm_daemon_callback(enum cdcacm_event_e event) { if (event == CDCACM_EVENT_LINECODING) { sem_post(&g_board_bootsel_on_baudrate_change_daemon_sem); } } static int cdcacm_daemon(int argc, char *argv[]) { while (true) { sem_wait(&g_board_bootsel_on_baudrate_change_daemon_sem); int fd = open("/dev/ttyACM0", O_RDONLY); struct cdc_linecoding_s linecoding; int ret = ioctl(fd, CAIOC_GETLINECODING, &linecoding); unsigned long baud = (linecoding.baud[3] << 24 | linecoding.baud[2] << 16 | linecoding.baud[1] << 8 | linecoding.baud[0]); close(fd); if (baud == 1200) { boardctl(BOARDIOC_RESET_BOOTSEL, (uintptr_t)NULL); } } } static int board_cdcacm_daemon_setup(int argc, char *argv[]) { uint8_t retry = 0; uint8_t retry_delay_lut[] = { 1, 2, 3, 5, 10, 15, 30, 60 }; int fd; while (true) { fd = open("/dev/ttyACM0", O_RDONLY); if (fd >= 0) break; if (retry < ARRAY_SIZE(retry_delay_lut)) { uint8_t delay = retry_delay_lut[retry++]; usleep(delay * USEC_PER_SEC); } else { return EXIT_FAILURE; } } ioctl(fd, CAIOC_REGISTERCB, &cdcacm_daemon_callback); close(fd); sem_init(&g_board_bootsel_on_baudrate_change_daemon_sem, 0, 0); sem_setprotocol(&g_board_bootsel_on_baudrate_change_daemon_sem, SEM_PRIO_NONE); task_create("cdcacm_daemon", sched_get_priority_min(SCHED_FIFO), 512, cdcacm_daemon, NULL); return EXIT_SUCCESS; } int board_app_finalinitialize(uintptr_t arg) { int pid = task_create("board_cdcacm_daemon_setup", sched_get_priority_min(SCHED_FIFO) + 1, 1024, board_cdcacm_daemon_setup, NULL); return EXIT_SUCCESS; } ``` </details> ```plaintext nsh> ps PID GROUP PRI POLICY TYPE NPX STATE EVENT STACK USED FILLED COMMAND 0 0 0 FIFO Kthread - Ready 0001008 0000560 55.5% Idle_Task 1 1 100 RR Task - Running 0003032 0001664 54.8% nsh_main 3 3 1 RR Task - Waiting Semaphore 0000472 0000408 86.4%! cdcacm_daemon ``` This way I can run `stty -F /dev/serial/by-id/usb-<your_device_id> 1200` on the host and have the board reboot to bootloader, and then it's just a matter of a few shell commands to wait for the USB drive to appear and copy the new UF2 file to it. I've wrapped all these actions in a couple of [Just](https://just.systems/man/en/) recipes for ease of use, so I can get away with things like `just build && just bootsel-flash` :) @cederom What do you think of this approach? Would it be interesting to upstream it or is it too niche? I typically use a debug probe while developing, but this alternative way of flashing still comes in handy at times. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: commits-unsubscr...@nuttx.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org