неділя, 20 травня 2018 р.

STM32: Бібліотека для роботи з EEPROM типу AT24XXX по шині I2C

update 01.06.2018: шановний ReAl з форуму replace допоміг зі створенням вже оновленої версії цієї бібліотеки. Обговорення тут. Йому велика дяка, всім іншим - користуйтесь на здоров'я.

Передмова

В проектах, які вже "виросли" за межі просто поблимати світлодіодами, іноді виникає потреба десь зберігати дані в енергонезалежній пам'яті. Це можуть бути як і дані налаштувань, так і дані телеметрії, тощо. Варіантів безліч. Звісно, можна замість зовнішньої EEPROM використати внутрішню FLASH пам'ять самого мікроконтролеру і там зберігати якісь дані. Але ця стаття саме про зовнішню енергонезалежну EEPROM типу AT24Cxx, як її під'єднати до мікроконтролеру, як записати і як прочитати дані.

Схема підключення

Мікросхеми типу AT24Cxx працюють по шині I2C і підключаються до мікроконтролеру як і будь-який інший пристрій з шиною I2C:
Схема підключення EEPROM до мікроконтролера
Схема типова для всіх мікросхем цієї серії. В схемі що на малюнку EEPROM має адресу 0x50 (A0, A1, A2 - GND), та є дозвіл на запис (HOLD - GND). Не забуваймо про підтяжку до плюс живлення (логічної 1) ліній SDA і SCL шини I2C.

Корисно ознайомитись з документацією на свій чип EEPROM в мене це AT24C512. А також по цій темі є дуже хороша стаття: "Робота з EEPROM пам'яттю 24CXX -- огляд". Зі схемами і подробицями роботи I2C. 

Бібліотека AT24Cxx

Бібліотеку взяв у Ben Brown допис STM32 I2C EEPROM with HAL. Переробив на мову C замість C++, додав одну функцію для визначення чи під'єднаний чип EEPROM, чи ні.
Бібліотека має два файли:
У файлі AT24Cxx.h під'єднуємо бібліотеку HAL для свого чипу, прописуємо порт I2C до якого під'єднаний EEPROM, адресу EEPROM на шині I2C та розмір сторінки пам'яті EEPROM.
Наприклад, EEPROM AT24C512 (512 сторінок по 128 байт з розрядністю 16 біт) під'єднаний до STM32F103C8T6 до першого I2C1 з адресою 0x50 (A0, A1, A2 - GND), то значення пишемо такі:
#include "stm32f1xx_hal.h"
#define EEPROM_I2C  hi2c1
#define EEPROM_ADDRESS  0x50
#define EEPROM_PAGESIZE 128

Бібліотека має всього три функції:
HAL_StatusTypeDef AT24Cxx_IsConnected(void);
HAL_StatusTypeDef AT24Cxx_ReadEEPROM(unsigned address, const void* src, unsigned len);
HAL_StatusTypeDef AT24Cxx_WriteEEPROM(unsigned address, const void* src, unsigned len);

Перша, це просто перевірка чи є відгук за адресою EEPROM на шині I2C, чи немає. Повертає успіх чи невдачу з переліку HAL_StatusTypeDef.


Друга, читання з EEPROM в RAM мікроконтролера. Приймає початкову адресу в межах адресного простору вашого чипу EEPROM звідки прочитуються збережені дані, вказівник на змінну куди прочитуються дані, розмір даних які читаються з EEPROM. Повертає успіх чи невдачу з переліку HAL_StatusTypeDef.

Третя, запис до EEPROM. Приймає початкову адресу в межах адресного простору вашого чипу EEPROM куди будуть зберігатись дані, вказівник на дані які потрібно зберегти, розмір даних для збереження. Повертає успіх чи невдачу з переліку HAL_StatusTypeDef.

Приклад роботи

