TI中文支持网
TI专业的中文技术问题搜集分享网站

F28027 i2c对EEPROM的读写问题

F28027 i2c对EEPROM的读写问题

在写入时,向I2CINT寄存器写入NumOfBytes个字节数时,语句为:

I2caRegs.I2CCNT = msg-> NumOfBytes + 2;

请问为什么要加2?

整个程序源代码如下:对应代码做了高亮处理

// ################################################ ########################### 
// 
// FILE:Example_2802xI2c_eeprom.c 
// 
// TITLE:f2802x I2C EEPROM示例
// 
//假设:
// 
//此程序需要f2802x头文件。
// 
//该程序需要一个外部I2C EEPROM连接到
地址为0x50的I2C总线。
// 
//提供时,此项目配置为“boot to SARAM” 
//操作。2802x引导模式表如下所示。
//有关配置eZdsp引导模式的信息,
//请参阅eZdsp附带的文档,
// 
// $ Boot_Table
//当模拟器连接到您的设备时,TRSTn引脚= 1,
//将设备设置为EMU_BOOT引导模式。在这种模式下,
//周引导模式如下:
// 
//引导模式:EMU_KEY EMU_BMODE 
//(量0xD00)(0xD01)
// —————– ———————- 
//等待!= 0x55AA X 
// I / O 0x55AA 0x0000 
// SCI 0x55AA 0x0001 
//等待
0x55AA 0x0002 // Get_Mode 0x55AA 0x0003 
// SPI 0x55AA 0x0004 
// I2C 0x55AA 0x0005 
// OTP 0x55AA 0x0006 
//等待0x55AA 0x0007 
//等待
0x55AA 0x0008 // SARAM 0x55AA 0x000A < – “引导至SARAM” 
//闪存0x55AA 0x000B 
//等待0x55AA 其他
/ /
// 
根据上面的Boot Mode Table,通过调试器// 将EMU_KEY写入0xD00,将EMU_BMODE写入0xD01 。构建/加载项目,
//重置设备,运行示例
// 
// $ End_Boot_Table 
// 
// DESCRIPTION:
// 
//该程序将1-14个字写入EEPROM并将其读回。
//写入的数据和写入的EEPROM地址包含
在消息结构I2cMsgOut1中。回读的数据将
//包含在消息结构I2cMsgIn1中。
// 
//该程序将与
F2802x eZdsp 上提供的板载I2C EEPROM配合使用。
// 
// 
// ############################################# ###############################
// $ TI发布:F2802x支持库v230 $ 
// $发布日期:星期五5月8日07:43:05 CDT 2015 $ 
// $版权所有:Copyright(C)2008-2015 Texas Instruments Incorporated – 
// http:// www.ti.com/ ALL RIGHTS RESERVED $ 
// ###################################### #####################################

#include“DSP28x_Project.h”//设备头文件和示例包含文件

//注意:本例中使用的I2C宏可以在
// f2802x_I2C_defines.h文件中找到

//此文件中找到的函数的原型语句。
void I2CA_Init(void); 
uint16_t I2CA_WriteData(struct I2CMSG * msg); 
uint16_t I2CA_ReadData(struct I2CMSG * msg); 
__interrupt void i2c_int1a_isr(void); 
void pass(void); 
void fail(void);

#define I2C_SLAVE_ADDR 0x50 
#define I2C_NUMBYTES 3 
#define I2C_EEPROM_HIGH_ADDR 0x00 
#define I2C_EEPROM_LOW_ADDR 0x30

//全局变量
//两个字节将用于传出地址,
//因此仅设置14个字节最大
结构I2CMSG I2cMsgOut1 = { 
I2C_MSGSTAT_SEND_WITHSTOP,
I2C_SLAVE_ADDR,
I2C_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR,0X11,0X12,0X13,// Msg Byte 1 
0x34}; // Msg Byte 2

struct I2CMSG I2cMsgIn1 = {I2C_MSGSTAT_SEND_NOSTOP,
I2C_SLAVE_ADDR,
I2C_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR};

struct I2CMSG * CurrentMsgPtr; //用于中断
uint16_t PassCount; 
uint16_t FailCount;

void main(void)

uint16_t错误; 
uint16_t i;

//警告:始终确保在从RAM运行任何函数之前调用memcpy 
// InitSysCtrl包含对基于RAM的函数的调用,而不
首先调用// memcpy,处理器将“进入杂草” 
#ifdef _FLASH 
memcpy( &RamfuncsRunStart,&RamfuncsLoadStart,(size_t)&RamfuncsLoadSize); 
#万一

CurrentMsgPtr =&I2cMsgOut1;

//步骤1.初始化系统控制:
// PLL,WatchDog,启用外设时钟
//此示例函数位于f2802x_SysCtrl.c文件中。
InitSysCtrl();

//步骤2.初始化GPIO:
//此示例函数位于f2802x_Gpio.c文件中,
//说明了如何将GPIO设置为默认状态。
// InitGpio(); 
//仅为I2C功能设置GP I / O 
InitI2CGpio();

//步骤3.清除所有中断并初始化PIE向量表:
//禁用CPU中断
DINT;

//将PIE控制寄存器初始化为默认状态。
//默认状态是禁用所有PIE中断并
清除标志//。
//此函数位于f2802x_PieCtrl.c文件中。
InitPieCtrl();

//禁用CPU中断并清除所有CPU中断标志:
IER = 0x0000; 
IFR = 0x0000;

//使用指向shell Interrupt 
// Service Routines(ISR)的指针初始化PIE向量表。
//这将填充整个表,即使
在此示例中未使用中断//。这对于调试目的很有用。
// shell ISR例程可以在f2802x_DefaultIsr.c中找到。
//此函数位于f2802x_PieVect.c中。
InitPieVectTable();

//此示例中使用的中断被重新映射
到此文件中找到的// ISR函数。
EALLOW; //这需要写入EALLOW保护寄存器
PieVectTable.I2CINT1A =&i2c_int1a_isr; 
EDIS; //这是禁止写入受EALLOW保护的寄存器所必需的

//步骤4.初始化所有设备外设:
I2CA_Init(); //仅限I2C-A

//步骤5.用户特定代码

//清除计数器
PassCount = 0; 
FailCount = 0;

//清除传入的消息缓冲区
(i = 0; i <(I2C_MAX_BUFFER_SIZE – 2); i ++)

I2cMsgIn1.MsgBuffer [i] = 0x0000; 
}

//启用此示例所需的中断

//在PIE:Group 8中断中启用I2C中断1 
PieCtrlRegs.PIEIER8.bit.INTx1 = 1;

//启用连接到PIE组8的CPU INT8 
IER | = M_INT8; 
EINT;

//应用程序循环
(;;)

////////////////////////////////// 
//将数据写入EEPROM部分// 
//////////////////////////////////

//检查传出消息,看看是否应该发送./在本例中,它被初始化为使用停止位发送
.if(I2cMsgOut1.MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP)

Error = I2CA_WriteData(&I2cMsgOut1); 
//如果正确启动了通信,请将msg status设置为busy 
//并更新CurrentMsgPtr以获取中断服务例程。
//否则,什么都不做,再试一次下一个循环。一旦
//启动消息,I2C中断将处理其余的事件。在
i2c_eeprom_isr.c文件中搜索// ICINTR1A_ISR。
if(错误== I2C_SUCCESS)

CurrentMsgPtr =&I2cMsgOut1; 
I2cMsgOut1.MsgStatus = I2C_MSGSTAT_WRITE_BUSY; 

} //写入部分的结尾

/////////////////////////////////// 
//从EEPROM部分// 
//// 读取数据/////////////////////////////

//检查外发邮件状态。如果状态为
//未激活,则绕过读取部分。
if(I2cMsgOut1.MsgStatus == I2C_MSGSTAT_INACTIVE)

//检查传入的消息状态。
if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)

// EEPROM地址设置部分
while(I2CA_ReadData(&I2cMsgIn1)!= I2C_SUCCESS)

//也许设置一个尝试计数器来打破无限的
//循环。EEPROM将在执行
写操作时发回NACK 。即使此时
完成写通信,EEPROM仍可能忙于
//编程数据。因此,需要多次尝试

}
//更新当前消息指针和消息状态
CurrentMsgPtr =&I2cMsgIn1; 
I2cMsgIn1.MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY; 
}

//一旦消息进入设置
EEPROM 的内部地址//,重新发送以从
// EEPROM 读取数据字节。用停止位完成公报。
在中断服务例程中//更新了MsgStatus 。
else if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_RESTART)

//读取数据部分
while(I2CA_ReadData(&I2cMsgIn1)!= I2C_SUCCESS)

//也许设置一个尝试计数器来打破无限的
//循环。

//更新当前消息指针和消息状态
CurrentMsgPtr =&I2cMsgIn1; 
I2cMsgIn1.MsgStatus = I2C_MSGSTAT_READ_BUSY; 

} //读取部分的
结尾} // for(;;)的结尾
} //主要结束

void I2CA_Init(void)

//初始化I2C 
I2caRegs.I2CSAR = 0x0050; //从机地址 – EEPROM控制代码

// I2CCLK = SYSCLK /(I2CPSC + 1)
#if(CPU_FRQ_40MHZ || CPU_FRQ_50MHZ)
I2caRegs.I2CPSC.all = 4; //预分频器 – 在模块clk 
#endif 上需要7-12 Mhz

#if(CPU_FRQ_60MHZ)
I2caRegs.I2CPSC.all = 6; //预分频器 – 模块clk需要7-12 Mhz 
#endif 
I2caRegs.I2CCLKL = 10; //注意:必须为非零
I2caRegs.I2CCLKH = 5; //注意:必须为非零
I2caRegs.I2CIER.all = 0x24; //启用SCD和ARDY中断

I2caRegs.I2CMDR.all = 0x0020; //使I2C退出复位
//暂停时停止I2C

I2caRegs.I2CFFTX.all = 0x6000; //启用FIFO模式和TXFIFO 
I2caRegs.I2CFFRX.all = 0x2040; //启用RXFIFO,清除RXFFINT,

返回; 
}

uint16_t I2CA_WriteData(struct I2CMSG * msg)

uint16_t i;

//等待STP位从之前的任何主通信中清除。
//延迟模块清除该位,直到
设置了SCD位为止。如果在启动新消息之前未检查此位,则
// I2C可能会混淆。
if(I2caRegs.I2CMDR.bit.STP == 1)

return I2C_STP_NOT_READY_ERROR; 
}

//设置从站地址
I2caRegs.I2CSAR = msg-> SlaveAddress; 
//I2caRegs.I2CSAR = 0X50; 
//检查总线是否忙
(I2caRegs.I2CSTR.bit.BB == 1)

return I2C_BUS_BUSY_ERROR ; 
}

//设置要发送的字节数
// MsgBuffer +地址

I2caRegs.I2CCNT = msg-> NumOfBytes + 2;

//设置数据发送
I2caRegs.I2CDXR = msg-> MemoryHighAddr; 
I2caRegs.I2CDXR = msg-> MemoryLowAddr;

for(i = 0; i <msg-> NumOfBytes; i ++)

I2caRegs.I2CDXR = *(msg-> MsgBuffer + i); 
}

//发送作为主发送器开始
I2caRegs.I2CMDR.all = 0x6E20;

返回I2C_SUCCESS; 
}

uint16_t I2CA_ReadData(struct I2CMSG * msg)

