WCH USB Host CherryUSB

前面的文章我们介绍了如何为CH582芯片移植CherryUSB Device,前些天我考虑将Host也移植一下,但是那会CherryUSB还没有CH582主机的驱动,所以我们也需要自己编写主机驱动,在对比了CH58x系列和CH32系列的(USBFS OTGFS)主机寄存器后发现他们几乎没什么区别,就只有几个bit有差异,所以基本可以一同编写使用,下面我们列出wch主机ip的一些差异。

CH58x,CH57x是一个主机IP(USBFS),CH32V,CH32F是一个主机IP(USBFS和OTG_FS)。这里我们就对比CH58x和CH32V的主机寄存器差异。

1、 USBFS_UH_PRE_PID_EN,USBFS_UH_SOF_EN

 2、 USBFS_UH_R_AUTO_TOG,USBFS_UH_R_TOG,USBFS_UH_R_RES

  2、 USBFS_UH_T_AUTO_TOG,USBFS_UH_T_TOG,USBFS_UH_T_RES

好了,就上面这些简单的差异,不过我还是挺好奇的,为啥就偏偏搞几个寄存器是不一样的,对于这些差异,我的处理就是根据用户选择的芯片,把这个宏取消掉的,然后再定义一下即可,如下图,详细代码见文章末尾的仓库地址。

CherryUSB的主机协议栈是要依赖操作系统的,这里我选择沁恒已经适配好的rt-thread。下面我们就开始正式编写wch host驱动代码。代码结构参照CherryUSB port/musb/usb_hc_musb.c。

本文只介绍全速主机的移植,高速见仓库内的代码,基本是一致的。

1、usb_hc_init

看上图,黄色框是为host管道创建一些信号量,防止在不同管道之间出现访问冲突,蓝色框的部分来自于沁恒的下面这段代码:

这里我们可以看到官方没开中断,用的是查询的方式,我们将其改成中断的方式,所以在最后使能了传输完成中断和插拔中断,还有就是官方静态分配了一段内存,USBFS_RX_Buf,USBFS_TX_Buf,并将地址给到了dma地址寄存器,这样就只能每次都要将待发送的数据copy到TX数组,或者从RX数组中读取接收的数据,其实是损失了dma的性能的。其实我们可以设计成将用户的buff地址直接给到dma地址寄存器,所以在初始化函数中,我们并没有操作dma地址寄存器。

2、usbh_reset_port

这一部分参照官方给的如下代码:

在复位完成以后我们就可以使能端口了,并且开启自动发送sof包。

3、usbh_ep0_pipe_reconfigure

这一部分代码会在主机第一次获取完设备描述符后调用(根据设备描述符重新配置端点0的最大包长),也会在设置完地址以后调用(重新配置设备地址),实现如图中所示,不做过多解释。

4、usbh_pipe_alloc

这一部分跟硬件相关的东西不多,因为沁恒的主机就一组收发端点和一组收发dma,所以这一部分主要是配置一下软件虚拟的管道,存储一些管道的相关变量,供协议栈来分配。

5、usbh_get_port_speed

这一部分参照官方给的如下代码:

6、usbh_submit_urb

蓝色框中的是框架中的代码,可以参照CherryUSB的其他主机驱动,黄色框中是因为沁恒就一个主机管道,防止发生访问冲突导致失败。

上图中这一部分我们后面会说。

7、chusb_host_pipe_transfer

上图中黄色框中代码,更新全局变量current_token,记录当前事务令牌,记录当前管道current_pipe,记录current_time_out(大于0则需要nak重试),更新主管道正在使用flag,为编写中断服务函数做准备。

下面我按照SETUP,OUT,IN事务分了三个区域。

一、SETUP

二、OUT

 三、IN

8、chusb_control_pipe_init

需要注意的就是设置完自动翻转DATAPID,就不能手动设置了,需要清除自动翻转那一个bit才能手动写进去,见如下代码:

9、chusb_bulk_pipe_init

10、chusb_intr_pipe_init

可以看到其实跟bulk是一样的。

11、chusb_iso_pipe_init

12、USBH_IRQHandler

上图中黄色部分:

这是官方在移植rtos的时候做的一些东西,主要就是堆栈的切换。我们需要在中断服务函数中添加这俩函数,要不然会HardFault。

蓝色框框选的就是传输完成中断和插拔中断。

1、插拔中断

主要就是设备连接和断开的操作,然后要调用usbh_roothub_thread_wakeup来唤醒主机协议栈中的线程。

2、传输完成中断

根据当前事务令牌来分。

一、先看out的。

设备回复stall,表示发生错误,这个处理比较简单,自己去看源码就好。

1、我们先看一下设备回复主机nak的。

如果是控制端点,setup发生nak那一定是出错了,out发生nak,则需要重新发起传输。

上图已经基本注释清除了。

2、接下来看设备回复ack的。

上图是控制端点且是setup传输完成,根据ep0_state来决定下一步将发起怎样的传输。

上图是控制端点且是out数据阶段传输完成,红字已经注释的差不多了,主要就是再次启动发送与状态阶段。

上图是成功发送out包作为状态阶段的处理,复位ep0_state为setup,放下信号量并调用回调。

上图是非控制端点的out成功处理。

上图示out超时做的处理,如果不是同步端点超时都认为是出错。

到此,out处理完成。

二、接下来看in

上图就是in的处理框架。

1、我们先看nak的

是控制端点,则需要重传,(协议栈中控制端点的pipe_timeout是大于0的)。

上图的注释中,可能有点费解的就是主机获取0长度字节包收到nak的,我也有考虑这个是否可以不要,因为在控制传输中的最后一包是最大包长的时候,我们是需要设备发送0长度字节包告诉主机已经发送完成的。但是对于普通端点来说,都是主机轮询访问,大部分设备的app都不会在发送最大包长的包后面跟上一个0长度字节包,所以我写了在这种情况的nak进回调,没什么大问题,但是可能会损失一些性能。

2、正确收到数据

上图是控制写传输完成,最后以一个in作为状态阶段结束。

上图是控制读的数据阶段的处理,红字已经基本注释清楚。

上图是普通端点的in处理,收到短包或者0长度字节包则是传输完成。

到此全速主机的移植就全部结束了。

CherryUSB仓库地址:GitHub - sakumisu/CherryUSB: Tiny and portable USB Stack (device & host) for embedded system with USB IP

WCH MCU USB Demo仓库地址:GitHub - CherryUSB/cherryusb_wch: CherryUSB Demo for WCH

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值