[STM32] AT24C256 hardware I2C reading and writing, based on HAL library

Table of Contents

1. Brief introduction

2. Configuration project

Open CubeMX, configure clock, debugging interface, project name, directory, etc.

Configure iic

Configure the serial port to display information

3. Hardware connection

4. Code writing

1. Write a byte randomly

test code

The waveform is as follows

Code writing

2. Continuous writing

code show as below

3. Random reading

test code

The waveform is as follows

Code writing

4. Continuous reading

code show as below

5. Effect display

5. Driver Appendix

AT24C256.h

AT24C256.c


1. Brief introduction

EEPROM (Electrically Erasable Programmable read only memory) refers to electrically erasable programmable read-only memory. It is a memory chip that does not lose data after power failure. EEPROM can be erased and reprogrammed on a computer or special device. Generally used in plug and play.

The module used by the author is AT24C256, with a storage capacity of 256Kb or 32KB (32K bytes). The schematic diagram of the module is as follows

Pin name Function
A0-A1 (A2 is actually an NC foot, the principle picture is wrong) Device address input
SDA (in the schematic diagram DATA foot) Serial data
SCL Clock
WP (HOLD foot in the schematic) Write protection (high level is valid)
VCC Connect to high level (1.8-5.5V wide voltage)
GND Ground

The driver protocol is IIC. Consider enabling hardware IIC for communication. The author chose to use IIC2.

2. Configuration Project

Open CubeMX, configure clock, debugging interface, project name, directory, etc.

Configuration iic

Configure the serial port to display information

3. Hardware connection

As configured in the previous step, connect the module to the microcontroller as follows

PB10—->SCL

PB11—->SDA

VCC—->3V3

GND—->GND

4. Code Writing

1. Write a byte randomly

First send the device address or read and write instructions, then send the address to be written (occupies 2 bytes), then send the written byte, and then send the stop bit.

Since A0 and A1 are both low level, that is, 0, then the device address is 0x50(0101 0000)

This is writing, R/W is 0, after combination it is 0xA0

Test code

That is, write data “1” to the memory address of AT24C256 0. It should be noted that AT24C256 needs to wait 5~10ms to write data, and a delay must be added

The waveform is as follows

Code Writing

void AT24C256_WriteByte(uint16_t addr,uint8_t dat)
{
HAL_I2C_Mem_Write( & amp;hi2c2,AT24C256_ADDR_WRITE,addr,AT24C256_ADDR_LEN, & amp;dat,1,0xffff);
HAL_Delay(AT24C256_WAIT_TIME_UINT);
}

2. Continuous writing

Continuous writing is similar to random writing, except that if the number of writes at one time exceeds the number of bytes on a page or the address is counted to the end of a page, it will return to the beginning of the page to overwrite the number written without The page will turn automatically, this is what needs to be dealt with.

The code is as follows

/*
AT24C256 has 256K bits, that is, 32KB, 32k bytes, and the addressing space is 0~0x7FFF.
Divided into two bytes, address 1 is 0~0x7F, address AT24C256_ADDR_LEN is 0~0xFF
One page has 64 bytes and is divided into 512 pages
*/
void AT24C256_WriteMultiByte(uint16_t addr,uint8_t* dat,uint16_t n)
{
uint16_t i = 0;
    uint16_t cnt = 0; //Write byte count
uint16_t head;
uint16_t left;
uint16_t tail;
\t
if((n + addr)/AT24C256_PAGE_SIZE == addr/AT24C256_PAGE_SIZE) //If on the same page
{
HAL_I2C_Mem_Write( & amp;hi2c2, AT24C256_ADDR_WRITE, addr, AT24C256_ADDR_LEN, dat, n, 0xFFFF);
    HAL_Delay(AT24C256_WAIT_TIME_UINT*n);
}
else
{
head = (addr / AT24C256_PAGE_SIZE + 1) * AT24C256_PAGE_SIZE - addr; //The number of bytes remaining to be written in the starting page
left = n - head; //Number of bytes remaining after excluding the start page
tail=left-left/AT24C256_PAGE_SIZE*AT24C256_PAGE_SIZE; //Number of bytes to be written on the last page
HAL_I2C_Mem_Write( & amp;hi2c2, AT24C256_ADDR_WRITE,addr,AT24C256_ADDR_LEN,dat,head,0xffff);
HAL_Delay(AT24C256_WAIT_TIME_UINT*head);
for(i=0;i<left/AT24C256_PAGE_SIZE;i + + )
{
HAL_I2C_Mem_Write( & amp;hi2c2, AT24C256_ADDR_WRITE, addr + head + i*AT24C256_PAGE_SIZE,\
AT24C256_ADDR_LEN, dat + head + i*AT24C256_PAGE_SIZE,AT24C256_PAGE_SIZE, 0xFFFF);
HAL_Delay(AT24C256_WAIT_TIME_UINT*AT24C256_PAGE_SIZE);
}
HAL_I2C_Mem_Write( & amp;hi2c2, AT24C256_ADDR_WRITE,addr + head + i*AT24C256_PAGE_SIZE,AT24C256_ADDR_LEN,\
dat + head + i*AT24C256_PAGE_SIZE,tail,0xffff);
HAL_Delay(AT24C256_WAIT_TIME_UINT*tail);
}
}

3. Random reading

First send a fake write action, locate the address to the place to be read, and then send the read command. At this time, the module will clock out the data one by one

Test code

The waveform is as follows

Code writing

