Внутри Ардуины есть EEPROM, конечно же. Много места не надо, чтобы хранить пяток длинных целых, но есть нюанс. EEPROM имеет слишком ограниченный ресурс на запись. Хотелось бы писать данные раз в несколько секунд хотя бы. Ресурс же EEPROM позволяет это делать вполне обозримое время, то есть, встроенная память явно не вечна.
Сначала я хотел обмануть судьбу записывая структурку данных в разные места 1К памяти чипа по кругу. Упёрся в то, что указатель надо где-то хранить тоже, а данные достаточно случайные, чтобы использовать какой-то маркер для последовательного поиска.
Коллеги из НТЦ Метротек подсказали поискать FRAM. Это ферритовая память с бешеным быстродействием и 1014 циклами записи.
Услужливый Aliexpress привёз мне вот такой модуль. Память дорогая весьма, кстати. В микросхеме 8К, то есть, больше, чем у Atmega32 в 4 раза. :)
Погуглив на тему готового чего-то для этого чипа я не нашёл ничего. Отличная кошка, решил я, буду на ней тренироваться! Открыл доку по Wire, даташит по FM24, чей-то проект EEPROM/I2C с похожим интерфейсом и набросал класс для FRAM.
Проект на гитхабе: http://ift.tt/2idpX1e
Пример прилагается вот такой.
#include "FM24I2C.h"
// Объект для платы. Адрес в i2c.
FM24I2C fm(0x57);
void setup() {
Wire.begin();
Serial.begin(9600);
char str1[]="12345678901234567890";
char str2[]="qwertyuiopasdfghjklzxcvbnm";
int a1=0x00; // Первый в FRAM
int a2=0x40; // Второй адрес в FRAM
fm.pack(a1,str1,strlen(str1)+1); // Пишем в память
delay(5);
fm.pack(a2,str2,strlen(str2)+1); // Пишем вторую строку
delay(5);
char buf[80];
fm.unpack(a2,buf,strlen(str2)+1); // Читаем вторую
Serial.println(str2);
fm.unpack(a1,buf,strlen(str1)+1); // Читаем первую
Serial.println(str1);
}
Протокол i2c для FRAM сильно проще, чем для EEPROM. Память работает быстрее передачи данных по шине и можно лить хоть все 2К ардуининых мозгов за один раз. Польза от моего кода хоть в том, что нет лишнего разбиения на блоки по 32 байта или вообще побайтной передачи.
class FM24I2C {
private:
int id;
public:
FM24I2C(int id_addr);
~FM24I2C();
void pack(int addr, void* data, int len); // Упаковать данные в FRAM
int unpack(int addr, void* data, int len); // Распаковать из FRAM. Возвращает количество переданных байтов.
// Это уже специально для меня, пишет беззнаковые длинные целые.
void inline writeUnsignedLong(int addr, unsigned long data) {
pack(addr, (void*)&data, sizeof(unsigned long));
}
// И читает.
unsigned long inline readUnsignedLong(int addr) {
unsigned long data;
return unpack(addr, (void*)&data, sizeof(unsigned long)) == sizeof(unsigned long) ? data : 0UL;
}
// Можно для других типов сделать чтение/запись, но мне было не нужно, а флеш занимает.
// Каждый же может унаследовать класс и дописать сам.
};
Кода же немножко совсем.
void FM24I2C::pack(int addr, void* data, int len) {
Wire.beginTransmission(id);
Wire.write((byte*)&addr,2);
Wire.write((byte*)data,len); // Наверное, стоит всё же unsigned int использовать :)
Wire.endTransmission(true);
}
int FM24I2C::unpack(int addr, void* data, int len) {
int rc;
byte *p;
Wire.beginTransmission(id);
Wire.write((byte*)&addr,2);
Wire.endTransmission(false);
Wire.requestFrom(id,len);
// Здесь можно поспорить про замену rc на p-data :)
for (rc=0, p=(byte*)data; Wire.available() && rc < len; rc++, p++) {
*p=Wire.read();
}
return(rc);
}
Так как на модуле, кроме чипа и разъёмов, практически ничего нет, уже хочу купить несколько микросхем. Нравятся.
Комментарии (0)