//等到STP位从之前的任何主通信中清除。
//延迟模块清除该位,直到
设置了SCD位为止。如果在启动新消息之前未检查此位,则
// I2C可能会混淆。
if(I2caRegs.I2CMDR.bit.STP == 1)

return I2C_STP_NOT_READY_ERROR; 
}

I2caRegs.I2CSAR = 0X50;

if(msg-> MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)

//检查总线是否忙
(I2caRegs.I2CSTR.bit.BB == 1)

return I2C_BUS_BUSY_ERROR ; 

//I2caRegs.I2CCNT = msg-> NumOfBytes;

I2caRegs.I2CCNT = msg-> NumOfBytes;

I2caRegs.I2CDXR = msg-> MemoryHighAddr; 
I2caRegs.I2CDXR = msg-> MemoryLowAddr; 
I2caRegs.I2CMDR.all = 0x2620; //发送数据到设置EEPROM地址

否则if(msg-> MsgStatus == I2C_MSGSTAT_RESTART)

I2caRegs.I2CCNT = msg-> NumOfBytes; //设置预期的字节数
I2caRegs.I2CMDR.all = 0x2C20; //发送重启作为主接收器
}

返回I2C_SUCCESS; 
}

__interrupt void i2c_int1a_isr(void)// I2C-A 

uint16_t IntSource,i;

//读取中断源
IntSource = I2caRegs.I2CISRC.all;

//中断源=检测到停止条件
if(IntSource == I2C_SCD_ISRC)

//如果已完成消息正在写入数据,
则将msg重置为非活动状态if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_WRITE_BUSY)

CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_INACTIVE; 

else 

//如果消息在
// EEPROM读取的地址设置部分期间收到NACK ,则下面的代码包括在寄存器访问就绪
//中断源代码中将生成停止条件。
收到停止//条件(此处)后,将消息状态设置为再次尝试。
//用户可能希望在生成错误之前限制重试次数。
if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)

CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_SEND_NOSTOP; 

//如果已完成的消息正在读取EEPROM数据,则将msg重置为无效状态
//并从FIFO读取数据。
else if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_READ_BUSY)

CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_INACTIVE; 
for(i = 0; i <I2C_NUMBYTES; i ++)

CurrentMsgPtr-> MsgBuffer [i] = I2caRegs.I2CDRR; 


//检查收到的数据
(i = 0; i <I2C_NUMBYTES; i ++)

if(I2cMsgIn1.MsgBuffer [i] == I2cMsgOut1.MsgBuffer [i])

PassCount ++; 

else 
{
故障计数++; 


如果(通过计数== I2C_NUMBYTES)

通(); 

else 

fail(); 




//检测到停止条件的结束

//中断源=寄存器访问就绪
//该中断用于确定
//读取数据通信的EEPROM地址设置部分何时完成。由于没有命令停止位,因此该标志
//告诉我们何时发送了消息而不是SCD标志。如果
//收到NACK ,则清除NACK位并命令停止。否则,转到
通信的读取//数据部分。
else if(IntSource == I2C_ARDY_ISRC)

if(I2caRegs.I2CSTR.bit.NACK == 1)

I2caRegs.I2CMDR.bit.STP = 1; 
I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT; 

else if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
{
CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_RESTART; 

} //注册访问结束准备就绪

else 

//由于无效的中断源
__asm(“ESTOP0”)而产生一些错误; 
}

//启用未来的I2C(PIE Group 8)中断
PieCtrlRegs.PIEACK.all = PIEACK_GROUP8; 
}

void pass()

__ asm(“ESTOP0”); 
对于(;;); 
}

void fail()

__ asm(“ESTOP0”); 
对于(;;); 
}

// ================================================ =========================== 
//没有更多。
// ================================================ ===========================

笨鸟:应该还要发送器件地址的,所以加了个2吧。

F28027 i2c对EEPROM的读写问题

在写入时,向I2CINT寄存器写入NumOfBytes个字节数时,语句为:

I2caRegs.I2CCNT = msg-> NumOfBytes + 2;

请问为什么要加2?

整个程序源代码如下:对应代码做了高亮处理

// ################################################ ########################### 
// 
// FILE:Example_2802xI2c_eeprom.c 
// 
// TITLE:f2802x I2C EEPROM示例
// 
//假设:
// 
//此程序需要f2802x头文件。
// 
//该程序需要一个外部I2C EEPROM连接到
地址为0x50的I2C总线。
// 
//提供时,此项目配置为“boot to SARAM” 
//操作。2802x引导模式表如下所示。
//有关配置eZdsp引导模式的信息,
//请参阅eZdsp附带的文档,
// 
// $ Boot_Table
//当模拟器连接到您的设备时,TRSTn引脚= 1,
//将设备设置为EMU_BOOT引导模式。在这种模式下,
//周引导模式如下:
// 
//引导模式:EMU_KEY EMU_BMODE 
//(量0xD00)(0xD01)
// —————– ———————- 
//等待!= 0x55AA X 
// I / O 0x55AA 0x0000 
// SCI 0x55AA 0x0001 
//等待
0x55AA 0x0002 // Get_Mode 0x55AA 0x0003 
// SPI 0x55AA 0x0004 
// I2C 0x55AA 0x0005 
// OTP 0x55AA 0x0006 
//等待0x55AA 0x0007 
//等待
0x55AA 0x0008 // SARAM 0x55AA 0x000A < – “引导至SARAM” 
//闪存0x55AA 0x000B 
//等待0x55AA 其他
/ /
// 
根据上面的Boot Mode Table,通过调试器// 将EMU_KEY写入0xD00,将EMU_BMODE写入0xD01 。构建/加载项目,
//重置设备,运行示例
// 
// $ End_Boot_Table 
// 
// DESCRIPTION:
// 
//该程序将1-14个字写入EEPROM并将其读回。
//写入的数据和写入的EEPROM地址包含
在消息结构I2cMsgOut1中。回读的数据将
//包含在消息结构I2cMsgIn1中。
// 
//该程序将与
F2802x eZdsp 上提供的板载I2C EEPROM配合使用。
// 
// 
// ############################################# ###############################
// $ TI发布:F2802x支持库v230 $ 
// $发布日期:星期五5月8日07:43:05 CDT 2015 $ 
// $版权所有:Copyright(C)2008-2015 Texas Instruments Incorporated – 
// http:// www.ti.com/ ALL RIGHTS RESERVED $ 
// ###################################### #####################################

#include“DSP28x_Project.h”//设备头文件和示例包含文件

//注意:本例中使用的I2C宏可以在
// f2802x_I2C_defines.h文件中找到

//此文件中找到的函数的原型语句。
void I2CA_Init(void); 
uint16_t I2CA_WriteData(struct I2CMSG * msg); 
uint16_t I2CA_ReadData(struct I2CMSG * msg); 
__interrupt void i2c_int1a_isr(void); 
void pass(void); 
void fail(void);

#define I2C_SLAVE_ADDR 0x50 
#define I2C_NUMBYTES 3 
#define I2C_EEPROM_HIGH_ADDR 0x00 
#define I2C_EEPROM_LOW_ADDR 0x30

//全局变量
//两个字节将用于传出地址,
//因此仅设置14个字节最大
结构I2CMSG I2cMsgOut1 = { 
I2C_MSGSTAT_SEND_WITHSTOP,
I2C_SLAVE_ADDR,
I2C_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR,0X11,0X12,0X13,// Msg Byte 1 
0x34}; // Msg Byte 2

struct I2CMSG I2cMsgIn1 = {I2C_MSGSTAT_SEND_NOSTOP,
I2C_SLAVE_ADDR,
I2C_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR};

struct I2CMSG * CurrentMsgPtr; //用于中断
uint16_t PassCount; 
uint16_t FailCount;

void main(void)

uint16_t错误; 
uint16_t i;

//警告:始终确保在从RAM运行任何函数之前调用memcpy 
// InitSysCtrl包含对基于RAM的函数的调用,而不
首先调用// memcpy,处理器将“进入杂草” 
#ifdef _FLASH 
memcpy( &RamfuncsRunStart,&RamfuncsLoadStart,(size_t)&RamfuncsLoadSize); 
#万一

CurrentMsgPtr =&I2cMsgOut1;

//步骤1.初始化系统控制:
// PLL,WatchDog,启用外设时钟
//此示例函数位于f2802x_SysCtrl.c文件中。
InitSysCtrl();

//步骤2.初始化GPIO:
//此示例函数位于f2802x_Gpio.c文件中,
//说明了如何将GPIO设置为默认状态。
// InitGpio(); 
//仅为I2C功能设置GP I / O 
InitI2CGpio();

//步骤3.清除所有中断并初始化PIE向量表:
//禁用CPU中断
DINT;

//将PIE控制寄存器初始化为默认状态。
//默认状态是禁用所有PIE中断并
清除标志//。
//此函数位于f2802x_PieCtrl.c文件中。
InitPieCtrl();

//禁用CPU中断并清除所有CPU中断标志:
IER = 0x0000; 
IFR = 0x0000;

//使用指向shell Interrupt 
// Service Routines(ISR)的指针初始化PIE向量表。
//这将填充整个表,即使
在此示例中未使用中断//。这对于调试目的很有用。
// shell ISR例程可以在f2802x_DefaultIsr.c中找到。
//此函数位于f2802x_PieVect.c中。
InitPieVectTable();

//此示例中使用的中断被重新映射
到此文件中找到的// ISR函数。
EALLOW; //这需要写入EALLOW保护寄存器
PieVectTable.I2CINT1A =&i2c_int1a_isr; 
EDIS; //这是禁止写入受EALLOW保护的寄存器所必需的

//步骤4.初始化所有设备外设:
I2CA_Init(); //仅限I2C-A

//步骤5.用户特定代码

//清除计数器
PassCount = 0; 
FailCount = 0;

//清除传入的消息缓冲区
(i = 0; i <(I2C_MAX_BUFFER_SIZE – 2); i ++)

I2cMsgIn1.MsgBuffer [i] = 0x0000; 
}

//启用此示例所需的中断

//在PIE:Group 8中断中启用I2C中断1 
PieCtrlRegs.PIEIER8.bit.INTx1 = 1;

//启用连接到PIE组8的CPU INT8 
IER | = M_INT8; 
EINT;

//应用程序循环
(;;)

////////////////////////////////// 
//将数据写入EEPROM部分// 
//////////////////////////////////

//检查传出消息,看看是否应该发送./在本例中,它被初始化为使用停止位发送
.if(I2cMsgOut1.MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP)

Error = I2CA_WriteData(&I2cMsgOut1); 
//如果正确启动了通信,请将msg status设置为busy 
//并更新CurrentMsgPtr以获取中断服务例程。
//否则,什么都不做,再试一次下一个循环。一旦
//启动消息,I2C中断将处理其余的事件。在
i2c_eeprom_isr.c文件中搜索// ICINTR1A_ISR。
if(错误== I2C_SUCCESS)

CurrentMsgPtr =&I2cMsgOut1; 
I2cMsgOut1.MsgStatus = I2C_MSGSTAT_WRITE_BUSY; 

} //写入部分的结尾

/////////////////////////////////// 
//从EEPROM部分// 
//// 读取数据/////////////////////////////

//检查外发邮件状态。如果状态为
//未激活,则绕过读取部分。
if(I2cMsgOut1.MsgStatus == I2C_MSGSTAT_INACTIVE)

//检查传入的消息状态。
if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)

// EEPROM地址设置部分
while(I2CA_ReadData(&I2cMsgIn1)!= I2C_SUCCESS)

