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.

[参考译文] CC1350:如何实现低功耗 RF 和 SCS UART

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

https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/1283545/cc1350-how-to-implement-low-power-rf-and-scs-uart

器件型号:CC1350
主题中讨论的其他器件:CC1310

团队成员、您好。

我希望能生成一个程序、利用 SCS 的 UART 通过 RS485与器件通信、并使用 RF 的 TX 传输数据。

现在我已经确定 SCS 的 UART 可以使用 scifWaitOnNbl(5000000);来降低5秒的功耗。  

但我不知道如何关闭 Cortex-M3。 我已经在 TI 驱动程序示例中查看了 pinstanby,但它似乎是 sleep();无法满足我的需要。

我希望能得到一些建议、或者如果 SCS UART 的睡眠状态出现错误、那么可以麻烦告诉我。

谢谢、下面提供了代码、希望您能得到最好的建议。


可以解释、它主要是通过 uartTaskInit 和 rfTxTaskInit 之间的交互来进行的

/*
 * Copyright (c) 2019, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/***** Includes *****/
/* Standard C Libraries */
#include <stdlib.h>
#include <unistd.h>

/* TI Drivers */
#include <ti/drivers/rf/RF.h>
#include <ti/drivers/PIN.h>
#include <ti/drivers/UART.h>
#include <ti/drivers/uart/UARTCC26XX.h>
/* Driverlib Header files */
#include DeviceFamily_constructPath(driverlib/rf_prop_mailbox.h)

/* Board Header files */
#include "Board.h"

/* Application Header files */
#include "RFQueue.h"
#include "smartrf_settings/smartrf_settings.h"
//#include DeviceFamily_constructPath(inc/hw_fcfg1.h)

//SCS include
#include <ti/devices/DeviceFamily.h>
#include "scif.h"
#include <ti/sysbios/knl/Semaphore.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/BIOS.h>

/***** Defines *****/
#define NO_PACKET              0
#define PACKET_RECEIVED        1

volatile uint8_t packetRxCb;
volatile size_t bytesReadCount;

/* Packet RX Configuration */
#define MAX_LENGTH             240 /* Max length byte the radio will accept */
#define NUM_DATA_ENTRIES       2  /* NOTE: Only two data entries supported at the moment */
#define NUM_APPENDED_BYTES     2  /* The Data Entries data field will contain:
                                   * 1 Header byte (RF_cmdPropRx.rxConf.bIncludeHdr = 0x1)
                                   * Max 30 payload bytes
                                   * 1 status byte (RF_cmdPropRx.rxConf.bAppendStatus = 0x1) */

/* RFQueue */
static dataQueue_t dataQueue;
static rfc_dataEntryGeneral_t* currentDataEntry;
static uint8_t rfRxPacketLength;
static uint8_t* rfRxPacketDataPointer;
static uint8_t rfRxPacket[MAX_LENGTH + NUM_APPENDED_BYTES - 1]; /* The length byte is stored in a separate variable */
static uint8_t rfTxPacket[MAX_LENGTH + NUM_APPENDED_BYTES - 1];

#if defined(__TI_COMPILER_VERSION__)
#pragma DATA_ALIGN (rxDataEntryBuffer, 4);
static uint8_t
rxDataEntryBuffer[RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(NUM_DATA_ENTRIES,
                                                  MAX_LENGTH,
                                                  NUM_APPENDED_BYTES)];
#elif defined(__IAR_SYSTEMS_ICC__)
#pragma data_alignment = 4
static uint8_t
rxDataEntryBuffer[RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(NUM_DATA_ENTRIES,
                                                  MAX_LENGTH,
                                                  NUM_APPENDED_BYTES)];
#elif defined(__GNUC__)
static uint8_t
rxDataEntryBuffer[RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(NUM_DATA_ENTRIES,
                                                  MAX_LENGTH,
                                                  NUM_APPENDED_BYTES)]
                                                  __attribute__((aligned(4)));
#else
#error This compiler is not supported.
#endif

