欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

第三部分 进阶篇-第1章 CC2530 BasicRF协议剖析

程序员文章站 2022-06-09 19:29:08
...

1理论讲解

1.1 CC2530 BasicRF工程文件放置说明

当我们获取到CC2530BasicRF工程文件后,打开文件夹一看,比我们之前裸机实验的文件放置复杂得多,要找出light_switch.eww实属不易。下面就来探讨一下它的架构组成,图就是CC2530BasicRF工程文件的分布图。

第三部分 进阶篇-第1章 CC2530 BasicRF协议剖析

图1 CC2530 BasicRF工程文件的分布图

按照图进行分析,我们来看看各个文件夹里究竟放了些什么东西。
 docs文件夹
打开文件夹一看,里面就是这样一个文档:
CC2530_Software_Example.pdf。
而这个文档就是CC2530BasicRF例程的说明书。
 ide文件夹
这个文件夹里面有3个子文件夹,具体如图所示。其中,
(1)setting文件夹里是IAR的相关设置,比如IAR的注释是什么颜色的等等;
(2)srf05_cc2530文件夹里面有CC2530没有加PA(CC2591)时的3个工程,分别是:
light_switch.eww、per_test.eww、spectrum_analyzer.eww。
(3)srf05_cc2530_91文件夹里面有CC2530加PA(CC2591)时的2个工程的hex文件,分
别是:light_switch.hex、per_test.hex。
(4)cc2530_sw_example.eww就是这3个工程(light_switch.eww、per_test.eww、spectrum_analyzer.eww)的总工程,也就是将它们包装在一起了。
第三部分 进阶篇-第1章 CC2530 BasicRF协议剖析

图 2 ide文件夹

 Source文件夹
顾名思义,这个文件夹就是放置工程的源文件的。它里面有2个子文件夹,分别为:app和components,其中,
(1)app文件夹里是上面所说的3个工程的main函数所在的地方,另外,以后我们的外设底层驱动,基本上都是移植到app文件里面的,以后的实验会有详细的介绍。
(2)components文件夹是BasicRF的一些底层驱动文件,包括:BasicRF协议、hal层驱动文件、加密文件、系统驱动文件等等。

1.2 CC2530 BasicRF工程软件架构

当我们知道文件的放置后,我们就来探讨这个工程软件的架构,它就是CC2530BasicRF工程软件架构,如图所示,下面分别介绍各层。

第三部分 进阶篇-第1章 CC2530 BasicRF协议剖析

图3 CC2530BasicRF工程软件架构

 Applicationlayer
用户应用层,它为用户使用Basic RF层和HAL,所提供的接口。
 Basic RF
为双向无线传输提供一种简单的协议。
 Hardware Abstraction Layer(hal)
为无线和板载资源,比如:LCD,UART,buttons,timers等,提供访问接口。
 Hardware
其实,硬件已经不属于BasicRF工程软件的范畴了,它是我们使用BasicRF所需要的硬件平台而已,至于这个平台,已经做好,具体可以看原理图。
总结一下:往后实验的重点就在Application层,main函数就在这里。至于Basic RF层是实现无线通信的简单协议,而Hal层是一些硬件驱动,这两层我们下面会有讲解,但是读者如果没有兴趣研究的话,也没有关系,只需大致知道数据传输和函数的调用关系,在这三个层之间是怎么进行的,就可以了,重点还是Application层,至于这个层,我们以后的实验都会详细讲解的,当然下面我们也会作理论讲解。

1.3 Basic RF层介绍

Basic RF是双向无线传输提供一种简单的协议,它并不是协议栈。

1.3.1 BasicRF简介

Basic RF由TI公司提供,它包含了IEEE802.15.4标准的数据包的收发功能但并没有使用到协议栈,它仅仅是是让两个结点进行简单的通信,也就是说Basic RF仅仅是包含着IEEE802.15.4标准的一小部分而已。其主要特点有:
(1)不会自动加入协议、也不会自动扫描其他节点也没有组网指示灯(LED3);
(2)没有协议栈里所说的协调器、路由器或者终端的区分,节点的地位都是相等的;
(3)没有自动重发的功能。BasicRFlayer为双向无线通信提供了一个简单的协议。
通过这个协议能够进行数据的发送和接收。BasicRF还提供了安全通信所使用的CCM-64身份验证和数据加密,它的安全性大家可以通过在工程文件里面定义SECURITY_CCM在Project->Option里面就可以选择。

