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.

[参考译文] LP-CC2651R3SIPA:使用 GATT_ReadMultiCharValues 执行周期性任务会导致默认 SPINLOCK

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

https://e2e.ti.com/support/wireless-connectivity/bluetooth-group/bluetooth/f/bluetooth-forum/1237773/lp-cc2651r3sipa-performing-periodictask-with-gatt_readmulticharvalues-causes-default-spinlock

器件型号:LP-CC2651R3SIPA

您好!

我正在处理2个 多角色基础项目、虽然一个项目充当客户端、另一个项目充当服务器。  我的 SDK 是 CC13xx CC26xx 7.10.00.98、我使用的是2个 LP-CC2651R3SIPA。

我的目标是在0、5到1秒的范围内接收读数、以便尽可能快地更新客户端项目中的数据、就像服务器中发生的那样(时间现在在1、8-2秒之间、太慢)。 我正在读取正确的数据、如果我必须执行此操作、我可以减少读取的数据量或更改某些数据类型。 也不需要显示方法、因为目前它仅用于调试目的、如果这会使显示速度变慢。

我有一个客户、在 multi_role_performPeriodicTask 方法中使用 GATT_ReadMultiCharValues、我设法将 MR_PERIOD_EVT_PERIOD 设置为低至1000、而不存在自旋锁问题、但当它设置为800或更低(尚未测试1000和800之间的其他值)时、会出现错误、 然后、 AssertHandler 执行时的参数为"assertCause" 8、"assertSubcaus"为0 (无论我将 Sub-800设置为 MR_PERIOD_EVT_PERIOD 的时间如何)。 虽然周期性事件每秒发生一次,我得到的结果每1,8-2,2秒(大约,由电话的计时器计算),这是太慢的目的。 一旦它是 Sub-800、程序就会显示默认的 SPINLOCK! 没有响应。

由于出现相同的错误代码、因此在 MR_PERIOD_EVT_PERIOD 为800 (或更低)的情况下读取较少的特征值也没有帮助。

 multi_role_performPeriodicTask 中的代码如下:

static void multi_role_performPeriodicTask(void)
{
    if (debug_isGATTavailable) {
        attReadMultiReq_t reqMulti;
        reqMulti.numHandles = 2;
        reqMulti.pHandles = GATT_bm_alloc(mrConnHandle, ATT_READ_MULTI_REQ, 4, NULL);
        reqMulti.pHandles[0] = LO_UINT16(connList[0].charHandle);
        reqMulti.pHandles[1] = HI_UINT16(connList[0].charHandle);
        reqMulti.pHandles[2] = LO_UINT16(connList[0].charHandle + 3);
        reqMulti.pHandles[3] = HI_UINT16(connList[0].charHandle + 3);
        reqMulti.pHandles[4] = LO_UINT16(connList[0].charHandle + 6);
        reqMulti.pHandles[5] = HI_UINT16(connList[0].charHandle + 6);
        reqMulti.pHandles[6] = LO_UINT16(connList[0].charHandle + 9);
        reqMulti.pHandles[7] = HI_UINT16(connList[0].charHandle + 9);
        reqMulti.pHandles[8] = LO_UINT16(connList[0].charHandle + 12);
        reqMulti.pHandles[9] = HI_UINT16(connList[0].charHandle + 12);
        reqMulti.pHandles[10] = LO_UINT16(connList[0].charHandle + 15);
        reqMulti.pHandles[11] = HI_UINT16(connList[0].charHandle + 15);
        reqMulti.pHandles[12] = LO_UINT16(connList[0].charHandle + 18); 
        reqMulti.pHandles[13] = HI_UINT16(connList[0].charHandle + 18);

        bStatus_t status = FAILURE;
        while (status != SUCCESS)
        {
            if (status == blePending) {
                break;
            }

            status = GATT_ReadMultiCharValues(mrConnHandle, &reqMulti, selfEntity);
            Display_print1(dispHandle, MR_ROW_CHAR_1, 0, "Read multi char status - %d", status);
        }
        Display_printf(dispHandle, MR_ROW_CHAR_1, 0, "Success. Status - %d", status);
        GATT_bm_free( (gattMsg_t *) &reqMulti, ATT_READ_MULTI_REQ);
    }
}

