В предыдущей статье был представлен вариант реализации примитивов для асинхронной работы с шиной 1-wire для микроконтроллеров Atmel. Ну а сейчас вашему вниманию предлагается реализацию того же самого, но на более мощных микроконтроллерах семейства STM8L (для отладки использовалась обычная оценочная плата STM8L-Discovery с извлеченным LCD-дисплеем). С минимальными изменениями описываемая реализация может быть адаптирована и для семейства STM32.



В качестве toolchain использовался IAR Embedded Workbench для STM8 с бесплатной лицензией (ограничение размера кода 8Кб).

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

  • контакт PB1 оценочной платы подключаем к OCRA драйвера
  • контакт PD0 оценочной платы подключаем к ICP драйвера
  • контакт PA5 оценочной платы подключаем к PULLUP драйвера

Не забываем подключить GND, питание +5V и питание +3V3.

В отличии от AVR микроконтроллеры семейства STM8 (и STM32) предлагают более широкий набор внутренней периферии. Таким образом описываемый проект можно скомпилировать в нескольких вариантах:

  1. IRQ-only. Логика работы реализована только по прерываниям, без использования DMA. Этот вариант компилируется когда символ __DRV_ONEWIRE_DMA не определен.

    Плюсы реализации:

    • Требуется всего 3 байта RAM
    • Возможность запрограммировать таймер на любое требуемое разрешение

    Минусы реализации:

    • Большое количество прерываний (по 3 прерывания на каждый передаваемый бит)

  2. DMA с 8-ми битной передачей. Программирование таймера и сохранение результатов во время приема и передачи битов производится при помощи DMA. Этот вариант компилируется когда символ __DRV_ONEWIRE_DMA=1.

    Плюсы реализации:

    • Требуется 9 байт RAM
    • Небольшое количество прерываний (одно прерывание на 1-й передаваемый бит и 3 прерывания в случае успешного завершения обмена)

    Минусы реализации:

    • Невозможность запрограммировать таймер на большое разрешение

  3. DMA с 16-ти битной передачей. Программирование таймера и сохранение результатов во время приема и передачи битов производится при помощи DMA.Этот вариант компилируется когда символ __DRV_ONEWIRE_DMA=2.

    Плюсы реализации:

    • Небольшое количество прерываний (одно прерывание на 1-й передаваемый бит и 3 прерывания в случае успешного завершения обмена)
    • Возможность запрограммировать таймер на любое требуемое разрешение

    Минусы реализации:

    • Требуется 17 байт RAM

Кроме того, благодаря наличию у таймеров входа запрета PWM (BREAK-сигнал), появилась возможность аппаратно реализовать защиту от попытки выполнить обмен данными в момент включенного active-pullup (т.е. чтобы случайно не замыкали 1-wire на землю в момент, когда на нее подается питание для выполнения преобразований).

Общие особенности реализации

Когда примитивы не используются, на выходе PB1 поддерживается низкий уровень сигнала (т.е. модулирующий каскад не активен). Таймер запрограммирован таким образом, что длительность периода соответствует длительности таймслота плюс длительность защитной паузы между битами (для процедуры передачи битов) либо суммарной длительности импульса RESET, паузы до возможного начала PRESENCE и максимальной длительности самого PRESENCE (для процедуры RESET).

Регистры управления PWM (TIMx_CCR1) и Capture (TIMx_CCR2) программируются в режим использования shadow-регистров. Это означает, что после программного изменения регистра PWM ((TIMx_CCR1) его значение начнет использоваться только после возникновения сигнала UEV внутри микроконтроллера. А этот сигнал формируется либо автоматически при достижении счетчиком заданной вершины (период), либо программно путем установки бита UG в регистре TIMx_EGR).

Непосредственно до запуска PWM вычисляется и загружается в регистр PWM (TIMx_CCR1) требуемая длительность импульса самого младшего передаваемого бита. После этого таймер запускается установкой бита CEN в регистре TIMx_CR1. В этот момент сигнал PWM еще не активен, т.к. бит MOE в регистре TIMn_BKR заранее был сброшен в 0. После этого программно устанавливается бит UG в TIMx_EGR, что вызывает активацию внутреннего сигнала UEV, сброс текущего значения счетчика в 0 и загрузку содержимого регистра PWM (TIMx_CCR1) в его shadow-копию, используемую для сравнения.

Кроме того, так как в регистре TIMn_BKR заранее был установлен бит AOE, по сигналу UEV может автоматически установится бит MOE в регистре TIMn_BKR, что разрешит выход PWM. Однако это произойдет только при не активном сигнале BREAK, который формируется от управления внешним active-pullup (это возможно потому, что сигнал BREAK внутри микроконтроллера формируется непосредственно по значению сигнала на внешнем пине независимо от того, в запрограммирован ли он на режим входа или выхода). Таким образом, если при выполнении процедуры RESET либо попытки передать/принять бит(ы) будет активен сигнал active-pullup, то включение выхода PWM будет блокировано.