//也许设置一个尝试计数器来打破无限的
//循环。EEPROM将在执行
写操作时发回NACK 。即使此时
完成写通信,EEPROM仍可能忙于
//编程数据。因此,需要多次尝试

}
//更新当前消息指针和消息状态
CurrentMsgPtr =&I2cMsgIn1; 
I2cMsgIn1.MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY; 
}

//一旦消息进入设置
EEPROM 的内部地址//,重新发送以从
// EEPROM 读取数据字节。用停止位完成公报。
在中断服务例程中//更新了MsgStatus 。
else if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_RESTART)

//读取数据部分
while(I2CA_ReadData(&I2cMsgIn1)!= I2C_SUCCESS)

//也许设置一个尝试计数器来打破无限的
//循环。

//更新当前消息指针和消息状态
CurrentMsgPtr =&I2cMsgIn1; 
I2cMsgIn1.MsgStatus = I2C_MSGSTAT_READ_BUSY; 

} //读取部分的
结尾} // for(;;)的结尾
} //主要结束

void I2CA_Init(void)

//初始化I2C 
I2caRegs.I2CSAR = 0x0050; //从机地址 – EEPROM控制代码

// I2CCLK = SYSCLK /(I2CPSC + 1)
#if(CPU_FRQ_40MHZ || CPU_FRQ_50MHZ)
I2caRegs.I2CPSC.all = 4; //预分频器 – 在模块clk 
#endif 上需要7-12 Mhz

#if(CPU_FRQ_60MHZ)
I2caRegs.I2CPSC.all = 6; //预分频器 – 模块clk需要7-12 Mhz 
#endif 
I2caRegs.I2CCLKL = 10; //注意:必须为非零
I2caRegs.I2CCLKH = 5; //注意:必须为非零
I2caRegs.I2CIER.all = 0x24; //启用SCD和ARDY中断

I2caRegs.I2CMDR.all = 0x0020; //使I2C退出复位
//暂停时停止I2C

I2caRegs.I2CFFTX.all = 0x6000; //启用FIFO模式和TXFIFO 
I2caRegs.I2CFFRX.all = 0x2040; //启用RXFIFO,清除RXFFINT,

返回; 
}

uint16_t I2CA_WriteData(struct I2CMSG * msg)

uint16_t i;

//等待STP位从之前的任何主通信中清除。
//延迟模块清除该位,直到
设置了SCD位为止。如果在启动新消息之前未检查此位,则
// I2C可能会混淆。
if(I2caRegs.I2CMDR.bit.STP == 1)

return I2C_STP_NOT_READY_ERROR; 
}

//设置从站地址
I2caRegs.I2CSAR = msg-> SlaveAddress; 
//I2caRegs.I2CSAR = 0X50; 
//检查总线是否忙
(I2caRegs.I2CSTR.bit.BB == 1)

return I2C_BUS_BUSY_ERROR ; 
}

//设置要发送的字节数
// MsgBuffer +地址

I2caRegs.I2CCNT = msg-> NumOfBytes + 2;

//设置数据发送
I2caRegs.I2CDXR = msg-> MemoryHighAddr; 
I2caRegs.I2CDXR = msg-> MemoryLowAddr;

for(i = 0; i <msg-> NumOfBytes; i ++)

I2caRegs.I2CDXR = *(msg-> MsgBuffer + i); 
}

//发送作为主发送器开始
I2caRegs.I2CMDR.all = 0x6E20;

返回I2C_SUCCESS; 
}

uint16_t I2CA_ReadData(struct I2CMSG * msg)

//等到STP位从之前的任何主通信中清除。
//延迟模块清除该位,直到
设置了SCD位为止。如果在启动新消息之前未检查此位,则
// I2C可能会混淆。
if(I2caRegs.I2CMDR.bit.STP == 1)

return I2C_STP_NOT_READY_ERROR; 
}

I2caRegs.I2CSAR = 0X50;

if(msg-> MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)

//检查总线是否忙
(I2caRegs.I2CSTR.bit.BB == 1)

return I2C_BUS_BUSY_ERROR ; 

//I2caRegs.I2CCNT = msg-> NumOfBytes;

I2caRegs.I2CCNT = msg-> NumOfBytes;

I2caRegs.I2CDXR = msg-> MemoryHighAddr; 
I2caRegs.I2CDXR = msg-> MemoryLowAddr; 
I2caRegs.I2CMDR.all = 0x2620; //发送数据到设置EEPROM地址

否则if(msg-> MsgStatus == I2C_MSGSTAT_RESTART)

I2caRegs.I2CCNT = msg-> NumOfBytes; //设置预期的字节数
I2caRegs.I2CMDR.all = 0x2C20; //发送重启作为主接收器
}

返回I2C_SUCCESS; 
}

__interrupt void i2c_int1a_isr(void)// I2C-A 

uint16_t IntSource,i;

//读取中断源
IntSource = I2caRegs.I2CISRC.all;

//中断源=检测到停止条件
if(IntSource == I2C_SCD_ISRC)

//如果已完成消息正在写入数据,
则将msg重置为非活动状态if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_WRITE_BUSY)

CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_INACTIVE; 

else 

//如果消息在
// EEPROM读取的地址设置部分期间收到NACK ,则下面的代码包括在寄存器访问就绪
//中断源代码中将生成停止条件。
收到停止//条件(此处)后,将消息状态设置为再次尝试。
//用户可能希望在生成错误之前限制重试次数。
if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)

CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_SEND_NOSTOP; 

//如果已完成的消息正在读取EEPROM数据,则将msg重置为无效状态
//并从FIFO读取数据。
else if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_READ_BUSY)

CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_INACTIVE; 
for(i = 0; i <I2C_NUMBYTES; i ++)

CurrentMsgPtr-> MsgBuffer [i] = I2caRegs.I2CDRR; 


//检查收到的数据
(i = 0; i <I2C_NUMBYTES; i ++)

if(I2cMsgIn1.MsgBuffer [i] == I2cMsgOut1.MsgBuffer [i])

PassCount ++; 

else 
{
故障计数++; 


如果(通过计数== I2C_NUMBYTES)

通(); 

else 

fail(); 




//检测到停止条件的结束

//中断源=寄存器访问就绪
//该中断用于确定
//读取数据通信的EEPROM地址设置部分何时完成。由于没有命令停止位,因此该标志
//告诉我们何时发送了消息而不是SCD标志。如果
//收到NACK ,则清除NACK位并命令停止。否则,转到
通信的读取//数据部分。
else if(IntSource == I2C_ARDY_ISRC)

if(I2caRegs.I2CSTR.bit.NACK == 1)

I2caRegs.I2CMDR.bit.STP = 1; 
I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT; 

else if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
{
CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_RESTART; 

} //注册访问结束准备就绪

else 

//由于无效的中断源
__asm(“ESTOP0”)而产生一些错误; 
}

//启用未来的I2C(PIE Group 8)中断
PieCtrlRegs.PIEACK.all = PIEACK_GROUP8; 
}

void pass()

__ asm(“ESTOP0”); 
对于(;;); 
}

void fail()

__ asm(“ESTOP0”); 
对于(;;); 
}

// ================================================ =========================== 
//没有更多。
// ================================================ ===========================

Green Deng:应该是加了两位地址位

F28027 i2c对EEPROM的读写问题

在写入时,向I2CINT寄存器写入NumOfBytes个字节数时,语句为:

I2caRegs.I2CCNT = msg-> NumOfBytes + 2;

请问为什么要加2?

整个程序源代码如下:对应代码做了高亮处理

// ################################################ ########################### 
// 
// FILE:Example_2802xI2c_eeprom.c 
// 
// TITLE:f2802x I2C EEPROM示例
// 
//假设:
// 
//此程序需要f2802x头文件。
// 
//该程序需要一个外部I2C EEPROM连接到
地址为0x50的I2C总线。
// 
//提供时,此项目配置为“boot to SARAM” 
//操作。2802x引导模式表如下所示。
//有关配置eZdsp引导模式的信息,
//请参阅eZdsp附带的文档,
// 
// $ Boot_Table
//当模拟器连接到您的设备时,TRSTn引脚= 1,
//将设备设置为EMU_BOOT引导模式。在这种模式下,
//周引导模式如下:
// 
//引导模式:EMU_KEY EMU_BMODE 
//(量0xD00)(0xD01)
// —————– ———————- 
//等待!= 0x55AA X 
// I / O 0x55AA 0x0000 
// SCI 0x55AA 0x0001 
//等待
0x55AA 0x0002 // Get_Mode 0x55AA 0x0003 
// SPI 0x55AA 0x0004 
// I2C 0x55AA 0x0005 
// OTP 0x55AA 0x0006 
//等待0x55AA 0x0007 
//等待
0x55AA 0x0008 // SARAM 0x55AA 0x000A < – “引导至SARAM” 
//闪存0x55AA 0x000B 
//等待0x55AA 其他
/ /
// 
根据上面的Boot Mode Table,通过调试器// 将EMU_KEY写入0xD00,将EMU_BMODE写入0xD01 。构建/加载项目,
//重置设备,运行示例
// 
// $ End_Boot_Table 
// 
// DESCRIPTION:
// 
//该程序将1-14个字写入EEPROM并将其读回。
//写入的数据和写入的EEPROM地址包含
在消息结构I2cMsgOut1中。回读的数据将
//包含在消息结构I2cMsgIn1中。
// 
//该程序将与
F2802x eZdsp 上提供的板载I2C EEPROM配合使用。
// 
// 
// ############################################# ###############################
// $ TI发布:F2802x支持库v230 $ 
// $发布日期:星期五5月8日07:43:05 CDT 2015 $ 
// $版权所有:Copyright(C)2008-2015 Texas Instruments Incorporated – 
// http:// www.ti.com/ ALL RIGHTS RESERVED $ 
// ###################################### #####################################

#include“DSP28x_Project.h”//设备头文件和示例包含文件

//注意:本例中使用的I2C宏可以在
// f2802x_I2C_defines.h文件中找到

//此文件中找到的函数的原型语句。
void I2CA_Init(void); 
uint16_t I2CA_WriteData(struct I2CMSG * msg); 
uint16_t I2CA_ReadData(struct I2CMSG * msg); 
__interrupt void i2c_int1a_isr(void); 
void pass(void); 
void fail(void);

#define I2C_SLAVE_ADDR 0x50 
#define I2C_NUMBYTES 3 
#define I2C_EEPROM_HIGH_ADDR 0x00 
#define I2C_EEPROM_LOW_ADDR 0x30

//全局变量
//两个字节将用于传出地址,
//因此仅设置14个字节最大
结构I2CMSG I2cMsgOut1 = { 
I2C_MSGSTAT_SEND_WITHSTOP,
I2C_SLAVE_ADDR,
I2C_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR,0X11,0X12,0X13,// Msg Byte 1 
0x34}; // Msg Byte 2

struct I2CMSG I2cMsgIn1 = {I2C_MSGSTAT_SEND_NOSTOP,
I2C_SLAVE_ADDR,
I2C_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR};

struct I2CMSG * CurrentMsgPtr; //用于中断
uint16_t PassCount; 
uint16_t FailCount;

void main(void)

uint16_t错误; 
uint16_t i;

//警告:始终确保在从RAM运行任何函数之前调用memcpy 
// InitSysCtrl包含对基于RAM的函数的调用,而不
首先调用// memcpy,处理器将“进入杂草” 
#ifdef _FLASH 
memcpy( &RamfuncsRunStart,&RamfuncsLoadStart,(size_t)&RamfuncsLoadSize); 
#万一