第三部分 进阶篇-第1章 CC2530 BasicRF协议剖析

图 4 Option for node“light_switch”

1.3.2 BasicRF工作原理

1.3.2.1启动

(1)板载外设、射频接口、系统时钟、中断等的初始化(halBoardInit(););
(2)创建BasicRF数据结构体(basicRfCfg_t,具体见下图5),并初始化其成员;若要加密的话,则更高的层(用户层)会分频一个16字节的**;
(3)BasicRF协议初始化(halRfInit(););

1.3.2.2发送

(1)将刚才配置的Basic RF结构体进行初始化,并为下一步的数据发送创建一个负载缓冲区,这个缓冲区最大为103个字节;
(2)如果要发送数据,就调用basicRfSendPacket(),将数据发送出去。

1.3.2.3接收

(1)通过调用basic RfPacketIs Ready()函数,以查询的方式检测用户层是否接收到数据;
(2)用户层首先创建一个足够大的缓冲区用于接收用户数据,并创建2个字节的缓冲区来存放RSSI值,然后调用basic RfReceive()函数接收数据。

1.3.3 Basic RF API说明

1.3.3.1加密功能

Basic RF提供安全通信所使用的CCM-64身份验证和数据加密。若要使用加密功能,可以通过在工程文件里面定义SECURITY_CCM来实现,具体操作是:在Project->Option里面就可以选择,本次实验并不是什么高度机密,所以在SECURITY_CCM前面带X了。

1.3.3.2数据结构体

下面是BasicRF数据结构体,翻译成中文如图所示。

typedef struct{
uint16myAddr;//16-bitshortaddress(Thisnode’saddress)
uint16panId;//PANID(IDofthePersonalAreaNetworkthisnodeisoperatingon)
uint8channel;//RFChannel(mustbesetbetween11and26)

uint8ackRequest;//Settruetorequestacknowledgementfromdestination
#ifdefSECURITY_CCM
uint8*securityKey;//Pointertothesecuritykeybufferallocatedbythecaller
uint8*securityNonce;//Pointertothesecuritynoncebuffer.Thisisnotusedbythecaller
#endif
}basicRfCfg_t;

第三部分 进阶篇-第1章 CC2530 BasicRF协议剖析

图 5 Basic RfCfg_t结构体

1.3.3.3函数

void basicRfInit(basicRfCfg_t*pRfConfig)
初始化Basic RF的数据结构体,设置通道、短地址和节点PANID,以及配置数据接收中断。不过在调用此函数前,必须先调用halBoardInit()来初始化板载外设和射频接口。
uint8 basicRfSendPacket(uint16 destAddr,uint8* pPayload,uint8 length)
将数据发送到目的地址的节点,发送成功返回successfully,否则返回FAILED。返回successfully意味着:目标确认了,而且收到目的地址的节点发回来的应答信号。
uint8 basicRfPacketIsReady(void)
用于判断用户层是否准备好接收数据,准备好了则返回TRUE。
int8 basicRfGetRssi(void)
返回最后收到的数据包的RSSI(接收信号强度)值。
uint8 basicRfReceive(uint8* pRxData,uint8 len,int16* pRssi)
由用户层调用,用于将basicRF层接收到的数据和RSSI值,存入预先分频好的缓冲区。
void basicRfReceiveOn(void)
由用户层调用,用于打开数据接收器,直到调用basicRfReceiveOff把接收器关掉为止,接收器会一直接收数据。
void basicRfReceiveOff(void)
在不需要接收数据的时候,调用这个函数可以将接收器关闭。
void basicRfSecurityInit(basicRfCfg_t*pConfig)
初始化节点和安全**

1.4 硬件抽象层(hal)介绍

1.4.1 Hal层简介

Hal层为无线和板载资源,比如:LCD,UART,buttons,timers等,提供访问接口。Hal层是介于软件跟硬件之间,是驱动硬件资源最直接的层,所以,有关系统时钟、中断、板载资源等等,都由hal层管理,具体请看图。

1.4.2 Hal层API说明

