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

版权声明:原创博客,不得用于商业用途 https://blog.csdn.net/weixin_39768579/article/details/82252094

   本人正式使用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<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;
		}
	}

}

猜你喜欢

转载自blog.csdn.net/weixin_39768579/article/details/82252094
I2C