CurrentMsgPtr =&I2cMsgOut1;

//步骤1.初始化系统控制:
// PLL,WatchDog,启用外设时钟
//此示例函数位于f2802x_SysCtrl.c文件中。
InitSysCtrl();

//步骤2.初始化GPIO:
//此示例函数位于f2802x_Gpio.c文件中,
//说明了如何将GPIO设置为默认状态。
// InitGpio(); 
//仅为I2C功能设置GP I / O 
InitI2CGpio();

//步骤3.清除所有中断并初始化PIE向量表:
//禁用CPU中断
DINT;

//将PIE控制寄存器初始化为默认状态。
//默认状态是禁用所有PIE中断并
清除标志//。
//此函数位于f2802x_PieCtrl.c文件中。
InitPieCtrl();

//禁用CPU中断并清除所有CPU中断标志:
IER = 0x0000; 
IFR = 0x0000;

//使用指向shell Interrupt 
// Service Routines(ISR)的指针初始化PIE向量表。
//这将填充整个表,即使
在此示例中未使用中断//。这对于调试目的很有用。
// shell ISR例程可以在f2802x_DefaultIsr.c中找到。
//此函数位于f2802x_PieVect.c中。
InitPieVectTable();

//此示例中使用的中断被重新映射
到此文件中找到的// ISR函数。
EALLOW; //这需要写入EALLOW保护寄存器
PieVectTable.I2CINT1A =&i2c_int1a_isr; 
EDIS; //这是禁止写入受EALLOW保护的寄存器所必需的

//步骤4.初始化所有设备外设:
I2CA_Init(); //仅限I2C-A

//步骤5.用户特定代码

//清除计数器
PassCount = 0; 
FailCount = 0;

//清除传入的消息缓冲区
(i = 0; i <(I2C_MAX_BUFFER_SIZE – 2); i ++)

I2cMsgIn1.MsgBuffer [i] = 0x0000; 
}

//启用此示例所需的中断

//在PIE:Group 8中断中启用I2C中断1 
PieCtrlRegs.PIEIER8.bit.INTx1 = 1;

//启用连接到PIE组8的CPU INT8 
IER | = M_INT8; 
EINT;

//应用程序循环
(;;)

////////////////////////////////// 
//将数据写入EEPROM部分// 
//////////////////////////////////

//检查传出消息,看看是否应该发送./在本例中,它被初始化为使用停止位发送
.if(I2cMsgOut1.MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP)

Error = I2CA_WriteData(&I2cMsgOut1); 
//如果正确启动了通信,请将msg status设置为busy 
//并更新CurrentMsgPtr以获取中断服务例程。
//否则,什么都不做,再试一次下一个循环。一旦
//启动消息,I2C中断将处理其余的事件。在
i2c_eeprom_isr.c文件中搜索// ICINTR1A_ISR。
if(错误== I2C_SUCCESS)

CurrentMsgPtr =&I2cMsgOut1; 
I2cMsgOut1.MsgStatus = I2C_MSGSTAT_WRITE_BUSY; 

} //写入部分的结尾

/////////////////////////////////// 
//从EEPROM部分// 
//// 读取数据/////////////////////////////

//检查外发邮件状态。如果状态为
//未激活,则绕过读取部分。
if(I2cMsgOut1.MsgStatus == I2C_MSGSTAT_INACTIVE)

//检查传入的消息状态。
if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)

// EEPROM地址设置部分
while(I2CA_ReadData(&I2cMsgIn1)!= I2C_SUCCESS)

//也许设置一个尝试计数器来打破无限的
//循环。EEPROM将在执行
写操作时发回NACK 。即使此时
完成写通信,EEPROM仍可能忙于
//编程数据。因此,需要多次尝试

}
//更新当前消息指针和消息状态
CurrentMsgPtr =&I2cMsgIn1; 
I2cMsgIn1.MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY; 
}

//一旦消息进入设置
EEPROM 的内部地址//,重新发送以从
// EEPROM 读取数据字节。用停止位完成公报。
在中断服务例程中//更新了MsgStatus 。
else if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_RESTART)

//读取数据部分
while(I2CA_ReadData(&I2cMsgIn1)!= I2C_SUCCESS)

//也许设置一个尝试计数器来打破无限的
//循环。

//更新当前消息指针和消息状态
CurrentMsgPtr =&I2cMsgIn1; 
I2cMsgIn1.MsgStatus = I2C_MSGSTAT_READ_BUSY; 

} //读取部分的
结尾} // for(;;)的结尾
} //主要结束

void I2CA_Init(void)

//初始化I2C 
I2caRegs.I2CSAR = 0x0050; //从机地址 – EEPROM控制代码

// I2CCLK = SYSCLK /(I2CPSC + 1)
#if(CPU_FRQ_40MHZ || CPU_FRQ_50MHZ)
I2caRegs.I2CPSC.all = 4; //预分频器 – 在模块clk 
#endif 上需要7-12 Mhz

#if(CPU_FRQ_60MHZ)
I2caRegs.I2CPSC.all = 6; //预分频器 – 模块clk需要7-12 Mhz 
#endif 
I2caRegs.I2CCLKL = 10; //注意:必须为非零
I2caRegs.I2CCLKH = 5; //注意:必须为非零
I2caRegs.I2CIER.all = 0x24; //启用SCD和ARDY中断

I2caRegs.I2CMDR.all = 0x0020; //使I2C退出复位
//暂停时停止I2C

I2caRegs.I2CFFTX.all = 0x6000; //启用FIFO模式和TXFIFO 
I2caRegs.I2CFFRX.all = 0x2040; //启用RXFIFO,清除RXFFINT,

返回; 
}

uint16_t I2CA_WriteData(struct I2CMSG * msg)

uint16_t i;

//等待STP位从之前的任何主通信中清除。
//延迟模块清除该位,直到
设置了SCD位为止。如果在启动新消息之前未检查此位,则
// I2C可能会混淆。
if(I2caRegs.I2CMDR.bit.STP == 1)

return I2C_STP_NOT_READY_ERROR; 
}

//设置从站地址
I2caRegs.I2CSAR = msg-> SlaveAddress; 
//I2caRegs.I2CSAR = 0X50; 
//检查总线是否忙
(I2caRegs.I2CSTR.bit.BB == 1)

return I2C_BUS_BUSY_ERROR ; 
}

//设置要发送的字节数
// MsgBuffer +地址

I2caRegs.I2CCNT = msg-> NumOfBytes + 2;

//设置数据发送
I2caRegs.I2CDXR = msg-> MemoryHighAddr; 
I2caRegs.I2CDXR = msg-> MemoryLowAddr;

for(i = 0; i <msg-> NumOfBytes; i ++)

I2caRegs.I2CDXR = *(msg-> MsgBuffer + i); 
}

//发送作为主发送器开始
I2caRegs.I2CMDR.all = 0x6E20;

返回I2C_SUCCESS; 
}

uint16_t I2CA_ReadData(struct I2CMSG * msg)

//等到STP位从之前的任何主通信中清除。
//延迟模块清除该位,直到
设置了SCD位为止。如果在启动新消息之前未检查此位,则
// I2C可能会混淆。
if(I2caRegs.I2CMDR.bit.STP == 1)

return I2C_STP_NOT_READY_ERROR; 
}

I2caRegs.I2CSAR = 0X50;

if(msg-> MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)

//检查总线是否忙
(I2caRegs.I2CSTR.bit.BB == 1)

return I2C_BUS_BUSY_ERROR ; 

//I2caRegs.I2CCNT = msg-> NumOfBytes;

I2caRegs.I2CCNT = msg-> NumOfBytes;

I2caRegs.I2CDXR = msg-> MemoryHighAddr; 
I2caRegs.I2CDXR = msg-> MemoryLowAddr; 
I2caRegs.I2CMDR.all = 0x2620; //发送数据到设置EEPROM地址

否则if(msg-> MsgStatus == I2C_MSGSTAT_RESTART)

I2caRegs.I2CCNT = msg-> NumOfBytes; //设置预期的字节数
I2caRegs.I2CMDR.all = 0x2C20; //发送重启作为主接收器
}

返回I2C_SUCCESS; 
}

__interrupt void i2c_int1a_isr(void)// I2C-A 

uint16_t IntSource,i;

//读取中断源
IntSource = I2caRegs.I2CISRC.all;

//中断源=检测到停止条件
if(IntSource == I2C_SCD_ISRC)

//如果已完成消息正在写入数据,
则将msg重置为非活动状态if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_WRITE_BUSY)

CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_INACTIVE; 

else 

//如果消息在
// EEPROM读取的地址设置部分期间收到NACK ,则下面的代码包括在寄存器访问就绪
//中断源代码中将生成停止条件。
收到停止//条件(此处)后,将消息状态设置为再次尝试。
//用户可能希望在生成错误之前限制重试次数。
if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)

CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_SEND_NOSTOP; 

//如果已完成的消息正在读取EEPROM数据,则将msg重置为无效状态
//并从FIFO读取数据。
else if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_READ_BUSY)

CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_INACTIVE; 
for(i = 0; i <I2C_NUMBYTES; i ++)

CurrentMsgPtr-> MsgBuffer [i] = I2caRegs.I2CDRR; 


//检查收到的数据
(i = 0; i <I2C_NUMBYTES; i ++)

if(I2cMsgIn1.MsgBuffer [i] == I2cMsgOut1.MsgBuffer [i])

PassCount ++; 

else 
{
故障计数++; 


如果(通过计数== I2C_NUMBYTES)

通(); 

else 

fail(); 




//检测到停止条件的结束

//中断源=寄存器访问就绪
//该中断用于确定
//读取数据通信的EEPROM地址设置部分何时完成。由于没有命令停止位,因此该标志
//告诉我们何时发送了消息而不是SCD标志。如果
//收到NACK ,则清除NACK位并命令停止。否则,转到
通信的读取//数据部分。
else if(IntSource == I2C_ARDY_ISRC)

if(I2caRegs.I2CSTR.bit.NACK == 1)

I2caRegs.I2CMDR.bit.STP = 1; 
I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT; 

else if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
{
CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_RESTART; 

} //注册访问结束准备就绪

else 

//由于无效的中断源
__asm(“ESTOP0”)而产生一些错误; 
}

//启用未来的I2C(PIE Group 8)中断
PieCtrlRegs.PIEACK.all = PIEACK_GROUP8; 
}

void pass()

__ asm(“ESTOP0”); 
对于(;;); 
}

void fail()

__ asm(“ESTOP0”); 
对于(;;); 
}

// ================================================ =========================== 
//没有更多。
// ================================================ ===========================

user6102121:

回复 笨鸟:

你好,这个程序我的疑问在于,只能写读2个字节数据,之后不管增加写的数据还是读的数据都会出现1个数据都读不出来的情况,请问这是为什么,求指教、

F28027 i2c对EEPROM的读写问题

在写入时,向I2CINT寄存器写入NumOfBytes个字节数时,语句为:

I2caRegs.I2CCNT = msg-> NumOfBytes + 2;

请问为什么要加2?

整个程序源代码如下:对应代码做了高亮处理

