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.

[参考译文] MSP430F5419A:与EEPROM进行I2C通信(24LC32)-不工作(返回0xFF)

Guru**** 2595770 points
Other Parts Discussed in Thread: MSP430F5419A

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/636507/msp430f5419a-i2c-communication-with-eeprom-24lc32---not-working-returning-0xff

部件号:MSP430F5419A
主题中讨论的其他部件: BQ7.62万

您好,  

我尝试使用应用报告中提供的代码- SLAA115,以便与EEPROM 24LC32AT通信。

问题是,当我尝试从EEPROM读取一些值时,它为所有寄存器提供255 (下图)。



EEPROM通过以下方式连接到UC:

我使用的代码如下:

主要c

#include <msp430f5419a.h>
#include <I2Croutings.h>

unsigned char read_val[10];
unsigned char write_val[10];
unsigned int address;

int main(void){

无符号int I;

WDTCTL = WDTPW + WDTHOLD;//停止看门狗计时器

InitI2C (0x50);//初始化I2C模块

而(1){

//用计数器值填充write_val数组
对于(i =0 ; i <= sizeof(write_val); I++){
write_val[i]= i;
}

地址= 0x0000;//将起始地址设置为0

//写入一个数据数组序列
eeprom_PageWrite (地址,write_val,sizeof(write_val));

//从EEPROM读取一系列数据
eeprom_SequentialRead (地址,读取val,大小of (读取val));

__DELAY周期(1万);
}

}

I2Croutings.c

#include "msp430f5419a.h"
#include "I2Croutings.h"

#define MAXPAGEWRITE 32

int PtrTransmit;
unsigned char I2CBufferArray[66];
unsigned char I2CBuffer;/*------------------

*///
说明:
// I2C模块的初始化
/*---------------------------------- */
void InitI2C (unsigned char eeprom_i2c_address)
{
I2C_PORT_DIR |= SDA_PIN + SCL_PIN;
I2C_PORT_SEL || SDA_PIN + SCL_PIN; //将I2C引脚分配给USI_B0

//建议的I2C模块初始化步骤,如用户指南中所示:
UCB2CTL1 |= UCSWRST; //启用软件重置
UCB2CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C主控,同步模式
UCB2CTL1 = UCSSEL_2 + UCTR + UCSSWRST; //使用SMCLK,TX模式,保持软件重置
UCB2BR0 = SCL_CLock_DIV; // fSCL = SMCLK/12 =~100kHz
UCB2BR1 = 0;
UCB2I2CSA = eeprom_i2c_address; //定义从属地址
//在本例中为从属地址
//定义的控制字节是
//发送到EEPROM。
//UCB2I2COA = 0x01A5; //自己的地址。

UCB2IE |= UCTXIE+UCRXIE;
UCB2CTL1 &=~UCSWRST; //清除软件重置,

如果(UCB2STAT和UCBBUSY)恢复操作 //测试总线是否为空闲
{ //否则手动时钟打开
//已生成
I2C_PORT_SEL &=~SCL_PIN; //为SCL选择端口功能
I2C_PORT_OUT &=~SCL_PIN; //
I2C_PORT_DIR || SCL_PIN; //驱动SCL过低
I2C_PORT_SEL || SDA_PIN + SCL_PIN; //为选择模块功能
//使用的I2C引脚
};

__enable_interrupit();
}/*------------------

*///
说明:
//初始化I2C模块以进行写入操作。
/*------------------ */
void I2CWriteInit (void)
{
UCB2CTL1 |= UCTR; // UCTR = 1 =>传输模式(R/W位= 0)
UCB2IFG &=~UCTXIFG;
UCB2IE &=~UCRXIE; //禁用接收就绪中断
UCB2IE|= UCTXIE; //启用传输就绪中断
}//*------------------

