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.

[参考译文] CCS/MSP430F5529:I2C主读取-第一字节读取为垃圾(正确读取其余数据)

Guru**** 2538955 points


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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/582995/ccs-msp430f5529-i2c-master-read---first-byte-read-is-garbage-rest-of-data-is-read-properly

部件号:MSP430F5529

工具/软件:Code Composer Studio

我正在MSP430F5529LP评估板(默认时钟速率)上编写通用的,基于轮询的I2C主RX/TX驱动程序。 我有一个Adafruit metro微型(基于Arduino)板,它作为从变送器在我请求读取时发送"Hello"。

我的写功能工作正常,但当我尝试阅读时,我会遇到奇怪的行为。 从XBUF读取的第一个字节是垃圾,但整个消息以连续读取的方式接收。 如果我逐步执行代码,第一个字节不再是垃圾,我可以正确地接收整个消息。 这让我觉得我没有检查启动条件后是否正确设置了某些IFG/CCL标志,因此出现了计时问题。 令人困惑的是,如果我在发出启动条件之前阅读了RXBUF,则所有字节数都可以正确读取。  我在用户指南中没有看到任何明显的内容,让我认为这是正确的(似乎更像是黑客),所以我希望你们看到我的问题。  

I2C::i2c (I2C_Type端口,uint8_t clkDiv)
{
	SWITCH((Int16_t)port)
	{
		CASE USCIB0:

			UCxxCTL1 =	&UCB0CTL1;
			UCxxCTL0 =&UCB0CTL0;
			UCxxBR0 =&UCB0BR0;
			UCxxBR1 =&UCB0BR1 = UCBI0CSA;
			UC2I
			UCxxIFG =&UCB0IFG;
			UCxxRXBUF =&UCB0RXBUF;
			UCxxTXBUF =&UCB0TXBUF;

			Break;
		Case USCIB1:

			UCxxCTL1 =&UCB1CTL1;
			UCxxCTL0 =&UCB1CTL0;
			UCxxBR0 = CBI1BR1
			=
			
			UCxxIFG =&UCB1IFG;
			UCxxRXBUF =&UCB1RXBUF;
			UCxxTXBUF =&UCB1TXBUF;

			中断;

		默认:
			返回
	;}

	pinSetup();

	*UCxxCTL1 || UCSWRST; //启用软件重置
	*UCxxCTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C主控,同步模式
	*UCxxCTL1 = UCSSEL_2 + UCSSWRST; //使用SMCLK,保持软件重置
//	*UCxxI2CSA = 0x04;
	*UCxxBR0 = clkDiv; //将时钟分配器应用到SMCLK
	*UCxxBR1 =0;
	*UCxxCTL1 &=~UCSWRST; //清除软件重置,恢复操作

	*UCxxIE =0;
	*UCxxIFG =0; //清除中断标志

}

bool i2c::start(bool isRead)
{//
	设置I2C r/w位,发送启动条件
	if (isRead == false)
	{
		*UCxxCTL1 |= UCCTR|UCTXSTT;
	}
	else
	{
		*UCxxCTL1 || UCTXSTT;
		*UCxxCTL1 &= UCCM= UIFG;~
	

	UCNIFG}}


bool i2c::stop(void){//

	等待停止条件被接受
	uint16_t count =5000;

	*UCxxCTL1 || UCTXSTP;

	while (*UCxxCTL1 & UCTXSTP)=UCTXSTP)
	{
		COUNT--;
		IF (count <= 0)
			return false; STP
	

	return true;
}

