DSP中i2c存储eeprom实例分析.docx
《DSP中i2c存储eeprom实例分析.docx》由会员分享,可在线阅读,更多相关《DSP中i2c存储eeprom实例分析.docx(27页珍藏版)》请在冰豆网上搜索。
![DSP中i2c存储eeprom实例分析.docx](https://file1.bdocx.com/fileroot1/2023-2/22/e2493217-e623-4f4f-ab22-b33e769affce/e2493217-e623-4f4f-ab22-b33e769affce1.gif)
DSP中i2c存储eeprom实例分析
1.示例程序中几种状态说明
第一次看i2c_eeprom示例程序,对程序中的MsgStatus信息状态切换非常懵懂,为什么要有这几个状态?
状态切换顺序如何安排?
一大堆的状态,让人有些摸不着头脑。
先把程序中的头文件
涉及的7种状态分析一下。
//I2CMessageCommandsforI2CMSGstruct
#defineI2C_MSGSTAT_INACTIVE0x0000//未激活状态:
一般成功发送数据或者//接受数据后可以设置信息状态为此状态,告诉用户可进行下一次的写数据或读数据。
#defineI2C_MSGSTAT_SEND_WITHSTOP0x0010//发送带停止位数据:
这是为写数据而设///的状态,写入地址和数据之后发个停止位告诉存储器数据写入完毕。
#defineI2C_MSGSTAT_WRITE_BUSY0x0011//写数据忙状态:
在将待写的数据放入//缓存后,就可以使能IIC传输数据了,然后把信息状态设为该状态,意在告诉用户:
数据//已经在传送过程中。
当然是否传送完毕,还需要通过查询SCD位来判断。
#defineI2C_MSGSTAT_SEND_NOSTOP0x0020//发送无停止位数据:
这个状态是为了读//取数据而设的,有查阅过AT24C1024EEPROM存储器使用手册的读者知道,在读数据之前//要发送数据的地址,发完地址不能产生停止位,这是存储器硬件设计决定的。
设为这个状//态意在告诉读者,可以发送要读取的数据的地址了。
#defineI2C_MSGSTAT_SEND_NOSTOP_BUSY0x0021//发送无停止位数据忙状态:
这个状态是//为了读取数据而设的,似于I2C_MSGSTAT_WRITE_BUSY,说明地址数据已经在传送过程中。
//传送是否成功,还要看ARDY的状态。
#defineI2C_MSGSTAT_RESTART0x0022//重发开始位状态:
这个状态也是为读取
////数据而设。
我们知道,读取存储器数据主要分两个步骤:
第一,发送START位+设备地址
//+数据地址+无停止位。
第二,再发START位+设备地址,紧接着存储器发送数据到IIC接收
//缓存器(I2CDRR),接收到设定好的数据数量(I2CCNT值)时输出停止位STOP.
//值得注意的是:
理论上写完数据就能马上读取数据,但事实上EEPROM存储器仍需要一
////定延时来存储数据,约有2ms左右。
通过示波器可以观察到,写完数据后,并不能马上
//成功读取数据,也就是说读数据的第一步骤要重复好几次(总线为50K时,大约要重复
//8次)才能成功。
#defineI2C_MSGSTAT_READ_BUSY0x0023//读取数据忙状态:
这个状态是为读取数
//据而设。
在读数据的第二步骤中,发完START位+设备地址后,就设为这一状态。
意在说//明IIC开始等待接收固定数量(I2CCNT值)的数据。
可以通过查询ARDY位判断。
//头文件中的其他定义应该没什么大问题了!
2.AT24C1024EEPROM读写数据格式
(1)AT24C1024设备地址:
1
0
1
0
0
A1
P0
R/W
(2)单字节写入:
START->发送从设备地址(写控制码R/W=0)->处理Ack->发送字节地址->处理Ack[->发送1字节数据->处理Ack]->STOP。
如下图:
(3)按页写入:
START->发送从设备地址(写控制码R/W=0)->处理Ack->发送字节地址->处理Ack[->发送1字节数据->处理Ack->发送第2字节数据->处理Ack->发送第3字节数据->处理Ack……直到发完X字节]->STOP。
如下图。
注意,连续写入的数据字节数不能超过每页所能容下的总量。
如果写入的数据超过一页的长度,将发生回卷,即从EEPROM的0地址处进行数据覆盖。
比如,AT24C1024有512页,每页最大容纳256字节。
超过这个长度,地址指针将从每页首地址重新开始。
(4)随机单字节读取:
第一步:
发START->发送从设备地址(写控制码R/W=0)->处理Ack->发送字节地址高位->处理Ack->发送字节地址低位->处理Ack->第二步:
发START->发送器件地址(读控制码R/W=1)->处理Ack->接收1字节数据->STOP。
(5)随机连续读取:
在随机单字节读取操作的STOP信号发送之前,加入若干个[->发送Ack->接收1字节数据]即可实现。
(6)当前位置单字节读取:
START->发送从设备地址(读控制码)->处理Ack->发送字节地址->处理Ack->接收1字节数据->STOP。
当前指的是之前进行过读取操作但是没有发送STOP信号,EEPROM芯片内部指针所在的位置即为当前位置。
(7)当前位置连续读取:
在当前位置单节读取操作的STOP信号发送之前,加入若干个[->发送Ack->接收1字节数据]即可实现。
备注:
部分内容引用XX文库中的《I2C读写流程》文档
3.主程序说明及流程图
详细的注释可以参见程序附录,,这里主要解释一下设备地址取0x50的缘由。
从AT24C1024的数据手册可知,设备地址为
。
而在程序中设置的地址是0x50,即0B01010000。
看似不妥,其实,这个例子中设备地址采用7位地址模式,这样只取0x50的低7位作为设备地址的高七位,设备地址的最低位R/W则由寄存器I2CMDR中的TRX位决定。
这样读数据时设备地址为0B10100001,写数据时设备地址改为0B10100000。
通过示波器可以验证这些数据。
问题1:
每次检测到SCD中断时,也就是顺利发完指定数量的数据或者接收指定数量的数据了,理论上I2caRegs.I2CCNT==0,但是本人设了几个中断点去观察该寄存器的值,发现总是不为零。
通过观察I2caRegs.I2CFFTX.bit.TXFFST和I2caRegs.I2CFFRX.bit.RXFFST,可以发现这两个寄存器为零时,I2caRegs.I2CCNT也不为零。
由此可知,I2CCNT不能实时反映发送/接收存储器中数据的数量,不过可以用TXFFST/RXFFST来代替。
图1主程序流程图,图2为写数据程序流程图,图3为读数据程序流程图,图4为中断函数流程图。
图1主程序流程图
图2写数据程序流程图图3读数据程序流程图
图4中断函数流程图
4.程序附录
//可以用以下代码替换示例程序Example_280xI2c_eeprom.c中的代码,再进行调试。
//
//该程序跟原始程序没多大区别,主要改变为:
引入几个统计变量,改变发送数据长度为2字节//
//TIFile$Revision:
/main/5$
//Checkin$Date:
April4,200717:
18:
36$
//###########################################################################
//
//FILE:
Example_280xI2c_eeprom.c
//
//TITLE:
DSP280xI2CEEPROMExample
//
//ASSUMPTIONS:
//
//ThisprogramrequirestheDSP280xheaderfiles.
//
//ThisprogramrequiresanexternalI2CEEPROMconnectedto
//theI2Cbusataddress0x50.
//
//Assupplied,thisprojectisconfiguredfor"boottoSARAM"
//operation.The280xBootModetableisshownbelow.
//ForinformationonconfiguringthebootmodeofaneZdsp,
//pleaserefertothedocumentationincludedwiththeeZdsp,
//
//BootGPIO18GPIO29GPIO34
//ModeSPICLKASCITXDA
//SCITXB
//-------------------------------------
//Flash111
//SCI-A110
//SPI-A101
//I2C-A100
//ECAN-A011
//SARAM010<-"boottoSARAM"
//OTP001
//I/0000
//
//DESCRIPTION:
//
//Thisprogramwillwrite1-14wordstoEEPROMandreadthemback.
//ThedatawrittenandtheEEPROMaddresswrittentoarecontained
//inthemessagestructure,I2cMsgOut1.Thedatareadbackwillbe
//containedinthemessagestructureI2cMsgIn1.
//--------------------------------------------------------------
//CODEMODIFICATIONSAREREQUIREDFOR60MHZDEVICES(In
//DSP280x_Examples.hinthecommon/include/directory,set
//#defineCPU_FRQ_60MHZto1,and#defineCPU_FRQ_100MHZto0).
//--------------------------------------------------------------
//Thisprogramwillworkwiththeon-boardI2CEEPROMsuppliedon
//theF280xeZdsp.
//
//
//###########################################################################
//OriginalAuthor:
D.F.
//
//$TIRelease:
DSP280xHeaderFilesV1.60$
//$ReleaseDate:
December3,2007$
//###########################################################################
#include"DSP280x_Device.h"//DSP280xHeaderfileIncludeFile
#include"DSP280x_Examples.h"//DSP280xExamplesIncludeFile
//Note:
I2CMacrosusedinthisexamplecanbefoundinthe
//DSP280x_I2C_defines.hfile
//Prototypestatementsforfunctionsfoundwithinthisfile.
voidI2CA_Init(void);
Uint16I2CA_WriteData(structI2CMSG*msg);
Uint16I2CA_ReadData(structI2CMSG*msg);
interruptvoidi2c_int1a_isr(void);
voidpass(void);
voidfail(void);
#defineI2C_SLAVE_ADDR0x50//EEPROM地址
#defineI2C_NUMBYTES2//为方便示波器观察,设置发送2字节的数据
#defineI2C_EEPROM_HIGH_ADDR0x11//数据的写入地址高位
#defineI2C_EEPROM_LOW_ADDR0x0F//数据的写入地址低位
//Globalvariables//全局变量
//Twobyteswillbeusedfortheoutgoingaddress,//有2个字节是地址
//thusonlysetup14bytesmaximum//最多只能设置14字节数据
structI2CMSGI2cMsgOut1={I2C_MSGSTAT_SEND_WITHSTOP,//初始状态为:
发送带停止位数据
I2C_SLAVE_ADDR,
I2C_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR,
0xff,//MsgByte01
0x3F,//MsgByte02
0x56,//MsgByte03
0x78,//MsgByte04
0x9A,//MsgByte05
0xBC,//MsgByte06
0xDE,//MsgByte07
0xF0,//MsgByte08
0x11,//MsgByte09
0x10,//MsgByte10
0x11,//MsgByte11
0x12,//MsgByte12
0x13,//MsgByte13
0x12,//MsgByte14
};
structI2CMSGI2cMsgIn1={I2C_MSGSTAT_SEND_NOSTOP,
I2C_SLAVE_ADDR,
I2C_NUMBYTES,
I2C_EEPROM_HIGH_ADDR,
I2C_EEPROM_LOW_ADDR};
structI2CMSG*CurrentMsgPtr;//Usedininterrupts
Uint16PassCount;
Uint16FailCount;
Uint16ARDY_ISRC_NACK_number=0;//统计ARDY中断源引起的中断中NACK次数
Uint16SCD_ISRC_number=0;//统计SCD中断源引起的中断次数
Uint16ARDY_ISRC_number=0;//统计ARDY中断源引起的中断次数
Uint16all_ISRC_number=0;//统计所有中断源引起的中断次数
Uint16Write_load_num=0;//统计写数据函数调用次数
Uint16Read_load_num1=0;//统计读数据函数调用次数1第一步骤
Uint16Read_load_num2=0;//统计读数据函数调用次数2第二步骤
voidmain(void)
{
Uint16Error;
Uint16i;
CurrentMsgPtr=&I2cMsgOut1;
//Step1.InitializeSystemControl:
//PLL,WatchDog,enablePeripheralClocks
//ThisexamplefunctionisfoundintheDSP280x_SysCtrl.cfile.
InitSysCtrl();
//Step2.InitalizeGPIO:
//ThisexamplefunctionisfoundintheDSP280x_Gpio.cfileand
//illustrateshowtosettheGPIOtoit'sdefaultstate.
//InitGpio();
//SetuponlytheGPI/OonlyforI2Cfunctionality
InitI2CGpio();
//Step3.ClearallinterruptsandinitializePIEvectortable:
//DisableCPUinterrupts
DINT;
//InitializePIEcontrolregisterstotheirdefaultstate.
//ThedefaultstateisallPIEinterruptsdisabledandflags
//arecleared.
//ThisfunctionisfoundintheDSP280x_PieCtrl.cfile.
InitPieCtrl();
//DisableCPUinterruptsandclearallCPUinterruptflags:
IER=0x0000;
IFR=0x0000;
//InitializethePIEvectortablewithpointerstotheshellInterrupt
//ServiceRoutines(ISR).
//Thiswillpopulatetheentiretable,eveniftheinterrupt
//isnotusedinthisexample.Thisisusefulfordebugpurposes.
//TheshellISRroutinesarefoundinDSP280x_DefaultIsr.c.
//ThisfunctionisfoundinDSP280x_PieVect.c.
InitPieVectTable();
//Interruptsthatareusedinthisexamplearere-mappedto
//ISRfunctionsfoundwithinthisfile.
EALLOW;//ThisisneededtowritetoEALLOWprotectedregisters
PieVectTable.I2CINT1A=&i2c_int1a_isr;
EDIS;//ThisisneededtodisablewritetoEALLOWprotectedregisters
//Step4.InitializealltheDevicePeripherals:
//ThisfunctionisfoundinDSP280x_InitPeripherals.c
//InitPeripherals();//Notrequiredforthisexample
I2CA_Init();
//Step5.Userspecificcode
//ClearCounters
PassCount=0;
FailCount=0;
//Clearincomingmessagebuffer
for(i=0;i{
I2cMsgIn1.MsgBuffer[i]=0x0000;
}
//Enableinterruptsrequiredforthisexample
//EnableI2Cinterrupt1inthePIE:
Group8interrupt1
PieCtrlRegs.PIEIER8.bit.INTx1=1;
//EnableCPUINT8whichisconnectedtoPIEgroup8
IER|=M_INT8;
EINT;
//Applicationloop
for(;;)
{
//////////////////////////////////
//WritedatatoEEPROMsection//
//////////////////////////////////
//Checktheoutgoingmessagetoseeifitshouldbesent.
//Inthisexampleitisinitializedtosendwithastopbit.
if(I2cMsgOut1.MsgStatus==I2C_MSGSTAT_SEND_WITHSTOP)
{Write_load_num++;
Error=I2CA_WriteData(&I2cMsgOut1);
//Ifcommunicationiscorrectlyinitiated,setmsgstatustobusy//如果通信已经正确初始化,设置msg状态为’忙‘,并
//andupdateCurrentMsgPtrfortheinterruptserviceroutine.//更新作为中断服务路径的指针CurrentMsgPtr。
//Otherwise,donothingandtryagainnextloop.Oncemessageis//否则,不做任何操作,等待下一次重新写数据。
一旦信息正确
//initiated,theI2Cinterruptswillhandletherest.Searchfor//初始化,I2C中断将处理接下来的事情。
可以在
//ICINTR1A_ISRinthei2c_eeprom_isr.cfile.//i2c_eeprom_isr.c文件中找到ICINTR1A_ISR。
if(Error==I2C_SUCCESS)//数据已成功放入缓存寄存器
{
CurrentMsgPtr=&I2cMsgOut1;//改变指针路径
I2cMsgOut1.MsgStatus=I2C_MSGSTAT_WRITE_BUSY;//设为发送数据忙状态
}
}//endofwritesection
///////////////////////////////////
//ReaddatafromEEPROMsection//该过程包括两次发送START位,第一次发送地址
////////////////////////