This is an automated email from the ASF dual-hosted git repository. vipulrahane pushed a commit to branch debug_u_s_b in repository https://gitbox.apache.org/repos/asf/mynewt-core.git
commit a572ffb6b2d61c1180dd44c42fdd50ae760064b5 Author: Vipul Rahane <[email protected]> AuthorDate: Wed Aug 27 16:02:25 2025 -0700 Init --- hw/usb/tinyusb/da146xx/include/tusb_hw.h | 33 +++ hw/usb/tinyusb/da146xx/pkg.yml | 3 + hw/usb/tinyusb/da146xx/src/da1469x.c | 185 +++++++++++++++- .../include/keepalive_detect/keepalive_detect.h | 110 ++++++++++ .../tinyusb/{da146xx => keepalive_detect}/pkg.yml | 16 +- .../keepalive_detect/src/keepalive_detect.c | 234 +++++++++++++++++++++ .../pkg.yml => keepalive_detect/syscfg.yml} | 30 +-- hw/usb/tinyusb/syscfg.yml | 4 + 8 files changed, 589 insertions(+), 26 deletions(-) diff --git a/hw/usb/tinyusb/da146xx/include/tusb_hw.h b/hw/usb/tinyusb/da146xx/include/tusb_hw.h index 54c48602f..f02c3171a 100644 --- a/hw/usb/tinyusb/da146xx/include/tusb_hw.h +++ b/hw/usb/tinyusb/da146xx/include/tusb_hw.h @@ -25,6 +25,39 @@ #include <syscfg/syscfg.h> #include <stdbool.h> +#if MYNEWT_VAL(DA1469X_USB_KEEPALIVE_DETECT) +/** + * Set event queue for keep-alive monitoring + */ +void tinyusb_ka_evq_set(struct os_eventq *evq); + +/** + * Check if USB keep-alive detection considers USB to be active + */ +bool tinyusb_ka_is_active(void); + +/** + * Get number of SOFs received since last USB disconnect + */ +uint32_t tinyusb_ka_get_sof_cnt(void); + +/** + * Reset SOF count to zero + */ +void tinyusb_ka_reset_sof_cnt(void); + +/** + * + * Register callback for keep-alive state changes + */ +void tinyusb_ka_register_cb(void (*cb)(bool connected)); +#endif + +/** + * Check if USB is connected (based on keep-alive and VBUS if used) + */ +bool tinyusb_is_connected(void); + /* Function should be exported from TinyUSB */ void tusb_vbus_changed(bool present); diff --git a/hw/usb/tinyusb/da146xx/pkg.yml b/hw/usb/tinyusb/da146xx/pkg.yml index 5e0e9c2d0..88c7c3d84 100644 --- a/hw/usb/tinyusb/da146xx/pkg.yml +++ b/hw/usb/tinyusb/da146xx/pkg.yml @@ -31,3 +31,6 @@ pkg.apis: pkg.deps: - "@apache-mynewt-core/kernel/os" - "@apache-mynewt-core/hw/usb/tinyusb" + +pkg.deps.USB_KEEPALIVE_DETECT: + - "@apache-mynewt-core/hw/usb/tinyusb/keepalive_detect" diff --git a/hw/usb/tinyusb/da146xx/src/da1469x.c b/hw/usb/tinyusb/da146xx/src/da1469x.c index 02e224e5b..d3fb215c5 100644 --- a/hw/usb/tinyusb/da146xx/src/da1469x.c +++ b/hw/usb/tinyusb/da146xx/src/da1469x.c @@ -24,21 +24,34 @@ #include <device/usbd.h> -static bool vbus_present; +#if MYNEWT_VAL(USB_KEEPALIVE_DETECT) -static void -USBD_IRQHandler(void) -{ - tud_int_handler(0); -} +#ifdef MYNEWT_VAL_USB_KEEPALIVE_EVQ +struct os_eventq MYNEWT_VAL(USB_KEEPALIVE_EVQ); +#endif + +#include <keepalive_detect/keepalive_detect.h> + +/* USB register bit definitions moved here when keepalive is enabled, + * this combines position and mask, so an absolute mask can be used + */ +#define USB_MAMSK_REG_USB_M_FRAME_Msk (0x0001U) +#define USB_ALTMSK_REG_USB_M_SD3_Msk (0x0008U) +#define USB_ALTMSK_REG_USB_M_RESUME_Msk (0x0004U) +#define USB_MAEV_REG_USB_FRAME_Msk (0x0001U) +#define USB_ALTEV_REG_USB_SD3_Msk (0x0008U) +#define USB_ALTEV_REG_USB_RESUME_Msk (0x0004U) +#endif + +static bool g_vbus_present; static void tinyusb_vbus_changed(bool present) { - if (vbus_present == present) { + if (g_vbus_present == present) { return; } - vbus_present = present; + g_vbus_present = present; if (present) { da1469x_pd_acquire(MCU_PD_DOMAIN_SYS); @@ -49,6 +62,99 @@ tinyusb_vbus_changed(bool present) } } +#if MYNEWT_VAL(USB_KEEPALIVE_DETECT) +/* + * DA1469x-specific keep-alive callbacks implementation + */ +static uint16_t +da1469x_get_frame_number(void) +{ + uint16_t frame_num; + + frame_num = USB->USB_FNL_REG & 0xFF; + frame_num |= (USB->USB_FNH_REG & 0x07) << 8; + + return frame_num; +} + +static void +da1469x_handle_sof_interrupt(void) +{ + uint32_t maev; + + maev = USB->USB_MAEV_REG; + + if (maev & USB_MAEV_REG_USB_FRAME_Msk) { + /* Clear the interrupt flag */ + USB->USB_MAEV_REG = USB_MAEV_REG_USB_FRAME_Msk; + + /* Notify keep-alive module */ + usb_keepalive_handle_sof(); + } +} + +static void +da1469x_check_suspend(void) +{ + uint32_t altev; + + altev = USB->USB_ALTEV_REG; + + if (altev & USB_ALTEV_REG_USB_SD3_Msk) { + /* No SOF for 3ms - USB suspended */ + USB->USB_ALTEV_REG = USB_ALTEV_REG_USB_SD3_Msk; + usb_keepalive_handle_suspend(); + } + + if (altev & USB_ALTEV_REG_USB_RESUME_Msk) { + /* Resume detected */ + USB->USB_ALTEV_REG = USB_ALTEV_REG_USB_RESUME_Msk; + usb_keepalive_handle_resume(); + } +} + +static void +da1469x_enable_ka_interrupts(void) +{ + /* Enable frame/SOF interrupt */ + USB->USB_MAMSK_REG |= USB_MAMSK_REG_USB_M_FRAME_Msk; + + /* Enable suspend detection */ + USB->USB_ALTMSK_REG |= USB_ALTMSK_REG_USB_M_SD3_Msk | + USB_ALTMSK_REG_USB_M_RESUME_Msk; +} + +static const struct usb_keepalive_cbs da1469x_keepalive_cbs = { + .handle_sof_interrupt = da1469x_handle_sof_interrupt, + .check_suspend = da1469x_check_suspend, + .enable_interrupts = da1469x_enable_ka_interrupts, + .get_frame_number = da1469x_get_frame_number, +}; + +static void +da1469x_keepalive_cb(bool connected) +{ + /* Trigger vbus change if not using VBUS detection */ + if (MYNEWT_VAL_CHOICE(DA1469X_USB_VBUS_HANDLING, ignore)) { + tinyusb_vbus_changed(connected); + } +} +#endif /* MYNEWT_VAL(USB_KEEPALIVE_DETECT) */ + +static void +USBD_IRQHandler(void) +{ +#if MYNEWT_VAL(USB_KEEPALIVE_DETECT) + /* Handle SOF/keep-alive interrupts */ + da1469x_handle_sof_interrupt(); + + /* Check for suspend (no keep-alives) */ + da1469x_check_suspend(); +#endif + + tud_int_handler(0); +} + void tinyusb_hardware_init(void) { @@ -69,6 +175,69 @@ tinyusb_hardware_init(void) } else if (MYNEWT_VAL_CHOICE(DA1469X_USB_VBUS_HANDLING, ignore)) { /* If VBUS handling is ignored notify TinyUSB that VBUS is on */ +#if MYNEWT_VAL(USB_KEEPALIVE_DETECT) + /* With keep-alive detection, don't immediately notify VBUS on */ + /* Wait for actual USB activity (SOF) to be detected */ +#else tinyusb_vbus_changed(true); +#endif } + +#if MYNEWT_VAL(USB_KEEPALIVE_DETECT) + /* Register DA1469x-specific callbacks */ + usb_keepalive_register_cbs(&da1469x_keepalive_cbs); + + /* Register callback for connection events */ + usb_keepalive_register_cb(da1469x_keepalive_cb); + + /* Set event queue if specified */ +#if MYNEWT_VAL(USB_KEEPALIVE_EVQ) + usb_keepalive_evq_set(MYNEWT_VAL(USB_KEEPALIVE_EVQ)); +#endif + + /* Initialize keep-alive detection */ + usb_keepalive_init(); +#endif } + +/* + * Public API functions - map to keepalive_detect functions + */ +#if MYNEWT_VAL(USB_KEEPALIVE_DETECT) + +bool +tinyusb_ka_is_active(void) +{ + return usb_keepalive_is_active(); +} + +uint32_t +tinyusb_ka_get_sof_cnt(void) +{ + return usb_keepalive_get_sof_cnt(); +} + +void +tinyusb_ka_register_cb(void (*cb)(bool connected)) +{ + usb_keepalive_register_cb(cb); +} + +bool +tinyusb_is_connected(void) +{ + bool ka_active; + + /* Check keep-alive detection status */ + ka_active = usb_keepalive_is_active(); + + /* If using auto VBUS handling, also check VBUS */ + if (MYNEWT_VAL_CHOICE(DA1469X_USB_VBUS_HANDLING, auto)) { + return g_vbus_present || ka_active; + } + + /* If ignoring VBUS, rely only on keep-alive */ + return ka_active; +} + +#endif /* MYNEWT_VAL(USB_KEEPALIVE_DETECT) */ diff --git a/hw/usb/tinyusb/keepalive_detect/include/keepalive_detect/keepalive_detect.h b/hw/usb/tinyusb/keepalive_detect/include/keepalive_detect/keepalive_detect.h new file mode 100644 index 000000000..da8dd637a --- /dev/null +++ b/hw/usb/tinyusb/keepalive_detect/include/keepalive_detect/keepalive_detect.h @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_USB_KEEPALIVE_DETECT_ +#define H_USB_KEEPALIVE_DETECT_ + +#include <stdint.h> +#include <stdbool.h> +#include <os/os.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * USB keep-alive detection callback type + * + * @param connected true when USB is connected, false when disconnected + */ +typedef void (*usb_keepalive_cb_t)(bool connected); + +/** + * USB keep-alive detection callbacks + * Platform-specific implementations must provide these functions + */ +struct usb_keepalive_cbs { + void (*handle_sof_interrupt)(void); + void (*check_suspend)(void); + void (*enable_interrupts)(void); + uint16_t (*get_frame_number)(void); +}; + +/** + * Initialize USB keep-alive detection + * + * @return 0 on success, error code on failure + */ +int usb_keepalive_init(void); + +/** + * Set event queue for keep-alive monitoring + * + * @param evq Event queue to use (NULL for default) + */ +void usb_keepalive_evq_set(struct os_eventq *evq); + +/** + * Register platform-specific callbacks + * + * @param cbs Platform-specific callback implementation + */ +void usb_keepalive_register_cbs(const struct usb_keepalive_cbs *cbs); + +/** + * Register callback for USB connection status changes + * + * @param cb Callback function + */ +void usb_keepalive_register_cb(usb_keepalive_cb_t cb); + +/** + * Check if USB is active (receiving keep-alives) + * + * @return true if USB is active, false otherwise + */ +bool usb_keepalive_is_active(void); + +/** + * Get number of SOF packets received + * + * @return SOF cnt since last disconnect + */ +uint32_t usb_keepalive_get_sof_cnt(void); + +/** + * Handle SOF interrupt (called by platform code) + */ +void usb_keepalive_handle_sof(void); + +/** + * Handle suspend event (called by platform code) + */ +void usb_keepalive_handle_suspend(void); + +/** + * Handle resume event (called by platform code) + */ +void usb_keepalive_handle_resume(void); + +#ifdef __cplusplus +} +#endif + +#endif /* H_USB_KEEPALIVE_DETECT_ */ diff --git a/hw/usb/tinyusb/da146xx/pkg.yml b/hw/usb/tinyusb/keepalive_detect/pkg.yml similarity index 79% copy from hw/usb/tinyusb/da146xx/pkg.yml copy to hw/usb/tinyusb/keepalive_detect/pkg.yml index 5e0e9c2d0..29b2d0112 100644 --- a/hw/usb/tinyusb/da146xx/pkg.yml +++ b/hw/usb/tinyusb/keepalive_detect/pkg.yml @@ -17,17 +17,21 @@ # under the License. # -pkg.name: hw/usb/tinyusb/da146xx -pkg.description: Hardware initialization for Tinyusb +pkg.name: hw/usb/tinyusb/keepalive_detect +pkg.description: USB keep-alive detection for TinyUSB pkg.author: "Apache Mynewt <[email protected]>" pkg.homepage: "http://mynewt.apache.org/" pkg.keywords: - usb + - keepalive - tinyusb -pkg.apis: - - TINYUSB_HW_INIT - pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/hw/usb/tinyusb" + - "@apache-mynewt-core/hw/hal" + +pkg.apis: + - usb_keepalive_detect + +pkg.init: + usb_keepalive_init: 'MYNEWT_VAL(USB_KEEPALIVE_SYSINIT_STAGE)' diff --git a/hw/usb/tinyusb/keepalive_detect/src/keepalive_detect.c b/hw/usb/tinyusb/keepalive_detect/src/keepalive_detect.c new file mode 100644 index 000000000..afd0e0cce --- /dev/null +++ b/hw/usb/tinyusb/keepalive_detect/src/keepalive_detect.c @@ -0,0 +1,234 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <os/mynewt.h> +#include <string.h> +#include "keepalive_detect/keepalive_detect.h" +#include "syscfg/syscfg.h" + +#if MYNEWT_VAL(USB_KEEPALIVE_DETECT) + +/* Keep-alive detection state structure */ +struct usb_keepalive_state { + uint32_t last_frame_num; + uint32_t sof_cnt; + uint32_t prev_sof_time; + bool usb_active; + uint32_t suspend_cnt; + struct os_callout monitor_callout; + uint32_t ticks; + uint32_t prev_sof_cnt; +}; + +/* Keep-alive detection variables */ +static struct usb_keepalive_state g_uks; +static struct os_mutex g_uks_mutex; +static usb_keepalive_cb_t g_usb_ka_cb; +static const struct usb_keepalive_cbs *g_keepalive_cbs; + +/* + * Monitor callout callback for periodic SOF checking + */ +static void +keepalive_monitor_cb(struct os_event *ev) +{ + uint32_t curr_sof_cnt; + uint32_t sof_diff; + + os_mutex_pend(&g_uks_mutex, OS_TIMEOUT_NEVER); + curr_sof_cnt = g_uks.sof_cnt; + os_mutex_release(&g_uks_mutex); + + /* Calculate SOF rate */ + sof_diff = curr_sof_cnt - g_uks.prev_sof_cnt; + g_uks.prev_sof_cnt = curr_sof_cnt; + + /* Check if we're receiving SOFs */ + if (sof_diff > 0) { + g_uks.ticks = 0; + + if (!usb_keepalive_is_active()) { + os_mutex_pend(&g_uks_mutex, OS_TIMEOUT_NEVER); + g_uks.usb_active = true; + os_mutex_release(&g_uks_mutex); + + if (g_usb_ka_cb) { + g_usb_ka_cb(true); + } + } + } else { + g_uks.ticks += MYNEWT_VAL(USB_KEEPALIVE_MONITOR_RATE_MS); + + if (g_uks.ticks >= MYNEWT_VAL(USB_KEEPALIVE_TIMEOUT_MS)) { + if (usb_keepalive_is_active()) { + os_mutex_pend(&g_uks_mutex, OS_TIMEOUT_NEVER); + g_uks.usb_active = false; + os_mutex_release(&g_uks_mutex); + + if (g_usb_ka_cb) { + g_usb_ka_cb(false); + } + } + g_uks.ticks = 0; + } + } + + /* Reset callout */ + os_callout_reset(&g_uks.monitor_callout, + os_time_ms_to_ticks32(MYNEWT_VAL(USB_KEEPALIVE_MONITOR_RATE_MS))); +} + +int +usb_keepalive_init(void) +{ + int rc; + + /* Initialize mutex */ + rc = os_mutex_init(&g_uks_mutex); + if (rc != 0) { + return rc; + } + + /* Initialize state */ + memset(&g_uks, 0, sizeof(g_uks)); + + /* Initialize callout */ + os_callout_init(&g_uks.monitor_callout, os_eventq_dflt_get(), + keepalive_monitor_cb, NULL); + + /* Enable platform-specific interrupts if callbacks are registered */ + if (g_keepalive_cbs && g_keepalive_cbs->enable_interrupts) { + g_keepalive_cbs->enable_interrupts(); + } + + /* Start monitoring */ + os_callout_reset(&g_uks.monitor_callout, + os_time_ms_to_ticks32(MYNEWT_VAL(USB_KEEPALIVE_MONITOR_RATE_MS))); + + return 0; +} + +void +usb_keepalive_evq_set(struct os_eventq *evq) +{ + if (evq == NULL) { + evq = os_eventq_dflt_get(); + } + + os_callout_init(&g_uks.monitor_callout, evq, + keepalive_monitor_cb, NULL); +} + +void +usb_keepalive_register_cbs(const struct usb_keepalive_cbs *cbs) +{ + g_keepalive_cbs = cbs; +} + +void +usb_keepalive_register_cb(usb_keepalive_cb_t cb) +{ + g_usb_ka_cb = cb; +} + +bool +usb_keepalive_is_active(void) +{ + bool active; + + os_mutex_pend(&g_uks_mutex, OS_TIMEOUT_NEVER); + active = g_uks.usb_active; + os_mutex_release(&g_uks_mutex); + + return active; +} + +uint32_t +usb_keepalive_get_sof_cnt(void) +{ + uint32_t cnt; + + os_mutex_pend(&g_uks_mutex, OS_TIMEOUT_NEVER); + cnt = g_uks.sof_cnt; + os_mutex_release(&g_uks_mutex); + + return cnt; +} + +void +usb_keepalive_handle_sof(void) +{ + uint16_t current_frame; + + if (g_keepalive_cbs && g_keepalive_cbs->get_frame_number) { + current_frame = g_keepalive_cbs->get_frame_number(); + + os_mutex_pend(&g_uks_mutex, OS_TIMEOUT_NEVER); + + /* Check if frame number changed (valid SOF) */ + if (current_frame != g_uks.last_frame_num) { + g_uks.last_frame_num = current_frame; + g_uks.sof_cnt++; + g_uks.prev_sof_time = os_cputime_get32(); + + /* USB is active if we're receiving SOFs */ + if (!g_uks.usb_active) { + g_uks.usb_active = true; + if (g_usb_ka_cb) { + g_usb_ka_cb(true); + } + } + + /* Reset suspend cnter */ + g_uks.suspend_cnt = 0; + } + + os_mutex_release(&g_uks_mutex); + } +} + +void +usb_keepalive_handle_suspend(void) +{ + os_mutex_pend(&g_uks_mutex, OS_TIMEOUT_NEVER); + + g_uks.suspend_cnt++; + + if (g_uks.usb_active && + g_uks.suspend_cnt > MYNEWT_VAL(USB_KEEPALIVE_SUSPEND_COUNT)) { + /* USB disconnected (no keep-alives) */ + g_uks.usb_active = false; + g_uks.sof_cnt = 0; + if (g_usb_ka_cb) { + g_usb_ka_cb(false); + } + } + + os_mutex_release(&g_uks_mutex); +} + +void +usb_keepalive_handle_resume(void) +{ + os_mutex_pend(&g_uks_mutex, OS_TIMEOUT_NEVER); + g_uks.suspend_cnt = 0; + os_mutex_release(&g_uks_mutex); +} + +#endif /* MYNEWT_VAL(USB_KEEPALIVE_DETECT) */ diff --git a/hw/usb/tinyusb/da146xx/pkg.yml b/hw/usb/tinyusb/keepalive_detect/syscfg.yml similarity index 55% copy from hw/usb/tinyusb/da146xx/pkg.yml copy to hw/usb/tinyusb/keepalive_detect/syscfg.yml index 5e0e9c2d0..29608865f 100644 --- a/hw/usb/tinyusb/da146xx/pkg.yml +++ b/hw/usb/tinyusb/keepalive_detect/syscfg.yml @@ -17,17 +17,23 @@ # under the License. # -pkg.name: hw/usb/tinyusb/da146xx -pkg.description: Hardware initialization for Tinyusb -pkg.author: "Apache Mynewt <[email protected]>" -pkg.homepage: "http://mynewt.apache.org/" -pkg.keywords: - - usb - - tinyusb +syscfg.defs: + USB_KEEPALIVE_MONITOR_RATE_MS: + description: 'Keep-alive monitor check rate in milliseconds' + value: 5 -pkg.apis: - - TINYUSB_HW_INIT + USB_KEEPALIVE_TIMEOUT_MS: + description: 'Timeout for USB disconnection detection in milliseconds' + value: 10 -pkg.deps: - - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/hw/usb/tinyusb" + USB_KEEPALIVE_SUSPEND_COUNT: + description: 'Number of suspend events before declaring USB disconnected' + value: 2 + + USB_KEEPALIVE_SYSINIT_STAGE: + description: 'Sysinit stage for USB keep-alive detection' + value: 500 + + USB_KEEPALIVE_EVQ: + description: 'Event queue for keep-alive monitoring (NULL for default)' + value: "" diff --git a/hw/usb/tinyusb/syscfg.yml b/hw/usb/tinyusb/syscfg.yml index 9ccd8c5d6..12cf678f3 100644 --- a/hw/usb/tinyusb/syscfg.yml +++ b/hw/usb/tinyusb/syscfg.yml @@ -60,3 +60,7 @@ syscfg.defs: choices: - USB0 - USB1 + + USB_KEEPALIVE_DETECT: + description: 'Enable USB keep-alive detection' + value: 0
