在mini2440上面搞定CC2500驱动

  1. 写在前面

最近基本搞定了 CC2500 在 linux 下面的驱动,在这个过程中遇到了好多问题,特此总结出来和大家分享。但是需要注意的事情是:
第一,本文不负责程序的具体讲解,诸如每一行程序都讲什么:这个在程序的里面有注释。本篇文章更侧重于从整体结构上让大家对于 linux 下的 CC2500DE 驱动有一个整体的了解,如果到时候需要深入研究的时候,再来看具体的代码;
第二,很多师弟师妹没有习惯在 linux 下编程,或曰,在操作系统下面写程序;并且,对于本专业的东西理解并不扎实。但是,文章中不可能就每一个涉及到的概念都大加讲解。因此,这篇文章还是需要有一些基础才能来阅读的,如果遇到什么不明白的地方,请及时来问我,或者跟帖,或者自己查资料。毕竟,这个驱动花费了我半个多月的时间,其中遇到的问题,不可能在一篇文章中就讲得清清楚楚。

  1. 背景知识

如果大家看过实验室的 WSN 方面的程序,可能会被其中的架构搞得天昏地暗。这里,简单的帮助大家把实验室的 WSN 的软件、硬件方面捋一捋。
说到软件,就不能不说硬件。我们的节点由两部分组成,一个是单片机,一个是 CC2500 的射频模块。射频模块通过 SPI 接口和单片机进行通信。除了 SPI 模块用到的 4 条线,实际上 CC2500 还需要告诉单片机“我接收到一个数据”,这个地方 CC2500 可以通过配置 GDO 来实现。我们这里采用的 CC2500 的 GDO0 作为单片机的一个外部中断,当接收到数据的时候, GDO0 就会变为低电平,然后触发 CC2500 的中断,从而接收数据。
那么, CC2500 究竟是如何来进行数据发送、接收的呢?其实很简单。如果大家稍微用过一点可以控制的芯片就会知道,很多芯片内部都有寄存器, CC2500 之所以能够完成发送、接收的功能,就是通过配置寄存器来完成的。比较重要的配置有信道、波特率、信号强度等等,另外, CC2500 还有 64bytes 的 RXFIFO 和 64bytes 的 TXFIFO ,他们的作用就是用来发送和接收。当配置 CC2500 结束之后,如果用来发送,那么就把数据放在 TXFIFO 里面,然后把 CC2500 的状态变为发射状态,数据就自动发送出去了。同样的道理,当 RXFIFO 里面接收到了数据之后, CC2500 就会如前所说,发出一个中断,通知单片机来读取数据。
单片机通过 SPI 接口读出了 CC2500 中的数据,就需要进行简单的处理了。我们的节点是遵循 802.15.4 协议的,如果有兴趣,大家可以去看一看这个协议的内容。对于我们来说,比较重要的就是帧的结构。下面这个是物理层帧的结构:

字节:4
1
1
可变
先导码
帧定界符

帧长度(7位)

保留位(1位)
负载内容

同步头

PHY头

PHY负载

简单的讲,因为是无线通信,没有一个时钟的存在,因此本质上所有的无线通信都是一个异步的通信。那么,就需要发送和接收的双方首先对数据进行同步——这个就是同步头的作用。随后的是 PHY 的头,很简单,就是一个长度。换句话说,每个帧不能够超过 2 的 8 次方减一个数据( 127 个)。随后就是负载的内容了,简单吧?另外,由于 CC2500 是一个 802.15.4 兼容的芯片,这一部分内容都已经固化在芯片里面了,像同步头这种东西,都是芯片帮我们完成(当然也可以自行配置)。我们只需要把写入的数据大小和数据内容写入即可。
虽然简单,但是还有一个问题:每次从 CC2500 中读取了数据,存放到哪里呢?有的同学可能想的比较简单,比如建立一个大数组,收到多少个数,放在里面就行了。但是,这样就会遇到问题:如果收到了两个包,上层来不及处理怎么办?建立两个大数组?更多的包呢?当然,我们可以通过建立好多个数组来解决这个问题。但是,从效率上讲,这个是非常笨的一个办法。因此,我们建立了一个环形缓冲区 PHY_RX_BUFFER ,来解决这个问题。环形缓冲区的具体原理不过多涉及,可以自行百度。
另外一个问题就是,如果我们从 CC2500 中接收到了数据,那么应该怎样才能告诉上层来进行处理呢?这里就要用到操作系统的消息机制了。如果确定接收到了一个数据,那么就给上层发送一个消息,来通知上层。上层接收到这个消息,就会知道接收到了数据。
当从 CC2500 读取到了数据,因为物理层没有什么东西,我们就直接通知 MAC 层来处理数据。 MAC 层的结构如下:

