본문 바로가기

카테고리 없음

Arduino 외부 EEPROM 24C32BN 다루기 (RTC DS3231에 있는 거)

https://smartstore.naver.com/misoparts/products/6133256210

 

아두이노 DS3231 RTC 리얼타임 클럭 모듈 : 알파마이크로

[알파마이크로] 빠른배송 전자부품전문몰. 아두이노, 라즈베리파이, 모듈, 키트 등 전자부품 최저가 판매

smartstore.naver.com

아두이노로 시계 모듈 만들 때 사용하는 DS3231에 eeprom 32K bits 짜리가 달려 있음을 우연히 알게 되어서 테스트를 해봤다. eeprom을 별개로 사기에는 번거롭고 가격도 만만찮은데 다행이 아닐 수 없다. 칩 사진에서 왼쪽의 8핀짜리 작은 녀석.

칩에 24C32BN이라는 글자가 적혀 있다.

 

https://ww1.microchip.com/downloads/en/devicedoc/21061h.pdf

데이터시트를 보면 몇 가지 정보를 알 수 있다.

 

기본적인 정보와 코드는 아래 강좌에서 습득했다.

https://www.youtube.com/watch?v=ShqvATqXA7g

 

이렇게 일일이 코딩하는 것보다는 라이브러리를 사용하는 것이 여러 모로 편리하다.

JC_EEPROM을 테스트해보니 제법 편리하고 처리 속도도 빠른 편이다.

 

https://github.com/JChristensen/JC_EEPROM

 

GitHub - JChristensen/JC_EEPROM: Arduino library to support external I2C EEPROMs.

Arduino library to support external I2C EEPROMs. Contribute to JChristensen/JC_EEPROM development by creating an account on GitHub.

github.com

 

SparkFun에서도 관련 라이브러리를 내놓았는데 아직 테스트는 해보지 않았다.

https://github.com/sparkfun/SparkFun_External_EEPROM_Arduino_Library

 

GitHub - sparkfun/SparkFun_External_EEPROM_Arduino_Library: An Arduino library for the easy control of external I2C EEPROMs.

An Arduino library for the easy control of external I2C EEPROMs. - sparkfun/SparkFun_External_EEPROM_Arduino_Library

github.com

 

JC_EEPROM 설치는 아두이노 IDE 라이브러리 매니저에서 설치할 수 있다.

dronebot에서 소개한 코드를 실행하느라 설정되어 있는 모습인데, 케이블 4개만 연결하면 된다.

DS3231 RTC 모듈에 붙어있는 EEPROM은 32K bits로서 4K 바이트에 해당한다. 아두이노 우노와 나노는 1K의 내장 eeprom을 지원하므로 이 녀석이 우노의 4배 용량을 지원한다. 어떻게 보면, esp32, esp8266 계열에서 지원하는 기본 4M 바이트 Flash 메모리를 생각해보면 정말 작은 용량에다 사용하기 불편한 형태이지만, 우노에서 간단하게 저장장치로 사용하기에는 유용할 때도 있겠다.

 

데이터시트를 보면 페이지 사이즈는 8 bytes이고, I2C 클락 속도는 100Khz와 400Khz를 모두 지원한다. 

 

JC_EEPROM eep(JC_EEPROM::kbits_32, 1, 8, 0x57); 

 

에서 JC_EEPROM::kbits_32는 32 kbits임을, 1은 해당 버스에 eeprom이 1개 연결되어 있음을, 8은 page size이고, 0x57은 i2c_scan으로 확인한 eeprom의 I2C 주소이다.

 

  eep.begin(JC_EEPROM::twiClock400kHz);

 

JC_EEPROM::twiClock100kHz, JC_EEPROM::twiClock400kHz 둘 중 하나의 값이 올 수 있고 기본값은 100kHz이다.

// 간단한 정수, 소수, 문자열 쓰고 읽기

#include <JC_EEPROM.h>

// (the size of EEPROM device in k-bits, the number of EEPROM devices, page size in bytes, I2C address)
// in my case, eeprom is 24C32BN from RTC DS3231, so page size is 8 from the datasheet. I2C address is 0x57.
JC_EEPROM eep(JC_EEPROM::kbits_32, 1, 8, 0x57); 

