在STM32H7上使用HAL库控制外置USB HS PHY(如USB3300或CH132)进入低功耗状态(保持链接以支持PC唤醒),需通过ULPI接口操作PHY寄存器。以下是完整的实现步骤和示例代码:
核心步骤
- 配置ULPI接口:确保STM32H7的USB_OTG_HS控制器已正确初始化和ULPI接口使能。
- 操作PHY寄存器:通过ULPI接口写PHY寄存器,启用低功耗模式(如Suspend模式)。
- 唤醒配置:使能唤醒中断,确保PHY能检测到PC唤醒信号。
- 中断处理:在USB唤醒中断中恢复PHY状态。
代码实现
1. 初始化USB和PHY(关键配置)
#include "stm32h7xx_hal.h"
#include "usbh.h" // 根据你的驱动选择
void MX_USB_OTG_HS_PHY_Init(void) {
USB_OTG_GlobalTypeDef *USBx = USB_OTG_HS;
// 使能ULPI时钟和PHY
USBx->GCCFG |= USB_OTG_GCCFG_PHYHSEN; // 使能外部HS PHY
USBx->GUSBCFG |= USB_OTG_GUSBCFG_ULPIEVBUSD; // 禁用VBUS监控(低功耗要求)
HAL_Delay(10);
}
2. 进入低功耗模式(Suspend)
void Enter_USB_HS_PHY_LowPower(void) {
// 步骤1: 通过ULPI写PHY寄存器(以USB3300为例)
uint8_t func_ctrl_reg = 0x04; // 功能控制寄存器地址
uint8_t suspend_cmd = 0x10; // 设置bit4 (SUSPENDM) = 1
// 写入ULPI寄存器(见下文ULPI写函数实现)
USB_ULPI_Write(func_ctrl_reg, suspend_cmd);
// 步骤2: 配置STM32唤醒检测
USB_OTG_GlobalTypeDef *USBx = USB_OTG_HS;
USBx->GINTMSK |= USB_OTG_GINTMSK_WUIM; // 使能唤醒中断
USBx->GLPMCFG |= USB_OTG_GLPMCFG_LPMEN; // 使能LPM支持(可选)
}
3. ULPI寄存器写入函数
void USB_ULPI_Write(uint8_t reg_addr, uint8_t data) {
USB_OTG_GlobalTypeDef *USBx = USB_OTG_HS;
// 等待ULPI接口就绪
while ((USBx->GOTGINT & USB_OTG_GOTGINT_ULPIInt) == 0);
// 配置ULPI Viewport(寄存器访问模式)
USBx->GOTGCTL |= USB_OTG_GOTGCTL_ULPIVM; // 启用Viewport
USBx->GOTGCTL |= USB_OTG_GOTGCTL_ULPICSM; // 命令启动模式
// 组合地址和数据(ULPI格式:Read/Write# + Address + Data)
uint32_t ulpi_cmd = (0 << 7) | (reg_addr << 2) | data; // bit7=0表示写操作
USBx->GOTGCTL = (USBx->GOTGCTL & ~0xFFFF) | ulpi_cmd;
// 触发传输并等待完成
USBx->GOTGCTL |= USB_OTG_GOTGCTL_ULPIEEN; // 启用传输
while ((USBx->GOTGINT & USB_OTG_GOTGINT_ULPIInt) == 0);
USBx->GOTGINT = USB_OTG_GOTGINT_ULPIInt; // 清除中断标志
// 关闭Viewport
USBx->GOTGCTL &= ~(USB_OTG_GOTGCTL_ULPIVM | USB_OTG_GOTGCTL_ULPICSM);
}
4. 唤醒中断处理
在USB中断服务例程(如OTG_HS_IRQHandler)中检测唤醒事件:
void OTG_HS_IRQHandler(void) {
USB_OTG_GlobalTypeDef *USBx = USB_OTG_HS;
if (USBx->GINTSTS & USB_OTG_GINTSTS_WKUINT) {
// 步骤1: 清除唤醒中断标志
USBx->GINTSTS = USB_OTG_GINTSTS_WKUINT;
// 步骤2: 退出PHY低功耗模式
uint8_t func_ctrl_reg = 0x04;
uint8_t resume_cmd = 0x00; // SUSPENDM=0
USB_ULPI_Write(func_ctrl_reg, resume_cmd);
// 步骤3: 恢复USB时钟(如果之前关闭)
__HAL_RCC_USB_OTG_HS_ULPI_CLK_ENABLE();
// 步骤4: 通知应用层唤醒事件
USB_Wakeup_Callback();
}
HAL_PCD_IRQHandler(&hpcd_USB_OTG_HS); // 继续处理其他中断
}
// 用户自定义唤醒回调
__weak void USB_Wakeup_Callback(void) {
// 添加应用层唤醒处理代码
}
关键配置说明
PHY寄存器设置:
- USB3300:写寄存器
0x04(功能控制),设置SUSPENDM=1进入挂起模式。
- CH132:参考其数据手册,通常类似(如寄存器
0x01的SUSPEND位)。
STM32H7唤醒机制:
- 使能
USB_OTG_GINTMSK_WUIM中断(唤醒中断掩码)。
- PHY检测到PC唤醒信号(恢复信号)后,触发
USB_OTG_GINTSTS_WKUINT中断。
低功耗硬件设计:
- 确保PHY的
VBUS监控已禁用(避免漏电)。
- 如果使用Stop模式,需保留USB时钟源(如HSE)。
注意事项
- PHY兼容性:不同PHY的寄存器地址可能不同,需查阅数据手册(如USB3300 DS00001692B, CH132 DS000757)。
- 时钟管理:
- 进入低功耗前,勿关闭ULPI时钟(
USBPHYC或HSE)。
- 唤醒后检查时钟是否恢复。
- 中断优先级:确保USB中断优先级足够高(避免唤醒延迟)。
- 连接状态保持:在Suspend模式下,PHY自动维持USB连接。
通过以上步骤,USB HS PHY将在保持链接的状态下进入低功耗,PC可通过发送USB唤醒信号恢复设备。