基于LUFA开源框架库对AVR芯片进行USB终端设备开发

来源:互联网 发布:javascript call是什么 编辑:程序博客网 时间:2024/05/19 02:30

基于LUFA开源框架库对AVR芯片进行USB终端设备开发


摘要:本文针对一般USB设备的开发过程过于困难、复杂、繁琐等不利于快速开发的问题,引入了LUFA(Lightweight USB Framework for AVRs)开源框架库,解决了基于AVR芯片的USB设备的快速开发问题。这种方法能实现快速开发并实现相关的产品,并且有稳定的性能表现,具有工程实践意义。

本文引用地址:http://www.eepw.com.cn/article/262220.htm

  概述

  目前,USB控制器主要有两种:一种是带USB接口的单片机(MCU),另一种是纯粹的USB接口芯片。前者的最大优势在于,开发者对系统结构和指令集非常熟悉,开发工具简单,容易进行功能拓展,但其成本相对较高;后者的最大特点是,价格便宜,接口方便,可靠性高,但其硬件架构相对复杂,软件部分限制相对较大。

  在工程实践中,有时需要快速可靠地开发出相应的USB终端设备,或者针对特定领域开发出专用产品。此时,如果有一个成熟可靠的软件框架,可以事半功倍地满足相应的需求。本文针对AVR的部分带USB接口的单片机,如:AT90USB系列,ATmega8U系列,ATmega16U系列,AT32UC3系列的部分型号,ATXmega系列的部分型号等,介绍LUFA开源框架,以实现快速开发USB终端设备,或者针对特定领域开发专用产品。

  1 USB协议概述

  USB是一种串行接口协议,应用日益广泛。但是,要熟悉其协议内容并不简单,其协议文档繁杂罗嗦,Linux uhci驱动作者之一Alan Stern曾经就说过:

  The USB documentation is downright evil. Most of it is just crap, written by a committee. You're better off ignoring most of it.

  他同时还对软件开发者指出,开发者最需要注意的是两点:一、底层协议(非常简单,但很多小细节要注意),二、其他。

  简而言之,USB协议,在硬件上,靠D+,D-两条数据线进行差分传输,以及NRZI的编码方式。在通信上,依靠封包(package)格式进行数据传输。封包由若干个域(Package Field)构成,每个域由若干位组成(具体的位数由具体的域决定)。其细节部分繁多复杂,上手困难,也极其容易出错。

  LUFA开源框架

  LUFA(Lightweight USB Framework for AVRs),由澳大利亚人Dean Camera开发,是一个基于MIT协议分发的开源框架。针对带USB接口的Atmel AVR8单片机和部分AVR32单片机系列,LUFA实现了一个完全符合USB通信协议的开源框架库。基于这个框架,不仅能开发出合适的终端设备,也能在部分设备上开发出合适的主控制端。

  该框架库经过多年的测试改进,现已处于稳定版本。其针对AVR-GCC编译器进行了优化设计,使用了部分GCC特有的拓展方式,使得这个库的相关API能更稳定流畅地运行。相关的编译器AVR-GCC,能在Atmel网站下载到相应系统的版本。在LUFA源码库里面,有多达三四十种不同应用的示例版本。

  ● 支持的芯片类型

  LUFA是针对带USB接口的Atmel AVR 8/32位单片机进行开发的,所以只要是带USB接口的Atmel AVR单片机,均可使用LUFA开源框架库。例如:AT90USB系列,ATmega8U系列,ATmega16U系列,AT32UC3系列,ATXmega系列等。详情可查看LUFA的相关文档。

  ● 源码下载

  LUFA的项目主页(英文)在http://www.fourwalledcubicle.com/LUFA.php。该项目的源码版本管理托管在github上,相关地址在http://github.com/abcminiuser/lufa。更多详情,可以在LUFA的项目主页上查看。

  ● 开发环境搭建

  Atmel提供了相关的工具链,使得开发者可以简单方便地进行开发,包括Linux平台和Windows平台。除了Atmel提供的工具链之外,还可以使用第三方工具链,按照自己的需要来进行开发。同时,LUFA已经成为Atmel Studio 6.1及后续版本的原生插件之一。无论是编译固件,还是固件上传,LUFA文档都提供了详细的说明。详情请参阅LUFA文档部分:LUFA Library -> Getting Started。

  3 设备开发示例说明

  在本示例中,本文以ATmega32U4制作一个可编程键盘为示例,演示LUFA开源框架库的开发流程方式。该示例分成两大部分:一、制作bootloader,以便对设备进行编程烧录;二、实现矩阵键盘功能。

  ● ATmega32U4微处理器

  ATmega32U4是一款采用低功耗CMOS工艺生产的基于AVR RISC(精简指令集)接口的高性能、低功耗8位单片机。处理器具有可控制的上电复位延时电路和可编程的前沿检测电路,带有双周期乘法器,以及32个8位通用工作寄存器,内部和外部共计13个中断源,加上丰富的的指令集,使得大部分的指令执行时仅为一个时钟周期。因此可达到1MIPS/MHz的性能,运行速度比普通单片机高得多。