字节:2
1
0/2
0/2/8
0/2
0/2/8
可变
2
帧控制域
序列号
目的PAN标示符
目的地址
源PAN标示符
源地址
帧负载
FCS
地址域
MAC帧头
MAC负载
MFR

具体内容可以参见老师的《无线传感器网络技术与工程应用》这本书,这里不再详细的讲,大概内容就是,会有一系列的帧头,然后是帧数据,最后有校验。而我们最关心的就是帧的内容。但是,帧头也比较麻烦,因此我们需要首先对帧头进行处理,把数据给“剥离”出来,这也是基本上所有的协议栈解析协议的方法。

  1. 硬件结构

硬件上,我们采用的是 mini2440 开发板,和实验室的 CC2500 节点(把单片机焊掉,然后把 mini2440 的相应管脚接到上面)。

Mini2440 方面,我们用的是 CON8 这个引脚,具体连线如下:
EINT8 对应 S3C2440 的 GPG0 引脚,连接到了 CC2500 的 GDO2
EINT11 对应 S3C2440 的 GPG3 引脚,连接到了 CC2500 的 CSN
EINT13 对应 S3C2440 的 GPG5 引脚,连接到了 CC2500 的 SO
EINT14 对应 S3C2440 的 GPG6 引脚,连接到了 CC2500 的 SI
EINT15 对应 S3C2440 的 GPG7 引脚,连接到了 CC2500 的 CLK
EINT19 对应 S3C2440 的 GPG11 引脚,连接到了 CC2500 的 GDO0
除此之外,还有 3.3V 电源和 GND

  1. Linux下驱动编写

为什么要用驱动呢?简单的说,就是为了在 linux 下完成用户空间和内核空间的交互。本质上,驱动就是完成了两件事情:第一,初始化 SPI 接口,并且通过 SPI 和 CC2500 完成通信。第二,完成读写函数, read 和 write ,通过读写函数的接口来对 CC2500 进行操作。
附件里面有几个文件,这里简单讲解一下:
Common.h 主要是包含了很多 linux 的头文件,并且对一些数据类型做了定义
CC2500.h 里面主要是对 CC2500 的寄存器做了一些定义,没啥东西
Driver.h 主要是定义了很多和 CC2500 进行通信,并且利用 CC2500 进行发送和接收的内容
Phy.h 主要是完成了一些诸如信道设定、通信速率等功能,并且把 CC2500 里的数据读到环形缓冲区里面
CC2500.c 这个就是完成设备注册、读写函数、 iocontrol 等功能
这样有了一个整体的把握之后,不用看很多代码,学会使用就好。

  1. 驱动接口使用

那么,这个驱动怎样使用呢?主要是通过 read/write/ioctl 三个接口来实现的。
在应用程序中 read/dev/CC2500 这个文件,如果有数据,会返回相应的数据。其中,返回的数据中第一个字节为数据的长度(不包括该字节本身),后面为相应的数据。
如果是写文件的话,只需要向 /dev/CC2500 中写入相应的数据即可。写入的时候需要注意,第一个字节同样为数据长度(不包括该字节本身),后面跟相应的数据。当写入的字节合适的时候,驱动会自动执行发送函数。如果写入的字节数量和写入的数据第一个字节不匹配的时候,会返回错误。
ioctl 主要有这样几种命令:

CC2500_IOC_PHY_DETECT_STATUS
表示将 CC2500 的状态变为 RX
CC2500_IOC_PHY_GET_BAUDRATE
读取 CC2500 的波特率,返回的是 1,2,3,4 ,分别是 2.4k,10k,250k,500k 的波特率
CC2500_IOC_PHY_SET_BAUDRATE
设定 CC2500 的波特率,后面的参数是 1,2,3,4 ,分别是 2.4k,10k,250k,500k 的波特率
CC2500_IOC_PHY_GET_TXPOWER
获取发送功率,返回的是在发送功率表 {0x00, 0x50, 0x44, 0xC0, 0x84, 0x81, 0x46, 0x93, 0x55, 0x8D, 0xC6,0x97, 0x6E, 0x7F, 0xA9, 0xBB, 0xFE, 0xFF } 中的数组下标
CC2500_IOC_PHY_SET_TXPOWER
设定发送功率,参数的是在发送功率表 {0x00, 0x50, 0x44, 0xC0, 0x84, 0x81, 0x46, 0x93, 0x55, 0x8D, 0xC6,0x97, 0x6E, 0x7F, 0xA9, 0xBB, 0xFE, 0xFF } 中的数组下标
CC2500_IOC_PHY_GET_CHANNEL
获取频段,参数是频段表 {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0,0xB0, 0xC0, 0xD0, 0xE0, 0xF0 } 中的数组下标
CC2500_IOC_PHY_SET_CHANNEL
设定频段,参数是频段表 {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0,0xB0, 0xC0, 0xD0, 0xE0, 0xF0 } 中的数组下标

  1. 应用层程序编写

