Аппаратная реализация 1-Wire на stm32f030

Аппаратной реализацией интерфейса 1Wire я называю совместное использование UART и DMA для приема/отправки таймслотов. Эта тема уже очень много где обсуждалась, очень хорошая статья есть на изиэлктрониксе. Собственно оттуда я и взял исходники и немного переделал для работы с серией f0. Основные отличия заключаются в настройках DMA, так как он устроен немного по другому, чем в в f1. Также вынес все функции работы с железом в отдельные инлайн функции-обертки. Как мне кажется это поможет при переносе на другие семейства. Можно было бы наверное изловчиться и написать более универсально и красиво, но я не стал сильно заморачиваться.

Подробное и понятное описание самого протокола 1 Wire можно посмотреть например тут.

Все же повторю суть аппаратной реализации. Настроив определенную скорость UART, мы получаем возможность аппаратно отправлять и принимать тайм-слоты 1Wire. Один тайм слот будет равняться одной посылке по UART. Соответственно, для приема/отправки одного байта 1Wire нужно отправить/принять 8 байт UART. Контроллер DMA есть даже в самой простой серии f0, то думаю задействовать его будет оптимальным решением. Скорость для приема и отправки тайм слотов данных является 115200. Для формирования на линии сброса и приема импульса присутствия используется скорость 9600. UART STM32 имеет полудуплексный режим работы по одному проводу ( Single-wire half-duplex communication).  Также есть возможность перевести ножку приемопередатчика UART в режиме открытого коллектора (ОК). Как по мне все эти возможности позволяют удобно, без всякой возни с таймслотами работать с интерфейсом 1Wire.

// функция инициализирует UART_OW
__inline static void _ow_usart_init(void)
// функция инициализации UART_OW с указанной скоростью
__inline static void _ow_usart_set_speed(uint32_t speed)
//функция отправки по UART 1 байта
__inline static void _ow_uart_byte_send(uint8_t data)
// обертка функция приема по UART 1 байта
__inline static uint8_t _ow_uart_byte_recv(void)
//функция отправки/приема по UART через DMA
__inline static uint32_t _ow_uart_dma_send_recv(uint8_t* data, uint32_t cnt)

Функции обертки для работы с железом.

Модификатор static использовал для того чтобы область видимости данных функции была только в файле onewire.c. Т.к. функции служебные, не стоит, чтобы они были видны из других модулей. По своей сути данные функции являются обертками, то вполне оправдано использовать модификатор __inline. Потому как обертки вызываются всего лишь в нескольких местах модуля onewire, да и по сути своей реализации являются низкоуровневым исполнительным кодом. Поэтому, как мне, кажется, целесообразности в обычном вызове данных функций нет.

//функция приема по UART 1 байта
__inline static uint8_t _ow_uart_byte_recv(void)
{
 uint8_t data;
 HAL_UART_Receive(&_huart, &data, 1, 100);
 return data;
}

Функция приема байта.

В моем случае я использую функции библиотеки HAL. Она конечно не оптимальна и бывает довольно глючной, но в простых проектах считаю возможным ее использовать, да и для переносимости кода между разными семействами STM32 она тоже годится. Хотя  при глубоком задействовании возможностей периферии предпочитаю ее не использовать. Как мне, кажется, если использовать CubeMX и HAL с умом, они могут неплохо сэкономить время на разработке или помочь в быстрой проверки каких-нибудь идей. Во всяком случаи возможности CubeMX визуально назначать те или иные пины или наглядная настройка дерева тактовой частоты, считаю очень полезными. Как бы то ни было, данную функцию-обертку легко переписать используя лишь например интерфейс CMSIS. Остальные реализации оберток аналогичны.

Как обычно прикладываю пример, выполненный в Keil v.5. Пример этот содержит код для контроллера травильной ванночки. Сам алгоритм прима/отправки onewire пакетов не трогал. Благодарю авторов данных исходников, которыми они щедро поделились.