处理响应的代码部分(在 multi_role_processGATTMsg 中)如下。 目前我正在读取1字节特征和5 4字节特征(之后我将其转换为 uint32_t):

static uint8_t multi_role_processGATTMsg(gattMsgEvent_t *pMsg)
{
    // Get connection index from handle
    uint8_t connIndex = multi_role_getConnIndex(pMsg->connHandle);
    MULTIROLE_ASSERT(connIndex < MAX_NUM_BLE_CONNS);

    if (pMsg->method == ATT_FLOW_CTRL_VIOLATED_EVENT)
    {
        // ATT request-response or indication-confirmation flow control is
        // violated. All subsequent ATT requests or indications will be dropped.
        // The app is informed in case it wants to drop the connection.

        // Display the opcode of the message that caused the violation.
        Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "FC Violated: %d",
                       pMsg->msg.flowCtrlEvt.opcode);
    }
    else if (pMsg->method == ATT_MTU_UPDATED_EVENT)
    {
        // MTU size updated
        Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "MTU Size: %d",
                       pMsg->msg.mtuEvt.MTU);
    }

    // Messages from GATT server
    if (linkDB_Up(pMsg->connHandle))
    {
        
        if ( ... other conditions checking other kind of responses) {
        // methods just as the original code in multi_role is 
        
        }
        else if (((pMsg->method == ATT_READ_MULTI_RSP) && (pMsg->msg.readMultiRsp.len > 0))
            || ((pMsg->method == ATT_ERROR_RSP) && (pMsg->msg.errorRsp.reqOpcode == ATT_READ_MULTI_REQ)))
        {
            if (pMsg->method == ATT_ERROR_RSP)
            {
                Display_printf(dispHandle, MR_ROW_CHAR_2, 0, "ATT ERROR reqOpCode: %d, errCode: %d", pMsg->msg.errorRsp.reqOpcode, pMsg->msg.errorRsp.errCode);
            }
            else
            {
                Display_printf(dispHandle, MR_ROW_CHAR_2, 0,
                        "ATT_READ_MULTI_RSP, len: %d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
                        pMsg->msg.readMultiRsp.len, 
                        pMsg->msg.readMultiRsp.pValues[0], pMsg->msg.readMultiRsp.pValues[1],
                        pMsg->msg.readMultiRsp.pValues[2], pMsg->msg.readMultiRsp.pValues[3],
                        pMsg->msg.readMultiRsp.pValues[4], pMsg->msg.readMultiRsp.pValues[5],
                        pMsg->msg.readMultiRsp.pValues[6], pMsg->msg.readMultiRsp.pValues[7],
                        pMsg->msg.readMultiRsp.pValues[8], pMsg->msg.readMultiRsp.pValues[9],
                        pMsg->msg.readMultiRsp.pValues[10], pMsg->msg.readMultiRsp.pValues[11],
                        pMsg->msg.readMultiRsp.pValues[12], pMsg->msg.readMultiRsp.pValues[13],
                        pMsg->msg.readMultiRsp.pValues[14], pMsg->msg.readMultiRsp.pValues[15],
                        pMsg->msg.readMultiRsp.pValues[16], pMsg->msg.readMultiRsp.pValues[17]);

                uint8_t resp_char1 = 0;
                uint32_t resp_char2 = 0;
                uint32_t resp_char3 = 0;
                uint32_t resp_char4 = 0;
                uint32_t resp_char5 = 0;
                uint32_t resp_char6 = 0;
                
                // Converting values
                resp_char1 = pMsg->msg.readMultiRsp.pValues[0];
                Util_convertUInt8arrToUInt32(&resp_char2, pMsg->msg.readMultiRsp.pValues, 1);
                Util_convertUInt8arrToUInt32(&resp_char3, pMsg->msg.readMultiRsp.pValues, 5);
                Util_convertUInt8arrToUInt32(&resp_char4, pMsg->msg.readMultiRsp.pValues, 9);
                Util_convertUInt8arrToUInt32(&resp_char5, pMsg->msg.readMultiRsp.pValues, 13);
                Util_convertUInt8arrToUInt32(&resp_char6, pMsg->msg.readMultiRsp.pValues, 17);
                Display_printf(dispHandle, MR_ROW_CHAR_1, 0, "[1]=%u, [2]=%u, [3]=%u, [4]=%u, [5]=%u, [6]=%u", resp_char1, resp_char2, resp_char3, resp_char4, resp_char5, resp_char6);
            }

我在应该改善的地方有点停留、因为我不确定是什么导致了默认的 SPINLOCK 错误出现、或者我怎样才能提高接收速度。 我没有从 syscfg 修改过多个参数 、也不知道 需要阅读哪些文档(从这里)才能知道如何改进这一部件。

编辑:我也试图只读取一个特征、但时序是一样的、需要超过2-3秒的时间启动、然后它继续每~2秒接收数据。

我们将非常感谢您提供任何帮助、并会毫不犹豫地提出任何进一步的详细信息。

提前感谢

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

    您好!

    感谢您与我们联系。 我们将对此进行深入探讨、然后再与您联系。 同时、您能否提供您在项目中使用的连接间隔?

    此致、

    1月

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

    您好!

    设置是 multi_role 项目的默认设置。 我的确更改了一些、但我将它们设置为默认值。 就在这种情况下、我的设置为:

    服务器部件:

    客户端部分:

    我所做的另一个测试是  在 multi_role_performPeriodicTask 中使用 multi_role_doGattRead (基本上使用 GATT_ReadCharValue)  、其 MR_periodic_evt_period 为100、自旋锁没有问题、但 速度与使用 GATT_ReadMultiCharValues 一样慢。

    虽然我更喜欢读取多个特征(或多次读取、但速度更快)、但我可以制定读取单个特征的权变措施、并能够获取我所需的所有信息。

    感谢你的帮助。

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

    您好!

    首先、您要接收的读数位于另一个 LaunchPad 上、对吧? 您正在测量从服务器向客户端传输数据所需的时间? 您用于在客户端读取数据的 GUI 是什么? 我只是想知道这是一个"协议"请求、还是只显示一个请求。

    正如 Jan 提到的、连接间隔可能是你问题的一个主意、尝试缩短连接间隔以在你预期的0.5至1之间接收更多数据包。 (目前、您最多每秒钟发送一个事件、因此如果此事件无法包含您需要的所有数据、您将需要另一个)

    但是、功耗会更高。

    此致、

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

    纪尧姆、您好!

    首先、您要接收的读数位于另一个 LaunchPad 上、对吧?

    是的、充当服务器的 LaunchPad 将读取我希望在充当客户端的 LaunchPad 上接收的传感器。  

    您正在测量从服务器向客户端传输数据所需的时间? 您用于在客户端读取数据的 GUI 是什么? 我只是想知道这是一个"协议"请求、还是只显示一个请求。

    目前、我使用的是 multi_role 项目中使用的 Display 方法。 我的工作是:

    1.执行方法  multi_role_performPeriodicTask 时、使用第一个帖子中显示的代码、或者使用"multi_role_doGattRead (0)"的单次调用、即以下代码:

    bool multi_role_doGattRead(uint8_t index)
    {
      attReadReq_t req;
      uint8_t connIndex = multi_role_getConnIndex(mrConnHandle);
    
      // connIndex cannot be equal to or greater than MAX_NUM_BLE_CONNS
      MULTIROLE_ASSERT(connIndex < MAX_NUM_BLE_CONNS);
    
      req.handle = connList[connIndex].charHandle;
      Display_printf(dispHandle, MR_ROW_CHARSTAT, 0, "charHandle: %d | req.handle: %d", connList[connIndex].charHandle, req.handle);
    
      GATT_ReadCharValue(mrConnHandle, &req, selfEntity);
    
      return (true);
    }
    

    2.收到结果后, multi_role_processGATTmsg 方法会显示单次或多次读取的结果。 在单次读取的情况下、我在原始代码中添加了一个 Display_printf、该函数只显示了读取值:

    if ((pMsg->method == ATT_READ_RSP)   ||
            ((pMsg->method == ATT_ERROR_RSP) &&
             (pMsg->msg.errorRsp.reqOpcode == ATT_READ_REQ)))
        {
          if (pMsg->method == ATT_ERROR_RSP)
          {
            Display_printf(dispHandle, MR_ROW_CUR_CONN, 0, "Read Error %d", pMsg->msg.errorRsp.errCode);
          }
          else
          {
            // After a successful read, display the read value
            Display_printf(dispHandle, MR_ROW_CHAR_2, 0, "Read rsp: %d | rsp len: %d", pMsg->msg.readRsp.pValue[0], pMsg->msg.readRsp.len);
          }
    
        }
    

    3.这是我"测量"时间的方法。 我  还使用了板载 LED 在收到响应时点亮、我还没有使用示波器、但我认为如果这里采用了显示方法、我可能会发现计时差异不大。 我"测量"的是从客户端发送读取请求直至我在显示屏上收到答案的时间、尽管第一个答案确实感觉较慢。 由于它定期执行任务、我不断获得结果、并且这些结果每1、8-2秒返回一次、因此时间如下:

    读取请求 等待应答 接收读取响应 等待下一个答案 接收读取响应 等待下一个答案 不停重复
    2-3秒 1.8 - 2.2秒 1.8 - 2.2秒

    我知道、使用 Display 输出可能会导致延迟、但我不知道在多大程度上可以这样做。

    正如 Jan 提到的、连接间隔可能是你问题的一个主意、尝试缩短连接间隔以在你预期的0.5至1之间接收更多数据包。 (目前、您最多每秒钟发送一个事件、因此如果此事件无法包含您需要的所有数据、您将需要另一个)

    关于缩短连接间隔、您是指  中心侧的连接间隔最小值(ms)和连接间隔最大值(ms)、以及 请求的最小连接 间隔(ms)和请求的最大连接 时间间隔(ms)、对吧?

    但是、功耗会更高。

    我知道它会消耗更多的功率、但响应时间 在这个问题上更重要。 我将尝试您的建议、并不断向您更新。

    感谢你的帮助。

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

    感谢所有的细节,您的申请现在很清楚。

    关于显示时间的评估、我没有真实的数字、但为了获得非常准确的读取接收时间、您可以做的是使用 BLE 监听器并看到 BLE 跟踪、这样您就可以得到每个数据包的准确时间。  

    另一种方法是使用逻辑分析仪查看无线电活动。如果您需要更多输入、请转到 用户指南中的 调试部分调试射频输出一章。

    是的、您可以在开始时从中央侧设置连接间隔、为了节省一些可以发送连接更新参数请求的电量、 (在运行期间更改连接间隔、使在选定的时间段内发生更多连接事件、然后返回到"默认"参数以节省一些电量)

    此致、

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

    您好!

    似乎我转向了正确的方向、但有一些东西阻止了它。

    我设法使客户读得非常快(比我需要的多),但几秒钟后,它返回到接收每~2秒。 问题是、我无法看到这种情况为什么发生或者是如何发生的模式。  

    现在的情况如下:

    客户端有时在接收的第一秒内快速接收数据、但随后每~2秒返回接收一次。

    服务器已更改为:

    我仍在两个项目中使用 multi_role、我应该更改其中一个吗?

    无关的问题、当客户端的地址模式配置为"Public Address"、服务器的地址模式配置为"Publi Address"时、客户端的 multi_role 在尝试连接到服务器时似乎挂起。 这是否正常?

    提前感谢、

    艾伯特

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

    尊敬的 Albert:

    似乎几秒钟后有一个连接参数更新、为了确认此行为、我需要您配置 GPIO 以读取无线电活动。

    要执行此操作、请执行 用户指南中的调试章节、调试射频输出部分中的步骤。

    关于第二点、挂机是什么意思? 难以连接、尝试多次连接、然后再进行正确连接? 您的环境是否适合 BLE?

    此致、