0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于DWC2的USB驱动开发-0x0C 驱动框架设计

嵌入式USB开发 来源: 嵌入式USB开发 作者: 嵌入式USB开发 2023-06-05 17:15 次阅读

本文转自公众号,欢迎关注

基于DWC2的USB驱动开发-0x0C 驱动框架设计 (qq.com)

一. 驱动架构

1.1 前言

前面我们介绍了DWC2的控制器相关的寄存器,驱动的编写本质上就是进行寄存器的配置。为了代码的健壮性,可移植性,可调试性等我们必须设计一个比较好的架构。对于驱动编程来说输入就是各个寄存器,如果使用的都是DWC2的话甚至来说寄存器都是一样的输入就只需要寄存器基地址,即如果都是使用该IP的驱动甚至只要修改寄存器基地址,然后移植中断等一些和SOC相关的内容即可复用。

1.2 架构框图

图片

整体的设计思想如下:

借鉴面向对象的设计的依赖倒置原则:

面向接口编程,不依赖具体实现编程,应用层不直接依赖具体实现而是依赖接口,上层调用接口底层实现接口,接口是硬件隔离的桥梁.

接口即对应上图的HAL层。

硬件: 对于使用DWC2控制器的则还可以复用HW层本身的内容,只需要修改寄存器的基地址即可,因为DWC2控制器寄存器都是一样的。另外需要修改一些和SOC相关的内容,比如中断的设置。对于不同的控制器和SOC平台的则需要根据具体的平台进行封装。理论上也可以直接依赖硬件实现HAL层,而不需要HW层的封装,但是这样的话直接在HAL层操作寄存器代码的阅读性上不佳。

HW层:即对头文件中寄存器的操作进行封装,主要采用宏的方式封装,目的是为了可阅读性。同时对于一些联系紧密的操作放在一起进行封装,比如初始化等,提供比如结构体参数等,进行相应的参数配置。这一层对于使用同样的DWC2控制器的也完全可复用。

HAL层:这是硬件和上层隔离的一层,定义了一系列接口,协议栈调用该接口进行硬件操作,而HAL调用HW层实现上述的接口。对于不使用DWC2控制器的,则需要重新实现HAL层,而同使用DWC2控制器的则本层也通用。本层的设计原则是接口个数尽可能少和简单但是要足够满足协议栈层的需要。符合面向对象设计的最少知道原则。

协议栈层:依赖HAL接口,实现USB规格书规定的协议。

协议栈和HAL层以及以下的层次,尽可能不进行资源分配(比如内存)等预留相应的接口,资源分配由应用层实现,这样设计的目的是在嵌入式开发环境资源往往受限,资源的分配往往需要应用层来把控,应用层来负责。底层尽可能少的依赖资源,尽可能保持确定性,避免过多动态行为。

应用层:调用协议栈实现具体的应用功能。

考虑到通用性和可移植性,我们要支持OS和无OS的实现,所以非必要不依赖OS相关的API,如果不可避免则尽可能少依赖,且实现需要依赖的API的OS和NONE-OS版本,将依赖抽离出来作为需要移植实现的部分,使得在不同OS和裸机下都能运行,这里会涉及到协议栈基于中断驱动的处理方式和基于事件驱动的处理方式两种实现,后面到协议栈设计部分再说。

1.3 调试方案

调试手段是驱动开发中需要重点考虑的一环,没有合适的调试手段,遇到问题,会两眼一抹黑完全无从下手。进行USB开发,硬件上示波器和协议分析仪是必须的。另外软件上也需要一些手段配合调试。以下是几种常见的方式。

1.3.1 仿真器

这是嵌入式开发必须的,尤其是驱动开发阶段,需要跟踪代码流,寄存器的配置,变量的值等等。仿真器调试有个问题就是需要中断正常的程序流.USB是一个有着严格时序要求,且高速的协议,程序中断会导致USB的处理过程由于超时等导致异常,所以很多时候不能通过仿真器打断点等方式进行调试。

1.3.2 IO

