IC读写EEPROM问题总结
IC读写EEPROM问题总结

2017年6月30日星期五目(de):利用TMS320F2801芯片上外设I2C(2线串口)读写EEPROM数据(24LC128)关键点1:24LC时钟频率400KHz,寄存器设置如下:I2caRegs.I2CPSC.all = 9; // Prescaler - need 7-12 Mhz on module clkI2caRegs.I2CCLKL = 10; // NOTE: must be non zeroI2caRegs.I2CCLKH = 5; // NOTE: must be non zero时钟频率也可设为200KHz,三个参数分别为9、20、20(CPU时钟频率为100MHz)(未测试)关键点2:波形分析问题:I2C模块是不是只有I2CCNT 减到0才会发出停止信号I2C模块是硬件(de),当检测到发送完了就会发结束自动发信号,不需要人为干预问题1:字节写操作正常,但是字节读函数出错原因:写EEPROM是在七位器件地址后添加写标志,而读EEPROM需要在七位器件地址后添加写标志.关键点:读EEPROM数据需要发送两次命令.第一次为写地址(此地址会被赋值给EEPROM内(de)地址指针),因此需要添加写标志;第二次为读数据,将写标志改为读标志.问题2:主机接收时,SDA数据线上有数据传输,且I2CDRR接收数据寄存器有数据更新,但寄存器显示不可读,即CPU认为一直没接收到数据,一直停在下面语句while关键点:初始化设置时采用(de)是FIFO接收方式,因此无效,应查询FIFO 接收中断位while方式查询位.此位只有在非FIFO中断接收方式时才有效.问题3:断续单字节读写正常,但是采用连续(de)单字节读写出错.原因:EEPROM写过程(de)结束并不是I2C总线写结束就结束,实际上I2C 总线(de)写入数据先被保存到了EEPROM内部(de)缓冲区,当遇到I2C结束条件后,EEPROM才启动内部写过程,这个过程才是保存数据(de)过程.非常悲哀(de)是这个过程比较长,官方文档标注为5ms.如果在这5ms以内对EEPROM芯片访问将被忽略.关键点:读写EEPROM应延时至少5ms,软件延时10msdo{}while(EEPROM_Timer <= 10); //10ms问题4:查询EEPROM写过程是否结束造成死机,只能查询EEPROM读过程.官方文档说EEPROM内部写周期最长为5ms,在很多情况下是远远低于5ms(de),为了节约时间,官方给出一个解决办法.当写周期完毕后就开始进行应答查询,来确定EEPROM写周期何时结束.所谓应答查询官方解释为:就是向EEPROM发送一个I2C起始条件后发送器件地址和一个读写标志位,当EEPROM完成内部写周期会回应一个ACK,这时MCU就可以进行正常(de)其他读写过程了.官方原文如下:杯具就是始于我画红线(de)那句话,它说可以在器件地址后任意填写读写标志.我就填了读标志,事实证明在EEPROM写入过程采用读查询将导致系统死机,I2C总线不能被正常拉高,可能是EEPROM内部已经把总线拉到了地不管怎样,反正就是死机了.经过多次尝试最终发现应答查询只能采用写应答查询可以正常确定EEPROM内部写周期(de)结束.——by数据传输过程:从机发送数据 SDA总线 I2CRSR缓冲寄存器I2CDRR接收数据寄存器中间变量内存.问题5:CPU以字(双字节)为单位读写EEPROM数据有误;原因:CPU中(de)内存单元以字(word-16bit)为单位,而EEPROM中(de)内存单元是字节(byte-8bit)为单位,因此将CPU内存地址转化为EEPROM 指针地址时,因乘以2(左移一位)问题6:使用读数据函数式,收到(de)数据都是1.原因:EEPROM初次读取未写过(de)内存单元时,默认为高电平,即收到(de)字节为0xFF.如果已经写过内存单元,则代表数据未成功写入;写入与读数据(de)内存地址不一样.问题7:写入EEPROM(de)数据与随后读出来(de)数据不一致,但读出来(de)数据又没有规律性.可能原因:数据未成功写入;数据读写字节数超过EEPROM(de)页内字节数(跨页);读写地址不一致;读写EEPROM之间应有一定(de)延时时间.解决办法:若连续读多字节数据,则读取数据之间应加延时,因为数据从I2CRSR数据接收缓冲寄存器(多字节)复制到I2CCDRR数据接收寄存器(一字节)需要时间.单字节延时25us,双字节(字)延时50us——测试通过问题8:使用示波器观测SDA数据线上(de)波形时,发现每次应答信号之前都有一个毛刺(尖峰),是什么原因导致(de)(不影响数据(de)正常读写)类似问题:使用F28335模拟I2C时序读取惯导器件(de)数据时,发现在更改SDA(de)传输方向时,Gpio中数据寄存器会发生变化,导致SDA上有毛刺产生.问题9: I2C在跟EEPROM通讯(de)时候,第一次写入数据,一个一个读取(de)话,能知道写入EEPROM(de)值是没有错(de),但是在连续读取数据(de)时候,就会出现,上电第一次读取数据串(de)时候,是全部读取正确,然后再读取一遍数据串(de)时候,只有第一个读取(de)数据是正确(de),后面(de)数据会全部变成FF FF 这是怎么回事办法1:大家都说STM32(de)IIC有点bug,所以很少人用其自带(de)IIC,一般都是用IO口模拟IIC,模拟很简单而且不会出错.逻辑分析仪抓取I2C总线数据, 改为转接板抓取数据,即I2C转USB通讯.问题10:I2C给EEPROM写数据时,两字节地址需不需要算进去吗答案:需要,且地址字节数与EEPROM(de)型号(容量)相关,有些为1字节地址,有些为2字节地址.24LC128需要两字节地址来区分内存单元,其内存最小单元为1字节,地址从0x00开始,一页64字节,因此地址指针范围为:0x00~0x3F.I2caRegs.I2CCNT = (n<<1)+2;问题11:一次读写数据字节数最好不超过16字节.原因:其一I2C深度寄存器范围限定,其二,读写数据字节太多会导致I2C 总线出错(de)概率加大.ST_5bit (0x0000~0x10000)I2caRegs.I2CFFTX.bit.TXFFIL_5bitI2caRegs.I2CFFRX.bit.RXFFST_5bit(0x0000~0x10000)I2caRegs.I2CFFRX.bit.RXFFIL_5bitI2caRegs.I2CCNT_32bit问题12:总是提示总线繁忙= 1总线繁忙,BB = 0 总线空闲关键:总线繁忙这个位只读.猜想解决办法:如果是上电第一次读写就出现总线繁忙,就对I2C模块进行复位;如果不是第一次,且I2C总线上只有一主,则等待一定时间(5ms);如果是多主,则返回,等待总线空闲吧.问题13:CPU写数据给EEPROM时,如果设置断点,就能成功写入数据,但没有断点,数据写不成功.什么原因呀原因:写保护WP引脚(de)电平应在接收到停止信号后,应保持低电平一段时间才使能写保护,即加延时语句.———已测试通过//所有字节(地址字节+数据字节)都是添加写标志,即低电平,2n+2 <=64////写EEPROM地址从0开始//void EEPROM_Write_call(Uint16 address,Uint16 n,Uint16 s){Uint16 i,data_temp;do{}while(EEPROM_Timer <= 20); //20ms// Check if bus busyif (I2caRegs.I2CSTR.bit.BB = 0)//总线忙位,不能手动清除{return;}if(WP = 0) WP = 0; //清除从机EEPROM写保护模式// Setup slave address-7bitI2caRegs.I2CSAR = 0x50;I2caRegs.I2CCNT = (n<<1)+2; // Setup number of bytes to send //set up write modeI2caRegs.I2CMDR.all= 0x6E20;// Send start as master transmitter //发起始信号//主机发送停止信号//TX modeif(I2caRegs.I2CSTR.bit.NACK = 0) return;//存储器首地址——2字节(14bit)while(I2caRegs.I2CSTR.bit.XRDY = 1);I2caRegs.I2CDXR = (address>>8);if(I2caRegs.I2CSTR.bit.NACK = 0) return;while(I2caRegs.I2CSTR.bit.XRDY = 1);I2caRegs.I2CDXR = (address&0x00FF);if(I2caRegs.I2CSTR.bit.NACK = 0) return;// Setup data to sendfor(i=0; i<n; i++){data_temp = MK_Data[s+i];while(I2caRegs.I2CSTR.bit.XRDY = 1);I2caRegs.I2CDXR = (data_temp&0x00FF);if(I2caRegs.I2CSTR.bit.NACK = 0) return;while(I2caRegs.I2CSTR.bit.XRDY = 1);I2caRegs.I2CDXR = data_temp >> 8;if(I2caRegs.I2CSTR.bit.NACK = 0) return;}do{}while(I2caRegs.I2CSTR.bit.SCD = 1); //是否有停止信号WP = 1; //保护EEPROM,使其只读EEPROM_Timer = 0;}问题14:波形错误——用I2C接口,SCK 和 SDA都接有4.7K(de)上拉电阻,用示波器抓SCK和SDA(de)波形,发现SCK时序正常,SDA异常,见附图(黄为SCK,紫为SDA),请问这个锯齿波形大概是什么原因造成(de)呢——by猜测原因:可能是I2C模块时钟频率设置不合理;——未验证IIC中断作用:IIC中断和UART中断一样,你可以立刻得到数据,而不需要总是查询.IIC接收数据只是存到指定(de)寄存器中,如果你不取走,下次再接收数据就直接冲掉了,所以IIC接收到数据之后给CPU中断,去处理这些收到(de)数据查找中断源是一种保险(de)做法,要是由于其他(de)哪几种原因产生了中断,但是此时数据并没有接收完,中断服务子程序去处理数据了,结果就不对了如果你自己敢保证不会出现哪几种情况就可以完全不用写——by//I2C (接收)interrupt void i2c_int1a_isr(void) // I2C-A{Uint16 IntSource; // Read interrupt sourceswitch(IntSource){case I2C_NO_ISRC: break; // =0case I2C_ARB_ISRC: break; // =1case I2C_NACK_ISRC:break; // =2case I2C_ARDY_ISRC:break; // =3case I2C_RX_ISRC: // =4InData[I2cIndex++] = I2caRegs.I2CDRR; break;case I2C_TX_ISRC: break; // =5case I2C_SCD_ISRC: break; // =6case I2C_AAS_ISRC: break; // =7default: //asm(" ESTOP0"); // Halt on invalid number. asm(" RPT 5 ||NOP ");} // Enable future I2C (PIE Group 8) interrupts}。
eeprom读写程序详解