void setup() {
  unsigned long addr = 0;
  // JC_EEPROM::twiClock100kHz or JC_EEPROM::twiClock400kHz. default = twiClock100kHz
  eep.begin(JC_EEPROM::twiClock400kHz);
  Serial.begin(115200);

  uint32_t a = 3227976;
  float b = 371.2393;
  char str[16];

  eep.write(addr, (uint8_t *)&a, sizeof(a));
  uint32_t a2 = 0;
  eep.read(addr, (uint8_t *)&a2, sizeof(a2));
  Serial.println(a2);

  addr += sizeof(a2);

  eep.write(addr, (uint8_t *)&b, sizeof(b));
  float b2 = 0.0;
  eep.read(addr, (uint8_t *)&b2, sizeof(b2));
  Serial.println(b2);

  addr += sizeof(b2);
  strcpy(str, "fuck you");
  eep.write(addr, (uint8_t *)str, sizeof(str));
  char str2[16];
  eep.read(addr, (uint8_t *)str, sizeof(str2));
  Serial.println(str);

  // --------- read again
  eep.read(0, (uint8_t *)&a2, sizeof(a2));
  Serial.println(a2);
 
  eep.read(0+sizeof(a2), (uint8_t *)&b2, sizeof(b2));
  Serial.println(b2);

  eep.read(0+sizeof(a2)+sizeof(b2), (uint8_t *)str, sizeof(str2));
  Serial.println(str);
}

void loop() {

}

몇 번 리셋을 시켜봐도 read write가 잘된다.

우노에서 int는 16bit이므로, 32비트 정수(가령 3227976)를 int형으로 읽으려면 오버플로가 발생할 수도 있으므로 조심해야 한다. 

uint8_t, uint16_t, uint32_t, uint64_t 처럼 형을 정확하게 지정해야 할 때가 있다.

 

라이브러리 샘플 코드 중에 구조체를 쓰고 읽는 코드가 있는데, 그것을 살짝 바꾸어서 써본다.

 

#include <JC_EEPROM.h>

typedef struct myStruct__ {
  int16_t a;
  int32_t b;
  float c;
  double d;
  uint8_t e;
  bool f;
  char g[16];
} myStruct;

JC_EEPROM eep(JC_EEPROM::kbits_32, 1, 8, 0x57); // for 24C32

void setup() {
  uint8_t i2cStat = eep.begin(JC_EEPROM::twiClock400kHz);
  if (i2cStat != 0) {
    Serial.println("I2C begin failed");
    while(1) delay(10000);
  }
  Serial.begin(115200);

  const uint32_t addr = 0x24;
  myStruct w;
  w.a = 1;
  w.b = 2;
  w.c = 12.33;
  w.d = 32.66;
  w.e = 233;
  w.f = true;
  strcpy(w.g, "my pretty");
  
  Serial.print("Writing ");
  Serial.print(sizeof(w));
  Serial.println(" bytes");

  uint8_t s = eep.write(addr, (uint8_t *)&w, sizeof(w));
  if (s != 0) {
    Serial.println("Error occured during writing!");
  }

  Serial.print("Write status ");
  Serial.println(s);
  printStruct(w);
  
  Serial.println("Reading");
  myStruct r;
  eep.read(addr, (uint8_t *)&r, sizeof(r));
  if (s != 0) {
    Serial.println("Error occured during reading!");
  }
  printStruct(r);
  Serial.println();
  Serial.println("Done.");
}

void loop() {}

void printStruct(myStruct s) {
  Serial.print(s.a);
  Serial.print(' ');
  Serial.print(s.b);
  Serial.print(' ');
  Serial.print(s.c);
  Serial.print(' ');
  Serial.print(s.d);
  Serial.print(' ');
  Serial.print(s.e);
  Serial.print(' ');
  Serial.print(s.f);
  Serial.print(' ');
  Serial.print(s.g);
  Serial.print(' ');
  Serial.println();
}