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.

[参考译文] RF430CL331H:具有400kbits/s、时钟扩展的 I2C 接口

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

https://e2e.ti.com/support/wireless-connectivity/other-wireless-group/other-wireless/f/other-wireless-technologies-forum/939501/rf430cl331h-i2c-interface-with-400kbits-s-clock-stretching

器件型号:RF430CL331H
主题中讨论的其他器件: MSP430FR2475

我通过使用 RF430CL331H_Host_Firmware (sloc320.zip)中提供的通信堆栈、使用 RF430CL331H 实现了 NDEF 4类标签。

RF430CL331H 连接到 MSP430FR2475 eUSCI_B1接口。 代码已从 eUSCI_B0迁移到 eUSCI_B1。

总线上没有其他 I2C 外设。 MSP430FR2475以16MHz 运行。

如果我们使用100kBit/s 的 I2C 接口运行、通信工作正常、我可以从标签读取所有数据。

但是、如果我们希望与400kBits 进行通信、那么通信将在 MSP 向 RF430写入命令以从3读取数据时停止。 NDEF 文件。

SCL 线路被永久拉低、任何事件都不会将 MSP430从睡眠状态唤醒。

RF430CL331H 数据表指定如果主控器件支持时钟扩展、则支持400kBit/s、如所示、eUSCI_B 就是这种情况

MSP430FR4xx 和 MSP430FR2xx 系列数据表。

TI 的示例应用配置为在400kBits /秒上运行

   UCB0BRW = 20;                         //波特率= SMLK/20 = 400kHz

有一些令人恼火的东西:为什么在示例实现中没有检查 RF430_I2C_Write 函数中的 UCSCLLOW?

我还不清楚的是:MSP430FR2xx 系列数据表规定了应避免时钟拉伸的情况。

这些情况是否适用于主模式? 如果是、在示例代码中在何处处理它们?

感谢您的支持!

