针对CYPRESS™ CX3 (FX3)辅助引导加载程序(SBL)导致USB 3.0枚举失败的问题,以下是逐步解决方案:
1. 检查内存配置和资源释放
- 确保SBL释放所有硬件资源:在跳转到应用程序前,调用
CyU3PDeviceStop()停止外设,并使用CyU3PMemoriesRelease()释放DMA缓冲区。
- 验证内存布局:检查链接脚本(
.ld文件),确认SBL和应用程序的RAM使用区域无重叠,尤其是USB相关缓冲区。
// 在SBL跳转前添加资源释放代码
CyU3PDeviceStop(); // 停止设备
CyU3PMemoriesRelease(); // 释放内存和DMA通道
2. 复位外设和时钟
- 复位USB控制器:在跳转前调用
CyU3PDeviceDeInit(),确保USB控制器处于初始状态。
- 避免时钟冲突:SBL中若修改了时钟配置,应在跳转前恢复默认设置或由应用程序显式重新配置。
CyU3PDeviceDeInit(); // 复位外设和时钟
3. 中断处理
- 禁用全局中断:在跳转前禁用中断,避免残留中断影响应用程序。
- 验证应用程序的中断向量表(IVT):确保应用程序的IVT正确加载到RAM起始位置。
// 在SBL跳转前禁用中断
CyU3PIntrDisable(); // 关闭所有中断
4. 添加延时或同步机制
- 在USB初始化前插入延时:若SPI Flash加载后硬件需要稳定时间,可在应用程序的USB初始化代码前添加
CyU3PBusyWait(1000);(1ms)。
- 轮询关键状态寄存器:检查USB PHY是否就绪,例如等待
CY_U3P_USB_PHY_READY标志。
5. 调试应用程序的启动流程
- 检查堆栈和全局变量初始化:确保应用程序的启动代码(如
Reset_Handler)正确初始化堆栈和BSS段。
- 验证应用程序入口点:确认SBL正确跳转到应用程序的入口地址(通常为
0x40000000)。
6. 使用调试工具定位问题
- GPIO调试:在关键步骤(如USB初始化)前后切换GPIO引脚,用示波器观察时序。
- JTAG调试:连接调试器,单步执行应用程序的USB初始化代码,检查寄存器状态(如
CY_U3P_USB_CONTROLLER_ID)是否正确。
7. 修复应用程序的USB初始化顺序
- 显式重新初始化USB:即使SBL已初始化USB,应用程序仍需完整执行USB配置流程,包括描述符提交和连接使能。
// 应用程序中的USB初始化示例
CyU3PUsbStart(); // 启动USB模块
CyU3PUsbSetDesc(usbDescriptors); // 设置描述符
CyU3PUsbRegisterSetupCallback(handleUsbSetup, TRUE); // 注册回调
CyU3PUsbRegisterLpmRequestCallback(handleLpmRequest); // 低功耗回调
CyU3PUsbRegisterVendorExtension(handleVendorCmd); // 扩展命令
CyU3PUsbConnect(TRUE); // 连接USB
8. 检查SPI Flash加载的正确性
- 验证固件完整性:确保从SPI Flash读取的应用程序固件未被损坏,可计算CRC并与原始文件对比。
- 调整SPI时钟速度:过高的SPI时钟可能导致读取错误,尝试降低SPI速率(如从33MHz降至10MHz)。
9. 参考官方示例调整代码
- 对比
spi_test.c中的跳转代码,确保流程一致:
// 正确跳转到应用程序的流程
void JumpToApp() {
typedef void (*EntryPoint)(void);
EntryPoint appEntry = (EntryPoint)(0x40000000);
// 关闭中断,复位外设
CyU3PIntrDisable();
CyU3PDeviceDeInit();
// 设置堆栈指针(根据应用程序的向量表)
__set_MSP(*(uint32_t*)0x40000000);
appEntry(); // 跳转到应用程序
}
总结
问题通常源于SBL未完全清理硬件状态或应用程序未能正确重新初始化。重点检查内存冲突、外设复位、中断清理、时钟配置,并通过调试工具验证硬件状态。若添加打印后问题消失,可尝试在关键步骤(如USB连接前)插入短延时,或优化初始化顺序确保硬件就绪。
针对CYPRESS™ CX3 (FX3)辅助引导加载程序(SBL)导致USB 3.0枚举失败的问题,以下是逐步解决方案:
1. 检查内存配置和资源释放
- 确保SBL释放所有硬件资源:在跳转到应用程序前,调用
CyU3PDeviceStop()停止外设,并使用CyU3PMemoriesRelease()释放DMA缓冲区。
- 验证内存布局:检查链接脚本(
.ld文件),确认SBL和应用程序的RAM使用区域无重叠,尤其是USB相关缓冲区。
// 在SBL跳转前添加资源释放代码
CyU3PDeviceStop(); // 停止设备
CyU3PMemoriesRelease(); // 释放内存和DMA通道
2. 复位外设和时钟
- 复位USB控制器:在跳转前调用
CyU3PDeviceDeInit(),确保USB控制器处于初始状态。
- 避免时钟冲突:SBL中若修改了时钟配置,应在跳转前恢复默认设置或由应用程序显式重新配置。
CyU3PDeviceDeInit(); // 复位外设和时钟
3. 中断处理
- 禁用全局中断:在跳转前禁用中断,避免残留中断影响应用程序。
- 验证应用程序的中断向量表(IVT):确保应用程序的IVT正确加载到RAM起始位置。
// 在SBL跳转前禁用中断
CyU3PIntrDisable(); // 关闭所有中断
4. 添加延时或同步机制
- 在USB初始化前插入延时:若SPI Flash加载后硬件需要稳定时间,可在应用程序的USB初始化代码前添加
CyU3PBusyWait(1000);(1ms)。
- 轮询关键状态寄存器:检查USB PHY是否就绪,例如等待
CY_U3P_USB_PHY_READY标志。
5. 调试应用程序的启动流程
- 检查堆栈和全局变量初始化:确保应用程序的启动代码(如
Reset_Handler)正确初始化堆栈和BSS段。
- 验证应用程序入口点:确认SBL正确跳转到应用程序的入口地址(通常为
0x40000000)。
6. 使用调试工具定位问题
- GPIO调试:在关键步骤(如USB初始化)前后切换GPIO引脚,用示波器观察时序。
- JTAG调试:连接调试器,单步执行应用程序的USB初始化代码,检查寄存器状态(如
CY_U3P_USB_CONTROLLER_ID)是否正确。
7. 修复应用程序的USB初始化顺序
- 显式重新初始化USB:即使SBL已初始化USB,应用程序仍需完整执行USB配置流程,包括描述符提交和连接使能。
// 应用程序中的USB初始化示例
CyU3PUsbStart(); // 启动USB模块
CyU3PUsbSetDesc(usbDescriptors); // 设置描述符
CyU3PUsbRegisterSetupCallback(handleUsbSetup, TRUE); // 注册回调
CyU3PUsbRegisterLpmRequestCallback(handleLpmRequest); // 低功耗回调
CyU3PUsbRegisterVendorExtension(handleVendorCmd); // 扩展命令
CyU3PUsbConnect(TRUE); // 连接USB
8. 检查SPI Flash加载的正确性
- 验证固件完整性:确保从SPI Flash读取的应用程序固件未被损坏,可计算CRC并与原始文件对比。
- 调整SPI时钟速度:过高的SPI时钟可能导致读取错误,尝试降低SPI速率(如从33MHz降至10MHz)。
9. 参考官方示例调整代码
- 对比
spi_test.c中的跳转代码,确保流程一致:
// 正确跳转到应用程序的流程
void JumpToApp() {
typedef void (*EntryPoint)(void);
EntryPoint appEntry = (EntryPoint)(0x40000000);
// 关闭中断,复位外设
CyU3PIntrDisable();
CyU3PDeviceDeInit();
// 设置堆栈指针(根据应用程序的向量表)
__set_MSP(*(uint32_t*)0x40000000);
appEntry(); // 跳转到应用程序
}
总结
问题通常源于SBL未完全清理硬件状态或应用程序未能正确重新初始化。重点检查内存冲突、外设复位、中断清理、时钟配置,并通过调试工具验证硬件状态。若添加打印后问题消失,可尝试在关键步骤(如USB连接前)插入短延时,或优化初始化顺序确保硬件就绪。
举报