Аппаратная реализация 1-Wire на stm32f030: 10 комментариев

  1. Олег

    Я так понимаю, запустить одновременно приём и передачу по юарт средствами HAL всё-таки не получается?

  2. Kos

    Воспользовался Вашей библиотекой. Адаптировав ее под stm32f103. Но моя аппаратная часть была сделана несколько иначе(была дана готовая схема ) Я работал с полноценным UART. FullDuplex.
    К Вашей библиотеке возник ряд вопросов но которые были успешно решены. Могу прислать Вам файлы если хотите.
    И я читал «таблетку » была добавлена ф=ция подсчета CRC.

    1. Вячеслав Автор записи

      Спасибо за отзыв, очень рад, что библиотека пригодилась. Можно на ты). Да было бы интересно посмотреть, что получилось. А в будущем, если вы не против, мог бы ее добавить к статье

      1. Kos

        Куда кинуть?? Напишите мне в почту которая указана я отвечу.
        Меня тоже можно на ТЫ

        1. KossDM

          Добрый день Kos, поделитесь пожлайста вашей реализацией. Заранее спасибо! kossdm(сАбАкА)gmail(ТочЕка)КОМ

        2. Valerj

          Kos Где можно скачать вашу реализацию, хочу сделать на Atmege..

  3. Fly777

    Здравствуйте, подскажите ламеру, пожалуйста: на stm32f103 компилятор ругается на эти строчки:
    WRITE_REG(DMA_Channel->CPAR, (uint32_t)&(USART->TDR));
    WRITE_REG(DMA_Channel->CPAR, (uint32_t)&(USART->RDR));
    вот так:
    ‘USART_TypeDef {aka struct }’ has no member named ‘TDR’; did you mean ‘DR’?
    Что это за регистры такие TDR и RDR и на что их заменить в stm32f103?
    Спасибо!

    1. Вячеслав Автор записи

      Здравствуйте, это строчка подсказывает ‘USART_TypeDef {aka struct }’ has no member named ‘TDR’; did you mean ‘DR’?, что возможно, стоит заменить TDR на DR. К, сожалению, я мало работал с stm32f103 и точно не помню название его регистров. В данном куске кода идет настройка DMA. Я бегло глянул доки на f103 и похоже его USART имеет только регистр DR (DATA REGISTER). На него и стоит настраивать каналы DMA

      1. Fly777

        stm32f103 Поправил, но как-то криво работает.
        Отправляем
        OW_Send(OW_SEND_RESET, (uint8_t*)»\xCC\x44″, 2, 0, 0, OW_NO_READ);
        На лог анализаторе вижу 0xCD 0x45
        Выполняем
        status=OW_Send(OW_SEND_RESET,(uint8_t*) «\xcc\xBE\xff\xff», 4, buf,2, 2);
        Анализатор выдает 0xCC 0xBF 0xFF 0xFF
        Ну естественно датчик ни чего не отвечает.
        Почему-то после 0xCC некоторые байты изменяют последний бит на 1
        Ну уже тупо взял такую строку отправил.
        OW_Send(OW_SEND_RESET, (uint8_t*)»\xCC\x44\x44\xDD\xEE\xFF\x01\x02\x03\x03\x22\x33\x44\x44\x55″, 15, 0, 0, OW_NO_READ);
        Анализатор кажет: 0xcc, 0x45, 0x44, 0xDC, 0xEF , 0xFF , 0x01 , 0x02 , 0x02 , 0x02 , 0x22 , 0x32 , 0x44 , 0x44 , 0x54

        1. Phantom

          Столкнулся с той же проблемой при портировании на STM32F103. Удалось выяснить, что последний бит портит функция uart_dma_rx_link. В теле функции _ow_uart_dma_send_recv перенёс строчку uart_dma_rx_link(OW_USART, OW_DMA_CH_RX, data, cnt); после uart_dma_tx(OW_DMA_CH_TX, data, cnt);
          Данные отправляются нормально, но при чтении портятся уже принимаемые данные, сдвигает на один бит влево. Не стал заморачиваться, добавил костыль в виде сдвига при обработке. Температура считывается!
          Есть, правда, ещё один неприятный момент. Я обращаюсь к датчику по прерыванию таймера динамической индикации 4-разрядного 7-сегментника, и каждый раз при обращении к датчику он едва заметно мигает. Почти не видно, но всё равно неприятно, специально ведь выбрал библиотеку с DMA, чтобы такого не было. Причём если вызывать датчик в бесконечном цикле, мерцания нет. Кроме того, в таймере индикации есть обращение к I2C датчику DS1624 (можно выбирать тип датчика кнопкой), и с ним всё отображается и не мигает.

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

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