// ################################################ ########################### 
// 
// FILE:Example_2802xI2c_eeprom.c 
// 
// TITLE:f2802x I2C EEPROM示例
// 
//假设:
// 
//此程序需要f2802x头文件。
// 
//该程序需要一个外部I2C EEPROM连接到
地址为0x50的I2C总线。
// 
//提供时,此项目配置为“boot to SARAM” 
//操作。2802x引导模式表如下所示。
//有关配置eZdsp引导模式的信息,
//请参阅eZdsp附带的文档,
// 
// $ Boot_Table
//当模拟器连接到您的设备时,TRSTn引脚= 1,
//将设备设置为EMU_BOOT引导模式。在这种模式下,
//周引导模式如下:
// 
//引导模式:EMU_KEY EMU_BMODE 
//(量0xD00)(0xD01)
// —————– ———————- 
//等待!= 0x55AA X 
// I / O 0x55AA 0x0000 
// SCI 0x55AA 0x0001 
//等待
0x55AA 0x0002 // Get_Mode 0x55AA 0x0003 
// SPI 0x55AA 0x0004 
// I2C 0x55AA 0x0005 
// OTP 0x55AA 0x0006 
//等待0x55AA 0x0007 
//等待
0x55AA 0x0008 // SARAM 0x55AA 0x000A < – “引导至SARAM” 
//闪存0x55AA 0x000B 
//等待0x55AA 其他
/ /
// 
根据上面的Boot Mode Table,通过调试器// 将EMU_KEY写入0xD00,将EMU_BMODE写入0xD01 。构建/加载项目,
//重置设备,运行示例
// 
// $ End_Boot_Table 
// 
// DESCRIPTION:
// 
//该程序将1-14个字写入EEPROM并将其读回。
//写入的数据和写入的EEPROM地址包含
在消息结构I2cMsgOut1中。回读的数据将
//包含在消息结构I2cMsgIn1中。
// 
//该程序将与
F2802x eZdsp 上提供的板载I2C EEPROM配合使用。
// 
// 
// ############################################# ###############################
// $ TI发布:F2802x支持库v230 $ 
// $发布日期:星期五5月8日07:43:05 CDT 2015 $ 
// $版权所有:Copyright(C)2008-2015 Texas Instruments Incorporated – 
// http:// www.ti.com/ ALL RIGHTS RESERVED $ 
// ###################################### #####################################

#include“DSP28x_Project.h”//设备头文件和示例包含文件

//注意:本例中使用的I2C宏可以在
// f2802x_I2C_defines.h文件中找到

//此文件中找到的函数的原型语句。
void I2CA_Init(void); 
uint16_t I2CA_WriteData(struct I2CMSG * msg); 
uint16_t I2CA_ReadData(struct I2CMSG * msg); 
__interrupt void i2c_int1a_isr(void); 
void pass(void); 
void fail(void);

#define I2C_SLAVE_ADDR 0x50 
#define I2C_NUMBYTES 3 
#define I2C_EEPROM_HIGH_ADDR 0x00 
#define I2C_EEPROM_LOW_ADDR 0x30

//全局变量
//两个字节将用于传出地址,
//因此仅设置14个字节最大
结构I2CMSG I2cMsgOut1 = { 
I2C_MSGSTAT_SEND_WITHSTOP,
I2C_SLAVE_ADDR,
I2C_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR,0X11,0X12,0X13,// Msg Byte 1 
0x34}; // Msg Byte 2

struct I2CMSG I2cMsgIn1 = {I2C_MSGSTAT_SEND_NOSTOP,
I2C_SLAVE_ADDR,
I2C_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR};

struct I2CMSG * CurrentMsgPtr; //用于中断
uint16_t PassCount; 
uint16_t FailCount;

void main(void)

uint16_t错误; 
uint16_t i;

//警告:始终确保在从RAM运行任何函数之前调用memcpy 
// InitSysCtrl包含对基于RAM的函数的调用,而不
首先调用// memcpy,处理器将“进入杂草” 
#ifdef _FLASH 
memcpy( &RamfuncsRunStart,&RamfuncsLoadStart,(size_t)&RamfuncsLoadSize); 
#万一

CurrentMsgPtr =&I2cMsgOut1;

//步骤1.初始化系统控制:
// PLL,WatchDog,启用外设时钟
//此示例函数位于f2802x_SysCtrl.c文件中。
InitSysCtrl();

//步骤2.初始化GPIO:
//此示例函数位于f2802x_Gpio.c文件中,
//说明了如何将GPIO设置为默认状态。
// InitGpio(); 
//仅为I2C功能设置GP I / O 
InitI2CGpio();

//步骤3.清除所有中断并初始化PIE向量表:
//禁用CPU中断
DINT;

//将PIE控制寄存器初始化为默认状态。
//默认状态是禁用所有PIE中断并
清除标志//。
//此函数位于f2802x_PieCtrl.c文件中。
InitPieCtrl();

//禁用CPU中断并清除所有CPU中断标志:
IER = 0x0000; 
IFR = 0x0000;

//使用指向shell Interrupt 
// Service Routines(ISR)的指针初始化PIE向量表。
//这将填充整个表,即使
在此示例中未使用中断//。这对于调试目的很有用。
// shell ISR例程可以在f2802x_DefaultIsr.c中找到。
//此函数位于f2802x_PieVect.c中。
InitPieVectTable();

//此示例中使用的中断被重新映射
到此文件中找到的// ISR函数。
EALLOW; //这需要写入EALLOW保护寄存器
PieVectTable.I2CINT1A =&i2c_int1a_isr; 
EDIS; //这是禁止写入受EALLOW保护的寄存器所必需的

//步骤4.初始化所有设备外设:
I2CA_Init(); //仅限I2C-A

//步骤5.用户特定代码

//清除计数器
PassCount = 0; 
FailCount = 0;

//清除传入的消息缓冲区
(i = 0; i <(I2C_MAX_BUFFER_SIZE – 2); i ++)

I2cMsgIn1.MsgBuffer [i] = 0x0000; 
}

//启用此示例所需的中断

//在PIE:Group 8中断中启用I2C中断1 
PieCtrlRegs.PIEIER8.bit.INTx1 = 1;

//启用连接到PIE组8的CPU INT8 
IER | = M_INT8; 
EINT;

//应用程序循环
(;;)

////////////////////////////////// 
//将数据写入EEPROM部分// 
//////////////////////////////////

//检查传出消息,看看是否应该发送./在本例中,它被初始化为使用停止位发送
.if(I2cMsgOut1.MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP)

Error = I2CA_WriteData(&I2cMsgOut1); 
//如果正确启动了通信,请将msg status设置为busy 
//并更新CurrentMsgPtr以获取中断服务例程。
//否则,什么都不做,再试一次下一个循环。一旦
//启动消息,I2C中断将处理其余的事件。在
i2c_eeprom_isr.c文件中搜索// ICINTR1A_ISR。
if(错误== I2C_SUCCESS)

CurrentMsgPtr =&I2cMsgOut1; 
I2cMsgOut1.MsgStatus = I2C_MSGSTAT_WRITE_BUSY; 

} //写入部分的结尾

/////////////////////////////////// 
//从EEPROM部分// 
//// 读取数据/////////////////////////////

//检查外发邮件状态。如果状态为
//未激活,则绕过读取部分。
if(I2cMsgOut1.MsgStatus == I2C_MSGSTAT_INACTIVE)

//检查传入的消息状态。
if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)

// EEPROM地址设置部分
while(I2CA_ReadData(&I2cMsgIn1)!= I2C_SUCCESS)

//也许设置一个尝试计数器来打破无限的
//循环。EEPROM将在执行
写操作时发回NACK 。即使此时
完成写通信,EEPROM仍可能忙于
//编程数据。因此,需要多次尝试

}
//更新当前消息指针和消息状态
CurrentMsgPtr =&I2cMsgIn1; 
I2cMsgIn1.MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY; 
}

//一旦消息进入设置
EEPROM 的内部地址//,重新发送以从
// EEPROM 读取数据字节。用停止位完成公报。
在中断服务例程中//更新了MsgStatus 。
else if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_RESTART)

//读取数据部分
while(I2CA_ReadData(&I2cMsgIn1)!= I2C_SUCCESS)

//也许设置一个尝试计数器来打破无限的
//循环。

//更新当前消息指针和消息状态
CurrentMsgPtr =&I2cMsgIn1; 
I2cMsgIn1.MsgStatus = I2C_MSGSTAT_READ_BUSY; 

} //读取部分的
结尾} // for(;;)的结尾
} //主要结束

void I2CA_Init(void)

//初始化I2C 
I2caRegs.I2CSAR = 0x0050; //从机地址 – EEPROM控制代码

// I2CCLK = SYSCLK /(I2CPSC + 1)
#if(CPU_FRQ_40MHZ || CPU_FRQ_50MHZ)
I2caRegs.I2CPSC.all = 4; //预分频器 – 在模块clk 
#endif 上需要7-12 Mhz

#if(CPU_FRQ_60MHZ)
I2caRegs.I2CPSC.all = 6; //预分频器 – 模块clk需要7-12 Mhz 
#endif 
I2caRegs.I2CCLKL = 10; //注意:必须为非零
I2caRegs.I2CCLKH = 5; //注意:必须为非零
I2caRegs.I2CIER.all = 0x24; //启用SCD和ARDY中断

I2caRegs.I2CMDR.all = 0x0020; //使I2C退出复位
//暂停时停止I2C

I2caRegs.I2CFFTX.all = 0x6000; //启用FIFO模式和TXFIFO 
I2caRegs.I2CFFRX.all = 0x2040; //启用RXFIFO,清除RXFFINT,

返回; 
}

uint16_t I2CA_WriteData(struct I2CMSG * msg)

uint16_t i;

//等待STP位从之前的任何主通信中清除。
//延迟模块清除该位,直到
设置了SCD位为止。如果在启动新消息之前未检查此位,则
// I2C可能会混淆。
if(I2caRegs.I2CMDR.bit.STP == 1)

return I2C_STP_NOT_READY_ERROR; 
}

//设置从站地址
I2caRegs.I2CSAR = msg-> SlaveAddress; 
//I2caRegs.I2CSAR = 0X50; 
//检查总线是否忙
(I2caRegs.I2CSTR.bit.BB == 1)

return I2C_BUS_BUSY_ERROR ; 
}

//设置要发送的字节数
// MsgBuffer +地址

I2caRegs.I2CCNT = msg-> NumOfBytes + 2;

//设置数据发送
I2caRegs.I2CDXR = msg-> MemoryHighAddr; 
I2caRegs.I2CDXR = msg-> MemoryLowAddr;

for(i = 0; i <msg-> NumOfBytes; i ++)

I2caRegs.I2CDXR = *(msg-> MsgBuffer + i); 
}

//发送作为主发送器开始
I2caRegs.I2CMDR.all = 0x6E20;

返回I2C_SUCCESS; 
}

uint16_t I2CA_ReadData(struct I2CMSG * msg)

//等到STP位从之前的任何主通信中清除。
//延迟模块清除该位,直到
设置了SCD位为止。如果在启动新消息之前未检查此位,则
// I2C可能会混淆。
if(I2caRegs.I2CMDR.bit.STP == 1)

return I2C_STP_NOT_READY_ERROR; 
}

I2caRegs.I2CSAR = 0X50;

if(msg-> MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)

//检查总线是否忙
(I2caRegs.I2CSTR.bit.BB == 1)

return I2C_BUS_BUSY_ERROR ; 

//I2caRegs.I2CCNT = msg-> NumOfBytes;

I2caRegs.I2CCNT = msg-> NumOfBytes;