Для відладки і виводу різної інформації дуже зручно використовувати порт UART мікроконтролеру який під'єднано до ПК через UART2USB перехідник. Скористаємось такою нагодою і в CubeMX крім шини I2C1 увімкнемо порт UART1. Та приєднаємо бібліотеку UART до проекту.

CubeMX

Запускаємо CubeMX, створюємо новий проект, обираємо свій мікроконтролер, та вмикаємо потрібну периферію:
Налаштування в CubeMX
Робимо як на світлині позначено червоним:
  1. Вмикаємо шину I2C1
  2. Вмикаємо тактування від зовнішнього кварцового резонатору
  3. Вмикаємо налагодження по SerialWire
  4. Вмикаємо порт UART1
Налаштування всі за замовчуванням нічого не міняв. Зберігаємо проект, генеруємо код.

Демо-код

Відкриваємо чи експортуємо проект в своєму засобі розробки. Копіюємо в теку inc проекту файл AT24Cxx.h, а в теку src проекту копіюємо файл AT24Cxx.c. І в визначені CubeMX для користувача ділянки - додаємо такий код:

Під'єднуємо бібліотеки до проекту.
/* USER CODE BEGIN Includes */
#include "AT24Cxx.h"
#include "uart.h"
/* USER CODE END Includes */

Оголосимо структуру для прикладу:
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
typedef struct{
 int intVar;
 char str[256];
 uint8_t flag;
 uint16_t save;
}ExampleTypeDef;
/* USER CODE END PV */

Та зміну цієї структури:
/* USER CODE BEGIN 0 */
ExampleTypeDef example;
/* USER CODE END 0 */

І сам демо-код.
 /* USER CODE BEGIN 2 */

  UART_SendStr("UART is OK!\n\r");

  if(AT24Cxx_IsConnected() == HAL_OK)
  {
   UART_SendStr("EEPROM is OK!\n\r");
   UART_SendStr("Size data = ");
   UART_SendInt(sizeof(example));
   UART_SendStr("\n\r");

   if(AT24Cxx_ReadEEPROM(396, &example, sizeof(example)) == HAL_OK)
   {
    UART_SendStr("EEPROM read is OK!\n\r");

    if(example.save != 0xABCD)
    {
     example.flag = 1;
       example.intVar = 12345678;
       example.save = 0xABCD;
       strcpy(example.str, "Testing for save any data structure. Thank you, ReAl!!! The link http://replace.org.ua/topic/9430/");

       if(AT24Cxx_WriteEEPROM(396, &example, sizeof(example)) == HAL_OK)
     {
      UART_SendStr("EEPROM save is OK!\n\r");
     }
     else
     {
      UART_SendStr("EEPROM save is failed!\n\r");
     }
    }

    UART_SendInt(example.intVar);
    UART_SendStr("\n\r");
    UART_SendStr("0x");
    UART_SendHex16(example.save);
    UART_SendStr("\n\r");
    UART_SendStr(example.str);
    UART_SendStr("\n\r");
   }
   else
   {
    UART_SendStr("EEPROM read is failed!\n\r");
   }
  }
  else
  {
   UART_SendStr("EEPROM is not connected!\n\r");
  }
  /* USER CODE END 2 */
Тут в зміну example читаємо дані з EEPROM і якщо ще не було запису до EEPROM, то записуємо певну інформацію. Компілюємо, заливаємо до мікроконтролеру і в терміналі ПК спостерігаємо запис/читання даних.
Тепер можна зняти живлення з мікроконтролеру і знову подати його. В термінал надрукуються ті самі дані, що були збережені до EEPROM першого разу.

Архів з бібліотекою

Завантажити архів з бібліотекою AT24Cxx.rar
Або завантажити з GitHub

2 коментарі:

  1. можно вопрос а где стартовый бит? где стоповый?

    ВідповістиВидалити
    Відповіді
    1. Не зрозумів питання про старт/стоп біт? Більш розгорнуто будь ласка поставте питання.

      Видалити