STM32CubeMX learning tutorial ten: hardware I2C read and write AT24C02

Complete source code download: https://github.com/simonliu009/STM32CubeMX-hardware-I2C-AT24C02

There is a saying that has been circulating on the Internet for a long time, that is, the I2C of STM has bugs and is not easy to use. Indeed, many people have encountered various problems in practical applications, so most of them are using software to simulate IIC.

With STM32CubeMX, we can try to use hardware I2C. There can be no mistake in the official optimization, right? (In fact, there is still a small bug, but it can be corrected). The goal of this article is to use the hardware I2C of STM32CubeMX to perform complete read and write operations on the AT24C02 EEPROM on the Kylin base.

Software version:

STM32CubeMX V4.25.0  

System Workbench V2.4

Firmware library version:
STM32Cube FW_F1 V1.6.1

Firmware library version:

STM32Cube FW_F1 V1.6.1

Hardware: OneNet Unicorn V2.3

Create a new project in STM32CubeMX and select the correct MCU model (or save the old project as well).


First set RCC and SYS, as shown below


Then set the clock according to the actual situation of the board (the external crystal oscillator of Kirin is 12M, and the highest frequency of STM32F103x is 72M), as shown below


To set I2C2, the AT24C02 of Unicorn V2.3 is connected to I2C2, the setting of I2C does not need to be changed, just use the default value.


Open the serial port USART1, and the serial port settings do not need to be modified. The default baud rate is 115200.


The pin settings are as follows:


Project - setting, ToolChain/IDE select SW4STM32, note that there can be no spaces in the project name, it is best not to use Chinese.



check here




After saving, click the Generate Code icon on the taskbar


After the generation is completed, click "Open Project" in the pop-up dialog box, System Workbench automatically opens Eclipse, imports and opens the project, and then expands the project tree,

Double-click i2c.c in the Src folder to advance the I2C clock initialization to the front of the GPIO (this is the bug we need to modify):

void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(i2cHandle->Instance==I2C2)
  {
  /* USER CODE BEGIN I2C2_MspInit 0 */
	  __HAL_RCC_I2C2_CLK_ENABLE(); //By default, this clock initialization code is placed after GPIO initialization and needs to be adjusted here, that is, before GPIO initialization
  /* USER CODE END I2C2_MspInit 0 */
  
    /**I2C2 GPIO Configuration    
    PB10     ------> I2C2_SCL
    PB11 ------> I2C2_SDA
    */
    GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init (GPIOB, & GPIO_InitStruct);

    /* I2C2 clock enable */
// __HAL_RCC_I2C2_CLK_ENABLE();//By default this clock initialization code is placed here, it needs to be commented out here
  /* USER CODE BEGIN I2C2_MspInit 1 */

  /* USER CODE END I2C2_MspInit 1 */
  }
}

Then edit main.c. First, we need to use printf to output some information and redirect it to the serial port. Referring to the previous tutorial, we make the following modifications:

Also don't forget to copy the STM32Cube_FW_F1_V1.6.0\Projects\STM3210C_EVAL\Examples\UART\UART_Printf\syscalls.c file to the src directory

/* USER CODE BEGIN PFP */

/* Private function prototypes -----------------------------------------------*/

#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
/* USER CODE END PFP */

/* USER CODE BEGIN 0 */

PUTCHAR_PROTOTYPE
{
    HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
    return ch;
}
/* USER CODE END 0 */

AT24C02 is an EEPROM with 256 Byte (ie 2Kbit). First define the device address and read and write variables

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
#define ADDR_AT24C02_Write 0xA0
#define ADDR_AT24C02_Read 0xA1
uint8_t I2C_Buffer_Write[256];
uint8_t I2C_Buffer_Read[256];
uint16_t i;
/* USER CODE END PV */

256 bytes we fill 0x00 to 0xFF in order, we use the following function to write

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), the meanings are as follows:

 I2C_HandleTypeDef *hi2c -- handle of IIC mA uint16_t  DevAddress
 -- external address of IIC device
The internal address of the IIC device
 uint16_t MemAddSize -- the way to read and write the internal address, generally use the I2C_MEMADD_SIZE_8BIT method,
                                   note that there are only two options: I2C_MEMADD_SIZE_8BIT or I2C_MEMADD_SIZE_16BIT
 uint8_t *pData -- written array or pointer
 uint16_t Size -- written bytes number!
