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.

[参考译文] CC1312R:wM-Bus 应用手册与示例

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

https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/1106067/cc1312r-wm-bus-application-note-vs-example

器件型号:CC1312R
Thread 中讨论的其他器件:SysConfigCC1310

应用手册 swra522e (https://www.ti.com/lit/pdf/SWRA522E)和 TI/Stackforce 提供的 wM-Bus 示例(https://software-dl.ti.com/lprf/WMBUS/wmbus_cc13x2_rtos_1_0_1.exe)之间似乎存在一些差异

例如、表3/4中列出的硬件覆盖在代码中未实现、并且没有使用 RX_N_Data_Writed 中断(或 RF_EventDataWritten)和 CMD_PROP_SET_LEN。

此外、SWRA602中指出:

". T-/C 模式补丁必须是
已使用。 它具有检测"动态" IF 的优势
传入的数据包处于 T 模式或 C 模式、然后
基于此解码、T 模式中的"6个中的3个"编码或
将数据"按原样"保留在 C 模式中。"

您能否澄清如何使用 wM-Bus (射频补丁)?

此致!

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

    您好、Frode

    您参考的应用手册仅对 CC13x0有效。 对于 CC13x2、您将在 SmartRF Studio 或 SysConfig 中找到 wM-Bus 设置。

    这些将与 Stackforce 的 wM-Bus 堆栈中使用的堆栈相同。

    应用手册中提到的地址在 CC13x2上是不同的。

    见下表。

    CC1310

    CC1312

    0x4004 6090

    0x4004 60A4

    0x4004 52B4

    0x4004 5328

    0x4004 5178

    0x4004 51E4

    0x4004 5180

    0x4004 51EC

    0x4004 5184

    0x4004 51F0

    不确定您说 CMD_PROP_SET_LEN 未使用时的含义。 堆栈使用此功能、但堆栈本身不是开源的、因此您将无法看到堆栈强制执行其代码最低级别的确切方式。

    由于 C 模式和 T 模式的数据包格式不同、因此当数据条目中有一些字节时、您的应用需要设置中断、并且需要读取 RxPacketType 寄存器以确定它是 C 模式还是 T 模式数据包。 基于此、应用程序将知道要解读的字节为长度字节、并可以使用 CMD_PROP_SET_LEN 命令设置正确的长度。

    如果修补程序确定数据包是 T 模式数据包,则它本身将对接收到的数据进行编码,这意味着不必对数据条目中接收到的应用程序数据进行进一步解码。

    wM-Bus 标准不开放(意味着您必须付费)、这就是为什么我们无法提供代码示例来说明如何发送和接收真正的 wM-Bus、因为这将使我们提供完整数据包格式的详细信息。

    下面是一个示例、展示了如何使用 CMD_PROP_SET_LEN 命令:  

    这些示例展示了如果应用程序知道长度字节是数据包的第5个字节、如何完成此操作。

    该示例读取数据包的第5个字节并使用该字节来设置长度。

    对于  wM-Bus、应用程序必须首先查明数据包是 C 模式还是 T 模式、以便能够确定长度字节的位置、然后从正确的位置读取长度、然后使用它来设置数据包的长度。

    /***** Includes *****/
    /* Standard C Libraries */
    #include <stdlib.h>
    
    /* TI Drivers */
    #include <ti/drivers/rf/RF.h>
    #include <ti/drivers/PIN.h>
    
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Semaphore.h>
    
    /* Driverlib Header files */
    #include DeviceFamily_constructPath(driverlib/rf_prop_mailbox.h)
    
    /* Board Header files */
    #include "ti_drivers_config.h"
    
    /* Application Header files */
    #include "RFQueue.h"
    #include <ti_radio_config.h>
    
    // CMD_PROP_SET_LEN
    rfc_CMD_PROP_SET_LEN_t RF_cmdPropSetLen =
    {
       .commandNo = 0x3401,
       .rxLen = 0x0000,
    };
    
    /***** Defines *****/
    
    /* Packet RX Configuration */
    //  ----------------------------------------------------------------------------------------------------------
    //  | DATA_ENTRY_HEADER (12 bytes) | H0 | H1 | H2 | H3 | Length N | D0 | D1 | D2 | .. | .. | D(N-2) | D(N-1) |
    //  ----------------------------------------------------------------------------------------------------------
    
    // Optional appended bytes
    //  -------------------------------------------------------
    //  | CRC1 | CRC0 | RSSI | TS3 | TS2 | TS1 | TS0 | Status |
    //  -------------------------------------------------------
    #define DATA_ENTRY_HEADER_SIZE  12                      /* Constant header size of a Partial Data Entry */
    #define MAX_LENGTH              10                      /* Max length byte the application will accept */
    #define PACKET_HEADER_SIZE      4                       /* Bytes in packet before location of the length byte */
    #define LENGTH_POSITION         PACKET_HEADER_SIZE + 1  /* Position of length byte (after sync) */
    #define NUM_APPENDED_BYTES      8                       /* .rxConf.bIncludeCrc = 0x1;       // 2 bytes (if default CRC is used)
                                                               .rxConf.bAppendRssi = 0x1;       // 1 byte
                                                               .rxConf.bAppendTimestamp = 0x1;  // 4 bytes
                                                               .rxConf.bAppendStatus = 0x1;     // 1 byte */
    
    
    
    /***** Prototypes *****/
    static void callback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e);
    
    /***** Variable declarations *****/
    static RF_Object rfObject;
    static RF_Handle rfHandle;
    static RF_CmdHandle rxHandle;
    
    /* Receive dataQueue for RF Core to fill in data */
    static dataQueue_t dataQueue;
    
    #if defined(__TI_COMPILER_VERSION__)
    #pragma DATA_ALIGN (rxDataEntryBuf0, 4);
    static uint8_t rxDataEntryBuf0[DATA_ENTRY_HEADER_SIZE + MAX_LENGTH + LENGTH_POSITION + NUM_APPENDED_BYTES];
    #pragma DATA_ALIGN (rxDataEntryBuf1, 4);
    static uint8_t rxDataEntryBuf1[DATA_ENTRY_HEADER_SIZE + MAX_LENGTH + LENGTH_POSITION + NUM_APPENDED_BYTES];
    
    #elif defined(__IAR_SYSTEMS_ICC__)
    #pragma data_alignment = 4
    static uint8_t rxDataEntryBuf0[DATA_ENTRY_HEADER_SIZE + MAX_LENGTH + LENGTH_POSITION + NUM_APPENDED_BYTES];
    #pragma data_alignment = 4
    static uint8_t rxDataEntryBuf1[DATA_ENTRY_HEADER_SIZE + MAX_LENGTH + LENGTH_POSITION + NUM_APPENDED_BYTES];
    
    #elif defined(__GNUC__)
    static uint8_t rxDataEntryBuf0[DATA_ENTRY_HEADER_SIZE + MAX_LENGTH + LENGTH_POSITION + NUM_APPENDED_BYTES] __attribute__((aligned(4)));
    static uint8_t rxDataEntryBuf1[DATA_ENTRY_HEADER_SIZE + MAX_LENGTH + LENGTH_POSITION + NUM_APPENDED_BYTES] __attribute__((aligned(4)));
    
    #else
    #error This compiler is not supported.
    #endif
    
    /* Receive dataQueue for RF Core to fill in data */
    static dataQueue_t dataQueue;
    static uint16_t payloadLength;
    
    rfc_dataEntryPartial_t* partialReadEntry0 = (rfc_dataEntryPartial_t*)&rxDataEntryBuf0;
    rfc_dataEntryPartial_t* partialReadEntry1 = (rfc_dataEntryPartial_t*)&rxDataEntryBuf1;
    rfc_dataEntryPartial_t* currentReadEntry = (rfc_dataEntryPartial_t*)&rxDataEntryBuf0;
    
    rfc_propRxOutput_t rxStatistics;
    static uint8_t lengthWritten = false;
    static uint8_t cancelRx = false;
    
    /* RX Semaphore */
    static Semaphore_Struct rxSemaphore;
    static Semaphore_Handle rxSemaphoreHandle;
    
    static uint8_t packetHeader[PACKET_HEADER_SIZE];
    static uint8_t packetPayload[MAX_LENGTH + 1]; // Must have room to store the length byte as well
    static uint8_t packetStatusBytes[NUM_APPENDED_BYTES];
    
    static uint16_t propDoneOk = 0;
    static uint16_t propDoneRxErr = 0;
    static uint16_t propDoneRxTimeout = 0;
    static uint16_t propDoneBreak = 0;
    static uint16_t propDoneEnded = 0;
    static uint16_t propDoneStopped = 0;
    static uint16_t propDoneAbort = 0;
    static uint16_t propErrorRxBuf = 0;
    static uint16_t propErrorRxFull = 0;
    static uint16_t propErrorPar = 0;
    static uint16_t propErrorNoSetup = 0;
    static uint16_t propErrorNoFs = 0;
    static uint16_t propErrorRxOvf = 0;
    
    /***** Function definitions *****/
    
    void *mainThread(void *arg0)
    {
        RF_Params rfParams;
        RF_Params_init(&rfParams);
    
        /* Initialize RX semaphore */
        Semaphore_construct(&rxSemaphore, 0, NULL);
        rxSemaphoreHandle = Semaphore_handle(&rxSemaphore);
    
        partialReadEntry0->length = MAX_LENGTH + LENGTH_POSITION + NUM_APPENDED_BYTES + 4;  // Make sure there is enough room for a complete packet in one data entry.
                                                                                            // Number of bytes following this length field
                                                                                            // + 4 is to make room for the pktStatus (2 bytes) and nextIndex (2 bytes)
        partialReadEntry0->config.irqIntv = LENGTH_POSITION;
        partialReadEntry0->config.type = DATA_ENTRY_TYPE_PARTIAL;
        partialReadEntry0->status = DATA_ENTRY_PENDING;
    
        partialReadEntry1->length = MAX_LENGTH + LENGTH_POSITION + NUM_APPENDED_BYTES + 4;  // Make sure there is enough room for a complete packet in one data entry.
                                                                                            // Number of bytes following this length field
                                                                                            // + 4 is to make room for the pktStatus (2 bytes) and nextIndex (2 bytes)
        partialReadEntry1->config.irqIntv = LENGTH_POSITION;
        partialReadEntry1->config.type = DATA_ENTRY_TYPE_PARTIAL;
        partialReadEntry1->status = DATA_ENTRY_PENDING;
    
        partialReadEntry0->pNextEntry = (uint8_t*)partialReadEntry1;
        partialReadEntry1->pNextEntry = (uint8_t*)partialReadEntry0;
    
        dataQueue.pCurrEntry = (uint8_t*)partialReadEntry0;
        dataQueue.pLastEntry = NULL;
    
        /* Modify CMD_PROP_RX command for application needs */
        RF_cmdPropRx.pQueue = &dataQueue;
        RF_cmdPropRx.pOutput = (uint8_t*)&rxStatistics;
        RF_cmdPropRx.rxConf.bIncludeHdr = 1; // Must be 1 to receive the first byte after sync in the data entry
        RF_cmdPropRx.maxPktLen = 0;          // Unlimited length
    
        // Optional status bytes appended AFTER the payload
        // If these are changed, NUM_APPENDED_BYTES must also be updated
        RF_cmdPropRx.rxConf.bIncludeCrc = 0x1;      // 2 byte (if default CRC is used)
        RF_cmdPropRx.rxConf.bAppendRssi = 0x1;      // 1 byte
        RF_cmdPropRx.rxConf.bAppendStatus = 0x1;    // 1 Byte
        RF_cmdPropRx.rxConf.bAppendTimestamp = 0x1; // 4 bytes
    
        /* Request access to the radio */
        rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);
    
        /* Set the frequency */
        RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0);
    
        while(true)
        {
            lengthWritten = false;
            cancelRx = false;
    
            rxHandle = RF_postCmd(rfHandle, (RF_Op*)&RF_cmdPropRx, RF_PriorityNormal, &callback, IRQ_RX_N_DATA_WRITTEN);
    
            Semaphore_pend(rxSemaphoreHandle, BIOS_WAIT_FOREVER);
    
            if (cancelRx)
            {
                RF_cancelCmd(rfHandle, rxHandle, 0);
                RF_pendCmd(rfHandle, rxHandle, RF_EventLastCmdDone   |
                                               RF_EventLastFGCmdDone |
                                               RF_EventCmdAborted    |
                                               RF_EventCmdStopped    |
                                               RF_EventCmdCancelled);
    
                currentReadEntry->status = DATA_ENTRY_PENDING;
                currentReadEntry = (rfc_dataEntryPartial_t*)currentReadEntry->pNextEntry;
                dataQueue.pCurrEntry = (uint8_t*)currentReadEntry;
            }
            uint32_t cmdStatus = ((volatile RF_Op*)&RF_cmdPropRx)->status;
            switch(cmdStatus)
            {
                case PROP_DONE_OK:
                    // Packet received with CRC OK
                    propDoneOk++;
                    break;
                case PROP_DONE_RXERR:
                    // Packet received with CRC error.
                    // This can happen if the length byte is less than 5 (for 50 kbps). In this case, CMD_PROP_SET_LEN is sent after the
                    // complete packet has been received, and the CRC check fails (even if the correct payload is received)
                    propDoneRxErr++;
                    break;
                case PROP_DONE_RXTIMEOUT:
                    // Observed end trigger while in sync search
                    propDoneRxTimeout++;
                    break;
                case PROP_DONE_BREAK:
                    // Observed end trigger while receiving packet when the command is
                    // configured with endType set to 1
                    propDoneBreak++;
                    break;
                case PROP_DONE_ENDED:
                    // Received packet after having observed the end trigger; if the
                    // command is configured with endType set to 0, the end trigger
                    // will not terminate an ongoing reception
                    propDoneEnded++;
                    break;
                case PROP_DONE_STOPPED:
                    // received CMD_STOP after command started and, if sync found,
                    // packet is received
                    propDoneStopped++;
                    break;
                case PROP_DONE_ABORT:
                    // Received CMD_ABORT after command started
                    propDoneAbort++;
                    break;
                case PROP_ERROR_RXBUF:
                    // No RX buffer large enough for the received data available at
                    // the start of a packet
                    propErrorRxBuf++;
                    break;
                case PROP_ERROR_RXFULL:
                    // Out of RX buffer space during reception in a partial read
                    propErrorRxFull++;
                    break;
                case PROP_ERROR_PAR:
                    // Observed illegal parameter
                    propErrorPar++;
                    break;
                case PROP_ERROR_NO_SETUP:
                    // Command sent without setting up the radio in a supported
                    // mode using CMD_PROP_RADIO_SETUP or CMD_RADIO_SETUP
                    propErrorNoSetup++;
                    break;
                case PROP_ERROR_NO_FS:
                    // Command sent without the synthesizer being programmed
                    propErrorNoFs++;
                    break;
                case PROP_ERROR_RXOVF:
                    // RX overflow observed during operation
                    propErrorRxOvf++;
                    break;
                default:
                    // Uncaught error event - these could come from the
                    // pool of states defined in rf_mailbox.h
                    while(1);
                }
            }
    }
    
    void callback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
    {
        if (e & RF_EventNDataWritten)
        {
            if (!lengthWritten)
            {
                lengthWritten = true;
    
                payloadLength = *(uint8_t*)(&currentReadEntry->rxData + LENGTH_POSITION);
    
                if (payloadLength > MAX_LENGTH)
                {
                    cancelRx = true;
                    Semaphore_post(rxSemaphoreHandle);
                }
                else
                {
                    RF_cmdPropSetLen.rxLen = payloadLength + LENGTH_POSITION; // Must subtract 1 due to rxConf.bIncludeHdr = 1
                    RF_runImmediateCmd(rfHandle, (uint32_t*)&RF_cmdPropSetLen);
                }
            }
        }
    
        if (e & RF_EventLastCmdDone)
        {
            memcpy(packetHeader,        (uint8_t*)(&currentReadEntry->rxData + 0                              ), PACKET_HEADER_SIZE);
            memcpy(packetPayload,       (uint8_t*)(&currentReadEntry->rxData + (LENGTH_POSITION - 1)          ), (payloadLength + 1));
            memcpy(packetStatusBytes,   (uint8_t*)(&currentReadEntry->rxData + LENGTH_POSITION + payloadLength), NUM_APPENDED_BYTES);
    
            currentReadEntry->status = DATA_ENTRY_PENDING;
            currentReadEntry = (rfc_dataEntryPartial_t*)currentReadEntry->pNextEntry;
            dataQueue.pCurrEntry = (uint8_t*)currentReadEntry;
            Semaphore_post(rxSemaphoreHandle);
        }
    }

    BR

    Siri