stem32F407 USB data toggle error的分析和解决

因工作需要从某个设备上读取USB数据。该设备有windows驱动和应用软件,需要用stm32F407做一个读取和转发设备。

首先用BusHound在Windows上分析了该设备的USB数据。设备USB类为特殊的0XFF,EndPoint有两个,一个IN一个OUT Endpoint均是Bulk。主机OUT大约10几个字节的命令,设备会回应一帧(Frame)或多帧。每帧有一个或多个包(Packet)组成。

因为之前没有做过USB程序,所以使用了例程"USB鼠标键盘(Host)实验"的代码进行改造。正确匹配了USB的厂家和USB Class信息后,STM32F407可以和设备进行数据传输,主机OUT的数据设备能收到,设备也能正确回应数据,STM32F407 HOST也能收到设备数据。然而不知道为什么有时应会出现丢包现象。以为是硬件问题,换了不同型号固障依旧,那没办法需要深入进行分析。

为了分析需要将STM32F407 USB OTG 相关的寄存器通过串打印出来,碰到串口速度慢USB HOST不能完成设备枚举,又开了一块内存将打印放在内存中,在main循环中发串口。实在很郁闷。终于将寄存器打印出来了。
结果发现channel中断错误data toggle error。在网上查很少有资料提及这个错误。

深入学习分析后结果:
主机IN BULK(本文仅指BULK类型的传输)数据过程是这样的:
在寄存器HCTSIZ中设置PID。 全速设备PID为DATA0或DATA1,这个值必须和设备发来的数据包PID一样,如果不一样就会出data toggle error。一个IN Bulk通道中设备PID会重复DATA0、DATA1。

当设备发来数据时,会触发中断,GINTSTS中RXFLVL: RxFIFO non-empty
寄存器GRXSTSP中PKTSTS状态为IN data packet received, GRXSTSP中的DPID为设备发来数据包的PID。同时HCTSIZ中PID为DPID的下一个值,应该是硬件自动设置的,即
HCTSIZ.PID = next GRXSTSP.DPID

如果一帧中有多个数据包,那么DPID就反复DATA0 DATA1 DATA0 DATA1…循环,至此工作正常。

但是在一帧(Frame)结束时,会产生另一个中断,寄存器GRXSTSP中PKTSTS状态为IN transfer completed。
在程序usb_hcd_int.c中,函数USB_OTG_USBH_handle_hc_n_In_ISR,
else if (hcint.b.xfercompl)
{

if ((hcchar.b.eptype == EP_TYPE_CTRL)||
(hcchar.b.eptype == EP_TYPE_BULK)){
pdev->host.hc[num].toggle_in ^= 1;
}

关键就在这里pdev->host.hc[num].toggle_in ^= 1;将toggle_in翻转了一次。

在下一次接收时,在usb_ioreq.c中,USBH_BulkReceiveData函数中,
if( pdev->host.hc[hc_num].toggle_in == 0)
{
pdev->host.hc[hc_num].data_pid = HC_PID_DATA0;
}
else
{
pdev->host.hc[hc_num].data_pid = HC_PID_DATA1;
}

根据host channle的toggle_in设置了data_pid。
在usb_core.c中,USB_OTG_HC_StartXfer函数,
hctsiz.b.pid = pdev->host.hc[hc_num].data_pid;
USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCTSIZ, hctsiz.d32);

简单说,就是根据channel变量中的toggle_in设置了HCTSIZ.PID。 而HCTSIZ.PID设置错了就会出data toggle error;

pdev->host.hc[num].toggle_in只有在一帧结束时才设置一次翻转,那么如果一帧有奇数个数据包,那么就是碰巧正确的。如果一帧有偶数个数据包,pdev->host.hc[num].toggle_in值就是错误的。这就是为什么有时对,有时不对。 同一个设备命令,先发送后发送有时对有时出toggle error。

终于找到问题,那么就好解决了:既然HOST IN Channel,BULK模式下,HCTSIZ.PID本来就是对的,
犯不着画蛇添足写入,于是修改usb_core.c,USB_OTG_HC_StartXfer函数:
读现在的值
oldhctsiz.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[hc_num]->HCTSIZ);
if(pdev->host.hc[hc_num].ep_is_in && pdev->host.hc[hc_num].ep_type == 2){
//如果是IN Bulk,就用现在寄存器中的PID
hctsiz.b.pid = oldhctsiz.b.pid;
}else{
//其它情况仍使用host.hc中的data_pid
hctsiz.b.pid = pdev->host.hc[hc_num].data_pid;
}
//写入
USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[hc_num]->HCTSIZ, hctsiz.d32);

到此程序正常了。总结根本原因原来程序没有考虑到一个帧Frame有多个包Packet的情况。

### 将YOLOv5模型部署到STM32F407微控制器上的过程 #### 准备工作 为了能够顺利地将YOLOv5模型部署至STM32F407,需先完成一系列准备工作。这包括但不限于获取适合嵌入式设备运行的小型化版本YOLOv5模型以及准备开发工具链。 - **选择合适的YOLOv5变体**:考虑到资源受限的硬件条件,建议选用较小规模的YOLOv5s作为基础模型[^1]。 - **安装必要的软件包**:确保已安装Python及其相关库(如PyTorch)、CMake、GCC编译器等用于构建转换模型所需的依赖项。 #### 模型优化与转换 由于原始的YOLOv5是由PyTorch框架实现并训练得到的,因此需要对其进行特定处理以便能够在ARM Cortex-M架构上高效执行: - 使用ONNX简化模型表示形式,并通过量化技术减少参数量级从而适应低功耗平台的需求; - 利用TensorFlow Lite Micro或CMSIS-NN这样的轻量化推理引擎来加载经由上述步骤转化后的二进制文件[^3]; ```bash pip install onnx==1.8.1 tf-nightly tflite-support python -m pip install git+https://github.com/tensorflow/models.git@master#egg=models[tensorrt]&subdirectory=research ``` #### 配置项目工程 创建一个新的Keil MDK工程项目或者利用CubeMX初始化设置好外设接口之后,按照如下方式集成机器学习组件: - 添加来自官方仓库或者其他开源项目的预编译静态链接库至源码目录内; - 修改`main.c`入口函数以调用预测API并对结果做进一步解析展示给用户界面。 ```c #include "tensorflow/lite/micro/all_ops_resolver.h" #include "tensorflow/lite/micro/kernels/activations.h" // 初始化全局变量... static const tflite::MicroOpResolver<6> micro_op_resolver; tflite::MicroInterpreter interpreter(model, micro_op_resolver); if (interpreter.AllocateTensors() != kTfLiteOk){ while(true); } while(1){ // 获取图像帧数据... TfLiteStatus invoke_status = interpreter.Invoke(); } ``` #### 测试验证 最后一步是在实际环境中测试整个系统的功能表现,确认其能否稳定识别目标物体的同时也要关注性能指标是否满足预期要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值