zephyr: add an option to use GPIO to enable USB DFU.
Devices with a physical reset button might prefer to use it to enter USB
DFU mode, instead of always entering it with a timeout. Extract the
existing CONFIG_BOOT_SERIAL_DETECT detection code and use it to enter
DFU mode when CONFIG_BOOT_USB_DFU_GPIO is enabled.
This commit depends on zephyrproject-rtos/zephyr#30015, which changes
wait_for_usb_dfu from a nullary function that waits for a compile-time
fixed amount of time, to one that takes a timeout.
Signed-off-by: Josh Gao <josh@jmgao.dev>
diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c
index 2471ee4..763f90e 100644
--- a/boot/zephyr/main.c
+++ b/boot/zephyr/main.c
@@ -44,7 +44,7 @@
};
#endif
-#ifdef CONFIG_BOOT_WAIT_FOR_USB_DFU
+#if defined(CONFIG_BOOT_USB_DFU_WAIT) || defined(CONFIG_BOOT_USB_DFU_GPIO)
#include <usb/class/usb_dfu.h>
#endif
@@ -128,7 +128,7 @@
#define LED0_GPIO_LABEL DT_GPIO_LABEL(LED0_NODE, gpios)
#define LED0_GPIO_PIN DT_GPIO_PIN(LED0_NODE, gpios)
#define LED0_GPIO_FLAGS (GPIO_OUTPUT | FLAGS_OR_ZERO(LED0_NODE))
-#else
+#else
/* A build error here means your board isn't set up to drive an LED. */
#error "Unsupported board: led0 devicetree alias is not defined"
#endif
@@ -137,7 +137,7 @@
void led_init(void)
{
-
+
led = device_get_binding(LED0_GPIO_LABEL);
if (led == NULL) {
BOOT_LOG_ERR("Didn't find LED device %s\n", LED0_GPIO_LABEL);
@@ -365,6 +365,71 @@
#endif/* defined(CONFIG_LOG) && !defined(CONFIG_LOG_IMMEDIATE) &&\
!defined(CONFIG_LOG_PROCESS_THREAD) */
+#if defined(CONFIG_MCUBOOT_SERIAL) || defined(CONFIG_BOOT_USB_DFU_GPIO)
+static bool detect_pin(const char* port, int pin, uint32_t expected, int delay)
+{
+ int rc;
+ int detect_value;
+ struct device const *detect_port;
+
+ detect_port = device_get_binding(port);
+ __ASSERT(detect_port, "Error: Bad port for boot detection.\n");
+
+ /* The default presence value is 0 which would normally be
+ * active-low, but historically the raw value was checked so we'll
+ * use the raw interface.
+ */
+ rc = gpio_pin_configure(detect_port, pin,
+#ifdef GPIO_INPUT
+ GPIO_INPUT | GPIO_PULL_UP
+#else
+ GPIO_DIR_IN | GPIO_PUD_PULL_UP
+#endif
+ );
+ __ASSERT(rc == 0, "Failed to initialize boot detect pin.\n");
+
+#ifdef GPIO_INPUT
+ rc = gpio_pin_get_raw(detect_port, pin);
+ detect_value = rc;
+#else
+ rc = gpio_pin_read(detect_port, pin, &detect_value);
+#endif
+ __ASSERT(rc >= 0, "Failed to read boot detect pin.\n");
+
+ if (detect_value == expected) {
+ if (delay > 0) {
+ k_sleep(K_MSEC(50));
+
+ /* Get the uptime for debounce purposes. */
+ int64_t timestamp = k_uptime_get();
+
+ for(;;) {
+#ifdef GPIO_INPUT
+ rc = gpio_pin_get_raw(detect_port, pin);
+ detect_value = rc;
+#else
+ rc = gpio_pin_read(detect_port, pin, &detect_value);
+#endif
+ __ASSERT(rc >= 0, "Failed to read boot detect pin.\n");
+
+ /* Get delta from when this started */
+ uint32_t delta = k_uptime_get() - timestamp;
+
+ /* If not pressed OR if pressed > debounce period, stop. */
+ if (delta >= delay || detect_value != expected) {
+ break;
+ }
+
+ /* Delay 1 ms */
+ k_sleep(K_MSEC(1));
+ }
+ }
+ }
+
+ return detect_value == expected;
+}
+#endif
+
void main(void)
{
struct boot_rsp rsp;
@@ -406,91 +471,47 @@
#endif
#ifdef CONFIG_MCUBOOT_SERIAL
-
- struct device const *detect_port;
- uint32_t detect_value = !CONFIG_BOOT_SERIAL_DETECT_PIN_VAL;
-
- detect_port = device_get_binding(CONFIG_BOOT_SERIAL_DETECT_PORT);
- __ASSERT(detect_port, "Error: Bad port for boot serial detection.\n");
-
- /* The default presence value is 0 which would normally be
- * active-low, but historically the raw value was checked so we'll
- * use the raw interface.
- */
- rc = gpio_pin_configure(detect_port, CONFIG_BOOT_SERIAL_DETECT_PIN,
-#ifdef GPIO_INPUT
- GPIO_INPUT | GPIO_PULL_UP
-#else
- GPIO_DIR_IN | GPIO_PUD_PULL_UP
-#endif
- );
- __ASSERT(rc == 0, "Error of boot detect pin initialization.\n");
-
-#ifdef GPIO_INPUT
- rc = gpio_pin_get_raw(detect_port, CONFIG_BOOT_SERIAL_DETECT_PIN);
- detect_value = rc;
-#else
- rc = gpio_pin_read(detect_port, CONFIG_BOOT_SERIAL_DETECT_PIN,
- &detect_value);
-#endif
- __ASSERT(rc >= 0, "Error of the reading the detect pin.\n");
- if (detect_value == CONFIG_BOOT_SERIAL_DETECT_PIN_VAL &&
- !boot_skip_serial_recovery()) {
-
-#if CONFIG_BOOT_SERIAL_DETECT_DELAY > 0
- k_sleep(K_MSEC(50));
-
- /* Get the uptime for debounce purposes. */
- int64_t timestamp = k_uptime_get();
-
- for(;;) {
-
-#ifdef GPIO_INPUT
- rc = gpio_pin_get_raw(detect_port, CONFIG_BOOT_SERIAL_DETECT_PIN);
- detect_value = rc;
-#else
- rc = gpio_pin_read(detect_port, CONFIG_BOOT_SERIAL_DETECT_PIN,
- &detect_value);
-#endif
- __ASSERT(rc >= 0, "Error of the reading the detect pin.\n");
-
- /* Get delta from when this started */
- uint32_t delta = k_uptime_get() - timestamp;
-
- /* If not pressed OR if pressed > debounce period stop loop*/
- if( delta >= CONFIG_BOOT_SERIAL_DETECT_DELAY ||
- detect_value != CONFIG_BOOT_SERIAL_DETECT_PIN_VAL ) {
- break;
- }
-
-
- /* Delay 1 ms */
- k_sleep(K_MSEC(1));
- }
-#endif
-
- /* Then run DFU */
- if (detect_value == CONFIG_BOOT_SERIAL_DETECT_PIN_VAL) {
+ if (detect_pin(CONFIG_BOOT_SERIAL_DETECT_PORT,
+ CONFIG_BOOT_SERIAL_DETECT_PIN,
+ CONFIG_BOOT_SERIAL_DETECT_PIN_VAL,
+ CONFIG_BOOT_SERIAL_DETECT_DELAY) &&
+ !boot_skip_serial_recovery()) {
#ifdef CONFIG_MCUBOOT_INDICATION_LED
- gpio_pin_set(led, LED0_GPIO_PIN, 1);
-#endif
- BOOT_LOG_INF("Enter the serial recovery mode");
- rc = boot_console_init();
- __ASSERT(rc == 0, "Error initializing boot console.\n");
- boot_serial_start(&boot_funcs);
- __ASSERT(0, "Bootloader serial process was terminated unexpectedly.\n");
-
- }
-}
+ gpio_pin_set(led, LED0_GPIO_PIN, 1);
#endif
-#ifdef CONFIG_BOOT_WAIT_FOR_USB_DFU
+ BOOT_LOG_INF("Enter the serial recovery mode");
+ rc = boot_console_init();
+ __ASSERT(rc == 0, "Error initializing boot console.\n");
+ boot_serial_start(&boot_funcs);
+ __ASSERT(0, "Bootloader serial process was terminated unexpectedly.\n");
+ }
+#endif
+
+#if defined(CONFIG_BOOT_USB_DFU_GPIO)
+ if (detect_pin(CONFIG_BOOT_USB_DFU_DETECT_PORT,
+ CONFIG_BOOT_USB_DFU_DETECT_PIN,
+ CONFIG_BOOT_USB_DFU_DETECT_PIN_VAL,
+ CONFIG_BOOT_USB_DFU_DETECT_DELAY)) {
+#ifdef CONFIG_MCUBOOT_INDICATION_LED
+ gpio_pin_set(led, LED0_GPIO_PIN, 1);
+#endif
+ rc = usb_enable(NULL);
+ if (rc) {
+ BOOT_LOG_ERR("Cannot enable USB");
+ } else {
+ BOOT_LOG_INF("Waiting for USB DFU");
+ wait_for_usb_dfu(K_FOREVER);
+ BOOT_LOG_INF("USB DFU wait time elapsed");
+ }
+ }
+#elif defined(CONFIG_BOOT_USB_DFU_WAIT)
rc = usb_enable(NULL);
if (rc) {
BOOT_LOG_ERR("Cannot enable USB");
} else {
BOOT_LOG_INF("Waiting for USB DFU");
- wait_for_usb_dfu();
+ wait_for_usb_dfu(K_MSEC(CONFIG_BOOT_USB_DFU_WAIT_DELAY_MS));
BOOT_LOG_INF("USB DFU wait time elapsed");
}
#endif