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



Сегодня мы попробуем с помощью библиотеки CMSIS поработать с шиной I2C. В качестве подопытного устройства мы возьмём микросхему EEPROMAT24C32, которая установлена в модуле с часовой микросхемой DS3231 и также в часовом модуле с микросхемой DS1307. С данной микросхемой мы уже работали, когда изучали программирование шины I2C для контроллеров AVR. Там эта шина называлась TWI. Причём микросхему мы использовали с часовым модулем на микросхеме DS1307. Данный модуль мы будем использовать и сегодня. Также в уроке 150 мы работали с данной микросхемой, причём мы подробно изучили аппаратную организацию модуля I2C в контроллере STM32F1, все регистры, биты и битовые поля. Также узнали, как вычисляются коэффициенты для настройки различных скоростей работы шины. Поэтому сегодня нам будет проще, так как ещё раз изучать нам это не придётся. Поэтому кто не видел урок 150, обязательно посмотрите.

Единственная трудность будет в том, что всю инициализацию модуля I2C взял на себя проектогерератор, а в данном уроке нам придётся это проделать самим. Но, так как мы всё равно просматривали, что нам сгенерировал Cube MX, то нам тоже проинициализировать I2C много труда не составит.

Схема осталась прежняя, также подключен к ней логический анализатор для того, чтобы мониторить, что происходит на шине

 

 

Проект за основу мы возьмём из урока 170 по динамической индикации с именем CMSIS_LED_DYN и назовём его CMSIS_I2C_EEPROM.

Откроем проект в Keil и из тела бесконечного цикла функции main() файла main.c удалим весь код.

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

 

 

Вызовем её в main()

 

 

И начнём потихоньку наполнять кодом её тело. Инициализируем сначала ножки GPIO PB6 и PB7 для шины I2c, включив им альтернативный режим и максимальную скорость, а затем включим порту B тактирование

 

 

Хотя у нас уже включено тактирование данного порта, так как мы его другие ножки используем для индикатора, но сделаем это для универсальности.

Включим тактирование модуля I2C

 

 

Отключим режим двойной адресации

 

 

Работу с широковещательными адресами мы не планируем, поэтому отключим также и эту возможность

 

 

Задействуем отложенный отклик в случае невозможности SLAVE откликнуться мгновенно

 

 

Отключим модуль для его безболезненной дальнейшей настройки

 

 

Настроим скорость шины 100 кГц, как настраивается скорость, мы также знаем. Причём настроим ещё и на 400 кГц, но данные настройки пока закомментируем

 

 

Добавим макросы — один для настройки модуля на 7-битный режим адресации, а другой — для режима I2C (как мы помним, бывает ещё SMBus)

 

 

В функции I2C_Init настроим данные режимы путём инициализации определённых регистров и их битов

 

 

Включим модуль

 

 

Разрешим генерацию условия ACK после приёма байта

 

 

Установим значение второго адреса в 0

 

 

Вот и вся инициализация.

Осталось научить наш модуль отправлять и принимать данные. Это мы тоже делать умеем.

Поэтому выше функции main() создадим сначала функцию для передачи определённого количества байтов из буфера в шину

 

 

Для того, чтобы что-то передавать по шине I2C, нужно знать адрес устройства, который мы знаем, поэтому создадим соответствующий макрос для адреса. Так как адрес 7-битный, то в качестве 8-го бита будет либо 0 в случае записи, либо 1 в случае чтения, поэтому кроме адреса добавим ещё 2 макроса

 

 

 

Передавать мы будем 20 байт подряд, читать тоже, поэтому создадим два буфера, один сразу инициализированный числами, а другой — пока нулями

 

 

Вызовем функцию передачи байтов в main()

 

 

Начнём писать код тела данной функции.

Сбросим бит POS в регистре CR1

 

 

Включим генерирование условия ACK

 

 

Сгенерируем условие START

 

 

Дождёмся установки бита SB в регистре SR1. Данный бит устанавливается, как мы уже знаем, в случае наличия на шине условия START

 

 

Передадим адрес SLAVE микросхеме

 

 

Передадим 16-битный адрес памяти EEPROM, с которого мы будем писать байты в неё путём дальнейшей их последовательной передачи

 

 

Затем последовательно передадим байты, которые запишутся с данного адреса в память микросхемы

 

 

Сгенерируем условие STOP для окончания передачи

 

 

Вот и вся функция передачи.

