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.

[参考译文] RTOS/LAUNCHXL-CC2650:从特定寄存器进行 I2C 读取和写入

Guru**** 2609895 points
Other Parts Discussed in Thread: CC2650, CC2560, CC2650STK

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

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/581551/rtos-launchxl-cc2650-i2c-read-and-write-from-specific-register

器件型号:LAUNCHXL-CC2650
主题中讨论的其他器件:CC2650CC2560CC2650STK

工具/软件:TI-RTOS

您好!

我有一个采用 I2C 协议的激光测距仪(激光雷达光)、用于触发传感器和读取距离测量。

我已经与 Arduino 和 Raspberry PI 进行了交互、并希望将其添加到 CC2650 Launchchapd 中。

我检查了 Sensortag I2C 的示例。 但问题是、我不知道如何定义寄存器地址和我要写入的值。

我需要这样的东西:

写入:WRITE (REGISTER_VALUE、REGISTER_ADDRESS、SENSOR_I2C_ADDRESS)。

读取:读取(register_address、sensor_I2C_Address)。

我有的激光雷达传感器具有 I2C 地址= 0x62。

要触发传感器来测量距离、我需要将"0x03"写入传感器的寄存器0x00。

然后等待几毫秒、然后从传感器的寄存器0x52读取测量值。

请帮我使用 CC2560 I2C 驱动程序实现它。

在驱动程序中、我如何指定我要读取或写入哪个寄存器。 以及如何定义要写入特定寄存器的值。

