打印
[Zigbee]

CC2530 BasicRF协议剖析

[复制链接]
1805|19
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
gwsan|  楼主 | 2019-8-2 12:45 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
1理论讲解
1.1 CC2530 BasicRF工程文件放置说明
当我们获取到CC2530BasicRF工程文件后,打开文件夹一看,比我们之前裸机实验的文件放置复杂得多,要找出light_switch.eww实属不易。下面就来探讨一下它的架构组成,图就是CC2530BasicRF工程文件的分布图。



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


使用特权

评论回复
评论
dirtwillfly 2019-8-3 20:44 回复TA
感谢分享 

相关帖子

沙发
gwsan|  楼主 | 2019-8-2 12:46 | 只看该作者
按照图进行分析,我们来看看各个文件夹里究竟放了些什么东西。

        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)的总工程,也就是将它们包装在一起了。



图 2 ide文件夹
        Source文件夹
顾名思义,这个文件夹就是放置工程的源文件的。它里面有2个子文件夹,分别为:app和components,其中,

(1)app文件夹里是上面所说的3个工程的main函数所在的地方,另外,以后我们的外设底层驱动,基本上都是移植到app文件里面的,以后的实验会有详细的介绍。

(2)components文件夹是BasicRF的一些底层驱动文件,包括:BasicRF协议、hal层驱动文件、加密文件、系统驱动文件等等。


使用特权

评论回复
板凳
gwsan|  楼主 | 2019-8-2 12:46 | 只看该作者
1.2 CC2530 BasicRF工程软件架构

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

图3 CC2530BasicRF工程软件架构

使用特权

评论回复
地板
gwsan|  楼主 | 2019-8-2 12:46 | 只看该作者
        Applicationlayer
用户应用层,它为用户使用Basic RF层和HAL,所提供的接口。

        Basic RF
为双向无线传输提供一种简单的协议。

        Hardware Abstraction Layer(hal)
为无线和板载资源,比如:LCD,UART,buttons,timers等,提供访问接口。

        Hardware
其实,硬件已经不属于BasicRF工程软件的范畴了,它是我们使用BasicRF所需要的硬件平台而已,至于这个平台,已经做好,具体可以看原理图。

总结一下:往后实验的重点就在Application层,main函数就在这里。至于Basic RF层是实现无线通信的简单协议,而Hal层是一些硬件驱动,这两层我们下面会有讲解,但是读者如果没有兴趣研究的话,也没有关系,只需大致知道数据传输和函数的调用关系,在这三个层之间是怎么进行的,就可以了,重点还是Application层,至于这个层,我们以后的实验都会详细讲解的,当然下面我们也会作理论讲解。


使用特权

评论回复
5
gwsan|  楼主 | 2019-8-2 12:47 | 只看该作者
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里面就可以选择。



图 4 Option for node“light_switch”


使用特权

评论回复
6
gwsan|  楼主 | 2019-8-2 12:47 | 只看该作者
1.3.2 BasicRF工作原理
1.3.2.1启动
(1)板载外设、射频接口、系统时钟、中断等的初始化(halBoardInit()

使用特权

评论回复
7
gwsan|  楼主 | 2019-8-2 12:48 | 只看该作者
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;



图 5 Basic RfCfg_t结构体


使用特权

评论回复
8
gwsan|  楼主 | 2019-8-2 12:48 | 只看该作者
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)

初始化节点和安全密钥


使用特权

评论回复
9
gwsan|  楼主 | 2019-8-2 12:49 | 只看该作者
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)


使用特权

评论回复
10
gwsan|  楼主 | 2019-8-2 12:50 | 只看该作者

写16位PANID到无线电

图 6 BasicRF硬件抽象层

使用特权

评论回复
11
gwsan|  楼主 | 2019-8-2 12:50 | 只看该作者
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 ** and splash screen on LCD
31        utilPrint**("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工作原理里接收的内容;


使用特权

评论回复
12
gwsan|  楼主 | 2019-8-2 12:51 | 只看该作者
下面是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步;

使用特权

评论回复
13
gwsan|  楼主 | 2019-8-2 12:51 | 只看该作者
下面是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个层之间是怎么进行的。


使用特权

评论回复
14
gwsan|  楼主 | 2019-8-2 12:51 | 只看该作者
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。



图7 BasicRF初始化过程


使用特权

评论回复
15
gwsan|  楼主 | 2019-8-2 12:52 | 只看该作者
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,说明数据发送成功。



图8 BasicRF数据发送过程


使用特权

评论回复
16
gwsan|  楼主 | 2019-8-2 12:52 | 只看该作者
1.6.3数据接收

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

图9 BasicRF数据接收过程

使用特权

评论回复
17
gwsan|  楼主 | 2019-8-2 12:53 | 只看该作者
(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的指针,方便用户使用。

使用特权

评论回复
18
gwsan|  楼主 | 2019-8-2 12:53 | 只看该作者
附:相关名称解释
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

使用特权

评论回复
19
manufact| | 2019-8-6 14:48 | 只看该作者
非常感谢楼主的分享!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

68

主题

3426

帖子

1

粉丝