*///
说明:
//初始化I2C模块以进行读取操作。
/*------------------ */
void I2CReadInit(void)
{
UCB2CTL1 &=~UCTR; // UCTR = 0 =>接收模式(R/W位= 1)
UCB2IFG &=~UCRXIFG;
UCB2IE &=~UCTXIE; //禁用传输就绪中断
UCB2IE |= UCRXIE; //启用接收就绪中断
}/*----------------------------------

*///
说明:
//字节写入操作。
通过I2C总线与EEPROM //(2465)实现通信。 数据字节写入用户定义的地址。
/*------------------ */
void eeprom_ByteWrite (无符号int地址,无符号char数据)
{
无符号char ADR_HI;
无符号char ADR_lo;

while (UCB2STAT & UCBUSY); //等待I2C模块
//已完成所有操作。

ADR_HI =地址>> 8; //计算高字节
ADR_LO =地址和0xFF; //和地址

I2CBufferArray[2]的低字节= ADR_HI; //低字节地址。
I2CBufferArray[1]= ADR_LO; //高字节地址。
I2CBufferArray[0]=数据;
PtrTransmit = 2; //设置I2CBufferArray Pointer

I2CWriteInit();
UCB2CTL1 || UCTXSTT; //开始条件生成
//=> I2C通信已启动
//__bis_sr_register (LPM0_bits + GIE); //输入LPM0 w/中断
while (UCB2CTL1 & UCTXSTP); //确保已发送停止条件
}/*----------------------------------

*///
说明:
//页面写入操作。
通过I2C总线与EEPROM //(24xx65)实现通信。 数据字节写入用户定义的地址。
/*------------------ */
void eeprom_PageWrite (unsigned int StartAddress,unsigned char * Data,unsigned char size)
{
volatile unsigned int i =0;
volatile unsigned char counterI2cBuffer;
unsigned char ADR_hi;
unsigned char char_lo;adr
int currentAddress = StartAddress;
unsigned char currentSize = size;unsigned
bufferPtr =0;
unsigned moreDataRead =1;

期间(UCB2STAT和UCBUSY); //等待I2C模块
//已完成所有操作。

//执行,直到数据缓冲区中没有更多数据
,同时(moreDataToRead)
{
ADR_HI =当前地址>> 8; //计算高字节
ADR_LO =当前地址和0xFF; //和地址的低字节

//将数据降级为每次传输的64字节数据包
//保留当前startaddress的指针
IF (当前大小> MAXPAGEWRITE)
{
bufferPtr = bufferPtr + MAXPAGEWRITE;
CounterI2cBuffer = MAXPAGEWRITE -1;
PtrTransmit = MAXPAGEWRITE + 1; //设置I2CBufferArray指针
currentSize =当前大小- MAXPAGEWRITE;
currentAddress = currentAddress + MAXPAGEWRITE;

//获取起始地址
I2CBufferArray[MAXPAGEWRITE + 1]= ADR_HI;//高字节地址。
I2CBufferArray[MAXPAGEWRITE]= ADR_lo;//低字节地址
。}
否则
{
bufferPtr = bufferPtr +当前大小;
counterI2cBuffer =当前大小-1;
PtrTransmit =当前大小+1; //设置I2CBufferArray指针。
moreDataToRead = 0;
currentAddress = currentAddress + currentSize;

//获取起始地址
I2CBufferArray[currentSize + 1]= ADR_HI;//高字节地址。
I2CBufferArray[当前大小]= ADR_lo;//低字节地址
。}

//将数据复制到I2CBufferArray
无符号字符temp;
对于(i;i < bufferPtr;I++)
{
Temp =数据[I]; //必需或否则IAR抛出
//警告[Pa082]
I2CBufferArray[counterI2cBuffer]= temp;
CounterI2cBuffer--;
}

I2CWriteInit();
UCB2CTL1 || UCTXSTT; //开始条件生成
//=> I2C通信已启动
//__bis_sr_register (LPM0_bits + GIE); //输入带中断的LPM0
(UCB2CTL1和UCTXSTP); //确保停止条件已发送

eeprom_AckPolling(); //确保在EEPROM中写入数据
}}/*----------------------------------


*///
说明:
//当前地址读取操作。 从EEPROM读取数据。
使用来自EEPROM的当前//地址。
/*------------------ */
unsigned char eeprom_CurrentAddressRead (void)
{
while (UCB2STAT & UCBUSY); //等待I2C模块
//已完成所有操作
I2CReadInit();

UCB2CTL1 || UCTXSTT; // I2C启动条件
while (UCB2CTL1和UCTXSTT); //开始条件已发送?
UCB2CTL1 || UCTXSTP; // I2C停止条件
//__bis_sr_register (LPM0_bits + GIE); //输入LPM0 w/中断
while (UCB2CTL1 & UCTXSTP); //确保停止条件已发送
返回I2CBuffer;
}/*------------------

*///
说明:
//随机读取操作。 从EEPROM读取数据。 EEPROM
//地址是使用参数Address定义的。
/*------------------ */
unsigned char eeprom_RandomRead (unsigned int Address)
{
unsigned char ADR_hi;
unsigned char ADR_lo;

while (UCB2STAT & UCBUSY); //等待I2C模块
//已完成所有操作

ADR_HI =地址>> 8; //计算高字节
ADR_LO =地址和0xFF; //和地址

I2CBufferArray[1]= ADR_HI的低字节; //存储必须存储到
I2CBufferArray[0]= ADR_LO的单个字节; //在I2CBuffer中发送。
PtrTransmit = 1; //设置I2CBufferArray指针

//写入地址第一
I2CWriteInit();
UCB2CTL1 || UCTXSTT; //开始条件生成
//=> I2C通信已启动
//__bis_sr_register (LPM0_bits + GIE); //输入LPM0 w/中断
while (UCB2CTL1 & UCTXSTP); //确保停止条件已发送

//读取数据字节
I2CReadInit();

UCB2CTL1 |= UCTXSTT; // I2C启动条件
while (UCB2CTL1和UCTXSTT); //开始条件已发送?
UCB2CTL1 || UCTXSTP; // I2C停止条件
//__bis_sr_register (LPM0_bits + GIE); //输入LPM0 w/中断
while (UCB2CTL1 & UCTXSTP); //确保停止条件已发送
返回I2CBuffer;
}/*------------------

*///
说明:
//连续读取操作。 从作为
起点的参数地址以连续//形式从EEPROM读取数据。 指定
要//读取的大小并填充到数据缓冲区。
/*------------------ */
void eeprom_SequentialRead (无符号int地址,无符号char *数据,无符号int大小)
{
无符号char ADR_HI;
无符号charADR_lo;
无符号int counterSize;

while (UCB2STAT & UCBUSY); //等待I2C模块
//已完成所有操作

ADR_HI =地址>> 8; //计算高字节
ADR_LO =地址和0xFF; //和地址

I2CBufferArray[1]= ADR_HI的低字节; //存储必须存储到
I2CBufferArray[0]= ADR_LO的单个字节; //在I2CBuffer中发送。
PtrTransmit = 1; //设置I2CBufferArray指针

//写入地址第一
I2CWriteInit();
UCB2CTL1 || UCTXSTT; //开始条件生成
//=> I2C通信已启动
//__bis_sr_register (LPM0_bits + GIE); //输入LPM0 w/中断
while (UCB2CTL1 & UCTXSTP); //确保停止条件已发送

//读取数据字节
I2CReadInit();

UCB2CTL1 |= UCTXSTT; // I2C启动条件
while (UCB2CTL1和UCTXSTT); //开始条件已发送?

对于(尺寸= 0;尺寸<尺寸;尺寸+)
{
//__bis_sr_register (LPM0_bits + GIE); //输入带中断的LPM0
Data[CounterSize]= I2CBuffer;
}
UCB2CTL1 || UCTXSTP; // I2C停止条件
//__bis_sr_register (LPM0_bits + GIE); //输入LPM0 w/中断
while (UCB2CTL1 & UCTXSTP); //确保已发送停止条件
}/*----------------------------------

*///
说明:
//确认轮询。 如果正在
执行写入循环//,EEPROM将不会确认。 它可用于确定何时完成写入周期。
/*------------------ */
void eeprom_AckPolling(void){

while (UCB2STAT & UCBUSY); //等待I2C模块
//已完成所有操作
,请执行
{
UCB2STAT = 0x00; //清除I2C中断标志
UCB2CTL1 |= UCTR; // I2CTRX=1 =>传输模式(R/W位=0)
UCB2CTL1 &=~UCTXSTT;
UCB2CTL1 || UCTXSTT; //生成启动条件
While (UCB2CTL1和UCTXSTT) //等待I2CSTT位被清除
{
IF (!(UCNACKIFG和UCB2STAT)) //如果收到ACK,则中断
中断;
}
UCB2CTL1 || UCTXSTP; //停止条件在之后生成
//已发送从属地址=>开始I2C通信
同时(UCB2CTL1和UCTXSTP); //等待停止位重置
__DELAY周期(500); //软件延迟

时间} While (UCNACKIFG & UCB2STAT);
}//

