TinyPhoto – это миниатюрный электронный фотоальбом с встраиваемой графикой, собранный с использованием микроконтроллера ATiny85 и OLED-дисплея 128х64px. Такой дуэт может обеспечить не менее 20 часов непрерывного показа изображений от «таблетки» на 3В и 225мАч.
Для сборки этого устройства понадобится 12 электронных компонентов общей стоимостью £5, размещенных на односторонней печатной плате размером 3х7см. В качестве встраиваемого ПО задействуется 150 строк кода Си, которые займут 1,300 байтов памяти.
TinyPhoto прокручивает пять выбранных пользователем изображений, используя в общей сложности 4,900 байтов (да, байтов!) флэш-памяти. В результате на OLED-дисплее в реальном времени отображаются четкие фотографии с незаметной для человеческого глаза скоростью обновления 60Гц, что обеспечивается повышением тактовой частоты ATiny85 до 8МГц.
Кастомный драйвер устройства (размером 200 байтов) настраивает экран и делает возможным попиксельное отображение. В свою очередь, кастомный код Forth преобразует изображение с глубиной цвета 1 бит в поток байтов, которые записываются на встроенную флэш-память для быстрого показа. Все это лишний раз напоминает о том, чего можно добиться с помощью примитивных вычислительных ресурсов.
При этом вся магия, конечно же, реализуется в ПО. В данной статье я поэтапно опишу сборку TinyPhoto, а также программы, которые в нем использовал.
Tiny Photo – это инструмент просмотра фотографий, работающий на 8-битном микроконтроллере ATTiny85, который отправляет пиксельные данные изображения на OLED-дисплей размером 128 х 64px. Питание обеспечивается батареей по типу «таблетка» с напряжением 3В. Переключение происходит циклически по 5 фотоснимкам, занимающим 5Кб встроенной флэш-памяти. (Заметьте, что это в миллион раз меньше памяти, чем в среднем ПК, оборудованном 8Гб). Вся магия в ПО.
Дополнение от 24 июля 2021) – TinyPhoto V3 готов! Эта версия включает драйвер шрифтов фиксированной ширины для OLED-дисплея (размер 700 байтов), разовый экран запуска и команды SSD1306.
Простое оборудование
По приведенным мной выше наброскам схемы и макета платы видно, что электроника достаточно проста. В общей сложности используется 12 компонентов и лишь немного проводов, что позволяет уместить все это на плату размером 3х7см. Для фиксации ATiny85 я использовал 8-контактное гнездо DIL, чтобы микроконтроллер можно было снимать, перепрограммировать и подключать обратно с новым набором из 5 фотографий или измененным порядком их отображения. На зарисовку схемы и макета платы у меня ушло пол часа, на пайку и тестирование еще полтора, плюс час на подготовку изображений, включая их ретуширование.
Вся магия в ПО
Преобразование большого цветного изображения в матрицу 0-1 с 8к пикселей или менее для отображения на OLED-дисплее 128х64px
Первый алгоритм изменяет размер изображения, например 1.7Мп (JPG, 225Кб, 24-бита) до 128-64px (25Кб BMP, 24-бита, уменьшение на 90%, IrfanView). Изображение при этом также остается цветным и четким.
Второй алгоритм преобразует уменьшенный вариант в оттенки серого (Rec 601 luma formula Y=0.2989R+0.5870G+0.1140B, т.е. 30% красного, 60% зеленого, 10% синего) и применяет выбираемый пользователем порог (скажем, 25) для создания матрицы 0-1 (двоичного изображения), где 1=черный, а 0=белый, Image Binarizer).
OLED-дисплеи 128х64px созданы для удобства отображения текста. Наименьший размер шрифта составляет 8px в высоту, поэтому RAM дисплея сегментирована на 8 текстовых рядов 8px высотой и 128 столбцов. Данные изображения выводятся на экран путем отправки потока байтов, где каждый вертикальный байтовый код содержит 8 пикселей из заданного текстового столбца с младшим битом вверху.
Преобразование матрицы 0-1 в байткод OLED/LCD-дисплея. Каждый вертикальный фрагмент байткода содержит 8 пикселей из одного столбца, где младший бит является верхним, а старший нижним
Последним этапом идет постобработка этой матрицы 0-1 и извлечение вертикальных байткодов (1 байт содержит 8 пикселей из одного столбца), используемых для вывода изображения на дисплей. В качестве примера на картинке выше три вертикальных фрагмента байткода, обведенные красным, представляют 0х00
, 0х03
и 0х30
соответственно.
Макрос получает текстовую матрицу 0-1 для непосредственной загрузки в Forth в виде содержащейся в памяти карты изображения, готовой для извлечения байткодов. Вычисление вертикального байткода выполняется в нескольких строках Forth (см. раздел «Код» ниже – файл 3iArt.fs).
Далее байткод записывается на встроенную флэш-память ATiny85 (4,900 байтов для 5 изображений). Для хранения параметров каждого снимка я использую 4 поля структуры данных (размер изображения, размер передаваемого по I2C пакета, количество пакетов до добавления новой строки и т.д.).
Микроконтроллер выполняет 150 строк кода Си (объемом 1,300 байтов) в непрерывном цикле, который поочередно генерирует пять изображений и отправляет их данные через I2C на OLED-дисплей 128х64 пикселя.
Для ATiny85 размер имеет значение
Для того, чтобы все это уместить на ATiny85 (512 байтов SRAM, 8Кб Flash), я написал собственный простой код (200 байтов Flash) для драйвера микросхемы дисплея SSD1306. Он удаляет все лишнее и сохраняет лишь то, что мне требуется для инициализации дисплея, настройки его контраста (высокая яркость) и ориентации, а также прямой отправки на него данных изображения.
Это избавляет от необходимости применения в 35 раз более крупных (7Кб Flash) драйверов, например от Adafruit, которые бы просто не оставили свободного места под снимки. Помимо этого, исчезает необходимость в использовании программного буфера SRAM объемом 1Кб, который дублирует RAM дисплея, но вдвое превышает имеющиеся у ATiny85 512 байтов. В результате получился максимально скромный графический драйвер для микросхемы дисплея SSD1306.
Связь с дисплеем
Поскольку ATiny85 не имеет в своем составе интерфейса I2C, я использовал драйверы TinyWireM от BroHogan, которые с помощью аппаратного модуля USI (универсальный последовательный интерфейс) от Atmel эмулируют протокол I2C. Это уменьшило максимальный размер пакета до 8 байтов (с 32 байтов, получающихся при использовании Atmega328P, оборудованного I2C), но при этом картинка на дисплее осталась плавной, а сам дисплей смог генерировать все 8к пикселей (128х64) при скорости обновления 60Гц, позволяющей человеку видеть «мгновенно» генерируемое изображение.
Примечание: для получения достаточно быстрого отображения ATiny85 должен работать на частоте 8МГц или выше. По умолчанию фьюзы микросхемы скорее всего установлены на 1Мгц, чего недостаточно для обновления экрана с частотой 60Гц. Поэтому нужно будет выбрать 8МГц (внутренне) и записать загрузчик, используя программатор ISP. Таким образом, вы настроите фьюзы микросхемы на работу при более высокой частоте.
Программирование микросхемы
Последним шагом будет программирование микросхемы при помощи Arduino IDE. Для этого нужно загрузить определения платы ATiny и драйвер TinyWireM I2C.
Для этого можно использовать коммерческий программатор ISP (стоит меньше £20) либо при наличии свободного Arduino Nano или Uno задействовать его (подробно об этом можно почитать в статье Programming Microcontrollers).
Низкое энергопотребление
Компоненты TinyPhoto подобраны с учетом экономии энергии. ATiny85 требуется всего 3мА. Oled-дисплей потребляет 5мА при отображении фото 64х64px и 10мА при отображении полноэкранного фото размером 128х64px. При среднем потреблении 10мА TinyPhoto способен работать 22 часа от «таблетки» CR2032, 3В, 225мАч.
Результат
Результат можно пронаблюдать на видео ниже.
Как отметил один из читателей, двухцветные желто/синий OLED-дисплей, который нашелся на тот момент у меня среди деталей, не лучший вариант, и для финальной версии лучше взять полностью белый или синий.
Детали проекта
Спецификация
- Микроконтроллер – Tiny85, 8 контактов DIP, 8 бит (1Кб SRAM, 8Кб Flash), работающий на 8МГц.
- Компактное оборудование – печатная плата 3 x 7см.
- Низкое энергопотребление – менее 10мА.
- Длительный срок службы батареи – питается от элемента питания типа «таблетка» 2032, 3В, 225 мАч; предполагается работа в течение 20+ часов.
- Требуется мало памяти: 300 байтов SRAM, 1.3Кб основная программа; максимум 1Кб на изображение.
- Дисплей – OLED 128×64 пикселей с интегрированным контроллером SSD1306 и протоколом I2C.
- Драйвер I2C – BroHogan 2011: TinyWireM.avr
Занятные факты
- Tiny85 использует всего какие-то 6Кб памяти (1Кб код и 5Кб данные), что в миллион раз меньше, чем 8Гб RAM, используемой в типичном ПК.
- TinyPhoto включается и отображает первую картинку сразу (в течение 200мс) после подачи питания.
- Скорость обновления достаточна (60Гц) для того, чтобы задержки были незаметны человеческому глазу.
Перечень этапов сборки и настройки
- Подобрать фотографию для показа. Ограничений по размеру и глубине цвета нет.
- С помощью IrfanView изменить размер до растрового изображения 128Х64 пикселя.
- С помощью Image to Binary преобразовать фото в hex-коды, предназначенные для драйвера SSD1306.
- Протестировать отображение фото, используя 3iForth.
- Если все работает как надо, сохранить hex-коды на Flash и считывать с Flash.
- Инициализировать OLED-дисплей, отправив необходимые команды драйверу микросхемы SSD1306 (нет нужды использовать раздутые драйверы AdaFruit SSD1306/GFX).
- Настроить I2C-связь между МК и драйвером микросхемы SSD1306, интегрированной в дисплей (актуально для процессоров ATiny85/84). Для процессоров на базе Atmega328P можно использовать встроенную библиотеку.
- Записать изображения и код на Tiny85, используя программатор ISP.
- Запустить устройство на 8МГц для отображения графики (пикселей) сплошным циклом.
Список деталей
Общая стоимость: £5.09 за 12 деталей (цены указаны на момент покупки и на данный момент ввиду рыночных флуктуаций могут отличаться).
- Микроконтроллер ATtiny85 (£1.50)
- OLED-дисплей 128×64px (£2.50, белый или синий)
- 2 конденсатора по 0.1uF для плавной подачи питания на Tiny85 и дисплей OLED (1p)
- Гнездо DIL на 8 контактов для Tiny85 (6p)
- «Таблетка» CR2032 на 3В(22p)
- Фиксатор батарейки CR2032 (5p)
- Зеленый светодиод 3мм (2p)
- Ограничивающий резистор на 1kОм для светодиода (1p)
- Движковый переключатель SPDT (2p)
- Печатная плата 3x7см (30p)
- 4 стойки платы, M2, M/F 8мм/6мм (5p каждая, 20p)
- 4 гайки, M2, F/F 6мм (5p каждая, 20p)
Код/Инструкции
Образцы изображений: бабочка и ягуар
1. butterfly_sm.bmp (цветное изображение бабочки после изменения размера, 114×64px).
2. jaguar.bmp (цветное изображение ягуара после изменения размера, 114×64px).
Код Forth:
Инструкции: этот код GForth загружает пиксельные данные из изображения бабочки и преобразует их в вертикальные байткоды, сохраняемые в файле TinyPhoto_data.avr, который Tiny85 отправляет на OLED-дисплей.
include 3iArt_rel.fs
include 3iArt-butterfly_rel.fs
butterfly
3. 3iArt_rel.fs (GForth) (содержит код Forth для дополнительных байтовых данных из матрицы пикселей).
4. 3iArt-butterfly_rel.fs (содержит входные данные матрицы пикселей для butterfly.bmp).
Код Си для микроконтроллера Tiny85 (Arduino)
Инструкции: скомпилировать TinyPhoto.avr в Arduino IDE, используя файлы платы ATtiny и драйвер BroHogan I2C TinyWireM. Загрузить на МК с помощью программатора ISP.
5. TinyPhoto.avr (скомпилируйте его в Arduino; измените путь, добавив *_data.avr)
6. Дополнение от 24 июля 2021 года: 3iFonts.avr (содержит определения шрифтов фиксированной ширины (8 высота х 5 ширина) для отображения на дисплее).
7. TinyPhoto_data.avr (содержит байткод изображения)
8. ATtiny_ArduinoBoardFiles.zip
9. ATtiny_I2C_driver_BroHogan2011.zip
Программатор ISP
Дополнено (июль 2021). Для программирования чипов с помощью Arduino IDE я собрал из трех микросхем простой программатор Atmel, оборудованный гнездами для подключения ATiny85 (DIP-8), ATiny84 (DIP-14) или Atmega328P (DIP-28). При этом он задействует Arduino Nano, который выполняет код ArduinoISP, позволяющий ему работать в качестве встроенного программатора (ISP) для записи скомпилированного кода на целевые схемы. Его легко собрать на скромной печатной плате размером 4х6см с применением всего десятка компонентов для планарного монтажа. Общая стоимость деталей, включая Nano, составила £5.
Автор: Дмитрий Брайт