-
Notifications
You must be signed in to change notification settings - Fork 8
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
app: add USB Device Firmware Upgrade (DFU) support #28
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
0a420e1
app: add support for generating an USB DFU image
henrikbrixandersen 610263e
app: add support for USB DFU mode via MCUboot
henrikbrixandersen 2815adc
app: turn off DFU LED once booted
henrikbrixandersen 571bb64
boards: add frdm_k64f board extension
henrikbrixandersen 5d82060
app: add support for triggering DFU mode via DFU button
henrikbrixandersen b513292
README: document DFU mode
henrikbrixandersen File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,5 @@ | |
zephyr_include_directories(include) | ||
|
||
add_subdirectory(subsys) | ||
|
||
include(cmake/cannectivity.cmake) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# Copyright (c) 2024 Henrik Brix Andersen <[email protected]> | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
menuconfig CANNECTIVITY_USB_DFU | ||
bool "CANnectivity USB DFU mode" | ||
help | ||
Enable support for CANnectivity USB Device Firmware Upgrade (DFU) mode using the MCUboot | ||
bootloader. | ||
|
||
if CANNECTIVITY_USB_DFU | ||
|
||
config CANNECTIVITY_USB_DFU_MANUFACTURER | ||
string "USB DFU mode manufacturer string" | ||
default "CANnectivity" | ||
help | ||
CANnectivity USB DFU mode manufacturer string. | ||
|
||
config CANNECTIVITY_USB_DFU_PRODUCT | ||
string "USB DFU mode product string" | ||
default "CANnectivity USB to CAN adapter in DFU mode" | ||
help | ||
CANnectivity USB DFU mode product string. | ||
|
||
config CANNECTIVITY_USB_DFU_VID | ||
hex "USB DFU mode Vendor ID (VID)" | ||
default 0x1209 | ||
help | ||
CANnectivity USB DFU mode Vendor ID (VID). | ||
|
||
config CANNECTIVITY_USB_DFU_PID | ||
hex "USB DFU mode Product ID (PID)" | ||
default 0x0001 | ||
help | ||
CANnectivity USB DFU mode Product ID (PID). | ||
|
||
config CANNECTIVITY_USB_DFU_MAX_POWER | ||
int "USB DFU mode maximum power" | ||
default 125 | ||
range 0 250 | ||
help | ||
CANnectivity USB DFU mode maximum current draw in milliampere (mA) divided by 2. | ||
A value of 125 results in a maximum current draw value of 250 mA. | ||
|
||
endif # CANNECTIVITY_USB_DFU | ||
|
||
source "share/sysbuild/Kconfig" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
/* | ||
* Copyright (c) 2024 Henrik Brix Andersen <[email protected]> | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#include <zephyr/sys_clock.h> | ||
#include <zephyr/dfu/mcuboot.h> | ||
#include <zephyr/drivers/gpio.h> | ||
#include <zephyr/kernel.h> | ||
#include <zephyr/logging/log.h> | ||
#include <zephyr/sys/reboot.h> | ||
|
||
#include "cannectivity.h" | ||
|
||
LOG_MODULE_REGISTER(dfu, CONFIG_CANNECTIVITY_LOG_LEVEL); | ||
|
||
/* DFU button poll timing */ | ||
#define DFU_BUTTON_POLL_HZ 5 | ||
#define DFU_BUTTON_POLL_INTERVAL_MS (MSEC_PER_SEC / DFU_BUTTON_POLL_HZ) | ||
#define DFU_BUTTON_POLL_TOTAL (CONFIG_CANNECTIVITY_DFU_BUTTON_HOLD_TIME * DFU_BUTTON_POLL_HZ) | ||
|
||
/* DFU button and LED devicetree nodes */ | ||
#define DFU_LED_NODE DT_ALIAS(mcuboot_led0) | ||
#define DFU_BUTTON_NODE DT_ALIAS(mcuboot_button0) | ||
|
||
#ifdef CONFIG_CANNECTIVITY_DFU_LED | ||
struct gpio_dt_spec dfu_led = GPIO_DT_SPEC_GET(DFU_LED_NODE, gpios); | ||
#endif /* CONFIG_CANNECTIVITY_DFU_LED */ | ||
|
||
#ifdef CONFIG_CANNECTIVITY_DFU_BUTTON | ||
struct gpio_dt_spec dfu_button = GPIO_DT_SPEC_GET(DFU_BUTTON_NODE, gpios); | ||
static struct gpio_callback dfu_button_cb; | ||
static struct k_work_delayable dfu_button_work; | ||
static struct k_sem dfu_button_sem; | ||
|
||
static void dfu_button_poll(struct k_work *work) | ||
{ | ||
struct k_work_delayable *dwork = k_work_delayable_from_work(work); | ||
int err; | ||
|
||
err = gpio_pin_get_dt(&dfu_button); | ||
if (err < 0) { | ||
LOG_ERR("failed to get DFU button state (err %d)", err); | ||
goto done; | ||
} | ||
|
||
if (err > 0) { | ||
#ifdef CONFIG_CANNECTIVITY_DFU_LED | ||
err = gpio_pin_toggle_dt(&dfu_led); | ||
if (err != 0) { | ||
LOG_ERR("failed to toggle DFU LED (err %d)", err); | ||
goto done; | ||
} | ||
#endif /* CONFIG_CANNECTIVITY_DFU_LED */ | ||
|
||
k_sem_give(&dfu_button_sem); | ||
if (k_sem_count_get(&dfu_button_sem) >= DFU_BUTTON_POLL_TOTAL) { | ||
LOG_INF("rebooting"); | ||
sys_reboot(SYS_REBOOT_COLD); | ||
} | ||
|
||
k_work_reschedule(dwork, K_MSEC(DFU_BUTTON_POLL_INTERVAL_MS)); | ||
return; | ||
} | ||
|
||
done: | ||
#ifdef CONFIG_CANNECTIVITY_DFU_LED | ||
err = gpio_pin_set_dt(&dfu_led, 0); | ||
if (err != 0) { | ||
LOG_ERR("failed to turn off DFU LED (err %d)", err); | ||
return; | ||
} | ||
#endif /* CONFIG_CANNECTIVITY_DFU_LED */ | ||
} | ||
|
||
static void dfu_button_interrupt(const struct device *port, struct gpio_callback *cb, | ||
gpio_port_pins_t pins) | ||
{ | ||
ARG_UNUSED(port); | ||
ARG_UNUSED(cb); | ||
ARG_UNUSED(pins); | ||
|
||
k_sem_reset(&dfu_button_sem); | ||
k_work_reschedule(&dfu_button_work, K_NO_WAIT); | ||
} | ||
|
||
static int dfu_button_init(void) | ||
{ | ||
int err; | ||
|
||
err = k_sem_init(&dfu_button_sem, 0, K_SEM_MAX_LIMIT); | ||
if (err != 0) { | ||
LOG_ERR("failed to initialize DFU button semaphore (err %d)", err); | ||
return err; | ||
} | ||
|
||
if (!gpio_is_ready_dt(&dfu_button)) { | ||
LOG_ERR("DFU button device not ready"); | ||
return -ENODEV; | ||
} | ||
|
||
err = gpio_pin_configure_dt(&dfu_button, GPIO_INPUT); | ||
if (err != 0) { | ||
LOG_ERR("failed to configure DFU button (err %d)", err); | ||
return err; | ||
} | ||
|
||
err = gpio_pin_interrupt_configure_dt(&dfu_button, GPIO_INT_EDGE_TO_ACTIVE); | ||
if (err != 0) { | ||
LOG_ERR("failed to configure DFU button interrupt (err %d)", err); | ||
return err; | ||
} | ||
|
||
k_work_init_delayable(&dfu_button_work, dfu_button_poll); | ||
|
||
gpio_init_callback(&dfu_button_cb, dfu_button_interrupt, BIT(dfu_button.pin)); | ||
err = gpio_add_callback_dt(&dfu_button, &dfu_button_cb); | ||
if (err != 0) { | ||
LOG_ERR("failed to add DFU button callback (err %d)", err); | ||
return err; | ||
} | ||
|
||
return 0; | ||
} | ||
#endif /* CONFIG_CANNECTIVITY_DFU_BUTTON */ | ||
|
||
#ifdef CONFIG_CANNECTIVITY_DFU_LED | ||
static int dfu_led_init(void) | ||
{ | ||
int err; | ||
|
||
if (!gpio_is_ready_dt(&dfu_led)) { | ||
LOG_ERR("DFU LED device not ready"); | ||
return -ENODEV; | ||
} | ||
|
||
err = gpio_pin_configure_dt(&dfu_led, GPIO_OUTPUT_INACTIVE); | ||
if (err != 0) { | ||
LOG_ERR("failed to turn off DFU LED (err %d)", err); | ||
return err; | ||
} | ||
|
||
return 0; | ||
} | ||
#endif /* CONFIG_CANNECTIVITY_DFU_LED */ | ||
|
||
int cannectivity_dfu_init(void) | ||
{ | ||
int err; | ||
|
||
/* | ||
* Confirm updated image if running under MCUboot booloader. This could be done on | ||
* successful USB enumeration instead, but that could cause unwanted image reverts on | ||
* e.g. self-powered development boards. | ||
*/ | ||
if (!boot_is_img_confirmed()) { | ||
err = boot_write_img_confirmed(); | ||
if (err != 0) { | ||
LOG_ERR("failed to confirm image (err %d)", err); | ||
return err; | ||
} | ||
|
||
LOG_INF("image confirmed"); | ||
} | ||
|
||
#ifdef CONFIG_CANNECTIVITY_DFU_LED | ||
err = dfu_led_init(); | ||
if (err != 0) { | ||
return err; | ||
} | ||
#endif /* CONFIG_CANNECTIVITY_DFU_LED */ | ||
|
||
#ifdef CONFIG_CANNECTIVITY_DFU_BUTTON | ||
err = dfu_button_init(); | ||
if (err != 0) { | ||
return err; | ||
} | ||
#endif /* CONFIG_CANNECTIVITY_DFU_BUTTON */ | ||
|
||
return 0; | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PID is for testing only. Waiting on pidcodes/pidcodes.github.com#981