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**** 2540440 points
Other Parts Discussed in Thread: MSP430F5529

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/583664/ccs-msp430f5529-critiques-welcome-for-my-blocking-i2c-driver

部件号:MSP430F5529

工具/软件:Code Composer Studio

我在过去的几天里一直在使用MSP430F5529启动板作为测试板深入了解I2C。 我通常使用SPI和UART进行数据传输,但我最近启动了一个需要I2C的项目。 用户指南很好地概述了协议和时间要求,但我觉得它没有准确解释何时需要写入寄存器(以及写入顺序)以便传输成功。

如果您对我早期的奋斗感兴趣,请参阅以下论坛帖子: e2e.ti.com/.../214.3085万

请注意,我尚未完全完成这段代码(超时,压力测试等)。 这是我的车手,可以随时提出建议。 我总是很兴奋地学习更多知识,并帮助那些经历过同样困难的人。

头文件

/*
* i2c.h
*
*创建时间:2017年3月20日
* 作者:Sheldon
*/

#ifndef I2C_H_
#define I2C_H_

#include "stdint.h"

class i2c
{
private:

	volatile uint8_t *UCxxRXBUF;
	volatile uint8_t *volatile xxTXBUF;UCUint8_t
	*UCxxBR1;
	volatile uint8_t *UCxxBR0;
	lvolatile
	volatile uint8_t *UCxxCTL0;
	volatile uint8_t *UCxxIFG;
	volatile uint8_t *UCxxIE;
	volatile uint16_t *UCxxI2CSA;

	virtual void pinSetup(); 	// Super类负责正确设置公共引脚

:

	typedef enumI2C_Type_t
	{
		USCIB0,
		USCIB1,
		USCIB2
	}I2C_Type;

	//	创建I2C主接口
	i2c (I2C_Type port, uint8_t clkDiv);
	~i2c();

	bool Byte (uint8_t address, uint*);
	bool writeByte (uint8_t地址,uint8_t字节);
	uint8_t readReg (uint8_t slaveAdd,uint8_t regAdd,uint8_t* data, uINT8_t len);

};

#endif /* I2C_H_*/ 

源文件

 

/*
* i2c.cpp
*
*创建时间:2017年3月20日
* 作者:Sheldon
*/

#include "i2c.h"
#include "MSP40.0."

i2c::i2c (I2C_Type port, uint8_t clkDiv)
{
	SWITCH(((Int16_t)port)
	{
		Case USCIB0:

			UCxxCTL1 =	&UCB0CTL1;
			UCxxCTL0 = UCB0CTR1;UCB0CT0
			=
			
			UBR0;UCBI0 = UBR0;UBR0
			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,keep SW reset
	*UCxxBR0 = clkDiv; //将时钟分配器应用到SMCLK
	*UCxxBR1 =0;
	*UCxxCTL1 &=~UCSWRST; //清除软件重置,恢复操作

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

}

i2c:~i2c ()
{

}

void i2c::pinSetup()
{
	#define ACC_I2C_SDA_PIN BIT0
	#define ACC_I2C_SDA_OUT P3SEL
	#define ACC_IR_SDA_DIR P3DIC_OUT_P3SEL
	#define #define
	ACC_I2C_REN_I2C_REB3SCL=

	
	
	
	
	

	
	

	//初始化I2C线路的GPIO功能

	ACC_I2C_SDA_SEL &=~ACC_SDA_SDA_PIN;
	ACC_I2C_SCL_SEL &=~ ACC_I2C_SCL_PIN;

	//确保将DIR设置为高电
	阻器以防止上/下拉//电阻器启用	(参见用户指南中的REN设置) ACC_I2C_DIC_DIC_DIR_SCL_PIN

	
	

	~ACC_I2C_ACC_I2C_PIN
	~

	ACC_I2C_SDA_OUT ||~ACC_I2C_SDA_PIN;
	ACC_I2C_SCL_OUT ||~ACC_I2C_SCL_PIN;

	ACC_I2C_SDA_OUT =~ACC_I2C_SDA_PIN;
	ACC_I2C_SCL_OUT ==~ACC_I2C_SCL_PIN;

	__Delay_Cycles (1000);

	ACC_ACC_SDA_DIR &=~ACC_I2C_I2C_I2C_PIN;
	ACC_I2C_SCL_DIR &=~ACC_I2C_SCL_PIN;

	__Delay_Cycles (1000);

	//将引脚功能分配给I2C
	ACC_I2C_SDA_SEL || ACC_I2C_SDA_PIN;
	ACC_I2C_SCL_SEL || ACC_I2C_SCL_PIN;
}

布尔i2c::readByte (uint8_t地址,uint8_t*字节)
{//
	问题重复启动条件(SDA高-> SCL高时低转换)
	//按下启动条件后,也将按下7位从属地址+ R/W位(UCTR )。
	//请参见下面的时间图://#####################################################.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.
	
	//#位#| 1 | 7. | 1 | 1 |#
	//#----------- ------------------------------- #//#
	Master #| start | slave address | R/W | #//#-----------
	------------------------------- #//#
	从属# | ACK|#//##########################################
	

	*UCxxI2CSA =地址;
	*UCxxCTL1 || UCTXSTT;
	*UCxxCTL1 &=~UCTR;

	//等待启动条件清除
	,同时(*UCxxCTL1和UCTXSTT)== UCTXSTT); 	//使用计时器执行机具超时

	//确保从从属设备接收到确认
	//(如果我们没有收到ACK,将设置一个nack中断位)
	IF (*UCxxIFG & UCNACKIFG)== UCNACKIFG)
	{//
		如果收到Nack,发出停止条件
		*UCxxCTL1;|| UCTXSTP;

		//不从从属设备读取任何字节返回
		//警告:如果总线锁定
		返回错误,请考虑重置从属设备;
	}//

	此时从属设备已确认启动条件+ ReadBit,并正在通过总线推动数据字节。
	//由于此函数只接收到一个字节,因此我们必须在此处发出停止条件,以确保从属设备不会试图
	//发送更多数据。

	*UCxxCTL1 || UCTXSTP;

	//等待接收数据中断触发
	//从从属设备检索到数据后,USCI模块将推出一个停止位

	,同时(!(*UCxxIFG & UCRXIFG)); 	//使用计时器执行超时

	//现在我们可以从XBUF加载从属数据字节
	*byte =*UCxxXBUF;

	//现在我们必须检查从属设备是否已确认我们的停止位
	。而(*UCxxCTL1 & UCTXSTP)=UCTXSTP); 		//使用计时器执行超时

	//向成功接收数据的调用函数发送信号
	返回true;
}