eeprom读写程序详解EEPROM(Electrically Erasable Programmable Read-Only Memory) 是一种可编程只读存储器,可以在电信号的作用下进行擦写和改写。
它通常用于存储单片机或其他嵌入式系统中的数据、设置参数、配置文件等。
对于 EEPROM 的读写程序,需要考虑以下几个方面:1. 读操作:读操作通常包括以下步骤:- 等待上次读操作完成。
- 获取要读取的数据的单元地址。
- 将 EEPGD 位和 CFGS 位清零。
- 启动读操作控制位 RD。
- 等待本次读操作完成。
- 将该单元地址中对应的数据返回。
在读取 EEPROM 数据时,为了避免芯片在一瞬间无法获取到数据,需要给芯片一定的时间来稳定获取数据。
因此,在读取操作中需要加入等待步骤。
2. 写操作:写操作通常包括以下步骤:- 等待上次写操作完成。
- 获取要写的数据的单元地址。
- 将要写的数据写入 EEPROM 的单元中。
- 将 EEPGD 位和 CFGS 位清零。
- 启动写操作控制位 WP。
- 等待写操作完成。
在写操作中,为了确保数据的可靠性,需要将要写的数据写入EEPROM 的单元中,并等待写操作完成。
同时,在写操作过程中,需要注意避免对无关的单元进行写操作,以免损坏 EEPROM 芯片。
3. 中断处理:在 EEPROM 的读写操作中,通常需要加入中断处理机制,以便在读写过程中及时响应和处理异常情况。
例如,在读取 EEPROM 数据时,如果 EEPROM 芯片出现故障,可能会导致读取失败。
为了避免这种情况,可以在读取操作中加入中断处理机制,在读取失败时及时报警或采取相应的应对措施。
总之,EEPROM 读写程序的实现需要考虑多个方面的因素,包括读操作、写操作、中断处理等。
同时,需要考虑 EEPROM 芯片的特性和限制,以便实现高效、稳定、可靠的 EEPROM 读写操作。
最新EEPROM读写访问汇总