ISR

#pragma vector = USCI_B2_Vector
__interrupt void USI_B2_B2(void)
{
IF (UCTXIFG & UCB2IFG)
{
UCB2TXBUF = I2CBufferArray[PtrTransmit];//加载TX缓冲区
PtrTransmit --; // Decrement TX字节计数器
IF (PtrTransmit <= 0)
{
while (!(UCB2IFG和UCTXIFG));
UCB2CTL1 || UCTXSTP; // I2C停止条件
UCB2IE &=~UCTXIE; //禁用中断。
UCB2IFG &=~UCTXIFG; //清除USI_B0 TX int标志
//__BIC_SR_REGISTER_ON_EXIT (LPM0_bits);//退出LPM0
}
}
否则IF (UCRXIFG和UCB2IFG)
{
I2CBuffer = UCB2RXBUF; //将收到的数据存储在缓冲区中
//__BIC_SR_REGISTER_ON_EXIT (LPM0_bits);//退出LPM0
}

I2Croutines.h

#define I2C_PORT_SEL P9SEL
#define I2C_PORT_OUT P9OUT
#define I2C_PORT_DIR
P9DIR #define I2C_PIN
BIX1 // UCB0SDA引脚
#define SCL_PIN BIIT2 // UCB.S引脚
#define SCL_CLock_DIV 0x14 //

无
符号EEPROM byitchar,I2c_unsigned地址
void eeprom_PageWrite (unsigned int StartAddress,unsigned char * Data,unsigned char size);
unsigned char eeprom_CurrentAddressRead
(void);
void_SequentialRead (unsigned int Address,unsigned char * Data,unsigned int size);
void eeprom_AckPolling(void); 

我错过了什么吗? 有任何提示?

谢谢!

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

    从MSP430x11x到MSP430F5419A的移植工作看起来是有效的,但可能仍存在一些遗漏。 您是否使用示波器或逻辑分析仪评估了I2C总线? 您为什么完全禁用LPM0条目? 这很可能会干扰您的读/写序列,因为在发送多个字节时,仅检查UCTXSTP位是不够的。

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

    我降低了CLK频率并启用了LMP0条目,它已经工作了! 谢谢!

    在我得到的示例中,代码的这些部分被禁用,这就是为什么我甚至没有考虑它的原因。

    但是,我对这个嵌入式编程主题很陌生,我不明白为什么我必须启用低功耗模式。 对我来说,如果我想节省能源,我只需要启用/禁用此模式。 请详细解释为什么会出现这种情况,以及如何在没有此LPM0启用/禁用序列的情况下使其工作?

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

    我很高兴听到您现在有了一个有效的解决方案。 启用LPM0会禁用CPU在ISR允许其退出LPM之前主动执行指令。 不这样做,加上没有正确的标志轮询检查,会导致I2C序列混淆。

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

    现在我明白了。 我添加了一个标志来控制流,它在未激活LPM的情况下工作。
    感谢你的帮助。

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

    github.com/.../msp430-i2c_eeprom-rtc-24LC32AT-BQ7.62万

    MSP430F5419A正在通过WFP 9.1 /2与24LC32AT和bq7.62万通信(读/写)。

    我们欢迎任何建议和改进。

    此致,