1.4.2.1包括的头文件

hal_rf.h
hal_rf_security.h

1.4.2.2函数

uint8 halRfInit(void)
用于给无线电上电、通过相关寄存器的设置来配置无线电、使能自动应答和配置无线电IO,它是在调用halBoardInit()后才可以调用此函数。
uint8 halRfSetPower(uint8power)
设置无线电发送电压
uint8 halRfTransmit(void)
传输帧
void halRfSetGain(uint8gainMode)
集增益模式,只在使用外部LNA/PA时使用。
uint8 halRfGetChipId(void)
获取无线电芯片的ID。
uint8 halRfGetChipVer(void)
获取无线电芯片的版本。
uint8 halRfGetRandomByte(void)
获取随机字节。
uint8 halRfGetRssiOffset(void)
获取无线电RSSI偏移值。
void halRfWriteTxBuf(uint8*data,uint8length)
将存储器里的数据写到无线电的发送缓冲区里。
void halRfReadRxBuf(uint8*data,uint8length)
将无线电的接收缓冲区里的数据读到存储器里。
void halRfWaitTransceiverReady(void)
等待发送器准备完毕。
void halRfReceiveOn(void)
关闭无线电接收器。
void halRfReceiveOff(void)
打开无线电接收器。
void halRfDisableRxInterrupt(void)
关接收中断。
void halRfEnableRxInterrupt(void)
使能接收中断。
void halRfRxInterruptConfig(ISR_FUNC_PTRpf)
配置接收中断,以及设置本函数在中断时被调用
void halRfSetChannel(uint8channel)
设置视频通道,通道必须在11~26之间。
void halRfSetShortAddr(uint16shortAddr)
写16位短地址到无线电。
void halRfSetPanId(uint16PanId)
写16位PANID到无线电

第三部分 进阶篇-第1章 CC2530 BasicRF协议剖析

图 6 BasicRF硬件抽象层

1.5 用户层(Applicationlayer)

下面只会从理论上来讲解用户层,往后的实验会结合实际例子来讲解。我们以后的外设驱动,基本上都是放在用户层,不过也有例外,如LCD,我们就最好放在hal层,保持跟官方使用LCD的方法一致;而整个BasicRF工程的main函数就放在用户层,我们以后修改代码基本上都在用户层文件里进行,如light_switch工程,就在用户层文件夹里的light_switch.c里进行修改。下面我们就以light_switch.c为例子来讲解用户层。
下面是light_switch工程的light_switch.c中的main函数:

1   void main(void)
2   {
3   uint8 appMode=NONE;//不设置模块的模式
4
5   //创建BasicRF数据结构体(basicRfCfg_t),并初始化其成员
6   basicRfConfig.panId=PAN_ID; //用户的PAN_ID
7   basicRfConfig.channel=RF_CHANNEL; //RF通道必须在-26之间
8   basicRfConfig.ackRequest=TRUE; //目标确认设置
9   
10  #ifdefSECURITY_CCM
11  basicRfConfig.securityKey=key;
12  //若要加密的话,则频一个16字节节的**;
13 
14  #endif
15
16  //Initaliseboardperipherals
17  halBoardInit();
18  //板载外设、射频接口、系统时钟、中断的初始化---byCavani
19  
20  halJoystickInit();
21
22  //Initalisehal_rf
23  if(halRfInit()==FAILED){//BasicRF协议初始化(halRfInit();)
24  HAL_ASSERT(FALSE);
25  }
26
27  //Indicate that device is powered
28  halLedSet(1);
29
30  //Print Logo and splash screen on LCD
31  utilPrintLogo("Light Switch");
32
33  //Wait for user to press S1 to enter menu
34  while(halButtonPushed()!=HAL_BUTTON_1);
35  halMcuWaitMs(350);
36  halLcdClear();
37
38  //Set application role
39  appMode=appSelectMode();
40  halLcdClear();
41
42  //Transmitter application
43  if(appMode==SWITCH){
44  //No return from here
45  appSwitch();
46  }
47  //Receiver application
48  else if(appMode==LIGHT){
49  //No return from here
50  appLight();
51  }
52  //Role is undefined .This code should not be reached
53  HAL_ASSERT(FALSE);
54  }

