Наверное многие, глядя на цифровую фоторамку, задумывались — можно ли выводить на нее собственную информацию, меняющуюся во времени? Поскольку я уже несколько лет являюсь владельцем фоторамки, то такая мысль приходила в голову и мне — рамка отлично подошла бы для отображения прогноза погоды и информации с «умного дома». О том, как же реализовать подобный функционал, не вмешиваясь при этом в конструкцию рамки — читайте под катом.
Способы реализации
Наиболее простой способ управлять выводимым на цифровую фоторамку изображением — это просто нужным образом переключать заранее заготовленные изображения, хранящиеся в ее памяти. Вот пример реализации такого способа. Очевидно, что этот способ не отличается большой гибкостью — можно выводить одно единственное изменяемое число, а процесс изменения этого числа будет достаточно медленным.
Таким образом, при условии, что разбирать рамку нельзя, остается только использовать ее интерфейсы внешней памяти — SPI (для работы с SD Card) и USB. Достаточно сделать устройство, имитирующее внешний накопитель, подключить его к рамке — и она сама будет запрашивать с такого устройства изображения. При помощи микроконтроллера эмулировать SD карту достаточно сложно, да и форм-фактор самой карты довольно сложно повторить. Можно было бы использовать готовую WiFi SD карту, но все такие карты, про которые я знаю, имели слишком высокую цену (>40$, что близко к стоимости самой рамки).
Использование USB для решения такой задачи подходит больше — не проблема найти производительный микроконтроллер с поддержкой USB; подключение к рамке осуществляется стандартным разъемом. Более того, на Хабре уже была публикация, посвященная эмуляции USB диска при помощи микроконтроллера stm32. В комментариях к этой статье обсуждалась возможность передачи динамически изменяемых данных таким методом. Из-за кеширования операционной системой данных при считывании файла нет смысла менять содержимое эмулируемых файлов — ОС просто не будет их запрашивать, так как не сможет узнать, что они изменились. Однако фоторамки не кешируют файлы (в них просто нет нужного объема ОЗУ)! Проверить это можно, подключив к фоторамке любую USB флешку, со светодиодом, мигающим при чтении файлов — он будет мигать постоянно при считывании файлов. Поэтому я решил использовать именно этот способ.
Программная часть
У меня уже была отладочная плата STM32F4DISCOVERY, так что я решил проверить работу библиотеки «emfat», предложенной в вышеуказанной статье. С Windows 7 проблем не возникло, а вот фоторамка не смогла обнаружить файлы на «виртуальном» диске. Как оказалось позже, планшет с Android тоже не обнаруживал накопителя. Другой компьютер с Ubuntu обнаружил USB устройство, но не смог монтировать диск.
Пришлось заняться проблемой глубже. Как оказалось, несмотря на то, что Windows обнаруживала накопитель и могла считывать с него файлы, программа TestDisk не могла определить файловую систему на нем:
Постепенно, изучая результаты «сырых» данных, выдаваемых TestDisk, а также покопавшись в исходниках этой программы, я понял, что один из критериев, по которым TestDisk определяет используемую файловую систему — размер диска. В «emfat» размер эмулируемого диска зависит от количества данных на нем. Таким образом, если на диске один или несколько небольших файлов, то и размер диска не превысит 16 Мбайт. При этот FAT32 накладывает ограничения на минимальный размер тома – не менее 65527 кластеров. С учетом того, что в «emfat» один кластер занимает 4096 байт, то для соответствия FAT32 размер диска должен быть 65527*4096 ~ 268Мб. В реальности этого нет, что и вызывает ошибки при определении типа файловой системы. Попытка увеличить объем диска, увеличив объем эмулируемого файла до 400 МБ не сработала — возможно, там еще что-то не сходилось. Поэтому я решил переделать «emfat» для эмуляции файловой системы FAT16.
В конечном счете это удалось, и накопитель начал корректно обнаруживаться всеми устройствами:
Стоит отметить, что у FAT16 тоже есть ограничение на размер диска — не менее 4087 кластеров, то есть 16 МБ в данном случае. Для выполнения этого условия приходится создать в «emfat» виртуальный файл на 20 Мб.
Проверка с фоторамкой прошла нормально — рамка успешно отображала тестовое изображение, хранящееся в Flash памяти контроллера. Следующий этап — вывод пользовательских изображений. Проще всего эмулировать BMP файлы — у них довольно простая структура, изображение может быть 256-цветным, т.е. на один пиксель приходится один байт. Вот только в таком случае для хранения картинки размером 800*600 понадобится 480 Кбайт ОЗУ. У микроконтроллера такого объема памяти нет, а значит остается один вариант — формировать изображение «на лету». Принцип работы следующий — в том случае, когда устройство-хост запрашивает с накопителя данные из файла, «emfat» вызывает callback-функцию, соответствующую этому файлу. В эту функцию передаются номер сектора, из которого запрашиваются данные, и указатель, по которому эти данные нужно записать. Зная номер сектора, можно определить, какой участок изображения запрошен и сформировать его.
В процессе экспериментов обнаружился неприятный факт — Windows может запрашивать данные из секторов не по порядку их следования. Почему так сделано — непонятно, но это усложняет формирование изображения на лету, так как приходится но номеру сектора вычислять — какой участок данных запрашивается в данный момент. Еще одна проблема — строки в BMP файлах идут снизу вверх, что еще больше запутывает расчет позиции.
Для отображения текста я использовал библиотеку mcufont. Она удобна тем, что позволяет использовать сжатые шрифты, за счет чего заметно сокращается использование Flash памяти. Так как я использовал достаточно крупные шрифты, то эта возможность является довольно важной.
Эта библиотека напрямую записывает сформированное изображение в память, так что для работы библиотеки приходится выделять отдельный массив в ОЗУ.
Также я реализовал отрисовку изображений из памяти контроллера. Все изображения, как и текст, выводятся в черно-белом виде, за счет чего в одном байте изображения можно хранить информацию о 8 пикселях. Для того, чтобы преобразовать обычные изображения в вид, пригодный для подключения к проекту, была использована программа LCD Assistant.
В результате на подключенном USB накопителе формируется изображение вот такого вида:
Заголовок
После того, как работа программы была проверена на STM32F4DISCOVERY, я сделал само устройство, которое представляет собой микроконтроллер с подключенным к нему WiFi модулем на ESP8266. Из подходящих у меня был только контроллер STM32F107RCT7.
Схема получившегося устройства вышла довольно простая:
А вот из-за ограничений на размер платы — 17x36мм (я планировал установить ее в готовый корпус) и большого размера контроллера печатная плата вышла не самая простая в изготовлении — двухсторонняя, с монтажом деталей с двух сторон. При этом некоторые линии питания пришлось сделать проводом.
Вид получившейся платы (в процессе отладки вместе с модулем ESP-01):
При указанных размерах платы наиболее подходящим был WiFi модуль ESP-03. Вот так выглядит получившаяся плата с уже установленным модулем:
И со стороны контроллера:
В процессе экспериментов оказалось, что чувствительности керамической антенны явно не хватает — модуль с трудом подключался к роутеру. После подключения к выводу WIFI_ANT кусочка проволоки длиной 31 мм чувствительность заметно улучшилась, и стала сходной с чувствительностью ESP-01. Место, где фоторамка установлена постоянно, находится в нескольких метрах от роутера, и там нормально работает и родная антенна модуля, так что на фотографии дополнительной антенны нет.
Так как при постоянной работе ESP8266 довольно сильно нагревалась, я решил включать ее только во время запросов информации. Управление питанием можно производить, используя вывод CH_PD модуля. Перевод этого вывода в 0 приводит в переходу ESP8266 в режим пониженного потребления.
Для того, чтобы было удобнее тестировать работу ESP8266, я написал для микроконтроллера отдельную прошивку, реализующую мост USB-UART. Именно через нее ведется настройка модуля для работы с роутером, так что после включения ESP8266 автоматически подключается к нему.
Принцип работы получившегося устройства достаточно прост — каждые 10 минут контроллер пытается запросить данные с сервера, и если это удается, обновляет данные о погоде. Данные о текущей температуре и прогноз на 3 дня вперед берутся с сайта openweathermap.org, информация о температуре снаружи и внутри балкона — c сервера majordomo. В то же время фоторамка запрашивает изображение каждые 6 секунд, отображая при этом текущую информацию. Так как оба процесса могут происходить одновременно, то для приема данных от ESP8266 используется DMA.
В результате, на фоторамке отображается вот такое изображение:
Исходный код проекта:
github.com/iliasam/USB_Photoframe