同时,处理器还有丰富的外部接口,如14个PWM通道,12路10位ADC,SPI,USART等。片内集成了32KB的Flash程序储存器(其中4KB可被引导程序使用),2.5KB片内SRAM,1KB的片内EEPROM,2个带预分频的8位定时/计数器,2个带预分频的16位定时/计数器,带看门狗定时器等,还支持ISP和IAP编程,带有符合IEEE 1149.1标准的JTAG接口。其USB接口,可工作在全速/低速设备模式下。对于控制传输方式,端点0最大能支持64b的数据包。对于块传输、中断传输和同步传输方式,有6个可编程端点,最大能支持256b的数据包。

本文引用地址:http://www.eepw.com.cn/article/262220.htm

  在启动阶段,可以通过对熔丝位HWBE(上划线)置0,并下拉HWB(上划线)引脚,使得系统先进入引导区程序,以方便固件更新。启动流程部分,请参考图2。

  ● bootloader开发示例

  对于AVR微处理器来说,出厂的时候都预先烧录了Atmel DFU (Device Firmware Update)进bootloader区。如果不需要进行bootloader区编程,可以省却外部编程器。当需要更新固件程序时,无需外部编程器的参与,只需使系统运行在bootloader环境下,就可以利用USART、SPI或者USB接口,进行固件更新烧录。

  在LUFA开源框架库中,有好几种不同的bootloader示例。如支持AVR109协议的自编程框架,支持USB DFU协议的自编程框架,或者其他。在开发过程中,作为开发者,只要能理解其相关原理,即可灵活运用。

  从示例中可以看出,整个软件的工作流程如图3所示。在启动过程中,系统先调用初始化程序对相关的I/O口进行输入/输出定义及参数初始化;接着,进入bootloader循环。在bootloader循环中,系统不断的检测USB接口下的Endpoint,读取数据,返回指令信息等。直到收到结束通信的指令(AVR109和DFU协议均有相关指令),才退出bootloader应用。最后断开这次USB连接,程序指针跳转到0x0000位置,也就是应用程序的开始点。如图3。

从示例可以看出,在LUFA框架下,bootloader的开发有了极大的效率提升。开发者可以通过简单地修改USB设备的描述页信息,添加或修改相关的传输协议,即可快速开发出符合需求的bootloader模块。

