Top.Mail.Ru

Часть 13. STM32 и C++. EEPROM AT24Cxx.

В предыдущей статье мы рассмотрели реализацию I2C на ядре Cortex-M4. Теперь настало время что-нибудь подключить. Давайте подключим серию микросхем AT24Cxx. Кроме этих микросхем можно подключить кучу разных датчиков. Позже на подходе BMP280, BME280, SGP30 и HDC1080. Других у меня пока нет.

В библиотеку входит всего один конструктор и две функции. Конструктору AT24Cxx(I2C* I2C_Ptr, uint8_t DevAddress, uint8_t AT24C_Type, uint8_t MemAddSize) передаётся всего четыре параметра:

  1. I2C_Ptr - указатель на объект I2C.
  2. DevAddress - адрес микросхемы AT24Cxx. По умолчанию он равен 0х50.
  3. AT24C_Type - тип микросхемы. От AT24C02 до AT24C1024.
  4. MemAddSize - сколько бит отводится под адрес внутри микросхемы, 8 или 16. 

Четвёртый пункт ввёл для совместимости с другими типами микросхем. Некоторым микросхемам нужно передавать адрес по байтам друг за другом, сначала старший, потом младший. Другим типам то же самое, но протокол передачи чуть-чуть другой. Но проверить это утверждение пока не удалось.

Далее функция Read(). Она может читать байт, массив, структуру и любой тип переменных. Ну байт и массив понятно. А вот структуру? Я исходил из того, что ставить такую микросхему для записи пары тройки переменных смысла нет. Поэтому функции записи целых, с плавающих запятой и так далее, возможны, и в примере показано как это сделать, но большого смысла в этом нет. Придётся следить за выравниванием данных, что довольно утомительно.

Записать один байт весьма просто - Write(0x0073, 0x11). Данная команда запишет число 0х11 в ячейку с адресом 0х0073.

Массив байт - Write(0, BuffFill, 32). Команда запишет 32 байта из буфера BuffFill, начиная с адреса 0х0000.

Но вдруг вам нужно записать кучу переменных, да ещё и разных. Вот здесь лучше всего использовать структуру. До функции main() можно объявить структуру, если она должна быть глобальной или в самой функции main() если локальной.

struct sSaveType // Объявляем структуру
{
    uint32_t  Data; // Целая 32-х разрядная переменная
    uint8_t   Serial; // Целая 8-ми разрядная переменная
    float     Fl; // Переменная с плавающей запятой
};
// Инициализируем I2C
I2C myI2C(I2C2, false); // Класс I2C
// Инициализируем библиотеку AT24Cxx
AT24Cxx EEPROM(&myI2C, 0x50, AT24C64, Size_Add_16bit); // Пользуемся ранее созданным классом I2C

В функции main() присваиваем структуре имя и пишем её:

struct sSaveType SaveType; // Теперича у неё есть имя

// Инициализируем структуру и пишем её с 20-го адреса
SaveType.Data   = 123456;
SaveType.Serial = 0xAA;
SaveType.Fl     = 1246.345;
EEPROM.Write(0x20, &SaveType, sizeof(SaveType)); // Пишем структуру с адреса 0х20

// Ну и читаем её обратно
EEPROM.Read(0x20, &SaveType, sizeof(SaveType));

Все функции Read() просты до безобразия:

// Чтение байта
int16_t AT24Cxx::Read(uint16_t MemAddress)
{
  uint8_t Buff[1];
  int16_t Temp;
  Temp = _I2C_Ptr->MasterMemRead(_DevAddress, MemAddress, _MemAddSize, Buff, 1, 15);
  if(Temp != 0) return Temp; else return Buff[0];
}

// Чтение массива
int16_t AT24Cxx::Read(uint16_t MemAddress, uint8_t* DataBuff, uint16_t Size)
{
  _MemAddress = MemAddress;
  _Size       = Size;

  return _I2C_Ptr->MasterMemRead(_DevAddress, _MemAddress, _MemAddSize, DataBuff, _Size, 15);
}

// Чтение данных неопределённого формата
int16_t AT24Cxx::Read(uint16_t MemAddress, const void* DataBuff, uint16_t Size)
{
  return Read(MemAddress, (uint8_t*) DataBuff, Size);
}

Вот с записью немного сложнее. Дело в том, что запись производится постранично, и байтов в странице для разных чипов - разное количество. Поэтому в начале инициализации в зависимости от типа микросхемы производится инициализация переменных, в которых хранится эта информация:

switch (AT24C_Type)
{
  case AT24C02:
    _Pages = 32;
    _BytePerPages = 8;
    break;

  case AT24C04:
    _Pages = 32;
    _BytePerPages = 16;
    break;

  case AT24C08:
    _Pages = 64;
    _BytePerPages = 16;
    break;
}

И так далее для остальных микросхем. Далее в функции записи проверяется, с какого адреса страницы пишутся данные и превышен ли размер страницы, сначала или со случайного места, вычисляется сколько байт мы можем записать. После записи куска задержка на 10 миллисекунд, необходимые микросхеме, чтобы скинуть свой буфер. И если количество данных больше, чем на одну страницу, пишется следующая. И так до тех пор, пока все данные не будут записаны.

int16_t AT24Cxx::Write(uint16_t MemAddress, uint8_t *DataBuff, uint16_t Size)
{
  _MemAddress = MemAddress;
  _Size = Size;

  // Проверяем адрес и размер EEPROM, войдёт ли наш блок?
  if(!_CheckSpace(_MemAddress, _Size)) return 0; // Да ну. Не влезет.

  uint8_t *page = DataBuff;
  uint16_t left = _Size;
  uint16_t toWrite;

  // Начинаем запись
  while (left != 0)
  {
    // Вычисляем количество байт, записываемых в текущую страницу
    // Если адрес не выровнен относительно страницы, пишем невыравненный кусок, затем полные страницы и остаток, если будет.
    if((_MemAddress % _BytePerPages) != 0)
    {
      toWrite = (((_MemAddress / _BytePerPages) + 1) * _BytePerPages) - _MemAddress;
      if(toWrite > _Size) toWrite = _Size;
    }
    else
    {
      if(left <= _BytePerPages) toWrite = left; else toWrite = _BytePerPages;
    }

    // Производим запись одной страницы или её части
    // Запись сорвалась, возвращаем количество записанных байт.
    if(_I2C_Ptr->MasterMemWrite(_DevAddress, _MemAddress, _MemAddSize, page, toWrite, 15) != 0) return _Size - left;
    delay(11); // После записи страницы, задержка не менее 10мс, чтобы буфер сбросился.

    // Перерасчёт всех счётчиков
    left -= toWrite;
    _MemAddress += toWrite;
    page = DataBuff + toWrite;
  }

  return _Size;
}

Все функции возвращают целое число. Если оно равно "0" или в случае чтения одного байта - возвращается байт, а при записи массива возвращается количество записанных. Если число отрицательное, значит произошла ошибка.

Пример применения библиотеки в каталоге WorkDevel\Developer\Tests\MK\F407\F407_I2C_AT24xx.

Все материалы на Яндекс Диске и WorkDevel.

Тема на форуме - перейти.

Подписаться
Уведомить о
guest

0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x