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/MSP430F6720:通过 I2C 与 EEPROM 24xx128通信时出现问题

Guru**** 2564565 points


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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/605107/ccs-msp430f6720-problem-communicating-with-eeprom-24xx128-via-i2c

器件型号:MSP430F6720

工具/软件:Code Composer Studio

您好!

我正在尝试将 slaa208a 从 MSP430F1/2xxx 移植到 MSP430F67XX。 我能够在某种程度上使代码正常工作、但遇到了一些奇怪的问题。 从 EEPROM 读取似乎正常、但写入 EEPROM 总是会出现问题:

1) 1)逐一写入256字节需要几十秒。

2) 2)这些字节中的很多字节未成功写入 EEPROM。 当从这些地址读回时、其中许多地址为默认值0xFF。

下面随附了我的代码。 我应该如何进行故障排除?

提前感谢。

i2ceeprom.h

#define I2C_PORT_SEL P2SEL
#define I2C_PORT_OUT P2OUT
#define I2C_PORT_REN P2REN
#define I2C_PORT_DIR P2DIR
#define SDA_PIN BIT1 // UCB0SDA 引脚
#define SCL_PIN BIT0 // UCB.S 引脚
#define SCL_CLOCK _DIV 0x0050 // SCL 时钟分频

器 void InitI2C (unsigned char EEPROM_i2c_address);
void EEPROM_ByteWrite (unsigned int Address、unsigned
char StartAddress、unsigned char * Data、unsigned char Size);
unsigned char EEPROM_RandomRead (unsigned char int Address);// unsigned
char eeproM_CurrentRefad (unsigned
char)、unsigned char Reset_Reset_Resize*、void *、unsigned char Data)
void EEPROM_AckPolling (void);
void resetI2C (void); 

i2ceeprom.c

#include "msp430.h"
#include "i2ceeprom.h"

#define MAXPAGEWRITE 8

int PtrTransmit;
unsigned char I2CBufferArray[16];
unsigned char I2CBuffer;

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

//设置 eUSCI_B0
UCB0CTLW0 |= UCSWRST; //启用 SW 复位
UCB0CTLW0 |= UCMST | UCMODE_3 | UCSSEL_SMCLK | UCSYNC; // I2C 主设备,使用 SMCLK

// UCB0BRW = SCL_Cock_DIV; // fSCL = SMCLK/40 =~100kHz
UCB0BRW_L = 40; // fSCL = SMCLK/12 =~100kHz
UCB0BRW_H = 0;
UCB0I2CSA = EEPROM_i2c_address; //从器件地址
UCB0CTLW0 &=~UCSWRST; //清除 SW 复位、

如果(UCB0STATW 和 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 引脚
};
}

void resetI2C()
{
I2C_PORT_SEL &=~(SDA_PIN + SCL_PIN); //将 I2C 引脚分配给 GPIO
I2C_PORT_DIR &=~(SDA_PIN + SCL_PIN);//将 I2C 引脚设置为输入
I2C_PORT_REN &=~(SDA_PIN + SCL_PIN);//没有上拉或下拉电阻
器}

