cc2530应用笔记
文章目录
说明
CC2530相关应用笔记
z-stack
OSAL - Operating System Abstraction Layer,系统抽象层
- Components
- Projects
主循环
main()->osal_start_system()->osal_run_system()
- Hal_ProcessPoll() - 驱动处理轮询
- tasksEvents[idx] - 任务优先级处理
- osal_pwrmgr_powerconserve() - 任务完成,进入睡眠模式
USE_ICALL
宏定义
USE_ICALL宏定义在CC2630芯片上使用,用于启用或禁用ICall功能。
ICall是一种在CC2630上特有的功能,主要用于简化函数调用,提高代码的执行效率。
如果使用CC2530或其他芯片,则不需要关心USE_ICALL的设置。
AF(Application Framework)应用框架层
-
AF_DataRequest() - 数据发送函数
-
Endpoint -端点
- 0号endpoint是Zigbee device object(ZDO)用的一个端点,
- 255号是用作广播用途,我们可以自己设定的是
- 1~240号
- 其余的保留。
ZCL层
- Addressing
- Profile Identifier
- 0x0000-0x7ffff - Standard application profile
- 0xc000-0xffff - manufacturer specific application profile
- Device Identifier
- 0x0000-0xbfff - Standard device description
- Cluster Identifier
- 0x0000-0x7fff - standard cluster
- 0xfc00-0xffff - manufacturer specific cluster
- Attribute Identifier
- 0x0000-0x4fff - standard attribute
- 0xf000-0xfffe - global attributes
- Command Identifier
- 0xff-0x7f - standard command or manufacture specific command, depending on the Frame control field in the ZCL header
Identifier
- Profile - 应用各领域
- 0x0104 - ZigBee Home Automation
- 0x0105 - Building Automation
- 0x0109 - Smart Energy
- 0xc05e - ZigBee Light Link
- Device Type
- Generic
- Lighting
- Closures
- HVAC
- IAS - Intruder Alarm System/侵入式报警系统
ZCL接口函数
- zcl_Init()
- zcl_event_loop()
- zcl_registerForMsg()
- zcl_registerForMsgExt()
- zcl_registerPlugin()
- zcl_registerCmdList()
- zcl_registerAttrList()
- zcl_registerClusterOptionList()
- zcl_registerValidateAttrData()
- zcl_registerValidateAttrData()
- zcl_registerReadWriteCB()
- zcl_ProcessMessageMSG()
- zcl_SendCommand()
- zcl_SendRead()
- zcl_SendReadRsp()
- zcl_ReadAttrData()
- zcl_SendWriteRequest()
- zcl_SendWriteRsp()
- zcl_SendConfigReportCmd()
- zcl_SendConfigReportRspCmd()
- zcl_SendReadReportCfgCmd()
- zcl_SendReadReportCfgRspCmd()
- zcl_SendReportCmd()
- zcl_SendDefaultRspCmd()
- zcl_SendDiscoverCmdsCmd()
- zcl_SendDiscoverCmdsRspCmd()
- zcl_SendDiscoverAttrsCmd()
- zcl_SendDiscoverAttrsRspCmd()
- zcl_SendDiscoverAttrsExt()
- zcl_SendDiscoverAttrsExtRsp()
- zclParseInReadCmd()
- zclParseInWriteCmd()
- zclParseInConfigReportCmd()
- zclParseInReadReportCfgCmd()
- zclAnalogDataType()
- zclParseInReportCmd()
- zclParseInDiscCmdsCmd() - Discover
- zclParseInDiscAttrsCmd() -
- zclFindCmdRec()
- zclParseHdr()
- zclFindAttrRec()
- zclSetAttrRecList()
- zclReadAttrData()
- zclGetDataTypeLength()
- zclSerializeData()
- zclGetAttrDataLength()
- zcl_getRawAFMsg()
- zcl_getParsedTransSeqNum()
死机
来自与百度 - cc2530 死机:
https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=baidu&wd=cc2530%20%E6%AD%BB%E6%9C%BA&oq=cc25%2526lt%253B0%2520%25E8%25B0%2583%25E8%25AF%2595%25E5%25B7%25A5%25E5%2585%25B7&rsv_pq=8e647187000d6fb5&rsv_t=2d71CUa4%2Fj9yKxvq3jYrlCQIrXR7ITd%2FCuFXMWlUcHWpe9w173vNRfRUldo&rqlang=cn&rsv_enter=1&rsv_dl=tb&rsv_btype=t&inputT=5198&rsv_sug3=60&rsv_sug1=50&rsv_sug7=100&bs=cc2530%20%E8%B0%83%E8%AF%95%E5%B7%A5%E5%85%B7
CC2530死机的主要原因包括内存溢出、串口回调函数重复调用、定时器配置错误等。
内存溢出
在使用CC2530进行大数据通信时,可能会出现内存溢出导致程序卡死的情况。例如,终端设备以1000字节/秒的速度发送数据给协调器设备,通信几个小时后协调器设备出现程序卡死现象,且无法通过看门狗功能重启设备1。
串口回调函数重复调用
在使用CC2530的串口时,协议栈会生成一个串口发送事件,执行该事件时会触发相应的串口回调函数,导致回调函数被重复调用,从而引发程序卡死。解决这个问题的方法是在_hal_uart_dma.c文件中找到HalUARTPollDMA函数,将if (dmaCfg.txMT)判断语句注释掉2。
定时器配置错误
在使用CC2530的定时器时,配置错误也可能导致程序死机。例如,在设置PWM输出时,如果配置了错误的寄存器(如CLKCONCMD),可能会导致程序异常停止3。
调试和排查方法
查看内存使用情况:检查程序的内存使用情况,确保没有内存溢出。
注释掉重复调用的代码:在_hal_uart_dma.c文件中注释掉可能导致重复调用的代码段。
检查定时器配置:仔细检查定时器的配置,确保没有错误的设置导致程序异常。
使用调试工具:利用调试工具如IAR Embedded Workbench进行代码调试,查看具体是哪部分代码导致程序卡死。
通过以上方法,可以有效排查和解决CC2530死机的问题。
内存溢出
串口回调函数重复调用
定时器配置错误
中断
1. IO中断
参考代码:
#include <stdio.h>
#include <string.h>
#include <ioCC2530.h>
#include "hal_mcu.h"
#include "hal_defs.h"
#include "hal_types.h"
#include "hal_board.h"
#include "hal_drivers.h"
#include "hal_mir3da_int.h"
#include "hal_mir3da_evt.h"
#include "hal_mir3da.h"
/**/
#define HAL_GSENSOR_INT_RISING_EDGE 0
#define HAL_GSENSOR_INT_FALLING_EDGE 1
/* CPU port interrupt */
#define HAL_GSENSOR_CPU_PORT_1_IF P1IF
#define HAL_GSENSER_INT1_PORT P1
#define HAL_GSENSOR_INT1_BIT BV(4)
#define HAL_GSENSOR_INT1_SEL P1SEL
#define HAL_GSENSOR_INT1_DIR P1DIR
#define HAL_GSENSER_INT2_PORT P1
#define HAL_GSENSOR_INT2_BIT BV(3)
#define HAL_GSENSOR_INT2_SEL P1SEL
#define HAL_GSENSOR_INT2_DIR P1DIR
/* dege interrupt */
#define HAL_GSENSOR_INT1_EDGEBIT BV(2) // P1ICONH P1.7-P1.4
#define HAL_GSENSOR_INT2_EDGEBIT BV(1) // P1ICONL P1.3-P1.0
/* int1 interrupts */
#define HAL_GSENSOR_INT1_IEN IEN2
#define HAL_GSENSOR_INT1_IENBIT BV(4)
#define HAL_GSENSOR_INT1_ICTL P1IEN
#define HAL_GSENSOR_INT1_ICTLBIT BV(4) // P1IEN - P1.4
#define HAL_GSENSOR_INT1_PXIFG P1IFG
#define HAL_GSENSOR_INT2_IEN IEN2
#define HAL_GSENSOR_INT2_IENBIT BV(4)
#define HAL_GSENSOR_INT2_ICTL P1IEN
#define HAL_GSENSOR_INT2_ICTLBIT BV(3) // P1IEN - P1.3
#define HAL_GSENSOR_INT2_PXIFG P1IFG
/* */
/**************************************************************************************************
* FUNCTIONS - Local
**************************************************************************************************/
static void halProcessGSensorInterrupt(void);
/**************************************************************************************************
* @fn HalGSensorIntInit
*
* @brief Initilize GSensor Interrupt Service 初始化中断服务
*
* @param none
*
* @return None
**************************************************************************************************/
void HalGSensorIntInit( void )
{
// 中断1配置
HAL_GSENSOR_INT1_SEL &= ~(HAL_GSENSOR_INT1_BIT); /* Set pin function to GPIO */
HAL_GSENSOR_INT1_DIR &= ~(HAL_GSENSOR_INT1_BIT); /* Set pin direction to Input */
// INT1-P1.4 (P1.7-P1.4)
PICTL &= ~(HAL_GSENSOR_INT1_EDGEBIT); // 上升沿
// PICTL |= HAL_GSENSOR_INT1_EDGEBIT; // 下将沿
HAL_GSENSOR_INT1_ICTL |= HAL_GSENSOR_INT1_ICTLBIT; // P1 port interrupt Mask(使能P1.4中断)
//HAL_GSENSOR_INT1_IEN |= HAL_GSENSOR_INT1_IENBIT; // Interrupt Enable 2 / port 1 interrupt enable
HAL_GSENSOR_INT1_PXIFG = ~(HAL_GSENSOR_INT1_BIT); // 清除中断标志
// 中断2配置(已经可以工作)
HAL_GSENSOR_INT2_SEL &= ~(HAL_GSENSOR_INT2_BIT); /* Set pin function to GPIO */
HAL_GSENSOR_INT2_DIR &= ~(HAL_GSENSOR_INT2_BIT); /* Set pin direction to Input */
// INT2-P1.3 (P1.3-P1.0)
PICTL &= ~(HAL_GSENSOR_INT2_EDGEBIT); // 上升沿
// PICTL |= HAL_GSENSOR_INT2_EDGEBIT; // 下将沿
HAL_GSENSOR_INT2_ICTL |= HAL_GSENSOR_INT2_ICTLBIT; // P1 port interrupt Mask(使能P1.3中断)
HAL_GSENSOR_INT2_IEN |= HAL_GSENSOR_INT2_IENBIT; // Interrupt Enable 2 /port 1 interrupt enable
HAL_GSENSOR_INT2_PXIFG = ~(HAL_GSENSOR_INT2_BIT); // 清除中断标志
}
/**************************************************************************************************
* @fn halKeyPort1Isr
*
* @brief Port1 ISR
*
* @param
*
* @return
**************************************************************************************************/
HAL_ISR_FUNCTION( halGSensorPortIsr, P1INT_VECTOR )
{
HAL_ENTER_ISR();
if (HAL_GSENSOR_INT2_PXIFG & HAL_GSENSOR_INT2_BIT) /* Interrupt Flag has been set */
{
HAL_GSENSOR_INT2_PXIFG = ~(HAL_GSENSOR_INT2_PXIFG); /* Clear Interrupt Flag */
printf("int2\r\n");
}else
if (HAL_GSENSOR_INT1_PXIFG & HAL_GSENSOR_INT1_BIT) /* Interrupt Flag has been set */
{
HAL_GSENSOR_INT1_PXIFG = ~(HAL_GSENSOR_INT1_PXIFG); /* Clear Interrupt Flag */
printf("int1\r\n");
}
CLEAR_SLEEP_MODE();
HAL_EXIT_ISR();
}
2. 定时器中断
定时器中断基本思路,希望该中断在底层进行工作。不需要发送到应用层。主要参考hal_key.c/h相关代码。
影响文件:
- hal_driver.c/h
- hal_gsensor.c/h
定时20ms中断实现思路
20ms定时器实现,主要在驱动层进行。
在Z-Stack 3.0.1\Components\hal\common\hal_drivers.c
中,存在一个驱动的循环和事件处理函数。个人认为,如何希望能够快速响应20ms的定时任务,最好在驱动层进行处理。不将20ms的定时任务推送到应用层。
实现步骤:
- 在
hal_drivers.h
创建一个20ms的事件标志;
#define HAL_KEY_EVENT 0x0010
#define HAL_20MS_EVENT 0x0008
- 在
hal_drivers.c
创建该事件的响应函数;
if (events & HAL_KEY_EVENT)
{
#if (defined HAL_KEY) && (HAL_KEY == TRUE)
/* Check for keys */
HalKeyPoll();
/* if interrupt disabled, do next polling */
if (!Hal_KeyIntEnable)
{
osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100);
}
#endif
return events ^ HAL_KEY_EVENT;
}
if (events & HAL_20MS_EVENT)
{
Hal20msPoll (); // 20ms中断响应函数
return events ^ HAL_20MS_EVENT;
}
- 驱动中如何触发定时器
osal_start_timerEx (Hal_TaskID, HAL_20MS_EVENT, 20);
电池电压检测
ADC输入
电源电压和温度传感器默认接入了CC2530的ADC输入脚,所以我们不需要外部接口直接可以通过ADC对电压和温度进行检测。
- AIN0-AIN7/P0口 - 接入ADC
- temperature Sensor/TR0.ADCTM&ATEST.ATESTCTRL - 温度传感器接入ADC
- AVDD5/3 - 电源电压进入ADC,检测电源电压
终端在使用的时候用CR2032的纽扣电池供电,空闲的时候能进入PM2模式,有一个电池电压检测的功能。我使用VDD/3通道检测电池电压,是先使用adv = HalAdcRead(HAL_ADC_CHN_VDD3, HAL_ADC_RESOLUTION_8);读取值,然后这样计算BatteryLevel = adv100/1273*115/100;获得电压值 ,最后就将电池电压值发送给协调器。在电池电量比较的充足的时候,这个测得的电压值还是比较准确的。
睡眠
使能POWER_SAVING
宏,该宏影响文件:
-
bdb_touchlink_initiator.c
-
hal_drivers.c
-
hal_mcu.h
-
OSAL.c
-
OSAL_PwrMgr.c
-
OSAL_Timers.c
-
ZDApp.c
hal_sleep.c/h
参考文档:
https://blog.youkuaiyun.com/code_farmer_ou/article/details/78651345
https://blog.youkuaiyun.com/ironboiler/article/details/80591802
睡眠功能暂时还没有实现,可能存在一下问题,需要进一步的验证。
参考文档
*(zigbee学习总结二)Z-stack按键机制 - https://blog.youkuaiyun.com/weixin_30520015/article/details/96086754