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.

[参考译文] CC1352P:I2C 间歇性停止读取传感器

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

https://e2e.ti.com/support/wireless-connectivity/other-wireless-group/other-wireless/f/other-wireless-technologies-forum/1067872/cc1352p-i2c-intermittently-stops-reading-sensor

部件号:CC1352P
线程中讨论的其他部件: MSP432P401RsysconfigtestLPSTK-CC1352RHDC2080

我一直在寻找 I2C 问题,我希望 cc1352p 从我们的一个传感器读取6个字节。

但读取过程似乎在第一个字节后停止驱动时钟线路。

下面是故障的捕获:

请注意,从这一点开始,数据线一直处于低位。

我猜测传感器在处理完前2个字节后一直在等待其余时钟(再等待5个字节)。

这是成功发生的事例:

我犹豫要提出下一个观察,因为这可能是对实际问题的一个错误,但当上面的阅读框紧跟在下面的块时,很可能会失败。

但我想强调,不遵循以下限制并不会使问题消失,而只是大大减少了问题。

上述捕获是对另一个 I2C 设备的请求,该设备当前不在 I2C 总线上。

两次尝试与 IT 进行沟通后,我们都希望能有机会。

我正在使用 SimpleLink_cc13x2_26x2_SDK_5_20_00_52

当我逐步了解驱动程序代码时,我将转至功能“I2CSupport_primeTransfer”,第607行:

我已确认事务对象,特别是“ReadCount”值设置为值6。

因此,第607行的 ELSE 案例似乎是此案例的正确代码路径。

另一条信息:

这是一个将现有产品从 MSP432P401R (您决定不再支持的处理器)移植到 CC1352P 的项目。
I2C 过程在 MSP432上运行正常,所以我想知道是否有需要考虑的不同之处。

此外,我已经浏览了勘误表,并注意到 I2CMasterControl 函数中有一个“CPUDelay (2)”,看起来就像勘误表中所提及的“变通办法”:

这对我来说听起来不是同一个问题,但我认为如果这有助于对话,我会提及这一问题。