I2caRegs.I2CDXR = msg-> MemoryHighAddr; 
I2caRegs.I2CDXR = msg-> MemoryLowAddr; 
I2caRegs.I2CMDR.all = 0x2620; //发送数据到设置EEPROM地址

否则if(msg-> MsgStatus == I2C_MSGSTAT_RESTART)

I2caRegs.I2CCNT = msg-> NumOfBytes; //设置预期的字节数
I2caRegs.I2CMDR.all = 0x2C20; //发送重启作为主接收器
}

返回I2C_SUCCESS; 
}

__interrupt void i2c_int1a_isr(void)// I2C-A 

uint16_t IntSource,i;

//读取中断源
IntSource = I2caRegs.I2CISRC.all;

//中断源=检测到停止条件
if(IntSource == I2C_SCD_ISRC)

//如果已完成消息正在写入数据,
则将msg重置为非活动状态if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_WRITE_BUSY)

CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_INACTIVE; 

else 

//如果消息在
// EEPROM读取的地址设置部分期间收到NACK ,则下面的代码包括在寄存器访问就绪
//中断源代码中将生成停止条件。
收到停止//条件(此处)后,将消息状态设置为再次尝试。
//用户可能希望在生成错误之前限制重试次数。
if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)

CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_SEND_NOSTOP; 

//如果已完成的消息正在读取EEPROM数据,则将msg重置为无效状态
//并从FIFO读取数据。
else if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_READ_BUSY)

CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_INACTIVE; 
for(i = 0; i <I2C_NUMBYTES; i ++)

CurrentMsgPtr-> MsgBuffer [i] = I2caRegs.I2CDRR; 


//检查收到的数据
(i = 0; i <I2C_NUMBYTES; i ++)

if(I2cMsgIn1.MsgBuffer [i] == I2cMsgOut1.MsgBuffer [i])

PassCount ++; 

else 
{
故障计数++; 


如果(通过计数== I2C_NUMBYTES)

通(); 

else 

fail(); 




//检测到停止条件的结束

//中断源=寄存器访问就绪
//该中断用于确定
//读取数据通信的EEPROM地址设置部分何时完成。由于没有命令停止位,因此该标志
//告诉我们何时发送了消息而不是SCD标志。如果
//收到NACK ,则清除NACK位并命令停止。否则,转到
通信的读取//数据部分。
else if(IntSource == I2C_ARDY_ISRC)

if(I2caRegs.I2CSTR.bit.NACK == 1)

I2caRegs.I2CMDR.bit.STP = 1; 
I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT; 

else if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
{
CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_RESTART; 

} //注册访问结束准备就绪

else 

//由于无效的中断源
__asm(“ESTOP0”)而产生一些错误; 
}

//启用未来的I2C(PIE Group 8)中断
PieCtrlRegs.PIEACK.all = PIEACK_GROUP8; 
}

void pass()

__ asm(“ESTOP0”); 
对于(;;); 
}

void fail()

__ asm(“ESTOP0”); 
对于(;;); 
}

// ================================================ =========================== 
//没有更多。
// ================================================ ===========================

user6102121:

回复 Green Deng:

你好,这个程序我的疑问在于,只能写读2个字节数据,之后不管增加写的数据还是读的数据都会出现1个数据都读不出来的情况,请问这是为什么,求指教,

F28027 i2c对EEPROM的读写问题

在写入时,向I2CINT寄存器写入NumOfBytes个字节数时,语句为:

I2caRegs.I2CCNT = msg-> NumOfBytes + 2;

请问为什么要加2?

整个程序源代码如下:对应代码做了高亮处理

// ################################################ ########################### 
// 
// FILE:Example_2802xI2c_eeprom.c 
// 
// TITLE:f2802x I2C EEPROM示例
// 
//假设:
// 
//此程序需要f2802x头文件。
// 
//该程序需要一个外部I2C EEPROM连接到
地址为0x50的I2C总线。
// 
//提供时,此项目配置为“boot to SARAM” 
//操作。2802x引导模式表如下所示。
//有关配置eZdsp引导模式的信息,
//请参阅eZdsp附带的文档,
// 
// $ Boot_Table
//当模拟器连接到您的设备时,TRSTn引脚= 1,
//将设备设置为EMU_BOOT引导模式。在这种模式下,
//周引导模式如下:
// 
//引导模式:EMU_KEY EMU_BMODE 
//(量0xD00)(0xD01)
// —————– ———————- 
//等待!= 0x55AA X 
// I / O 0x55AA 0x0000 
// SCI 0x55AA 0x0001 
//等待
0x55AA 0x0002 // Get_Mode 0x55AA 0x0003 
// SPI 0x55AA 0x0004 
// I2C 0x55AA 0x0005 
// OTP 0x55AA 0x0006 
//等待0x55AA 0x0007 
//等待
0x55AA 0x0008 // SARAM 0x55AA 0x000A < – “引导至SARAM” 
//闪存0x55AA 0x000B 
//等待0x55AA 其他
/ /
// 
根据上面的Boot Mode Table,通过调试器// 将EMU_KEY写入0xD00,将EMU_BMODE写入0xD01 。构建/加载项目,
//重置设备,运行示例
// 
// $ End_Boot_Table 
// 
// DESCRIPTION:
// 
//该程序将1-14个字写入EEPROM并将其读回。
//写入的数据和写入的EEPROM地址包含
在消息结构I2cMsgOut1中。回读的数据将
//包含在消息结构I2cMsgIn1中。
// 
//该程序将与
F2802x eZdsp 上提供的板载I2C EEPROM配合使用。
// 
// 
// ############################################# ###############################
// $ TI发布:F2802x支持库v230 $ 
// $发布日期:星期五5月8日07:43:05 CDT 2015 $ 
// $版权所有:Copyright(C)2008-2015 Texas Instruments Incorporated – 
// http:// www.ti.com/ ALL RIGHTS RESERVED $ 
// ###################################### #####################################

#include“DSP28x_Project.h”//设备头文件和示例包含文件

//注意:本例中使用的I2C宏可以在
// f2802x_I2C_defines.h文件中找到

//此文件中找到的函数的原型语句。
void I2CA_Init(void); 
uint16_t I2CA_WriteData(struct I2CMSG * msg); 
uint16_t I2CA_ReadData(struct I2CMSG * msg); 
__interrupt void i2c_int1a_isr(void); 
void pass(void); 
void fail(void);

#define I2C_SLAVE_ADDR 0x50 
#define I2C_NUMBYTES 3 
#define I2C_EEPROM_HIGH_ADDR 0x00 
#define I2C_EEPROM_LOW_ADDR 0x30

//全局变量
//两个字节将用于传出地址,
//因此仅设置14个字节最大
结构I2CMSG I2cMsgOut1 = { 
I2C_MSGSTAT_SEND_WITHSTOP,
I2C_SLAVE_ADDR,
I2C_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR,0X11,0X12,0X13,// Msg Byte 1 
0x34}; // Msg Byte 2

struct I2CMSG I2cMsgIn1 = {I2C_MSGSTAT_SEND_NOSTOP,
I2C_SLAVE_ADDR,
I2C_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR};

struct I2CMSG * CurrentMsgPtr; //用于中断
uint16_t PassCount; 
uint16_t FailCount;

void main(void)

uint16_t错误; 
uint16_t i;

//警告:始终确保在从RAM运行任何函数之前调用memcpy 
// InitSysCtrl包含对基于RAM的函数的调用,而不
首先调用// memcpy,处理器将“进入杂草” 
#ifdef _FLASH 
memcpy( &RamfuncsRunStart,&RamfuncsLoadStart,(size_t)&RamfuncsLoadSize); 
#万一

CurrentMsgPtr =&I2cMsgOut1;

//步骤1.初始化系统控制:
// PLL,WatchDog,启用外设时钟
//此示例函数位于f2802x_SysCtrl.c文件中。
InitSysCtrl();

//步骤2.初始化GPIO:
//此示例函数位于f2802x_Gpio.c文件中,
//说明了如何将GPIO设置为默认状态。
// InitGpio(); 
//仅为I2C功能设置GP I / O 
InitI2CGpio();

//步骤3.清除所有中断并初始化PIE向量表:
//禁用CPU中断
DINT;

//将PIE控制寄存器初始化为默认状态。
//默认状态是禁用所有PIE中断并
清除标志//。
//此函数位于f2802x_PieCtrl.c文件中。
InitPieCtrl();

//禁用CPU中断并清除所有CPU中断标志:
IER = 0x0000; 
IFR = 0x0000;

//使用指向shell Interrupt 
// Service Routines(ISR)的指针初始化PIE向量表。
//这将填充整个表,即使
在此示例中未使用中断//。这对于调试目的很有用。
// shell ISR例程可以在f2802x_DefaultIsr.c中找到。
//此函数位于f2802x_PieVect.c中。
InitPieVectTable();

//此示例中使用的中断被重新映射
到此文件中找到的// ISR函数。
EALLOW; //这需要写入EALLOW保护寄存器
PieVectTable.I2CINT1A =&i2c_int1a_isr; 
EDIS; //这是禁止写入受EALLOW保护的寄存器所必需的

//步骤4.初始化所有设备外设:
I2CA_Init(); //仅限I2C-A

//步骤5.用户特定代码

//清除计数器
PassCount = 0; 
FailCount = 0;

//清除传入的消息缓冲区
(i = 0; i <(I2C_MAX_BUFFER_SIZE – 2); i ++)

I2cMsgIn1.MsgBuffer [i] = 0x0000; 
}

//启用此示例所需的中断

//在PIE:Group 8中断中启用I2C中断1 
PieCtrlRegs.PIEIER8.bit.INTx1 = 1;

//启用连接到PIE组8的CPU INT8 
IER | = M_INT8; 
EINT;

//应用程序循环
(;;)

////////////////////////////////// 
//将数据写入EEPROM部分// 
//////////////////////////////////

//检查传出消息,看看是否应该发送./在本例中,它被初始化为使用停止位发送
.if(I2cMsgOut1.MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP)

Error = I2CA_WriteData(&I2cMsgOut1); 
//如果正确启动了通信,请将msg status设置为busy 
//并更新CurrentMsgPtr以获取中断服务例程。
//否则,什么都不做,再试一次下一个循环。一旦
//启动消息,I2C中断将处理其余的事件。在
i2c_eeprom_isr.c文件中搜索// ICINTR1A_ISR。
if(错误== I2C_SUCCESS)

CurrentMsgPtr =&I2cMsgOut1; 
I2cMsgOut1.MsgStatus = I2C_MSGSTAT_WRITE_BUSY; 

} //写入部分的结尾

/////////////////////////////////// 
//从EEPROM部分// 
//// 读取数据/////////////////////////////

//检查外发邮件状态。如果状态为
//未激活,则绕过读取部分。
if(I2cMsgOut1.MsgStatus == I2C_MSGSTAT_INACTIVE)

//检查传入的消息状态。
if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)

// EEPROM地址设置部分
while(I2CA_ReadData(&I2cMsgIn1)!= I2C_SUCCESS)

//也许设置一个尝试计数器来打破无限的
//循环。EEPROM将在执行
写操作时发回NACK 。即使此时
完成写通信,EEPROM仍可能忙于
//编程数据。因此,需要多次尝试

}
//更新当前消息指针和消息状态
CurrentMsgPtr =&I2cMsgIn1; 
I2cMsgIn1.MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY; 
}