EEPROM写使能。当EEPROM的
地址和数据准备好后,用户必须
设置EEWE为“1”,才能将数据 写入EEPROM中。在置EEWE为 “1”前,EEMWE必须置“1”, 否则写入操作无效。
EEPROM读使能。此位用于对 EEPROM的数据读取,当EEAR中 设置了EEPROM的读取地址后, EERE的置“1”操作将使单元的数 据送至EEDR寄存器中,此时EERE 位自动清“0”。
void sleep_enable(void) //允许低功耗模式
void sleep_disable(void) //禁止低功耗模式
void idle(void)
//闲置模式
void powerdown(void) //掉电模式
void powersave(void) //休眠模式
在调用这些库函数之前必须将头文件#include <sleep.h>
显
sei();
//开中断
while(1);
}
§AVR单片机的节电方式
一、节电方式概述 单片机低功耗设计方案主要从以下几个方面考虑:
(1)采用CMOS低功耗的单片机; (2)尽量降低单片机的供电电源; (3)降低晶振的频率; (4)采用低功耗的外围电路; (5)使用休眠模式。 二、ATmage16单片机的休眠模式 单片机进入休眠模式,停止正常程序运行,以减少功
耗。休眠状态主要有以下3种模式: 1、闲置模式 此模式下CPU停止运行,而SPI、UART、模拟比较器、
ADC、定时器/计数器、看门狗及中断系统继续工作。 2、掉电模式 此模式下外部晶振停振,而外部中断及看门狗在使能
的前提下继续工作。只有外部复位、看门狗复位及外部中 断INT0和INT1可以使MCU脱离掉电模式。
STC单片机EEPROM的读写问题