这里的应用层主要是将 mac 层实现了。其实, mac 层的作用也很简单,主要是对要发送的包进行封装,接收回来的包进行包的解析。这一部分的内容还不全面,仅仅是将原来的程序移植过来,还有很多需要改动的地方,有待补充。因此,这里只是提供源代码,具体的说明请参见程序内部

  1. 如何配置内核文件

1 首先修改 /opt/FriendlyARM/mini2440/linux-2.6.32.2/drivers/char/Kconfig
加入如下几句话:
config CC2500_DRIVER

tristate "CC2500 driverfor FriendlyARM Mini2440 development boards"

depends on MACH_MINI2440

default m if MACH_MINI2440

help

this is CC2500 driver forFriendlyARM Mini2440 development boards

2  修改 Makefile ,让 CC2500 的驱动可以编译。
加入如下几句话:

obj-$(CONFIG_CC2500_DRIVER)     +=CC2500inuse.o

CC2500inuse-objs :=./CC2500.in_use/cc2500.o ./CC2500.in_use/phy.o./CC2500.in_use/driver.o

其中, CONFIG_CC2500_DRIVER  需要和 Kconfig 中的 configCC2500_DRIVER
保持一致。
CC2500inuse-objs 这句话,意思是 CC2500inuse.ko 是由哪几个文件组成的。这样就实现了模块化的处理。
需要注意的是, CC2500inuse-objs 和冒号之间需要有个空格,不然会出错误。这个地方我搞了好久。
具体的 Makefile 的格式也可以参考这两篇文章:
http://blog.csdn.net/tommy_wxie/article/details/7282463
http://hi.baidu.com/wjq_qust/blog/item/97ddbdfdfb2e541309244d30.html

  1. 调试过程中的一些问题

CC2500 驱动调试的过程中,遇到的一些问题
第一,在调试的过程中,发现板子和 2500 没有办法进行通信。一开始怀疑是 2500 芯片的问题,后来确认 2500 芯片没有问题之后,用示波器看了一下波形,发现 SPI 引脚上没有输出。进而发现,对 SPI 寄存器进行读写的时候,无论写入是什么,读出的都是 0 。后来发现,原来是 PCLK (也就是 SPI 模块的时钟)没有使能,囧。设置了寄存器之后,问题就解决了。
第二, CC2500 驱动没有办法自动在 /dev/ 目录下面创建节点。这个问题可以参考下面几篇文章:
http://blog.csdn.net/cjok376240497/article/details/6848536
整体来说,创建节点的工作是这样的:
我们通过 udev 来创建节点。但是, udev 是应用层的东东,不要试图在内核的配置选项里找到它 ; 加入对 udev 的支持很简单,只要在驱动初始化的代码里调用 class_create 为该设备创建一个 class ,再为每个设备调用 class_device_create 创建对应的设备。
换句话说,首先要为每一个设备创建一个类。然后用这个类去申请一个设备节点。
第三,在调试的过程中,发现只要一启动 CC2500 ,那么液晶屏就熄灭了。调试了半天也没有找到原因。
最后发现,在配置 S3C2440 中 GPGCON 寄存器的时候,对寄存器直接进行了覆盖性的修改;而该寄存器还管理着 LCD 的电源 ... 于是,对寄存器进行覆盖性修改的时候,悲剧了 ...
总结一下吧,在 linux 下 2500 驱动编写的过程中,如果涉及到寄存器级别的操作,和单片机一样,必须十分注意各个模块之间的关系,以及相关模块的寄存器配置,不要认为 linux 会全部给你配好!

