Skip to main content
Senior III
June 10, 2026
Solved

EEPROM Read and Write Function Definition

  • June 10, 2026
  • 7 replies
  • 146 views

I am trying to interface the EEPROM AT24C04C with STM32G4 series controllers. I have confusion in the function parameters

HAL_StatusTypeDef HAL_I2C_Mem_Read_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress,
uint16_t MemAddSize, uint8_t *pData, uint16_t Size)

Can you please clarify on the MemAddSize parameter what has to be sent to for the above EEPROM?

2nd Question: 1 page is 16 bytes, is it possible for me to write data above 16 bytes as well?

 

Best answer by Pavel A.

> Can you please clarify on the MemAddSize parameter

Per the  AT24C04C data sheet, the address part of  the I2C transaction is always one byte (8 bit) - which covers 256 bytes. Extra address bit is encoded in the I2C device address. In other words,  AT24C04C occupies two I2C addresses, each holds 256 data bytes. For example, 0b1010000x and 0b1010001x. Bit 1 (mask 0x2) of the I2C address selects the half.

> is it possible for me to write data above 16 bytes as well?

Don’t think so. The data sheet says “up to 16 bytes”. To move more, use several transactions.

 

7 replies

Ozone
Principal
June 10, 2026

While I don’t use Cube / HAL, I think this is a generic I2C function, not specific for the 2404 EEPROM devices.
You will need to read the device datasheet (of the AT24C04C) to check what a write entails, and check the source code (of  HAL_I2C_Mem_Read_IT) were this parameter ends up.

> 2nd Question: 1 page is 16 bytes, is it possible for me to write data above 16 bytes as well?

Again, check with the datasheet. Here two quotes from the Microchip datasheet :

> Page Write: The 4K and 8K EEPROM devices are capable of a 16-byte Page Write.

> If more than 16 data words are transmitted to the EEPROM, the data word address will “roll over” and previous data will be overwritten.

Andrew Neil
Super User
June 10, 2026

​@Ozone 

I think this is a generic I2C function, not specific for the 2404 EEPROM devices

 

This is correct.

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
Ozone
Principal
June 11, 2026

Since I don’t use Cube/HAL, I start with the datasheet of the device to design my own “HAL” code.

Reading the datasheets is highly recommended in general, and simply mandatory in some cases. Even if some vendor’s salesmen want to make you believe otherwise.

Pavel A.
Pavel A.Best answer
June 10, 2026

> Can you please clarify on the MemAddSize parameter

Per the  AT24C04C data sheet, the address part of  the I2C transaction is always one byte (8 bit) - which covers 256 bytes. Extra address bit is encoded in the I2C device address. In other words,  AT24C04C occupies two I2C addresses, each holds 256 data bytes. For example, 0b1010000x and 0b1010001x. Bit 1 (mask 0x2) of the I2C address selects the half.

> is it possible for me to write data above 16 bytes as well?

Don’t think so. The data sheet says “up to 16 bytes”. To move more, use several transactions.

 

STuser2Author
Senior III
June 12, 2026

I have written the code but as of now i don’t have access to hardware which is remotely located and i need to support for testing, meanwhile i have written the code as below. Can you please review.

/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
bool writesuccess = false;
bool readsuccess = false;

/* USER CODE END 0 */

/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
static uint8_t eepdata[10]={0x0A,0x0B,0x0C};
static uint8_t eepread[10];
static bool writeflag=false;

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/* MCU Configuration--------------------------------------------------------*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();

/* USER CODE BEGIN Init */

/* USER CODE END Init */

/* Configure the system clock */
SystemClock_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
/* USER CODE BEGIN 2 */

/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
if(writeflag == false)
{
HAL_I2C_Mem_Write_IT(&hi2c1,0xA0,0x00,1,eepdata,2);
writeflag = true;
}
if(writesuccess == true && readsuccess == false)
{
HAL_I2C_Mem_Read_IT(&hi2c1,0xA0,0x00,1,eepread,2);
}

}
/* USER CODE END 3 */
}

/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST);

/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV4;
RCC_OscInitStruct.PLL.PLLN = 85;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}

/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
}

/**
* @brief I2C1 Initialization Function
* @param None
* @retval None
*/
static void MX_I2C1_Init(void)
{

/* USER CODE BEGIN I2C1_Init 0 */

/* USER CODE END I2C1_Init 0 */

/* USER CODE BEGIN I2C1_Init 1 */

/* USER CODE END I2C1_Init 1 */
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x40621236;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}

/** Configure Analogue filter
*/
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
Error_Handler();
}

/** Configure Digital filter
*/
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C1_Init 2 */

/* USER CODE END I2C1_Init 2 */

}

/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
/* USER CODE BEGIN MX_GPIO_Init_1 */

/* USER CODE END MX_GPIO_Init_1 */

/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();

/* USER CODE BEGIN MX_GPIO_Init_2 */

/* USER CODE END MX_GPIO_Init_2 */
}


/* USER CODE BEGIN 4 */
void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
writesuccess = true;

}
void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
readsuccess = true;

}
/* USER CODE END 4 */

/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

 

* @param DevAddress Target device address: The device 7 bits address value

* in datasheet must be shifted to the left before calling the interface

HAL_StatusTypeDef HAL_I2C_Mem_Write_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress,
uint16_t MemAddSize, uint8_t *pData, uint16_t Size)

So device address is as per data sheet 

 

A2 is Gnd, A1 is Gnd A8 i plan 0 lower 2K bits

so, 

1 0 1 0 0 0 0 i shift it by 1 → 1 0 1 0 0 0 0 0 → 0xA0 is device address. Is my understanding correct.

 

 

STuser2Author
Senior III
June 13, 2026

I am confused with the below website

How To Interface an I2C EEPROM With STM32

#define DevAddress 0x53
#define MemAddress 0x00
#define MemAddSize 2
#define Size 1
#define Timeout 100
uint8_t WriteData;
uint8_t ReadData;

WriteData = 0xEE;

HAL_I2C_Mem_Write(&hi2c1, DevAddress << 1, MemAddress, MemAddSize, &WriteData, Size, Timeout);
/* wait utill the write cycle finishes */
HAL_Delay(10);
HAL_I2C_Mem_Read(&hi2c1, DevAddress << 1, MemAddress, MemAddSize, &ReadData, Size, Timeout);


He is writing 0x50 instead of 0xA0, A2 is Gnd 0, A1=1, A0=1 (+5V). How did he get 0x50?

STuser2Author
Senior III
June 13, 2026

Sorry i did not check 

DevAddress << 1

it is clear now.