/*
 * RF430_Comm.c
 * Polarion ID:ISM_CU-2171
 *
 * RF430CL331H 主机示例项目
 *
 *版权所有(C) 2015 Texas Instruments Incorporated - http://www.ti.com/
 *
 *
 * 以源代码和二进制形式重新分发和使用、有无
 * 如果满足以下条件、则允许进行修改
 符合*:  
 *
 *   源代码的重新分发必须保留上述版权
 *   注意、此条件列表和以下免责声明。
 *
 *   二进制形式的再发行必须复制上述版权
 *   请注意、中的此条件列表和以下免责声明
 *   随提供的文档和/或其他材料
    *分发。
 *
 *   德州仪器公司的名称和名称均不相同
 *   其贡献者可用于认可或推广衍生产品
 *   未经特定的事先书面许可。
 *
 * 本软件由版权所有者和贡献者提供
 * "按原样"以及任何明示或暗示的保证、包括但不包括
 * 仅限于对适销性和适用性的暗示保证
 * 一项特定目的不予承认。 在任何情况下、版权均不得
 * 所有者或贡献者应对任何直接、间接、偶然或
 * 特殊、惩戒性或后果性损害(包括但不包括)
 * 仅限于采购替代货物或服务;丧失使用、
 * 数据或利润;或业务中断)
 * 责任理论、无论是合同责任、严格责任还是侵权行为
 * (包括疏忽或其他)因使用而以任何方式产生
 * 、即使被告知可能会发生此类损坏。
 *
*
#include "config.h"
#if CONFIG_IMPLET_NFC

//#include "msp430.h"
#include "RF430_example.h"
#include "RF430_Comm.h"
#include
#include

#define START          1.
#define 继续       0
#define 失败           0
define PASS           1
#define SET            1
#define CLEAR          0
#define I2C_Nack_RCVD  2.
#define I2C_Transmit   3.
#define LPM_MODE       LPM0_BITS
uint8_t * PTxData;                    //指向 TX 数据的指针
uint8_t * PRxData;                    //指向 RX 数据的指针
uint16_t TXByteCtr;
uint16_t RXByteCtr;

uint8_t RF430_I2C_STATE;
uint8_t RF430_I2C_Start = 0;

//#define I2C_DELAY                600
//#define PULSEL_OUT P1SEL &=~BIT4;P1DIR |= BIT4;P1OUT|= BIT4 //范围中断
#define I2C_DELAY          0
#define I2C_allow              (I2C_READY_IN 和 I2C_READY_PIN)

/
*  Read_Register
(三
*
*简介:在 reg_addr 读取寄存器,返回结果
*
* param[in]:  reg_addr:从中读取数据的地址
*
* param[out]:  无
*
* return:     uint16_t:寄存器的结果
(二 /
uint16_t READ_Register (uint16_t REG_addr)

   uint8_t TxAddr[2]={0、0};
   uint8_t RxBuffer[2]={0、0};

   TxAddr[0]= reg_addr >> 8;     //地址的 MSB
   TxAddr[1]= reg_addr & 0xFF;   //地址 LSB

   while (!I2C_allow);     //等待、直到它可以安全地传输

   if (RF430_I2C_Write_Restart_Read (((uint8_t *) TxAddr、2、(uint8_t *) RxBuffer、2)!=失败)
       返回 RxBuffer[1]<< 8 | RxBuffer[0];
   其他
       __no_operation();

   while (UCB1CTL1 & UCTXSTP);            //确保发送了 STOP 条件

   返回 RxBuffer[1]<< 8 | RxBuffer[0];


/
*  Read_Continuous
(三
*
*简介:连续读取 data_length 字节并存储在"read_data"区域
*
* param[in]:  reg_addr:从中读取数据的地址
*              data_length:要读出的数据量
*
* param[out]:  read_data:存储读出数据的数组
*
*返回:     无
(二 /
void read_continuous (uint16_t reg_addr、uint8_t* read_data、uint16_t data_length)

   uint8_t TxAddr[2]={0、0};

   TxAddr[0]= reg_addr >> 8;     //地址的 MSB
   TxAddr[1]= reg_addr & 0xFF;   //地址 LSB

   while (!I2C_allow);     //等待、直到它可以安全地传输

   RF430_I2C_Write_Restart_Read (((uint8_t *) TxAddr、2、(uint8_t *) Read_data、data_length);

   while (UCB1CTL1 & UCTXSTP);            //确保发送了 STOP 条件



/
*  Write_Register
(三
*
*简介:在 reg_addr 写入寄存器的值
*
* param[in]:  reg_addr:要将数据写入的地址
*              value:要写入 reg_addr 的值
*
* param[out]:  无
*
*返回:     无
(二 /
空 Write_Register (uint16_t reg_addr、uint16_t value)

   uint8_t TxData[4]={0、0、0};

   TxData[0]= reg_addr >> 8;     //地址的 MSB
   TxData[1]= reg_addr & 0xFF;   //地址 LSB
   TxData[2]=值& 0xFF;
   TxData[3]=值>> 8;

   while (!I2C_allow);     //等待、直到它可以安全地传输

   RF430_I2C_Write ((uint8_t *) TxData、4、start);

   RF430_I2C_Send_Stop ();

   {
       uint16_t delay = 10;
       while (((UCB1CTL1 & UCTXSTP)&& DELAY)            //确保发送停止条件,添加了由于无限循环而导致的超时时间(不应为 AK 10-27-2013)
       {
           _DELAY_CYCLES (10);
           延迟;
       }
   }


/
*  Write_Continuous
(三
*
*简介:在 reg_addr 写入寄存器,并使用长度为 data_length 的"write_data"中的数据递增地址
*
* param[in]:  reg_addr:写入数据的起始地址
*              write_data:要写入的数据数组
*              data_length:要写入的数据量
*
* param[out]:  无
*
*返回:     无
(二 /
void Write_Continuous (uint16_t reg_addr、uint8_t * write_data、uint16_t data_length)

   uint8_t TxAddr[2]={0、0};

   while (!I2C_allow);     //等待、直到它可以安全地传输

   TxAddr[0]= reg_addr >> 8;     //地址的 MSB
   TxAddr[1]= reg_addr & 0xFF;   地址的//LSB

   RF430_I2C_Write ((uint8_t *) TxAddr、2、start);

   RF430_I2C_Write (((uint8_t *) write_data、data_length、continue);

   RF430_I2C_Send_Stop ();

   while (UCB1CTL1 & UCTXSTP);            //确保发送了 STOP 条件


/
*  RF430_I2C_Write
(三
*
*简介:通过 I2C 写入数据
*
* param[in]:  data:要写入的数据数组
*              length:要写入的数据量
*              CONT:如果设置为 START,则会在 I2C 总线上发出 START 条件。  另一个选项是继续(不带 Start 的数据写入)
*
* param[out]:  无
*
*返回:     无
(二 /
void RF430_I2C_Write (uint8_t *数据、uint16_t 长度、uint16_t 续)

   _DELAY_CYCLES (I2C_DELAY);                  //事务之间需要延迟

   PTxData =(uint8_t *) data;     // TX 数组起始地址

   TXByteCtr =长度;
/*检查 SCL 是否被外部拉低*/
   while (((UCB1STATW 和 UCSCLLOW)!=0)
   {}

   如果(CONT== START){
       RF430_I2C_Start =设置;                 //需要一种了解 ISR AK 10-23-2013中何时设置了启动条件的方法
       UCB1CTL1 |= UCTR + UCTXSTT;            // I2C TX、启动条件
   }
   否则{
       UCB1CTL1 |= UCTR;                      // I2C TX
       UCB1IFG |= UCTXIFG;                    //自起不发送 Kickoff IFG
   }

   _bis_SR_register (LPM_MODE + GIE);    //输入 LPM、启用中断
   __no_operation();                      //保持在 LPM 中直到所有数据
                                           //是 TX
   RF430_I2C_Start =清除;               //这应该在中断中清除、但为了确保也在这里清除、AK-1023-2013

   如果(!(RF430_I2C_STATE = I2C_NACK_RCVD))
   {
       while (TXByteCtr!= 0);         //确保发送了 STOP 条件
   }



/
*  RF430_I2C_READ
(三
*
*简介:通过 I2C 读取数据
*
* param[in]:  data:存储读出数据的数组
*              length:要读取的数据量
*
* param[out]:  无
*
*返回:     无
(二 /
void RF430_I2C_Read (uint8_t*数据、uint16_t 长度)

   _DELAY_CYCLES (I2C_DELAY);                  //事务之间需要延迟

   PRxData =(uint8_t *) data;   // RX 缓冲区开始
   RXByteCtr =长度;                         //加载 RX 字节计数器

   UCB1CTL1 &=~UCTR;                     // I2C 读取
   UCB1CTL1 |= UCTXSTT;                   // I2C 启动条件

   _bis_SR_register (LPM_MODE + GIE);    //输入 LPM、启用中断
                                           //保持在 LPM 中直到所有数据
                                           //是 RX
   __no_operation();                      //在此处设置断点<<和
                                           //读取 RxBuffer 缓冲区


/
*  RF430_I2C_Write_Restart_Read
(三
*
*简介:首先发送一部分数据(TX_DATA),然后接收 RF430CL331H 发送的数据
*
* param[in]:  TX_DATA:要传输的数据数组
*              TX_LENGTH:要传输的数据量
*              RX_DATA:要接收的数据数组(在发送之后)
*              rx_length:要接收的数据量
*
* param[out]:  无
*
*返回:     无
(二 /
uint8_t RF430_I2C_Write_Restart_Read (uint8_t * TX_data、uint16_t TX_length、uint8_t* Rx_data、uint16_t Rx_length)

   RF430_I2C_STATE = I2C_Transmit;

   PTxData =(uint8_t *) TX_DATA;    // TX 阵列起始地址
   TXByteCtr = TX_LENGTH;

   RF430_I2C_Start =设置;                 //需要一种了解 ISR AK 10-23-2013中何时设置了启动条件的方法
   UCB1CTL1 |= UCTR + UCTXSTT;            // I2C 主发送器模式、生成启动条件

   if (RF430_I2C_STATE = I2C_NACK_RCVD)   //如果 RF430为 NACK
   {
       //Debug_Print ("RF430 NACK!!!!!!!! \n");
       退货失败;
   }

   _bis_SR_register (LPM_MODE + GIE);    //输入 LPM、启用中断
   __no_operation();                      //保持在 LPM 中直到所有数据

   RF430_I2C_Start =清除;               //这应该在中断中清除、但为了确保也在这里清除、AK-1023-2013

   if (RF430_I2C_STATE = I2C_NACK_RCVD)   //如果 RF430为 NACK
   {
       //Debug_Print ("RF430 NACK!!!!!!!! \n");
       退货失败;
   }

   PRxData =(uint8_t *) Rx_DATA;          // RX 缓冲区开始
   RXByteCtr = rx_length;                         //加载 RX 字节计数器

   UCB1CTL1 &=~UCTR;                     // I2C 读取
   RF430_I2C_Start =清除;               //仅在发送和启动条件-AK 10-23-2013上需要
   UCB1CTL1 |= UCTXSTT;                   // I2C 启动条件

   _bis_SR_register (LPM_MODE + GIE);    //输入 LPM、启用中断
                                           //保持在 LPM 中直到所有数据
                                           //是 RX
   RF430_I2C_Start =清除;               //这应该在中断中清除、但为了确保也在这里清除、AK-1023-2013
   __no_operation();                      //在此处设置断点<<和
                                           //读取 RxBuffer 缓冲区
   回程通行证;


/
*  RF430_I2C_Send_Stop
(三
*
*简介:发出停止条件以终止数据包
*
* param[in]:  无
*
* param[out]:  无
*
*返回:     无
(二 /
void RF430_I2C_Send_Stop ()

   _DELAY_CYCLES (100);
   UCB1CTL1 |= UCTXSTP;                   // I2C 停止条件
   _enable_interrupt ();
   while (!(UCB1CTL1 & UCTXSTP));            //确保发送停止条件
   _disable_interrupt ();



/
*  USCI_B1_ISR
(三
*
*简介:处理通过 I2C 发送和接收数据包。  由上述功能控制。
*
* param[in]:  无
*
* param[out]:  无
*
*返回:     无
(二 /
#pragma vector = USCI_B1_Vector
_interrupt void USCI_B1_ISR (void)

 switch (__evo_in_range (UCB1IV、12))
 {
 USCI_NONE 案例 :
     中断;                               //无中断
 案例 USCI_I2C_UCALIFG:                  // UCALIFG 中断
     中断;
 案例 USCI_I2C_UCNACKIFG:                //收到 NACK
   RF430_I2C_STATE = I2C_NACK_RCVD;
   UCB1CTL1 |= UCTXSTP;                   // I2C 停止条件
   UCB1IFG = 0;                           //清除所有 USCI_B0标志
   _BIC_SR_REGISTER_ON_EXIT (LPM_MODE);   //退出 LPM
   中断;
 案例 USCI_I2C_UCSTTIFG:                 //开始条件
     中断;
 案例 USCI_I2C_UCSTPIFG:                 //停止条件
     中断;
 案例 USCI_I2C_UCRXIFG0:                  //处理 RX 数据
   RXByteCtr --;                           //递减 RX 字节计数器
   IF (RXByteCtr)
   {
     * PRxData++= UCB1RXBUF;              //将 RX 数据移动到地址 PRxData
     IF (RXByteCtr = 1)
       UCB1CTL1 |= UCTXSTP;               //在下一个 RX 上生成 I2C 停止条件
   }
   其他
   {
     * PRxData = UCB1RXBUF;                //将最终 RX 数据移动到 PRxData
     _BIC_SR_REGISTER_ON_EXIT (LPM_MODE);//退出活动 CPU
   }
   中断;
 案例 USCI_I2C_UCTXIFG0:                   //处理 TX 数据
   if (TXByteCtr)                         //检查 TX 字节计数器
   {
     unsigned int delay = 0;
     UCB1TXBUF =* PTxData++;              //加载 TX 缓冲区
     TXByteCtr -;                         //减量 TX 字节计数器
     if (TXByteCtr = 1)
     {
         while ((延迟< 9000)&&(UCB1CTL1 & UCTXSTT)&&(RF430_I2C_Start = SET)//仅在请求启动条件时进入此循环
         {
             _DELAY_CYCLES (40);
             延迟+=40;
         }
         if (((UCB1CTL1 & UCTXSTT)&&(RF430_I2C_Start = SET)//           仍在等待?  --仅当需要启动条件时,
         {
             RF430_I2C_STATE = I2C_NACK_RCVD;
             _BIC_SR_REGISTER_ON_EXIT (LPM_MODE);//退出 LPM
         }
     }
   }
   其他
   {
     //UCB1CTL1 |= UCTXSTP;                 // I2C 停止条件
     UCB1IFG &=~UCTXIFG;                 //清除 USCI_B0 TX 内部标志
     _BIC_SR_REGISTER_ON_EXIT (LPM_MODE);//退出 LPM
   }
   RF430_I2C_Start =清除;           //清除在第一个 TX、开始已经通过
   中断;
 默认值:
   __no_operation();
   中断;
 }


#endif

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

    尊敬的 Thomas:

    在示例中、它们看起来不包含所有检查、我同意添加 UCSCLLOW 的检查是好的。  我认为检查时钟低电平超时中断(UCCLTOIFG)也会很好。  如果这个中断触发并且您复位 eUSCI、时钟是否保持低电平?   

    对于拉伸避免、这必须只适用于从器件、因为从器件控制时钟拉伸。