/* UART */
#define MAX_NUM_UART_RX_BYTES    1000
#define MAX_NUM_UART_TX_BYTES    1000

static int uartRxCount;
uint8_t UartRxBuf[MAX_NUM_UART_RX_BYTES];   // Receive buffer
uint8_t UartTxBuf[MAX_NUM_UART_TX_BYTES];   // Transmit buffer

UART_Handle uart;
UART_Params uartParams;

static char input[MAX_NUM_UART_RX_BYTES];
static char output[MAX_NUM_UART_TX_BYTES];
int32_t UARTwrite_semStatus;
int_fast16_t status = UART_STATUS_SUCCESS;
static int i,j;

// Uart TASK DATA
// Task data
static Task_Params uartTaskParams,rfTxTaskParams,rfRxTaskParams;
static Task_Struct uartTaskStruct,rfTxTaskStruct,rfRxTaskStruct;
static Char uartTaskStack[1024],rfTxTaskStack[1024],rfRxTaskStack[1024];


Semaphore_Struct uartTaskSem, rfTxTaskSem, rfRxTaskSem;
Semaphore_Handle uartTaskSemHandle, rfTxTaskSemHandle, rfRxTaskSemHandle;

/* RF handle */
static RF_Object rfObject;
static RF_Handle rfHandle;
static RF_CmdHandle rfTxPostHandle,rfRxPostHandle;
static RF_Params rfParams;

/* LED */
static PIN_Handle ledPinHandle;
static PIN_State ledPinState;

PIN_Config pinTable[] =
{
    Board_PIN_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
    Board_PIN_LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
    PIN_TERMINATE
};

/***** Function definitions *****/
void ReceiveonUARTcallback(UART_Handle handle, void *UartRxBuf, size_t count, void *userArg, int_fast16_t status)
{
    bytesReadCount = count;
}

void led_init()
{
    ledPinHandle = PIN_open(&ledPinState, pinTable);

    PIN_setOutputValue(ledPinHandle, Board_PIN_LED1,!PIN_getOutputValue(Board_PIN_LED1));
    usleep(300000);
    PIN_setOutputValue(ledPinHandle, Board_PIN_LED1,!PIN_getOutputValue(Board_PIN_LED1));

    PIN_setOutputValue(ledPinHandle, Board_PIN_LED2,!PIN_getOutputValue(Board_PIN_LED2));
    usleep(300000);
    PIN_setOutputValue(ledPinHandle, Board_PIN_LED2,!PIN_getOutputValue(Board_PIN_LED2));

    if (ledPinHandle == NULL)
    {
        while(1);
    }
}

void uartTxRfRxPacket()
{
    printf("uartTxRfRxPacket\n");

    if(packetRxCb)
    {
        for(i=0;i<rfRxPacketLength;i++)
        {
            scifUartTxPutChar((char)rfRxPacket[i]);
        }

        packetRxCb = NO_PACKET;

        Semaphore_post(rfRxTaskSemHandle);
    }
}

void ReceivedOnRFcallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
{
    if (e & RF_EventRxEntryDone)
    {
        PIN_setOutputValue(ledPinHandle, Board_PIN_LED2, 1);

        /* Get current unhandled data entry */
        currentDataEntry = RFQueue_getDataEntry(); //loads data from entry

        /* Handle the packet data, located at &currentDataEntry->data:
         * - Length is the first byte with the current configuration
         * - Data starts from the second byte */
        rfRxPacketLength      = *(uint8_t*)(&currentDataEntry->data); //gets the packet length (send over with packet)
        rfRxPacketDataPointer = (uint8_t*)(&currentDataEntry->data + 1); //data starts from 2nd byte

        /* Copy the payload + the status byte to the packet variable */
        memcpy(rfRxPacket, rfRxPacketDataPointer, (rfRxPacketLength + 1));

        /* Move read entry pointer to next entry */
        RFQueue_nextEntry();

        packetRxCb = PACKET_RECEIVED;

        PIN_setOutputValue(ledPinHandle, Board_PIN_LED2, 0);

        uartTxRfRxPacket();
    }
}

