串口dma驱动实现linux,UART蓝牙Linux调试的一些经验, DMA, FTP

这几天在调试一块Atheros 3001的蓝牙芯片,今天算是有一个里程碑了,总结一下放在这里吧,开始写博客的习惯吧。尽管这有些out,不过当作自己的一个习惯吧。

先介绍下这个芯片吧, Ath3001, 一块通过uart,也就是串口,连到host的蓝牙芯片。特点呢,我不清楚,一个比较明显的感觉就是比较快吧。最多支持3000000(3M)的波特率,如果忽略上层的话,数据吞吐量应该比较好。 不过应该主流的蓝牙芯片都差不多吧。

我的任务呢,就是要在我们的平台上, Freescale i.MX53上把这块芯片跑好,跑顺。。。说实话,我不太喜欢做第三方的东西支持,有时候交流起来比较困难,但是做成以后呢,自己又好像没多大意思似的。不过既然是咱做,咱就把它做好吧。

最后通过该驱动,打到了3M 的波特率。FTP的速度可以达到,接受140KB/s, 输出75KB/s。具体无法达到375K的理论最高速度应该是和上层的MTU之类的设置有关。插播一下,刚搜到说iPhone之间传文件最高为67KB/s,尽管我没有测试过两台mx53之间的速度,但是能和苹果达到一个数量级已经让我感到很欣慰了。阿门。

期间遇到了这么几个问题,

最早是CTS/RTS的问题。

因为这块芯片的驱动,在芯片的reset以后probe的过程中,需要手动控制RTS脚去踢芯片来唤醒它,一开始我们的UART驱动没有很好的对Linux tty标准做适配,无法在运行过程中对流控进行开关。后来在驱动中加入这个以后,芯片就起来了。

波特率

然后首先试的Profile是A2DP,也就是立体声听歌的配置,注意到声音在播放一段时间以后就会有规律的卡一次,然后从log上看是写数据下去的时候被什么东西给block住了,当时还有一个猜想就是波特率不够,在增加波特率到56K以后,有些缓解,可是还是会有一两次的卡。这个问题一直到最近才解决掉了。是uart驱动里面对于tx的处理有些问题。

DMA传输

现在uart传输是用中断模式做的,这样做的好处,好处就是简单,呵呵。但是坏处比较大,如果我以一个高的波特率传输音乐或者文件,可怜的cpu被中断的非常痛苦,这时候会对系统新能造成很大影响。 具体计算, 可以简单的用你的速度/fifo大小来得出,比如我们以30K/S的速度传文件,我们的FIFO是32个字节,那么每秒CPU将被中断1000次,所以这是不可接受的,当然这么多中断的话,就不可能达到这个速度 :)

解决办法只有一个, 打开DMA传输。只有在打开和不打开之间,才可以体验到这个东西的优越性。 如果用中断,我大概A2DP的时候是90+%的CPU loading, 如果是DMA,那么就到了3%的loading了。 差距啊。 DMA设置的BUFFER size可以比你的fifo大,比如我设置的是128的,fifo只有32。 DMA控制器会从你的uart fifo里面一直搬数据,搬满了就给你个中断。 让你去处理这些数据。

当开DMA的过程也有些曲折,因为打开DMA的以后会要求SOC打开一个访问DDR的emi_fast的clock,当时也费了点功夫查这个问题。 ps, 53的clock真复杂。

A2DP的调试还好,因为听歌传错一两个帧没什么大碍。但是传文件这个就不一样了。错一点都不行。

UART驱动的BUG

于是在调试FTP的时候,又发现了两个小BUG在我们的uart驱动中。

一个是在传输的时候,因为是用DMA传送的,DMA在传完一个buffer的时候会去调用一个callback,这时候原来的驱动会设置好新的buffer地址以后去启动一个tasklet来进行传下一个buffer。可是我发现这种异步的方法会有丢一些数据,换成直接调用那个函数来传下一个buffer就没问题了。我想这个问题大概是这样的,因为dmaread的callback和write的callback都修改一个bufferid的变量来记录哪段buffer,而如果调用tasklet来传输下一段buffer,会有这样一种情况:

dma_wirtecallback->让tasklet开始run.

可是由于tasklet在soft irq的context下面,会有一点的延迟。

这个时候,dma_readcallback来了,并且在这个tasklet前面执行,所以就会修改掉buffer id。

然后传输失败了,也有可能是传错东西了,远端不认识这些数据。 就没给正确的回应。所以蓝牙驱动里面就报错了。

这时候,FTP协议就会不正常了。

另外一个问题是read的时候, 由于使用了dma传输,每次会有128或者更多的data从给到dma_read的callback上面,这时候原来的驱动会去调用tty_buffer_request_room()来去申请空间,然后把申请到空间的长度的数据调用tty_insert_flip_string来送给上层。这么做是不对的,申请空间的工作应该由tty_insert_flip_string来完成,它在 tty_insert_flip_string_fixed_flag() 函数中会有一个循环来request_room,而每次reqeust_room的值都不会太大以至于失败。而uart驱动中就是在这里一次申请了太大的数据,比如128之类的,导致申请失败返回,所以数据就丢掉了。

我在传输两边用md5sum能够看到传输的文件内容不同了。

硬件的波特率

在调试过程中还碰到过一种情况,就是在ftp传文件传的很high的时候,会莫名其妙的把数据传错。最后发现是因为我们用的这个ATH3001的卡上的传输器(transceiver)天生只对几种波特率支持的比较好,比如1500000,3000000之类的,而我当时用的是1152000的波特率。当切换了波特率以后就不会出现这种莫名其妙的数据错误了。

