Skip to content

boards: pjrc: Added Support for the Teensy CLI Tools soft reboot functionality #88024

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Kconfig.zephyr
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,19 @@ config BOOTLOADER_BOSSA_ADAFRUIT_UF2

endchoice

config BOOTLOADER_TEENSY
bool "Teensy bootloader support"
depends on SOC_SERIES_IMXRT10XX
help
Sets whether the teensy bootloader should be loaded when an baudrate change is send or not.

config BOOTLOADER_TEENSY_DEVICE_NAME
string "Teensy CDC ACM device name"
depends on BOOTLOADER_TEENSY
default "USB CDC-ACM"
help
Sets the CDC ACM port to watch for reboot commands.

endmenu

menu "Compatibility"
Expand Down
1 change: 1 addition & 0 deletions boards/pjrc/teensy4/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ if(CONFIG_NXP_IMXRT_BOOT_HEADER)
zephyr_compile_definitions(BOARD_FLASH_SIZE=CONFIG_FLASH_SIZE*1024)
zephyr_library_sources(flexspi_nor_config.c)
zephyr_library_sources_ifdef(CONFIG_DEVICE_CONFIGURATION_DATA teensy4_sdram_ini_dcd.c)
zephyr_library_sources_ifdef(CONFIG_BOOTLOADER_TEENSY bootloader_teensy.c)
endif()
51 changes: 51 additions & 0 deletions boards/pjrc/teensy4/bootloader_teensy.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2025 Navimatix GmbH.
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <soc.h>
#include <zephyr/drivers/uart/cdc_acm.h>
#include <zephyr/drivers/usb/usb_dc.h>
#include <zephyr/init.h>
#include <zephyr/usb/class/usb_cdc.h>
#include <zephyr/logging/log.h>

LOG_MODULE_REGISTER(reset, CONFIG_SOC_LOG_LEVEL);

#define TEENSY_RESET_BAUDRATE 134
#define TEENSY_RESET_COMMAND "bkpt #251"
#define TEENSY_VID 0x16c0
#define TEENSY_PID 0x0483

static void teensy_reset(const struct device *dev, uint32_t rate)
{
if (rate != TEENSY_RESET_BAUDRATE) {
return;
}

/* The programmer set the baud rate to 134 baud. Reset into the
* bootloader.
*/
__ASM volatile(TEENSY_RESET_COMMAND);
}

void board_late_init_hook(void)
{
const struct device *dev = device_get_binding(CONFIG_BOOTLOADER_TEENSY_DEVICE_NAME);

if (dev == NULL) {
LOG_ERR("Could not find reset signal device with name %s",
CONFIG_BOOTLOADER_TEENSY_DEVICE_NAME);
return;
}

if ((CONFIG_USB_DEVICE_VID != TEENSY_VID) || (CONFIG_USB_DEVICE_PID != TEENSY_PID)) {
LOG_ERR("Incorrect USB VID or PID. CONFIG_USB_DEVICE_VID should be 0x%x and "
"CONFIG_USB_DEVICE_PID should be 0x%x.",
TEENSY_VID, TEENSY_PID);
return;
}

cdc_acm_dte_rate_callback_set(dev, teensy_reset);
}
9 changes: 7 additions & 2 deletions scripts/west_commands/runners/teensy.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@
class TeensyBinaryRunner(ZephyrBinaryRunner):
'''Runner front-end for teensy.'''

def __init__(self, cfg, mcu, teensy_loader):
def __init__(self, cfg, mcu, teensy_loader, flags):
super().__init__(cfg)

self.mcu_args = ['--mcu', mcu]
self.teensy_loader = teensy_loader
self.hex_name = cfg.hex_file
self.flags = flags

@classmethod
def name(cls):
Expand All @@ -30,12 +31,13 @@ def do_add_parser(cls, parser):
help='Teensy mcu target')
parser.add_argument('--teensy', default='teensy_loader_cli',
help='path to teensy cli tool, default is teensy_loader_cli')
parser.add_argument('--flags', help='Flags for the teensy cli tool')

@classmethod
def do_create(cls, cfg, args):
ret = TeensyBinaryRunner(
cfg, args.mcu,
teensy_loader=args.teensy)
teensy_loader=args.teensy, flags=args.flags)
return ret

def do_run(self, command):
Expand All @@ -54,6 +56,9 @@ def flash(self):
self.mcu_args +
[fname])