//一旦消息进入设置
EEPROM 的内部地址//,重新发送以从
// EEPROM 读取数据字节。用停止位完成公报。
在中断服务例程中//更新了MsgStatus 。
else if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_RESTART)

//读取数据部分
while(I2CA_ReadData(&I2cMsgIn1)!= I2C_SUCCESS)

//也许设置一个尝试计数器来打破无限的
//循环。

//更新当前消息指针和消息状态
CurrentMsgPtr =&I2cMsgIn1; 
I2cMsgIn1.MsgStatus = I2C_MSGSTAT_READ_BUSY; 

} //读取部分的
结尾} // for(;;)的结尾
} //主要结束

void I2CA_Init(void)

//初始化I2C 
I2caRegs.I2CSAR = 0x0050; //从机地址 – EEPROM控制代码

// I2CCLK = SYSCLK /(I2CPSC + 1)
#if(CPU_FRQ_40MHZ || CPU_FRQ_50MHZ)
I2caRegs.I2CPSC.all = 4; //预分频器 – 在模块clk 
#endif 上需要7-12 Mhz

#if(CPU_FRQ_60MHZ)
I2caRegs.I2CPSC.all = 6; //预分频器 – 模块clk需要7-12 Mhz 
#endif 
I2caRegs.I2CCLKL = 10; //注意:必须为非零
I2caRegs.I2CCLKH = 5; //注意:必须为非零
I2caRegs.I2CIER.all = 0x24; //启用SCD和ARDY中断

I2caRegs.I2CMDR.all = 0x0020; //使I2C退出复位
//暂停时停止I2C

I2caRegs.I2CFFTX.all = 0x6000; //启用FIFO模式和TXFIFO 
I2caRegs.I2CFFRX.all = 0x2040; //启用RXFIFO,清除RXFFINT,

返回; 
}

uint16_t I2CA_WriteData(struct I2CMSG * msg)

uint16_t i;

//等待STP位从之前的任何主通信中清除。
//延迟模块清除该位,直到
设置了SCD位为止。如果在启动新消息之前未检查此位,则
// I2C可能会混淆。
if(I2caRegs.I2CMDR.bit.STP == 1)

return I2C_STP_NOT_READY_ERROR; 
}

//设置从站地址
I2caRegs.I2CSAR = msg-> SlaveAddress; 
//I2caRegs.I2CSAR = 0X50; 
//检查总线是否忙
(I2caRegs.I2CSTR.bit.BB == 1)

return I2C_BUS_BUSY_ERROR ; 
}

//设置要发送的字节数
// MsgBuffer +地址

I2caRegs.I2CCNT = msg-> NumOfBytes + 2;

//设置数据发送
I2caRegs.I2CDXR = msg-> MemoryHighAddr; 
I2caRegs.I2CDXR = msg-> MemoryLowAddr;

for(i = 0; i <msg-> NumOfBytes; i ++)

I2caRegs.I2CDXR = *(msg-> MsgBuffer + i); 
}

//发送作为主发送器开始
I2caRegs.I2CMDR.all = 0x6E20;

返回I2C_SUCCESS; 
}

uint16_t I2CA_ReadData(struct I2CMSG * msg)

//等到STP位从之前的任何主通信中清除。
//延迟模块清除该位,直到
设置了SCD位为止。如果在启动新消息之前未检查此位,则
// I2C可能会混淆。
if(I2caRegs.I2CMDR.bit.STP == 1)

return I2C_STP_NOT_READY_ERROR; 
}

I2caRegs.I2CSAR = 0X50;

if(msg-> MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)

//检查总线是否忙
(I2caRegs.I2CSTR.bit.BB == 1)

return I2C_BUS_BUSY_ERROR ; 

//I2caRegs.I2CCNT = msg-> NumOfBytes;

I2caRegs.I2CCNT = msg-> NumOfBytes;

I2caRegs.I2CDXR = msg-> MemoryHighAddr; 
I2caRegs.I2CDXR = msg-> MemoryLowAddr; 
I2caRegs.I2CMDR.all = 0x2620; //发送数据到设置EEPROM地址

否则if(msg-> MsgStatus == I2C_MSGSTAT_RESTART)

I2caRegs.I2CCNT = msg-> NumOfBytes; //设置预期的字节数
I2caRegs.I2CMDR.all = 0x2C20; //发送重启作为主接收器
}

返回I2C_SUCCESS; 
}

__interrupt void i2c_int1a_isr(void)// I2C-A 

uint16_t IntSource,i;

//读取中断源
IntSource = I2caRegs.I2CISRC.all;

//中断源=检测到停止条件
if(IntSource == I2C_SCD_ISRC)

//如果已完成消息正在写入数据,
则将msg重置为非活动状态if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_WRITE_BUSY)

CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_INACTIVE; 

else 

//如果消息在
// EEPROM读取的地址设置部分期间收到NACK ,则下面的代码包括在寄存器访问就绪
//中断源代码中将生成停止条件。
收到停止//条件(此处)后,将消息状态设置为再次尝试。
//用户可能希望在生成错误之前限制重试次数。
if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)

CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_SEND_NOSTOP; 

//如果已完成的消息正在读取EEPROM数据,则将msg重置为无效状态
//并从FIFO读取数据。
else if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_READ_BUSY)

CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_INACTIVE; 
for(i = 0; i <I2C_NUMBYTES; i ++)

CurrentMsgPtr-> MsgBuffer [i] = I2caRegs.I2CDRR; 


//检查收到的数据
(i = 0; i <I2C_NUMBYTES; i ++)

if(I2cMsgIn1.MsgBuffer [i] == I2cMsgOut1.MsgBuffer [i])

PassCount ++; 

else 
{
故障计数++; 


如果(通过计数== I2C_NUMBYTES)

通(); 

else 

fail(); 




//检测到停止条件的结束

//中断源=寄存器访问就绪
//该中断用于确定
//读取数据通信的EEPROM地址设置部分何时完成。由于没有命令停止位,因此该标志
//告诉我们何时发送了消息而不是SCD标志。如果
//收到NACK ,则清除NACK位并命令停止。否则,转到
通信的读取//数据部分。
else if(IntSource == I2C_ARDY_ISRC)

if(I2caRegs.I2CSTR.bit.NACK == 1)

I2caRegs.I2CMDR.bit.STP = 1; 
I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT; 

else if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
{
CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_RESTART; 

} //注册访问结束准备就绪

else 

//由于无效的中断源
__asm(“ESTOP0”)而产生一些错误; 
}

//启用未来的I2C(PIE Group 8)中断
PieCtrlRegs.PIEACK.all = PIEACK_GROUP8; 
}

void pass()

__ asm(“ESTOP0”); 
对于(;;); 
}

void fail()

__ asm(“ESTOP0”); 
对于(;;); 
}

// ================================================ =========================== 
//没有更多。
// ================================================ ===========================

笨鸟:

回复 user6102121:

虽然这个芯片我没搞过,但我看别人的例程,写的是I2caRegs.I2CCNT = 2n+ 2;没有找到你msg-> NumOfBytes这个的原型,这个是几位字节呢,要注意外部eeprom和mcu字节的不同。

F28027 i2c对EEPROM的读写问题

在写入时,向I2CINT寄存器写入NumOfBytes个字节数时,语句为:

I2caRegs.I2CCNT = msg-> NumOfBytes + 2;

请问为什么要加2?

整个程序源代码如下:对应代码做了高亮处理

// ################################################ ########################### 
// 
// FILE:Example_2802xI2c_eeprom.c 
// 
// TITLE:f2802x I2C EEPROM示例
// 
//假设:
// 
//此程序需要f2802x头文件。
// 
//该程序需要一个外部I2C EEPROM连接到
地址为0x50的I2C总线。
// 
//提供时,此项目配置为“boot to SARAM” 
//操作。2802x引导模式表如下所示。
//有关配置eZdsp引导模式的信息,
//请参阅eZdsp附带的文档,
// 
// $ Boot_Table
//当模拟器连接到您的设备时,TRSTn引脚= 1,
//将设备设置为EMU_BOOT引导模式。在这种模式下,
//周引导模式如下:
// 
//引导模式:EMU_KEY EMU_BMODE 
//(量0xD00)(0xD01)
// —————– ———————- 
//等待!= 0x55AA X 
// I / O 0x55AA 0x0000 
// SCI 0x55AA 0x0001 
//等待
0x55AA 0x0002 // Get_Mode 0x55AA 0x0003 
// SPI 0x55AA 0x0004 
// I2C 0x55AA 0x0005 
// OTP 0x55AA 0x0006 
//等待0x55AA 0x0007 
//等待
0x55AA 0x0008 // SARAM 0x55AA 0x000A < – “引导至SARAM” 
//闪存0x55AA 0x000B 
//等待0x55AA 其他
/ /
// 
根据上面的Boot Mode Table,通过调试器// 将EMU_KEY写入0xD00,将EMU_BMODE写入0xD01 。构建/加载项目,
//重置设备,运行示例
// 
// $ End_Boot_Table 
// 
// DESCRIPTION:
// 
//该程序将1-14个字写入EEPROM并将其读回。
//写入的数据和写入的EEPROM地址包含
在消息结构I2cMsgOut1中。回读的数据将
//包含在消息结构I2cMsgIn1中。
// 
//该程序将与
F2802x eZdsp 上提供的板载I2C EEPROM配合使用。
// 
// 
// ############################################# ###############################
// $ TI发布:F2802x支持库v230 $ 
// $发布日期:星期五5月8日07:43:05 CDT 2015 $ 
// $版权所有:Copyright(C)2008-2015 Texas Instruments Incorporated – 
// http:// www.ti.com/ ALL RIGHTS RESERVED $ 
// ###################################### #####################################

#include“DSP28x_Project.h”//设备头文件和示例包含文件

//注意:本例中使用的I2C宏可以在
// f2802x_I2C_defines.h文件中找到

//此文件中找到的函数的原型语句。
void I2CA_Init(void); 
uint16_t I2CA_WriteData(struct I2CMSG * msg); 
uint16_t I2CA_ReadData(struct I2CMSG * msg); 
__interrupt void i2c_int1a_isr(void); 
void pass(void); 
void fail(void);

#define I2C_SLAVE_ADDR 0x50 
#define I2C_NUMBYTES 3 
#define I2C_EEPROM_HIGH_ADDR 0x00 
#define I2C_EEPROM_LOW_ADDR 0x30

//全局变量
//两个字节将用于传出地址,
//因此仅设置14个字节最大
结构I2CMSG I2cMsgOut1 = { 
I2C_MSGSTAT_SEND_WITHSTOP,
I2C_SLAVE_ADDR,
I2C_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR,0X11,0X12,0X13,// Msg Byte 1 
0x34}; // Msg Byte 2

struct I2CMSG I2cMsgIn1 = {I2C_MSGSTAT_SEND_NOSTOP,
I2C_SLAVE_ADDR,
I2C_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR};

struct I2CMSG * CurrentMsgPtr; //用于中断
uint16_t PassCount; 
uint16_t FailCount;

void main(void)

uint16_t错误; 
uint16_t i;

//警告:始终确保在从RAM运行任何函数之前调用memcpy 
// InitSysCtrl包含对基于RAM的函数的调用,而不
首先调用// memcpy,处理器将“进入杂草” 
#ifdef _FLASH 
memcpy( &RamfuncsRunStart,&RamfuncsLoadStart,(size_t)&RamfuncsLoadSize); 
#万一

CurrentMsgPtr =&I2cMsgOut1;