uint32_t Timeout -- timeout

Reading the specification of AT24C02, we can see that the 2Kbit of AT24C02 is divided into 32 pages, each page is 8 bytes. And EEPROM has a way to write by page, not by byte. So our example uses the page-by-page write method, which is divided into 32 writes. Note that it needs a delay of 5ms after each write, which is the requirement of AT24C02.


So the parameters should be chosen as follows:

 I2C_HandleTypeDef *hi2c -- &hi2c2 // I2C2

 uint16_t DevAddress --ADDR_AT24C02_Write //That is 0xA0, this is the write address, the read address is the write address + 1
 uint16_t MemAddress --i //Write 8 bytes each time, so increase 8 from 0
 uint16_t MemAddSize --I2C_MEMADD_SIZE_8BIT / / The way to read and write the internal address, the screenshot of the specification above also shows that it is the 8BIT method   
 uint8_t *pData --I2C_Buffer_Write+i , because the array is a pointer, so you can also use (uint8_t*)(&(I2C_Buffer_Write[i]))
                                                        or &(I2C_Buffer_Write[i])

 uint16_t Size -- 8//Write one page at a time, as mentioned above, it is 8 bytes

uint32_t Timeout -- 1000//1000 or above, some people also use 0xFFFF.

After each page is written, the serial port prints the success message.

  /* USER CODE BEGIN 3 */
	  /* USER CODE BEGIN 2 */

	  printf("\r\n \r\n*********STM32CubeMX I2C AT24C02 Example*********\r\n");
	  printf("\r\n I2C Write Buffer:\r\n");
	  for(i=0; i<256; i++)
	  {
		  I2C_Buffer_Write[i]=i;    /* WriteBuffer Initialization */
		  printf("%02X ", I2C_Buffer_Write[i]);

	  }

	  /* write data to AT24C02 */
	  for(i=0; i<256; i=i+8)
//	  for(i=0; i<256; i++)
	  {
		  /*
		   *  
			/* The following three statements can be written correctly
			 *Write 8 bytes each time
			 */
//		  if (HAL_I2C_Mem_Write(&hi2c2, ADDR_AT24C02_Write, i, I2C_MEMADD_SIZE_8BIT,I2C_Buffer_Write+i,8, 10000) == HAL_OK)
//		  if (HAL_I2C_Mem_Write(&hi2c2, ADDR_AT24C02_Write, i, I2C_MEMADD_SIZE_8BIT,(uint8_t*)(&(I2C_Buffer_Write[i])),8, 10000) == HAL_OK)
		  if (HAL_I2C_Mem_Write(&hi2c2, ADDR_AT24C02_Write, i, I2C_MEMADD_SIZE_8BIT,&(I2C_Buffer_Write[i]),8, 1000) == HAL_OK)
		  {
			  printf("\r\n Byte %02d to Byte %02d Write OK",i,i+8);
			  HAL_Delay(5);//After writing, it needs to delay 5ms, this can not be less
		  }

		  else
			  printf("\r\n Byte %02d to Byte %02d Write Failed",i,i+8);
	  }

After writing, we read the EEPROM value and print it to the serial port. There is no page limit for reading, and we can read all 256 bytes at a time. Read using the following command:

HAL_I2C_Mem_Read(&hi2c2, ADDR_AT24C02_Read, 0, I2C_MEMADD_SIZE_8BIT,I2C_Buffer_Read,256, 1000);

	  /* read data from EEPROM */
	  printf("\r\n Reading from AT24C02:\r\n");
	  HAL_I2C_Mem_Read(&hi2c2, ADDR_AT24C02_Read, 0, I2C_MEMADD_SIZE_8BIT,I2C_Buffer_Read,256, 1000);

	  for(i=0; i<256; i++)
	  {
		  printf("0x%02X  ",I2C_Buffer_Read[i]);
	  }

It is also possible to do a direct memory comparison to see if the read and write are the same. :

	  if(memcmp(I2C_Buffer_Read,I2C_Buffer_Write,256) == 0 ) /* check data */
	      printf("\r\n AT24C02 Read Test OK\r\n");
	  else
	      printf("\r\n AT24C02 Read Test Failed\r\n");

