Решил изобразить из себя крутого программиста и написать класс для работы с 1Wire через USART + DMA
И офигел.
Важно !!! Чип STM32F030CCT
Вся идея, подсмотренная у более опытных программистов состоит в том, что бы отправить байт в 1 Wire, нужно через UART послать 8 байт на определённой скорости. Что бы послать бит "1", подсовываем UART 0xFF, что бы послать "0", посылаем 0x00.
Чем не задача для DMA. Провозился долго, пока не прочитал, что STM32F030xC особенный в отличие от всей линейки. Но справился. Попросил DS18B20 измерить температуру, микросхема байт приняла и начала замер температуры. Теперь надо считать данные. Для этого нужно послать две команды. "Пропустить адрес" и "Читать данные". Запуливаю два байта команд и наблюдаю полную кашу на линии.
Не понял. Как так. Да я забыл отслеживать окончание передачи. НО !!! В Мануале сказано, что пока DMA работает, перезаписать регистры невозможно и я хотя бы одну посылку должен получить правильную. Чёрта с два !!! Можно !!! Есть второй вариант. Может я что то напутал.
Для проверки я поставил задержку на 1 миллисекунду. Команды проходят. Значит в этом месте нужно просто проверять флаги. (Перед посылкой я их естественно сбросил). И пока флаг не поднимется, следующий пакет не посылать. Ага жди. Не работает. Похеризация пакетов просто изменила рисунок.
Сейчас начал готовить пакет запросов с одновременным приёмом результата, но рабочий день закончился и я не успел.
До этого пробовал запустить DMA под HAL. Не заработало. И я не один такой невезучий.
Наконец то разобрался с данной связкой. Всё, что я написал ранее, оказалось совсем не так, как я предполагал. Исходил из неверных предпосылок и выводов.
Всё оказалось проще. Я думал, что при окончании работы DMA и поднятии им флага всё заканчивается, данные ушли. Но это оказалось совершенно не так.
Я не учёл, что DMA высокоскоростное устройство, а USART довольно медленный. Получается так, что DMA подняв флаг окончания передачи, рапортует об окончании перекачивания данных в USART. Но USART продолжает передавать последний байт. Понял я это проанализировав логи линии передачи с помощью логического анализатора. Если в этот момент мы снова проинициализируем DMA и USART на новую передачу, USART прерывает передачу предыдущей информации и начинает новую и данные становятся кривыми. Без переиницииализации USART не знаю будет работать или нет. Не пробовал. Такой подход усложняет код очень значительно.
Ну чтож. Нам никто не мешает дождаться окончания передачи USART и продолжить работу. Удалось начать читать температуру. Но как то не устойчиво. В логах логического анализатора было видно, что часть информации при чтении почему то кривая. Читаем байты друг за другом и некоторый момент получаем битый байт.
Сейчас могу опять сделать немного неправильный вывод, но кто знает, может он и верен.
Дело в том, что я передаю и принимаю данные в полудуплексе. В этом случае вход и выход USART объеденены вместе на уровне коммутатора GPIO самого МК. Пробовал и внешнее соединение, но результат был тот же. Правда есть некоторые схемные решения, которые я не мог попробовать. Так как плата уже собрана.
Выводы TX и RX переключены в режим открытого стока, что позволяет нам не использовать внешние схемы. И такой способ подключения или что то ещё так же влияет на обмен информацией. Решение оказалось довольно простым. Есть такой флаг BUSY. Он устанавливается в "1" когда идёт приём. И в "0", когда приём закончен. Оказалось, что перед каждой передачей, нужно с помощью этого флага убедиться, что приёма нет, сбросить флаги DMA и начать процесс обмена. Всё заработало с полтыка.
Есть очень неприятная вещь. Библиотека 1-Wire получилась не универсальной. Из за разных каналов DMA подключаемых к периферии. Поэтому придётся для каждого типа МК писать свою библиотеку. Можно при инициализации указывать какой DMA использовать и какие именно каналы. Я позже этим и займусь. И как всегда есть одно НО. Я делал это всё на STM32F030CCT6. А у него всё никак у людей. У всей серии этих МК каналы DMA фиксированно закреплены за определённой периферией, но вот именно у этого кристалла каждое периферийное устройство можно подключить к одному из нескольких каналов DMA.
Немного причешу библиотеку. Осталось доделать поиск адресов подключенных устройств. И можно выкладывать статью.
@eduard слушай, а не будет нерационального расходования ресурсов? DS18B20 вроде медленный сам по себе, то есть между считанными с него новыми значениями очень большой период. А тут целый канал DMA под это помимо самого USART'а.
Там не совсем так.
После команды "Померять температуру" проходит 700-800 мС.
Команда - это два байта. Следовательно в UART нужно кинуть 16 байт. На скорости 115200 проскакивает быстро. После чего производится измерение.
Всё это время можно заниматься чем угодно. Можно или спросить DS18B20 закончила ли она, или просто заниматься чем нибудь, а через 800мС считать температуру.
Это 2 байта команда и 9 байт ответ. Всего UART передаёт 16 байт и принимает 72 байта.
Я обычно в устройствах обновление экрана делаю раз в секунду, если нет быстрых процессов. Сразу же после обновления делаю запрос на измерение. Потом занимаюсь чем угодно, а после истечения секунды запрашиваю измерянную температуру, вывожу её на экран и т.д. по кругу.
Я делал это на ногодрыге на быстрых МК. На медленных библиотека не захотела работать. Поэтому и пришлось натравливать на это дело UART.
DMA я сюда прикрутил ради интереса. Без него код будет проще, а время уходить то же самое. Если не быстрее. Инициализация DMA команд многовато.
Можно попробовать скрестить с предыдущей библиотекой UART. Где есть FIFO. Плюнул и забыл. FIFO само всё выкинет. Только там проблема. FIFO может работать только с одним UART. Там всё через прерывания. А прерывания как класс, я ещё не доделал.
DMA я сюда прикрутил ради интереса.
Так да, а то получается десяток байт в секунду плюс-минус всего.
Перед тем как это делать, я проштудировал несколько статей на эту тему.
У некоторых доходит до маразма.
Они принимают 8 байт и переинициализируют всё заново. И так пока весь пакет не примут. Тогда вообще смысл в DMA теряется.
Получается да же дольше.
Один деятель делал заливку экрана сплошным цветом создавая буфер экрана в памяти, а затем перезаливая его с помощью DMA. На то, что бы отключить инкремент памяти и передать один байт в контроллер экрана нужное количество раз, ума не хватило.
Вообще DMA довольно интересная вещь. Немногие умеют им пользоваться. А кто умеет, им некогда описать, как правильно делать.
А жаль.
@eduard DMA зачастую пихают бездумно, чисто чтобы галочку поставить "тут в проекте DMA, значит круто" 😆