uINT8_t i2c::read(uint8_t address, uint8_t* data, uint8_t length, bool endered)
{//
	保留读
	uint8_t的字节数br =0;//

	分配从属地址
	*UCxxI2CSA =地址;

	{//
		如果我不清除RXBUF=xxUXbf
		,将读取一个垃圾字节
	

	//发出启动请求
	if (start(true)== false)
	{//
		无论状态是否重复,都发出stop和terminate
		stop();
		返回br
	;}

	for (uint8_t idx =0;idx <长度;idx++)
	{
		Int16_t

		
		
		
			
			计数=10;//等待上一个Rx完成。while (!(*UCxxIFG & UCRXIFG){- delay;_100);
			如果(计数<= 0)
			{//
				无论状态是否重复,发出stop和terminate
				stop();
				返回0;
			}
		data[br+]=

		*UCxxRXBUF;
	}//

	调用函数将发出重复启动,如果
	(REPLUSTED == false)
		stop(),则不要发出stop;

	返回br;
} 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    在继续操作之前,是否已尝试等待启动条件完成发送(while (*UCxxCTL1 & UCTXSTT)=UCTXSTT);?

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

    感谢您的建议。 我将尝试一下,并让 您知道 结果如何。

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

    虽然我觉得这条线很好(我会把它保留在我的开始功能中),但它没有解决我的问题。 我想这并不奇怪,因为在我的源代码中,读取RXBUF的黑客攻击发生在启动条件之前。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    似乎在开始I2C序列之前已设置了RXIFG,这可能是由于之前的序列在接收到第二个至最后一个数据字节后未设置UCTXSTP位(请参阅代码示例MSP430F55xx_uscib0_i2c_10.c)。 无论如何,继续执行您已实施的变通办法/黑客攻击没有任何问题。 您可以尝试使用I2C线路的示波器或逻辑分析仪屏幕截图来进一步了解问题。

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

    感谢您的回复。 我对I2C工作原理的理解似乎存在缺陷。 我在收到信息的最后一个字节后一直在发送停止位,而它应该是倒数第二个字节。 如果我错了,请更正我,但请输入以下代码:

    uINT8_t i2c::read (uint8_t地址,uint8_t*数据,uint8_t长度,bool重复)
    {//
    	保留读取
    	uint8_t的字节数br =0;
    
    	//分配从属地址
    	*UCxxI2CSA =地址;
    
    	//如果不清除XBUF,则在实际数据之前读取垃圾字节。 (hack)
    	uint8_t dunk =*UCxxRXBUF;
    
    	//发出启动请求
    	IF (start(true)== false)
    	{//
    		无论状态是否重复,发出stop和terminate
    		stop();
    		返回br
    	;}
    
    	for (uint8_t idx =0;_idx < length;idx++
    	{
    		Int16_t counts=10;
    
    		//等待
    		
    		
    			前一个周期(IFXxx)和UCRG*100)
    			计数--;
    			IF (计数<= 0)
    			{//
    				无论状态是否重复,发出stop和terminate
    				stop();
    				返回0;
    			}
    		data[br+]=*UCxxXBUF;
    
    		
    	}//
    
    	调用函数将发出重复启动,如果
    	(REPLUSE == false)
    		stop(),请勿发出stop;
    
    	返回br;
    } 

    应该如下所示:

    uINT8_t i2c::read (uint8_t地址,uint8_t*数据,uint8_t长度,bool重复)
    {//
    	保留读取
    	uint8_t的字节数br =0;
    
    	//分配从属地址
    	*UCxxI2CSA =地址;
    
    	//如果不清除XBUF,则在实际数据之前读取垃圾字节。 (hack)
    	uint8_t dunk =*UCxxRXBUF;
    
    	//发出启动请求
    	IF (start(true)== false)
    	{//
    		无论状态是否重复,发出stop和terminate
    		stop();
    		返回br
    	;}
    
    	for (uint8_t idx =0;_idx < length;idx++
    	{
    		Int16_t counts=10;
    
    		//等待
    		
    		
    			前一个周期(IFXxx)和UCRG*100)
    			计数--;
    			IF (计数<= 0)
    			{//
    				无论状态是否重复,发出stop和terminate
    				stop();
    				返回0;
    			}
    		data[br+]=*UCxxXBUF;
    
    		
    
    //检查最后一个字节(长度- 2个表示0索引偏移和倒数第二个字节)
    IF (idx ==长度-2)
    	*UCxxCTL1 || UCTXSTP;
    	}//
    
    	调用函数将发出重复启动,如果
    	(重复== false)
    		stop(),则不发出停止; //检查是否已成功发出停止条件
    
    	返回br;
    } 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    是的,请尝试使用此代码,看看它是否解决了问题。

    此致,
    Ryan
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Ryan,这解决了我的额外垃圾字节问题。 感谢您的参与。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    只是一个免责声明,适用于计划危险地将其复制到项目中的任何人:有很多事情我都没有解决,特别是对于组合写+读操作等事情。 读取=1时的边界条件也不起作用。 最后,delay_cycles不应用于超时,因为调整时钟设置将导致超时前的可变时间量。


    只是一个警告!