在mini2440上面搞定CC2500物理层驱动相关推荐

  1. 看完这篇,黑苹果驱动VoodooI2C编译打包所有错误全搞定

    黑苹果驱动,源码级别的编译打包,VoodooI2C是出问题最多的.下面我带大家解决它们. 首先如果你只是下载了这个: git clone https://github.com/alexandred/V ...

  2. linux作为输出电脑声卡,今天终于搞定我的电脑的ALC883声卡linux驱动了

    今天终于搞定我的电脑的ALC883声卡linux驱动了 发布时间:2007-10-30 01:14:20来源:红联作者:kwareregb 我的电脑是神舟F206S,声卡是realtek ALC883 ...

  3. 终于搞定android驱动USB摄像头了!

    终于搞定android驱动USB摄像头了! 多亏了stackoverflow看到的一篇帖子,其中有几句关键的话,然后顺藤摸瓜解决了问题. 帖子大意: 讨论的前提是你的USB摄像头是UVC兼容的(如今大 ...

  4. 为Debian搞定Mercury MW150US无线网卡驱动

    买无线网卡前没认真研究Linux兼容性的问题,看着水星的mini无线网卡挺好看就买回来了.狗狗了一下才发现Linux不支持这款,得自己搞定驱动. 先安装些编译工具: apt-get install b ...

  5. 轻松搞定ThinkPad T530蓝牙驱动

    轻松搞定ThinkPad T530蓝牙驱动 我的ThinkPad T530本本的蓝牙芯片是BCM20702的,硬件id是0x21E6,换成十进制就是8678.在10.9下,修改个id就能驱动. 方法如 ...

  6. android 打开外置摄像头驱动程序,嵌入式er日常系列!终于搞定android驱动USB摄像头了!...

    原标题:嵌入式er日常系列!终于搞定android驱动USB摄像头了! 感谢网上的大神分享经验,终于解决了让我头疼好久的USB摄像头问题,讨论的前提是你的USB摄像头是UVC兼容的(如今大部分摄像头兼 ...

  7. 搞定QQ游戏系列(寻仙,DNF等等)驱动保护TesSafe.sys

    1.用RKU看一下SSDT和SSDTShadow,发现SSDT并没有被HOOK,SSDTShadow HOOK了5个调用: NtUserBuildHwndList NtUserFindWindowEx ...

  8. 过NP 系列之一---搞定QQ游戏系列(寻仙,DNF等等)驱动保护TesSafe.sys

    1.用RKU看一下SSDT和SSDTShadow,发现SSDT并没有被HOOK,SSDTShadow HOOK了5个调用: NtUserBuildHwndList NtUserFindWindowEx ...

  9. 神操作!一行Python代码搞定一款游戏?给力!

    来源:pypl编程榜 一直以来Python长期霸占编程语言排行榜前三位,其简洁,功能强大的特性使越来越多的小伙伴开始学习Python .甚至K12的同学都开始学习Python 编程.新手入门的时候趣味 ...

  10. 1080Ti 就搞定最新 SOTA 模型?一个普通研究生勇敢发毕业论文引起热议

    点击上方"视学算法",选择加"星标"或"置顶" 重磅干货,第一时间送达 转自 | 新智元 来源 | Reddit 编辑 | 好困 除了在顶会 ...

最新文章

  1. java.lang.OutOfMemoryError: PermGen space及其解决方法
  2. java build path entries 为空_TOOLFK工具-在线JAVA代码执行工具
  3. C++union 联合
  4. 新的一年到来了,我要做的第一件事是放弃……
  5. 字节跳动证实28岁员工离世;《英雄联盟》回应服务器崩了:官方直接回退了旧版本;Deno 1.19 发布|极客头条...
  6. hdu 1251 字典树,指针版
  7. 2nbsp;时间管理和内存管理
  8. php json 存储数据格式,文件存储(一):通过 JSON 格式序列化文本数据
  9. C语言从入门到精通需要多久?你真的知道吗!
  10. 【C语言】标准内容介绍(C99)
  11. 兜兜转转 - 2019开启CSDN博客的新篇章
  12. chrome18-使用network waterfall分析页面载入性能
  13. properties解耦数据库参数和SQL参数的传递
  14. 基于FPGA的UART串口通信实验(VHDL语言实现)
  15. 川土微数字隔离器CA-IS36XX高性能数字隔离器 可替代TI ADI MAX等
  16. 网易云音乐热评的规律,44万条数据告诉你
  17. 2019组队赛第二场(ACM International Collegiate Programming Contest, Arabella Collegiate 解题报告 Apare_xzc
  18. 基于timestamp和nonce的防止重放攻击方案
  19. git rebase 简介
  20. (蓝桥杯嵌入式)LED模块

热门文章

  1. python3.6实现的A星算法
  2. YOLO系列目标检测算法-YOLOv2
  3. Java语言学习指导与习题解答_Java语言程序设计(第3版)学习指导与习题解析
  4. 华为悦盒E6108无线投屏-机顶盒连接wifi-我的盒子-DLNA-手机视频有TV标识-点击TV标识
  5. C语言打印100以内素数(开根号法)
  6. IAR EWARM 破解方法
  7. android随机抽奖代码_Android自定义效果——随机抽奖
  8. python提取pdf表格数据 无边框_Python使用Tabula提取PDF表格数据
  9. 目前颜值最高的开源BI工具-Superset
  10. 移动办公平台忘记密码怎么办?移动办公平台下载