//步骤1.初始化系统控制:
// PLL,WatchDog,启用外设时钟
//此示例函数位于f2802x_SysCtrl.c文件中。
InitSysCtrl();

//步骤2.初始化GPIO:
//此示例函数位于f2802x_Gpio.c文件中,
//说明了如何将GPIO设置为默认状态。
// InitGpio(); 
//仅为I2C功能设置GP I / O 
InitI2CGpio();

//步骤3.清除所有中断并初始化PIE向量表:
//禁用CPU中断
DINT;

//将PIE控制寄存器初始化为默认状态。
//默认状态是禁用所有PIE中断并
清除标志//。
//此函数位于f2802x_PieCtrl.c文件中。
InitPieCtrl();

//禁用CPU中断并清除所有CPU中断标志:
IER = 0x0000; 
IFR = 0x0000;

//使用指向shell Interrupt 
// Service Routines(ISR)的指针初始化PIE向量表。
//这将填充整个表,即使
在此示例中未使用中断//。这对于调试目的很有用。
// shell ISR例程可以在f2802x_DefaultIsr.c中找到。
//此函数位于f2802x_PieVect.c中。
InitPieVectTable();

//此示例中使用的中断被重新映射
到此文件中找到的// ISR函数。
EALLOW; //这需要写入EALLOW保护寄存器
PieVectTable.I2CINT1A =&i2c_int1a_isr; 
EDIS; //这是禁止写入受EALLOW保护的寄存器所必需的

//步骤4.初始化所有设备外设:
I2CA_Init(); //仅限I2C-A

//步骤5.用户特定代码

//清除计数器
PassCount = 0; 
FailCount = 0;

//清除传入的消息缓冲区
(i = 0; i <(I2C_MAX_BUFFER_SIZE – 2); i ++)

I2cMsgIn1.MsgBuffer [i] = 0x0000; 
}

//启用此示例所需的中断

//在PIE:Group 8中断中启用I2C中断1 
PieCtrlRegs.PIEIER8.bit.INTx1 = 1;

//启用连接到PIE组8的CPU INT8 
IER | = M_INT8; 
EINT;

//应用程序循环
(;;)

////////////////////////////////// 
//将数据写入EEPROM部分// 
//////////////////////////////////

//检查传出消息,看看是否应该发送./在本例中,它被初始化为使用停止位发送
.if(I2cMsgOut1.MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP)

Error = I2CA_WriteData(&I2cMsgOut1); 
//如果正确启动了通信,请将msg status设置为busy 
//并更新CurrentMsgPtr以获取中断服务例程。
//否则,什么都不做,再试一次下一个循环。一旦
//启动消息,I2C中断将处理其余的事件。在
i2c_eeprom_isr.c文件中搜索// ICINTR1A_ISR。
if(错误== I2C_SUCCESS)

CurrentMsgPtr =&I2cMsgOut1; 
I2cMsgOut1.MsgStatus = I2C_MSGSTAT_WRITE_BUSY; 

} //写入部分的结尾

/////////////////////////////////// 
//从EEPROM部分// 
//// 读取数据/////////////////////////////

//检查外发邮件状态。如果状态为
//未激活,则绕过读取部分。
if(I2cMsgOut1.MsgStatus == I2C_MSGSTAT_INACTIVE)

//检查传入的消息状态。
if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)

// EEPROM地址设置部分
while(I2CA_ReadData(&I2cMsgIn1)!= I2C_SUCCESS)

//也许设置一个尝试计数器来打破无限的
//循环。EEPROM将在执行
写操作时发回NACK 。即使此时
完成写通信,EEPROM仍可能忙于
//编程数据。因此,需要多次尝试

}
//更新当前消息指针和消息状态
CurrentMsgPtr =&I2cMsgIn1; 
I2cMsgIn1.MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY; 
}

//一旦消息进入设置
EEPROM 的内部地址//,重新发送以从
// EEPROM 读取数据字节。用停止位完成公报。
在中断服务例程中//更新了MsgStatus 。
else if(I2cMsgIn1.MsgStatus == I2C_MSGSTAT_RESTART)

//读取数据部分
while(I2CA_ReadData(&I2cMsgIn1)!= I2C_SUCCESS)

//也许设置一个尝试计数器来打破无限的
//循环。

//更新当前消息指针和消息状态
CurrentMsgPtr =&I2cMsgIn1; 
I2cMsgIn1.MsgStatus = I2C_MSGSTAT_READ_BUSY; 

} //读取部分的
结尾} // for(;;)的结尾
} //主要结束

void I2CA_Init(void)

//初始化I2C 
I2caRegs.I2CSAR = 0x0050; //从机地址 – EEPROM控制代码

// I2CCLK = SYSCLK /(I2CPSC + 1)
#if(CPU_FRQ_40MHZ || CPU_FRQ_50MHZ)
I2caRegs.I2CPSC.all = 4; //预分频器 – 在模块clk 
#endif 上需要7-12 Mhz

#if(CPU_FRQ_60MHZ)
I2caRegs.I2CPSC.all = 6; //预分频器 – 模块clk需要7-12 Mhz 
#endif 
I2caRegs.I2CCLKL = 10; //注意:必须为非零
I2caRegs.I2CCLKH = 5; //注意:必须为非零
I2caRegs.I2CIER.all = 0x24; //启用SCD和ARDY中断

I2caRegs.I2CMDR.all = 0x0020; //使I2C退出复位
//暂停时停止I2C

I2caRegs.I2CFFTX.all = 0x6000; //启用FIFO模式和TXFIFO 
I2caRegs.I2CFFRX.all = 0x2040; //启用RXFIFO,清除RXFFINT,

返回; 
}

uint16_t I2CA_WriteData(struct I2CMSG * msg)

uint16_t i;

//等待STP位从之前的任何主通信中清除。
//延迟模块清除该位,直到
设置了SCD位为止。如果在启动新消息之前未检查此位,则
// I2C可能会混淆。
if(I2caRegs.I2CMDR.bit.STP == 1)

return I2C_STP_NOT_READY_ERROR; 
}

//设置从站地址
I2caRegs.I2CSAR = msg-> SlaveAddress; 
//I2caRegs.I2CSAR = 0X50; 
//检查总线是否忙
(I2caRegs.I2CSTR.bit.BB == 1)

return I2C_BUS_BUSY_ERROR ; 
}

//设置要发送的字节数
// MsgBuffer +地址

I2caRegs.I2CCNT = msg-> NumOfBytes + 2;

//设置数据发送
I2caRegs.I2CDXR = msg-> MemoryHighAddr; 
I2caRegs.I2CDXR = msg-> MemoryLowAddr;

for(i = 0; i <msg-> NumOfBytes; i ++)

I2caRegs.I2CDXR = *(msg-> MsgBuffer + i); 
}

//发送作为主发送器开始
I2caRegs.I2CMDR.all = 0x6E20;

返回I2C_SUCCESS; 
}

uint16_t I2CA_ReadData(struct I2CMSG * msg)

//等到STP位从之前的任何主通信中清除。
//延迟模块清除该位,直到
设置了SCD位为止。如果在启动新消息之前未检查此位,则
// I2C可能会混淆。
if(I2caRegs.I2CMDR.bit.STP == 1)

return I2C_STP_NOT_READY_ERROR; 
}

I2caRegs.I2CSAR = 0X50;

if(msg-> MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)

//检查总线是否忙
(I2caRegs.I2CSTR.bit.BB == 1)

return I2C_BUS_BUSY_ERROR ; 

//I2caRegs.I2CCNT = msg-> NumOfBytes;

I2caRegs.I2CCNT = msg-> NumOfBytes;

I2caRegs.I2CDXR = msg-> MemoryHighAddr; 
I2caRegs.I2CDXR = msg-> MemoryLowAddr; 
I2caRegs.I2CMDR.all = 0x2620; //发送数据到设置EEPROM地址

否则if(msg-> MsgStatus == I2C_MSGSTAT_RESTART)

I2caRegs.I2CCNT = msg-> NumOfBytes; //设置预期的字节数
I2caRegs.I2CMDR.all = 0x2C20; //发送重启作为主接收器
}

返回I2C_SUCCESS; 
}

__interrupt void i2c_int1a_isr(void)// I2C-A 

uint16_t IntSource,i;

//读取中断源
IntSource = I2caRegs.I2CISRC.all;

//中断源=检测到停止条件
if(IntSource == I2C_SCD_ISRC)

//如果已完成消息正在写入数据,
则将msg重置为非活动状态if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_WRITE_BUSY)

CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_INACTIVE; 

else 

//如果消息在
// EEPROM读取的地址设置部分期间收到NACK ,则下面的代码包括在寄存器访问就绪
//中断源代码中将生成停止条件。
收到停止//条件(此处)后,将消息状态设置为再次尝试。
//用户可能希望在生成错误之前限制重试次数。
if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)

CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_SEND_NOSTOP; 

//如果已完成的消息正在读取EEPROM数据,则将msg重置为无效状态
//并从FIFO读取数据。
else if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_READ_BUSY)

CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_INACTIVE; 
for(i = 0; i <I2C_NUMBYTES; i ++)

CurrentMsgPtr-> MsgBuffer [i] = I2caRegs.I2CDRR; 


//检查收到的数据
(i = 0; i <I2C_NUMBYTES; i ++)

if(I2cMsgIn1.MsgBuffer [i] == I2cMsgOut1.MsgBuffer [i])

PassCount ++; 

else 
{
故障计数++; 


如果(通过计数== I2C_NUMBYTES)

通(); 

else 

fail(); 




//检测到停止条件的结束

//中断源=寄存器访问就绪
//该中断用于确定
//读取数据通信的EEPROM地址设置部分何时完成。由于没有命令停止位,因此该标志
//告诉我们何时发送了消息而不是SCD标志。如果
//收到NACK ,则清除NACK位并命令停止。否则,转到
通信的读取//数据部分。
else if(IntSource == I2C_ARDY_ISRC)

if(I2caRegs.I2CSTR.bit.NACK == 1)

I2caRegs.I2CMDR.bit.STP = 1; 
I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT; 

else if(CurrentMsgPtr-> MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
{
CurrentMsgPtr-> MsgStatus = I2C_MSGSTAT_RESTART; 

} //注册访问结束准备就绪

else 

//由于无效的中断源
__asm(“ESTOP0”)而产生一些错误; 
}

//启用未来的I2C(PIE Group 8)中断
PieCtrlRegs.PIEACK.all = PIEACK_GROUP8; 
}

void pass()

__ asm(“ESTOP0”); 
对于(;;); 
}

void fail()

__ asm(“ESTOP0”); 
对于(;;); 
}

// ================================================ =========================== 
//没有更多。
// ================================================ ===========================

user6102121:

回复 笨鸟:

您好,例程是这样写的,写操作:I2caRegs.I2CCNT = 2+2.写2个字节, 读操作:I2caRegs.I2CCNT = 2,读2个字节。读到的2个数据与写入的2个数据相同。
写操作:I2caRegs.I2CCNT = 1+2.写1个字节, 读操作:I2caRegs.I2CCNT = 2,读2个字节。读到的1个数据与写入的1个数据相同。
这个地方我就已经不是很明白了,这种情况不应该读2个字节数据吗?
之后-
我增加写字节的个数为3,加断点DXR寄存器可检测到更新的3个写数据值,但是读数据却一个都读不到。求指教!

赞(0)
未经允许不得转载:TI中文支持网 » F28027 i2c对EEPROM的读写问题
分享到: 更多 (0)