void scCtrlReadyCallback(void) {
    printf("scCtrlReadyCallback\n");
} // scCtrlReadyCallback

void scTaskAlertCallback(void) {
    printf("scTaskAlertCallback\n");

    // Clear the ALERT interrupt source
    scifClearAlertIntSource();

    // Echo all characters currently in the RX FIFO
    int rxFifoCount = scifUartGetRxFifoCount();

    uartRxCount = rxFifoCount;

    i = 0;

    while (rxFifoCount--)
    {
        UartRxBuf[i] = (char)scifUartRxGetChar();
        i++;
    }

    // Clear the events that triggered this
    scifUartClearEvents();

    // Acknowledge the alert event
    scifAckAlertEvents();

    if(uartRxCount > 0)
    {
        //開啟rf tx
        Semaphore_post(rfTxTaskSemHandle);
    }

    // Wake up the OS task
    //Semaphore_post(uartTaskSemHandle);
} // scTaskAlertCallback

// CRC計算函數
uint16_t calculateCRC(uint8_t *data, int length) {
    uint16_t crc = 0xFFFF;

    for (i = 0; i < length; i++) {
        crc ^= data[i];
        for (j = 0; j < 8; j++) {
            if (crc & 0x0001) {
                crc >>= 1;
                crc ^= 0xA001; // 16位CRC多項式
            } else {
                crc >>= 1;
            }
        }
    }
    return crc;
}

void scUartTask(UArg a0, UArg a1) {

    printf("scUartTask start\n");
    // Initialize the Sensor Controller
    scifOsalInit();
    scifOsalRegisterCtrlReadyCallback(scCtrlReadyCallback);
    scifOsalRegisterTaskAlertCallback(scTaskAlertCallback);
    scifInit(&scifDriverSetup);

    //scifStartRtcTicksNow(0x00010000 / 8);

    uint8_t command[] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x0A};
    int commandLength = sizeof(command) / sizeof(command[0]);

    uint16_t crc = calculateCRC(command, commandLength);

    // 將CRC檢驗碼附加到數據報文
    command[commandLength] = crc & 0xFF; // 低位字節
    command[commandLength + 1] = (crc >> 8) & 0xFF; // 高位字節
    int newCommandLength = commandLength + 2;

    while(1)
    {
        //printf("Uart restart\n");
        // Start the UART emulator
        scifResetTaskStructs((1 << SCIF_UART_EMULATOR_TASK_ID), (1 << SCIF_STRUCT_CFG) | (1 << SCIF_STRUCT_INPUT) | (1 << SCIF_STRUCT_OUTPUT));
        scifExecuteTasksOnceNbl(1 << SCIF_UART_EMULATOR_TASK_ID);

        // Enable baud rate generation
        scifUartSetBaudRate(9600);

        // Enable RX (10 idle bit periods required before enabling start bit detection)
        scifUartSetRxFifoThr(SCIF_UART_RX_FIFO_MAX_COUNT / 2);
        scifUartSetRxTimeout(10 * 2);
        scifUartSetRxEnableReqIdleCount(10 * 2);
        scifUartRxEnable(1);

        // Enable events (half full RX FIFO or 10 bit period timeout
        scifUartSetEventMask(BV_SCIF_UART_ALERT_RX_FIFO_ABOVE_THR | BV_SCIF_UART_ALERT_RX_BYTE_TIMEOUT);

        //printf("wait 0.5s\n");
        scifWaitOnNbl(500000);

        // 使用循環將整個帶CRC檢驗碼的數據報文傳輸到UART
        for (i = 0; i < newCommandLength; i++) {
            scifUartTxPutChar(command[i]);
        }

        //printf("scUartTask wait for semaphore post\n");

        // Wait for an ALERT callback
        //Semaphore_pend(uartTaskSemHandle, BIOS_WAIT_FOREVER);


        //printf("wait 0.5s\n");
        scifWaitOnNbl(500000);
        //printf("scifUartStopEmulator\n");
        scifUartStopEmulator();

        scifUartSetBaudRate(0);

        //printf("wait 5s\n");
        scifWaitOnNbl(500000);
    }

} // taskFxn

