mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-10-01 08:27:30 +08:00
[cherryusb][fsdev] add N32H4x USBFS device support #11764
This commit is contained in:
@@ -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 */
|
||||
Reference in New Issue
Block a user