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个写数据值,但是读数据却一个都读不到。求指教!