[cherryusb][fsdev] add N32H4x USBFS device support #11764

This commit is contained in:
Onlyou_tzZ
2026-09-21 15:43:37 +08:00
committed by GitHub
parent 3eff2d5c7e
commit 0edbc15ea9
6 changed files with 619 additions and 4 deletions
+2
View File
@@ -28,6 +28,8 @@ if RT_USING_CHERRYUSB
bool "CUSTOM (Implement it yourself)"
config RT_CHERRYUSB_DEVICE_FSDEV_ST
bool "fsdev_st"
config RT_CHERRYUSB_DEVICE_FSDEV_NATION
bool "fsdev_nation"
config RT_CHERRYUSB_DEVICE_FSDEV_CUSTOM
bool "fsdev_custom"
config RT_CHERRYUSB_DEVICE_DWC2_ST
@@ -37,6 +37,9 @@ if GetDepend(['RT_CHERRYUSB_DEVICE']):
if GetDepend(['RT_CHERRYUSB_DEVICE_FSDEV_ST']):
src += Glob('port/fsdev/usb_dc_fsdev.c')
src += Glob('port/fsdev/usb_glue_st.c')
if GetDepend(['RT_CHERRYUSB_DEVICE_FSDEV_NATION']):
src += Glob('port/fsdev/usb_dc_fsdev.c')
src += Glob('port/fsdev/usb_glue_nation.c')
if GetDepend(['RT_CHERRYUSB_DEVICE_FSDEV_CUSTOM']):
src += Glob('port/fsdev/usb_dc_fsdev.c')
if GetDepend(['RT_CHERRYUSB_DEVICE_DWC2_ST']):
@@ -28,3 +28,11 @@
## CH32
- CH32F10x、CH32V10x
## N32
- N32H473、N32H474、N32H475、N32H481、N32H482、N32H480、N32H487、N32H488
- N32H49X
@@ -5,7 +5,7 @@
*/
#include "usbd_core.h"
#if (CONFIG_USB_DBG_LEVEL >= USB_DBG_LOG)
#if defined(CONFIG_USB_DBG_LEVEL) && defined(USB_DBG_LOG) && (CONFIG_USB_DBG_LEVEL >= USB_DBG_LOG)
#error "fsdev cannot enable USB_DBG_LOG"
#endif
@@ -60,10 +60,30 @@ __WEAK void usb_dc_low_level_deinit(void)
{
}
/**
* @brief Initialize the USB device controller.
* @param busid USB bus index (fsdev supports a single instance, bus 0).
* @retval 0 on success.
*/
int usb_dc_init(uint8_t busid)
{
usb_dc_low_level_init();
#if defined(N32H4X_FSDEV)
/* N32H4x power-on sequence: the USB_CTRL reset value is 0x0300
* -- PD(bit9, power-down) and FRST(bit8, force-reset) are both set.
* 1. Clear PD, wait for the internal analog voltage reference to settle.
* 2. Clear FRST.
* 3. Clear the STS register to drop pending interrupts. */
USB->CNTR &= (uint32_t)~USB_CNTR_PDWN; /* exit power-down */
/* Wait for the internal reference voltage to stabilise. */
for (volatile uint32_t i = 0U; i < 1000U; i++) {
}
USB->CNTR &= (uint32_t)~USB_CNTR_FRES; /* clear force-reset flag */
USB->ISTR = 0U; /* clear pending interrupts */
#else
/* Init Device */
/* CNTR_FRES = 1 */
USB->CNTR = (uint16_t)USB_CNTR_FRES;
@@ -73,6 +93,7 @@ int usb_dc_init(uint8_t busid)
/* Clear pending interrupts */
USB->ISTR = 0U;
#endif
/*Set Btable Address*/
USB->BTABLE = BTABLE_ADDRESS;
@@ -91,8 +112,13 @@ int usb_dc_init(uint8_t busid)
/* Set interrupt mask */
USB->CNTR = (uint16_t)winterruptmask;
#if defined(N32H4X_FSDEV)
/* Enabling DP Pull-UP through USB_CTRL.PU */
USB->CNTR |= (uint32_t)USB_CNTR_PU;
#else
/* Enabling DP Pull-UP bit to Connect internal PU resistor on USB DP line */
USB->BCDR |= (uint16_t)USB_BCDR_DPPU;
#endif
return 0;
}
@@ -325,6 +351,10 @@ int usbd_ep_start_read(uint8_t busid, const uint8_t ep, uint8_t *data, uint32_t
return 0;
}
/**
* @brief USB FS device interrupt handler: dispatches ISTR events.
* @param busid USB bus index (fsdev supports a single instance, bus 0).
*/
void USBD_IRQHandler(uint8_t busid)
{
uint16_t wIstr, wEPVal;
@@ -339,7 +369,13 @@ void USBD_IRQHandler(uint8_t busid)
wIstr = USB->ISTR;
/* extract highest priority endpoint number */
#if defined(N32H4X_FSDEV)
/* EP_ID is at STS bits [11:8] */
ep_idx = (uint8_t)((wIstr & USB_ISTR_EP_ID) >> USB_ISTR_EP_ID_Pos);
#else
/* ST: EP_ID is at ISTR bits [3:0] */
ep_idx = (uint8_t)(wIstr & USB_ISTR_EP_ID);
#endif
if (ep_idx == 0U) {
if ((wIstr & USB_ISTR_DIR) == 0U) {
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,191 @@
/*
* Copyright (c) 2025, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "usbd_core.h"
/* N32H4x family detection (N32H47x_48x + N32H49x): same part-macro list as
* the SDKs (n32h47x_48x.h typedef enum IRQn, n32h49x.h) and as
* usb_fsdev_reg.h. Defined here locally so this file never needs to include
* usb_fsdev_reg.h next to the SDK headers (which would re-define e.g.
* USB_EP_SETUP). */
#if defined(N32H473) || defined(N32H474) || defined(N32H475) || \
defined(N32H481) || defined(N32H482) || defined(N32H480) || \
defined(N32H487) || defined(N32H488) || defined(N32H49X)
#define N32H4X_FSDEV 1
#endif
#if defined(N32H4X_FSDEV)
#if defined(N32H473) || defined(N32H474) || defined(N32H475) || \
defined(N32H481) || defined(N32H482) || defined(N32H480) || \
defined(N32H487) || defined(N32H488)
#include "n32h47x_48x_rcc.h"
#include "n32h47x_48x_gpio.h"
#include "misc.h"
#define USBFS_REG_BASE 0x40004800UL
#define USBFS_SRAM_BASE 0x40004C00UL
#define USBFS_APB1_CLK RCC_APB1_PERIPH_USBFS
#elif defined(N32H49X)
#include "n32h49x_rcc.h"
#include "n32h49x_gpio.h"
#include "misc.h"
#define USBFS_REG_BASE 0x40004800UL
#define USBFS_SRAM_BASE 0x40004C00UL
#define USBFS_APB1_CLK RCC_APB1_PERIPHEN_USBFS
#else
#error "unsupported N32H4x part: define a N32H47x_48x part macro (N32H473/474/475/481/482/480/487/488) or N32H49X"
#endif /* N32H473..N32H488 (48x SDK) / N32H49X (49x SDK) */
/*
* N32H4x (N32H47x_48x / N32H49x) USB Full-Speed Device (USB_FS_Device).
*
* The USBFS core is the same Synopsys USBFS as STM32, but Nations re-arranged
* every register/bit field. The re-map lives in usb_fsdev_reg.h; this file
* only does the chip-level bring-up (clock, GPIO, NVIC, interrupt dispatch)
* and mirrors the Nations USBFSD examples (HID_CDC_Composite): hw_config.c
* (USBFS_IO_Configure / Set_USBClock / USB_Config) and n32h47x_48x_it.c /
* n32h49x_it.c (USB_FS_LP_IRQHandler).
*
* USBFS:
* - register base : 0x40004800 (USB_BASE)
* - packet buffer : 0x40004C00 (USB_SRAM_BASE, 512 bytes)
* - APB1 peripheral; USBFS needs a precise 48 MHz USB clock derived from
* PLLCLK (48/96/144/192/240 MHz -> DIV1/2/3/4/5).
* - IRQ : USB_FS_LP_IRQn (20, low priority, used here) ; USB_FS_HP_IRQn
* (19, high priority, iso/double-buffer only)
*/
/**
* @brief Configure the USBFS 48 MHz clock from the actual PLLCLK.
*
* The prescaler source is derived from SystemCoreClock at runtime, so the
* divider always matches the frequency the board is actually running at
* (no per-part compile-time table to keep in sync with the PLL setup).
* Supported PLLCLK values: 48/96/144/192/240 MHz -> DIV1/2/3/4/5.
* Unsupported frequencies leave the prescaler untouched and must be fixed
* in the board clock configuration (48 MHz USB clock is then not guaranteed).
*/
static void Set_USBClock(void)
{
switch (SystemCoreClock) {
case 48000000: /* SYSCLK_VALUE_48MHz -> DIV1 */
RCC_ConfigUSBPLLPresClk(RCC_USBPLLCLK_SRC_PLL, RCC_USBPLLCLK_DIV1);
RCC->CFG3 &= ~RCC_CFG3_USBFSTM;
break;
case 96000000: /* SYSCLK_VALUE_96MHz -> DIV2 */
RCC_ConfigUSBPLLPresClk(RCC_USBPLLCLK_SRC_PLL, RCC_USBPLLCLK_DIV2);
RCC->CFG3 &= ~RCC_CFG3_USBFSTM;
break;
case 144000000: /* SYSCLK_VALUE_144MHz -> DIV3 */
RCC_ConfigUSBPLLPresClk(RCC_USBPLLCLK_SRC_PLL, RCC_USBPLLCLK_DIV3);
RCC->CFG3 |= RCC_CFG3_USBFSTM;
break;
case 192000000: /* SYSCLK_VALUE_192MHz -> DIV4 */
RCC_ConfigUSBPLLPresClk(RCC_USBPLLCLK_SRC_PLL, RCC_USBPLLCLK_DIV4);
RCC->CFG3 |= RCC_CFG3_USBFSTM;
break;
case 240000000: /* SYSCLK_VALUE_240MHz -> DIV5 */
RCC_ConfigUSBPLLPresClk(RCC_USBPLLCLK_SRC_PLL, RCC_USBPLLCLK_DIV5);
RCC->CFG3 |= RCC_CFG3_USBFSTM;
break;
default:
USB_LOG_ERR("Unsupported system clock %u Hz for USBFS 48 MHz clock (supported: 48/96/144/192/240 MHz)\r\n",
(unsigned int)SystemCoreClock);
break;
}
}
/**
* @brief Configure the USB DM/DP pins.
*
* Defaults to the EVAL board mapping (PA11 = DM, PA12 = DP, AF10).
* Marked __WEAK so the board layer can override it for other pin maps.
*/
__WEAK void n32h4xx_usbfs_gpio_init(void)
{
RCC_EnableAHB1PeriphClk(RCC_AHB_PERIPHEN_GPIOA, ENABLE);
GPIO_InitType GPIO_InitStructure;
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_11;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.GPIO_Alternate = GPIO_AF10;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_12;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.GPIO_Alternate = GPIO_AF10;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
}
/**
* @brief Low-level USBFS initialization: clock, GPIO and interrupt channel.
*
* Signature must match the __WEAK stub in usb_dc_fsdev.c (no parameter),
* so the fsdev port always talks to bus 0.
*/
void usb_dc_low_level_init(void)
{
if (g_usbdev_bus[0].reg_base != USBFS_REG_BASE) {
return;
}
/* 1. USBFS 48 MHz clock: source select, PLL prescaler, APB1 enable. */
RCC_ConfigUSBFSClk(RCC_USBFS_CLKSRC_PLLPRES);
Set_USBClock();
RCC_EnableAPB1PeriphClk(USBFS_APB1_CLK, ENABLE);
/* 2. USB DM/DP pins (weak hook, override in the board layer). */
n32h4xx_usbfs_gpio_init();
/* 3. Low-priority USB FS interrupt (all FS device events, including the
* USB_STS.WKUP/SUSPD bits handled by usb_dc_fsdev.c). Priority-group
* selection stays with the board/application startup code. */
NVIC_InitType NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USB_FS_LP_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/**
* @brief Low-level USBFS deinitialization: disable interrupt and APB1 clock.
*/
void usb_dc_low_level_deinit(void)
{
if (g_usbdev_bus[0].reg_base != USBFS_REG_BASE) {
return;
}
NVIC_InitType NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USB_FS_LP_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
NVIC_Init(&NVIC_InitStructure);
RCC_EnableAPB1PeriphClk(USBFS_APB1_CLK, DISABLE);
}
/**
* @brief Low-priority USB FS interrupt: dispatches all FS device events.
*/
void USB_FS_LP_IRQHandler(void)
{
USBD_IRQHandler(0);
}
#endif /* N32H4X_FSDEV */