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.

[参考译文] CC2640R2F:使用 HWI 中断无法退出待机模式

Guru**** 2619205 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/wireless-connectivity/bluetooth-group/bluetooth/f/bluetooth-forum/1200976/cc2640r2f-not-coming-out-of-standby-mode-using-hwi-interrupt

器件型号:CC2640R2F

我的应用是读取 SPI 上的传感器数据并对其进行广播。 广播后、它应该在设定的时间段内进入睡眠(待机模式)、但只要发生外部硬件中断、它就应该被唤醒。 但我的应用无法退出待机模式。 正如你在代码中看到的,我使用了"sleep()" API,并将其发送到 sleep10秒,但当我尝试把它唤醒早,它不会唤醒。 我还尝试了 "Power_sleep (PowerCC26XX_STANDBY)"但它甚至没有进入睡眠状态。

PIN_Config wakeup_pin[] =
{
     IOID_18  | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE | PIN_HYSTERESIS,
     PIN_TERMINATE /* Terminate list */
};
void spi_createTask(void)
{
    Display_init();
    GPIO_init();
    SPI_init();

    Task_Params taskParams;

    // Configure task
    Task_Params_init(&taskParams);
    taskParams.stack = appTaskStack;
    taskParams.stackSize = SPI_TASK_STACK_SIZE;
    taskParams.priority = SPI_TASK_PRIORITY;

    Task_construct(&SPI_task, SPI_taskFunction, &taskParams, NULL);
}
void vfnSpiPerformXfers (SPI_Handle masterSpi)
{
    uint8_t u8xfer_nb_bytes;
    static uint8_t u8Temperature = 0;
    static float fPressure = 0;
    static float fAccZ = 0;
    static float fAccX = 0;

    char bleStr[30] = {0};
    char tempStr[10] = {0};
    Int key;

    /* Prepare the Tx buffer for SPI transfers */
    u8xfer_nb_bytes = u8SpiFillTxBuffer();

    key = HwiP_disable();
    /* Launch the SPI transfers - this is a blocking operation */
    vfnSpiTriggerXfers(masterSpi, u8xfer_nb_bytes);
    HwiP_restore(key);
   // key = Hwi_disable();
    /* Store sensor data in the application buffer.

       Note that the returned status is discarded here, but in a final application it should
       be used to check the validity of the data received and do a re-try in case transfers
       were not successfully */
    if(u8SpiStoreData())
    { key = HwiP_disable();
#if 0
        u8Temperature = getTemperatureValue(gSendData.array_data[13]);
        fPressure = getPressureValue(gSendData.array_data[6], gSendData.array_data[7]);
        fAccZ = getAccelerometerValue(gSendData.array_data[8], gSendData.array_data[9]);
        fAccX = getAccelerometerValue(gSendData.array_data[10], gSendData.array_data[11]);
#else

       // sleep(30);
        u8Temperature = getTemperatureValue(gSendData.array_data[13]);
        fPressure = getPressureValue(gSendData.array_data[7], gSendData.array_data[6]);
        fAccZ = getAccelerometerValue(gSendData.array_data[9], gSendData.array_data[8]);
        fAccX = getAccelerometerValue(gSendData.array_data[11], gSendData.array_data[10]);

#endif

        if(u8Temperature >= HIGH_TEMPERATURE_THRESHOLD){
            notifyTemperature(NOTIFY_HIGH_TEMPERATURE);
        }
        else if(u8Temperature <= LOW_TEMPERATURE_THRESHOLD){
            notifyTemperature(NOTIFY_LOW_TEMPERATURE);
        }
        else{
            notifyTemperature(NOTIFY_NONE);
        }

        if(fPressure >= HIGH_PRESSURE_THRESHOLD){
            notifyPressure(NOTIFY_HIGH_PRESSURE);
        }
        else if(fPressure <= LOW_PRESSURE_THRESHOLD){
            notifyPressure(NOTIFY_LOW_PRESSURE);
        }
        else{
            notifyPressure(NOTIFY_NONE);
        }

        memset(tempStr, 0, sizeof(tempStr));
        memset(bleStr, 0, sizeof(bleStr));

        itoa(u8Temperature, tempStr);
        strcat(bleStr, tempStr);
        strcat(bleStr, ",");

        memset(tempStr, 0, sizeof(tempStr));
        ftoa(fPressure, tempStr, 2 );
        strcat(bleStr, tempStr);
        strcat(bleStr, ",");

        memset(tempStr, 0, sizeof(tempStr));
        ftoa(fAccX, tempStr, 2 );
        strcat(bleStr, tempStr);
        strcat(bleStr, ",");

        memset(tempStr, 0, sizeof(tempStr));
        ftoa(fAccZ, tempStr, 2 );
        strcat(bleStr, tempStr);
       // PRCMPeripheralSleepEnable(PRCM_PERIPH_GPIO);
      //  PRCMPeripheralDeepSleepEnable(PRCM_PERIPH_GPIO);
      //  PRCMLoadSet();
       // PINCC26XX_setWakeup(wakeup_pin);
       // DataService_SetParameter(DS_STRING_ID, sizeof(bleStr), bleStr);

        HwiP_restore(key);
       sleep(10);
        //Power_sleep( PowerCC26XX_STANDBY);
        DataService_SetParameter(DS_STRING_ID, sizeof(bleStr), bleStr);
       // PRCMSleep();

    }
   // Hwi_restore(key);
}
void SPI_taskFunction(UArg arg0, UArg arg1)
{
    /* Local variables. Variables here go onto task stack!! */
    /* Run one-time code when task starts */

    SPI_Handle      masterSpi;
    SPI_Params      spiParams;
    uint32_t        i;
    Semaphore_Handle semHandle;
    Clock_Handle     clockHandle;
    int32_t wakeuppincurrent = 0;
    int32_t wakeuppinprevious = 0;

    semHandle = setupTimer(&clockHandle, 1000); // 1 Second delay

    if (semHandle == NULL) {
        while (1);
    }
    hPin_wakeup = PIN_open(&pinState_wakeup, wakeup_pin);
    // Register ISR
    PIN_registerIntCb(hPin_wakeup, buttonHwiFxn);
    // Configure interrupt
    PIN_setConfig(hPin_wakeup, PIN_BM_IRQ, IOID_18 | PIN_IRQ_NEGEDGE);
    // Enable wakeup
    PIN_setConfig(hPin_wakeup, PINCC26XX_BM_WAKEUP, IOID_18|PINCC26XX_WAKEUP_NEGEDGE);
    while(1)
    {
        hPin_wakeup = PIN_open(&pinState_wakeup, wakeup_pin);

        //KBI high
        hPin_kbi = PIN_open(&pinState_kbi, kbi_pin_table);
        PIN_setOutputValue(hPin_kbi, IOID_9, 1);


        while(1)
        {
            wakeuppincurrent = PIN_getInputValue(IOID_18);

            if(wakeuppincurrent != wakeuppinprevious)
            {
                // status change of wake up pin changes
                wakeuppinprevious = wakeuppincurrent;

                if(wakeuppincurrent == 1)
                {
                    int i = 0;
                    for( i = 0; i<100; i++)
                    {
                        PIN_setOutputValue(hPin_kbi, IOID_9, 1);
                        PIN_setOutputValue(hPin_kbi, IOID_9, 0);
                    }

                    //wait for KBI acknowledge(slave will drive wake up pin to low)
                    while(PIN_getInputValue(IOID_18) == 1)
                    {
                    }

                    break;
                }
            }
        }

        PIN_remove(hPin_kbi, IOID_9);

        /* Open SPI as master (default) */
        SPI_Params_init(&spiParams);
        spiParams.frameFormat = SPI_POL0_PHA0;
        spiParams.bitRate = 1000000 ;
        spiParams.dataSize = 16;
        spiParams.mode = SPI_MASTER;

        masterSpi = SPI_open(Board_SPI_MASTER, &spiParams);
        if (masterSpi == NULL) {
            Display_printf(display, 0, 0, "Error initializing master SPI\n");
            while (1);
        }
        else {
            Display_printf(display, 0, 0, "Master SPI initialized\n");
        }

        for (i=0; i < SPI_MSG_LENGTH; i++)
            memmove((void *)masterTxBuffer+i, (const void *)masterTxBuffer1+i, 1);
        if (1) {
            vfnSpiPerformXfers(masterSpi);

        }

        SPI_close(masterSpi);
        Display_printf(display, 0, 0, "\nDone");
        /*
         *  Block until the timer posts the semaphore.
         *  Since it is waiting forever, no need to check the return code.
         */
        Semaphore_pend(semHandle, BIOS_WAIT_FOREVER);
    }
}

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    T

    static void buttonHwiFxn(PIN_Handle hPin, PIN_Id pinId)
    {
       
        test_var=~test_var;
      
    
    }
    他是我的回调函数,基本而言,我什么也不做回调函数,因为我只是想唤醒设备。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Ankit、您好!

    默认情况下、电源管理器应能够实现所需的功能。 如果是广播、则它应该在广播之间进入待机状态、并在发生中断时从待机状态唤醒。用户指南的"电源管理"部分中提供了一些相关信息。 电源管理用户指南 提供了许多有关电源管理器如何工作以及如何在应用中利用它的有用信息。

    我建议不要明确地将器件设置为待机模式、看看电源管理器的默认行为是否实现了所需的任务。

    此致、

    1月

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    您的目的可能是进入关断模式。 我建议您查看您的代码。

    -kel

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Markel、

    我不想进入关闭模式、因为我想在1秒的间隔内继续广播。 此处、我使用了 BLE 项目0、并将 advt 间隔修改为1秒、并在从传感器传输 SPI 数据的项目中添加了 SPI 运行代码、传输完成后、我将睡眠10秒、我使用了"Sleep (unsigned seconds)";...、即 由 TiRtos 提供的 API。 实际上、我可以借助 WAKEUP 引脚退出电源关断模式、但在关断模式下、advt 会停止。因此我不再想进入关断模式、而是选择使用待机模式。 您能帮助我查看代码的哪些部分吗?

     *  ======== sleep ========
     */
    unsigned sleep(unsigned seconds)
    {
        unsigned long secs, ticks;  /* at least 32-bit */
        unsigned max_secs, rval;    /* native size, might be 16-bit */
    
        max_secs = MAX_SECONDS;
    
        if (seconds < max_secs) {
            secs = seconds;
            rval = 0;
        }
        else {
            secs = max_secs;
            rval = seconds - max_secs;
        }
    
        /* must use 64-bit math to compute tick value */
        ticks = ((uint64_t)secs * 1000000L) / (uint64_t)Clock_tickPeriod;
    
        /* must add one tick to ensure a full duration of requested ticks */
        Task_sleep((UInt32)(ticks + 1));
    
        return (rval);
    }
    

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Jan、

    如您所见、我并没有明确地将控制器置于待机模式、而是调用一个"sleep (unsigned seconds)"的 Tirtos API、用于将当前任务置于睡眠状态、 如果我错了,请更正我,我认为这与 FreeRTOS 中的 vTaskdelay ()一样有效。 这里、我允许电源管理器将其置于待机模式、甚至进入待机模式、但它不会被外部硬件中断唤醒、我只会在设置的间隔 (设置为"睡眠(无符号秒)"、即10秒)后唤醒。 请提供帮助。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Ankit、您好!

    简单外设程序由事件驱动。 如果没有事件、则器件会进入待机模式。 电源管理可处理这些任务、而且您无需添加代码。 TI 2004年1月已经提及详细信息

    您需要分析 器件的电流消耗才能了解待机模式。 详情如下所示。  

    https://www.ti.com/lit/an/swra478d/swra478d.pdf

    -kel

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Markel、

    我甚至在移除该强制睡眠后,该器件会进入待机状态,但它 不会在外部硬件中断时唤醒。 所以问题仍然存在。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    ,但它 没有在外部硬件中断上唤醒

    您是如何通过 外部硬件中断从待机模式唤醒的。 这是您的中断处理程序。

    static void buttonHwiFxn(PIN_Handle hPin, PIN_Id pinId)
    {
       
        test_var=~test_var;
      
    
    }

    要从待机模式唤醒、您可以发布应用需要处理该事件的事件。

    /*********************************************************************
     * @fn      Button_ProcessKeyRight
     *
     * @brief   Interrupt handler for BUTTON 1(right)
     *
     * @param   none
     *
     * @return  none
     */
    void Button_ProcessKeyRight(void)
    {
      if (PIN_getInputValue(Board_BTN2))
      {
        keys &= ~SK_KEY_RIGHT;
      }
      else
      {
        keys |= SK_KEY_RIGHT;
      }
    
      // Wake up the application thread
      Event_post(syncEvent, SBP_KEYPRESS_EVT);
    }

    完成任务时按下按钮的操作

    static void SimplePeripheral_taskFxn(UArg a0, UArg a1)
    {
      // Initialize application
      SimplePeripheral_init();
    
      // Application main loop
      for (;;)
      {
        uint32_t events;
    
        // Waits for an event to be posted associated with the calling thread.
        // Note that an event associated with a thread is posted when a
        // message is queued to the message receive queue of the thread
        events = Event_pend(syncEvent, Event_Id_NONE, SBP_ALL_EVENTS,
                            ICALL_TIMEOUT_FOREVER);
    
        if (events)
        {
          ICall_EntityID dest;
          ICall_ServiceEnum src;
          ICall_HciExtEvt *pMsg = NULL;
    
          // Fetch any available messages that might have been sent from the stack
          if(ICall_fetchServiceMsg(&src, &dest,
                                  (void **)&pMsg) == ICALL_ERRNO_SUCCESS)
          {
            uint8 safeToDealloc = TRUE;
    
            if((src == ICALL_SERVICE_CLASS_BLE) && (dest == selfEntity))
            {
              ICall_Stack_Event *pEvt = (ICall_Stack_Event *)pMsg;
    
              if (pEvt->signature != 0xffff)
              {
                  // Process inter-task message
                  safeToDealloc = SimplePeripheral_processStackMsg((ICall_Hdr *)pMsg);
              }
            }
    
            if (pMsg && safeToDealloc)
            {
              ICall_freeMsg(pMsg);
            }
          }
    
          // If RTOS queue is not empty, process app message.
          if(events & SBP_QUEUE_EVT)
          {
            while (!Queue_empty(appMsgQueue))
            {
              sbpEvt_t *pMsg = (sbpEvt_t *)Util_dequeueMsg(appMsgQueue);
              if (pMsg)
              {
                // Process message.
                SimplePeripheral_processAppMsg(pMsg);
    
                // Free the space from the message.
                ICall_free(pMsg);
              }
            }
          }
    
          if(events & SBP_KEYPRESS_EVT)
          {
            Button_ProcessEvent();
          }

    另一种方法是在中断处理程序中发布信标。

    此外,调用 Task_sleep()将只会阻止当前正在运行的任务

    -kel