void uartTaskInit()
{
    //Initialize Uart semaphore
    Semaphore_construct(&uartTaskSem, 0, NULL);
    uartTaskSemHandle = Semaphore_handle(&uartTaskSem);

    // Configure the Uart task
    Task_Params_init(&uartTaskParams);
    uartTaskParams.stack = uartTaskStack;
    uartTaskParams.stackSize = sizeof(uartTaskStack);
    uartTaskParams.priority = 2;
    Task_construct(&uartTaskStruct, scUartTask, &uartTaskParams, NULL);
}

void rfTxTask()
{
    //RF_Params_init(&rfTxParams);

    // TX指令參數設定
    RF_cmdPropTx.pPkt = rfTxPacket;
    RF_cmdPropTx.startTrigger.triggerType = TRIG_NOW;

    //rfTxHandle = RF_open(&rfTxObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfTxParams);

    //設定頻率
    //RF_postCmd(rfTxHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0);

    while(1)
    {
        printf("rfTxTask wait for semaphore post\n");

        Semaphore_pend(rfTxTaskSemHandle, BIOS_WAIT_FOREVER);

        if(uartRxCount > 0)
        {
            RF_cmdPropTx.pktLen = uartRxCount;

            int i;

            for(i=0; i<uartRxCount; i++)
            {
                rfTxPacket[i] = UartRxBuf[i];
            }

            /*for(i=0;i<sizeof(rfTxPacket);i++)
            {
                printf("%c\n",rfTxPacket[i]);
            }*/

            RF_cancelCmd(rfHandle, rfRxPostHandle, 1);

            PIN_setOutputValue(ledPinHandle, Board_PIN_LED1, 1);

            RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal, NULL, 0);

            PIN_setOutputValue(ledPinHandle, Board_PIN_LED1, 0);

            rfRxPostHandle = RF_postCmd(rfHandle, (RF_Op*)&RF_cmdPropRx,RF_PriorityNormal, &ReceivedOnRFcallback,RF_EventRxEntryDone);

            uartRxCount = 0;

            for(i=0;i<sizeof(UartRxBuf);i++)
            {
                UartRxBuf[i] = '\0';
            }
        }
    }
}

void rfTxTaskInit()
{
    //Initialize RFTx semaphore
    Semaphore_construct(&rfTxTaskSem, 0, NULL);
    rfTxTaskSemHandle = Semaphore_handle(&rfTxTaskSem);

    // Configure the RFTx task
    Task_Params_init(&rfTxTaskParams);
    rfTxTaskParams.stack = rfTxTaskStack;
    rfTxTaskParams.stackSize = sizeof(rfTxTaskStack);
    rfTxTaskParams.priority = 1;
    Task_construct(&rfTxTaskStruct, rfTxTask, &rfTxTaskParams, NULL);
}

void rfInit()
{
    RF_Params_init(&rfParams);

    rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);

    //設定頻率
    RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0);
}

void *mainThread(void *arg0)
{
    while(ledPinHandle == NULL)
    {
        led_init();
    }

    uartTaskInit();

    rfInit();

    rfTxTaskInit();
}

此致、