谢谢。

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

    您好、Asad、

    您可以使用驱动程序文档中的示例查看如何实现接收和发送功能。 它还显示了如何设置从器件的地址。 可在此处找到:
    I2CCC26XX 驱动程序参考

    谢谢、
    Gerardo

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

    我之前检查过它、但我找不到我们定义要读取或写入的寄存器地址的位置。
    i2cTrans.slaveAddress = 0x3C;设置从器件(传感器)的 I2C 地址。 但是、例如在读取基本示例中、我找不到代码指定我们要从中读取的寄存器地址的位置。
    请您向我展示一下吗?

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

    I2C 协议仅指定从机地址、然后您发送和接收到该地址。 对于具有寄存器的器件、通常的工作方式是先向从器件写入您正在读取或写入的寄存器、然后再执行后续读取或写入以获取数据。 在这种情况下、您只需将发送缓冲区设置为寄存器的地址、然后执行该操作。

    从器件的数据表可能会提供有关如何完成此操作的更多信息。

    谢谢、
    Gerardo
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我的传感器的数据表显示:"、器件具有一个默认值为0x62"A 的7位从器件地址
    然后、根据您的建议、我编写了如下代码:

    I2C_Handle I2C;
    I2C_Params i2cParams;
    I2C_Transaction i2cTransaction;
    /*创建 I2C 以供使用*/
    I2C_Params_init (&i2cParams);
    i2cParams.bitrate = I2C_400kHz;
    //i2c = I2C_open (Board_I2C_TMP、&i2cParams);
    I2C = I2C_open (Board_I2C、&i2cParams);

    txBuffer[0]= 0x65;//要从中读取的寄存器 I 的地址
    i2cTransaction.slaveAddress = 0x62;
    i2cTransaction.writeBuf = txBuffer;
    i2cTransaction.writeCount = 1;
    i2cTransaction.readBuf = rxBuffer;
    i2cTransaction.ReadCount = 2;

    /*采集20个样本并将其打印到控制台*/
    对于(i = 0;i < 20;i++){
    if (I2C_transfer (i2c、&i2cTransaction)){
    System_printf ("示例%u:%u %u\n"、i、rxBuffer[0]、rxBuffer[1]);

    否则{
    System_printf ("I2C 总线故障\n");


    但我没有得到预期的值。
    通常、对于第一个读数(i=0)、我会得到"I2C 总线故障\n"。

    阿萨德
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您的代码在我看来是正确的、您之前提到过"要触发传感器测量距离、我需要将"0x03"写入传感器的寄存器0x00 "、您是否需要在开始读取之前这么做? 我不知道器件是如何工作的、因此我想知道您正在读取的寄存器0x65中是否已经有有意义的数据。

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

    您好!
    感谢您的确认。 您是正确的、但在不触发传感器的情况下、我正在读取的寄存器应该具有有效值。
    我将再次尝试它、以查看问题是什么。
    如果我想使用相同的概念进行写入、我可以在一个命令中执行此操作、因为我需要首先写入我要写入的寄存器地址、然后写入值。 我是否可以将这两个文件都放在同一个 rxRuffer 中、只需将"i2cTransaction。writeCount"更改为2? 这种情况只会触发传感器、然后使用上一帖子中的命令开始读取测量值:

    txBuffer[0]= 0x00;//要写入的寄存器 I 的地址
    txBuffer[1]= 0x03;//我要写入寄存器的值
    i2cTransaction.slaveAddress = 0x62;
    i2cTransaction.writeBuf = txBuffer;
    i2cTransaction.writeCount = 2;
    i2cTransaction.readBuf = rxBuffer;
    i2cTransaction.ReadCount = 0;

    I2C_transfer (i2c、&i2cTransaction)

    谢谢。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    是的、没错。 如果这不起作用、您可以分享您正在使用的传感器的型号吗?

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

    当然。

    我正在使用 Garmin 的 Lidar Lite V3。

    您可以通过以下链接下载数据表:

    在为 Sensortag 模块编写的原始 I2Ctmp007代码中、我刚刚将 CC2650STK.h 中的 DIO 引脚映射更改为4号和5号引脚、因为我有 launchpad 传感器。

    我遇到的主要问题是、当我尝试使用示波器检查 DIO04和05信号时、我看不到信号值的任何变化、并且它始终为3.3伏。 但是、正如我所知(并检查了 Arduino 微控制器信号的信号)、SCL 和 SDA 信号应在读取和写入期间发生变化。

    阿萨德

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    是的、如果正在进行 I2C 通信、您应该会看到 SDA 和 SCL 信号在发送数据时发生变化。 这告诉我、这不是您要发送的数据的问题、但可能是 I2C 配置的问题。 您是否想分享您的项目以便我了解一下?

    谢谢、
    Gerardo
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    为了确保配置方面的一切正常、我甚至使用了主 i2ctmp007 (在设置上没有任何更改、只需更改地址和寄存器、并监控引脚 DI05和 DI06 (在传感器标签中用作 SDA 和 SCL) 要查看问题出在哪、但我仍然看不到信号发生任何变化。
    这里是原始文件的链接、也是我将 board.c 文件更改为与 launchpad 配合使用的链接。

    www.dropbox.com/.../AADIRq925WRjoQqaKenNTi5na

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

    当然。

    我尝试了两种设置、第一种设置我只是简单地使用了传感器标签 I2C 项目而不修改任何内容、然后只检查了 pis 5和6。 第二个项目我将 CC2650STK.h 中的引脚设置更改为引脚4和5、以使用 Launch Pad 引脚分配。 在偶数 I2C 连接尝试期间、这两种情况都不会显示 SCL 和 SDA 信号的变化。

    我在此附上了两个项目。 第一个是修改后的一个、第一个是原始的一个。 我正在使用 CCS 云。

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

    为了排除上拉电阻器的问题、您是否可以从 Launchpad 上拔下传感器并再次运行代码以检查 SDA 和 SCL 是否发生变化。

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

    我可以在 SensorTag 上使用 CCS 运行代码。

    我有一个 Lidar 传感器版本、我已经可以从中读取数据。 传感器的版本较新(根据数据表、寄存器地址用于读取和写入、但它们对协议而不是寄存器值进行了一些更改)、我不知道为什么我无法从该数据读取数据。

    I2C 数据传输正常、我不会得到任何错误、但我正在读取的寄存器值返回0。 我知道他们在较新版本的 I2C 协议中做了一些更改、但我不确定如何实现、因为我不熟悉使用您的处理器实现 I2C 协议。

    请帮帮我。

    我已经连接了传感器的数据表。

    非常感谢您的帮助。

    谢谢。

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

    阿萨德

    在执行 I2C 事务时、您是否能够确认 SDA 和 SCL 切换为低电平和高电平?

    您对 i2ctmp007_CC2650_launch_TI 所做的更改是正确的、您需要使用该项目。 在项目中、您正在读取器件的序列号(寄存器0x96)、这是查看您是否获得数据的好方法、您是否在那里获得了任何值?

    在您之前发布的代码块上、您正在从寄存器0x65读取、该寄存器似乎只是电源状态控制寄存器、我相信它会返回0。 该寄存器没有低电平和高电平寄存器、因此它只返回1个字节、因此您需要将代码修改为:

    txBuffer[0]= 0x65;//要从
    i2cTransaction.slaveAddress 读取的寄存器 I 的地址= 0x62;
    i2cTransaction.writeBuf = txBuffer;
    i2cTransaction.writeCount = 1;
    i2cTransaction.readBuf = rxBuffer;
    i2cTransaction.ReadCount = 1; 

    谢谢、
    Gerardo

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

    我认为代码是可以的、因为我从旧版本的传感器中获取数据。
    我刚刚使用公司制造传感器进行了检查。 上述更改了新版本的传感器 I2C 协议。 可能导致问题的主要更改是:“多字节读取需要使用单独的“Start”(开始)和“Stop”(停止)命令。”
    但我不知道如何使用您的平台实现它。
    对于 AVR 微控制器、我使用的线缆库非常好用且易于使用。

    您能帮助我如何修改我的代码以适应这一重要变化吗?
    我需要将从器件地址0x62写入第一个0x04至0x00
    然后、我需要从0x0F 读取结果的高字节、从0x10读取低字节。

    我还尝试先从0x0F 读取、然后从0x10完全独立、但它不起作用。

    如下所示:
    TxBuffer[0]= 0x0F;
    i2cTransaction.writeBuf = txBuffer;
    i2cTransaction.writeCount = 1;
    i2cTransaction.readBuf = rx1;
    i2cTransaction.ReadCount = 1;
    I2C_transfer (i2c、&i2cTransaction);
    Task_sleep (10000/ Clock_tickPeriod);

    TxBuffer[0]= 0x10;
    i2cTransaction.writeBuf = txBuffer;
    i2cTransaction.writeCount = 1;
    i2cTransaction.readBuf = rx2;
    i2cTransaction.ReadCount = 1;
    I2C_transfer (i2c、&i2cTransaction);
    Result =(rx1[0]<< 8)|(rx2[0]);
    System_printf ("示例%u:%d %d %d %d %d (C)\n"、i、result、rx1[0]、rx2[0]);

    我不知道如何实现这个概念:
    多字节读取需要使用单独的“Start”(开始)和“Stop”(停止)命令

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

    阿萨德

    我相信它们的意思是每个事务都需要有起始位和停止位、因此它们不允许使用重新启动位。 他们提到这仅适用于多字节读取、这意味着您刚刚发布的代码应该可以正常工作。 但是、您可以通过将您的读取和写入分解为两个事务来消除重新启动的问题、如下所示:

    /*先写*/
    txBuffer[0]= 0x0F;
    i2cTransaction.writeBuf = txBuffer;
    i2cTransaction.writeCount = 1;
    i2cTransaction.readBuf = rx1;
    i2cTransaction.ReadCount = 0;
    I2C_transfer (i2c、&i2cTransaction);
    Task_sleep (10000 / Clock_tickPeriod);
    
    //现在读取*/
    i2cTransaction.writeBuf = txBuffer;
    i2cTransaction.writeCount = 0;
    i2cTransaction.readBuf = rx1;
    i2cTransaction.ReadCount = 1;
    i2C_transfer (i2c) i2cTransaction); 

    谢谢、
    Gerardo

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    嗯、我测试了这种方法、它运行良好。

    非常感谢您的帮助。

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

    您好!

    我只是对 I2C 有另一个问题。 环路速度非常慢。

    我使用 Arduino 与相同的传感器、每4毫秒获得一次读数。 但是、对于 CC2650、相同的过程需要大约500甚至更多的时间才能获得一个循环和数据。

    我不知道为什么这个处理器的 I2C 这么慢。

    我很确定我设置的速度是传感器支持的400kHz。

    在我的 main()代码中,我初始化了以下所有内容:

    //生成 I2C 对象
    I2C_Params_init (&i2cParams);
    i2cParams.bitrate = I2C_400kHz;
    i2c = I2C_open (Board_I2C_TMP、&i2cParams);
    if (i2c = taskparams.bitrate= taskparams.pabort
    ("Error Initializing I2c\n");
    }
    否则为 TIC_params.taskParams.taskparams/
    
    
    
    taskparams.pstack (0taskparams.pparams
    
    
    
    
    = taskparams.pstack);)
    (Task_FuncPtr) taskFxn、&taskParams、NULL); 

    然后、我的任务是:

    void taskFxn (UArg0、UArgarg1)
    {
    unsigned int i;
    对于(i = 0;i < 10000;i++){
    
    if (toggle = 0)
    toggle = 1;
    else
    toggle = 0;
    PIN_setOutputValue (ledPinHandle、Board_LED1、toggle);
    
    uint32_t time1 = Clock_getTicks();
    uint8_t * resp=i2c_read (0x8F、2、0x62);
    uint32_t time2=Clock_getTicks();
    
    uint16_t temperature =(*(RESP+0)<< 8)|(*(RESP+1));
    //System_printf ("采样%u:%d (C)\n"、i、temperature);
    
    i2c_write (0x00、0x04、0x62);
    //Task_sleep (10000/ Clock_tickPeriod);
    System_printf ("系统时间=%lu %lu %u\n"、(Ulong) time1、(Ulong) time2、time2-time1);
    //System_flush ();
    
    }
    /*已取消初始化 I2C */
    I2C_Close (i2c);
    System_printf ("I2C 已关闭!\n"\});
    
    system_flush();
    } 
    uint8_t i2c_write (uint8_t reg_add、uint8_t reg_val、uint8_t add){
    uint8_t flag=1;
    uint8_t rx[2];
    uint8_t TX[2];
    TX[0]= reg_add;
    TX[1]=reg_val;
    i2cTransaction.slaveAddress = add;
    i2cTransaction.writeBuf = TX;
    i2cTransaction.writeCount = 2;
    i2cTransaction.readBuf = Rx;
    i2cTransaction.ReadCount = 0;
    if (!I2C_transfer (i2c、&i2cTransaction)){
    flag=0;
    System_printf ("I2C Bus FAULT_write\n");
    System_flush ();
    }
    
    return flag;
    }
    
    uint8_t * i2c_read (uint8_t reg_add、uint8_t rx_c、uint8_t add){
    uint8_t rx[1];
    uint8_t tx[2];
    rx[0]=reg_add;
    i2cTransaction slaveAddress = add;
    TX[0]= reg_add;
    i2cTransaction.writeBuf = TX;
    i2cTransaction.writeCount = 1;
    i2cTransaction.readBuf = Rx;
    i2cTransaction.ReadCount = 0;
    I2C_transfer (i2c、 i2cTransaction);
    
    //Task_sleep (10000/ Clock_tickPeriod);
    
    i2cTransaction.writeBuf = TX;
    i2cTransaction.writeCount = 0;
    i2cTransaction.readBuf = Rx;
    i2cTransaction.ReadCount = rx_c;
    
    if (!I2C_transfer (i2c、&i2cTransaction)){
    System_printf ("I2C 总线故障\n");
    System_flush ();
    }
    
    return Rx;
    } 

    我尝试在 I2C 读取和写入命令前后获取系统节拍、并发现这段时间大约为几百微秒、这是有道理的。 然后我认为问题是"system_print"、然后清除。 我移除了它们并放置一个 LED 闪烁、并看到环路速度仍然非常慢。 当我从环路中删除 I2C 命令时、速度是应该的速度。

    您是否有什么想法会导致此问题?

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

    阿萨德

    从 time1和 time2变量中打印出哪些值?

    此外、您的代码有两个问题:

    • 在 i2c_read()函数上,您似乎将 Rx 和 TX 数组的大小混合在一起,现在您正在将两个值读取到大小为1的 Rx 数组中。 您需要使大小至少为2。
    • 在 i2c_read()函数上,您将返回一个指向函数内部局部变量的指针,这是一个错误的主意,因为该内存在函数调用后将不在作用域中。 修复它的一种简单方法是将该变量声明为静态变量、如下所示:
      静态 uint8_t rx[2]; 

    谢谢、
    Gerardo

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

    我按照您的建议修改了转接代码、并且距离测量是准确的。

    但环路仍然非常慢。

    以下是两次迭代的结果:

    采样41:221 (C)
    系统时间= 25762 25976 214
    采样42:221 (C)
    系统时间= 26403 26617 214 

    您可以看到读取时间不慢、只需214个 clock_tick (我在配置文件中将时钟节拍持续时间设置为1usec)。

    我再次尝试注释系统打印并清除,但代码仍然很慢。

    我阅读了有关 I2C 阻塞模式的内容或类似内容。 您是否认为这会导致问题? 我没有在代码中设置任何有关它的内容。

    以下是我的修改代码:

    uint8_t i2c_write (uint8_t reg_add、uint8_t reg_val、uint8_t add){
    uint8_t flag=1;
    uint8_t rx[2];
    uint8_t TX[2];
    TX[0]= reg_add;
    TX[1]=reg_val;
    i2cTransaction.slaveAddress = add;
    i2cTransaction.writeBuf = TX;
    i2cTransaction.writeCount = 2;
    i2cTransaction.readBuf = Rx;
    i2cTransaction.ReadCount = 0;
    if (!I2C_transfer (i2c、&i2cTransaction)){
    flag=0;
    System_printf ("I2C Bus FAULT_write\n");
    System_flush ();
    }
    
    return flag;
    }
    
    
    uint8_t * i2c_read (uint8_t reg_add、uint8_t rx_c、uint8_t add){
    静态 uint8_t rx[2];
    uint8_t tx[1];
    i2cTransaction slaveAddress = add;
    TX[0]= reg_add;
    i2cBuf.writeTX;
    i2cTransaction.writeCount = 1;
    i2cTransaction.readBuf = Rx;
    i2cTransaction.ReadCount = 0;
    I2C_transfer (i2c、&i2cTransaction);
    
    //Task_sleep (10000/ Clock_tickPeriod);
    
    i2cTransaction.writeBuf = TX;
    i2cTransaction.writeCount = 0;
    i2cTransaction.readBuf = Rx;
    i2cTransaction.ReadCount = Rx_c;
    
    if (!I2C_transfer (i2c、&i2cTransaction)){
    System_printf ("I2C 总线故障\n");
    System_flush ();
    }
    return Rx;
    }
    
    
    
    
    /*
    === 回声 Fxn =====
    *此函数的任务是静态创建的。 请参阅工程的.cfg 文件。
    */
    void taskFxn (UArg0、UArg0 arg1)
    {
    unsigned int i;
    对于(i = 0;i < 10000;i++){
    
    if (toggle = 0)
    toggle = 1;
    else
    toggle = 0;
    PIN_setOutputValue (ledPinHandle、Board_LED1、toggle);
    
    uint32_t time1 = Clock_getTicks();
    uint8_t * resp=i2c_read (0x8F、2、0x62);
    uint32_t time2=Clock_getTicks();
    
    uint16_t temperature =(*(RESP+0)<< 8)|(*(RESP+1));
    System_printf ("示例%u:%d (C)\n"、i、temperature);
    
    
    i2c_write (0x00、0x04、0x62);
    //Task_sleep (10000/ Clock_tickPeriod);
    System_printf ("系统时间=%lu %lu %u\n"、(Ulong) time1、(Ulong) time2、time2-time1);
    System_flush ();
    
    }
    /*已取消初始化 I2C */
    I2C_Close (i2c);
    System_printf ("I2C 已关闭!\n"\});
    
    system_flush();
    }
    

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

    阿萨德

    从这些打印输出来看、循环迭代仅花费641个时钟周期、看起来不是很重要。 如果您想尝试并加快速度、您可以在不需要时注释掉此部分:

    /*if (toggle=0)
    TOGGLE = 1;
    否则
    TOGGL=0;
    PIN_setOutputValue (ledPinHandle、Board_LED1、toggle);* 

    至于阻塞模式与回调模式、在本示例中它不会产生影响。 在阻塞模式下、任务在 I2C 事务期间被阻止执行。 传输完成后、代码执行将恢复。 在回调模式下、任务的执行不会被阻止、从而允许其他事务排队或处理一些其他代码。 由于代码的重点是读取 i2c 数据、然后使用它、因此您不会从回调模式中受益、因为您仍需要等待 i2c 数据的接收。

    谢谢、
    Gerardo

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

    Gerardo、

    我使用了 launchpad、相同代码的速度也可以。

    我不知道 sensortag 板有什么问题。

    阿萨德