Learning Notes IV. Reading and writing EEPROM for stm32f103 hardware based on cubemx

Posted by noeledoran on Wed, 08 Dec 2021 11:02:37 +0100

cubemx-based stm32f103 hardware read-write EEPROM

An erasable memory is introduced today.
EEPROM (Electrical Erasable Programmable read only memory) is a live, erasable programmable read-only memory. It is a memory chip with no data loss after power failure. EEPROM can erase existing information and reprogram it on a computer or on a dedicated device. Usually used for Plug and Play. (Baidu Encyclopedia)
EEPROM of general single-chip computer is AT24C02
(AT24C02 is a 2K-bit serial CMOS E2PROM with 256 8-bit bytes inside. CATALYST's advanced CMOS technology substantially reduces the power consumption of the device. AT24C02 has a 16-byte page write buffer. The device operates through the IIC bus interface and has a dedicated write protection function. [Baidu Encyclopedia]


The most common way of communication for EEPROM chips is the I2C protocol. In the last article, we introduced writing OLED with software IIC. Today we use hardware IIC (because the software IIC debugging problem has not been solved, the supplementary upload has been solved).
Turn on cubemx to configure hardware IIC and configure the serial port conveniently for monitoring data.

Read and write eeprom mainly uses this function
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)
Parameter Interpretation

With a small encapsulation of this function, you can write bytes and pages. Before writing, be aware that eeprom has a write address of 0XA0 and a read address of 0XA1.

//Write-only
uint8_t At24c02_Write_Byte(uint16_t addr, uint8_t* data)
{
	return HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, addr, I2C_MEMADD_SIZE_8BIT, data, 1, 0xFFFF);
}
//read-only
uint8_t At24c02_Read_Byte(uint16_t addr, uint8_t* data,uint16_t size)
{
	return HAL_I2C_Mem_Read(&hi2c1, AT24C02_ADDR_READ, addr, I2C_MEMADD_SIZE_8BIT, data, size, 0xFFFF);
}



//The parameters are write address, write data (you can generally define an array), read address
void eeprom_onebit_rw(uint16_t write_addr, uint8_t* write_dat,uint16_t read_addr)		
{
  uint8_t recv_buf=0;//An array of read data
	if(HAL_OK == HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, write_addr, I2C_MEMADD_SIZE_8BIT, write_dat, 1, 0xFFFF))
	{
		printf("EEPROM WRITE OK\n");
	}
	else
	{
		printf("WRITE FAIL\n");
	}
	
	HAL_Delay(5);		//5 ms delay
	
	if(HAL_OK == HAL_I2C_Mem_Read(&hi2c1, AT24C02_ADDR_READ, read_addr, I2C_MEMADD_SIZE_8BIT, &recv_buf, 1, 0xFFFF))
	{
		printf("Read Ok, recv_data = %d\n ",recv_buf);
	}
	else
	{
		printf("Read Fail\n");
	}
}

Call the function directly in the main function, print the data through serial port

The delay of 5ms in the function is important, if there is no delay, data writing will fail

This is a single byte write. Writing one byte to one byte is cumbersome, so we continue encapsulating and writing page write functions.
First of all, we know that eeprom has 8 bytes per page, addresses from 0-255, referring to the wildfire's page writing method, and making changes before transplanting parameters, you can write your own and try it

uint32_t I2C_EE_PageWrite(uint8_t* pBuffer, uint8_t WriteAddr,uint8_t NumByteToWrite)
 {
	HAL_StatusTypeDef status = HAL_OK;
	/* Write EEPROM_PAGESIZE */
	status=HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_READ,WriteAddr,I2C_MEMADD_SIZE_8BIT, (uint8_t*)(pBuffer),NumByteToWrite, 100);
	while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY){
	}
	/* Check if the EEPROM is ready for a new operation */
	while (HAL_I2C_IsDeviceReady(&hi2c1, AT24C02_ADDR_WRITE,3000, 0xffff) == HAL_TIMEOUT);
	/* Wait for the end of the transfer */
	while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY) {
	}
	return status;
}
 