USB由于其严格的时序要求,且高速的处理,很多时候我们需要测试相应的处理时间,使用定时器进行计时并打印时间是一种方法,但是对于高精度计时定时器的处理代码本身需要时间会带来误差。这时使用IO翻转,来指示某种状态的变化非常有用,比如测试SOF之间的时间,可以在SOF中断中翻转IO,使用示波器或者逻辑分析仪测量波形即可。翻转IO往往一条指令即可,这使得代码带来的误差减小。

更重要的是可以通过多个IO关联多个事件,看到多个事件之间的关联关系,尤其是使用示波器和逻辑分析仪查看时。曲线会非常直观。这是使用定时器打印所不具备的。

IO翻转的调试方法是嵌入式实时分析中重要的手段。

1.3.3 串口打印

USB的处理流程对应着状态的流转,实际对于软件来说过是各种中断的进入与退出。使用仿真器跟踪会破坏USB的处理流程导致超时等,所以需要一个非中断方式的跟踪事件的方式。常见的方式是使用串口打印,这里要注意串口打印不能使用阻塞方式,否则同样的会导致USB处理流的异常。一般采用缓冲区的方式,打印接口将数据写入缓冲区,主循环或者其他线程中将缓冲区的数据通过串口发送。

当然除了串口打印还有很多其他类似的方式比如 Jlink提供的rtt等性能更高,也可以使用网口等接口,根据具体平台而定。

串口打印可是设置为宏的方式,debug版本使能,release版本可不使能,打印输出也可以设置等级和类别,这样通过等级和类别控制输出,避免一次打印过多干扰分析,也可以使用CLI动态配置等级可列别的控制。

如下是一个简单的示例,依赖printf,假设printf已经实现是一个非阻塞的版本(即写入缓冲区),其他地方再真正的发送数据。可以通过宏配置不同等级的LOG,且打印信息对应不同的颜色。

头文件中

#define USB_HAL_DEBUG 1
#define USB_HAL_LOG_LEVEL_ERROR 1
#define USB_HAL_LOG_LEVEL_WARN 1
#define USB_HAL_LOG_LEVEL_INFO 1


/** Debug levels */
typedef enum 
{
    USB_HAL_DEBUG_ERROR = 0,
    USB_HAL_DEBUG_WARN  = 1,
    USB_HAL_DEBUG_INFO  = 2,
}USB_HAL_DEBUG_e;


#define USB_HAL_DEBUG_COLOR_MASK_COLOR  0x0F
#define USB_HAL_DEBUG_COLOR_MASK_MODIFIER   0xF0


typedef enum {
    /* Colors */
    USB_HAL_DEBUG_COLOR_RESET       = 0xF0,
    USB_HAL_DEBUG_COLOR_BLACK       = 0x01,
    USB_HAL_DEBUG_COLOR_RED     = 0x02,
    USB_HAL_DEBUG_COLOR_GREEN       = 0x03,
    USB_HAL_DEBUG_COLOR_YELLOW  = 0x04,
    USB_HAL_DEBUG_COLOR_BLUE        = 0x05,
    USB_HAL_DEBUG_COLOR_MAGENTA = 0x06,
    USB_HAL_DEBUG_COLOR_CYAN        = 0x07,
    USB_HAL_DEBUG_COLOR_WHITE       = 0x08,
    /* Modifiers */
    USB_HAL_DEBUG_COLOR_NORMAL  = 0x0F,
    USB_HAL_DEBUG_COLOR_BOLD        = 0x10,
    USB_HAL_DEBUG_COLOR_UNDERLINE   = 0x20,
    USB_HAL_DEBUG_COLOR_BLINK       = 0x30,
    USB_HAL_DEBUG_COLOR_HIDE        = 0x40,
} USB_HAL_DEBUG_COLOR_e;


void usb_hal_do_debug(USB_HAL_DEBUG_e level, const char *format, ...);


#ifdef USB_HAL_DEBUG
    #define usb_hal_debug(level, format, ...) do { usb_hal_do_debug(level, format, ##__VA_ARGS__); } while(0)