谢谢,我期待能提供的任何帮助...

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

    我在上面的第三次拍摄中留下了详细信息...

    通常(但并非总是),这两个帧会在第一次捕获之前发生(如果失败)...
    当设备存在于 I2C 总线上时,全帧的写入命令(0x69,0x11,0x03)中将包含3个字节。
    因此,正在为该 I2C_transferTimeout 调用将 writeCount 值设置为2。

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

    你(们)好,Cary

    为了进一步帮助您,我们需要了解几件事。

    请分享一个完整的示例,展示如何配置 I2C 驱动程序以及为传输 I2C 上的数据而编写的代码?

    您可以共享与之通信的传感器的相关信息,并共享示意图,显示 CC1352如何连接到传感器,以及如何在 sysconfig 中配置 I2C,这一点也很有用。

    如果我理解正确,您可以使用 MSP432P401R 获得解决方案。 您使用的是哪种 SDK 用于此设备,您是否可以共享此设备的代码以从传感器读取,以便我们可以将它们与您的 CC1352代码进行比较?

    巴西

    西里

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

    MSP432的实施使用了 simplelink_msp432p4_SDK_3_40_01_02。

    接下来是 MSP432和 CC1352实施使用的代码库。
    我们确实注意到 I2C 驱动程序函数 I2C_TRANferTimeout 似乎在新 SDK 中返回了更多可能的错误代码,因此我们知道要实施这些代码需要做些什么。  

    e2e.ti.com/.../i2c_5F00_multi.c

    请注意,驱动程序是在阻止模式下初始化的,I2C 总线以100k 的速度运行

    从我原始帖子中捕获的两个传感器是 Sensiron SHHT3x (第一个和第二个图像,I2C 地址0x44)和 SPS30 (第三个图像,I2C 地址0x69)

    以下函数每500毫秒调用一次,以方便在一个周期内“开始测量”,然后在第二个周期内“开始测量”:

    extern void SENSIRION_getSHT3XMeasurement(Sensirion_Sensor_t *pSensor,
            Temp_Msrmnt_t *pTmeas, RH_Msrmnt_t *pRHmeas, bool writeCmd)
    {
        union {
            Buf_Wr_Cmd_t cmd;
            Buf_Rd_2_Msrmnts_t msrmnts;
        } buf;
    
        if(writeCmd)
        {
            // Prepare write buffer with measurement command set for
            // high repeatability.
            *(uint16_t *) buf.cmd =
                    REVERSE_END_16(SHT3X_STS3X_CMD_MEAS_POLLING_H);
    
            if(I2C_MULTI_write(pSensor->i2cAddr, buf.cmd, sizeof(buf.cmd)))
            {
                pTmeas->status.i2c_error = false;
                pRHmeas->status.i2c_error = false;
            }
            else
            {
                pTmeas->status.i2c_error = true;
                pRHmeas->status.i2c_error = true;
            }
        }
        else
        {
            if(I2C_MULTI_read(pSensor->i2cAddr, buf.msrmnts, sizeof(buf.msrmnts)))
            {
                _convertRH(&buf.msrmnts[3], pRHmeas);
                _convertTemp(buf.msrmnts, pTmeas);
    
                pTmeas->status.i2c_error = false;
                pRHmeas->status.i2c_error = false;
            }
            else
            {
                pTmeas->status.i2c_error = true;
                pRHmeas->status.i2c_error = true;
            }
        }
    }

    下面是 syscfg 文件:

    /**
     * These arguments were used when this file was generated. They will be automatically applied on subsequent loads
     * via the GUI or CLI. Run CLI with '--help' for additional information on how to override these arguments.
     * @cliArgs --device "CC1352P1F3RGZ" --package "RGZ" --part "Default" --product "simplelink_cc13x2_26x2_sdk@5.20.00.52"
     * @versions {"data":"2021060817","timestamp":"2021060817","tool":"1.8.2+1992","templates":null}
     */
    
    /**
     * Import the modules used in this configuration.
     */
    const CCFG      = scripting.addModule("/ti/devices/CCFG");
    const Board     = scripting.addModule("/ti/drivers/Board");
    const GPIO      = scripting.addModule("/ti/drivers/GPIO");
    const GPIO1     = GPIO.addInstance();
    const GPIO2     = GPIO.addInstance();
    const GPIO3     = GPIO.addInstance();
    const GPIO4     = GPIO.addInstance();
    const I2C       = scripting.addModule("/ti/drivers/I2C", {}, false);
    const I2C1      = I2C.addInstance();
    const NVS       = scripting.addModule("/ti/drivers/NVS", {}, false);
    const NVS1      = NVS.addInstance();
    const NVS2      = NVS.addInstance();
    const PWM       = scripting.addModule("/ti/drivers/PWM", {}, false);
    const PWM1      = PWM.addInstance();
    const PWM2      = PWM.addInstance();
    const PWM3      = PWM.addInstance();
    const PWM4      = PWM.addInstance();
    const PWM5      = PWM.addInstance();
    const PWM6      = PWM.addInstance();
    const Power     = scripting.addModule("/ti/drivers/Power");
    const RTOS      = scripting.addModule("/ti/drivers/RTOS");
    const SPI       = scripting.addModule("/ti/drivers/SPI", {}, false);
    const SPI1      = SPI.addInstance();
    const Timer     = scripting.addModule("/ti/drivers/Timer", {}, false);
    const Timer1    = Timer.addInstance();
    const UART2     = scripting.addModule("/ti/drivers/UART2", {}, false);
    const UART21    = UART2.addInstance();
    const UART22    = UART2.addInstance();
    const Watchdog  = scripting.addModule("/ti/drivers/Watchdog", {}, false);
    const Watchdog1 = Watchdog.addInstance();
    
    /**
     * Write custom configuration values to the imported modules.
     */
    CCFG.enableDCDC         = false;
    CCFG.xoscCapArray       = true;
    CCFG.xoscCapArrayDelta  = 0x2;
    CCFG.ccfgTemplate.$name = "ti_devices_CCFGTemplate0";
    
    Board.generateInitializationFunctions = false;
    
    GPIO1.$name             = "GPIO_NFC_GPO";
    GPIO1.pull              = "Pull Up";
    GPIO1.interruptTrigger  = "Falling Edge";
    GPIO1.callbackFunction  = "ST25DVXXK_NFC_GPO_Callback";
    GPIO1.gpioPin.$assign   = "11";
    GPIO1.pinInstance.$name = "CONFIG_PIN_1";
    
    GPIO2.$name              = "GPIO_OLED_DISPLAY_RS";
    GPIO2.mode               = "Output";
    GPIO2.initialOutputState = "High";
    GPIO2.gpioPin.$assign    = "14";
    GPIO2.pinInstance.$name  = "CONFIG_PIN_5";
    
    GPIO3.$name             = "GPIO_OLED_DISPLAY_DC";
    GPIO3.mode              = "Output";
    GPIO3.gpioPin.$assign   = "15";
    GPIO3.pinInstance.$name = "CONFIG_PIN_6";
    
    GPIO4.$name             = "GPIO_OLED_DISPLAY_CS";
    GPIO4.mode              = "Output";
    GPIO4.gpioPin.$assign   = "32";
    GPIO4.pinInstance.$name = "CONFIG_PIN_7";
    
    I2C1.$name                = "I2C_MULTI";
    I2C1.maxBitRate           = 100000;
    I2C1.i2c.sdaPin.$assign   = "30";
    I2C1.i2c.sclPin.$assign   = "29";
    I2C1.sdaPinInstance.$name = "CONFIG_PIN_8";
    I2C1.clkPinInstance.$name = "CONFIG_PIN_9";
    
    NVS1.$name                    = "NVS_SYS_VAR_META";
    NVS1.internalFlash.$name      = "ti_drivers_nvs_NVSCC26XX0";
    NVS1.internalFlash.regionType = "Pointer";
    NVS1.internalFlash.regionBase = 0x54000;
    
    NVS2.$name                    = "NVS_SYS_VARS_STORE";
    NVS2.internalFlash.$name      = "ti_drivers_nvs_NVSCC26XX1";
    NVS2.internalFlash.regionBase = 0x52000;
    NVS2.internalFlash.regionType = "Pointer";
    
    PWM1.$name                            = "PWM_V_A";
    PWM1.timerObject.$name                = "CONFIG_GPTIMER_0";
    PWM1.timerObject.timer.pwmPin.$assign = "10";
    PWM1.timerObject.pwmPinInstance.$name = "CONFIG_PIN_10";
    
    PWM2.$name                                          = "PWM_V_B";
    PWM2.timerObject.$name                              = "CONFIG_GPTIMER_1";
    PWM2.timerObject.timer.pwmPin.$assignAllowConflicts = "18";
    PWM2.timerObject.pwmPinInstance.$name               = "CONFIG_PIN_0";
    
    PWM3.$name                                          = "PWM_V_C";
    PWM3.timerObject.$name                              = "CONFIG_GPTIMER_2";
    PWM3.timerObject.timer.pwmPin.$assignAllowConflicts = "19";
    PWM3.timerObject.pwmPinInstance.$name               = "CONFIG_PIN_11";
    
    PWM4.$name                            = "PWM_mA_A";
    PWM4.timerObject.$name                = "CONFIG_GPTIMER_3";
    PWM4.timerObject.timer.pwmPin.$assign = "20";
    PWM4.timerObject.pwmPinInstance.$name = "CONFIG_PIN_12";
    
    PWM5.$name                            = "PWM_mA_B";
    PWM5.timerObject.$name                = "CONFIG_GPTIMER_4";
    PWM5.timerObject.timer.pwmPin.$assign = "17";
    PWM5.timerObject.pwmPinInstance.$name = "CONFIG_PIN_13";
    
    PWM6.$name                            = "PWM_mA_C";
    PWM6.timerObject.$name                = "CONFIG_GPTIMER_5";
    PWM6.timerObject.timer.pwmPin.$assign = "16";
    PWM6.timerObject.pwmPinInstance.$name = "CONFIG_PIN_14";
    
    Power.enablePolicy      = false;
    Power.calibrateRCOSC_HF = false;
    Power.calibrateRCOSC_LF = false;
    Power.calibrateFunction = "PowerCC26XX_noCalibrate";
    
    SPI1.minDmaTransferSize    = 0;
    SPI1.$name                 = "SPI_OLED_DISPLAY";
    SPI1.spi.sclkPin.$assign   = "28";
    SPI1.spi.misoPin.$assign   = "43";
    SPI1.spi.mosiPin.$assign   = "27";
    SPI1.sclkPinInstance.$name = "CONFIG_PIN_2";
    SPI1.misoPinInstance.$name = "CONFIG_PIN_3";
    SPI1.mosiPinInstance.$name = "CONFIG_PIN_4";
    
    Timer1.$name               = "TIMER_RS485";
    Timer1.timerType           = "32 Bits";
    Timer1.timerInstance.$name = "CONFIG_GPTIMER_6";
    
    UART21.$name               = "UART_MFG";
    UART21.uart.txPin.$assign  = "26";
    UART21.uart.rxPin.$assign  = "21";
    UART21.txPinInstance.$name = "CONFIG_PIN_15";
    UART21.rxPinInstance.$name = "CONFIG_PIN_16";
    
    UART22.$name                            = "UART_RS485";
    UART22.interruptPriority                = "6";
    UART22.rxInterruptFifoThreshold         = "1/8";
    UART22.rxRingBufferSize                 = 64;
    UART22.txRingBufferSize                 = 512;
    UART22.uart.txPin.$assignAllowConflicts = "19";
    UART22.uart.rxPin.$assignAllowConflicts = "18";
    UART22.txPinInstance.$name              = "CONFIG_PIN_17";
    UART22.rxPinInstance.$name              = "CONFIG_PIN_18";
    
    Watchdog1.$name = "WATCHDOG";
    
    /**
     * Pinmux solution for unlocked pins/peripherals. This ensures that minor changes to the automatic solver in a future
     * version of the tool will not impact the pinmux you originally saw.  These lines can be completely deleted in order to
     * re-solve from scratch.
     */
    I2C1.i2c.$suggestSolution                   = "I2C0";
    PWM1.timerObject.timer.$suggestSolution     = "GPTM0";
    PWM2.timerObject.timer.$suggestSolution     = "GPTM2";
    PWM3.timerObject.timer.$suggestSolution     = "GPTM0";
    PWM4.timerObject.timer.$suggestSolution     = "GPTM1";
    PWM5.timerObject.timer.$suggestSolution     = "GPTM1";
    PWM6.timerObject.timer.$suggestSolution     = "GPTM2";
    SPI1.spi.$suggestSolution                   = "SSI0";
    SPI1.spi.dmaRxChannel.$suggestSolution      = "DMA_CH3";
    SPI1.spi.dmaTxChannel.$suggestSolution      = "DMA_CH4";
    Timer1.timerInstance.timer.$suggestSolution = "GPTM3";
    UART21.uart.$suggestSolution                = "UART1";
    UART22.uart.$suggestSolution                = "UART0";
    Watchdog1.watchdog.$suggestSolution         = "WDT0";
    

    下面是显示 cc1352引脚和 I2C 总线以及上拉的示意图:

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

    这里有更多的数据...  我们还发现了一些失败。  计时似乎被某种程度上损坏。  要么我们得到一个运行脉冲,要么在字节的中间有一个位没有时钟。  由于它位于字节的中间,我不清楚我们如何使用我们的软件/硬件导致这种情况。

    径向:

    缺少时钟(注意数据会发生两次变化,因此 MCU 认为它发送了时钟脉冲):

    似乎并不是信号只是被其他一些力量所拉下来,等等。 似乎时间实际上在外围设备中浪费了。  您以前见过吗?

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

    我只是想告诉大家,我一直在请求司机团队的帮助,但事情可能需要一些时间,此外,当无法重现问题时,很难调试这一点。

    根据我的理解,您观察到两个不同的问题。

    • 读取过程停止(即使该字节为 ACK,在第一字节后时钟停止)
    • 时钟已损坏(字节中间一位根本没有时钟)

    首先,我没有听到有人报告类似的问题。

    最后一个问题似乎与硬件有关,我认为您现在拥有的硬件与您使用的 MSP432解决方案中拥有的硬件有一定的不同

    如果您有 CC1352P LP 和 MSP432套件,您能否在两个电路板上制作一个小型 I2C 示例,并将它们连接到您有传感器的电路板上,看看您是否仍然看到 MSP432代码工作正常,但 CC1352不工作? 这将为我们提供有关问题是否与您的硬件或 CC1352的 I2C 模块有关的有用信息。

    在执行上述测试时,示例应该尽可能简单,在执行测试时,最好只有一个传感器连接到总线。

    如果您能回答以下问题,也会很好:

    您多久看到一次不同的故障?

    您在所有主板上还是在某些主板上看到它?

    如果仅在某些主板上出现这种情况,您是否尝试将 CC1352P 换用另一个主板以查看问题是否消失?

    当出现时钟脉冲缺失问题时。 这是否仅在连接了传感器的情况下发生,或者您能否再现它是否不会将传感器连接到总线?

    是否仅在读取/写入数据或传输地址时发生?

    我对所有这些问题都感到非常抱歉,但如果无法重新创建问题,这可能难以解决。

    巴西

    西里

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

    是的,我们确实在寻找两种失败模式...
    此帖子将重点关注第一个问题:在第一个字节后,Sensiron RH/T 传感器读取帧停止,我有一些观察:

    我们正在以“一拍”模式读取传感器。
    这需要以下过程:
    1.发送启动测量 I2C 事务(writeCount = 2,ReadCount = 0):
         

    2.等待一段时间,以便传感器有时间执行测量。
    在此示例中,此时没有插入其他 I2C 通信。

    3.获取测量数据(具有 writeCount = 0且 ReadCount = 6的 I2C 事务):
        
    该命令成功读取了这6个数据字节。
    请注意,传感器在第一个字节后开始发送6个字节

    现在,如果上面的 START 和 GET 测量事务之间插入了以下事务:
       (writeCount = 3,ReadCount = 0)
        
    请注意,地址字节和两个数据字节中的第一个字节是不会被占用的。
    I2C 外围设备在第二个数据字节之前出现。
    I2C_transferTimeout 函数返回时出现-6 (data_nack)错误。

    我还可以看到 mstat 寄存器值设置了 ERR,DATACK_N 和 ADRACK_N 位。
        

    现在,由于 GET 测量命令(编号3以上)是在上述 nack 帧后发送的,因此所述的故障情况将如下所示:无限期地按住总线,直到我可以手动切换时钟线路9次,或者进行电源重置:
        
    此 I2C_TRANferTimeout 调用还返回-6 (data_nack)错误。

    我尝试在 mstat 寄存器中设置 ERR,DATACK_N 和 ADRACK_N 位,只是为了查看是否存在需要清除的内部 I2C 状态条件。

    我刚才尝试的另一件事是在查询 Sensirion 读数时启用时钟拉伸。
    新的 I2C_TranserTimeout 调用现在使用 writeCount =2,ReadCount =6:

    时钟保持低~12毫秒...

    CC1352和 MSP432之间的一个有趣的区别是,MSP432没有尝试发送超过它发出后的第一个地址字节,而 CC1352也在它发出之前发送了两个数据字节中的第一个。

    我忍不住认为,当启动/获取帧之间插入一个小帧时,I2C 驱动器/外围设备的内部状态会变得混乱。

    • 我们将使用我上面描述的时钟拉伸更改,因为有一些东西是要打破外围设备和/或驱动程序似乎不喜欢的启动/获取测量命令。
      这是有道理的吗?
      评论?
    • 我希望在 I2C 总线恢复运行失败后能够清除 mstat 位。
      这里有什么我可以做得更好吗?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你(们)好

    如果问题在 CC1352P 端(在插孔后未能正确清除),或者如果外围设备不希望 CC1352P 正在传输数据,即使您在地址上找到了一个小问题,那么最好确定问题是否在 CC1352P 端。

    请尝试以下操作:

    发送“开始测量”I2C 事务(writeCount = 2,ReadCount = 0)后,再发送两个 nack (writeCount = 3,ReadCount = 0)的事务后,能否关闭 I2C 驱动程序,然后在“获取测量数据”(writeCount = 0的 I2C 事务)之前再次打开 I2C 驱动程序, 读数=6)

    结果是相同的还是有效的? 如果是这样,问题似乎出在 CC1352P 方面,如果有一些寄存器等未被正确清除,我将尝试解决。

    如果这样做失败,我会假设外围设备在获取地址后不喜欢 I2C 主中继器传输数据。

    西里

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

    好的,我已经对代码进行了讲解,以便在执行以下步骤后,故障模式可以展开

    1. 将“开始测量”命令发送到地址0x44:
      (writeCount = 2,ReadCount = 0)
    2. 将命令发送到地址0x69:
      (writeCount = 3,ReadCount = 0)


      请记住,总线上没有地址0x69的设备,所以我对您上面的说法有点困惑:
      [引用 userid="2957" url="~/support/wireless-connectivity / other-wireless-group/other-wireless/f/other-wireless-technologies -forume/1067872/cc1352p-i2c-intermittently-stops-read-sensor/3958065#3958065]\n 如果问题在问题未能在问题发生后得到正确解决(CC1352P),请找出问题是否有用 或者,如果不喜欢外设,CC1352P 正在传输数据,即使您在地址上收到了一个 nack。地址0x69处没有设备,因此在这种情况下应该是 nack。
    3. 这是我关闭并重新打开 I2C 驱动程序的地方
    4. 现在,“获取测量”请求在设备上启动,地址0x44:
      (writeCount = 0,ReadCount = 6)
      此 i2cTransaction 失败,并出现-6 (data_nack)错误

    是的,它仍然失败……

    但我再次对上述一项声明感到困惑:

    [引用 userid="2957" url="~/support/wireless-connectivity / other-wireless-group/other-wireless/f/other-wireless-technologies -forume/1067872/cc1352p-i2c-intermittently-stops-read-sensor/3958065#3958065"]如果这样做失败,我会认为在发送数据后,I2C 主机/外围设备不愿意发送数据。]

    地址为0x44的设备正在等待更多时钟发送接下来的5字节数据。
    您提到的问题是在关注地址0x69处不存在的设备。
    地址0x44的设备在第一个字节后收到 CC1352的 ACK,现在正在等待更多时钟完成下一个5字节的发送(它从未收到)。

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

    首先,很抱歉我有误解。

    好消息是,我获得了一些通过 I2C 配置的传感器的 HW,我看到了类似的东西。

    需要做更多的测试,但只是想澄清一些事情。

    如果您执行“开始测量”,然后执行“获取测量”,那么您当时正在读取哪些寄存器地址?

    对于开始测量,我猜您是在写入0x00以在从设备0x44上注册0x24,但您不必为要读取的6个寄存器设置地址吗? 您正在阅读的6个寄存器的寄存器地址是什么?

    西里

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

    以下是 Sensirion SHT3X RH/T 传感器数据表的链接,供参考:
    https://sensirion.com/resource/datasheet/sht3x-d

    [引用 userid="2957" url="~ë/support/wireless-connectivity / other-wireless-group/other-wireless/f/other-wireless-technologies -forum/1067872/cc1352p-i2c-intermittently-stops-read-sensor /3959249#3959249"]如果您执行“开始测量”,并且随后出现“测量”,那么“您可以读取”下列哪些地址?

    是的,在这种情况下,测量似乎按预期工作。
    CC1352似乎仅在“获取测量”周期在紧靠框架后立即发生时才停止计时数据。

    [引用 userid="2957" url="~ë/support/wireless-connectivity / other-wireless-group/other-wireless/f/other-wireless-technologies -forume/1067872/cc1352p-i2c-intermittently-stops-read-sensor /3959249#3959249]44,您正在为开始测量编写0x0x00,但要在设备上设置地址时不能读取的记录,我想输入0x24吗? 您正在阅读的6个寄存器的寄存器地址是什么?

    开始测量不是真正的地址,不是
    看起来它被解释为一个2字节命令(0x24和0x00),当收到该命令时,SHHT3x 将开始其测量序列。
    测量序列完成后,当数据有效负载再次被寻址时,SHT3x 将开始发送6字节的数据有效负载(此部分似乎没有地址方案)。

    尽管如此,数据表确实引用了“时钟拉伸”模式,在此模式下,SHT3x 将保持 I2C 总线~15毫秒,直到测量完成,然后开始发送6字节的测量数据。

    此时,如果 CC1352不支持读取6个字节,而不在帧中包含“地址”字节(如 MSP432所做的那样),我希望实施“时钟拉伸”模式(在数据表中引用)。
    这将确保我们总线上的另一个 I2C 部件不会在“开始”和“获取”测量周期之间的事务帧中漏电。
    它不是首选的解决方案,因为它没有那么高效,但可能会像解决方案一样工作。

    感谢您的回复。
    我期待着听到您在测试过程中发现的内容。

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

    我将尝试总结我的调查结果和我迄今为止所测试的结果。

    我在我们的 LPSTK-CC1352R 上尝试制作一些与您的代码类似的代码,并与 HDC2080通信

    测试用例1:

    // Write 0x01 to register 0x0F (start conversion)
    i2cTransaction.slaveAddress = 0x41;
    txBuffer[0]                 = 0x0F;
    txBuffer[1]                 = 0x01;
    
    i2cTransaction.writeCount   = 2;
    i2cTransaction.readCount    = 0;
    I2C_transfer(i2c, &i2cTransaction);
    
    usleep(500);  // Wait for results to be ready
    
    // Read 4 bytes from the sensor
    // This is similar to what the customer is doing, but not the correct way to
    // communicate with the HDC2080, as the address of the register to read should have // been written first
    i2cTransaction.slaveAddress = 0x41;
        
    i2cTransaction.writeCount   = 0;
    i2cTransaction.readCount    = 4;
    I2C_transfer(i2c, &i2cTransaction);
    

    我不知道上述结果有多大意义,因为我不知道我在这种情况下实际阅读了哪些注册表。

    测试用例2:

    在本测试案例中,我引入了尝试访问总线上不存在的传感器(从地址0x40)的方法(与您所做的相同)

    // Write 0x01 to register 0x0F (start conversion)
    i2cTransaction.slaveAddress = 0x41;
    txBuffer[0]                 = 0x0F;
    txBuffer[1]                 = 0x01;
    
    i2cTransaction.writeCount   = 2;
    i2cTransaction.readCount    = 0;
    I2C_transfer(i2c, &i2cTransaction);
    
    usleep(500);  // Wait for results to be ready
    
    // Introduce NACKs (no slave with address 0x40), txBuffer is the same
    i2cTransaction.slaveAddress = 0x40;
    
    i2cTransaction.writeCount   = 2;
    i2cTransaction.readCount    = 0;
    I2C_transfer(i2c, &i2cTransaction);
    
    // Read 4 bytes from the sensor
    // This is similar to what the customer is doing, but not the correct way to
    // communicate with the HDC2080, as the address of the register to read should have // been written first
    i2cTransaction.slaveAddress = 0x41;
    
    i2cTransaction.writeCount   = 0;
    i2cTransaction.readCount    = 4;
    I2C_transfer(i2c, &i2cTransaction);
    

    如上所述,如果引入了两个 nack,则在读取第一个字节后时钟停止。

    测试案例3:

    当我介绍关闭和重新打开 I2C 驱动器时,在两个 nack 之后,以下读取操作按预期工作:

    // Write 0x01 to register 0x0F (start conversion)
    i2cTransaction.slaveAddress = 0x41;
    txBuffer[0]                 = 0x0F;
    txBuffer[1]                 = 0x01;
    
    i2cTransaction.writeCount   = 2;
    i2cTransaction.readCount    = 0;
    I2C_transfer(i2c, &i2cTransaction);
    
    usleep(500);  // Wait for results to be ready
    
    // Introduce NACKs (no slave with address 0x40), txBuffer is the same
    i2cTransaction.slaveAddress = 0x40;
    
    i2cTransaction.writeCount   = 2;
    i2cTransaction.readCount    = 0;
    I2C_transfer(i2c, &i2cTransaction);
        
    I2C_close(i2c);
    i2c = I2C_open(CONFIG_I2C_TMP, &i2cParams);
    
    // Read 4 bytes from the sensor
    // This is similar to what the customer is doing, but not the correct way to
    // communicate with the HDC2080, as the address of the register to read should have // been written first
    i2cTransaction.slaveAddress = 0x41;
    
    i2cTransaction.writeCount   = 0;
    i2cTransaction.readCount    = 4;
    I2C_transfer(i2c, &i2cTransaction);
    

    测试用例4:

    这与测试用例1相同,但我已向传感器添加了一条写入数据,指示要读取的寄存器:

    // Write 0x01 to register 0x0F (start conversion)
    i2cTransaction.slaveAddress = 0x41;
    txBuffer[0]                 = 0x0F;
    txBuffer[1]                 = 0x01;
    
    i2cTransaction.writeCount   = 2;
    i2cTransaction.readCount    = 0;
    I2C_transfer(i2c, &i2cTransaction);
    
    usleep(500);  // Wait for results to be ready
    
    // Write 0 to indicate which registers to read
    i2cTransaction.slaveAddress = 0x41;
    txBuffer[0]                 = 0x00;
    
    i2cTransaction.writeCount   = 1;
    i2cTransaction.readCount    = 0;
    I2C_transfer(i2c, &i2cTransaction);
    
    // Read 4 bytes from the sensor, starting at register 0x00
    i2cTransaction.writeCount   = 0;
    i2cTransaction.readCount    = 4;
    I2C_transfer(i2c, &i2cTransaction);
    

    测试用例5:

    在读取寄存器导致时钟停止之前,再次介绍 nack 情况

    // Write 0x01 to register 0x0F (start conversion)
    i2cTransaction.slaveAddress = 0x41;
    txBuffer[0]                 = 0x0F;
    txBuffer[1]                 = 0x01;
    
    i2cTransaction.writeCount   = 2;
    i2cTransaction.readCount    = 0;
    I2C_transfer(i2c, &i2cTransaction);
    
    usleep(500);  // Wait for results to be ready
    
    // Write 0 to indicate which registers to read
    i2cTransaction.slaveAddress = 0x41;
    txBuffer[0]                 = 0x00;
    
    i2cTransaction.writeCount   = 1;
    i2cTransaction.readCount    = 0;
    I2C_transfer(i2c, &i2cTransaction);
    
    // Introduce NACKs (no slave with address 0x40), txBuffer is the same
    i2cTransaction.slaveAddress = 0x40;
    i2cTransaction.writeCount   = 2;
    i2cTransaction.readCount    = 0;
    I2C_transfer(i2c, &i2cTransaction);
    
    // Read 4 bytes from the sensor, starting at register 0x00
    i2cTransaction.slaveAddress = 0x41;
    
    i2cTransaction.writeCount   = 0;
    i2cTransaction.readCount    = 4;
    I2C_transfer(i2c, &i2cTransaction);
    

    测试用例6:

    关闭并重新打开驱动程序可解决此问题:

    // Write 0x01 to register 0x0F (start conversion)
    i2cTransaction.slaveAddress = 0x41;
    txBuffer[0]                 = 0x0F;
    txBuffer[1]                 = 0x01;
    
    i2cTransaction.writeCount   = 2;
    i2cTransaction.readCount    = 0;
    I2C_transfer(i2c, &i2cTransaction);
    
    usleep(500);  // Wait for results to be ready
    
    // Write 0 to indicate which registers to read
    i2cTransaction.slaveAddress = 0x41;
    txBuffer[0]                 = 0x00;
    
    i2cTransaction.writeCount   = 1;
    i2cTransaction.readCount    = 0;
    I2C_transfer(i2c, &i2cTransaction);
    
    // Introduce NACKs (no slave with address 0x40), txBuffer is the same
    i2cTransaction.slaveAddress = 0x40;
    i2cTransaction.writeCount   = 2;
    i2cTransaction.readCount    = 0;
    I2C_transfer(i2c, &i2cTransaction);
    
    I2C_close(i2c);
    i2c = I2C_open(CONFIG_I2C_TMP, &i2cParams);
    
    // Read 4 bytes from the sensor, starting at register 0x00
    i2cTransaction.slaveAddress = 0x41;
    i2cTransaction.writeCount   = 0;
    i2cTransaction.readCount    = 4;
    I2C_transfer(i2c, &i2cTransaction);
    

    测试用例7:

    在写入寄存器地址以进行读取之前,添加生成两个 nack 的代码不会带来任何问题:

    // Write 0x01 to register 0x0F (start conversion)
    i2cTransaction.slaveAddress = 0x41;
    txBuffer[0]                 = 0x0F;
    txBuffer[1]                 = 0x01;
    
    i2cTransaction.writeCount   = 2;
    i2cTransaction.readCount    = 0;
    I2C_transfer(i2c, &i2cTransaction);
    
    usleep(500);  // Wait for results to be ready
        
    // Introduce NACKs (no slave with address 0x40), txBuffer is the same
    i2cTransaction.slaveAddress = 0x40;
    
    i2cTransaction.writeCount   = 2;
    i2cTransaction.readCount    = 0;
    I2C_transfer(i2c, &i2cTransaction);
    
    // Write 0 to indicate which registers to read
    i2cTransaction.slaveAddress = 0x41;
    txBuffer[0]                 = 0x00;
    
    i2cTransaction.writeCount   = 1;
    i2cTransaction.readCount    = 0;
    I2C_transfer(i2c, &i2cTransaction);
    
    // Read 4 bytes from the sensor, starting at register 0x00
    i2cTransaction.slaveAddress = 0x41;
    
    i2cTransaction.writeCount   = 0;
    i2cTransaction.readCount    = 4;
    I2C_transfer(i2c, &i2cTransaction);
    

    最后,如果 I2C 从地址未被确认(nacked),似乎存在一个与 I2C 传输单个数据字节相关的问题。

    只有在阅读后才会出现问题。

    奇怪的是,关闭并重新打开驱动程序可以“解决”我的问题,但不能解决你的问题。

    我将向研发部门报告我的调查结果,但我不知道我何时会分配资源来研究这一问题,以确定这是否是我们的驱动因素可以修复的问题, 或者,如果这是与导致主中继器传输数据字节的错误相关的另一个问题,即使从属设备未被确认。

     

    如果时钟拉伸模式对您有效,我强烈建议您采用这种方法。

    对此造成的不便,我深表歉意,我将随时向您通报我们的最新调查结果。

    巴西

    西里

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

    感谢 Siri 的努力...


    我们运行了25个(或以上)设备,但进行了以下修改:

    • 现在使用时钟拉伸,将测量命令强制为一个周期。
    • 我还创建了一个“恢复”过程,关闭 I2C 驱动程序,切换 SCL 10次,然后重新打开 I2C 驱动程序。  只要从 I2C_transferTimeout 函数返回“-9”(bus_busy 错误),就会运行此过程。

    在上一篇帖子中,您将我们的失败模式总结为两类:

    [引用 userid="2957" url="~ë/support/wireless-connection/other-wireless-group/other-wireless/f/other-wireless-technologies -forume/1067872/cc1352p-i2c-intermittently-stops-read-sensor /3955187#3955187英寸]

    根据我的理解,您观察到两个不同的问题。

    • 读取过程停止(即使该字节为 ACK,在第一字节后时钟停止)
    • 时钟已损坏(字节中间一位根本没有时钟)
    [/引用]

    由于上述代码更改,我们不再看到第一类故障。

    现在我们可以更深入地了解第二类故障:
    我们仍在看到时钟跳动和时钟缺失。

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

    你(们)好,Siri。 我正在与 Cary 合作解决这个问题。 我有一些数据可以分享他提到的第二类故障。 我们认为 CC1352 I2C 时钟偶尔会出现“问题”,导致时钟周期丢失或“运行”,从而使从属设备“停止”等待最后一个时钟完成事务。 这种情况很少发生,在某些特定设备上似乎更常见。 我们可以通过将引脚临时重新配置为 GPIO 并手动计时来成功清除总线,但是如果我们了解根本原因,我们会更愿意使用此变通办法。 以下是 由我们的软件检测 I2C 问题触发的范围的三个捕获。  

    上一次捕获的结果还表明,这种特定从设备的拖得不够低,但我们认为这是一个单独的问题。

    谢谢你

    达尔顿

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

    你(们)好

    这不是我能够重新创建的东西。

    要缩小问题范围,请尝试回答以下问题

    • 这种情况发生的频率如何
    • 您看到的是一个主板还是所有主板上的一个主板?
    • 是否仅在执行一种特定类型的访问时发生(仅写入,仅写入第一个数据等)
    • 这种情况是仅在与您的一个传感器(我猜您在同一个总线上有多个传感器)通信时发生的,还是在与所有传感器通信时发生的?
    • 如果从总线上断开除一个传感器外的所有传感器,您是否也看到了同样的情况?
    • 这种情况是否可以在没有任何连接的情况下重现?
    • 您是否能够找到一种我们可以通过 LP 重现这种情况的方法?

    西里

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

    你好,Siri,

    问题似乎只发生在某些装置上。 在最差的设备上,每隔几小时发生一次。 在写入过程中,似乎总是在地址后的第一个字节中发生,从不在读取过程中发生,从不在读取过程中发生。 这是否表明我们可以 尝试什么?

    我们还没有尝试在 LP 上复制。 接下来我将尝试卸下一些传感器。

    谢谢

    达尔顿

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

    你好,Dalton

    不幸的是,我无法再现这种情况,我也没有听说有类似问题的其他人。

    我担心,当我无法看到问题时,我很难找到根本原因。

    如果你能找到一种方法让我在 LP 上重现这种情况,或者如果你能以某种方式缩小问题的范围(是否只有在处理特殊传感器时才会出现这种情况? 总线上只有一个传感器等问题是否消失?)

    巴西

    西里