» » Примитивы для реализации 1-Wire master при помощи PWM и ICP на микроконтроллерах AVR AtMega

 

Примитивы для реализации 1-Wire master при помощи PWM и ICP на микроконтроллерах AVR AtMega

Автор: admin от 27-02-2017, 18:15, посмотрело: 219

Если кто-нибудь использовал linux-драйвер шины 1-Wire на основе GPIO, то наверняка замечал, что в момент выполнения обмена данными загрузка SY% подскакивает чуть ли не до ста 100% (что вполне логично для bitbang-реализации). Конечно, можно поставить специализированный контроллер шины 1-Wire с подключением через I2C DS28E17 или использовать UART, но… Все-таки использовать linux для приложений реального времени не лучшая идея. Пусть контроллер на нем занимается высокоуровневой логикой, а весь реалтайм можно вынести на отдельный процессор. Тем более, что задач для этого отдельного процессора в моем проекте более чем достаточно.

Нет, я не буду брать распиаренные сейчас STM32 — зачем стрелять из пушки по воробьям!? Возьмем старую добрую AtMega328P (ну или какую-нибудь Arduino, если так станет кому-либо легче) и соберем все на ней. Вот только делать все будем «по-взрослому», с работой в режиме разрешенных прерываний и с расчетом на последующую реализацию более высоких уровней при помощи protothreads (см. оригинал и расжеванные примеры на русском языке). Т.е. от bitbang-а отказываемся сразу и бесповоротно.

Также сохраним UART для будущего использования под другую периферию. Ибо он в нашем случае один, а мне бы еще протокол eBus сюда запихнуть. Ибо это тоже реалтайм.
I2C хорошо, но это еще один не самый дешевый кристалл с обвязкой, а оно нам надо? Итак, из интересного остается PWM и ICP.

Что такое PWM, я думаю, объяснять не надо. Это просто генерация импульсов заданной фазы и длительности, которая производится аппаратно (т.е. с точки зрения программы «в фоновом режиме»), но параметры которой можно изменять программно. А вот ICP достаточно интересная вещь: она позволяет аппаратно сохранять значение таймера в момент изменения уровня сигнала на определенном выводе микроконтроллера. Таким образом возможно достаточно точно получить момент возникновения события (изменения состояния вывода микроконтроллера) и/или измерить его продолжительность.

Итак, будем использовать аппаратный TIMER1 ATmega328 (таймеры 0 и 2 у меня используются для других целей). Для PWM можно использовать выводы OC1A и OC1B. Однако OC1B также используется в качестве сигнала SS, а подключать ATmega328 к целевому устройству я планировал именно по шине SPI. Это удобно с точки зрения апгрейда прошивок ATmega — делаем их при помощи целевого устройства, только один из CE-сигналов с его контроллера SPI заведем на контакт SS Atmega, а другой CE-сигнал заведем на контакт RESET. Да и с согласованием скоростей обмена возиться не нужно. Ну и в качестве еще одного довода против использования OC1B является то, что на плате Arduino MEGA 2560 этот сигнал вообще не выведен во внешний мир.

Итак, для генерации PWM используем контакт OC1A. Для ICP вариантов вообще нет — вывод такого типа у этой микросхемы только один. Для режима «ACTIVE PULLUP» используем любой свободный IO port и настроим его на работу в режиме «OUT».

Так, со схемотехникой разобрались. Теперь освежим в памяти физику работы шины 1-wire. В двух словах ее можно описать так:


  • Прием и передача тактируется master-устройством (т.е. нами)

  • Временной интервал между передаваемыми и/или принимаемыми битами не критичен (главное, чтобы он был не меньше минимально допустимого)

  • Критичным является длительность передаваемого импульса и длительность принимаемого (измеряемого) сигнала


Отлично, тогда выбираем режим работы Phase Correct PWM Mode (счетчик сначала считает «вверх» от значения BOTTOM до значения TOP, а после достижения значения TOP начинает считать «вниз» до значения BOTTOM). При этом значение BOTTOM фиксировано и всегда равно 0, а значение TOP может быть как одним из фиксированных значений (0xFF, 0x1FF, 0x3FF), так и значением из регистров OCR1A или ICR1. Два последних варианта нам не подходят, т.к. OCR1A мы будем использовать для формирования импульсов на выводе OC1A, а регистр ICR1 будет использоваться для измерения длительности низкого уровня на шине 1-Wire. Т.е. остается только использовать вариант с фиксированными значениями TOP, благо временной интервал между битами для нас не критичен.

В соответствии со схемой выход OC1A включен в инверсном режиме (т.е. установка на нем высокого уровня приведет к установке низкого уровня на шине 1-Wire и наоборот), будем использовать следующий режим PWM:


  • когда таймер считает «вниз» и его значение совпало со значением из регистра OCR1A, установим сигнал на выводе OC1A в высокий уровень (на шине 1-Wire будет низкий уровень).


  • когда таймер считает «вверх» и его значение совпало со значением из регистра OCR1A, установим сигнал на выводе OC1A в низкий уровень (и, возможно, начнем измерять момент перехода сигнала на выводе ICP с низкого уровня на высокий).