#else
    #define usb_hal_debug(...) do {} while (0)
#endif


#ifdef USB_HAL_LOG_LEVEL_ERROR
    #define usb_hal_error(format, ...) usb_hal_debug(USB_HAL_DEBUG_ERROR, format, ##__VA_ARGS__)
#else
    #define usb_hal_error(...) do {} while (0)
#endif


#ifdef USB_HAL_LOG_LEVEL_WARN
    #define usb_hal_warn(format, ...) usb_hal_debug(USB_HAL_DEBUG_WARN, format, ##__VA_ARGS__)
#else
    #define usb_hal_warn(...) do {} while (0)
#endif


#ifdef USB_HAL_LOG_LEVEL_INFO
    #define usb_hal_info(format, ...) usb_hal_debug(USB_HAL_DEBUG_INFO, format, ##__VA_ARGS__)
#else
    #define usb_hal_info(...) do {} while (0)
#endif

c文件中

static void usb_hal_set_color(uint32_t color) 
{


    unsigned int color_code, modifier_code;
    switch (color & USB_HAL_DEBUG_COLOR_MASK_COLOR) 
    {
        case USB_HAL_DEBUG_COLOR_BLACK:
            color_code = 30; break;
        case USB_HAL_DEBUG_COLOR_RED:
            color_code = 31; break;
        case USB_HAL_DEBUG_COLOR_GREEN:
            color_code = 32; break;
        case USB_HAL_DEBUG_COLOR_YELLOW:
            color_code = 33; break;
        case USB_HAL_DEBUG_COLOR_BLUE:
            color_code = 34; break;
        case USB_HAL_DEBUG_COLOR_MAGENTA:
            color_code = 35; break;
        case USB_HAL_DEBUG_COLOR_CYAN:
            color_code = 36; break;
        case USB_HAL_DEBUG_COLOR_WHITE:
            color_code = 37; break;
        case USB_HAL_DEBUG_COLOR_RESET:
        default:
            color_code = 0; break;
    }
    
    switch (color & USB_HAL_DEBUG_COLOR_MASK_MODIFIER) 
    {
        case USB_HAL_DEBUG_COLOR_BOLD:
            modifier_code = 1; break;
        case USB_HAL_DEBUG_COLOR_UNDERLINE:
            modifier_code = 2; break;
        case USB_HAL_DEBUG_COLOR_BLINK:
            modifier_code = 3; break;
        case USB_HAL_DEBUG_COLOR_HIDE:
            modifier_code = 4; break;
        case USB_HAL_DEBUG_COLOR_NORMAL:
        default:
            modifier_code = 0; break;
    }


    printf("\\\\033[%u;%um", modifier_code, color_code);
}


void usb_hal_do_debug(USB_HAL_DEBUG_e level, const char *format, ...)
{
    uint32_t color = USB_HAL_DEBUG_COLOR_RESET;
    va_list args;


    switch(level) 
    {
    case USB_HAL_DEBUG_INFO:
        color = USB_HAL_DEBUG_COLOR_GREEN | USB_HAL_DEBUG_COLOR_BOLD;
        break;
    case USB_HAL_DEBUG_ERROR:
        color = USB_HAL_DEBUG_COLOR_RED | USB_HAL_DEBUG_COLOR_BOLD;
        break;
    case USB_HAL_DEBUG_WARN:
        color = USB_HAL_DEBUG_COLOR_YELLOW | USB_HAL_DEBUG_COLOR_BOLD;
        break;
    default:
        return;
    }
    va_start(args, format);
    usb_hal_set_color(color);


    vprintf(format, args);


    //printf("\\\\r\\\\n");
    usb_hal_set_color(USB_HAL_DEBUG_COLOR_RESET);


    va_end(args);
}

1.4 总结

