This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

求助,关于CC2530在osal调度下PM2模式休眠和工作时间问题?

Other Parts Discussed in Thread: CC2530, Z-STACK

请教一个问题
cc2530(zstack-2.2.2-1.3.0),osal调度的PM2模式,如何自定义休眠时间和工作时间?


我现在是在ZED的

void zb_HandleOsalEvent( uint16 event )

{

.................


if ( event & MY_PERSONAL_ENTERPM2_EVT ) 
{
//P1_1 ^= 1;
myApp_StopReporting();
NLME_SetPollRate(myEnterpm2Period); // 60 000ms = 1 min

osal_start_timerEx( sapi_TaskID, MY_PERSONAL_ENTERPM2_EVT, myEnterpm2Period );
}

}


static uint16 myEnterpm2Period = 30000; 的时候,休眠30s,发送20s

static uint16 myEnterpm2Period = 40000; 的时候,休眠40s, 还是 发送20s

static uint16 myEnterpm2Period = 60000; 貌似直接就乱套了,也不休眠了,总是在发送


休眠时间 和 工作的时间,究竟怎么来做限制?

而在osal下,最大的休眠时间应该是65ms左右才对啊?

那工作时间,又该怎么来约束?


  • OSAL调度系统的休眠时间并不是自己随便可以设置的,而是osal调度系统每次都是以最近一次要发生事件的timeout作为本次的休眠时间,如果你的系统有一个最小的30ms事件的周期性的发生,那么你的休眠时间只能是30ms了。

  •     您说的我都明白,但是我在ZED的void zb_HandleOsalEvent( uint16 event )里面。

        有一个20ms的事件MY_PERSONAL_COLLECT_345_EVT

        我还有一个200ms的事件MY_PERSONAL_REPORT_345_EVT

        我还设置了另外一个事件MY_PERSONAL_ENTERPM2_EVT(比如说设置为40s),用于进入pm2状态。进入MY_PERSONAL_ENTERPM2_EVT事件以后,我利用myApp_StopReporting();来关掉20ms和200ms的定时器事件,但是不关40s的定时器事件。然后设置三个全部为0,这样让osal自动进入任务调度,按照您的说法,现在获取的休眠时间就应该是40s了

        当唤醒以后,我在hal_sleep.c里面HAL_SLEEP_SET_POWER_MODE(halPwrMgtMode);之后,设置正常的poll_rate值(1000,100,100),并且开启myApp_StartReporting();来开启20ms和200ms的定时器事件。然后等40s还有,再次进入我的MY_PERSONAL_ENTERPM2_EVT(40s)事件,由此循环。

        按照这个逻辑,如果我的MY_PERSONAL_ENTERPM2_EVT设置为40s,那是不是应该工作40s,然后进入pm2模式休眠40s,唤醒后再工作40s,由此循环?

        但事实上,如果这个值设置为40s了,实际上是工作20s,然后休眠40s。如果这个值设置为60s了,完全就没有休眠了,基本上都是工作状态。这是为什么呢???

    --------------------------------------------------------------------------------------------------------------------------------------------------------

    void zb_HandleOsalEvent( uint16 event )

    {

    static uint8 pData[2];
    uint8 pDataForExtAdc[2];


    if ( event & MY_START_EVT )
    {
    zb_StartRequest();
    }
    if ( event & MY_REPORT_TEMP_EVT )
    {
    // Read and report temperature value
    pData[0] = TEMP_REPORT;
    pData[1] = myApp_ReadTemperature();
    zb_SendDataRequest( 0xFFFE, SENSOR_REPORT_ADC_CMD_ID2, 2, pData, 0, AF_ACK_REQUEST, 0 );
    osal_start_timerEx( sapi_TaskID, MY_REPORT_TEMP_EVT, myTempReportPeriod );
    }

    if ( event & MY_REPORT_BATT_EVT )
    {
    // Read battery value
    // If battery level low, report battery value
    pData[0] = BATTERY_REPORT;
    pData[1] = myApp_ReadExtBattery(); // myApp_ReadBattery();
    zb_SendDataRequest( 0xFFFE, SENSOR_REPORT_ADC_CMD_ID2, 2, pData, 0, AF_ACK_REQUEST, 0 );
    osal_start_timerEx( sapi_TaskID, MY_REPORT_BATT_EVT, myBatteryCheckPeriod );
    }


    /*-------------------------------------------*/ 

    if ( event & MY_PERSONAL_COLLECT_345_EVT )
    {
    myApp_Read345();


    P0DIR |= 0x20;
    P0SEL &= ~0x20;
    P0_5 ^= 1;


    osal_start_timerEx( sapi_TaskID, MY_PERSONAL_COLLECT_345_EVT, myAdxl345CollectPeriod );
    }
    if ( event & MY_PERSONAL_REPORT_345_EVT )
    {
    // Read battery value
    // If battery level low, report battery value

    if( InitTimerFlag == 0x00 )
    {
    InitTimerFlag = 0x01;

    P1DIR |= 0x02;
    P1SEL &= ~0x02;
    //P1_1 = 0;
    P0DIR |= 0x40;
    P0SEL &= ~0x40;
    //P0_6 = 0;

    }


    // P1_1 ^= 1;
    if ( ( (BufHead - BufTail) > 10) || ( ( (BufHead - BufTail)&0x7F) > 10) )
    {
    osal_memcpy(PacketData+1,&PreSendValue.PreSend[BufTail*4],40);
    PacketData[0]= ADXL345_REPORT;

    zb_SendDataRequest( 0xFFFE, SENSOR_REPORT_ADC_CMD_ID2, 41, PacketData , 0,AF_ACK_REQUEST , 0 ); //AF_ACK_REQUEST
    BufTail += 10;
    BufTail %= 512;

    P0DIR |= 0x40;
    P0SEL &= ~0x40;
    P0_6 ^= 1;

    }

    osal_start_timerEx( sapi_TaskID, MY_PERSONAL_REPORT_345_EVT, myAdxl345ReportPeriod );

    Delay_1u(1);

    //不发这个了,发一个counter
    sprintf(SendCnt,"%d\r",SendCounter);//将数值格式化为字符串
    HalUARTWrite(0, (unsigned char*)&SendCnt,(unsigned char)osal_strlen( (void*)SendCnt ));
    SendCounter += 40;
    SendCounter %= 0xFFFF ;
    }

    if ( event & MY_PERSONAL_ENTERPM2_EVT ) // stop里面,不设置此事件(undo)
    {

    P0DIR |= 0x10;
    P0SEL &= ~0x10;
    P0_4 ^= 1;

    myApp_StopReporting();

    NLME_SetPollRate( 0 ); // 60 000ms = 1 min
    NLME_SetQueuedPollRate( 0 );
    NLME_SetResponseRate( 0 );

    osal_start_timerEx( sapi_TaskID, MY_PERSONAL_ENTERPM2_EVT, myEnterpm2Period );
    }

    /*-------------------------------------------*/
    if ( event & MY_FIND_COLLECTOR_EVT )
    {
    // Find and bind to a collector device
    zb_BindDevice( TRUE, SENSOR_REPORT_ADC_CMD_ID2, (uint8 *)NULL );
    }

    } // void zb_HandleOsalEvent( uint16 event )

    #define MY_PERSONAL_REPORT_VOLTAGE_EVT 0x0010 // 上报的采集电压值
    #define MY_PERSONAL_COLLECT_345_EVT 0x0020 
    #define MY_PERSONAL_REPORT_345_EVT 0x0040 // 上报的345值
    #define MY_PERSONAL_ENTERPM2_EVT 0x0080

    static uint16 myAdxl345CollectPeriod = 20;
    static uint16 myAdxl345ReportPeriod = 200; // milliseconds毫秒
    static uint16 myEnterpm2Period = 60000;

    void myApp_StopReporting( void )
    {
    osal_stop_timerEx( sapi_TaskID, MY_PERSONAL_REPORT_345_EVT );
    osal_stop_timerEx( sapi_TaskID, MY_PERSONAL_COLLECT_345_EVT );
    }


    void halSleep( uint16 osal_timeout )
    {
    static uint32 timeout; // add static for debug
    uint32 macTimeout = 0;

    halAccumulatedSleepTime = 0;

    /* get next OSAL timer expiration converted to 320 usec units */
    timeout = HAL_SLEEP_MS_TO_320US(osal_timeout);
    if (timeout == 0)
    {
    timeout = MAC_PwrNextTimeout();
    }
    else
    {
    /* get next MAC timer expiration */
    macTimeout = MAC_PwrNextTimeout();

    /* get lesser of two timeouts */
    if ((macTimeout != 0) && (macTimeout < timeout))
    {
    timeout = macTimeout;
    }
    }

    /* HAL_SLEEP_PM2 is entered only if the timeout is zero and
    * the device is a stimulated device.
    */
    halPwrMgtMode = (timeout == 0) ? HAL_SLEEP_DEEP : HAL_SLEEP_TIMER;

    /* DEEP sleep can only be entered when zgPollRate == 0.
    * This is to eliminate any possibility of entering PM3 between
    * two network timers.
    */
    #if !defined (RTR_NWK) && defined (NWK_AUTO_POLL)
    if ((timeout > HAL_SLEEP_MS_TO_320US(PM_MIN_SLEEP_TIME)) ||
    (timeout == 0 && zgPollRate == 0))
    #else
    if ((timeout > HAL_SLEEP_MS_TO_320US(PM_MIN_SLEEP_TIME)) ||
    (timeout == 0))
    #endif
    {
    halIntState_t ien0, ien1, ien2;

    HAL_ASSERT(HAL_INTERRUPTS_ARE_ENABLED());
    HAL_DISABLE_INTERRUPTS();

    /* always use "deep sleep" to turn off radio VREG on CC2530 */
    if (MAC_PwrOffReq(MAC_PWR_SLEEP_DEEP) == MAC_SUCCESS)
    {
    #if ((defined HAL_KEY) && (HAL_KEY == TRUE))
    /* get peripherals ready for sleep */
    HalKeyEnterSleep();
    #endif

    #ifdef HAL_SLEEP_DEBUG_LED
    HAL_TURN_OFF_LED3();
    #else
    /* use this to turn LEDs off during sleep */
    HalLedEnterSleep();
    #endif

    /* enable sleep timer interrupt */
    if (timeout != 0)
    {
    if (timeout > HAL_SLEEP_MS_TO_320US( MAX_SLEEP_TIME ))
    {
    timeout -= HAL_SLEEP_MS_TO_320US( MAX_SLEEP_TIME );
    halSleepSetTimer(HAL_SLEEP_MS_TO_320US( MAX_SLEEP_TIME ));
    }
    else
    {
    /* set sleep timer */
    halSleepSetTimer(timeout);
    }

    /* set up sleep timer interrupt */
    HAL_SLEEP_TIMER_CLEAR_INT();
    HAL_SLEEP_TIMER_ENABLE_INT();
    }

    #ifdef HAL_SLEEP_DEBUG_LED
    if (halPwrMgtMode == CC2530_PM1)
    {
    HAL_TURN_ON_LED1();
    }
    else
    {
    HAL_TURN_OFF_LED1();
    }
    #endif

    /* save interrupt enable registers and disable all interrupts */
    HAL_SLEEP_IE_BACKUP_AND_DISABLE(ien0, ien1, ien2);
    HAL_ENABLE_INTERRUPTS();

    /*---------------------------------*/
    // P1DIR |= 0x02;
    // P1SEL &= ~0x02;
    // P1_1 ^= 1;
    /*P2口*/
    P2SEL &= ~0x07; // 通用io
    P2DIR &= ~0x09; // 设置为输入
    P2INP |= 0x19;
    P2 = 0x00;
    /*P1口*/
    P1SEL &= ~0xFF; // 通用io
    P1DIR &= ~0xFF; // 设置为输入
    P1INP |= 0xFC;
    P1 = 0x00;
    /*P0口*/
    P0SEL &= ~0xFF; // 通用io
    P0DIR &= ~0xFF; // 设置为输入
    P0INP |= 0xFF;
    P0 = 0x00;

    // P1DIR |= 0x03;
    // P1SEL &= ~0x03;
    // P1_0 = 0;
    // P1_1 = 0;

    // P0DIR &= ~0x03;
    // P0SEL &= ~0x03;
    // P0INP |= 0x03;
    // P2INP &= ~0x20; //P0口bu拉
    // P0_0 = 1;
    // P0_1 = 1;

    OBSSEL1 |= 0x80;
    OBSSEL2 |= 0x80;
    OBSSEL3 |= 0x80;
    OBSSEL4 |= 0x80;
    OBSSEL5 |= 0x80;
    //
    // TR0 |= 0x01;
    /*---------------------------------*/
    /* set CC2530 power mode, interrupt is disabled after this function */
    HAL_SLEEP_SET_POWER_MODE(halPwrMgtMode);

    /*The macro HAL_SLEEP_SET_POWER_MODE() shuts down the radio and core.
    Try setting a breakpoint at this location to determine if sleep is being
    disallowed at some earlier point.*/

    /* the interrupt is disabled - see halSetSleepMode() */

    /* restore interrupt enable registers */
    HAL_SLEEP_IE_RESTORE(ien0, ien1, ien2);

    /* disable sleep timer interrupt */
    HAL_SLEEP_TIMER_DISABLE_INT();

    /* Calculate timer elasped */
    halAccumulatedSleepTime += (HalTimerElapsed() / TICK_COUNT);


    #ifdef HAL_SLEEP_DEBUG_LED
    HAL_TURN_ON_LED3();
    #else
    /* use this to turn LEDs back on after sleep */
    HalLedExitSleep();
    #endif

    #if ((defined HAL_KEY) && (HAL_KEY == TRUE))
    /* handle peripherals */
    (void)HalKeyExitSleep();
    #endif

    /* power on the MAC; blocks until completion */
    MAC_PwrOnReq();

    HAL_ENABLE_INTERRUPTS();

    /* For CC2530, T2 interrupt won抰 be generated when the current count is greater than
    * the comparator. The interrupt is only generated when the current count is equal to
    * the comparator. When the CC2530 is waking up from sleep, there is a small window
    * that the count may be grater than the comparator, therefore, missing the interrupt.
    * This workaround will call the T2 ISR when the current T2 count is greater than the
    * comparator. The problem only occurs when POWER_SAVING is turned on, i.e. the 32KHz
    * drives the chip in sleep and SYNC start is used.
    */
    macMcuTimer2OverflowWorkaround();
    /*----------------------*/
    P1DIR |= 0x02;
    P1SEL &= ~0x02;
    P1_1 ^= 1;
    NLME_SetPollRate( 1000 ); // 休眠完了设置为正常的poll时间间隔
    NLME_SetQueuedPollRate( 100 );
    NLME_SetResponseRate( 100 );

    /*重新初始化每个引脚*/
    /*P0口上有P0.0、P0.1拨码开关使用时初始化|P0.2(RX)、P0.3(TX)【需要】初始化|P0.4(校准ADXL345外部中断按键)使用时初始化|
    P0.5、P0.6、P0.7未使用空闲【unused pins 处理】*/
    P0SEL |= 0x0C;

    P0DIR &= ~0xE0;
    P0SEL &= ~0xE0;
    P0INP &= ~0xE0;
    P2INP &= ~0x20;
    /*P2口上有个LED灯*/
    P1DIR |= 0x01;
    P1SEL &= ~0x01;
    /*P1口上P1.0(ADXL345 Supply)、P1.1、P1.2(SCL)、P1.3(SDA)使用时初始化|P1.4~P1.7作为sniffer引脚使用,可不自行初始化*/
    myApp_StartReporting(); //解决外部定义问题
    /*----------------------*/
    }
    else
    {
    HAL_ENABLE_INTERRUPTS();
    }
    }
    }


    void myApp_StartReporting( void )
    {
    osal_start_timerEx( sapi_TaskID, MY_PERSONAL_COLLECT_345_EVT, myAdxl345CollectPeriod ); 

    osal_start_timerEx( sapi_TaskID, MY_PERSONAL_REPORT_345_EVT, myAdxl345ReportPeriod );
    }


  • 如果你开启了power_saving功能以后,在20ms 200ms的工作过程中也会再休眠和活动状态间切换的。

    能否把时间改短一点,测试下?

  • 您好,我有个问题,在对ZStack的SampleApp的终端节点设置进入PM2工作模式时,测得的工作电流始终无法降低,正常工作时测得的电流为12mA,休眠时测得的电流为11mA或者12mA(测试方法是用万用表串入电源输入电路中,观察电流值)。

    我设置终端节点设置进入PM2工作模式的步骤如下:

    1.打开POWER_SAVING 预编译

    2.f8wConfig_cfg 中的RFD_RCVC_ALWAYS_ON=FALSE
    3.f8wConfig_cfg中四个DPoll_RATE设为0

    4.ZGlobals.c中三个PollRate设为0

    5.Onboard.c文件中,OnboardKeyIntEnable=HAL_KEY_INTERUPT_ENABLE

    6.hal_drivers.c中if(!Hal_KeyIntEnable)中的语句关掉

    7.osal_pwrmgr_init(void)中pwrmgr_attribute.pwrmgr_device=PWRMGR_BATTERY

    在网上搜了不少方法,也参考了TI官方的文档“Power Management For The CC2530.pdf”,以及“Measuring Power Consumption of CC2530 with Z-Stack(swra292AN079).PDF”。

    按照上述设置,感觉终端节点并未进入睡眠状态,能不能给一个比较详细的设置方法呢?

  • 大侠,能不能给个简要的设置进入PM2模式的步骤啊?我按照下面的步骤设置,测试结果仍然是12mA左右,不知道为什么无法进入低功耗模式。


    1.开启POWER_SAVING 预编译

    2.f8wConfig_cfg 中的RFD_RCVC_ALWAYS_ON=FALSE

    3.f8wConfig_cfg中四个DPoll_RATE设为0

    4.ZGlobals.c中三个PollRate设为0

    5.Onboard.c文件中,OnboardKeyIntEnable=HAL_KEY_INTERUPT_ENABLE

    6.hal_drivers.c中if(!Hal_KeyIntEnable)中的语句关掉

    7.osal_pwrmgr_init(void)中pwrmgr_attribute.pwrmgr_device=PWRMGR_BATTERY

  • 你的做法太不可取了,我的问题也并没有解决!目前我在出差中,十一放假后才会上班!

    在我看来,只能给你一些建议,比如你先确定是不是真的进入了pm2模式,有对应的官方参照。如果你用的是cc2530的芯片,那用仿真器打个断点试一试,看看是不是真的进入了pm2模式。这里有一段TI工程师回复的原话

    /* set CC2530 power mode, interrupt is disabled after this function */
    HAL_SLEEP_SET_POWER_MODE(halPwrMgtMode);

    /*The macro HAL_SLEEP_SET_POWER_MODE() shuts down the radio and core.
    Try setting a breakpoint at this location to determine if sleep is being 
    disallowed at some earlier point.*/

  • 谢谢你的回复!

    我按照你说的方法设置了断点,发现可以进入睡眠模式PM2。我用万用表的电流档测得睡眠时的电流在0.4mA-0.5mA左右,醒来发射数据的电流在1.8-3.5mA之间。

    请问你测得的消耗电流是这个级别的吗?

    我按照0.5mA的数值来计算,700mAh的电池,最多只能支持700/0.5=1400h=58.333天,这个时间也不像网上宣称的那样能够工作1-2年啊。

    是不是我的设置方法不对?大侠你是怎么设置的呢?

  • 发射数据的电流只有1.8-3.5mA??

    不同产品的休眠功耗都不一样,取决于你的外设,我们数据手册的休眠电流PM2只代表,最小系统1uA

    是否进入休眠,一方面你可以通过程序断点调试,另外你可以通过示波器测32M晶振是否间歇工作

    对于休眠电流测试,最好用在供电电路中串联10欧电阻,测量两端电压。用万用表测不太准。

  • 第一,我最后的休眠就是连两节南孚,串联万用表,电流是0.8uA

    第二,把下面这段加上。虽然我没有用PA ,但我发现,它会耗电230uA左右。

    OBSSEL1 |= 0x80;
    OBSSEL2 |= 0x80;
    OBSSEL3 |= 0x80;
    OBSSEL4 |= 0x80;
    OBSSEL5 |= 0x80; 
    第三,你看下我休眠之前的一些设置,主要就是防止引脚耗电。但不推荐放在hal_sleep.c里面

    /*---------------------------------*/
    // P1DIR |= 0x02;
    // P1SEL &= ~0x02;
    // P1_1 ^= 1;
    /*P2口*/ 
    P2SEL &= ~0x07; // 通用io 
    P2DIR &= ~0x09; // 设置为输入
    P2INP |= 0x19;
    P2 = 0x00;
    /*P1口*/ 
    P1SEL &= ~0xFF; // 通用io 
    P1DIR &= ~0xFF; // 设置为输入
    P1INP |= 0xFC;
    P1 = 0x00; 
    /*P0口*/ 
    P0SEL &= ~0xFF; // 通用io 
    P0DIR &= ~0xFF; // 设置为输入
    P0INP |= 0xFF; 
    P0 = 0x00;

    // P1DIR |= 0x03;
    // P1SEL &= ~0x03;
    // P1_0 = 0;
    // P1_1 = 0; 

    // P0DIR &= ~0x03;
    // P0SEL &= ~0x03;
    // P0INP |= 0x03;
    // P2INP &= ~0x20; //P0口bu拉
    // P0_0 = 1;
    // P0_1 = 1;

    OBSSEL1 |= 0x80;
    OBSSEL2 |= 0x80;
    OBSSEL3 |= 0x80;
    OBSSEL4 |= 0x80;
    OBSSEL5 |= 0x80; 
    // 
    // TR0 |= 0x01;
    /*---------------------------------*/ 

    第四 ,引脚或者外设耗电。比如说我当初有个3K的电阻上拉电源,下面接地,设计为拨码开关,这样的话,也会耗电。看看你的引脚吧

    你也可以按照VV的说法,毕竟人家是万人景仰的TI大神,这个最权威了!!!真心的

  • 请问一下VV,pm2模式唤醒之后,程序运行的哪里呢?是reset了吗?

  • @wing burst

    能不能留个联系方式?或则你加我的  

    现在时间是2015年8月13日。我刚刚费了好大劲才把密码找回来,登了上来。我已经辞职两年了,现在转行了在送快递。留了QQ号码实在是不堪其忧,如果大家要是有送快递的,也请不要联系我了!!希望我的帖子,能对新人有所启发,研发永远不要见了!!

  • @阳春三月

    休眠定时器到的时候有两种方式,一种是中断,一种检测标志位

    在协议栈里面HAL_SLEEP_PREP_POWER_MODE这个函数中在检测标志位,

    休眠结束,程序往后执行。

  • OSAL的Timer时间是并行,你要自己安排好EVENT的时间队列,最好用笔画一个时间轴出来。

    目前我做的程序就是你说的那种时间控制的,我就是通过EVENT的TIMEOUT来控制休眠的,没有发现时间会误差的。

    PM2模式完全可以做到休眠的:中断唤醒,睡眠唤醒,我已经实现了,当没有event要触发的时候就进入中断唤醒了,我看过PM2的代码,里面有这方面的控制代码,很好理解。

  • @Fred Wang 

    您能详细说一下什么是“EVENT的时间队列”吗?

    我的sapi任务有三个event。

    第一个event只是用来采集,周期20ms。第二个event只是用来发送,周期200ms。第三个event进入后,关掉前两个事件,然后设置三个poll_rate为0(因为我理解的poll_rate也是属于timer),周期是30s。

    这样,让他自动进去休眠,然后在hal_sleep.c里面唤醒以后,我再将poll_rate设置为正常值(1000,100,100),然后使用myApp_StartReporting();再次设置sapi的前两个event,让系统执行。

    我在进入第三个event以后,已经关掉了前两个event了啊?怎么还会有,你说的“时间队列”了呢?

    我这样设置的时候发现,休眠时间确实是30s,但是工作时间是30s-8s=22s。如果做一次累加计数,他的工作时间是2*30s-8s=52s。不知道这个8s是为什么?

    如果我把这个周期设置为60s,休眠时间也是60s,但是工作时间大部分时间是60s-8s=52s,或者就成了2*60s-8s=112s,给人感觉好像第三个进入休眠的event没有响应。


    首先非常感谢你的回复,万分感谢。我说的有点长,问题已经卡住半个月了,我也很苦恼。如果您方便,还请再给一些指点,感激不尽

  • @VV

    我刚看了一下,我用的协议栈zstack-2.2.2-1.3.0真的没有HAL_SLEEP_PREP_POWER_MODE这个函数

    但是在休眠的时候,我Breakpoint,发现会经常停在

    void halSetSleepMode(void)
    {
    PCON = PCON_IDLE;
    HAL_DISABLE_INTERRUPTS();
    }

    不知道,是不是你所说的那个,检测标志位呢?

    非常感激 @VV

  • 用EVENT画一个时间轴出来,通过osal_start_timerEx和osal_stop_timerEx来控制EVENT触发的时间。

    首先你要确保没有其他EVENT在执行了,可以通过不启动这三个事件来测试,正常情况模块应该完全休眠,休眠也同时会断开连接,下一周期的连接需要重新通过广播来建立。(可以通过常亮一个LED来观察,休眠LED灭,工作LED是亮,HAL_LED里有休眠关闭的代码)

    时间轴规划:

    EVENT                          周期开始                                          周期结束

    采集                              start    20ms

    发送                              start    200ms

    下一周期                                                                                end 采集,发送,start 40s 超时后会下一周期

    osal timer是一个简单的定时器,好比是一个倒计时秒表,计时超时后,就向EventProcess事件发送EVENT消息,时间轴规划好就行了。

  • @Fred Wang

    首先,我关闭了三个事件来测试,模块确实是完全休眠了。


    其次,按照您的说法,我规划了一个时间轴如下:

    Event                周期开始                周期结束

    -----------------------------------------------------------------第一个周期

    采集                  start① 20ms

    发送                  start① 200ms

    休眠                  start① 40s                end①采集,发送。获取唯一剩下的休眠事件,时间为40s。休眠40s

    -----------------------------------------------------------------下一个周期,休眠40s后开始

    采集                  start② 20ms

    发送                  start② 200ms

    休眠                  start② 40s                end②采集,发送。获取唯一剩下的休眠事件,时间为40s。休眠40s

    -----------------------------------------------------------------下一个周期,休眠40s后开始

    ......以此类推

    像你说的,三个event是并行的,而且40s一定是20ms和200ms的公倍数。按照这么来说,工作的时间一定就是40s了,可是他是不准确的,并且是不可控的。

    这几天放假我也在想这个问题,一直是没想通。如果您看到了回复,还请多给些指点,恕我愚笨多有打扰

  • 你好,我想请问下您的休眠时间是怎么设置的。我的节点休眠时间设置20s以上就无法正常收到数据。 如果您有空,帮我解决一下这个问题,谢谢了。我是在sample例程上修改的。 具体修改如下:

    1.编译增加POWER_SAVING

    2.在f8wConfig.cfg中修改四个POLL为0

    3.在OnBoard.c中修改

    OnboardKeyIntEnable=HAL_KEY_INTERUPT_ENABLE

    4. 在程序中加入

    osal_pwrmgr_device(PWRMGR_BATTERY);

    osal_pwrmgr_task_state(GenericApp_TaskID,PWRMGR_CONSERVE);

    5.用osal_start_timerEx(GenericApp_TaskID,SEND_DATA_EVENT,10000);来定休眠时间。

  • 我也没做出来,我辞职了,这辈子再不干研发了!!!

    现在时间是2015年8月13日。我刚刚费了好大劲才把密码找回来,登了上来。我已经辞职两年了,现在转行了在送快递。留了QQ号码实在是不堪其忧,如果大家要是有需要快递的,也请不要联系我了!!希望我的帖子,能对新人有所启发,研发永远不要见了!!

  • 研发的确有些苦逼。。T T   不过还是继续努力看下怎么弄好了。

  • @阳春三月

    osal_timer是系统时钟,是一个RTC,timeout是从开始时开始计算的,所以事件周期是依据你的代码进行的。

    各个事件看似是并行的线程,其实只是通过RTC系统虚拟出来的,如果两个事件在同一个Real Time触发了,那肯定会有一个事件晚了一点,不过这并不影响其他不冲突事件的执行时间,所以我们可以近似把他们看成是并行线程。

  • @jack

    设置了POWER_SAVING就是开启了PM2模式,系统在没有事件需要执行的时候会自动进入休眠,不需要再增加睡眠事件,你只需要调整好需要执行的事件就行了,比如:周期性唤醒事件,广播事件等等。注意,此模式下如果 没有下一次周期事件,会自动进入PM3模式,然后就只能通过IO中断唤醒了,而且osal_clock会停止计时,所以最好写一个周期性唤醒任务,周期可以设置的比较长,事件不需要执行什么特殊指令,只要能唤醒芯片,维持时钟计时就行了。

  • 居然没有后文了。VV大神怎么没有出来解决

  • 原因在于早期版本的协议栈osal timer函数参数是16bit的,现在改成32bit,应该不会出现这个问题了

  • 嗯,有可能是这个问题,就是zstack-2.5.1a都改过来了对吧?

    另外想问一下VV大神,用zstack-2.5.1a的终端节点和用zstack-2.0(或者更老的版本)的协调器通信会不会出现问题?在对比文件的过程中,发现zstack-2.5.1a比老版本修改了很多。

    最后感谢VV大神给我每个提问都回复了。

  • 2.5.1a也是好几年前的协议栈了,现在最新的是2.6.1.x

    你可以下载Z-Stack Home 1.2.0 就可以看到了

    通信不好有问题,但是协议栈是在不断的添加新的功能,以及bug的修复的,所以建议使用最新版本的。

  • 还有一个问题,考虑到把现有程序改到新协议栈比较麻烦,我想问下是否可以在旧版本里面把osal time函数参数16bit改成32bit?如果可以需要修改哪些文件?

  • 嗯,最新版本是2.6.x,昨天下载了Z-Stack Home 1.2.0看了一下,在版本更新信息里面提到了需要IAR更高的版本,和RF05EB;结果确实无法打开工程,烧录器也只是RF04EB的,短时间能软硬件环境无法跟上。所以求助一下,看能否在现有版本进行一些修改。

  • 你好,假如我调用这个函数osal_start_timerEx(GenericApp_TaskID,SEND_DATA_EVENT,10000);每隔10s去激活一次SEND_DATA_EVENT事件爱你,我系统中只有这一个事件,处理完之后,在等待下一次事件发生时会自动进入休眠模式吗?然后10S时间到了,会自动进入自动模式处理SEND_DATA_EVENT,如此反复执行吗?

  • 只要10s钟的这个事件,是所有事件里面最短的一个,休眠时间就是10s。下次唤醒会自动执行该事件!

  • 请教TI工程师和各位大神们:

    我在终端设备的协议栈程序中通过函数

    osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
    (SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF) ));来实现定时广播数据,在HAL_SLEEP_PREP_POWER_MODE(halPwrMgtMode);加断点程序会运行到此处,指示联网状态的LED在入网后熄灭,只有定时广播数据时才会闪烁(程序设置发送时闪烁),看起来是进入PM2状态了吧,电流我还没有测量。现在有个问题就是,我需要按键唤醒,同时广播一条数据给路由器,然后等待路由器广播回复。设置了POWER_SAVING之后,终端设备就接收不到数据了,这是什么原因呢?我该怎么设置?

    我只是宏定义了POWER_SAVING,-DRFD_RCVC_ALWAYS_ON=FALSE,还有几个POLL_RATE都设成了0,路由器宏定义了NV_RESTORE。

    我看了有资料说终端设备在定时器或外部中断唤醒后会去有一个DataRequest的原语去向父节点询问是否有发给自己的数据,我这里是父节点直接广播应答不是有目的地址的点对点发送数据,不知道问题是出在这里吗?

  • 广播的地址是0xFFFF,对于Power Saving的end device来说也是indirect message,广播的数据也是保存在父节点的buffer里面,当子节点发送来data request的时候把广播数据发给它,你现在把POLL_RATE改成了0,相当于没有data request了。

  • 请问  终端睡眠问题你解决了嘛

  • 现在没什么问题了  协议栈正常休眠

  • 为什么协议栈睡眠啊     一般协议栈都是通电的    节能的话  没必要啊       

    我是想问问终端睡眠的 一些问题

    就是睡眠时间的问题

  • 你好,你是怎么设置断点进入PM2模式的啊?

  • 您好,在这个论坛里看到您解决了CC2530休眠的问题,想跟您请教一下,我想利用定时器,让终端定时休眠,比如工作5s,休眠10s,可是现在进入休眠之后,一直唤醒不了了,您是怎么解决的?方便告知一下吗?谢谢

  • 你进入的是PM2模式还是PM3模式?如果是通过协议栈休眠,只要在预编译里定义POWER_SAVING,协议栈会判断操作系统是否有Task要处理,如果有并且到时间,就唤醒处理,如果有Task但没到时间,就进入PM2休眠。如果没有Task就进入PM3休眠。一旦进入PM3,就需要外部IO中断或定时器中断来唤醒。

    你需要添加的Task可以用下面这个函数定时来执行,参数是我的工程里的,你自己定义:

    osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
    (SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF) ));

     

  • 十分感谢您的回答,可以再问一下需要在Onboard.c中做以下更改吗?

    将OnboardKeyIntEnable = HAL_KEY_INTERRUPT_DISABLE;改为OnboardKeyIntEnable = HAL_KEY_INTERRUPT_ENABLE;

    我参照了一下TI的Power Management For The CC2530.pdf这个文档,上面说需要将OnboardKeyIntEnable = HAL_KEY_INTERRUPT_ENABLE;,但是我改过之后数据就再也收不到了

  • 这个参数只是按键轮询检测还是中断检测的设置,应该不会影响休眠

  • 大神 能不能一起讨论下 ,我现在做睡眠

  • 对于设置低功耗的问题困惑了好久,不知道它是怎么进入睡眠的,睡眠后又是怎样唤醒的(有唤醒函数吗),方便的话,给个学习的例程吧

  • @阳春三月,你好!我设置断点了,HAL_SLEEP_PREP_POWER_MODE(halPwrMgtMode);查看halPwrMgtMode等于0x02;但是好像设置其他断点,这个值一直不变,那就是没有唤醒了吧

  • @wing burst

    您好,我的方法设置协议栈进入PM2之后,功耗为1.4uA噢。

  • Fred Wang 你好,有个问题请教一下:我的任务也有三个周期性事件,20ms,200ms,和3s的,但是发现pwrmgr_attribute.pwrmgr_task_state==2,进不到osal_set_cpu_into_sleep(next);怎么回事啊???????????谢谢

  • 阳春三月:你这个协议栈代码方便发我一份么???

    遇到同样的问题了,太纠结了,

    谢谢,1021256354@qq.com,再次谢谢

  • @roger huang1

    你好!可以加我QQ麽,402732326. 我现在也遇到一个需要在协议栈上修改进入PM2模式的问题困扰。具体要设置哪些参数?

  • 你好,请问你的终端节点休眠的问题解决了么?可否加我QQ:402732326.

    我现在需要你的帮助呢。谢谢!

  • W大侠,您好。我现在设备进入低功耗OK,每隔10秒钟唤醒一次,并发送1包32字节的数据,然后再次进入休眠。想请教下,如何计算出发送32字节所需要的功耗或电流之类的参数?我现在需要这个参数来确定设备的电池容量选型。如果无法计算,采用什么样的方式进行测量比较可行,需要什么设备?谢谢!