本文引用地址:http://www.eepw.com.cn/article/262220.htm

  ● 设备开发示例说明

  对于USB设备来说,首先进行USB枚举设定(setup过程),然后如果没错误,就可以开始USB设备的正常工作状态了。既然LUFA已经为开发者做出了众多可能的基本设置,开发者只需要知道个大概流程,大多数事情都可以留给LUFA来做了。

  首先,是0号端点(Endpoint 0)和控制传输模式。0号端点主要用于USB设备枚举。在枚举过程中,主机给设备分配相应的地址信息,同时也在读取设备信息,如设备类型。主机通过发送相应的控制指令给设备,设备回复相关信息给主机,完成握手通信,最后完成相关的设置。LUFA基本上能全自动地完成所有的相关工作,开发者只需要知道该怎么设置而已。如图4。

  接下来,是数据传输过程。当设定过程完成之后,数据传输过程的方向、可用端点的大小等基本信息已经确定下来了。这个时候,设备和主机之间就能进行正常的数据传输了。LUFA提供了多种不同的方式来接收数据包。通常来说,设备端点收到数据之后,会向主机返回“ACK”指令,以告知数据包已收到,但是最终的一个“ACK”指令包则不会自动回复,需要用户在程序里面实现。不过,对于开发者来说,只需要认真研读一下示例文件就可以理解,并得知实现方式。

  以Demo/Device/ClassDriver/Keyboard/这个项目为例。文件Descriptors.c里面,记录了USB设备的描述值,包括传输过程中的设备描述值,和枚举阶段的配置描述值,还有返回设备描述值调用的一个函数。这些相应参数,可在工程实践中,按需修改。文件Keyboard.c里面,包含了程序的主入口main()函数。

  main()函数中,SetupHardware()实现了基本的硬件初始化功能,值得注意的是USB_Init()函数。这个USB_Init()函数,是LUFA框架实现的一个函数。在这个函数中,它实现了USB接口相关的寄存器及I/O的初始化功能,调用了USB_ResetInterface()函数,以实现USB设备的相关设置。其中的一个功能是按照开发的需要,初始化USB设备,使其成为USB控制器或USB设备,在此示例中,初始化为USB设备,调用USB_Init_Device()函数。USB_Init_Device()函数又调用了一个需要自己按需实现的函数CALLBACK_USB_GetDescriptor(...)(在Descriptors.c文件中)。至此,完成USB设备的初始化过程。

  完成USB设备的初始化过程之后,就开始了一个不断循环的函数体。如果是想实现USB设备的相关功能,就把相关的功能模块写入这个函数体内就可以了。以Demo/Device/ClassDriver/Keyboard/项目为例,这个循环体内包括两个函数模块:HID_Device_USBTask(&Keyboard_HID_Interface)和USB_USBTask()。前者,调用了一个函数CALLBACK_HID_Device_CreateHIDReport(...),以记录测试哪个按键被按下或松开,并记录下来。后者,纯粹地把相应的按键信息按照USB协议的要求发送出去。实现相关的USB通信。

  因此,如果此时需要完成一个矩阵键盘,那么只需要在CALLBACK_HID_Device_CreateHIDReport(...)之内,插入相应的矩阵键盘扫描语句,延时消抖功能等,即可实现开发需求。其他的设备,如USB音频设备,U盘,鼠标等,也是类似的实现方式。

  4 结语

  对于开发者而言,LUFA开源框架库不仅能帮助快速完成相应的项目开发,如果能细读其代码,还可以大大地提高相应的编程水平。同时,LUFA开源框架库的引入,大大地降低了在AVR单片机上开发USB设备的门槛,极大地提高开发效率,并且减少了开发过程中的调试测试时间,增加了系统的稳定性。其示例文档丰富,入门容易,代码优美稳定,逻辑架构完美。因此,无论是出于项目开发的需要,还是能力提升的需要,都可以好好研究或阅读LUFA开源代码,借鉴其开发经验,做出更好更快更优质的工程项目。

  参考文献:
  [1]Atmel.ATmega32u4 Datasheet[M]
  [2]Universal Serial Bus Revision 2.0 Specification[S]
  [3]LUFA Online Documents[R/OL].(2014-03).http://www.fourwalledcubicle.com/files/LUFA/Doc/140302/
  [4]Redecker C.USB Control Transfers with LUFA[R/OL].(2011-10).http://www.avrbeginners.net/new/wp-content/uploads/2011/10/avrbeginners_40_USB_Control_Transfers_with_LUFA_1.0.pdf
  [5]USB in a Nutshell[R/OL].(2014-04).http://www.beyondlogic.org/usbnutshell


0 0