第6~14行:就是Basic RF工作原理里启动的第2步;
第17行:就是Basic RF工作原理里启动的第1步;
第23~25行:就是Basic RF工作原理里启动的第3步;
第45行:数据发送函数,就是Basic RF工作原理里发送的内容;
第50行:数据接收函数,就是Basic RF工作原理里接收的内容;
下面是light_switch工程的light_switch.c中的发送函数“appSwitch()函数”

1   static void appSwitch()
2   {
3   halLcdWriteLine(HAL_LCD_LINE_1,"Switch");
4   halLcdWriteLine(HAL_LCD_LINE_2,"JoystickPush");
5   halLcdWriteLine(HAL_LCD_LINE_3,"SendCommand");
6   #ifdefASSY_EXP4618_CC2420
7   halLcdClearLine(1);
8   halLcdWriteSymbol(HAL_LCD_SYMBOL_TX,1);
9   #endif
10
11  pTxData[0]=LIGHT_TOGGLE_CMD;
12
13  //Initialize BasicRF
14  basicRfConfig.myAddr=SWITCH_ADDR;
15  if(basicRfInit(&basicRfConfig)==FAILED){
16  //将刚才配置的Basic RF结构体进行初始化,并为下一步的数据发送创建一个负载
17  缓冲区,这个缓冲区最大为103个字节;
18 
19  HAL_ASSERT(FALSE);
20}
21
22  //Keep Receiver off when not needed to save power
23  basicRfReceiveOff();
24
25  //Main loop
26  while(TRUE){
27  if(halJoystickPushed()){
28
29  basicRfSendPacket(LIGHT_ADDR,pTxData,APP_PAYLOAD_LENGTH);
30  //如果要发送数据,就调用basicR
31  fSendPacket(),将数据发送出去。
32
33
34  //PutMCUtosleep.Itwillwakeuponjoystickinterrupt
35  halIntOff();
36  halMcuSetLowPowerMode(HAL_MCU_LPM_3);//Willturnon global
37  
38  //interruptenable
39  halIntOn();
40
41  }
42  }
43  }

第14~20行:就是BasicRF工作原理里发送的第1步;
第29~30行:就是BasicRF工作原理里发送的第2步;

下面是light_switch工程的light_switch.c中的接收函数“appLight()函数”:

1   static void appLight()
2   {
3   halLcdWriteLine(HAL_LCD_LINE_1,"Light");
4   halLcdWriteLine(HAL_LCD_LINE_2,"Ready");
5
6   #ifdefASSY_EXP4618_CC2420
7   halLcdClearLine(1);
8   halLcdWriteSymbol(HAL_LCD_SYMBOL_RX,1);
9   #endif
10
11  //InitializeBasicRF
12  basicRfConfig.myAddr=LIGHT_ADDR;
13  if(basicRfInit(&basicRfConfig)==FAILED){
14  HAL_ASSERT(FALSE);
15  }
16  basicRfReceiveOn();
17
18  //Mainloop
19  while(TRUE){
20  while(!basicRfPacketIsReady());
21  //通过调用basicRfPacketIsReady()函数,以查询的方式检测用户层是否接收数据;
22  
23  
24
25  if(basicRfReceive(pRxData,APP_PAYLOAD_LENGTH,NULL)>0){
26  //用户层首先创建一个足够大的缓冲区用于接收用户数据,并创建2个字节的缓冲
27  区来存放R28SSI值,然后调用basicRfReceive()函数接收数据。
29  
30  if(pRxData[0]==LIGHT_TOGGLE_CMD){
31  halLedToggle(1);
32  }
33  }
34  }
35  }

第20行:就是Basic RF工作原理里接收的第1步;
第25行:就是Basic RF工作原理里接收的第2步;
其实,上面只是简单地讲解没有修改过的light_switch工程的light_switch.c,读者关键是要从中读懂BasicRF的工作原理。好啦,上面分别讲解用户层、BasicRF层、hal层,下面我们就来个总结,讲解数据传输和函数的调用关系,在这3个层之间是怎么进行的。

1.6 Basic RF操作总结

1.6.1初始化

