本人正式使用I2C的经历只有一次,使用EEPROM是为了实现DSP的RAM中的变量断电后仍不会丢失的目的。这可能不是一个恰当的比喻。下面我来详细描述EEPROM的过程。

项目中使用的EEPROM的型号为AT24C256C,擦写次数约为100万次,内存约32768 字节。

项目中实际DSP需要写入的EEPROM中的字节,约100个。

项目中的系统大概类似下图:

其他设备在DSP运行时通过CAN通讯,修改DSP中的特定变量,然后DSP检测到这部分变量被修改以后,则会立即将这部分变量写入EEPROM中,下次DSP断电重启后,会在初始化中,从EEPROM中读取数据,覆盖原有RAM中特定变量的值,这样便实现了CAN修改后的变量,掉电后仍然不会丢失的功能。

本人在使用EEPROM时,实际考虑两个点:

1、EEPROM的擦写次数;

2、从EEPROM中读取数据准确性;

针对第一点,虽然EEPROM的擦写次数,其芯片手册上写的是100万次,但还是得有节制地向其中写入数据,我目前用的方法比较简单,对DSP中的变量,进行CRC计算得出CRC校验值,如果当前周期的CRC校验值与上个周期不同,则将变量写入EEPROM中,变量的CRC检验与上个周期不同,则通常情况下应该是CAN通讯修改了DSP中变量的值,当然这种做法,是否周全,还值得细细考虑,不过目前使用中还没有出现意外。还有一种做法是在修改DSP中变量时,加入一个选项,就是是否将当前的变量写入EEPROM中,这种做法更为细致,不过代码上就需要实现更多的功能,暂时没有使用这种功能。

针对第二点,我的做法是向EEPROM写入变量时,不单写入变量值,变量写完之后,还写入两个字节的CRC校验值,这CRC校验是DSP将所有变量进行CRC计算而生成的。从EEPROM中读取数据时,不单单读取变量,也将写入的CRC校验值读出,当所有数据从EEPROM中读取完毕后,DSP会重新对去所有读取的数据(除了最后两个字节)进行CRC计算,再生成新的CRC校验,这新的CRC校验会与读取的CRC校验进行对比,如果两者相同,则说明写入与读取的EEPROM数据没有问题,否则数据损坏。如果数据出现损坏怎么办?我的做法是,DSP检测到读取的数据出现损坏时,则DSP会重新从EEPROM中读取数据,但最多只会读取10次,如果10次之后,读取的结果仍是数据损坏怎么办,那我的做法是在RAM中事先写好一个备份数据,当真的出现数据损坏时,DSP会使用备份数据覆盖数据覆盖特定变量的值,这个备份数据起码能够保证系统正常运行,不会出现设备损坏,及人身安全的问题,但此时整个系统应该出现警告状态,告诉用户从EEPROM中读取数据损坏。

代码方面:

  • DSP的I2C设置;

初始化:

void InitI2c(void)
{I2caRegs.I2CSAR = 0x0050; // Slave address - EEPROM control codeI2caRegs.I2CMDR.bit.IRS = 0;I2caRegs.I2CPSC.all = 7;            // Prescaler - need 7-12 Mhz on module clk//  module clock frequency = SYSCLKOUT/(IPSC + 1)  80/8 = 10MhzI2caRegs.I2CCLKL = 10;         // NOTE: must be non zeroI2caRegs.I2CCLKH = 5;         // Tmst = Tmod *[( ICCL + d ) + ( ICCH + d )]   d = 5;I2caRegs.I2CIER.all = 0;        // Disable  interruptsI2caRegs.I2CMDR.all = 0x0020;    //   Take I2C out of resetI2caRegs.I2CMDR.bit.FREE = 1;   // runs free; that is, it continues to operate when a breakpoint occurs
// I2caRegs.I2CMDR.bit.XA = 0;      //   7 bit addressing mode
// I2caRegs.I2CMDR.bit.IRS = 1;     //The I2C module is enabled
//  I2caRegs.I2CMDR.bit.BC = 0     //8 bitI2caRegs.I2CFFTX.all = 0x6000;  // Enable FIFO mode and TXFIFO//  I2caRegs.I2CFFTX.bit.I2CFFEN  = 1;  //Enable the I2C FIFO mode.
//  I2caRegs.I2CFFTX.bit.TXFFRST  = 1; //Enable the transmit FIFO operationI2caRegs.I2CFFRX.all =  0x2040;    // Enable RXFIFO, clear RXFFINT,// I2caRegs.I2CFFRX.bit.RXFFST = 1 ; //Enable the receive FIFO operation.
// I2caRegs.I2CFFRX.bit.RXFFINTCLR = 1; // clears the RXFFINT flag}void InitI2cGpio(void)
{EALLOW;// First
//  GpioCtrlRegs.GPBPUD.bit.GPIO32 = 0;    // Enable pull-up for GPIO32 (SDAA)
//  GpioCtrlRegs.GPBPUD.bit.GPIO33 = 0;       // Enable pull-up for GPIO33 (SCLA)//    GpioCtrlRegs.GPBQSEL1.bit.GPIO32 = 3;  // Asynch input GPIO32 (SDAA)
//  GpioCtrlRegs.GPBQSEL1.bit.GPIO33 = 3;  // Asynch input GPIO33 (SCLA)// GpioCtrlRegs.GPBMUX1.bit.GPIO32 = 1;   // Configure GPIO32 for SDAA operation
//  GpioCtrlRegs.GPBMUX1.bit.GPIO33 = 1;   // Configure GPIO33 for SCLA operation//SecnodGpioCtrlRegs.GPAPUD.bit.GPIO28 = 0;GpioCtrlRegs.GPAPUD.bit.GPIO29 = 0;GpioCtrlRegs.GPAQSEL2.bit.GPIO28 = 3;GpioCtrlRegs.GPAQSEL2.bit.GPIO29 = 3;GpioCtrlRegs.GPAMUX2.bit.GPIO28 = 2;GpioCtrlRegs.GPAMUX2.bit.GPIO29 = 2;EDIS;
}

发送有停止位:

void SendI2c_WithStop(Uchar addr,Uchar *sndbuf,Uchar cnt)
{Uint16 i = 0;while(I2caRegs.I2CMDR.bit.STP == 1 || I2caRegs.I2CFFTX.bit.TXFFST != 0){DELAY_US(3);if(i >= 1000){I2caRegs.I2CMDR.all = 0;I2caRegs.I2CFFTX.bit.TXFFRST = 0;I2caRegs.I2CFFRX.bit.RXFFRST = 0;}i++;}I2caRegs.I2CMDR.bit.IRS = 1;I2caRegs.I2CFFTX.bit.TXFFRST = 1;I2caRegs.I2CFFRX.bit.RXFFRST = 1;I2caRegs.I2CSAR = addr;I2caRegs.I2CCNT = cnt;for(i = 0; i < cnt; i ++){I2caRegs.I2CDXR = sndbuf[i];}I2caRegs.I2CMDR.all = 0x6E20;   //STT STP MST TRX IRS=1 RM=0 8bit}

发送无停止位:

void SendI2c_WithNoStop(Uchar addr,Uchar *sndbuf,Uchar cnt)
{Uint16 i = 0;while(I2caRegs.I2CMDR.bit.STP == 1 || I2caRegs.I2CFFTX.bit.TXFFST != 0){DELAY_US(3);if(i >= 1000){I2caRegs.I2CMDR.all = 0;I2caRegs.I2CFFTX.bit.TXFFRST = 0;I2caRegs.I2CFFRX.bit.RXFFRST = 0;}i++;}I2caRegs.I2CMDR.bit.IRS = 1;I2caRegs.I2CFFTX.bit.TXFFRST = 1;I2caRegs.I2CFFRX.bit.RXFFRST = 1;I2caRegs.I2CSAR = addr;I2caRegs.I2CCNT = cnt;for(i = 0;i < cnt;i ++){I2caRegs.I2CDXR = sndbuf[i];}I2caRegs.I2CMDR.all = 0x6620; //STT MST TRX IRS RM=1 STP=0 8bit}

读取有停止位:

void ReadI2c_WithStop(Uchar addr,Uchar *sndbuf,Uchar cnt)
{Uint16 i = 0;while(I2caRegs.I2CMDR.bit.STP == 1 || I2caRegs.I2CFFTX.bit.TXFFST != 0){DELAY_US(3);if(i >= 1000){I2caRegs.I2CMDR.all = 0;I2caRegs.I2CFFTX.bit.TXFFRST = 0;I2caRegs.I2CFFRX.bit.RXFFRST = 0;}i++;}I2caRegs.I2CMDR.bit.IRS = 1;I2caRegs.I2CFFTX.bit.TXFFRST = 1;I2caRegs.I2CFFRX.bit.RXFFRST = 1;I2caRegs.I2CSAR = addr;I2caRegs.I2CCNT = cnt;I2caRegs.I2CMDR.all = 0x2C20; //STT STP MST IRS=1 RM TRX=0 8biti = 0;do{DELAY_US(3);if(i >= 1000){I2caRegs.I2CMDR.all = 0;I2caRegs.I2CFFTX.bit.TXFFRST = 0;I2caRegs.I2CFFRX.bit.RXFFRST = 0;return ;}i++;}while(I2caRegs.I2CSTR.bit.BB != 0);i = 0;while(I2caRegs.I2CFFRX.bit.RXFFST != 0){sndbuf[i++] = I2caRegs.I2CDRR;}}
  • AT24C256C的单个字节写、读函数;

单个字节写函数:

void WriteByte_AT24CX_Demo(Uchar data,Uint32 addr)
{Uchar Dev_Addr = 0;Uchar buff[3];Dev_Addr = AT24C256_Dev;buff[0]  = (addr >> 8) & 0x0FF;buff[1]  =  addr & 0x0FF;buff[2]  = data;SendI2c_WithStop(Dev_Addr,buff,3);}

单个字节读函数:

void ReadByte_AT24CX_Demo(Uchar *data,Uint32 addr,Uint16 cnt)
{Uchar Dev_Addr = 0;Uchar buff[5];Dev_Addr = AT24C256_Dev;buff[0]  = (addr >> 8) & 0x0FF;buff[1]  =  addr & 0x0FF;SendI2c_WithNoStop(Dev_Addr,buff,2);DELAY_US(5);ReadI2c_WithStop(Dev_Addr,data,1);}
  • CRC校验函数;

static char auchCRCHi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 };
/* CRC低位字节值表*/
static char auchCRCLo[] = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
0x43, 0x83, 0x41, 0x81, 0x80, 0x40 };Uint16 CRC16(Uchar *puchMsgg, Uint16 usDataLen)
{Uchar i;Uchar uchCRCHi = 0xFF ;               /* 高CRC字节初始化 */Uchar uchCRCLo = 0xFF ;                 /* 低CRC 字节初始化 */Uchar uIndex ;                          /* CRC循环中的索引 */for(i=0;i<usDataLen;i++){                      /* 传输消息缓冲区 */uIndex = uchCRCHi ^ (*(puchMsgg+i));         /* 计算CRC */uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex];uchCRCLo = auchCRCLo[uIndex];}return (uchCRCHi | uchCRCLo<< 8);
}
  • 项目函数;

写入函数:

每次写一个字节,每隔10个循环周期写一个字节;

void EEPROM_DataSend(void)
{EEPROM_MianLoopCnt ++;if(EEPROM_MianLoopCnt >= 10){EEPROM_SendDataHandle();if(SendData_CRC != LastSendData_CRC){SendDataNum += 99 ;}if(SendDataNum  != 0){if( DataSendCnt < 98 ){WriteByte_AT24CX_Demo( DataDic_SendBuf[DataSendCnt], SendDataAddr);SendDataAddr ++;DataSendCnt ++;}else{DataSendCnt = 0 ;SendDataAddr = DataDic[EEPROM_SendAddress];}SendDataNum--;}LastSendData_CRC = SendData_CRC;EEPROM_MianLoopCnt = 0;}}

读取函数:

void EEPROM_SystemStartingDataRead(void)
{while(1){EEPROM_DataRead();if(DataReadErrCnt > 10){EEPROM_BackupDataCoverage(); //使用备份数据此时系统应该处于警告状态,//但并不影响实际运行break;}if(ReadCla_CRC != ReadData_CRC){DataReadErrCnt ++;continue;}else{EEPROM_ReadDataCoverage();    //读取正常break;}}}

Ti的C28x系列的DSP(28069)使用经验,I2C与EEPROM(AT24C256C)相关推荐

  1. Ti的C28x系列的DSP使用经验,如何整合DSP中运行的函数。

    我从事Ti的C28x系列的DSP的开发时间不长,短短一年,使用过两种架构的DSP,主要针对资源管理有一些自己的心得. 在工程文件的分布上,本人认为需要DSP运行的的代码应该放在一个.C文件中管理,这样 ...

  2. Ti的C28x系列的DSP(28069)(28377)使用经验,ADC经验

    笔者使用过的项目中,使用的ADC都是DSP的片内ADC,使用片内ADC的好处是,转换速度快,节约成本,这是相比片外ADC的优势. DSP_28069的ADC精度是12位,DSP_28377D的ADC精 ...

  3. TI的C28x系列芯片的存储结构(1)——总括

    C28x内核为哈佛结构,程序储存和数据储存分开,使用32位数据地址和22位程序地址.这样总地址可以达到:在数据空间中存储4G个字(1个字= 16位),在程序空间中存储4M个字.C28x的程序和数据空间 ...

  4. 二、TI毫米波雷达系列——IWR6843 DSP系统内存结构

    DSP系统结构: 1)IWR6843的DSS的核心是600MHz的C674xDSP核,客户可以编程运行雷达信号处理算法.DSP本地有两级内存(L1和L2).L1(32KBL1D.32KBL1P)以60 ...

  5. TI的C28x系列芯片的存储结构(2)——CLA的RAM

    CLA有自己的程序和数据总线,它的RAM存储区分三种:程序RAM(program RAM).数据RAM(data RAM)和信号RAM(message RAM). ①program RAM CLA的程 ...

  6. [解疑][TI]TI毫米波雷达系列(一):Texas Instruments德州仪器 相关软件安装及使用时问题汇总,持续更新......

    德州仪器 (Texas Instruments),简称TI,是全球领先的半导体公司,为现实世界的信号处理提供创新的数字信号处理(DSP)及模拟器件技术.除半导体业务外,还提供包括传感与控制.教育产品和 ...

  7. 基于TI AM5728(浮点双DSP C66x +双ARM Cortex-A15)的开发板

    开发板简介 基于TI AM5728浮点双DSP C66x +双ARM Cortex-A15工业控制及高性能音视频处理器: 多核异构CPU,集成双核Cortex-A15.双核C66x浮点DSP.双核PR ...

  8. 信迈TI OMAP-L138(定点/浮点DSP C674x+ARM9) + Xilinx Spartan-6 FPGA开发板规格书

    1 评估板简介 基于TI OMAP-L138(定点/浮点 DSP C674x+ARM9)+ Xilinx Spartan-6 FPGA处理器: OMAP-L138 FPGA 通过uPP.EMIFA.I ...

  9. STC15系列单片机通过串口多字节数据读写EEPROM操作

    STC15系列单片机通过串口多字节数据读写EEPROM操作

最新文章

  1. 刘涵 美国 西北大学 计算机,西北大学关于表彰2010-2011学年度学生先进集体-红帆.doc...
  2. [architecture]-ARMV7架构下Linux Kernel的Userspace进程切换时保存和恢复哪些寄存器
  3. java new关键字
  4. 深藏不露,挖掘4种大脑网络中的管理工具
  5. 机器学习中非平衡数据处理
  6. LOAM_velodyne学习(三)
  7. 【线性代数】——投影矩阵
  8. 一楼土木人序列号查询_iPhone序列号是什么 序列号怎么查看【步骤】
  9. Source Xref 与 JavaDocs 学习理解
  10. 33 关 Python 游戏,测试你的爬虫能力到底及格不?
  11. 【考研】2020年,计算机,考研,专业课(408)大纲,排版校对版
  12. 高校固定资产折旧使用计算机,第六章固定资产_计算机会计学_ppt_大学课件预览_高等教育资讯网...
  13. 电脑爱好者 2008年第24期 12月下
  14. epc项目设计流程图_EPC工程总承包管理流程图解。
  15. 判断图同构大杀器---nauty算法
  16. ORA-00932:数据类型不一致,应为-,但却获得BLOB类型
  17. cups linux 升级_linux cups版本
  18. 念在天涯,心在咫尺【转载】
  19. DS,Enovia,MatrixOne, eMatrix
  20. tt服务器系统,TT服务器使用手册.doc

热门文章

  1. centos7安装jdk-8u191
  2. Go语言开发环境安装
  3. 全国省市县三级行政区划excel文件
  4. matlab 实现二进制与十进制相互转换
  5. matlab 将mat格式的数据另存为Excel数据(xls,xlsx)
  6. 16位增强色RGB转换为24/32位真色彩
  7. STC15单片机-通过PWM调整灯亮度
  8. 改善反激电源交叉调整率
  9. jdk1.5之后的新特性之可变参数
  10. HDU-4540 威威猫系列故事——打地鼠 (动态规划)