/*--- //
说明:
//初始化 I2C 模块以执行写操作。
/*------------------ */
void I2CWriteInit (void)
{
UCB0CTLW0 |= UCTR; // UCTL=1 =>发送模式(R/W 位= 0)
UCB0IFG &&~UCTXIFG0;
UCB0IE &&~UCRXIE0; //禁用接收就绪中断
UCB0IE |= UCTXIE0; //启用发送就绪中断}/--><!--kadov_tag{{</spaces>}/--><!--kadov_tag{</spaces>}}-->


*/
/说明:
// I2C 模块初始化以执行读取操作。
/*------------------ *
/ void I2CReadInit (void)
{
UCB0CTLW0 &&~UCTR; // UCTL=0 =>接收模式(R/W 位= 1)
UCB0IFG &&~UCRXIFG0;
UCB0IE &&~UCTXIE0; //禁用发送就绪中断
UCB0IE |= UCRXIE0; //启用接收就绪中断}/--><!--kadov_tag{{</spaces>}/--><!--kadov_tag{</spaces>}}-->


*/
//说明:
//字节写入操作。 通过 I2C 总线与 EEPROM
//(2465)进行通信。 一个数据字节被写入一个用户定义的地址。
/*------------------ //
void EEPROM_ByteWrite (unsigned int Address、unsigned char Data)
{
unsigned char ADR_hi;
unsigned char ADR_lo;

while (UCB0STATW 和 UCBUSY); //等待 I2C 模块完成所有操作。

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

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

I2CWriteInit();
UCB0CTLW0 |= UCTR | UCTXSTT; //开始条件生成 I2C 通信

__bis_SR_register (LPM0_bits + GIE); //通过中断 UCB0CTLW0输入 LPM0
|= UCTXSTP; // I2C 停止条件
while (UCB0CTLW0 & UCTXSTP); //确保已发送停止条件}/*--><!--kadov_tag{{</spaces>}--><!--kadov_tag{</spaces>}--><!--kadov_tag{</spaces>}--><!--kadov_tag{</spaces>}--><!--kadov_tag{</spaces>}}-->

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

UCB0CTLW0 |= UCTXSTT; // I2C 启动条件
while (UCB0CTLW0 & UCTXSTT); //起始条件是否已发送?
UCB0CTLW0 |= UCTXSTP; // I2C 停止条件
_ bis_SR_register (LPM0_bits + GIE); //通过中断
while (UCB0CTLW0 & UCTXSTP)输入 LPM0; //确保停止条件已发送
返回 I2CBuffer;
}-->---------------

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

while (UCB0STATW 和 UCBUSY); //等待 I2C 模块完成所有操作

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

I2CBufferArray[1]的低字节= ADR_HI; //存储必须
包含 I2CBufferArray[0]= ADR_lo 的单字节; //在 I2CBuffer 中发送。
PtrTransmit = 1;

//写入地址优先
I2CWriteInit();
UCB0CTLW0 |= UCTXSTT; //开始条件生成=> I2C 通信开始
__bis_SR_register (LPM0_Bits + GIE); //输入带中断的 LPM0
//读取数据字节
I2CReadInit();
UCB0CTLW0 |= UCTXSTT; // I2C 启动条件
while (UCB0CTLW0 & UCTXSTT); //起始条件是否已发送?
UCB0CTLW0 |= UCTXSTP; // I2C 停止条件
_ bis_SR_register (LPM0_bits + GIE); //通过中断
while (UCB0CTLW0 & UCTXSTP)输入 LPM0; //确保停止条件已发送
返回 I2CBuffer;
}-->---------------
//
//说明:
//确认轮询。 如果写入周期为
//正在进行、EEPROM 将不会应答。 它可用于确定写入周期何时完成。
/*------------------ */
void EEPROM_AckPolling (void)
{
while (UCB0STATW 和 UCBUSY); //等待 I2C 模块具有
//完成所有操作
都执行
{
UCB0STATW = 0x00; //清除 I2C 中断标志
UCB0CTLW0 |= UCTR; // I2CTRX=1 =>发送模式(R/W 位= 0)
UCB0CTLW0 &=~UCTXSTT;
UCB0CTLW0 |= UCTXSTT; //起始条件已生成
while (UCB0CTLW0和 UCTXSTT) //等待 I2CSTT 位被清零
{
if (!(UCNACKIFG & UCB0STATW)) //如果收到 ACK 则分接
中断;
}
UCB0CTLW0 |= UCTXSTP; //停止条件在之后生成
//发送从器件地址=> I2C 通信开始
while (UCB0CTLW0和 UCTXSTP); //等待停止位被复位
_delay_cycles (500); //软件延迟
}while (UCNACKIFG & UCB0STATW);
}//---------------


// USCIAB0_ISR 的结构使其可用于通过
预加载带有字节计数的 TXByteCtr 来发送任何//字节数。
///----------------------------------
// USCI_B0中断服务例程
#if defined (__TI_Compiler_version__)|| Defined (__IAR_systems_ICC__)
#pragma vector = USCI_B0_Vector
__interrupt void USCI_B0_ISR (void)
#Elif defined (__GSCI__)
void __attribute_(nvoid USCI_B0_bvector)(nuc1_b0_isr)#interrupt BUC0!


#endif
{
开关(_偶数_在范围内(UCB0IV、30))
{
USCI_NONE 案例:中断;//无中断
USCI_I2C_UCALIFG 案例:中断;// ALIFG
案例 USCI_I2C_UCNACKIFG:中断;// NACKIFG
案例 USCI_I2C_UCSTTIFG:中断;// STTIFG
案例 USCI_I2C_UCSTPIFG:中断;// STPIFG
USCI_I2C_UCRXIFG3案例:中断;// RXIFG3
USCI_I2C_UCTXIFG3案例:中断;// TXIFG3
USCI_I2C_UCRXIFG2案例:中断;// RXIFG2
USCI_I2C_UCTXIFG2案例:中断;// TXIFG2
USCI_I2C_UCRXIFG1案例:中断;// RXIFG1
USCI_I2C_UCTXIFG1案例:中断;// TXIFG1
USCI_I2C_UCRXIFG0案例:// RXIFG0
I2CBuffer = UCB0RXBUF;//将接收到的数据存储在缓冲区中
_BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//退出 LPM0
中断;
USCI_I2C_UCTXIFG0案例:// TXIFG0
UCB0TXBUF = I2CBufferArray[PtrTransmit];//加载 TX 缓冲区
PtrTransmit ----;//测量 TX 字节计数器
if (PtrTransmit < 0)
{
while (!(UCB0IFG & UCTXIFG0));
UCB0IE &=~UCTXIE0;//禁用中断。
UCB0IFG &=~UCTXIFG0;//清除 USCI_B0 TX int 标志
_BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//退出 LPM0
}
中断;
案例 USCI_I2C_UCBCNTIFG:break;// CNTIFG
USCI_I2C_UCCLTOIFG 案例:中断;// LTOIFG
USCI_I2C_UCBIT9IFG 案例:中断;// BIT9IFG
默认值:break;
}
} 

main.c

//WDTCTL = WDTPW | WDTHOLD;//停止看门狗计时器sysinit ();
WDTCTL = WDTPW | WDTSSEL_ACLK | WDTIS_3;//启用看门狗计时器:ACLK、4分钟和16秒
initSystem ();// Init i2c UART 和其他
int eepromAddr = 0;
字符 eepromCont = 0;

for (eepromAddr = 0;eepromAddr < 256;eepromAddr++){
EEPROM_ByteWrite (eepromAddr、++eepromCont);
EEPROM_AckPolling();
WDTCTL = WDTPW | WDTSSEL_ACLK | WDTIS_3 | WDTCNTCL;
}

eepromAddr = 0;
while (1){
eepromCont = EEPROM_RandomRead (eepromAddr);
eepromAddr++;
if (eepromAddr > 256){
eepromAddr = 0;
}
while (!(UCA1IFG&UCTXIFG));// USCI_A0 TX 缓冲器准备就绪?
UCA1TXBUF = eepromAddr;
while (!(UCA1IFG&UCTXIFG));// USCI_A0 TX 缓冲器准备就绪?
UCA1TXBUF = eepromCont;
while (!(UCA1IFG&UCTXIFG));// USCI_A0 TX 缓冲器准备就绪?
UCA1TXBUF = 0x0D;
WDTCTL = WDTPW | WDTSSEL_ACLK | WDTIS_3 | WDTCNTCL;
_bis_SR_register (LPM3_bits | GIE);
} 

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

    目前不涉及任何可能涉及的器件勘误表、我不明白为什么您的代码不起作用的直接原因、但已注意到您正在将 USCI 示例移植到 eUSCI。 这两个模块之间的细微差异可能会导致问题、我建议查看 SLAA522应用报告: www.ti.com/.../slaa522a.pdf

    您还应该参考 MSP430F672x I2C 代码示例并辨别是否存在明显差异。 否则、我建议您使用示波器或逻辑分析仪来查看 I2C 线路并查看发送到 EEPROM 的数据是否符合预期。

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

    感谢您的回复和指导。 到目前为止、该问题已与 Acknowledge _polling 函数隔离。 如果我用硬编码的5ms 去播放来替换轮询函数、那么写入不再是问题。

    关于 SLAA522、我认为它需要一些更新。 在第3页中、UCNACKIFG 不会在接收到 eUCSI 中的 START 条件时自动清零、但根据 MSP430F67XX 用户手册、这一情况不再正确。

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

    我很高兴听到您找到了该问题的解决方案。 这两个文档都指出、UCNACKIFG 由 eUSCI 中的一个起始条件清除。 在主控模式中、从不接收到一个 START 条件。

    此致、
    Ryan