uint8_t AT24C256_ReadByte(uint16_t addr)
{
uint8_t p;
HAL_I2C_Mem_Read( & amp;hi2c2,AT24C256_ADDR_READ,addr,AT24C256_ADDR_LEN, & amp;p,1,0xffff);
return p;
}

Four. Continuous Reading

Since the address will automatically increase during continuous reading and writing, and the page will turn, there is no need to worry about repeated reading. As long as you do not read addresses larger than the maximum address range, there is generally no problem (after testing by the author, if you read the 0x8000 address value, the value obtained is the value at 0x0000), and there is no need to wait to read the data, which is very good

The code is as follows

/*
Continuously read bytes, the parameters are the starting reading address, the address used to store data, and the number to be read.
*/
void AT24C256_ReadMultiByte(uint16_t addr,uint8_t* dat,uint16_t n)
{
if(addr + n<0x8000)
HAL_I2C_Mem_Read( & amp;hi2c2,AT24C256_ADDR_READ,addr,AT24C256_ADDR_LEN,dat,n,0xffff);
}

5. Effect display

The main function main.cmain code is as follows

#include "main.h"
#include "i2c.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes -------------------------------------------------- ----------*/
/* USER CODE BEGIN Includes */
#include "AT24C256.h"
#include "stdio.h"
#include "stdlib.h"
/* USER CODE END Includes */

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

/* USER CODE END PTD */

/* Private define -------------------------------------------------- ---------------*/
/* USER CODE BEGIN PD */
#define TEST_BUFFER_LEN 1024
/* USER CODE END PD */

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

/* USER CODE END PM */

/* Private variables -------------------------------------------------- -----------*/

/* USER CODE BEGIN PV */
uint16_t x;
uint8_t buffer[TEST_BUFFER_LEN];
uint8_t b[TEST_BUFFER_LEN];
/* USER CODE END PV */

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

/* USER CODE END PFP */

/*Private user code--------------------------------------------- ----------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief The application entry point.
  * @retval int
  */
int main(void)
{
  /* 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();
  MX_I2C2_Init();
  MX_TIM2_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

for(x=0;x<TEST_BUFFER_LEN;x + + )
{
*(buffer + x)=x%6;
}
printf("start\r\\
");
AT24C256_WriteMultiByte(0x0,buffer,TEST_BUFFER_LEN);
printf("end\r\\
");

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
AT24C256_ReadMultiByte(0,b,TEST_BUFFER_LEN);
for(uint16_t i=0;i<TEST_BUFFER_LEN;i + + )
{
x=AT24C256_ReadByte(i);
printf("addr:%d\t-->:%d\r\\
",i,b[i]);
}
printf("\r\\
\r\\
\r\\
");
HAL_Delay(1000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

5. Driver Appendix

AT24C256.h

#ifndef AT24C256_H
#define AT24C256_H
#include "main.h"
#define AT24C256_ADDR_LEN 2
#define AT24C256_ADDR_WRITE 0xA0
#define AT24C256_ADDR_READ 0xA1
#define AT24C256_PAGE_SIZE 64
#define AT24C256_WAIT_TIME_UINT 2
#define AT24C256_MEM_LEN 0x8000
void AT24C256_WriteByte(uint16_t add,uint8_t dat);
uint8_t AT24C256_ReadByte(uint16_t add);
void AT24C256_WriteMultiByte(uint16_t add,uint8_t* dat,uint16_t n);
void AT24C256_Fill(uint8_t fill);
void AT24C256_ReadMultiByte(uint16_t addr,uint8_t* dat,uint16_t n);
#endif

AT24C256.c

#include "i2c.h"
#include "AT24C256.h"
#include "string.h"
uint8_t erase[512];

void AT24C256_WriteByte(uint16_t addr,uint8_t dat)
{
HAL_I2C_Mem_Write( & amp;hi2c2,AT24C256_ADDR_WRITE,addr,AT24C256_ADDR_LEN, & amp;dat,1,0xffff);
HAL_Delay(AT24C256_WAIT_TIME_UINT);
}
/*
AT24C256 has 256K bits, that is, 32KB, 32k bytes, and the addressing space is 0~0x7FFF.
Divided into two bytes, address 1 is 0~0x7F, address 2 is 0~0xFF
One page has 64 bytes and is divided into 512 pages
*/
void AT24C256_WriteMultiByte(uint16_t addr,uint8_t* dat,uint16_t n)
{
uint16_t i = 0;
    uint16_t cnt = 0; //Write byte count
uint16_t head;
uint16_t left;
uint16_t tail;
\t
if((n + addr)/AT24C256_PAGE_SIZE == addr/AT24C256_PAGE_SIZE) //If on the same page
{
HAL_I2C_Mem_Write( & amp;hi2c2, AT24C256_ADDR_WRITE, addr, AT24C256_ADDR_LEN, dat, n, 0xFFFF);
    HAL_Delay(AT24C256_WAIT_TIME_UINT*n);
}
else
{
head = (addr / AT24C256_PAGE_SIZE + 1) * AT24C256_PAGE_SIZE - addr; //The number of bytes remaining to be written in the starting page
left = n - head; //Number of bytes remaining after excluding the start page
tail=left-left/AT24C256_PAGE_SIZE*AT24C256_PAGE_SIZE; //Number of bytes to be written on the last page
HAL_I2C_Mem_Write( & amp;hi2c2, AT24C256_ADDR_WRITE,addr,AT24C256_ADDR_LEN,dat,head,0xffff);
HAL_Delay(AT24C256_WAIT_TIME_UINT*head);
for(i=0;i