EEPROM 제어 및 시스템 정보 저장하기

이번 포스트에서는 EEPROM을 이용해 특정 정보를 읽고 쓰는 방법을 다룹니다. 임베디드 시스템 개발에서 EEPROM은 단순한 데이터 저장소 이상의 역할을 합니다. 전원이 꺼져도 유지되어야 하는 설정 값이나, 부팅 시 불러와야 하는 시스템 초기화 데이터 등을 저장하는 핵심 메모리로 활용되기 때문입니다.


왜 EEPROM이 필요한가?

EEPROM은 비휘발성 메모리로서, 다음과 같은 필요성을 충족합니다.

  • 장치의 전원이 꺼져도 유지되어야 하는 설정 정보 저장
  • 재부팅 시 EEPROM에 기록된 데이터를 읽어 자동 초기화 수행
  • 네트워크 장비의 경우, 펌웨어 업데이트 과정이나 장치 식별을 위한 버전 정보 및 MAC 주소 등의 유지

즉, EEPROM은 단순한 데이터 저장 공간이 아니라 장치의 일관성과 신뢰성을 유지하는 기반이라고 할 수 있습니다.


EEPROM 제어 방식

EEPROM은 일반적으로 I2C 또는 SPI 통신을 통해 접근합니다.

  • 소용량 EEPROM → I2C 사용
  • 대용량 Serial Flash → SPI 사용

본 튜토리얼에서 사용하는 TW100PC 모듈에는 4KB 용량의 AT24C32 EEPROM이 탑재되어 있으며, I2C 방식으로 제어합니다.
따라서 이번 글에서는 twlabcpp 라이브러리에서 제공하는 BaseI2C 클래스를 기반으로 동작을 설명합니다.


EEPROM 데이터 구조 (필드 정의)

TW100PC는 이더넷 장치이므로, EEPROM 내부에는 표준 구조에 따라 다양한 정보가 정의되어 있습니다.

  • 버전 정보
  • 네트워크 관련 설정 (예: IP, MAC 주소)
  • 펌웨어 업데이트용 메타데이터

이러한 필드 구조는 필요에 따라 확장하거나 수정할 수 있습니다.


코드 구성 요소

EEPROM 제어를 위해 프로젝트는 크게 3가지 클래스로 나누어집니다.

  1. EEPDefinition(.cpp, .h)
    • EEPROM 필드 이름 및 크기 정의
  2. AT24CTask(.cpp, .h)
    • AT24Cxx 계열 EEPROM을 제어하는 I2C 드라이버 클래스
  3. SystemInfo(.cpp, .h)
    • EEPROM에서 읽어온 데이터를 저장 및 관리

본 튜토리얼에서는 각 클래스의 내부 구현보다는, 객체 생성 및 활용 예제에 초점을 맞춥니다.


코드 구현 예제

1. 관련 헤더 파일 및 객체 선언

#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <ConsoleTask.h>
#include <BasicFunctions.h>
#include <RUNLEDTask.h>

#include <EEPDefinition.h>
#include <SystemInfo.h>
#include <AT24CTask.h>

#include <ProductCode.h>
...
ConsoleTask CTask;
__attribute__ ((section(".ccmram"))) volatile uint8_t consoleBuf[2048];

BasicFunctions basic;
RUNLEDTask runledTask;

EEPDefinition EEP;
SystemInfo SysInfo;
AT24CTask At24cTask;

2. 객체 초기화 함수 정의

...
void InitEepromLocationStruct(void);
void InitSystemInfo(void);
void InitAt24cTask(void);
...
/*
 *
 */
void InitEepromLocationStruct(void)
{
	EEP = EEPDefinition(&CTask);

	EEP.PrintPositionAndLength();
}

/*
 *
 */
void InitSystemInfo(void)
{
	CTask.PRINTF((char *)"InitSystemInfo starts\r\n");
	CTask.flushTxBuf();
	SysInfo = SystemInfo(&CTask);
	SysInfo.setEEPPtr(&EEP);
	SysInfo.setInitialization();
	CTask.PRINTF((char *)"InitSystemInfo finished\r\n");
	CTask.flushTxBuf();
}