Примитивы для реализации 1-Wire master при помощи PWM и ICP на микроконтроллерах AVR AtMega
Остальное все просто. Новое значение (длительность следующего передаваемого бита) в регистр OCR1A мы будем загружать по прерыванию TIMER1_OVF (в данном режиме оно генерируется при достижения счетчиком значения BOTTOM а активируется затем после достижения значения TOP), а по прерыванию TIMER1_ICP будем вычислять длительность нахождения шины 1-Wire в состоянии низкого уровня и, в зависимости от этого, делать вывод о принятии бита «1» или бита «0».

Таким образом, на каждую операцию приема или передачи одного бита у нас будут генерироваться одно прерывание OVF и одно прерывание ICP. Соответственно их ISR лучше бы оптимизировать, но пока пусть они будут написаны на языке C.

Ну а операцию RESET для шины 1-Wire будем выполнять, перепрограммировав TIMER1 в режим NORMAL (т.к. длительность импульса RESET и последующего возможного импульса PRESENCE достаточно большая, нам необходимо расширить «динамический диапазон» работы таймера. В режиме NORMAL он составляет значение 0xFFFF, чего вполне достаточно в нашем случае. Более того, мы его даже специально ограничим значением из регистра OCR1B, чтобы в случае отсутствия подключенных к шине 1-Wire устройств не ждать, пока таймер дойдет до 0xFFFF, а прервать операцию сразу после достижения максимального критического временного интервала).

Вручную считать параметры настройки таймера в зависимости от тактовой частоты ATmega это моветон (да и лениво проверять все граничные условия), поэтому заставим это делать preprocessor компилятора C воспользовавшись тем фактом, что у нас должна быть определенная константа F_CPU, значение которой равно используемой тактовой частоте в герцах (unsigned long, т.е. константа должна быть определена как 8000000UL либо 16000000UL, иначе preprocessor будет считать ее как int и потеряет значащие разряды).








Вот пример осциллограммы выполнения приема:

Примитивы для реализации 1-Wire master при помощи PWM и ICP на микроконтроллерах AVR AtMega

Канал C подключен к выходу OC1A (импульсы одинаковой длительности), а канал B подключен к шине 1-Wire. Видно, что длительность 1-го и 3-го импульса на канале B больше, чем длительность соответствующего синхроимпульса на канале C. Т.е. slave-устройство в битах 1 и 3 передает значение «0». А длительность импульса 2 на каналах B и C приблизительно равна, что соответствует биту «1».

Так как используемый драйвер шины 1-Wire поддерживает также режим «ACTIVE PULLUP» (что также реализовано в примитивах), ниже приводятся соответствующие осциллограммы:

Примитивы для реализации 1-Wire master при помощи PWM и ICP на микроконтроллерах AVR AtMega

Активация режима «ACTIVE PULLUP» после завершения передачи последнего бита команды (сигнал канала B переходит из низкого уровня в высокий, после чего в течении не больше 10мкс сигнал активации PULLUP также переходит в активное состояние, подавая через транзистор Q5 напряжение питания на сигнальную шину).

Примитивы для реализации 1-Wire master при помощи PWM и ICP на микроконтроллерах AVR AtMega

Тот же режим «ACTIVE PULLUP», но в меньшем масштабе (передача команды, активация PULLUP, деактивация PULLUP и команда чтения с получением результатов).

Примитивы для реализации 1-Wire master при помощи PWM и ICP на микроконтроллерах AVR AtMega

Окончание режиме «ACTIVE PULLUP» с передачей команды на чтение результатов в укрупненном виде.

Примитивы для реализации 1-Wire master при помощи PWM и ICP на микроконтроллерах AVR AtMega

Процедура RESET (первый импульс низкого уровня на канале B, совпадающий по длительности с импульсом высокого уровня на канале C) с последующим PRESENCE от устройства, подключенного к шине 1-Wire (второй импульс низкого уровня на канале B, когда на канале C также присутствует низкий уровень).

Примитивы для реализации 1-Wire master при помощи PWM и ICP на микроконтроллерах AVR AtMega

То же самое, но после окончания режима «ACTIVE PULLUP».

Вопрос к читателям: имеет ли смысл писать продолжение, где будет реализация команд протокола обмена 1-Wire на основе этих примитивов и библиотеки protothreads? В принципе там все очень просто и пишется просто сходу, подглядывая одним глазком в соответствующий datasheet.

Список литературы


  • Драйвер шины 1-Wire для контроллеров питанием меньше 5V

  • Четыре метода для подключения 1-Wire устройств к Raspberry Pi

  • 1-Wire Communication Through Software

  • 1-Wire-to-I2C Master Bridge

  • Single-Channel 1-Wire Master

  • Using a UART to Implement a 1-Wire Bus Master

  • А здесь на пальцах объясняется функционирование устройств 1-Wire (на русском языке)

  • Protothreads by Adam Dunkels

  • Protothread и кооперативная многозадачность

  • ATmega328/P datasheet

  • Arduino PRO mini

  • Arduino MEGA 2560


  • Источник: Хабрахабр

    Категория: Программирование, Веб-разработка

    Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
    Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

    Добавление комментария

    Имя:*
    E-Mail:
    Комментарий:
    Полужирный Наклонный текст Подчеркнутый текст Зачеркнутый текст | Выравнивание по левому краю По центру Выравнивание по правому краю | Вставка смайликов Выбор цвета | Скрытый текст Вставка цитаты Преобразовать выбранный текст из транслитерации в кириллицу Вставка спойлера
    Введите два слова, показанных на изображении: *