if self.flags is not None:
cmd.append("-" + self.flags)

self.logger.info(f'Flashing file: {fname}')

try:
Expand Down
32 changes: 32 additions & 0 deletions snippets/pjrc-teensy-bootloader/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
.. _snippet-pjrc-teensy-bootloader:

PJRC Teensy Bootloader (pjrc-teensy-bootloader)
###############################################

.. code-block:: console

west build -S pjrc-teensy-bootloader [...]

Overview
********

This snippet makes the nessecary configurations to allow flashing of Teensy 4
based boards without triggering the reset pin. This is done via a CDC ACM UART.

Requirements
************

A board that supports flashing via the teensy cli tools.

A devicetree node with node label ``zephyr_udc0`` that points to an enabled USB
device node with driver support. This should look roughly like this in
:ref:`your devicetree <get-devicetree-outputs>`:

.. code-block:: DTS

usb1: zephyr_udc0: usbd@402e0000 {
compatible = "nxp,ehci";
/* ... */
};

The Teensy 4.0 and 4.1 boards have this node by default, but others might not.
9 changes: 9 additions & 0 deletions snippets/pjrc-teensy-bootloader/pjrc-teensy-bootloader.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CONFIG_BOOTLOADER_TEENSY=y
CONFIG_USB_DEVICE_VID=0x16c0
CONFIG_USB_DEVICE_PID=0x0483
Comment on lines +2 to +3
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot use someone else's vendor ID in the tree.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thing is, it needs to be there, as the teensy cli looks for this specific VID/PID combination to send the soft-reboot command to.
I honestly have no idea what the process would be for getting permission to use the vendor id for this use case.

There are a handfull of uses of specific vendor ids in the tree, but I dont know their background.

Some other potential solutions, if we can not get permission to use the vendor id, would be to note the correct vendor id in the snippet readme, or look if we can get support for the zephyr vendor id in the teensy cli.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thing is, it needs to be there, as the teensy cli looks for this specific VID/PID combination to send the soft-reboot command to.

No, it does not need to be there. It is entirely the "teensy cli" problem.

I honestly have no idea what the process would be for getting permission to use the vendor id for this use case.

"Each Vendor ID Number is assigned to one company for its sole and exclusive use, along with associated Product ID Numbers. They may not be sold, transferred, or used by others, directly or indirectly, except in special circumstances and then only upon prior written approval by USB-IF. Unauthorized use of assigned or unassigned USB Vendor ID Numbers and associated Product ID Numbers are strictly prohibited." [0]

Also, I am not going to write about Vendor ID 0x16c0, but you can find some information about it on your own.

There are a handfull of uses of specific vendor ids in the tree, but I dont know their background.

I see only one left. I will remove it as well.

look if we can get support for the zephyr vendor id in the teensy cli.

It would not help you with your custom firmware/product because of [0]. I guess "teensy cli" could be improved to accept VID/PID arguments, but that is not an issue for the Zephyr Project.

[0] https://www.usb.org/sites/default/files/usb-if_member_agreement_080618_1.pdf

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification.

I did some investigation into teensy_cli, but the required changes are more difficult than they first appeared, so I currently don't plan on pursuing that avenue any further.

At this point it looks to me like the best option is to remove the vendor id from the snippet conf file and mention the correct vendor id in the readme instead.

I am also thinking about adding information about the snippet/soft reboot to the flashing section of the board readme.


CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_CDC_ACM=y
CONFIG_CDC_ACM_DTE_RATE_CALLBACK_SUPPORT=y
CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=y
Comment on lines +5 to +8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is about to become deprecated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would be the new way to do this?

CONFIG_BOARD_LATE_INIT_HOOK=y
12 changes: 12 additions & 0 deletions snippets/pjrc-teensy-bootloader/pjrc-teensy-bootloader.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright (c) 2025 Navimatix GmbH
*
* SPDX-License-Identifier: Apache-2.0
*/

&zephyr_udc0 {
snippet_pjrc_teensy_bootloader_uart {
compatible = "zephyr,cdc-acm-uart";
label = "USB CDC-ACM";
};
};
4 changes: 4 additions & 0 deletions snippets/pjrc-teensy-bootloader/snippet.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name: pjrc-teensy-bootloader
append:
EXTRA_CONF_FILE: pjrc-teensy-bootloader.conf
EXTRA_DTC_OVERLAY_FILE: pjrc-teensy-bootloader.overlay
Loading