接下来做做HFP的工作吧,这大概是蓝牙这玩意最有用的功能了。

PS,我这个驱动主要是在arm的ubuntu下面调试完成的,由于强大的工具支持,这个过程会比较顺畅。 调试好了底层,把东西跑在Android上也是非常顺利的。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
摘 要:基于对Linux蓝牙协议栈BlueZ 源代码的分析,给出BlueZ的组织结构和特点。分析蓝牙USB 传输驱动机制和数据处理过程, 给出实现蓝牙设备驱动的重要数据结构和流程,并总结Linux 下开发蓝牙USB 设备驱动的一般方法和关键技术。 关键词:Linux 系统;蓝牙协议栈;设备驱动 USB Device Driver for Linux Bluetooth Stack LIANG Jun-xue, YU Bin (Institute of Electronic Technology, PLA Information Engineering University, Zhengzhou 450004) 【Abstract】This paper depicts the structure and characteristics of BlueZ based on analyzing the source code of Linux bluetooth stack BlueZ. It analyzes the implementation of bluetooth USB transport driver scheme and data processing procedure in detail, and gives the key data structure and implementation of bluetooth device driver. It summarizes the approach of developing Linux bluetooth USB device driver and the key technology. 【Key words】Linux system; bluetooth stack; device driver 计 算 机 工 程 Computer Engineering 第 34 卷 第 9 期 Vol.34 No.9 2008 年 5 月 May 2008 ·开发研究与设计技术· 文章编号:1000—3428(2008)09—0273—03 文献标识码:A 中图分类号:TP391 1 概述 蓝牙技术是开放式通信规范,而 Linux 是开放源码的操 作系统。廉价设备与免费软件的结合,促进了蓝牙技术和 Linux 的发展与融合。 Linux最早的蓝牙协议栈是由Axis Communication Inc在 1999 年发布的 OpenBT 协议栈。 随后, IBM 发布了 BlueDrekar 协议栈,但没有公开其源码。Qualcomm Incorporated 在 2001 年发布的 BlueZ 协议栈被接纳为 2.4.6 内核的一部分。此外, Rappore Technology 及 Nokia 的 Affix Bluetooth Stack 都是 Linux 系统下的蓝牙协议栈,应用在不同的设备和领域中。 BlueZ 是 Linux 的官方蓝牙协议栈,也是目前应用最广 泛的协议栈,几乎支持所有已通过认证的蓝牙设备。对于基 于主机的蓝牙应用,目前常见的硬件接口有 UART, USB 和 PC 卡等,USB 作为 PC 的标准外设接口,具有连接方便、兼 容性好和支持高速设备等特点,已广泛应用于蓝牙设备。 目前对 Linux 下 USB 设备驱动的研究已较为广泛而深 入[1-4] ,但对 Linux 下的蓝牙设备驱动还没有专门的研究。本 文在分析 USB 设备驱动蓝牙协议栈的基础上,总结了 Linux 下开发蓝牙 USB 驱动程序的一般方法,并深入剖析了 其关键技术。 2 Linux 蓝牙协议栈 BlueZ 简介 BlueZ 目前已成为一个开放性的源码工程。它可以很好 地在 Linux 支持的各种体系的硬件平台下运行,包括各种单 处理器平台、多处理器平台及超线程系统。 BlueZ 由多个独立的模块组成,内核空间主要包括设备 驱动层、蓝牙核心及 HCI 层、L2CAP 与 SCO 音频层、 RFCOMM, BNEP, CMTP 与 HIDP 层、通用蓝牙 SDP 库和后 台服务及面向所有层的标准套接字接口;在用户空间提供了 蓝牙配置、测试及协议分析等工具。其组织结构如图 1 所示, BlueZ 没有实现专门的 SDP 层,而是将其实现为运行在后台 的蓝牙服务库例程(图 1 没有描述该后台服务)。 RFOMM 层支 持标准的套接口,并提供了串行仿真 TTY 接口,这使串行端 口应用程序和协议可以不加更改地运行在蓝牙设备上,例如 通过点对点协议 PPP 可实现基于 TCP/IP 协议簇的所有网络 应用。BNEP 层实现蓝牙的以太网仿真,TCP/IP 可以直接 运行于其上。 USB设备驱动 (hci_usb.o) L2CAP层(l2cap.o) RFCOMM层 (rfcomm.o) BNEP层 (bnep.o) CMTP层 (cmtp.o) 串口设备驱动 (hci_uart.o) 虚拟串口设备驱动 (hci_vhci.o) 音频 socket RFCOMM socket BNEP socket CMTP socket L2CAP socket HCI socket 内核 空间 用户 空间 串口设备 CAPI设备 输入设备 网络设备 HDIP socket 音频设备 AF_BLUETOOTH socket 音频层(sco.o) PPP TCP/IP AF_INET socket BNEP层 (bnep.o) 其他设备驱动 (bluecard_cs.o等) BlueZ工具和实用程序 HDIP层 (hdip.o) BlueZ核心 及HCI层(bluez.o/bluetooth.o) 图 1 BlueZ 组织结构 3 蓝牙 USB 设备驱动 设备驱动程序在 Linux 内核中起着重要作用,它使某个 硬件能响应一个定义良好的内部编程接口。这些接口隐藏了 设备的工作细节,用户通过一组独立于特定驱动程序的标准 调用来操作设备。而将这些调用映射到作用于实际硬件设备 的特有操作上,则是驱动程序的任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值