下图描述了在初始化时,各层的函数的调用关系:
(1)首先,用户层调用halBoardInit()函数,初始化hal层的硬件外设和配置IO端口;
(2)然后,用户层初始化basicRfCfg_t结构体成员;
(3)接着,用户层调用basicRfInit()函数,而basicRfInit()函数就会调用halRFInit()函数,将刚才的basicRfCfg_t结构体写到BasicRF层,并使能中断;
(4)另外,halRFInit()函数也会同时将通道、短地址、个域网ID写到CC2530。

第三部分 进阶篇-第1章 CC2530 BasicRF协议剖析

图7 BasicRF初始化过程

1.6.2数据发送

下图描述了在发送数据时,各层的函数的调用关系和数据传输之间的关系:
(1)首先,用户层调用basicRfSend()函数,将目的地址、数据缓冲区指针、数据缓冲区长度发给BasicRF层;
(2)然后,BasicRF层调用halRfWaitTransceiverReady()函数,检查SFD是否准备好;
(3)接着,BasicRF层调用basicRfBuildMpdu()函数,在BasicRF层建立一个缓冲区存放即将要发送出去的数据。
(4)接着,BasicRF层调用halRfWriteTxBuf()函数,将停留在BasicRF层缓冲区的数据传输到hal层的CC2530发送FIFO缓冲区里。
(5)接着,BasicRF层调用halRfTransmit()函数,通知hal层调用ISTXON()将数据发送出去。
(6)接着,halRfTransmit()函数会等待数据发送完毕,并从hal层获取发送结果Status给BasicRF层。
(7)接着,BasicRF层将等待由basicRfSend()函数返回的应答数据包;
(8)最后,如果BasicRF层从basicRfSend()函数里收到应答数据包,就往用户层发送SUCCESS,说明数据发送成功。

第三部分 进阶篇-第1章 CC2530 BasicRF协议剖析

图8 BasicRF数据发送过程

1.6.3数据接收

下图描述了在接收数据时,各层的函数的调用关系和数据传输之间的关系:

第三部分 进阶篇-第1章 CC2530 BasicRF协议剖析

图9 BasicRF数据接收过程

(1)首先,当hal层接收完一个数据包之后,就会自动申请中断,这时中断服务函basicRfRxFrmDoneIsr()(在BasicRF层里)就会停止BasicRF层去读取hal层接收到的数据;
(2)然后,BasicRF层就会调用halRfReadRxBuf(length,1)函数,从CC2530接收缓冲区里的第一个字节:接收帧;
(3)接着,BasicRF层调用halRfRecvFrame(rxMpdu,length)函数,将hal层接收缓冲区里所有数据读取到BasicRF层;
(4)接着,CC25320会自动发送应答信号ACK给发送端(如果使能了自动应答的话),同时,BasicRF层将会识别接收帧的地址,如果CRC正确则被接收。
(5)接着,BasicRF层就会对数据包的FCS和***进行检测,如果它们跟预期的rxiisReady标志一致的话,那么新的数据包就会被接收下来,并往用户层发送TRUE。
(6)接着,用户层将会通过basicRfPacketIsReady()函数,不断查询rxiisReady标志;
(7)接着,当basicRfPacketIsReady()返回TRUE,用户层就会调用basicRfReceive()函数,从BasicRF层获取新的数据和RSSI值;
(8)最后,basicRfReceive()函数,就会将数据和RSSI值存储到存储器内,并为这些数据提供一个名为pData的指针,方便用户使用。

附:相关名称解释

API-ApplicationProgrammingInterface
CBC-MAC-CipherBlockChainingMessageAuthenticationCode
CCM-CounterwithCBC-MAC(modeofoperation)
CCM*-ExtensionofCCM
FCS-FrameCheckSequence
HAL-HardwareAbstractionLayer
IO-Input/Output
MIC-MessageIntegrityCode
MPDU-MACProtocolDataUnit
PAN-PersonalAreaNetwork
PER-PacketErrorRate
RF-RadioFrequency
RSSI-ReceivedSignalStrengthIndicator
SFD-StartofFrameDelimiter

【注】本文分析的文件是TI的源文件–CC2530 BasicRF,有需要的请自行下载。

CC2530 BasicRF下载地址

GitHub下载地址

第三部分 进阶篇-第1章 CC2530 BasicRF协议剖析

相关标签: BasicRF CC2530