Then right-click the project, select Properties, Run-Debug Settings, click New on the right, and select Ac6 STM32 Debugging in the pop-up dialog box.


Then click on the Run diagram on the taskbar, of course, an error will be reported. Please see another blog of mine (https://blog.csdn.net/toopoo/article/details/79680323), so you need to right-click the project name Run. cfg , rename it,


Then right-click the project name in the project tree, select "Propeties", then click "Search Project" in Run/Debug Settings-select the project name-Edit-Main-C/C++Application, and then select the default elf that appears document:


Then select the configuration file you renamed in Debugger-User Defined-Browse:


Then right-click on that new cfg file, select "Open With - Text Editor", and make the following changes:

source [find interface/stlink.cfg] 更改为 source [find interface/stlink-v2.cfg]

reset_config srst_only srst_nogate connect_assert_srst This line is changed to reset_config  none 

Then run it again and you're done.

You can see the following information from the serial port program:

*********STM32CubeMX I2C AT24C02 Example*********

 I2C Write Buffer:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
 Byte 00 to Byte 07 Write OK
 Byte 08 to Byte 15 Write OK
 Byte 16 to Byte 23 Write OK
 Byte 24 to Byte 31 Write OK
 Byte 32 to Byte 39 Write OK
 Byte 40 to Byte 47 Write OK
 Byte 48 to Byte 55 Write OK
 Byte 56 to Byte 63 Write OK
 Byte 64 to Byte 71 Write OK
 Byte 72 to Byte 79 Write OK
 Byte 80 to Byte 87 Write OK
 Byte 88 to Byte 95 Write OK
 Byte 96 to Byte 103 Write OK
 Byte 104 to Byte 111 Write OK
 Byte 112 to Byte 119 Write OK
 Byte 120 to Byte 127 Write OK
 Byte 128 to Byte 135 Write OK
 Byte 136 to Byte 143 Write OK
 Byte 144 to Byte 151 Write OK
 Byte 152 to Byte 159 Write OK
 Byte 160 to Byte 167 Write OK
 Byte 168 to Byte 175 Write OK
 Byte 176 to Byte 183 Write OK
 Byte 184 to Byte 191 Write OK
 Byte 192 to Byte 199 Write OK
 Byte 200 to Byte 207 Write OK
 Byte 208 to Byte 215 Write OK
 Byte 216 to Byte 223 Write OK
 Byte 224 to Byte 231 Write OK
 Byte 232 to Byte 239 Write OK
 Byte 240 to Byte 247 Write OK
 Byte 248 to Byte 255 Write OK
 Reading from AT24C02:
0x00  0x01  0x02  0x03  0x04  0x05  0x06  0x07  0x08  0x09  0x0A  0x0B  0x0C  0x0D  0x0E  0x0F  0x10  0x11  0x12  0x13  0x14  0x15  0x16  0x17  0x18  0x19  0x1A  0x1B  0x1C  0x1D  0x1E  0x1F  0x20  0x21  0x22  0x23  0x24  0x25  0x26  0x27  0x28  0x29  0x2A  0x2B  0x2C  0x2D  0x2E  0x2F  0x30  0x31  0x32  0x33  0x34  0x35  0x36  0x37  0x38  0x39  0x3A  0x3B  0x3C  0x3D  0x3E  0x3F  0x40  0x41  0x42  0x43  0x44  0x45  0x46  0x47  0x48  0x49  0x4A  0x4B  0x4C  0x4D  0x4E  0x4F  0x50  0x51  0x52  0x53  0x54  0x55  0x56  0x57  0x58  0x59  0x5A  0x5B  0x5C  0x5D  0x5E  0x5F  0x60  0x61  0x62  0x63  0x64  0x65  0x66  0x67  0x68  0x69  0x6A  0x6B  0x6C  0x6D  0x6E  0x6F  0x70  0x71  0x72  0x73  0x74  0x75  0x76  0x77  0x78  0x79  0x7A  0x7B  0x7C  0x7D  0x7E  0x7F  0x80  0x81  0x82  0x83  0x84  0x85  0x86  0x87  0x88  0x89  0x8A  0x8B  0x8C  0x8D  0x8E0x8F  0x90  0x91  0x92  0x93  0x94  0x95  0x96  0x97  0x98  0x99  0x9A  0x9B  0x9C  0x9D  0x9E  0x9F  0xA0  0xA1  0xA2  0xA3  0xA4  0xA5  0xA6  0xA7  0xA8  0xA9  0xAA  0xAB  0xAC  0xAD  0xAE  0xAF  0xB0  0xB1  0xB2  0xB3  0xB4  0xB5  0xB6  0xB7  0xB8  0xB9  0xBA  0xBB  0xBC  0xBD  0xBE  0xBF  0xC0  0xC1  0xC2  0xC3  0xC4  0xC5  0xC6  0xC7  0xC8  0xC9  0xCA  0xCB  0xCC  0xCD  0xCE  0xCF  0xD0  0xD1  0xD2  0xD3  0xD4  0xD5  0xD6  0xD7  0xD8  0xD9  0xDA  0xDB  0xDC  0xDD  0xDE  0xDF  0xE0  0xE1  0xE2  0xE3  0xE4  0xE5  0xE6  0xE7  0xE8  0xE9  0xEA  0xEB  0xEC  0xED  0xEE  0xEF  0xF0  0xF1  0xF2  0xF3  0xF4  0xF5  0xF6  0xF7  0xF8  0xF9  0xFA  0xFB  0xFC  0xFD  0xFE  0xFF0xAD  0xAE  0xAF  0xB0  0xB1  0xB2  0xB3  0xB4  0xB5  0xB6  0xB7  0xB8  0xB9  0xBA  0xBB  0xBC  0xBD  0xBE  0xBF  0xC0  0xC1  0xC2  0xC3  0xC4  0xC5  0xC6  0xC7  0xC8  0xC9  0xCA  0xCB  0xCC  0xCD  0xCE  0xCF  0xD0  0xD1  0xD2  0xD3  0xD4  0xD5  0xD6  0xD7  0xD8  0xD9  0xDA  0xDB  0xDC  0xDD  0xDE  0xDF  0xE0  0xE1  0xE2  0xE3  0xE4  0xE5  0xE6  0xE7  0xE8  0xE9  0xEA  0xEB  0xEC  0xED  0xEE  0xEF  0xF0  0xF1  0xF2  0xF3  0xF4  0xF5  0xF6  0xF7  0xF8  0xF9  0xFA  0xFB  0xFC  0xFD  0xFE  0xFF0xAD  0xAE  0xAF  0xB0  0xB1  0xB2  0xB3  0xB4  0xB5  0xB6  0xB7  0xB8  0xB9  0xBA  0xBB  0xBC  0xBD  0xBE  0xBF  0xC0  0xC1  0xC2  0xC3  0xC4  0xC5  0xC6  0xC7  0xC8  0xC9  0xCA  0xCB  0xCC  0xCD  0xCE  0xCF  0xD0  0xD1  0xD2  0xD3  0xD4  0xD5  0xD6  0xD7  0xD8  0xD9  0xDA  0xDB  0xDC  0xDD  0xDE  0xDF  0xE0  0xE1  0xE2  0xE3  0xE4  0xE5  0xE6  0xE7  0xE8  0xE9  0xEA  0xEB  0xEC  0xED  0xEE  0xEF  0xF0  0xF1  0xF2  0xF3  0xF4  0xF5  0xF6  0xF7  0xF8  0xF9  0xFA  0xFB  0xFC  0xFD  0xFE  0xFF0xEA  0xEB  0xEC  0xED  0xEE  0xEF  0xF0  0xF1  0xF2  0xF3  0xF4  0xF5  0xF6  0xF7  0xF8  0xF9  0xFA  0xFB  0xFC  0xFD  0xFE  0xFF0xEA  0xEB  0xEC  0xED  0xEE  0xEF  0xF0  0xF1  0xF2  0xF3  0xF4  0xF5  0xF6  0xF7  0xF8  0xF9  0xFA  0xFB  0xFC  0xFD  0xFE  0xFF  
 AT24C02 Read Test OK

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324843617&siteId=291194637