dzjk2010-11-14 09:58貌似使用STC单片机内部EEPROM有一定的局限wieke982010-11-14 10:41 要分块的,如果两个字节是同时写入的可以放在一个块里,如果不是要放在两个块里!fang32010-11-14 13:11MOV DPTR,#2000H;指针指向第一扇区EEPROMW:;写MOV ISP_CONTR,#1;设置等等待时间ORL ISP_CONTR,#80h;允许ISP/IAP操作MOV ISP_CMD,#02H ;送写命令MOV ISP_ADDRH,DPH ;送高地址MOV ISP_ADDRL,DPL ;送低地址MOV ISP_DATA,A ;A是要写入的数据ACALL ISPXX ;触发RET上面的只是写一个字节A而已wieke982010-11-14 14:33EEPROMW:;写MOV R1,#30H;30h和31H是要写的数据MOV R3,#2;要写的字节数FGRW:MOV ISP_CONTR,#1;设置等等待时间ORL ISP_CONTR,#80h;允许ISP/IAP操作MOV ISP_CMD,#02H ;送写命令MOV ISP_ADDRH,DPH ;送高地址MOV ISP_ADDRL,DPL ;送低地址MOV A,@R1;将要写的数据传入累加器MOV ISP_DATA,A ;A是要写入的数据ACALL ISPXX ;触发INC DPTRINC R1DJNZ R3,FGRW;是否写完,没写继续fang32010-11-14 21:18FGRW:MOV ISP_CONTR,#1;设置等等待时间ORL ISP_CONTR,#80h;允许ISP/IAP操作MOV ISP_CMD,#02H ;送写命令MOV ISP_ADDRH,DPH ;送高地址MOV ISP_ADDRL,DPL ;送低地址MOV A,@R1;将要写的数据传入累加器MOV ISP_DATA,A ;A是要写入的数据ACALL ISPXX ;触发因为说扇区是空的才能写还是搞不明白,如果写完一个字节,那么这个扇区已经不是空的了,还能写第二个字节吗wieke982010-11-15 10:30所谓空就是是0FFH,在擦除之后就是0FFH都可以写入了!fang32010-11-15 22:35 哦,有点明白了,,,就是说,在一个扇区里,只要是空的单元就可以写入,谢谢哪么,你说的要分块的,如果两个字节是同时写入的可以放在一个块里,如果不是要放在两个块里!怎么解释?wieke982010-11-16 08:19因为是整块擦除的,每一块中的每一个字节只能写入一次第二次要写入就必须重新擦除,一擦除整块的数据都会被擦除,所以不是同时修改的数据要放在不同的块中。
IIC总线读写EEPROM(深度诠释)

