ST/STM32F103C8

STM32F103C8 - I2C(EEPROM)

engineer4ever 2025. 8. 8. 10:27

 

MCU
STM32F103(ST)
IDE
Atollic(TrueSTUDIO), STM32CubeMX
목표
HAL driver를 사용하여 I2C EEPROM 쓰고 읽기

 

1. STM32F103C8 - I2C EEPROM 회로도

- SDA, SCL pull-up 저항 값은 아래와 같이 설정되므로 적당히 아무거나(10k) 붙이면 통신이 안될수도 있음(NXP, UM10204 참고)

 

2. STM32CubeMX : I2C 설정

- 'Pinout & Configuration' Tab으로 이동

1) I2C1 선택

2) I2C : I2C 선택

3) I2C Clock Speed는 기본 100kHz로 설정된다. 사용하려는 device가 이 속도를 지원하는지 확인 할것

- PB7(I2C1_SDA), PB6(I2C1_SCL) 자동 할당(녹색 표시)

- GENERATE CODE 클릭


3. ATOLLIC : main.c 수정

- main() : 변수 선언

int main(void)
{
  /* USER CODE BEGIN 1 */
	HAL_StatusTypeDef status = HAL_ERROR;

	int i = 0;

	uint16_t FM24V02_addr = 0xA0;

	uint8_t tx_buffer[65] = {};
	uint8_t rx_buffer[65] = {};

  /* USER CODE END 1 */
 

- Address는 A2, A1, A0를 GND('0')에 연결하여 '0b1010000'이다.

- HAL_I2C_Mem_Write(), Read() 사용하려면 7bit address를 <<1 shift 하라고 되어있으므로 최종 주소는 '0xA0' (HAL_I2C_Mem_Write() 설명은 ATOLLIC에서 함수 이름에 마우스 커서를 올려놓거나, 키보드 F3을 누르거나 또는 HAL lib manual에서 확인 가능)

 

- main() : 실행 코드 작성

  /* USER CODE BEGIN 2 */
	tx_buffer[0] = 0x12;

	// Byte Write
	status = HAL_I2C_Mem_Write(&hi2c1, FM24V02_addr, 0x0001, 2, tx_buffer, 1, 1000);
	if(status != HAL_OK)
	{
		printf("I2C Byte Write error\n");
	}

	// Byte Read
	status = HAL_I2C_Mem_Read(&hi2c1, FM24V02_addr, 0x0001, 2, rx_buffer, 1, 1000);
	if(status == HAL_OK)
	{
		printf("Byte Read : %d\n", rx_buffer[0]);
	}
	else
	{
		printf("I2C Byte Read error\n");
	}

	// Page Write
	for (i = 0; i < 64; i++)
	{
		tx_buffer[i] = i;
	}
	status = HAL_I2C_Mem_Write(&hi2c1, FM24V02_addr, 0x0100, 2, tx_buffer, 64, 1000);
	if(status != HAL_OK)
	{
		printf("I2C Page Write error\n");
	}

	// Page Read
	status = HAL_I2C_Mem_Read(&hi2c1, FM24V02_addr, 0x0100, 2, rx_buffer, 64, 1000);
	if(status == HAL_OK)
	{
		for (i = 0; i < 64; i++)
		{
			printf("Page Read(%d) : %d\n", i, rx_buffer[i]);
		}
	}
	else
	{
		printf("I2C Page Read error\n");
	}

  /* USER CODE END 2 */
 

- 실행 결과

- 실행 결과 이하 생략

 

- 참고 : 일부러 Address를 틀리게 썼을때 실행 결과


4. 8bit 데이터는 위와 같이 하면 문제 없이 동작하나, 16bit 데이터(256이상)를 쓰고 읽어오려면 약간 다른 방법으로 해야 한다.

- write() : 16bit 데이터를 8bit로 쪼개서 쓰기

- read() : 8bit씩 읽어서 16bit로 합침

uint16_t FM24V02_addr = 0xA0;
uint8_t reg_addr = 0x0001;

uint8_t data_8bit = 0;
uint16_t data_16bit[65] = {};

void eeprom_i2c_write(uint16_t size)
{
	HAL_StatusTypeDef status = HAL_ERROR;
	reg_addr = 0x0001;

	for(int i = 0; i< size; i++)
    {
		data_8bit = (uint8_t)(data_16bit[i] >> 8);
		status = HAL_I2C_Mem_Write(&hi2c1, FM24V02_addr, reg_addr+(i*2), 2, &data_8bit, 1, 1000);
		HAL_Delay(10);

		data_8bit = (uint8_t)(data_16bit[i] & 0xff);
		status = HAL_I2C_Mem_Write(&hi2c1, FM24V02_addr, reg_addr+(i*2)+1, 2, &data_8bit, 1, 1000);

		if(status != HAL_OK)
		{
		    printf("EEPROM Byte Write error : %d\n", status);
		}
    }
}

void eeprom_i2c_read(uint16_t size)
{
	HAL_StatusTypeDef status = HAL_ERROR;
	reg_addr = 0x0001;

    for(int i = 0; i< size; i++)
    {
    	status = HAL_I2C_Mem_Read(&hi2c1, FM24V02_addr, reg_addr+(i*2), 2, &data_8bit , 1, 1000);
    	data_16bit[i] = data_8bit << 8;
        HAL_Delay(10);

        status = HAL_I2C_Mem_Read(&hi2c1, FM24V02_addr, reg_addr+(i*2)+1, 2, &data_8bit , 1, 1000);
        data_16bit[i] += data_8bit;

		if(status == HAL_OK)
		{
			printf("EEPROM Page Read(%d) : %d\n", i, data_16bit[i]);
		}
		else
		{
			printf("EEPROM Byte Read error\n");
		}
    }
}
 

'ST > STM32F103C8' 카테고리의 다른 글

STM32F103C8 - I2C HAL driver 오류  (0) 2025.08.08
STM32F103C8 - ADC(DMA interrupt)  (1) 2025.08.08
STM32F103C8 - RTC(Systick handler)  (0) 2025.08.08
STM32F103C8 - PWM  (0) 2025.08.08
STM32F103C8 - TIMER  (1) 2025.08.08