DSP

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

2019-07-13 10:06发布

   本人正式使用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 code I2caRegs.I2CMDR.bit.IRS = 0; I2caRegs.I2CPSC.all = 7; // Prescaler - need 7-12 Mhz on module clk // module clock frequency = SYSCLKOUT/(IPSC + 1) 80/8 = 10Mhz I2caRegs.I2CCLKL = 10; // NOTE: must be non zero I2caRegs.I2CCLKH = 5; // Tmst = Tmod *[( ICCL + d ) + ( ICCH + d )] d = 5; I2caRegs.I2CIER.all = 0; // Disable interrupts I2caRegs.I2CMDR.all = 0x0020; // Take I2C out of reset I2caRegs.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 bit I2caRegs.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 operation I2caRegs.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 //Secnod GpioCtrlRegs.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 8bit i = 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
  • 项目函数;
写入函数: 每次写一个字节,每隔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; } } }