/*----------------------------------------------------------------------------------------------------------IIC总线读写EEPROM(串行扩展eeprom,24c02)(STC12C系列单片机自带eeprom,且有另外的eeprom操作方式)作者:Allen.H(帮同学修改的一个程序)时间:2010.11.5----------------------------------------------------------------------------------------------------------*/#include <reg52.h>#include <intrins.h>//是用括号还是双引号看情况,本地头文件用双引号,系统头文件用括号//这里使用了_nop_()函数,所以调用此头文件#define TRUE 1/*define宏定义一般用大写,宏定义并不会减少最终代码空间define多行语句时,每一行末尾写上\,最后一行可以不写,有时比较短的语句写成一个子函数会牺牲更多的时间,因为函数调用耗时比较多,这个时候用一个define语句更好*/#define FALSE 0typedef unsigned char uchar;//良好的程序风格,不应该用#define//#define uchar unsigned charsbit sda=P2^0; //---------你把sda和scl引脚可能定反了,我换过来了-------------------------------sbit scl=P2^1;//等号对其,变量名长短不一时,注意,且测试等于号"=="或者其他双目关系运算符两边都空一格//-----------------------------------------------------------------void delay(uchar z)//带参数很好{//大括号所在行不要写代码uchar i,j;//局部变量中用来自加自减可以用i,j之类的定义,计数建议不要用i,j//局部变量不占内存,函数调用时生成堆栈,不应该定义局部变量时作初始化//----局部变量命名后空一格,写正式代码for(i=z;i>0;i--)for(j=100;j>0;j--);//注明多少时间,在调试模式下,看窗口左边的SEC值}//函数与函数之间空一格void delay_7nop()//子程序命名最好顾名思义,比如delay_1ms(),这里考虑都是使用7nop,不带参数{/*程序代码每进一层逻辑就缩进一格TAB键,TAB设置为3,4格,在keil的view->options里面设置,不要使用几个空格来缩进,统一使用TAB键*/_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();//这里0-1000多个_nop_都可以}//delay函数都放在一起,函数顺序不要乱放,相关的放一起,//--------------------------------------------------------------------void init(){sda=1;delay_7nop();scl=1;delay_7nop();}//---SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号;//SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信号。
51单片机读写内部EEPROM详解

