Найти в Дзене
narod stream

ESP32 Урок 6. I2C. Подключаем внешний EEPROM

На данном уроке мы попробуем поработать с шиной I2c.

С данной шиной мы раньше также работали с применением других микроконтроллеров. Настало время поработать с ней, подключив по ней что-нибудь к контроллеру ESP32.

Данная шина у контроллера ESP32 реализована аппаратно в отличие от младшей модели ESP8266. Только аппаратная поддержка работает только в том случае, если назначить нужные ножки, во всяком случае так гласит документация.

Мы не будем уходить от сложившихся традиций и подключим, как обычно, к данной шине микросхему памяти EEPROM — AT24C32, которая установлена в модуле с часовой микросхемой DS3231 и также в часовом модуле с микросхемой DS1307.

С данной микросхемой мы также работали неоднократно с использованием различных контроллеров и различных библиотек, поэтому знакомиться с ней также нет смысла.

Выглядит модуль DS1307, с которым мы будем работать на данном уроке вот так

Подключим модуль к нашей отладочной плате, только провода для SCL и SDA возьмём с ещё одним отводом для подключения логического анализатора, чтобы потом наглядно увидеть, как будут передаваться данные по шине, а заодно и скорость их передачи. Подключим сразу и логический анализатор

-2
-3

Посмотрим распиновку нашей платы

-4

Здесь мы видим, что ножки, предназначенные для I2C, то бишь SDA и SCL у нас соответствуют ножкам портов GPIO21 и GPIO22. Так мы их и подключили.

Теперь сразу к проекту. Он был сделан из проекта прошлого урока  с именем EXTI01 и назван был I2C_EEPROM.

Как всегда, сначала конфигурирование, поэтому после добавления проекта в дерево проектов среды Espressif IDE мы первым делом откроем файл Kconfig.projbuild и внесём там следующие изменения. Мы уберём пункт для ножки светодиода, а пункты для входов исправим под требования нашего нового проекта. Я приведу весь текст данного файла

Соберём проект и посмотрим, что у нас в конфигураторе

-5

В конфигураторе всё нормально. Значит будем в проекте будем пользоваться назначенными здесь макросами.

В main.c удалим все макросы, глобальные переменные и  функции с телами, за исключением app_main, в которой оставим только бесконечный цикл

Объявим макрос, в котором будет храниться адрес микросхемы

Объявим глобальный указатель на строку для отображения логов

В функции app_main объявим целочисленную переменную, переменную для номера модуля и переменную для кода ошибки

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

at24c.h

at24c.c

Подключим наш новый модуль в файле main.c

Перейдём в файл at24c.c и добавим там функцию инициализации периферии

На входе мы здесь получаем номер модуля, адрес микросхемы и номера портов для ножек SDA и SCL.

Создадим в заголовочном файле прототип на нашу функцию и вызовем её в app_main файла main.c

Если мы сейчас соберём код, то мы получим ошибку. Дело в том, что мы видим только прототип функции, а реализацию не видим. Если мы добавляем файлы реализации в дерево проекта, это не значит, что они будут видны из кода и будут выполняться. Чтобы полностью подключить такой файл в проект, откроем файл CMakeLists.txt в каталоге main и добавим в перечень подключаемых файлов наш новый файл

set(COMPONENT_SRCS "main.c at24c.c")

При сборке теперь будет только одна ошибка — отсутствие возвращаемого аргумента в нашей новой функции i2c_master_driver_initialize.

Для начала идём в файл at24c.h и объявим там макрос для частоты шины и заодно макрос для бита  проверки отклика

Перейдём в файл at24c.c в тело функции i2c_master_driver_initialize , объявим переменную типа структуры для конфигурации модуля I2C и проинициализируем её поля

Вызовем функцию конфигурации шины, результат вернётся в переменную, и вернём результат

Вот теперь всё соберётся без ошибок.

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

Объявим глобальную переменную

Вернёмся в функцию i2c_master_driver_initialize и сохраним в эту переменную адрес микросхемы

Вызовем функцию, которая окончательно установит драйвер для работы с нашей микросхемой по шине I2C

В main.c в функции app_main отобразим в терминале код возврата из функции инициализации и вызовем нашу функцию, чтобы записать в память микросхемы наш массив, не забыв перед этим добавить на неё прототип в заголовочный файл

В бесконечном цикле добавим небольшую задержку

Соберём код, подключим плату, логический анализатор, запустим программу логического анализа, прошьём контроллер и посмотрим результат в программе логического анализа

-6
-7

Также мы видим, что частота соответствует заявленной

-8

В терминале мы также видим успешный результат инициализации шины

-9

Теперь чтение. Закомментируем вызов функции записи, перейдём в файл at24c.c и добавим функцию для чтения, аналогично воспользовавшись той же структурой, а какие команды использовать для чтения серии байтов, мы и так давно знаем

Добавим на данную функцию прототип в заголовочном файле, вызовем её в main.c в функции app_main и отобразим в терминале принятые байты

Соберём код, прошьём контроллер и посмотрим результат сначала в терминале

-10

Всё отлично принялось!

А вот и результат в программе логического анализа

-11
-12

Итак, на данном уроке мы научились работать в своих программах с передачей и приёмом данных по интерфейсу I2C контроллера ESP32. На этом, конечно же, работа с данным интерфейсом не заканчивается. Будет ещё много уроков с его использованием.

Всем спасибо за внимание!

Оригинал статьи находится здесь.

<<Предыдущий урок | Следующий урок>>

Исходный код

Недорогие отладочные платы ESP32 можно купить здесь: Недорогие отладочные платы ESP32

Логический анализатор 16 каналов можно приобрести здесь

Модуль RTC DS3231 с микросхемой памяти (3 шт)

Модуль RTC DS3231 с микросхемой памяти (1 шт) - так дороже

Видео в RuTube

Программирование МК ESP32. Урок 6. I2C. Подключаем внешний EEPROM

Видео в Дзен

Видео в Youtube