Добавим код в функцию main(), который покажет нам значения байтов, которые мы записали в микросхему

 

 

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

 

 

 

Все байты успешно переданы.

 

 

Также дисплей у нас всё отображает

 

 

Добавим теперь функцию для чтения значений из микросхемы. Механизм чтения байтов из микросхемы немного сложнее, чем их записи. Последний байт (даже если он единственный) принимается без подтверждения (условие NACK). Начало функции аналогичное

 

 

В функции main() закомментируем вызов функции записи и вызовем функцию чтения

 

 

В цикле также закомментируем вывод элементов массива данных для записи и выведем элементы массива со считанными данными из микросхемы

 

 

Вернёмся в функцию AT24C_ReadBytes, сформируем ещё одно условие START, а затем передадим адрес устройства уже с установленным флагом чтения, такой порядок работы с шиной

 

 

В цикле примем все наши байты, причём последний с установленным флагом NACK

 

 

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

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

 

 

 

Мы видим, что все наши байты успешно принялись и последний пришёл без подтверждения. На дисплее тоже всё отобразились (думаю, показывать это не обязательно, поверьте на слово).

Теперь давайте попробуем настроить шину на максимальную скорость, так как производитель микросхемы нам обещает работу на огромных скоростях. Правда больше 400 кбпс наша шина на STM не разгоняется, но и это неплохо.

Да и у нас уже всё настроено на такую скорость, осталось нам найти данный фрагмент настройки скорости в функции инициализации модуля I2C_Init и закомментировать там настройку на 100 кГц в двух местах, а на 400 — раскомментировать

 

 

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

 

 

Процесс теперь длится окло 550 микросекунд, что вчетверо быстрее, чем в режиме Standard. Оно так и есть скорость вместо 100 кбпс у нас теперь 400.

Закоментируем теперь вызов функции чтения, раскомментируем запись, таким же образом поступим и с массивом в цикле

 

 

 

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

 

 

Всё нормально работает, времени уходит даже меньше, чем на чтение. Ну у нас и байтов меньше в обмене, мы адрес дважды не передаём.

Таким образом, на данном уроке мы научились работать с шиной I2C с использованием возможностей библиотеки CMSIS, что позволило нам записать и считать данные по данной шине в микросхему памяти EEPROM AT24C32. Также мы научились самостоятельно писать инициализацию модуля I2C без помощи автогенерации кода.

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

 

 

Предыдущий урок Программирование МК STM32 Следующий урок

 

Исходный код

 

 

Отладочную плату STM32F103C8T6 можно приобрести здесь STM32F103C8T6

Программатор недорогой можно купить здесь ST-Link V2

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

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

Семисегментный чертырехразрядный индикатор красный с общим анодом 10 шт

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

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

STM CMSIS. STM32F1. I2C. Подключаем внешний EEPROM

9 комментариев на “Урок 172. CMSIS. STM32F1. I2C. Подключаем внешний EEPROM
  1. Влад:

    Не удаётся пройти регистрацию — не приходят подтверждения

    • Странно, а как же Вы сюда пишете, вроде всё зарегистрировано.

      • Влад:

        Сам удивлён. Некто похозяйничал в моём ящике, жалко только полезные ссылки. Пусть это остаётся на совести авторов майл.ру.
        Ваши уроки вдохновили на старости лет заняться полезным делом — изучать языки, контроллеры. Всё очень доходчиво, понятно с первого раза. Чувствуется старая школа. Снимаю шляпу.

  2. Ollovein:

    Доброго времени суток. Такой вопрос: Вы не использовали еще новую среду разработки от ST CubeIDE на базе Eclipse (она ведь бесплатная)? Если да, то можете подсказать как правильно собрать проект с нуля где нужно вручную добавлять все файлы нужные для используемого камня, а то, насколько я понял, Вам Keil помогает с этим.

  3. Alex:

    Здравствуйте! Никак не соображу как переделать на 24с02. Подтолкните пожалуйста.

  4. Не увидел упоминаний о глючности I2C в stm32f1(03). Надежная инициализация предполагает некоторые танцы с бубном, по errdata?
    Чтение из I2C также в правильном исполнении выглядит гораздо сложней, с учетом всех особенностей.
    Печально, что это снова тропка по болоту, дальше без проводника снова не будет хода. А хотелось бы системных знаний. Ок, ок, читаем документацию.

  5. Андрей:

    Нормально. Но, странно как-то в 2019_м году видеть примеры для F1xx. Хотя бы F303 какой-нибудь взяли.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*