#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
/****************特殊功能寄存器声明****************/
_nop_();
Q0();//关闭ISP/IAP
/*
函数:写一字节
入口:addr=扇区单元地址, dat=待写入数据
此文档共包含三个程序。
第一个程序最简单易懂,看懂了基本就会读写51单片机内部EEPROMT。
第二个程序和第一个读写EEP ROM原理差不多,包含有LCD1602操作方 法,有写字符串的方法。
第三个程序在原有基础上增加了外部中断功能,细心的人会发现,操作内
部EEPROM过程会将总中断关闭,实际上程序要用到中断时只需在原有的EEP ROM操作后加上开总中断即可。
uchar V;
V =dcx(0x2002);//开机读取EEPROM区2002h数据,还原关电前LED的亮灭 状况
if(V==2){LED1=0;LED2=1;}
else if(V==6){LED1=0;LED2=0;}
while(1)
if(!K1)
while(!K1);
LED1=0;LED2=1;
sfr ISP_CMD=0xe5;
sfr ISP_TRIG=0xe6;
sfr ISP_CONTR=0xe7;
sbit LED1 = P2八0;
sbit LED2 = P 2八1;
sbit K1= P 3八2;//按钮1
学习笔记之内部eeprom读写

程序修改后重新编译下载到单片机后, 打开串口调试助手, 肯定会发现什么数据都没有, 别急, 重新按下单片机的复位键就可以看到数据了。 因为在主程序中发送数据的指令只执行 了一次, 速度很快, 在你打开串口调试助手前就已经过去了, 因此需复位一下才能看到现象。 现象如下图所示:
读回的数据分别是 00,01,02,03,04,05,06,07,08,09,发现和写入的数据是相同的,那么说 明成功的对 eeprom 进行了读写操作。 只要会了这两个最基本的读写操作,那么 Atmega16 内部的 512 字节的 eeprom 空间就 可以为你所用了。
AVR 学习笔记之内部 EEPROM 读写
AVR 单片机的多数型保存的数据。 Atmega16 内置的 EEPROM 的容量是 512 字节, 可以重复擦写的次数 是 10 万次。
AVRGCC 自带的 EEPROM 读写函数可对 Atmega16 内部的 EEPROM 进行读写操作。如果要使用 AVRGCC 中自带的 EEPROM 读写函数,首先要在程序中包含#include<avr/eeprom.h>这个头文件。 AVRGCC 内置 EEPROM 访问函数库如下: (1)void eeprom_read_block(void *buf, unsigned int addr, size_t n):从 EEPROM 的 addr 地址
} void usart_init() { UCSRA=0X00; UCSRC|=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);//写 UCSRC, 异步操作, 禁止奇偶校验, 停止位数为 1,8 位字符长度 UBRRH=(F_CPU/BAUD/16-1)/256;//波特率高 4 位 UBRRL=(F_CPU/BAUD/16-1)%256;//波特率低 8 位 UCSRB|=(1<<TXEN);//使能发送,使能接收,使能接受中断 } void usart_put_char(unsigned char TX_data)//发送一个字节的数据 { while(!(UCSRA&(1<<UDRE)));//检测 UDRE 是否为 1, 只有在 UDRE 为 1 的情况下, 才 能向缓冲器 UDR 中写入数据。 UDR=TX_data; } int main() { unsigned char i; port_init(); usart_init(); for(i=0;i<10;i++)eeprom_write_byte(i,i); while(1); } 上段程序是对 EEPROM 进行写操作,通过 for(i=0;i<10;i++)eeprom_write_byte(i,i);这段 程序实现的是在地址 0—9 分别写数据 0—9。 那么怎么知道我数据是否成功写入了呢?下面 还要进行读操作,作用是把刚才写入的数据读出来,看看是否和写入的一样,只需要修改主 程序即可。修改后的代码如下: int main() { unsigned char i; port_init(); usart_init(); for(i=0;i<10;i++) usart_put_char(eeprom_read_byte(i)); while(1); }
EEPROM可靠性

EEPROM 数据被破坏的主要原因有:1、电源异常使EEPROM的数据彻底丢失;2、复位不好和软件跑飞可能会使EEPROM的数据被改写。
要防止EEPROM数据被破坏,主要在以下几方面做工作:1、选用比MCU的电源范围宽并有WP引脚的EEPROM芯片;2、做好电源滤波,而且要等电源开机稳定后才去读写EEPROM;3、做好复位电路;4、做好软件跑飞的处理;5、SDA和SCK的上拉最好用I/O口控制,既可省电,也可在一定情况下保护EEPROM;6、WP接MCU的RESET;如WP做软件保护,将写不进数据;接I/O,上电时WP的状态可能不稳定。
7、EEPROM空间富余时考虑双备份或多备份数据,每份数据都有校验和.选用比MCU的电源范围宽并有WP引脚的EEPROM芯片的原因:1、EEPROM的芯片本身有一定的保护时序;2、电源低于MCU工作电源高于EEPROM芯片的最低工作电源时,EEPROM芯片会处于稳定状态,不会丢失数据.3、当电源较长时间低于EEPROM芯片的最低工作电压时非常容易丢失全部数据.否则MCU还能工作,但EEPROM芯片已不能工作时,EEPROM中的数据会全部丢失。
4、用I/O口线给EEPROM供电,只在读写EEPROM时才给器件供电,不仅能提高可靠性,而且能省电。
但有两点要注意:一是一些单片机复位时所有I/O都是高电平,会使EEPROM芯片进入工作;二是EEPROM芯片给电后需要有大于写周期的延时才能读写.EEPROM数据丢失的原因与对策1、环境因素★原因:高温、高湿、辐射、静电、强电磁场均可能使EEPROM存储单元造成数据丢失或数据保存时间缩短。
●对策:①不要在高温、高湿、辐射、静电、强电磁场环境中存放EEPROM器,如果法避免,应采取适当的防护措施。
②在高温环境中使用EEPROM器件,须确认存储内容的更新时间和器件使用期限③工作环境湿度较大时可考虑线路板灌胶防潮,防水胶要选用吸水率低的④在辐射、静电、强电磁场环境中工作要做好屏蔽。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
I C读写E E P R O M问题总结文件管理序列号:[K8UY-K9IO69-O6M243-OL889-F88688]2017年6月30日星期五目的:利用TMS320F2801芯片上外设I2C(2线串口)读写EEPROM数据(24LC128)关键点1:24LC时钟频率400KHz,寄存器设置如下:I2caRegs.I2CPSC.all = 9; // Prescaler - need 7-12 Mhz on module clkI2caRegs.I2CCLKL = 10; // NOTE: must be non zero I2caRegs.I2CCLKH = 5; // NOTE: must be non zero 时钟频率也可设为200KHz,三个参数分别为9、20、20(CPU时钟频率为100MHz)(未测试?)关键点2:波形分析问题:I2C模块是不是只有I2CCNT 减到0才会发出停止信号I2C模块是硬件的,当检测到发送完了就会发结束自动发信号,不需要人为干预问题1:字节写操作正常,但是字节读函数出错原因:写EEPROM是在七位器件地址后添加写标志,而读EEPROM需要在七位器件地址后添加写标志。
关键点:读EEPROM数据需要发送两次命令。
第一次为写地址(此地址会被赋值给EEPROM内的地址指针),因此需要添加写标志;第二次为读数据,将写标志改为读标志。
问题2:主机接收时,SDA数据线上有数据传输,且I2CDRR接收数据寄存器有数据更新,但寄存器显示不可读,即CPU认为一直没接收到数据,一直停在下面语句while关键点:初始化设置时采用的是FIFO接收方式,因此无效,应查询FIFO 接收中断位while方式查询位。
此位只有在非FIFO中断接收方式时才有效。
问题3:断续单字节读写正常,但是采用连续的单字节读写出错。
原因:EEPROM写过程的结束并不是I2C总线写结束就结束,实际上I2C 总线的写入数据先被保存到了EEPROM内部的缓冲区,当遇到I2C结束条件后,EEPROM才启动内部写过程,这个过程才是保存数据的过程。
非常悲哀的是这个过程比较长,官方文档标注为5ms。
如果在这5ms以内对EEPROM芯片访问将被忽略。
关键点:读写EEPROM应延时至少5ms,软件延时10msdo{}while(EEPROM_Timer <= 10); //10ms问题4:查询EEPROM写过程是否结束造成死机,只能查询EEPROM读过程。
官方文档说EEPROM内部写周期最长为5ms,在很多情况下是远远低于5ms的,为了节约时间,官方给出一个解决办法。
当写周期完毕后就开始进行应答查询,来确定EEPROM写周期何时结束。
所谓应答查询官方解释为:就是向EEPROM发送一个I2C起始条件后发送器件地址和一个读写标志位,当EEPROM完成内部写周期会回应一个ACK,这时MCU就可以进行正常的其他读写过程了。
官方原文如下:杯具就是始于我画红线的那句话,它说可以在器件地址后任意填写读写标志。
我就填了读标志,事实证明在EEPROM写入过程采用读查询将导致系统死机,I2C总线不能被正常拉高,可能是EEPROM内部已经把总线拉到了地!不管怎样,反正就是死机了。
经过多次尝试最终发现应答查询只能采用写应答查询可以正常确定EEPROM内部写周期的结束。
——by数据传输过程:从机发送数据?SDA总线?I2CRSR缓冲寄存器?I2CDRR接收数据寄存器?中间变量?内存。
问题5:CPU以字(双字节)为单位读写EEPROM数据有误;原因:CPU中的内存单元以字(word-16bit)为单位,而EEPROM中的内存单元是字节(byte-8bit)为单位,因此将CPU内存地址转化为EEPROM 指针地址时,因乘以2(左移一位)问题6:使用读数据函数式,收到的数据都是1。
原因:EEPROM初次读取未写过的内存单元时,默认为高电平,即收到的字节为0xFF。
如果已经写过内存单元,则代表数据未成功写入;写入与读数据的内存地址不一样。
问题7:写入EEPROM的数据与随后读出来的数据不一致,但读出来的数据又没有规律性。
可能原因:数据未成功写入;数据读写字节数超过EEPROM的页内字节数(跨页);读写地址不一致;读写EEPROM之间应有一定的延时时间。
解决办法:若连续读多字节数据,则读取数据之间应加延时,因为数据从I2CRSR数据接收缓冲寄存器(多字节)复制到I2CCDRR数据接收寄存器(一字节)需要时间。
单字节延时25us,双字节(字)延时50us——测试通过问题8:使用示波器观测SDA数据线上的波形时,发现每次应答信号之前都有一个毛刺(尖峰),是什么原因导致的(不影响数据的正常读写)类似问题:使用F28335模拟I2C时序读取惯导器件的数据时,发现在更改SDA的传输方向时,Gpio中数据寄存器会发生变化,导致SDA上有毛刺产生。
问题9: I2C在跟EEPROM通讯的时候,第一次写入数据,一个一个读取的话,能知道写入EEPROM的值是没有错的,但是在连续读取数据的时候,就会出现,上电第一次读取数据串的时候,是全部读取正确,然后再读取一遍数据串的时候,只有第一个读取的数据是正确的,后面的数据会全部变成FF FF 这是怎么回事办法1:大家都说STM32的IIC有点bug,所以很少人用其自带的IIC,一般都是用IO口模拟IIC,模拟很简单而且不会出错。
逻辑分析仪抓取I2C总线数据,?改为转接板抓取数据,即I2C转USB通讯。
问题10:I2C给EEPROM写数据时,两字节地址需不需要算进去吗答案:需要,且地址字节数与EEPROM的型号(容量)相关,有些为1字节地址,有些为2字节地址。
24LC128需要两字节地址来区分内存单元,其内存最小单元为1字节,地址从0x00开始,一页64字节,因此地址指针范围为:0x00~0x3F。
I2caRegs.I2CCNT = (n<<1)+2;问题11:一次读写数据字节数最好不超过16字节。
原因:其一I2C深度寄存器范围限定,其二,读写数据字节太多会导致I2C总线出错的概率加大。
ST_5bit (0x0000~0x10000)I2caRegs.I2CFFTX.bit.TXFFIL_5bitI2caRegs.I2CFFRX.bit.RXFFST_5bit(0x0000~0x10000)I2caRegs.I2CFFRX.bit.RXFFIL_5bitI2caRegs.I2CCNT_32bit问题12:总是提示总线繁忙= 1总线繁忙,BB = 0 总线空闲关键:总线繁忙这个位只读。
猜想解决办法:如果是上电第一次读写就出现总线繁忙,就对I2C模块进行复位;如果不是第一次,且I2C总线上只有一主,则等待一定时间(5ms);如果是多主,则返回,等待总线空闲吧。
问题13:CPU写数据给EEPROM时,如果设置断点,就能成功写入数据,但没有断点,数据写不成功。
什么原因呀原因:写保护WP引脚的电平应在接收到停止信号后,应保持低电平一段时间才使能写保护,即加延时语句。
———已测试通过//所有字节(地址字节+数据字节)都是添加写标志,即低电平,2n+2 <= 64////写EEPROM地址从0开始//void EEPROM_Write_call(Uint16 address,Uint16 n,Uint16 s){Uint16 i,data_temp;do{}while(EEPROM_Timer <= 20); //20ms// Check if bus busyif (I2caRegs.I2CSTR.bit.BB != 0)//总线忙位,不能手动清除{return;}if(WP != 0) WP = 0; //清除从机EEPROM写保护模式// Setup slave address-7bitI2caRegs.I2CSAR = 0x50;I2caRegs.I2CCNT = (n<<1)+2; // Setup number of bytes to send//set up write modeI2caRegs.I2CMDR.all = 0x6E20;// Send start as master transmitter//发起始信号//主机发送停止信号//TX modeif(I2caRegs.I2CSTR.bit.NACK != 0) return;//存储器首地址——2字节(14bit)while(I2caRegs.I2CSTR.bit.XRDY != 1);I2caRegs.I2CDXR = (address>>8);if(I2caRegs.I2CSTR.bit.NACK != 0) return;while(I2caRegs.I2CSTR.bit.XRDY != 1);I2caRegs.I2CDXR = (address&0x00FF);if(I2caRegs.I2CSTR.bit.NACK != 0) return;// Setup data to sendfor(i=0; i<n; i++){data_temp = MK_Data[s+i];while(I2caRegs.I2CSTR.bit.XRDY != 1);I2caRegs.I2CDXR = (data_temp&0x00FF);if(I2caRegs.I2CSTR.bit.NACK != 0) return;while(I2caRegs.I2CSTR.bit.XRDY != 1);I2caRegs.I2CDXR = data_temp >> 8;if(I2caRegs.I2CSTR.bit.NACK != 0) return; }do{}while(I2caRegs.I2CSTR.bit.SCD != 1); //是否有停止信号WP = 1; //保护EEPROM,使其只读EEPROM_Timer = 0;}问题14:波形错误——用I2C接口,SCK 和 SDA都接有4.7K的上拉电阻,用示波器抓SCK和SDA的波形,发现SCK时序正常,SDA异常,见附图(黄为SCK,紫为SDA),请问这个锯齿波形大概是什么原因造成的呢——by猜测原因:可能是I2C模块时钟频率设置不合理;——未验证IIC中断作用:IIC中断和UART中断一样,你可以立刻得到数据,而不需要总是查询。
IIC接收数据只是存到指定的寄存器中,如果你不取走,下次再接收数据就直接冲掉了,所以IIC接收到数据之后给CPU中断,去处理这些收到的数据!查找中断源是一种保险的做法,要是由于其他的哪几种原因产生了中断,但是此时数据并没有接收完,中断服务子程序去处理数据了,结果就不对了!如果你自己敢保证不会出现哪几种情况就可以完全不用写!——by//I2C (接收)interrupt void i2c_int1a_isr(void) // I2C-A{Uint16 IntSource; // Read interrupt sourceswitch(IntSource){case I2C_NO_ISRC: break; // =0case I2C_ARB_ISRC: break; // =1case I2C_NACK_ISRC:break; // =2case I2C_ARDY_ISRC:break; // =3case I2C_RX_ISRC: // =4InData[I2cIndex++] = I2caRegs.I2CDRR; break;case I2C_TX_ISRC: break; // =5case I2C_SCD_ISRC: break; // =6case I2C_AAS_ISRC: break; // =7default: //asm(" ESTOP0"); // Halt on invalid number. asm(" RPT #5 ||NOP ");} // Enable future I2C (PIE Group 8) interrupts}。