布尔i2c::writeByte (uint8_t地址,uint8_t字节)
{//
	问题重复启动条件(SDA高-> SCL高时低转换)
	//按下启动条件后,也将按下7位从属地址+ R/W位(UCTR )。
	//请参见下面的时间图://#####################################################.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.
	
	//#位#| 1 | 7. | 1 | 1 |#
	//#----------- ------------------------------- #//#
	Master #| start | slave address | R/W | #//#-----------
	------------------------------- #//#
	从属# | ACK|#//##########################################
	

	*UCxxI2CSA =地址;
	*UCxxCTL1 || UCTXSTT;
	*UCxxCTL1 || UCTR;


	//确保从从属设备收到确认
	//(如果我们没有收到ACK,将设置一个nack中断位)
	if(*UCxxIFG & UCNACKIFG)== UCNACKIFG)
	{//
		如果收到Nack,发出停止条件
		*UCxxCTL1 || UCTXSTP;

		//不从从属设备读取任何字节返回
		//警告:如果总线锁定
		返回false
	,则考虑重置从属设备;}//

	使用传出字节加载TXBuf
	*UCxxTXBUF = byte;

	//等待启动条件清除
	while (*UCxxCTL1和UCTXSTT)== UCTXSTT); 	//使用计时器执行机具超时

	//等待TXBUF移出
	,同时(!(* UCxxIFG和UCTXIFG));

	//发出停止条件
	* UCxxCTL1 ||= UCTXSTP;

	//我们现在必须检查从属设备是否已确认我们的停止位
	。同时(* UCxxCTL1和UCTXSTP)= UCTXSTP); 		//使用计时器执行超时

	//向成功传输数据的调用函数发送信号
	返回true;
}


uint8_t i2c::readReg (uint8_t slaveAdd, uint8_t regAdd, uint8_t* data, uint8_t len)
{//
	操作理论: 许多I2C从属设备都有一个与
	地址和值对应的寄存器表。 此函数通过
	执行以下操作来读取寄存器(或支持多寄存器读取的设备//)的值:

	// 1)发送从属I2C地址
	//2)发送从属寄存器地址
	//3)使用读取位设置发送重复启动
	// 4)读取任意数量的字节



	//使用写入启用的第一个发送启动条件
	*UCxxI2CSA = slaveAdd;
	*UCxxCTL1 |= UCTXSTT;
	*UCxxCTL1 || UCTR;

	//使用传出字节加载TXBuf
	*UCxxTXBUF = regAdd;

	//如果我们等待字节移出,即检查TXIFG
	//变低,我们就错过了重复启动的机会。
	//因此,我们将重复启动,然后等待
	//启动条件清除。

	//重复启动
	*UCxxCTL1 &=~UCTR;
	*UCxxCTL1 |= UCTXSTT;

	//等待启动条件清除
	while (*UCxxCTL1 & UCTXSTT)== UCTXSTT); 	//使用定时器执行机具超时


	//此时从属设备已确认启动条件+ ReadBit,并正在通过总线推送数据字节。
	for (uint8_t idx = 0;idx < len; IDX++)
	{//
		在我们预期接收的最后一个字节之前发出停止条件
		IF (idx == len -1)
			*UCxxCTL1 || UCTXSTP;

		//等待接收数据中断触发
		//从从属设备检索到数据后,USCI模块将推出一个停止位
		,同时(!(*UCxxIFG & UCRXIFG)); 	//使用计时器执行超时

		//现在我们可以从XBUF
		数据[idx]=*UCxxRXBUF;
	}//加载从属数据字节

	,我们现在必须检查从属设备是否已确认我们的停止位
			

	

。while (*UCxxCTL1 & UCTXSTP)=UCTXSTP);//要使用计时器执行超时,返回TRUE

 

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

    感谢您为I2C驱动程序提供帮助其他社区成员的帮助,我还将借此机会为SLAA734做广告,以获取有关常见MSP430通信问题的解决方案和调试建议: www.ti.com/.../slaa734.pdf

    此致,
    Ryan