//void I2C_EE_WaitEepromStandbyState(void); // Is a function that waits for a response and does not expand any more  

 /**
 * @brief Write data from buffer to I2C EEPROM
 * @param
 * @arg pBuffer:Buffer Pointer
 * @arg WriteAddr:Write Address
 * @arg NumByteToWrite:Bytes Written
 * @retval nothing
 */
  #define I2C_PageSize 8
  
 void I2C_EE_BufferWrite(u8* pBuffer, u8 WriteAddr,u16 NumByteToWrite)
 {
	u8 NumOfPage=0,NumOfSingle=0,Addr =0,count=0,temp =0;
 
	/*mod Operational complement if writeAddr is I2C_PageSize integer times,
	The result of the operation has an Addr value of 0*/
	Addr = WriteAddr % I2C_PageSize;
 
	/*Difference count data values, just aligned to page addresses*/
	count = I2C_PageSize - Addr;
	
	/*Calculate how many integer pages to write*/
	NumOfPage = NumByteToWrite / I2C_PageSize;
 
	/*mod Operational remainder to calculate the number of bytes remaining less than one page*/
	NumOfSingle = NumByteToWrite % I2C_PageSize;
	
	// Addr=0, then WriteAddr just aligned aligned by page
	// It's so easy, you can write it directly, after you've written the whole page
	// Finish the remaining pages
	if (Addr == 0) {
		/* If NumByteToWrite < I2C_ PageSize */
		if (NumOfPage == 0) {
			I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
			//I2C_EE_WaitEepromStandbyState();
		//	HAL_Delay(50);
		}
		/* If NumByteToWrite > I2C_ PageSize */
		else {
			/*Write all the integer pages first*/
			while (NumOfPage--) {
				I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
			//	I2C_EE_WaitEepromStandbyState();
			//	HAL_Delay(50);
				WriteAddr += I2C_PageSize;
				pBuffer += I2C_PageSize;
			}
			/*If you have more than one page of data, write it down*/
			if (NumOfSingle!=0) {
			I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
		//	I2C_EE_WaitEepromStandbyState();
		//		HAL_Delay(50);
			}
		}
	}
	// If WriteAddr does not press I2C_PageSize Alignment
	// Then figure out how much more data is needed to align to the page address, and then
	// Finish this data first, and the remaining starting addresses are aligned
	// To the page address, just repeat the above code
	else {
		/* If NumByteToWrite < I2C_ PageSize */
		if (NumOfPage== 0) {
			/*If NumOfSingle>count, the current side cannot be written, write to the next page*/
				if (NumOfSingle > count) {
					// temp data to be written to a page
					temp = NumOfSingle - count;
					I2C_EE_PageWrite(pBuffer, WriteAddr, count);
		//			I2C_EE_WaitEepromStandbyState();
		//			HAL_Delay(50);
					WriteAddr += count;
					pBuffer += count;
					
					I2C_EE_PageWrite(pBuffer, WriteAddr, temp);
			//		I2C_EE_WaitEepromStandbyState();
			//		HAL_Delay(50);
				} 
				else { /*If count is larger than NumOfSingle*/
						I2C_EE_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
		//				I2C_EE_WaitEepromStandbyState();
		//			HAL_Delay(50);
					}
		}
		/* If NumByteToWrite > I2C_ PageSize */
		else {
			/*Do not add this operation because the addresses are not aligned and the extra count s are processed separately*/
			NumByteToWrite -= count;
			NumOfPage = NumByteToWrite / I2C_PageSize;
			NumOfSingle = NumByteToWrite % I2C_PageSize;
			
			/*Write the remaining bytes of WriteAddr's page first*/
			if (count != 0) {
				I2C_EE_PageWrite(pBuffer, WriteAddr, count);
		//		I2C_EE_WaitEepromStandbyState();
		//		HAL_Delay(50);
				/*WriteAddr With count, the address is aligned to the page*/
				WriteAddr += count;
				pBuffer += count;
			}
			/*Write all integer pages*/
			while (NumOfPage--) {
				I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
		//		I2C_EE_WaitEepromStandbyState();
		//		HAL_Delay(50);
				WriteAddr += I2C_PageSize;
				pBuffer += I2C_PageSize;
			}
			/*If you have more than one page of data, write it down*/
			if (NumOfSingle != 0) {
				I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
	//			I2C_EE_WaitEepromStandbyState();
	//			HAL_Delay(50);
			}
		}
	}
}



Visible read correct, page written successfully.

Early sleep without hair loss, I wish you all plenty of water (manual dog head)

Topics: Single-Chip Microcomputer stm32 ARM