以上从整体上设计了整个的驱动框架,重点考虑可移植性,可维护性等原则,借鉴面向对象的一些设计思想和原则。同时提供了一些调试方案供参考。前面磨刀已经磨了很久了,后面我们就开始正式进入编程阶段了。

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • usb
    usb
    +关注

    关注

    60

    文章

    7874

    浏览量

    263664
  • USB驱动
    +关注

    关注

    1

    文章

    136

    浏览量

    20158
  • 驱动开发
    +关注

    关注

    0

    文章

    130

    浏览量

    12059
  • 驱动框架
    +关注

    关注

    0

    文章

    14

    浏览量

    4020
  • DWC2
    +关注

    关注

    0

    文章

    35

    浏览量

    118
收藏 人收藏

    评论

    相关推荐

    基于DWC2USB驱动开发-0x01开篇介绍与新思DWC2 USB2.0控制器简介

    本文转自公众号,欢迎关注 基于DWC2USB驱动开发-0x01开篇介绍与新思DWC2
    的头像 发表于 05-08 18:10 4454次阅读
    基于<b class='flag-5'>DWC2</b>的<b class='flag-5'>USB</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-<b class='flag-5'>0x</b>01开篇介绍与新思<b class='flag-5'>DWC2</b> <b class='flag-5'>USB</b>2.0控制器简介

    基于DWC2USB驱动开发-0x02 DWC2 USB2.0 IP功能特征介绍

    DWC2即新思(Synopsys )的DesignWare® Cores USB 2.0 HiSpeed On-The-Go (OTG)控制器IP,被大量使用。从linux的内核源码驱动中就带
    的头像 发表于 05-09 10:09 8906次阅读
    基于<b class='flag-5'>DWC2</b>的<b class='flag-5'>USB</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-<b class='flag-5'>0x</b>02 <b class='flag-5'>DWC2</b> <b class='flag-5'>USB</b>2.0 IP功能特征介绍

    基于DWC2USB驱动开发-0x07 DWC2 USB2.0 IP 配置参数

    混淆,IP的配置参数固定之后就不能改了,就决定了IP所具有的能力。对于软件开发者来说也要了解其具体的配置,因为只有知道当前IP的配置,知道支持哪些功能,哪些是软件可以配置的哪些是硬件固定了无法配置的,等等这些,后面写驱动才心中有数。 配置相关
    的头像 发表于 05-17 09:49 2128次阅读

    基于DWC2USB驱动开发-0x0E 使用逻辑分析仪分析ULPI数据

    工欲善其事必先利其器,所以在USB开发中工具很重要,示波器,逻辑分析仪,USB协议分析仪等都不可少。在底层问题分析时缺少有力工具时很难进一步分析,本文分享了ULPI抓包分析,实际抓包波形因为信号质量问题可能没有那么理想,所以信号
    的头像 发表于 06-07 16:56 1573次阅读
    基于<b class='flag-5'>DWC2</b>的<b class='flag-5'>USB</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-<b class='flag-5'>0x0</b>E 使用逻辑分析仪分析ULPI数据

    基于DWC2USB驱动开发-IAD描述符详解

    本文转自公众号,欢迎关注 基于DWC2USB驱动开发-IAD描述符详解 (qq.com) 一.  前言 IAD描述符用于一个设备功能关联多个接口,可以用于实现组合设备。 二.参考文档
    的头像 发表于 06-27 08:45 5.1w次阅读
    基于<b class='flag-5'>DWC2</b>的<b class='flag-5'>USB</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-IAD描述符详解

    基于DWC2USB驱动开发-USB复位详解

    本文转自公众号欢迎关注 基于DWC2USB驱动开发-USB复位详解 (qq.com) 一.前言          上一篇我们详细介绍了
    的头像 发表于 07-07 11:18 5.4w次阅读
    基于<b class='flag-5'>DWC2</b>的<b class='flag-5'>USB</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-<b class='flag-5'>USB</b>复位详解

    基于DWC2USB驱动开发-USB连接详解

    本文转自公众号,欢迎关注 基于DWC2USB驱动开发-USB连接详解 (qq.com) 一.前言   之前一直在阅读手册,规格书,练习招式
    的头像 发表于 07-07 08:46 3494次阅读
    基于<b class='flag-5'>DWC2</b>的<b class='flag-5'>USB</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-<b class='flag-5'>USB</b>连接详解

    基于DWC2USB驱动开发-高速设备枚举为全速设备问题案例分析

    本文转自公众号,欢迎关注 基于DWC2USB驱动开发-高速设备枚举为全速设备问题案例分析 (qq.com) 一.前言   本文分享一个高速设备被枚举为全速的问题。     高速设备速
    的头像 发表于 07-10 17:12 1274次阅读
    基于<b class='flag-5'>DWC2</b>的<b class='flag-5'>USB</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-高速设备枚举为全速设备问题案例分析

    基于DWC2USB驱动开发-设备类驱动框架

    本文转自公众号,欢迎关注 基于DWC2USB驱动开发-设备类驱动框架 (qq.com) 一.前
    的头像 发表于 07-16 15:56 1251次阅读
    基于<b class='flag-5'>DWC2</b>的<b class='flag-5'>USB</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-设备类<b class='flag-5'>驱动</b><b class='flag-5'>框架</b>

    基于DWC2USB驱动开发-发送相关的寄存器DMA寄存器详解

    本文转自公众号,欢迎关注 基于DWC2USB驱动开发-发送相关的寄存器DMA寄存器详解 (qq.com) 前言 如下寄存器DIEPxxx,对应IN端点,和发送数据相关,这一篇先介绍和
    的头像 发表于 07-16 16:42 1548次阅读
    基于<b class='flag-5'>DWC2</b>的<b class='flag-5'>USB</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-发送相关的寄存器DMA寄存器详解

    基于DWC2USB驱动开发-USB包详解

    不管什么通讯协议,比如UART,SPI,USB等等,不管是并口还是串口,不管是同步还是异步,我们从抽象的角度去看,其本质都是一样的。都是先定义物理信号,物理信号可能是差分,单端,电流驱动电压驱动等等
    的头像 发表于 07-23 17:11 2397次阅读
    基于<b class='flag-5'>DWC2</b>的<b class='flag-5'>USB</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-<b class='flag-5'>USB</b>包详解

    基于DWC2USB驱动开发-数据不能发送问题分析案例

    本文转自公众号欢迎关注 基于DWC2USB驱动开发-数据不能发送问题分析案例 (qq.com)   一.前言        对于驱动
    的头像 发表于 08-08 09:43 2051次阅读
    基于<b class='flag-5'>DWC2</b>的<b class='flag-5'>USB</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-数据不能发送问题分析案例

    如何对基于hal库的DWC2 USB IP进行调试呢

    背景之前适配 DWC2 USB IP 的时候,主要是基于 st 的 hal 库来走的,当时我就对他们的 hal 库代码不满,只是无奈,迫于时间就没重构,果不其然,usb bug 一堆,随意举例,这还
    发表于 06-14 15:23

    基于DWC2USB驱动开发-0x0A ULPI接口同步模式介绍

    同步模式是ULPI必须支持的且主要的模式,内容比较多,对于软件开发人员来说重点关注下总线时序,即数据是如何交互的,这样必要的的时候可以使用逻辑分析仪进行抓包分析。另外重点关注下各个状态是如何反应在ULPI的寄存器中的
    的头像 发表于 06-04 15:35 3743次阅读
    基于<b class='flag-5'>DWC2</b>的<b class='flag-5'>USB</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-<b class='flag-5'>0x0</b>A ULPI接口同步模式介绍

    基于DWC2USB驱动开发-抽丝剥茧再论切换到状态阶段标志DOEPINTn.StsPhseRcvd

    本文转自公众号系列文章,欢迎关注 基于DWC2USB驱动开发-USB包详解 (qq.com) 一.前言 前面我们对SETUP完成标志DOE
    的头像 发表于 07-24 18:04 1404次阅读
    基于<b class='flag-5'>DWC2</b>的<b class='flag-5'>USB</b><b class='flag-5'>驱动</b><b class='flag-5'>开发</b>-抽丝剥茧再论切换到状态阶段标志DOEPINTn.StsPhseRcvd