/*
 *
 */
void InitAt24cTask(void)
{
	At24cTask = AT24CTask(&hi2c3, &CTask, &SysInfo);
	At24cTask.setEEPDefinitionPtr(&EEP);

	if(At24cTask.checkEEPROM())
	{
		At24cTask.LoadSystemInfoFromEEPROM();

		if(memcmp(SysInfo.getMacAddr(), TWARELABMAC, 3) != 0)
		{
			CTask.PRINTF((char *)"First Run. Doing Factory Reset\r\n");
			SysInfo.setMacAddr(DeviceMac);
			At24cTask.saveMacAddrToEEPROM();
			SysInfo.setFactoryReset();
			bConfigChanged = True;
		}

		if((memcmp(SysInfo.getProductCode(), ProductCode, 2) != 0) || (memcmp(SysInfo.getVersion(), FWVer, 3) != 0))
		{
			CTask.PRINTF((char *)"Product Code is invalid\r\n");
			SysInfo.setProductCode(ProductCode);
			SysInfo.setVersion(FWVer);
			SysInfo.setNTPDomain(NullString);
			bConfigChanged = True;
		}

		if(SysInfo.General.NTPDomain[0] == 0xFF)
		{
			SysInfo.setNTPDomain(NullString);
			bConfigChanged = True;
		}

		if(SysInfo.getChannelNum() != 1)
		{
			SysInfo.setChannelNum(1);
			bConfigChanged = True;
		}

		CTask.flushTxBuf();

		if(bConfigChanged)
		{
			At24cTask.SaveSystemInfoToEEPROM();
			CTask.flushTxBuf();
			At24cTask.LoadSystemInfoFromEEPROM();
		}

	}
}

3. main.c에서 초기화 호출

...
  InitEepromLocationStruct();
  InitSystemInfo();
  InitAt24cTask();
...

트러블슈팅

EEPROM을 실제로 사용하다 보면 몇 가지 흔한 문제가 발생할 수 있습니다.

  1. 데이터가 저장되지 않음
    • 원인: Write 사이클 완료 전 I2C 버스를 다시 접근
    • 해결: Write 후 tWR(Write Cycle Time) 만큼 대기 필요
  2. 읽은 값이 예상과 다름
    • 원인: EEPROM 주소 계산 오류
    • 해결: 멀티바이트 주소 지원 여부 확인 (AT24C32는 2바이트 주소 사용)
  3. 부팅 시 데이터 초기화 실패
    • 원인: EEPROM이 준비되기 전에 읽기 시도
    • 해결: 전원 인가 후 안정화 시간을 보장

확장 활용 예시

EEPROM은 네트워크 설정 저장 외에도 다양한 용도로 활용 가능합니다.

  • 사용자 환경 설정 저장
    (예: 밝기, 볼륨, 모드 설정 값)
  • 로그 데이터 기록
    (간단한 이벤트 히스토리 저장)
  • 펌웨어 다중 이미지 관리
    (OTA 업데이트 시 활성 이미지 선택 플래그 저장)

정리

이번 단계에서는 EEPROM을 활용해 시스템 정보를 저장하고 불러오는 기본 구조를 소개했습니다.
핵심 포인트는 다음과 같습니다.

  • EEPROM은 전원 차단 후에도 유지되는 데이터를 저장하는 핵심 장치
  • TW100PC 모듈은 AT24C32 EEPROM을 사용하며 I2C로 제어
  • EEPROM 필드 정의를 통해 다양한 시스템 정보를 구조적으로 관리 가능
  • AT24CTask, SystemInfo 클래스와 같은 계층적 구조를 활용하면 코드 유지보수성이 높아짐
  • 트러블슈팅과 확장 활용법을 통해 실제 프로젝트에 쉽게 적용 가능

다음 포스트에서는 이 구조를 기반으로 Ethernet 통신을 위한 W5500 설정 및 네트워크 기능 사용에 대한 예제를 다룰 예정입니다.


0개의 댓글

답글 남기기

Avatar placeholder

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

ko_KRKorean