Принцип работы IRQ-only реализации совпадает с описанным в предыдущей статье с тем отличием, что вместо режима работы таймера «вверх-вниз» используется режим подсчета «вверх до заданного значения». Это стало возможным потому, что разрядов 16-ти битного таймера вполне хватает как для формирования периода таймслота передачи одного бита, так и для реализации процедуры «формирование сигнала RESET с ожиданием PRESENCE».

В этой реализации вычисление длительности очередного импульса производится при обработке прерывания, возникающего в момент окончания передачи предыдущего бита.

Реализация с использованием DMA с 8-ми и 16-ти битной передачей в принципе одинаковая и различается только разрядностю значений для PWM и ICP. Все длительности импульсов вычисляются заранее до запуска таймера. Длительность импульса самого младшего бита загружается в регистр PWM (TIMx_CCR1) как описано выше, а для загрузки остальных значений при необходимости программируется 1-й канал DMA. Все результаты измерений всегда сохраняются при помощи 2-го канала DMA.

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

Примечание.
В исходных текстах можно найти парочку высокоуровневых процедур для реализации протокола обмена на шине 1-Wire. Они вполне рабочие, но исключены из проекта директивами условной компиляции. Ждите продолжения про использование pthreads и асинхронную реализацию высокоуровневой части протокола.

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

  1. Код проекта на github
  2. Примитивы для реализации 1-Wire master при помощи PWM и ICP на микроконтроллерах AVR AtMega
  3. Драйвер шины 1-Wire для контроллеров питанием меньше 5V
  4. Высокоуровневые функции для работы с 1-Wire
Поделиться с друзьями
-->

Комментарии (8)


  1. Vedga
    12.04.2017 09:25

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


  1. leocat33
    12.04.2017 16:14
    -1

    КГ/АМ


    1. Vedga
      12.04.2017 16:17

      Обоснование?


      1. leocat33
        16.04.2017 19:32

        В коде не узрел, как «разгребать» разнотипные w1 устройства, напр: ds18b20 и iButton.
        Сигнал на w1 3.3V еще тот гемор.
        Нафига ДМА на W1? Аппаратной поддержки в МК w1 — нет, тогда смысл в DMA? Экономия 4-х тактов процессора?
        Да и ШИМ для w1 притянут за уши. Оно там надо?
        Как там понаснасчет гальванической развязки МК — линия w1?
        Ну и напоследок: долгий опыт практического использования w1 показал, что вешать все устройства w1 на один провод совершенно бессмысленно, хотя протокол именно для этого и задумывался.


        1. Vedga
          17.04.2017 09:52

          Коммент — ярчайший пример кодера-ардуинщика, никогда не писавшего серьезных проектов). Смотрим по пунктам:
          1. Высокоуровневые функции (например bus search) на основе pthreads — в списке литературы под п. 4.
          2. w1 3V3 (т.е. ссылку на п. 3 в списке литературы пропустили. Где там трехвольтовая 1-wire?)
          3. PWM. bitbang исключаем сразу. Ибо это работа с запрещенными прерываниями в интервалах от 10 мкс (единица или чтение) до 120 мкс (передача нуля. С разрешенными прерываниями она может плавно перейти в передачу RESET). Если мк выполняет одну задачу (уровень ардуинщика) — это нормально. Для профессионала это уровень даже не junior.
          4. DMA. Реализация по IRQ требует по 2 IRQ/бит (одно загрузка PWM, одно на запись результата, 16 IRQ на байт). Но экономит RAM. Выбирается по условиям компиляции. Если RAM не критична, но критично CPU — выбираем DMA (приблизительно 3 IRQ на байт).
          5. Вменяемые люди на одну шину вешают не отключаемые датчики (напр. температуры), а на вторую отключаемые (напр. таблетки для кода доступа). Таймеров на камне дофига, по одному на каждую шину вполне можно выделить. А можно коммутировать сигнал одним полевиком.

          И причем тут гальваническая развязка, если статья о программировании? Схему аппаратного драйвера (3) давно разобрали умные люди, и их советы давно учтены в production.


      1. leocat33
        16.04.2017 19:42

        Да, про ШИМ еще забыл. Устройства w1 латентны к опросу состояния бита, до 500-600 mSec запросто можно «притормозить» опрашивая, или инициализируя опрос бита. Тогда ШИМ никаким боком не нужен. Достаточно неспешнно опрашивать устройства в основном цикле.Что-то более важное обрабатывается в прерываниях, потом вернулись к работе с w1.


        1. Vedga
          17.04.2017 09:57

          А сам бит как будем принимать/передавать? С запрещенными прерываниями на время от 10 до 120 мкс при тактовой в 16Mhz? На какое время затормозим остальные фоновые задачи при выполнении, например, bus search с подключенным десятком датчиков? А если остальные задачи являются реалтайм-управлением сторонним устройством?


  1. leocat33
    17.04.2017 13:35

    Ни одного стоящего аргумента…
    Я и написал: КГ/АМ