cc2530/z-stack应用笔记

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的定时任务推送到应用层。

实现步骤:

  1. hal_drivers.h创建一个20ms的事件标志;
#define HAL_KEY_EVENT                       0x0010
#define HAL_20MS_EVENT                   	0x0008
  1. 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;
  }
  1. 驱动中如何触发定时器
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;获得电压值 ,最后就将电池电压值发送给协调器。在电池电量比较的充足的时候,这个测得的电压值还是比较准确的。

https://e2echina.ti.com/support/wireless-connectivity/zigbee-and-thread/f/zigbee-thread-forum/139351/cc2530/

睡眠

使能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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值