|
在前面的笔记(五)中,我们已经对物理层的基本概念做了详细的介绍。本篇可作为其理论知识的实践篇,从一个基本的字符串“feibit”的发送与接收来学习CC2530的物理层收发功能,看看这个物理层“小弟”到底是怎么干活的。
另外,要说明一点,zigbee本身是一个很复杂的协议,其中任何一层,如果要将每一个细节都讲清楚,都会是很庞大的工作。本文的侧重点在于基本概念的理解,对于IC与Zigbee协议的细节请参考其规格书。
[注:本文源自www.feibit.com--“飞比”Zigbee论坛,为尊重劳动者成果,如需转载请保留此行,并通知作者]
IC的应用并不是一件简单的事情,因为涉及到了很多IC的细节,如果没有详细的说明及应用例程,这些细节有时甚至是无从得知的。还好,相比其他家的无线IC,TI的资料与例程相对丰富,这也是我们选择TI作为开始的主要原因之一。本文中涉及到CC2530的应用部分,有很多是源于TI提供的BasicRF平台的,因为这也是一个开源的平台,方便我们进行移植。
要实现数据的收和发,最早想到的自然是IC的收发机制与相应寄存器的设置。走个捷径,我们从BasicRF的代码入手,了解CC2530的RADIO部分的初始化与读取代码。
首先是初始化的过程,这是保证IC在我们所需要的状态下正常工作的前提。从BasicRF的per_test例程中,我们可以看到,这部分工作主要在以下两个函数中进行,halRfInit与basicRfInit。我们总结下其中与硬件相关的初始化工作如下:
1、设置MCU的晶振频率,BasicRF下所用的函数:halMcuInit
这个工作在开始的时候容易被忽视,设置如果不对,发送的数据包可能是乱的,也可能会有些莫名其妙的问题。
2、设置数据数据传输所使用的频道,halRfSetChannel
这里我们选择频道11,则为2.405G
3、设备的PANID号,halRfSetPanId,我们指定为0x2007
4、设备的短地址,halRfSetShortAddr
由于我们暂时先不涉及网络层组网及地址安排等问题,仿照BasicRF,发送与接收端分别指定如下:
#define TX_ADDR 0x2520
#define RX_ADDR 0xBEEF
5、对于发送端来说,需要增加一个发射功率的设置,halRfSetTxPower
我们按照无PA模式的最大功率4dB进行设置,其实际值为2。
在系统的初始化阶段,执行以上过程,则将CC2530置于准备状态下,随时可用于收发。首先我们来看下数据的发送:
从BasicRF的basicRfSendPacket函数中,我们可以总结出如下的发送流程:- halRfReceiveOn();
- // Wait until the transceiver is idle
- halRfWaitTransceiverReady();
- // Turn off RX frame done interrupt to avoid interference on the SPI interface
- halRfDisableRxInterrupt();
- // write frame to buffer
- halRfWriteTxBuf(buf->dptr, buf->len);
- // Turn on RX frame done interrupt for ACK reception
- halRfEnableRxInterrupt();
- // Send frame with CCA. return FAILED if not successful
- while (halRfTransmit() != SUCCESS);
- halRfReceiveOff();
复制代码 注:为突出基本原理的理解,我会经常把一段代码中的关键部分提取出来进行分析,因为我希望把复杂的事情变得简单,而不是相反!
有兴趣的读者,可以将以上的函数逐一展开,参照CC2530 datasheet进行详细了解。此处我们只关注其数据的发送函数halRfWriteTxBuf
- /*************************************************************************
- * @fn halRfWriteTxBuf
- *
- * @brief Write to TX buffer
- *
- * @param uint8* pData - buffer to write
- * uint8 length - number of bytes
- *
- * @return none
- */
- void halRfWriteTxBuf(uint8* pData, uint8 length)
- {
- uint8 i;
- ISFLUSHTX(); // Making sure that the TX FIFO is empty.
- RFIRQF1 = ~IRQ_TXDONE; // Clear TX done interrupt
- // Insert data
- for(i=0;i<length;i++){
- RFD = pData[ i ];
- }
- }
复制代码 从中我们可以明显地看出,要发送的数据pData,在此函数中,通过逐个写进RFD的方式发送出去了。这不正是我们苦苦寻找的物理层“小弟”吗?不就是他一个一个字节地让“比特”飞翔了起来??
按照我们现在的理解试试能不能把数据发送出去:- uint8 test_str[6]="feibit";
- halRfWriteTxBuf(test_str, 6);
复制代码 难道就这么简单?小心翼翼地编译、下载,在IAR下单步进行跟踪,程序顺利地执行了halRfWriteTxBuf(test_str, 6);这一句。但不要高兴地太早,程序在执行到下面,halRfTransmit()这个函数的时候,进了死循环,一直出不来了。这是怎么回事?
我们看一下到底这个函数在做什么?- /************************************************************************
- * @fn halRfTransmit
- *
- * @brief Transmit frame with Clear Channel Assessment.
- *
- * @param none
- *
- * @return uint8 - SUCCESS or FAILED
- */
- uint8 halRfTransmit(void)
- {
- uint8 status;
- ISTXON(); // Sending
- // Waiting for transmission to finish
- while(!(RFIRQF1 & IRQ_TXDONE) );
- RFIRQF1 = ~IRQ_TXDONE;
- status= SUCCESS;
- return status;
- }
复制代码 程序明显死在了while(!(RFIRQF1 & IRQ_TXDONE) ),这句话是在等什么呢?看datasheet!
很明显,其中的TXDONE位是用来记录发送有没有完成的,如果完成了,则返回一个中断标志,在收到此标志后,程序才会继续。可是我们已经让它发送“feibit”这个字符串了,怎么会一直发不完呢??看来让这个“小弟”干活也不是件容易事。。。
做什么事都不能太急功近利!回顾下笔记(五)中所讲的理论知识,翻一下datasheet,再比较下basicRF中所发送的数据与我们的数据的不同,从中不难看出端倪。
还记得笔记(五)中提到的“付费”信息--payload和“免费赠送”的概念吗?虽然物理层小弟是最底层的工人,但是我们只想传送payload(即字符串“feibit”)也是不行的,必须也要带上赠送部分,这虽然是附加信息,但却是非常重要的。没有了这个,甚至IC连发送完成的中断都不产生了!
复习下802.15.4中的物理层所规定的数据桢结构:
从中我们可以看出,除了PHY Payload外,还有一个很重要的PHR(PHY层头信息),其中包含了物理桢长度信息—Frame Length。
按照这个思路,我们再改一下发送的数据:
uint8 test_str[7]={8,’f’,’e’,’i', ‘b’, ‘i', ‘t’}; //在其头部增加payload长度值8。
halRfWriteTxBuf(test_str, 9); //发送数据长度也相应增加一个。
重新下载程序,发现可以产生发送完成中断了。是不是这样就意味着数据已经发送到了空中呢?我们怎么来验证有没有成功发送呢?TI为我们提供了很好的一个工具—Packet Sniffer!有人翻译为“协议分析仪”,从字面理解也可以叫“数据包嗅探器”,其软件可以在TI的官方网站上下载,专用的硬件网上也可以买得到。不过,我们即将推出的FB2530EB+CC Debugger其实通过简单的跳线及软件设置即可实现packet sniffer的全部功能。其操作详见“CC2530-MDK中文使用说明书”,在此不做赘述。
打开Packet Sniffer后,在“select protocol and chip type”中选择“Generic”。点击开始,同时启动发送端的数据发送,此时在Packet Sniffer中可收到如下数据:
其中的黄色“Payload”部分为“66 65 69 62 69 74”,这实际上就是“feibit”这个字符串的ASIC值。至此,发送的核心部分已经完成。从上面的问题中,我们也可以对CC2530的发送机制有个了解,“发送完成”的中断,是在发送完成了数据桢第一个字节所指定的数量后产生的,这也不难理解,我们之前为什么进了死循环了,因为我们的第一个数据是"f",即0x66,而实际上我们只发送了6个字符出去,当然没有办法产生中断了!这也让我们知道了一点,实际上CC2530从硬件设计上已经支持了802.15.4的协议标准!
附上成功发送的源代码,供大家学习之用:
另外,移植中两个关键步骤的代码:
最小化的contiki操作系统代码:
成功控制CC2530外设的代码:
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
|