银河

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

    您好、Galaxy、

    1.您正在使用哪个版本的 SimpleLink CC13x0 SDK 和 SCS Studio?

    2.当你说 sleep()不能满足你的需要时,你能请深思吗? 器件处于睡眠状态时需要测量多少?

    3.如果 M3没有任何活动任务、并且功率配置文件设置为待机(power_saving 预定义符号)、器件将进入睡眠状态。

    4.通常情况下、在使用 UART 时、您不能允许器件完全进入睡眠状态、因为它正在等待接收到的事务。 您使用的是 UART 阻塞模式还是回调模式?

    谢谢、

    M·H

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

    您好, Marie H,

    1.SDK:SimpleLink CC13x0 SDK (4.20.02.07)

    SCS:2.9.0.208

    2.与其说它不能满足我的需要,我不知道如何使用睡眠来满足我的需要,这是更正确的。 我希望能够每60秒从 UART 向器件发送一个信号、等待返回、然后通过射频传递。 TX 被发送到另一个 CC1310器件、并且 RF RX 也可以定期接收信号、但我目前希望先到达 UART 和 RFTX 部件、然后在完成后继续完成其他项目。

    3.目前还没有有关功率分布的信息。 我见过其他人使用 power_sleep ()和其他相关的语法,但我不太明白。

    4.目前,它是通过回调触发的。 SCS 的触发似乎与 cc1310上的 UART echo 不同。 SCS 的 UART 似乎可以省电。


    现在我的需求和第二点描述的一样、但我还不知道如何解决。 如果可能的话,我希望你能给我一些建议和方向。 主要的一点是、A 主机使用 UART 在固定的时间内与器件进行通信、并且 UART 返回的内容通过 RFTX 发送到主机 B。

    此致、

    银河

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

    您好、Galaxy、

    TRM (CC13x0、CC26x0 SimpleLink 无线 MCU 技术参考手册(修订版 I)(TI.com))的第6.6章对 CC13xx 的电源模式进行了说明

    请参阅下表、查看该模式下活动的模式和外设列表:

    每种模式的预期流耗可参见数据表的第5.4章、如下所示:

    在待机用例中、您的电流消耗是否高于0.8µA?

    在使用待机模式时、传感器控制器仍然可用、您可以唤醒通过 UART 接收数据的器件。

    此致
    曼努埃尔

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

    您好、 Manuel:

    我的合作伙伴和我最近进行了测试、了解到为节省功耗测量了 rfSynchronizedPacketTx/RX 和 WORTX/RX。 最近、我一直在研究 rfSynchronizedPacketTx/RX、因为这种功能最符合我们的需求。


    1.我想问您能否向我介绍 rfSynchronizedPacketTx/RX 中的睡眠省电部分。 当然,我也会亲自研究。 我只是想听到你的解释,以避免我对程序的误解。

    2.rfSynchronizedPacketTx/RX 和 WORTX/RX 不会像其他示例那样使用 mainThread。 这是否与睡眠省电有关?

    此致、

    银河

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

    您好 Galaxy:

    1.顾名思义,这些示例正在发送同步数据包,这意味着发送方和接收方都知道数据包发送时隙。 因此、中的射频内核在每个发送的数据包之间断电、从而节省电力。 在本例中、间隔设置为500ms。
    但是、控制器本身不会在这些时隙中自动睡眠。
    在项目设置中编译之前、必须设置预定义的"power_saving"符号、如 Marie 前面所述。

    2.我想这是使用 RTOS 与使用无 RTOS 示例之间的差异造成的。 在本例中、您使用了哪些引脚?

    此致
    曼努埃尔

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

    您好、 Manuel:

    1.在哪里可以找到"power_saving"的信息? 有没有可以查看的屏幕截图?
    2.我总是使用 RTOS

    此致、

    银河

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

    您好、Galaxy、

    Rx 不使用 power_saving 预定义。 (对于误解很抱歉、SDK 示例工程之间的差异会有所不同。)

    而是在板级配置文件(CC1350_LAUNCHXL.c)中设置电源策略。 向下滚动到"Power driver definites"。  PolicyFxn 应设置为 PowerCC26XX_STANDBYPolicy、以允许器件进入待机模式。

    /*
     *  =============================== Power ===============================
     */
    #include <ti/drivers/Power.h>
    #include <ti/drivers/power/PowerCC26XX.h>
    
    const PowerCC26XX_Config PowerCC26XX_config = {
        .policyInitFxn      = NULL,
        .policyFxn          = &PowerCC26XX_standbyPolicy,
        .calibrateFxn       = &PowerCC26XX_calibrate,
        .enablePolicy       = true,
        .calibrateRCOSC_LF  = true,
        .calibrateRCOSC_HF  = true,
    };

    谢谢、

    M·H