Горячее
Лучшее
Свежее
Подписки
Сообщества
Блоги
Эксперты
Войти
Забыли пароль?
или продолжите с
Создать аккаунт
Я хочу получать рассылки с лучшими постами за неделю
или
Восстановление пароля
Восстановление пароля
Получить код в Telegram
Войти с Яндекс ID Войти через VK ID
Создавая аккаунт, я соглашаюсь с правилами Пикабу и даю согласие на обработку персональных данных.
ПромокодыРаботаКурсыРекламаИгрыПополнение Steam
Пикабу Игры +1000 бесплатных онлайн игр
Начните с маленькой подводной лодки: устанавливайте бомбы, избавляйтесь от врагов и старайтесь не попадаться на глаза своим плавучим врагам. Вас ждет еще несколько игровых вселенных, много уникальных сюжетов и интересных загадок.

Пикабомбер

Аркады, Пиксельная, 2D

Играть

Топ прошлой недели

  • AlexKud AlexKud 38 постов
  • SergeyKorsun SergeyKorsun 12 постов
  • SupportHuaport SupportHuaport 5 постов
Посмотреть весь топ

Лучшие посты недели

Рассылка Пикабу: отправляем самые рейтинговые материалы за 7 дней 🔥

Нажимая кнопку «Подписаться на рассылку», я соглашаюсь с Правилами Пикабу и даю согласие на обработку персональных данных.

Спасибо, что подписались!
Пожалуйста, проверьте почту 😊

Помощь Кодекс Пикабу Команда Пикабу Моб. приложение
Правила соцсети О рекомендациях О компании
Промокоды Биг Гик Промокоды Lamoda Промокоды МВидео Промокоды Яндекс Директ Промокоды Отелло Промокоды Aroma Butik Промокоды Яндекс Путешествия Постила Футбол сегодня

Arduino + Микроконтроллеры

С этим тегом используют

Электроника Ardublock Самоделки YouTube Своими руками Вертикальное видео Видео ВК Программирование Stm32 Радиолюбители Все
135 постов сначала свежее
230
monobogdan
monobogdan
Посты о ремонте и моддинге ретрогаджетов.
TECHNO BROTHER
1 год назад

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях!⁠⁠

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

Пожалуй, немалая часть моих читателей так или иначе интересуется DIY-тематикой. И в различных самодельных девайсах порой есть необходимость вывести какую-либо информацию на дисплей, будь это текст, графики или даже какая-то анимация! Для разных задач существуют самые разные дисплеи и в сегодняшнем материале я хотел бы систематизировать и собрать подробнейший гайд об использовании дисплеев с нерабочих мобильных телефонов: какие бывают протоколы и шины данных, как читать схемы устройств и определять контроллеры дисплеев, какие дисплеи стандартизированы, а какие придётся реверсить самому и как быть с подсветкой. В практической части статьи мы подключим дисплей используя протокол MIPI DBI к RP2040 с использованием DMA. Интересно? Тогда добро пожаловать в статью!

❯ Виды дисплеев и их протоколы


Пожалуй, ЖК-дисплеи с самого момента их появления стали основным инструментом для вывода информации и взаимодействия с пользователями. Первые ЖК-панели были монохромными и требовали отдельный драйвер, который занимался выводом изображения на экран и формированием необходимых для его работы напряжений.

Сейчас же всё гораздо проще и каждый любитель DIY-электроники может и сам подключить дисплейчик к своему проекту и использовать в необходимых ему целях. Ведь не зря написаны десятки библиотек по типу AdaFruit LCD, которые упрощают задачу программисту и дают ему возможность оперировать готовыми и простыми операциями по типу «вывести линию» или «отрисовать изображение». Однако, готовые библиотеки — это, конечно, здорово, но они не всегда дают понимание о том, как работают такие дисплеи на программном и аппаратном уровне. И первая часть статьи как раз и будет посвящена этому.

Всего в мире дисплейных матриц существует несколько общепринятых аппаратных протоколов. Некоторые из них можно легко использовать в собственных проектов с микроконтроллерами, с другими придется повозиться:

  • Параллельная шина 8080 — одна из самых простых и понятных шин данных, как в теории, так и на практике. Суть её очень простая: на каждый бит отводится по одной сигнальной линии, плюс две дополнительные линии для сообщения статуса передачи: RD означает запрос чтения, а WR — запрос на запись. Большинство дисплеев использует девятый, неявный бит D/C, который сообщает контроллеру, задаём ли мы номер команды, или уже пишем аргументы для этой команды. Что самое приятное — шина по сути стандартизирована и во многих дисплеях команды на старт записи в видеопамять, а также получение ID-контроллера идентичны. Шина бывает 8-битной и 16-битной (её состояние задаётся битами IM0..IM2 и используется не только для подключения дисплеев, но и микросхем параллельной флэш-памяти, ОЗУ и т. д. Такие шины используются в дисплеях с разрешением до 480x320.

  • SPI — шина, которая наверняка знакома большинству моих читателей. Достаточно простая — у нас есть две сигнальные линии с входным (MISO) и выходным (MOSI) битом, плюс сигнал тактирования, который согласовывает передачу данных. Таким образом, шина получается полнодуплексной. Фактически, каждый байт передаётся по одному биту через одну сигнальную линию, что, по сравнению с 8080, заставляет повышать тактовую частоту контроллера SPI, но при этом занимает гораздо меньше пинов самого МК или процессора. В программном плане, большинство дисплеев представленных в различных интернет-магазинах полностью совместимы с дисплеями 8080, ведь SPI — просто один из режимов работы. Единственный нюанс — из SPI дисплея не всегда можно вычитать ID-контроллера и вообще что-либо читать из регистров дисплея.

  • I2C — относительно редко используемая шина для дисплеев из-за её невысокой производительности, однако, тем не менее, очень подходящая для МК (благодаря использованию только двух сигнальных линий — SDA для данных и SCL для тактирования. Даже чипселект здесь программный благодаря тому, что каждое устройство имеет собственный адрес!), однако её можно найти в дисплеях некоторых телефонов из самого начала 2000-х годов.

  • TTL/параллельный RGB — тут, в общем-то, меня упрекали пару раз из-за того, что я продолжаю называть её TTL, но так сложилось исторически — даже в даташитах эту шину называют именно так. С логической точки зрения она очень простая: у нас есть 16/24 сигнальные линии, где 5 (или 8) бит используются для красного и синего канала и 6 (или опять же 8) бит используются для зеленого цвета (т. е. в 16-битном цвете у нас RGB565, а в 24-битном — RGB888). К ним идут сигналы HSYNC для горизонтальной синхронизации и VSYNC для вертикальной. Вообще, необязательно использовать все сигнальные линии предоставляемые дисплеем — можно использовать, например, RGB332 и использовать всего 8 сигнальных линий. Однако для отображения картинки, необходимо строго соблюдать тайминги синхронизации, иначе дисплей будет просто показывать белый цвет. Помимо цифрового варианта, бывает также аналоговый, очень похожий на телевизионный RGB или VGA. Такие дисплеи обычно используются для матриц до 1024x768 включительно.

  • MIPI DSI — протокол, используемый для дисплеев высокого разрешения — от 480x800 и выше, его можно встретить в большинстве современных смартфонов и планшетов. Кроме того, такие дисплеи используют относительно мало пинов — по два на каждый канал LVDS (обычно в смартфоне около двух-четырех каналов) + две сигнальные линии на тактирование. Звучит всё хорошо? Как-бы не так: протокол дифференциальный и на каждый канал (т. е. логический бит) приходится по две сигнальные линии — одна с положительная, а вторая отрицательная. Затем одна вычитается из другой и получается окончательный сигнал, а сделано это для уменьшения помех от передачи данных по нескольким линиям с очень высокой тактовой частотой без увеличения битности шины.

  • LVDS/eDP — Протоколы, используемые в матрицах ноутбуков, телевизоров и иногда планшетов. На физическом уровне близки к DSI, на программном — если честно, не знаю, но наслышан о некой стандартизации и высоком уровне совместимости. Даже «неродные» ноутбучные матрицы вполне «заводятся», максимум после перепрошивки родной EEPROM, даже если дисплей другого разрешения!


В списке выше, мы рассмотрели несколько популярных аппаратных шин для дисплеев. В данной статье, мы разберемся в программных особенностях таких дисплеев и узнаем, где взять по дисплею одного из следующих типов: SPI, I2C, а также 8080.

❯ Виды дисплеев и их протоколы


Пожалуй, писать статью, где были бы только готовые примеры без объяснения принципов работы «под капотом» было бы плохим тоном. Поэтому предлагаю немного разобраться в системе команд для самых распространенных контроллеров дисплеев в наше время.

У рассматриваемых нами дисплеев есть собственная видеопамять, благодаря чему нет необходимости соблюдать тайминги, а также общий набор команд (или аппаратных регистров), которые мы можем записывать и тем самым менять поведение дисплея. Если мы просто подадим питание на дисплей и попытаемся что-то вывести — у нас ничего не выйдет, поскольку при каждом аппаратном RESET'е, состояние большинства регистров, кроме SleepOn и PowerOn не определено и может содержать в себе любой «мусор». Для корректной работы дисплея, нам необходимо послать определенный набор команд, называемый инициализацией, который установит настройки драйвера дисплея, такие как контраст, параметры цветности, направление развертки изображения из VRAM и т. д. Пожалуй, стоит сразу отметить, что некоторые люди называют регистры дисплея командами — это означает одно и тоже!

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

Пример инициализации. На самом деле, не все люди делают такую простыню из вывозов функций чтения/записи регистров дисплея, поскольку это кушает драгоценный ROM. На AVR, например, команды инициализации можно хранить в ROM и читать из PROGMEM.

Если дисплей инициализирован неправильно, то мы можем наблюдать некорректную развертку, артефакты на дисплее и полосы: если вы когда-нибудь прошивали смартфоны прошивками других ревизий, то могли замечать подобный эффект сами.

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

Набор команд для контроллеров дисплеев частично стандартизирован спецификацией MIPI DBI, которая описывает и закрепляет некоторые конкретные адреса регистров, общие для всех контроллеров дисплея. К ним относится, например, установка «окна» для записи (0x2B и 0x2A), sleepout (0x11) и некоторые другие. Проприетарными командами остаются настройки питания, развертки, контраста и самого драйвера дисплея. Ну и всяческие LUT, а также палитровые режимы (если они есть) тоже проприетарные.

Пример одной из таких стандартизированных команд:

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

Почти во всех дисплеях есть разделение отправляемых байтов на команду (или выборка номера регистра для чтения/записи) и на данные. Как обработать текущий байт определяет отдельный пин (или бит, в зависимости от конфигурации дисплея), называемый D/C (Data/Command), иногда также можно встретить названиеRS. Обычно, при записи команды, D/C должен быть на низком уровне, при записи данных, соответственно, на высоком. Суть простая: записываем номер команды (или регистра) при низком D/C, а затем дописываем необходимые аргументы (или конфигурацию регистра) при высоком уровне D/C.
Примерно так:

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

Касательно сброса, то в дисплеях обычно существуют два вида этого процесса: аппаратный сброс через соответствующий пин и программный с помощью специальной команды. Пин RESET никогда нельзя оставлять в «воздухе» (т. е. не подключенным) в надежде что «да состояние пинов МК после ресета известно, мусора на шине явно не будет». Мусора может и не будет, а вот дисплей упадет в вечный ресет, поскольку ожидает перехода сигнала RESET в высокий уровень. Тоже самое касается и пина CS, отвечающий за выбор устройства на шине. Если вам не нужен CS и у вас висит только одно устройство на шине — просто притяните его к массе. Некоторые контроллеры (например, ILI9325) адекватно реагируют на CS «в воздухе», некоторые — нет. Только после того, как RESET оказался на высоком уровне, дисплей начнёт принимать команды:

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

Переходим конкретно в выводу данных. Для начала вывода изображения на дисплей, нам необходимо выполнить команду 0x2C, которая переведет контроллер дисплея в режим записи данных в видеопамять. После этого, нам остаётся лишь установить высокий уровень на пине D/C и просто слать непрерывный поток пикселей. Контроллер дисплея сам инкрементирует координаты на дисплее и после того, как координаты выйдут за границы нужной области, дисплей сам их переведет в изначальные. Таким образом, достаточно лишь один раз проинициализировать дисплей и просто гонять в него данные, например, с помощью DMA.

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

Всё просто и понятно :)

❯ Дисплеи с шиной 8080


Пожалуй, подобные дисплеи найти проще всего, поскольку они использовались в большинстве кнопочных телефонов из нулевых. Такие экранчики можно встретить во многих моделях Nokia, Samsung, LG, Fly, Sony Ericsson и большинстве китайских телефонов. С поиском распиновки и разводкой таких дисплеев всё относительно просто и одновременно сложно: на некоторые модели телефонов (например, почти на все Nokia) можно свободно найти схему в гугле и узнать распиновку коннектора дисплея… однако этот коннектор сначала надо сдуть и развести на breakout-плате, или под микроскопом вывести перемычки. В некоторых случаях (например, Siemens S-серии), дисплей просто прижимался к контактам на плате, а сами контакты имели более чем паябельный шаг.

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

Из схемы на Nokia N70. Этот дисплей применялся во многих Symbian-смартфонах Nokia тех лет: N-Gage/N-Gage QD, N70, N72, 6600 и некоторых других.

Но особо удобными можно считать дисплеи с паябельными шлейфами с большим шагом пинов — такие можно встретить в некоторых телефонах Samsung и большинстве китайских телефонов. Пытливый читатель спросит «так это ж китаец, где ты на него схему будешь искать?». И вот тут, китайские производители нас приятно порадуют, поскольку за редким исключением, такие дисплеи имеют стандартизированную распиновку: лично мне известны матрицы 37 Pin, 39 Pin и 44 Pin. Как найти для них распиновку? Пишем на «алике» или «таобао» 37 pin lcd tft и смотрим: в описании продавец частенько прилагает распиновку (правда учтите, что 37 pin не имеет пинов IM для настройки ширины шины, а 16-битный интерфейс может быть слишком прожорилвый по числу пинов):

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост
Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

В случае с китайцами, иногда можно найти и схему (нажимайте на зеленую стрелку) на устройство: например, почти на все модели Fly схемы лежат в свободном доступе, где почти всегда можно найти распиновку дисплея. Иногда производитель даже выводит тестпоинты на все сигнальные линии и дисплей с тачскрином можно использовать, не выпаивая его с платы!

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

Распиновка на Fly IQ239. На нижней части изображения, вы можете увидеть, что такие, безусловно, здоровенные дисплеи можно купить за копейки и сейчас :)

Но задумывались ли вы когда-нибудь, откуда на тачскринах в дисплеях с «али» взялись кнопки «домой», «сообщения», «телефон»? Это ведь те самые дисплеи, которые использовались в «ноклах», просто припаянные к удобной плате! :) Кроме того, на китайские дисплеи без проблем можно найти даташит: обычно они используют контроллеры от ST или ILI, в зависимости от разрешения дисплея.

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост
Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

Кстати, про девайс на фото выше есть отдельная статья, где я рассказываю что такие девайсы необязательно дербанить но запчасти, ведь под них можно писать полноценные нативные программы!

Концептуально, аппаратная реализация протокола одновременно простая и понятна любому: программа устанавливает состояние каждого бита передаваемого байта на сигнальных линиях D0..D7 (либо D00..D15, если шина у нас 16-битная), а затем просто «дёргает» линию RD (Read или чтение), либо WR (Write или запись) по переходу из низкого уровня в высокий, благодаря чему контроллер дисплея понимает, что байт (или слово в случае 16-битного интерфейса) можно «забирать» с шины. По переходу из высокого уровня в низкий, контроллер снова переходит в режим ожидания следующего байта с шины.

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

Где взять такие дисплейчики? Да почти везде! Но лучше всего брать дисплеи с китайчиков, которые можно развести на вот таких breakout-платах, которые можно заказать на алике за пару сотен рублей.

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

Обратите внимание на то, как по свински припаивают подсветку на некоторых дисплеях. И это завод! Лучше сразу прозвоните прежде чем подавать питание. Я, вот, забыл, понадеялся на производителя и по итогу сжёг подсветку :(

Другой вопрос, где искать на них информацию? Помимо схем, можно просто поискать на алике «37 pin lcd tft», «39 pin tft lcd», «24 pin tft lcd» и т. п. Обычно продавцы сами выкладывают распиновку и даже прикладывают ID контроллера дисплея. Поскольку иногда различия в распиновках всё же попадаются, обращайте внимание на то, куда у вас идут дорожки от подсветки и от резистивного тачскрина (если есть), а также вызванивайте все пины с массой — это поможет подобрать правильную распиновку без логического анализатора. Вот, например, дисплейчик из китайской нерабочей реплики Nokia 130 с здоровым 2.4" дисплеем… казалось бы, вообще не понятно что за дисплей, однако воспользовавшись смекалкой, мы находим его распиновку!

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост
Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

❯ SPI-дисплеи


SPI-дисплеи в телефонах встречались относительно редко. В основном, подобные дисплейчики можно было найти в моделях начала 2000х годов: сименсах, моторолах, ранних сонериках T-серии и Nokia на S40. Иногда SPI-дисплеи можно встретить в современных кнопочных телефонах — обычно они имеют шлейф с менее чем 15 пинами, как некоторые модели Fly. Обычно контроллер дисплея поддерживал сразу несколько аппаратных шин, а производитель телефона ещё на этапе установки шлейфа к контроллеру дисплея замыкал необходимые IM-пины выбирая необходимую шину, поэтому программный протокол фактически идентичен дисплеям с шиной 8080.

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

Несомненным плюсом SPI-дисплеев можно назвать малое число пинов для работы с матрицей: достаточно всего два (плюс сигнал D/C, если дисплей не 9-битный), если повесить RESET на VIO, либо три (четыре), если хотите управлять аппаратным RESET вручную. Но есть и, в некоторой степени, минусы: например, не все микроконтроллеры умеют работать в 9-битном режиме и возможно последний бит придётся досылать «ногодрыгом» (что ломает любую возможность реализации DMA).

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

Многие дисплеи с этим интерфейсом задокументированы ещё в начале 2000х годов на известных форумах и сайтах, таких как VRTP, Радиокот и easyelectronics, поэтому проблем с их подключением не возникнет даже у новичка. Даже такой крутой и уважаемый дядька, как @DIHALT, когда-то писал полезный материал об использовании FSMC в STM32.

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

Достать их новыми можно и сейчас: различные магазины запчастей для телефонов бывают продают их по 20-30-40 рублей… Я недавно себе целую коробочку накупил, в том числе и просто для ремонта смартфонов для будущих статей :)

❯ I2C-дисплеи


Дисплеи с такой шиной — настоящая редкость и обычно попадались в телефонах самого начала нулевых годов с низким разрешением дисплея. Из известных мне — Ericsson'ы и ранние Sony Ericsson T-серии, ODM Motorola (головастики например) и… пожалуй всё.
Казалось бы, разве I2C может быть полезен для работы с дисплеями, где требуется активный вывод графики? Ведь он совсем медленный! Однако, даже он может пригодится для некоторых проектов, а в большинстве МК частенько попадается аппаратный TWI.

Кроме того, I2C дисплейчики удобно отлаживать: благодаря тому, что периферийное устройство должно отрапортовать ACK (состояние успешности получения байта) мастер-устройству, можно сразу определить обрыв линий до дисплея. Но какой-то конкретной информации по ним я не смогу написать — они все совсем разные :( Правда, полезным линком поделюсь, ребята с форума VRTP собрали хорошую таблицу с различными контроллерами дисплеев, где бывают и i2c!

❯ Подсветка


Отдельного радела стоит тема подсветки дисплеев. По первой может показаться, что тут всё просто: современным дисплеями достаточно 5В, а на старых можно замерить напряжение бустера на живом девайсе и смастерить свой DC-DC повышающий преобразователь, или взять, например, уже готовый драйвер, как известный в определенных кругах LTYN. На самом деле и тут есть свои нюансы.

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

Итак, каким образом реализована подсветка в том или ином устройстве? Обычно её реализация заключается в последовательном соединении двух и более светодиодов, которые формируют небольшую ленту под рассеивающей плёнкой. На современных китайских дисплейчиках, для работы в полную яркость достаточно всего лишь 5В источника питания + токоограничивающего резистора. Но что самое приятное, подсветка в таких дисплеях способна работать и при 3.3В, пусть менее ярко, но всё равно вполне читабельно.

Если вы делаете портативное маломощное устройство, работающее от одного Li-Ion аккумулятора, то достаточно лишь пустить 3.3В с линейного стабилизатора, который формирует напряжение VSYS для микроконтроллера. Таким образом, у вас будет стабильная подсветка среднего уровня яркости. В качестве альтернативного «бомж» варианта, когда нет возможности собрать нормальный драйвер подсветки, можно попробовать подключить светодиоды напрямую к АКБ, но при разряде дисплей будет потихоньку «тухнуть». Ещё один «бомж» вариант — разобрать дисплейный модуль, порезать дорожки на ленте и соединить пару светодиодов параллельно, выведя их через отверстие, откуда выходит шлейф дисплея, однако в таком случае, потребление подсветки заметно увеличится.

Правильным выходом будет взять с того-же телефона бустер подсветки с индуктивностью и иной необходимой обвязкой, и собрать бустер самому. Особой популярностью когда-то пользовались вышеупомянутые LTYN из телефонов Samsung (это маркировка известного драйвера LT1937). Уровнем подсветки на подобных бустерах телефоны управляют с помощью встроенного ШИМ-контроллера, чем можете воспользоваться и вы :)

❯ Запускаем дисплейчик на практике


В первой части статьи, я постарался ввести вас в курс дела и кратко рассказать о том, как работают такие дисплейчики «под капотом». Как видите — с теоретической точки зрения, ничего сложного нет: пересылаем данные на дисплей, да вовремя дёргаем пин D/C. Но какого же это на практике?


К сожалению, у меня на руках не нашлось подходящего дисплейчика от мобильного телефона (я ведь брал новые по уценке, не все заработали нормально), поэтому в качестве примера работы мы возьмём фактически такой же «китайский» дисплей с алика. Но будьте уверены — с большинством дисплеев, принцип работы будет идентичен (если мы говорим о дисплеях 2005г.в и моложе).

В качестве МК, мы возьмём мой любимый RP2040, который, по моему мнению, незаслуженно обделен вниманием. Время от времени я делаю всякие прикольные девайсы на базе этого МК, поэтому крайне рекомендую его всем моим читателям :)

Давайте же перейдем к практической части статьи!
Обычно при создании проекта, я просто клонирую с гита RPi сэмплы с уже готовыми файлами CMake, беру hello world, конфигурирую CMakeLists.txt и пишу свою программу. На малинке пока что нет такого удобного способа создания проекта, как idf.py create-project :)
Само собой, для удобства отладки я всегда включаю встроенную в чипсет эмуляцию UART через USB.

if (TARGET tinyusb_device)
add_executable(hello_usb
main.cpp
)

# pull in common dependencies
target_link_libraries(hello_usb pico_stdlib hardware_spi)

# enable usb output, disable uart output
pico_enable_stdio_usb(hello_usb 1)
pico_enable_stdio_uart(hello_usb 0)

# create map/bin/hex/uf2 file etc.
pico_add_extra_outputs(hello_usb)

# add url via pico_set_program_url
example_auto_set_url(hello_usb)
elseif(PICO_ON_DEVICE)
message(WARNING "not building hello_usb because TinyUSB submodule is not initialized in the SDK")
endif()

И инициализирую USB-стек и биндинги stdout к нему:

stdio_init_all();
sleep_ms(1000);

Задержка здесь важна, иначе девайс отказывается определятся в системе. Переходим, собственно, к разводке дисплея. Для работы нам достаточно лишь питания, подсветки, общей массы и четырёх сигнальных линий: MOSI, CLK, DC, RESET. На CS я обычно ставлю перемычку с массой, т. к обычно не вешаю что-то ещё на одну шину с дисплеем.

Переходим к инициализации дисплея. Наш экранчик работает на базе контроллера ST7735R и имеет разрешение 128x160. Сначала, назначаем функции для пинов и дёргаем RESET:

gpio_set_function(LCM_SPI_CLK, GPIO_FUNC_SPI);
gpio_set_function(LCM_SPI_MOSI, GPIO_FUNC_SPI);

// HW reset
gpio_init(LCM_RESET);
gpio_set_dir(LCM_RESET, true);
gpio_put(LCM_RESET, false);
sleep_ms(400);
gpio_put(LCM_RESET, true);

gpio_init(LCM_DC);
gpio_set_dir(LCM_DC, true);

spi_init(spi0, 105535000);

Весьма негусто скажете вы? Ну, с минорными изменениями, здесь заработает дисплейчик любого разрешения, даже 480x320! Переходим к фактической инициализации:

void lcmCommand(unsigned char byte)
{
gpio_put(LCM_DC, 0);
spi_write_blocking(spi0, &byte, sizeof(byte));
}

void lcmData(unsigned char byte)
{
gpio_put(LCM_DC, 1);
spi_write_blocking(spi0, &byte, sizeof(byte));
}

...

lcmCommand(0x11);
sleep_ms(120);
lcmCommand(0xB1);
lcmData(0x01);
lcmData(0x2C);
lcmData(0x2D);
lcmCommand(0xB2);
lcmData(0x01);
lcmData(0x2C);
lcmData(0x2D);
lcmCommand(0xB3);
lcmData(0x01);
lcmData(0x2C);
lcmData(0x2D);
lcmData(0x01);
lcmData(0x2C);
lcmData(0x2D);

lcmCommand(0xB4);
lcmData(0x07);

lcmCommand(0xC0);
lcmData(0xA2);
lcmData(0x02);
lcmData(0x84);
lcmCommand(0xC1);
lcmData(0xC5);
lcmCommand(0xC2);
lcmData(0x0A);
lcmData(0x00);
lcmCommand(0xC3);
lcmData(0x8A);
lcmData(0x2A);
lcmCommand(0xC4);
lcmData(0x8A);
lcmData(0xEE);

lcmCommand(0xC5);//VCOM
lcmData(0x0E);
lcmCommand(0x36);//MX, MY, RGB mode
lcmData(0xC8);

lcmCommand(0xe0);
lcmData(0x02);
lcmData(0x1c);
lcmData(0x07);
lcmData(0x12);
lcmData(0x37);
lcmData(0x32);
lcmData(0x29);
lcmData(0x2d);
lcmData(0x29);
lcmData(0x25);
lcmData(0x2b);
lcmData(0x39);
lcmData(0x00);
lcmData(0x01);
lcmData(0x03);
lcmData(0x10);
lcmCommand(0xe1);
lcmData(0x03);
lcmData(0x1d);
lcmData(0x07);
lcmData(0x06);
lcmData(0x2e);
lcmData(0x2c);
lcmData(0x29);
lcmData(0x2d);
lcmData(0x2e);
lcmData(0x2e);
lcmData(0x37);
lcmData(0x3f);
lcmData(0x00);
lcmData(0x00);
lcmData(0x02);
lcmData(0x10);
lcmCommand(0x2A);
lcmData(0x00);
lcmData(0x02);
lcmData(0x00);
lcmData(0x81);

lcmCommand(0x2B);
lcmData(0x00);
lcmData(0x01);
lcmData(0x00);
lcmData(0xA0);
lcmCommand(0x3A);//65k mode
lcmData(0x05);
lcmCommand(0x29);//Display on

// Set viewport
lcmCommand(0x2A);
lcmData(0 >> 8);
lcmData(0 & 0xFF);
lcmData(128 >> 8);
lcmData(128 & 0xFF);

lcmCommand(0x2B);
lcmData(0 >> 8);
lcmData(0 & 0xFF);
lcmData(160 >> 8);
lcmData(160 & 0xFF);

Прошиваем наш МК и смотрим что получилось. Видим шум на экране? Значит дисплей инициализирован верно!

После инициализации дисплея, мы можем выводить на него данные! Дабы дать возможность процессору заниматься другими делами во время передачи картинки на дисплей, мы настроим один из DMA-каналов. DMA-контроллер занимается пересылкой данных из ОЗУ в другой участок ОЗУ (аппаратный memcpy) или периферию. Как раз для второго случая, т. е. пересылки данных в контроллер SPI, мы и будем использовать DMA!

Аллокейтим фреймбуфер, куда мы будем выводить нашу картинку и настраивает DMA-канал:

int backBufSize = LCM_WIDTH * LCM_HEIGHT * 2 + 1;
backBuffer = (byte*)malloc(backBufSize);

printf("LCM: Setting up DMA channel...\n");
bulkDMAChannel = dma_claim_unused_channel(true);
cfg = dma_channel_get_default_config(bulkDMAChannel);
channel_config_set_transfer_data_size(&cfg, DMA_SIZE_8);
channel_config_set_dreq(&cfg, spi_get_dreq(spi0, true));

Переходим к выводу изображения на дисплей. Для того, чтобы просто установить цвет пикселя в любых координатах экрана, достаточно лишь посчитать смещение от начала указателя на фреймбуфер к определенным координатам экрана. Формула очень простая и понятная: ширина дисплея * Y-координата + x координата и результат предыдущих операций помноженный на число байт в одном пикселе.

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

__inline void pixelAt(short x, short y, short color)
{
if(x < 0 || y < 0 || x >= LCM_WIDTH || y >= LCM_HEIGHT)
return;

byte* col = (byte*)&color;
*((short*)&backBuffer[(y * 128 + x) * 2]) = color;
}

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

Теперь для вывода картинки, нам достаточно лишь скопировать изначальное изображение в наш фреймбуфер и попросить DMA-канал вывести изображение на дисплей. Для прозрачных картинок без альфа-канала (т. е. с цветовым ключом), функция будет выглядеть так:

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

А вот как с этим всем работать:

stdio_init_all();

sleep_ms(1000);


printf("LCM test by monobogdan\n");


lcmInitInterface();

lcmAllocBackBuffer();

lcmInit();


grDrawBitmapTransparent((void*)&pikabu, PIKABU_WIDTH, PIKABU_HEIGHT, 0, 0);

lcmFlush();


while(1)

{


}

Запускаем и...

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

Можно сделать чуть комплекснее, добавив альфа-блендинг и аффинные трансформации (возможность поворота и скейла картинок), но пока-что такой задачи не стоит. Ну что, всё очень просто и понятно? :) Пример прошивки можно найти на моём GitHub!

Производительность такого способ на RP2040 можно увидеть вот в этом видосе (на Пикабу не смог залить из-за ограничения на число медиа-элементов). Обратите внимание, что подход предложенный выше больше подходит именно для динамического вывода изображения без dirty-регионов. Он подойдет для игровых консолей, камер, анимаций или устройств с выводом динамической информации по типу осциллографов. Если вам нужно обновлять картинку реже, например, если вы делаете умные часы с плеером, то нет необходимости занимать довольно большой объем ОЗУ фреймбуфером, ведь вы можете писать напрямую в видеопамять. Тут уже решать в зависимости от конкретной ситуации именно вам :)

❯ Заключение


Вот мы с вами и систематизировали информацию о том, как использовать дисплеи с мобильных телефонов в своих проектах. Надеюсь, информация была достаточно полезной для вас!
Однако, у меня к вам просьба: пожалуйста, не «дербаньте» рабочие девайсы «на запчасти» :(
Это будет не очень гуманно по отношению к нашему «технобалдежу», где мы наоборот стараемся найти применение стареньким девайсам :)

Был ли для вас материал полезен? Пишите в комментариях.

Полезный материал?
Всего голосов:
Какие дисплейчики подключали?
Всего голосов:

❯ Важное объявление для читателей касательно будущей рубрики

Друзья! Я, как и многие мои читатели, помимо программирования и железа обожаю тачки! Особенно те тачки, где что-то нужно доделывать самому… и речь, конечно-же, о ТАЗах! Я долго думал, но всё же решился: сейчас я коплю на будущий интересный проект, связанный с ультрабюджетным электронным дооснащением автомобиля, который старше меня в полтора раза — скорее всего, речь пойдет о ВАЗ 2108/2109/21099, причём не исключено что карбюраторной! В планах довольно крутой проект, заключающийся в следующем: мы спроектируем очень дешевый бортовой компьютер (т.е панель) для управления автомобилем на базе дешевого Б/У планшета за пару сотен рублей. Планшет будет связан с управляющим МК через UART (о подобной коммуникации через хардварные протоколы я уже писал целых две статьи: сам себе Linux смартфон, превращаем планшет с нерабочим тачскрином в игровую консоль), и с планшета мы сможем не только управлять основными системами машины (стеклоподъемники, центральный замок и соленоид багажника), но и собирать и пытаться примерно посчитать некоторую информацию о расходе, километраже и стабильности работы двигателя на карбюраторной(!) машине без электронных систем с завода!

Если вдруг двигатель машины будет живенький и заводиться с полтычка, то может и удаленный прогрев постараюсь реализовать :)

В наши задачи будет входить не только проектирование аппаратной части такого оснащения, но и разработка симпатичного интерфейса для самой панели, дабы было не хуже чем в BMW :D Всеми схемами, исходным кодом и инструкциями я буду делится с вами в каждой статье и, как обычно, расскажу обо всех деталях реализации во всех подробностях! У меня уже есть некоторые идеи и наработки. Собственно, почему-б и не попробовать? Будет новая рубрика в блоге: апгрейд автомобилей глазами электронщика и прожженного программера.

Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях! Опрос, Гаджеты, Покупка, Программирование, C++, Raspberry Pi, Arduino, Дисплей, Экран, 2D, Графика, Embedded, Своими руками, Микроконтроллеры, Код, Электроника, Железо, Длиннопост

Фото не моё, из интернета

Если вам нравятся мои статьи, вас интересует развитие такой рубрики и у вас есть желание и возможность — можете помочь проекту копеечкой с помощью формы доната ниже. Пикабу позволяет остаться анонимным и донатить даже без регистрации. Сейчас у меня есть 40 тысяч рублей личных накоплений, на покупку самой машины планирую выделить 70-80 тысяч рублей (я живу в Краснодарском крае, так что здесь ещё есть шансы найти что-то +- живое за такие деньги), так что остаётся собрать около 30-35 тысяч рублей. За каждую копейку я готов отчитаться (по факту покупки машины я сделаю пост с фотографиями авто, ДКП, а также оглашу фронт будущих работ и сразу начну заниматься проектом).

Интересный проект с тазиком?
Всего голосов:
Показать полностью 25 3
[моё] Опрос Гаджеты Покупка Программирование C++ Raspberry Pi Arduino Дисплей Экран 2D Графика Embedded Своими руками Микроконтроллеры Код Электроника Железо Длиннопост
12
224
ryavknul
ryavknul
1 год назад
TECHNO BROTHER

Дикая природа удивительна⁠⁠

Стая диких ATmega328 нападает на малыша NE555

Дикая природа удивительна Фотография, Arduino Nano V3, Arduino, Микроконтроллеры, Электроника, Дикая природа, Странный юмор
[моё] Фотография Arduino Nano V3 Arduino Микроконтроллеры Электроника Дикая природа Странный юмор
36
128
monobogdan
monobogdan
1 год назад
TECHNO BROTHER

Выполняем сторонние программы на микроконтроллерах с Гарвардской архитектурой: как загружать программы без знания ABI?⁠⁠

Выполняем сторонние программы на микроконтроллерах с Гарвардской архитектурой: как загружать программы без знания ABI? Опрос, Гаджеты, Программирование, C++, Avr, Arduino, Esp32, Embedded, Своими руками, Самоделки, Esp8266, Assembler, Железо, Микроконтроллеры, Длиннопост

Зачастую в процессе разработки собственных устройств или моддинга уже существующих, встаёт задача выполнения стороннего кода: будь то ваши собственные программы с SD-флэшек, или программы, написанные другими пользователями с помощью SDK для вашего устройства. Тема компиляторов и кодогенерации достаточно сложная: чтобы просто загрузить ELF или EXE (PE) программу, вам нужно досконально разбираться в особенностях вашей архитектуры: что такое ABI, релокации, GOT, отличие -fPIE от -fPIC, как писать скрипты для ld и т. п. Недавно я копал SDK для первых версий Symbian и основываясь на решениях из этой ОС понял, каким образом можно сделать крайне «дешевую» загрузку любого нативного кода практически на любом микроконтроллере, совершенно не вникая в особенности кодогенерации под неё! Сегодня мы с вами: узнаем, что происходит в процессе загрузки программы ядром Linux, рассмотрим концепцию, предложенную Symbian Foundation и реализуем её на практике для относительно малоизвестной архитектуры — XTensa (хотя она используется в ESP32, детали её реализации «под капотом» для многих остаются загадкой). Интересно? Тогда добро пожаловать под кат!

❯ Как это работает?


Думаю, для многих моих читателей реализация процесса загрузки exe-программ и dll-библиотек в память процесса оставалась эдаким чёрным ящиком, в детали реализации которого вдаваться не нужно. Отчасти это так и есть: современные ОС разруливают процесс загрузки бинарников в память сами, не требуя от программиста вообще ничего, даже понимания того, куда будет загружена его библиотека или программа.

Выполняем сторонние программы на микроконтроллерах с Гарвардской архитектурой: как загружать программы без знания ABI? Опрос, Гаджеты, Программирование, C++, Avr, Arduino, Esp32, Embedded, Своими руками, Самоделки, Esp8266, Assembler, Железо, Микроконтроллеры, Длиннопост




Давайте для общего понимания вкратце разберемся, как происходит загрузка программ в Windows/Linux:

1. Система создаёт процесс и загружает в память программы секции из ELF/PE. Обычные программы для своей работы используют 3 секции: .text (код), .data (не-инициализированный сегмент памяти для глобальных переменных), .bss (сегмент памяти для инициализированных переменных). Каждому процессу выделяется собственное адресное пространство, называемое виртуальной памятью, которое не позволяет программе испортить память ядра, а также позволяет не зависеть от разметки физической памяти на выполняющей машине. Концепцию виртуальной памяти реализует специальной модуль в процессоре, называемый MMU.

2. Если бы наши программы не использовали никаких зависимостей в виде динамических библиотек, то на этом процесс загрузки можно было бы закончить: каждая программа имеет свой адрес загрузки, относительно которого линкер строит связи между обращениями к коду/данным программы. Фактически, для самых простых программ линкеру остаётся лишь прибавить адрес загрузки программы (например, 0x100) к каждому абсолютному обращению к памяти.
Однако современные программы используют десятки библиотек и для всех предусмотреть собственный адрес загрузки не получится: кто-то где-то всё равно будет пересекаться и вероятно, портить память. Кроме того, современные стандарты безопасности в Linux рекомендуют использовать позиционно-независимый код, дабы использовать преимущества ASLR (Address Space Layout Randomization, или простыми словами возможность загрузить программу в случайное место в памяти, дабы некоторые уязвимости, завязанные на фиксированном адресе загрузки программы перестали работать).

3. Поэтому для решения этой проблемы придуман т. н. динамический линкер, который уже на этапе загрузки программы или библиотеки патчит программу так, чтобы её можно было загрузить в любой участок памяти. Для этого используются данные, полученные от обычного линкера а этапе компиляции программы: помимо .text, .data и .bss, линкер создаёт секции .rel и .rel-plt, которые называются релокациями. Если объяснять совсем условно, то релокации — это просто запись вида «какой абсолютный адрес в коде программы нужно пропатчить» -> «на какое смещение его пропатчить». Самая простая релокация выглядит вот так:

Выполняем сторонние программы на микроконтроллерах с Гарвардской архитектурой: как загружать программы без знания ABI? Опрос, Гаджеты, Программирование, C++, Avr, Arduino, Esp32, Embedded, Своими руками, Самоделки, Esp8266, Assembler, Железо, Микроконтроллеры, Длиннопост

Где по итогу:

Выполняем сторонние программы на микроконтроллерах с Гарвардской архитектурой: как загружать программы без знания ABI? Опрос, Гаджеты, Программирование, C++, Avr, Arduino, Esp32, Embedded, Своими руками, Самоделки, Esp8266, Assembler, Железо, Микроконтроллеры, Длиннопост

.rel-plt же служит для резолвинга вызовов к dll/so: изначально программа ссылается на заранее определенные в процессе компиляции символы, которые уже в процессе загрузки патчатся на физические адреса функций из загруженной библиотеки.

И казалось бы — всё очень просто, пока в дело не вступают GOT (Global Offset Table — глобальная таблица смещений) и особенности реализации конкретного ABI. И ладно бы x86 или ARM, там всё разжевано и понятно, однако на других архитектурах начинаются проблемы и не всегда очевидно что и где за что отвечает.

А ведь чаще всего нужно просто загрузить небольшую программу, которой не нужны комплексные загрузчики: немного кода, немного данных и всё. И тут у нас есть три выхода:

  1. Писать полноценный загрузчик ELF-бинарников. ELF может оказаться громоздким для некоторых окружений и его реализация может оказаться тривиальной не для всех.

  2. Зарезервировать определенный сегмент в памяти (пусть с 0xFFF по 0xFFFF) и скомпилировать нашу программу с адресом загрузки 0xFFF с параметром -fno-pic. В таком случае, линкер сгенерирует обращения к памяти по абсолютным адресам — если переменная лежит по адресу 0xFFF, то программа будет обращаться сразу к этому адресу памяти, без необходимости что либо динамически линковать. Именно такой подход использовался во времена ZX Spectrum, Commodore 64 и MS-DOS (однако там роль «виртуальной памяти» выполняла такая особенность 8086, как сегменты). У такого подхода есть и минусы: относительная невозможность загрузки сразу нескольких программ одновременно, зарезервированное пространство линейно отъест небольшой кусок памяти у основной прошивки, нет возможности динамической аллокации секций. Зато такой код теоретически будет работать быстрее, чем PIC.

    Проблемы реализации такого способа: иногда нужно лезть в систему сборки основной прошивки и патчить скрипт линкера так, чтобы он не трогал определенный регион памяти. В случае esp32, например, это требует патча в сам SDK и возможного «откола» от мейнлайн дистрибутива.

  3. Использовать программу с относительной адресацией, однако без сегментов .bss и .data. Самый простой в реализации способ, который к тому же очень экономичен к памяти, позволяет загружать программу в любое место и пользоваться всеми фишками динамического аллокатора и не требует вмешательств в основную прошивку, кроме примитивного загрузчика программ. Именно его я и предлагаю рассмотреть подробнее.


Недавно мы сидели в чате ELF-сцены (разработка нативных программ под телефоны Siemens, Sony Ericsson, Motorola и LG с помощью хаков) и думали, как же можно реализовать загрузчик сторонних программ на практически неизвестных платформах. Кто-то предлагал взять ELF под основу — однако с его реализацией под некоторые платформы есть трудности, а кто-то предлагал писать «бинлоадер» — самопальный формат бинарников, который получается из, например, тех же эльфов.

Выполняем сторонние программы на микроконтроллерах с Гарвардской архитектурой: как загружать программы без знания ABI? Опрос, Гаджеты, Программирование, C++, Avr, Arduino, Esp32, Embedded, Своими руками, Самоделки, Esp8266, Assembler, Железо, Микроконтроллеры, Длиннопост

В это же время я копал SDK для Symbian и хорошо помнил, что в прикладных приложениях для этой ОС нет поддержки глобальных переменных вообще. Да, сегмент .data и .bss полностью отсутствует — переменные предлагается хранить в структурах. Почему так сделано? Всё дело в том, что каждая программа в Symbian — это dll-библиотека, которую загружает EKA и создаёт экземпляр CApaApplication. И дабы была возможность загрузить dll один раз для всех программ (что справедливо для системных библиотек), ребята полностью выкинули возможность использования любых глобальных переменных. А ведь идея интересная!

Однако в таком подходе есть несколько серьезных ограничений:

  • Отсутствие глобальных переменных может стать проблемой при портированиии уже существующего софта, хотя вашим программам ничего не мешает передавать в каждую функцию структуру с глобальным стейтом, который можно при необходимости изменять. Кроме того, нет ограничений на использование C++ (за исключением необходимости ручной реализации new/delete и отсутствием исключений).

  • Отсутствие преинициализированных данных. Вот это уже может стать относительно серьёзной проблемой, у которой, тем не менее, есть свои обходные решения. Например если вы храните команды для инициализации дисплея в таблице, или какие-либо калибровочные данные — вы не сможете их объявить, просто используя инициализаторы в C. Тоже самое касается и строковых литерал. Тут есть два варианта: часть таблиц можно вынести на стек (если эти самые таблицы достаточно маленькие), либо подгружать необходимые данные из бинарника с помощью основной прошивки (например, LoadString и т. п.).


Давайте же на практике посмотрим, имеет ли право на жизнь такой подход!

❯ Практическая реализация


Формат нашего бинарника будет до безобразия прост: небольшой заголовок в начале файла и просто сырой дамп сегмента .text, который можно экспортировать из полученного elf даже без необходимости писать скрипт для линкера. При этом нужно учесть, что ESP32 — это микроконтроллер частично Гарвардской архитектуры, т. е. шина данных и кода у него расположены отдельно. Однако у чипа есть полноценный MMU, который позволяет маппить регионы физической памяти в виртуальную память, чем мы и воспользуемся в итоге!

Заголовок нашего бинарника будет выглядеть вот так:

Выполняем сторонние программы на микроконтроллерах с Гарвардской архитектурой: как загружать программы без знания ABI? Опрос, Гаджеты, Программирование, C++, Avr, Arduino, Esp32, Embedded, Своими руками, Самоделки, Esp8266, Assembler, Железо, Микроконтроллеры, Длиннопост

Программа общается с основной прошивкой посредством псевдо-syscall'ов: функции, которая в качестве первого аргумента ожидает номер нужной службы и один 32х-битный указатель для описания структуры с параметрами. Реализация syscall'ов — одна из самых простых и неприхотливых с точки зрения обратной совместимости с будущими прошивками.

Выполняем сторонние программы на микроконтроллерах с Гарвардской архитектурой: как загружать программы без знания ABI? Опрос, Гаджеты, Программирование, C++, Avr, Arduino, Esp32, Embedded, Своими руками, Самоделки, Esp8266, Assembler, Железо, Микроконтроллеры, Длиннопост

Концептуально всё очень просто: GetGlobalStateSize сообщает нашему загрузчику размер структуры для хранения глобального стейта, в то время как Start уже фактически заменяет main() в нашей программе. Необходимости в crt0 нет, поскольку весь необходимый инит выполняет бутлоадер ESP32. Впрочем, при желании вы можете выделить отдельный стек для вашей программы — это повысит надежность, если выполняемая программа удумает испортить стек.

Выполняем сторонние программы на микроконтроллерах с Гарвардской архитектурой: как загружать программы без знания ABI? Опрос, Гаджеты, Программирование, C++, Avr, Arduino, Esp32, Embedded, Своими руками, Самоделки, Esp8266, Assembler, Железо, Микроконтроллеры, Длиннопост

Собираем нашу программу:

xtensa-esp32-elf-cc.exe test.c -fno-pic -nostdlib -nostartfiles -Wl,--section-start=.text=0x0

xtensa-esp32-elf-objcopy.exe --only-section=.text --output-target binary a.out run.bin

-fno-pic отключает генерацию кода, зависимого от GOT, -nostdlib и -nostartfiles убирает из билда crt0 и stdlib, благодаря чему мы получаем только необходимый код. --section-start задает смещение для загрузки секции .text на 0x0 (в идеале это делать необходимо из скрипта для ld).
objcopy скопирует из полученного ELF только необходимую нам секцию .text.

Как же это работает на практике? Давайте дизассемблируем выходной бинарник и посмотрим, что у нас дает на выхлопе cc:

Выполняем сторонние программы на микроконтроллерах с Гарвардской архитектурой: как загружать программы без знания ABI? Опрос, Гаджеты, Программирование, C++, Avr, Arduino, Esp32, Embedded, Своими руками, Самоделки, Esp8266, Assembler, Железо, Микроконтроллеры, Длиннопост

Обратите внимание, что Start вызывает подфункции с помощью инструкции CALLX8, которая в отличии от обычного Immediate-версии CALL8, выполняет переход относительно текущего адреса в PC, благодаря чему переход полностью независим от адреса загрузки программы в памяти. А благодаря тому, что все данные, в том числе и указатель на глобальный стейт передаются через стек, нет необходимости релокейтить сегменты данных.

По итогу всё, что нужно от загрузчика бинарников — это загрузить программу в память для инструкций, выделить память для структуры с стейтом программы и передать управление Start. Всё!
Конкретно в случае ESP32, у нас есть два возможных решения задачи загрузки программы в память:

  1. Загрузить программу в IRAM. Такая возможность теоретически есть, однако на практике загрузчик ESP32 устанавливает права только на чтение и выполнение на данный регион памяти. Попытка что-то скопировать туда закончится исключением SIGSEGV. Кроме того, сегмент IRAM относительно небольшой — всего около 200Кб.

  2. Самопрограммирование. Для этого, в esp32 есть два механизма — Partition API и SPI Flash API. Я выбрал Partition API для простоты реализации.


Для нашей прошивки необходимо будет переразметить флэш-память. Для этого запускаем idf.py menuconfig, идём в Partition Table -> Custom partition table CSV. Создаём в папке проекта partitions.csv, куда пишем:

# ESP-IDF Partition Table
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
executable, data, undefined, 0x110000, 0x10000

Для заливки программы можно использовать соответствующее Partition API, либо parttool.py:

parttool.py --port "COM41" write_partition --partition-name=executable --input "run.bin"

Переходим к загрузчику программы:

Выполняем сторонние программы на микроконтроллерах с Гарвардской архитектурой: как загружать программы без знания ABI? Опрос, Гаджеты, Программирование, C++, Avr, Arduino, Esp32, Embedded, Своими руками, Самоделки, Esp8266, Assembler, Железо, Микроконтроллеры, Длиннопост

Прошиваем ESP32:

idf.py build

idf.py flash

idf.py monitor

И смотрим результат:

SysCall 25

SysCall 35

SysCall 15

Всё работает!

❯ Заключение


Как видите, ничего сложного в выполнении сторонних программ при условии соблюдении некоторых ограничений нет. Да, в таком подходе есть как серьезные плюсы, так и минусы, однако он делает своё дело и позволяет реализовать запуск игр на кастомных игровых консолях, или сторонних программ на самодельных компьютерах. Ну и конечно же не стоит забывать про плагины! Авось в вашем решении нужна возможность расширения функционала устройства, однако предоставлять исходный код или даже объектные файлы нет возможности — тогда вам может пригодится и такая методика.

Пожалуй, стоит упомянуть ещё один… очень своеобразный метод, который я иногда встречаю при реализации самодельных компьютеров. Люди пишут… эмуляторы 6502/Z80 :)
И если такой подход ещё +- применим к ESP32, то в AVR просадки производительности будут слишком серьезными. Так зачем, если можно использовать все возможности ядра на максимум?

Полезный материал?
Всего голосов:
Приходилось ли загружать сторонний код в ваших устройствах?
Всего голосов:
Показать полностью 9 2
[моё] Опрос Гаджеты Программирование C++ Avr Arduino Esp32 Embedded Своими руками Самоделки Esp8266 Assembler Железо Микроконтроллеры Длиннопост
12
17
sergsv1
1 год назад

Плата разработчика LILYGO® TTGO T-Display ESP32 Development Board WiFi и Bluetooth модуль с дисплеем⁠⁠

Плата разработчика LILYGO® TTGO T-Display

Очень удобный модуль разработчика. На основе микроконтроллера esp32 с дисплеем, а также со многими дополнительными модулями. Как замена популярных плат Arduino.

Для вас новинка:

Плата разработчика LILYGO® TTGO T-Display ESP32 Development Board WiFi и Bluetooth модуль с дисплеем Электроника, Электрика, Arduino, Esp8266, Esp32, Микроконтроллеры, Микрокомпьютер, Радиоэлектроника, Радиотехника, Радиоуправление, Радиолюбители, Умный дом, Интернет вещей, Длиннопост

Это плата позволяет очень быстро собрать какое-то конечное устройство. Особенно если оно у вас было реализовано на модуле Arduino и вы решили это переделать на более мощную и новую платформу.

Плата разработчика LILYGO® TTGO T-Display ESP32 Development Board WiFi и Bluetooth модуль с дисплеем Электроника, Электрика, Arduino, Esp8266, Esp32, Микроконтроллеры, Микрокомпьютер, Радиоэлектроника, Радиотехника, Радиоуправление, Радиолюбители, Умный дом, Интернет вещей, Длиннопост

Модуль TTGO T-Display ESP32 WiFi Bluetooth с контроллером ESP32, цветным дисплеем и схемой зарядки и питания от литиевого аккумулятора. Позволяет быстро собрать макет устройства сбора, отображения и обработки информации с датчиков. Использование контроллера ESP32 и схемы зарядки позволит собрать автономные и портативные устройства для которых важны быстродействие, малые размеры и малое потребление тока.

Характеристики:

  • Чипсет: ESPRESSIF-ESP32 240MHz Xtensa® двухядерный 32-бит LX6 микропроцессор

  • Память программ: QSPI flash 16МБ

  • Оперативная память:520 КБ SRAM

  • Кнопки: Сброс

  • Конвертер USB в TTL: CH9102

  • Интерфейсы: UART, SPI, SDIO, I2C, LED PWM, TV PWM, I2S, IRGPIO,ADC, интерфейс емкостного экрана, DACLNA предусилитель

  • Дисплей: IPS ST7789V 1.14 дюйма

  • Рабочее напряжение: 2.7В — 4.2В

  • Рабочий ток: примерно 60мА

  • Ток в спящем режиме: 120мкА

  • Диапазон рабочих температур: -40 ~ +85 °C

  • Размеры: 51.52 x 25.04 x 8.54мм

  • Питание модуля:

    • Источник питания: USB 5В/1А

    • Ток заряда аккумулятора: 500мА

    • Аккумулятор: 3.7В литиевый с JST разъёмом

    • Разъём питания: 2х контактный шаг 1.25мм

    • USB разъём: Type-C

  • Wi-Fi характеристики:

    • Стандарт: FCC/CE-RED/IC/TELEC/KCC/SRRC/NCC

    • Протоколы: 802.11 b/g/n (802.11n, скорость до 150Mbps) A-MPDU и A-MSDU полимеризация 0.4мкс

    • Частотный диапазон: 2.4ГГц ~ 2.5ГГц (2400МГц — 2483.5МГц)

    • Выходная мощность передатчика: 22dBm

    • Расстояние устойчивой связи: 300м

  • Bluetooth характеристики:

    • Протокол: Поддерживается bluetooth V4.2BR/EDR и BLE стандарт

    • Чувствительность приемника: -97dBm NZIF Class-1, Cl ass-2 & Class-3 emitter AFH

Характеристики контроллера и интегрированных модулей

Плата разработчика LILYGO® TTGO T-Display ESP32 Development Board WiFi и Bluetooth модуль с дисплеем Электроника, Электрика, Arduino, Esp8266, Esp32, Микроконтроллеры, Микрокомпьютер, Радиоэлектроника, Радиотехника, Радиоуправление, Радиолюбители, Умный дом, Интернет вещей, Длиннопост

Характеристики встроенного дисплея и ещё некоторые доп. параметры

На борту контроллера встроен цветной LCD дисплей

Плата разработчика LILYGO® TTGO T-Display ESP32 Development Board WiFi и Bluetooth модуль с дисплеем Электроника, Электрика, Arduino, Esp8266, Esp32, Микроконтроллеры, Микрокомпьютер, Радиоэлектроника, Радиотехника, Радиоуправление, Радиолюбители, Умный дом, Интернет вещей, Длиннопост

Возможности по питанию

Плата имеет возможность использовать в качестве источника питания литиевой аккумулятор. Также она имеет контроллер заряда этих аккумуляторов.

Плата разработчика LILYGO® TTGO T-Display ESP32 Development Board WiFi и Bluetooth модуль с дисплеем Электроника, Электрика, Arduino, Esp8266, Esp32, Микроконтроллеры, Микрокомпьютер, Радиоэлектроника, Радиотехника, Радиоуправление, Радиолюбители, Умный дом, Интернет вещей, Длиннопост

Распиновка МОДУЛЯ

Расположение внешних выводов модуля микроконтроллера.

Многие выводы поддерживают различные функции.

Плата разработчика LILYGO® TTGO T-Display ESP32 Development Board WiFi и Bluetooth модуль с дисплеем Электроника, Электрика, Arduino, Esp8266, Esp32, Микроконтроллеры, Микрокомпьютер, Радиоэлектроника, Радиотехника, Радиоуправление, Радиолюбители, Умный дом, Интернет вещей, Длиннопост

Габаритные РАЗМЕРЫ

Габаритные размеры платы модуля а также расстояние между выводами

Плата разработчика LILYGO® TTGO T-Display ESP32 Development Board WiFi и Bluetooth модуль с дисплеем Электроника, Электрика, Arduino, Esp8266, Esp32, Микроконтроллеры, Микрокомпьютер, Радиоэлектроника, Радиотехника, Радиоуправление, Радиолюбители, Умный дом, Интернет вещей, Длиннопост

Ссылки: Статья с САЙТА : http://schip.com.ua/plata-razrabotchika-lilygo-ttgo-display/

Показать полностью 7
Электроника Электрика Arduino Esp8266 Esp32 Микроконтроллеры Микрокомпьютер Радиоэлектроника Радиотехника Радиоуправление Радиолюбители Умный дом Интернет вещей Длиннопост
7
89
d383838
2 года назад

Аналогово-ламповые штуки? Есть у меня их⁠⁠

Вижу тут поток пошел постов с приемниками и часами с ламповыми индикаторами.

Отмечусь и я.

Аналоговый регулятор громкости и выбора источника звука из начала 00х

Городился для усилителя Одисей-100У. Вот он на фото. Фото не мое. В усилителе ДУ не было изначально чем сильно напрягало. Делать какое-то электронное управление громкостью не хотелось т.к. везде очень большие искажения.

Аналогово-ламповые штуки? Есть у меня их Arduino, Электроника, Intel, Ламповость, Аналоговый звук, Сделано в СССР, Самоделки, Длиннопост, Микроконтроллеры

Это вам на ардуины с Сями и загрузчиками. Только хардкор. Ассемблер и УФ ПЗУ.

Аналогово-ламповые штуки? Есть у меня их Arduino, Электроника, Intel, Ламповость, Аналоговый звук, Сделано в СССР, Самоделки, Длиннопост, Микроконтроллеры

Шаговый электродвигатель от 3х фазного электросчетчика. Шестерни от него же.

Аналогово-ламповые штуки? Есть у меня их Arduino, Электроника, Intel, Ламповость, Аналоговый звук, Сделано в СССР, Самоделки, Длиннопост, Микроконтроллеры
Аналогово-ламповые штуки? Есть у меня их Arduino, Электроника, Intel, Ламповость, Аналоговый звук, Сделано в СССР, Самоделки, Длиннопост, Микроконтроллеры

Декодирование сигналов ИК управления аппаратное на К1506ХЛ2 с выдачей чистой команды в последовательном коде в процессор. Герконы на соплях временно т.к. программа не умела на тот момент считать до крайних положений.

До готового устройства контроллер не дожил совсем чуть чуть: квартиру обнесли и уперли усилитель и все остальное оставив винил и колонки.

И да, дурная голова рукам покоя не дает

Показать полностью 3
[моё] Arduino Электроника Intel Ламповость Аналоговый звук Сделано в СССР Самоделки Длиннопост Микроконтроллеры
16
78
3Dfsd2021
3Dfsd2021
2 года назад
TECHNO BROTHER

Как GhatGPT умеет общаться с микроконтроллерами⁠⁠

И меня не обошло сие новомодное поветрие. Нашел чат в телеграме с доступом к ChatGPT и стал думать: а что бы такое его спросить? Давайте сначала теста ради что-нибудь простенькое:

Как GhatGPT умеет общаться с микроконтроллерами Arduino, Эксперимент, Stm32, Си, Программирование, Микроконтроллеры, ChatGPT, Нейронные сети, Длиннопост

Потрясающе! Но может ли оно объяснить, что там в коде за что отвечает?

Как GhatGPT умеет общаться с микроконтроллерами Arduino, Эксперимент, Stm32, Си, Программирование, Микроконтроллеры, ChatGPT, Нейронные сети, Длиннопост

Обалдеть. Оно почти понимает. А вот интересно, оно умеет только стандартный Си?

Как GhatGPT умеет общаться с микроконтроллерами Arduino, Эксперимент, Stm32, Си, Программирование, Микроконтроллеры, ChatGPT, Нейронные сети, Длиннопост

Однако. Оно умеет под STM32, причем самым пионерским ардуиновским способом - считая такты процессора. Но, тем не менее, под SPL. Умеет ли оно использовать таймер?

Как GhatGPT умеет общаться с микроконтроллерами Arduino, Эксперимент, Stm32, Си, Программирование, Микроконтроллеры, ChatGPT, Нейронные сети, Длиннопост
Как GhatGPT умеет общаться с микроконтроллерами Arduino, Эксперимент, Stm32, Си, Программирование, Микроконтроллеры, ChatGPT, Нейронные сети, Длиннопост

Так, и что мы видим? Мы видим, что инициализировать таймер оно умеет. И с правильными значениями. Но в процедуре прерывания оно не использует! И вместо этого вводит дополнительную процедуру, считающую такты процессора.

Таймер же оно использует, чтобы сделать задержку в 1 секунду в главном цикле! Напоминает известный анекдот: как вскипятить пустой чайник? налить воду и поставить на огонь. а если в чайнике уже есть вода? Вылить и тем самым свести условия задачи к предыдущему :) Возможно, робот неправильно меня понял :)

Как GhatGPT умеет общаться с микроконтроллерами Arduino, Эксперимент, Stm32, Си, Программирование, Микроконтроллеры, ChatGPT, Нейронные сети, Длиннопост
Как GhatGPT умеет общаться с микроконтроллерами Arduino, Эксперимент, Stm32, Си, Программирование, Микроконтроллеры, ChatGPT, Нейронные сети, Длиннопост

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

Вердикт - человек пока что пишет программы под STM32 лучше этой штуки. Но эта штука пишет уже лучше ардуиновского пионера. Где-то и такой подход сойдет.

Показать полностью 7
[моё] Arduino Эксперимент Stm32 Си Программирование Микроконтроллеры ChatGPT Нейронные сети Длиннопост
14
194
monobogdan
monobogdan
2 года назад
TECHNO BROTHER

Сам себе игровая консоль: превращаем планшет с нерабочим тачскрином в игровой девайс из 8 кнопок и микроконтроллера⁠⁠

Сам себе игровая консоль: превращаем планшет с нерабочим тачскрином в игровой девайс из 8 кнопок и микроконтроллера Смартфон, Телефон, Идея, Своими руками, Arduino, Embedded, Встраиваемые системы, Планшет, Игры, Консоли, Самоделки, Моддинг, Android, Linux, Java, C++, Kernel, Покупка, Raspberry pi, Микроконтроллеры, Видео, Длиннопост

К сожалению, в наше время многие старые, но весьма неплохие по характеристикам гаджеты отправляются напрямую в помойку, и их владельцы не подозревают, что им можно найти применение. Сервер, мультимедийная-станция, да даже просто как TV-приставка — люди в упор не замечают сфер, где старенький планшет мог бы быть полезен. Но как быть, если посвящаешь жизнь портативным гаджетам, кодингу и копанию в железе? Правильно: сделать довольно мощную игровую консоль из старого планшета самому! Сегодня вам расскажу, как я сделал свою портативную приставку из планшета с нерабочим тачскрином, Raspberry Pi Pico и 8 кнопок! За рабочим результатом прячется несколько дней работы: поиск UART на плате, разработка контроллера геймпада на базе RPi Pico, написание приложения-сервиса, которое слушает события и отправляет их в подсистему ввода Linux в обход Android. Интересно? Тогда жду вас под катом!

❯ Мотивация


Прошло уже практически 10 лет с того момента, как у меня появилась моя первая портативная консоль. Несмотря на то, что я был заядлым ПК-игроком, я уже успел посмотреть на PS3 и PSP, но денег на их покупку у меня особо не было, да и к тому времени уже был в наличии Android-планшет. Но к моему 13-летию в 2014 году, когда я ходил и выбирал себе будущий девайс на день рождения, отец и мама решили подарить мне мою первую портативную консоль. Изначально, я уговаривал её купить мне целых два девайса, но бюджет был ограничен 4.000 рублей, а я хотел взять смартфон Fly IQ239 и консоль JXD S601 одновременно:

Сам себе игровая консоль: превращаем планшет с нерабочим тачскрином в игровой девайс из 8 кнопок и микроконтроллера Смартфон, Телефон, Идея, Своими руками, Arduino, Embedded, Встраиваемые системы, Планшет, Игры, Консоли, Самоделки, Моддинг, Android, Linux, Java, C++, Kernel, Покупка, Raspberry pi, Микроконтроллеры, Видео, Длиннопост


Однако, увидев здоровую 7-дюймовую консоль в магазине TREC (думаю, жители южной части РФ помнят такой), мама уговорила меня взять именно её, мотивируя это «ну и чего ты будешь тыкаться в этот мелкий экран? Возьми большую». После покупки гаджета, я был доволен: играл какие-то игрушки с ретро-платформ, устанавливал игры на Android, сидел в ВК через Kate Mobile. Что еще нужно было школяру? Однако, планшет прожил у меня недолго: с очередного лага я психанул и ударил по нему кулачком, унеся на тот свет и дисплей и тачскрин. Так консолька и пролежала в подвале около 8 лет. Впрочем, мне продолжали импонировать подобные устройства и в прошлом году я купил и написал про несколько подобных девайсов.

Сам себе игровая консоль: превращаем планшет с нерабочим тачскрином в игровой девайс из 8 кнопок и микроконтроллера Смартфон, Телефон, Идея, Своими руками, Arduino, Embedded, Встраиваемые системы, Планшет, Игры, Консоли, Самоделки, Моддинг, Android, Linux, Java, C++, Kernel, Покупка, Raspberry pi, Микроконтроллеры, Видео, Длиннопост



Несколько месяцев назад, мой читатель Кирилл Севостьянов с Хабра прислал мне HTC HD2 в качестве донора и планшет Prestigio PMP7170B3G, который был рабочим, но… у него отказал тачскрин. Я всё думал, чего бы с ним сделать и решил реализовать игровую консольку своими руками из подручных средств. Идея крутилась в голове довольно давно, но реализовал я её только сейчас.

❯ Что нам нужно сделать?


Итак, что должно быть у портативной консоли? Чипсет, дисплей, звук, ОС — это всё нам уже предоставляет планшет. Нам остаётся лишь сделать свой геймпад. Давайте подумаем, что нам будет нужно для того, чтобы его сделать и передавать от него события на планшет:

  • Контроллер для геймпада: тут нам подойдет практически любой микроконтроллер, который работает от 3.3в. Выбор большой: Arduino Pro Mini 3.3v, ESP32, RPi Pico. Я остановился на последнем: недавно я взял себе две штучки «пощупать» их — и они мне очень понравились!

  • Физический интерфейс: с планшетом нужно как-то общаться. У нас есть три варианта: USB (не факт, что поддержка преобразователей включена в ядре), UART и SPI/I2C на пятачках тачскрина (потребуют написания драйвера т. к. в android-устройствах нет прямого доступа к SPI/I2C из userland'а). Я остановился на UART: его легко найти на большинстве китайских планшетов, а если не получилось — то на помощь может прийти схема платы.

  • Программная реализация: как это будет работать? Я решил реализовать геймпад в виде сервиса на Android, который слушает состояния кнопок с UART и «инжектит» события напрямую в драйвер ввода. Таким образом, поддержка нашего геймпада появляется даже в самой системе — можно управлять менюшкой или приложениями как с клавиатуры!


    С планом определились, пора начать с программной части: сначала нам обязательно понадобится ROOT-доступ. Его получение на разных девайсах отличается — на prestigio уже был порт CWM и я просто поставил SuperSU. Без ROOT доступа мы не сможем использовать UART!

Сам себе игровая консоль: превращаем планшет с нерабочим тачскрином в игровой девайс из 8 кнопок и микроконтроллера Смартфон, Телефон, Идея, Своими руками, Arduino, Embedded, Встраиваемые системы, Планшет, Игры, Консоли, Самоделки, Моддинг, Android, Linux, Java, C++, Kernel, Покупка, Raspberry pi, Микроконтроллеры, Видео, Длиннопост


Теперь нам нужно найти пятачки UART на плате. Разведен он не везде, но в случае устройств на MediaTek — почти всегда, ещё и пятачки подписаны. На моём планшете он нашёлся сразу: был между двух металлических экранов и соответствовал 4-ому каналу UART. Получить к нему доступ можно в /dev/ttyMT3. Я использую ESP32 в качестве UART преобразователя: подпаиваемся к RX/TX, запускаем putty и заходим в adb shell. Определяем бодрейт (скорость) нашего UART порта — на MediaTek он обычно равен 921600, на других чипсетах — 115200. Пытаемся что-то вывести и хоба — мы уже можем «поболтать» с планшетом!

Сам себе игровая консоль: превращаем планшет с нерабочим тачскрином в игровой девайс из 8 кнопок и микроконтроллера Смартфон, Телефон, Идея, Своими руками, Arduino, Embedded, Встраиваемые системы, Планшет, Игры, Консоли, Самоделки, Моддинг, Android, Linux, Java, C++, Kernel, Покупка, Raspberry pi, Микроконтроллеры, Видео, Длиннопост

❯ Приложение-сервис


Итак, у нас уже есть доступ к UART и мы можем общаться с планшетом из внешнего мира. Но получить события с кнопок пол дела, нужно их ещё и послать в систему. Для этого есть целых три способа:

  1. InputManager.injectInputEvent — именно этим методом пользуется команда input, которую вы можете использовать через adb. Но увы, он работает только при наличие разрешения INJECT_EVENTS, который доступен только системным приложениям — находятся они в /system/app и подписаны тем же сертификатом, что и остальная прошивка.

  2. Модуль uinput дает возможность создать виртуальное устройство ввода и посылать события из userland'а — т. е. из прикладного приложения. У моего планшета было устройство /dev/uinput, но lsmod показывал, что сам модуль не загружен. Так что отметаем — он есть не везде.

  3. Прямой инжект событий в character устройство — весьма грязный хак, который позволяет инжектить события, не притворяясь системным приложением, но имеет некоторые ограничения. Именно его я и выбрал и о ограничениях ниже.


Сначала нам нужно узнать, какие кнопки поддерживают загруженные устройства ввода в системе. Для этого используем команду getevent -li. Там есть разные устройства ввода, в том числе и тачскрин (если вам нужно симулировать нажатия на экран), мне же подошёл драйвер физических кнопок mtk-kpd. Он занимается обработкой кнопок громкости, включения и т. п. Тут важно обратить внимание на то, что если попытаться послать кнопку, которое устройство не реализует (например пробел), то ничего не произойдет:

Сам себе игровая консоль: превращаем планшет с нерабочим тачскрином в игровой девайс из 8 кнопок и микроконтроллера Смартфон, Телефон, Идея, Своими руками, Arduino, Embedded, Встраиваемые системы, Планшет, Игры, Консоли, Самоделки, Моддинг, Android, Linux, Java, C++, Kernel, Покупка, Raspberry pi, Микроконтроллеры, Видео, Длиннопост



Инжект событий я писал на C, т. к. это требовало прямой записи input_event, а в Java прокинул его через Jni. Концепция простая: открываем устройство /dev/input/event2 и посылаем в него события ввода и синхронизации (это обязательно!), которые затем Android читает и обрабатывает:

#include <linux/uinput.h>

#include <fcntl.h>

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>

#include <android/log.h>

#include <jni.h>

int uinput;

extern "C" JNIEXPORT void JNICALL Java_com_monobogdan_inputservicebridge_InputNative_init(JNIEnv *env, jclass clazz) {

uinput = open("/dev/input/event2", O_WRONLY);

__android_log_print(ANDROID_LOG_DEBUG , "Test", uinput >= 0 ? "Open event OK" : "Failed to open event"); }

void emit(int fd, int type, int code, int val) {

struct input_event ie; ie.type = type;

ie.code = code; ie.value = val;

ie.time.tv_sec = 0;

ie.time.tv_usec = 0;

write(fd, &ie, sizeof(ie)); }

extern "C" JNIEXPORT void JNICALL Java_com_monobogdan_inputservicebridge_InputNative_sendKeyEvent(JNIEnv *env, jclass clazz, jint key_code, jboolean pressed) {

__android_log_print(ANDROID_LOG_DEBUG , "Test", "Send");

emit(uinput, EV_KEY, key_code, (bool)pressed ? 1 : 0);

emit(uinput, EV_SYN, SYN_REPORT, 0);

}

Основной обработкой занимается сервис, который я реализовал в отдельном потоке: он слушает события с UART и посылает соответствующие изменения состояния через sendKeyEvent. На вход приходят простые сообщения вида:

U L где U/D — нажато, не нажато, а L — однобайтовый идентификатор кнопки. В случае L — это влево, R — вправо и т. п. Вся доступная раскладка хранится в словаре. Причём само чтение из UART реализовано костылем с чтением «чужого» stdout, т. к. android-приложения не умеют сами по себе работать с root правами. В теории, это могло дать неприятный оверхед, но на практике никакого серьезного инпут лага это не создает. Не забываем сделать устройство event записываемым — ставим ему права 777:

package com.monobogdan.inputservicebridge;

public class InputListener extends Service {

private static final int tty = 3;

private InputManager iManager;

private Map<Character, Integer> keyMap;

private Method injectMethod;

private Process runAsRoot(String cmd)

{

try {

return Runtime.getRuntime().exec(new String[] { "su", "-c", cmd });

}

catch (IOException e)

{

e.printStackTrace();

return null;

}

}

@override

public void onCreate() {

super.onCreate();

// According to linux key map (input-event-codes.h)

keyMap = new HashMap<>();

keyMap.put('U', 103);

keyMap.put('D', 108);

keyMap.put('L', 105);

keyMap.put('R', 106);

keyMap.put('E', 115);

keyMap.put('B', 158);

keyMap.put('A', 232);

keyMap.put('C', 212);

InputNative.init();

try {

runAsRoot("chmod 777 /dev/input/event2").waitFor();

} catch (InterruptedException e) {

throw new RuntimeException(e);

}

Executors.newSingleThreadExecutor().execute(new Runnable() {

@override

public void run() {

Process proc = runAsRoot("cat /dev/ttyMT" + tty);

BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));

while(true)

{

try {

String line = reader.readLine();

if(line != null && line.length() > 0) {

Log.i("Hi", "run: " + line);

boolean pressing = line.charAt(0) == 'D';

int keyCode = keyMap.get(line.charAt(2));

Log.i("TAG", "run: " + keyCode);

InputNative.sendKeyEvent(keyCode, pressing);

}

}

catch(IOException e)

{

e.printStackTrace();

}

/*try {

Thread.sleep(1000 / 30);

} catch (InterruptedException e) {

e.printStackTrace();

}*/

}

}

});

}

@override

public IBinder onBind(Intent intent) {

return null;

}

}

Таким образом, если мы отправляем с ПК «D L» — система считает, что мы зажали стрелку влево, а U L — считает что мы отпустили. Но если mtk-kpd поддерживает стрелки и еще некоторые действия без каких либо проблем, то enter в список обрабатываемых кнопок не входит: придется мудрить! И тут нам приходит на помощь механизм трансляции кодов кнопок в действия: они хранятся в специальных файлах .kl в /system/usr/keylayout/. Я назначил DPAD_CENTER на… кнопку регулировки громкости звука! Ну, а почему бы и нет. :) Таким образом можно переназначить уже имеющиеся кнопки громкости на, например, start/select.

Сам себе игровая консоль: превращаем планшет с нерабочим тачскрином в игровой девайс из 8 кнопок и микроконтроллера Смартфон, Телефон, Идея, Своими руками, Arduino, Embedded, Встраиваемые системы, Планшет, Игры, Консоли, Самоделки, Моддинг, Android, Linux, Java, C++, Kernel, Покупка, Raspberry pi, Микроконтроллеры, Видео, Длиннопост

❯ Геймпад


После того, как сервис был готов и отлажен, нужно было реализовать хардварную часть проекта — сам геймпад. В качестве контроллера я, как уже говорил, выбрал Raspberry Pi Pico на базе МК RP2040 — бодреньком контроллере с двумя ARM Cortex-M0 ядрами. Стоит копейки, а в отличии от ESP'шек, его SDK не такое перегруженное и выглядит более приближенным к bare-metal.

Сам себе игровая консоль: превращаем планшет с нерабочим тачскрином в игровой девайс из 8 кнопок и микроконтроллера Смартфон, Телефон, Идея, Своими руками, Arduino, Embedded, Встраиваемые системы, Планшет, Игры, Консоли, Самоделки, Моддинг, Android, Linux, Java, C++, Kernel, Покупка, Raspberry pi, Микроконтроллеры, Видео, Длиннопост



На данный момент, я решил развести все кнопки на бредборде — макетной плате без пайки, т. к. макеток для пайки у меня под рукой не было. Сделал примитивный геймпад:

Сам себе игровая консоль: превращаем планшет с нерабочим тачскрином в игровой девайс из 8 кнопок и микроконтроллера Смартфон, Телефон, Идея, Своими руками, Arduino, Embedded, Встраиваемые системы, Планшет, Игры, Консоли, Самоделки, Моддинг, Android, Linux, Java, C++, Kernel, Покупка, Raspberry pi, Микроконтроллеры, Видео, Длиннопост



Развел на соответствующие GPIO:

Сам себе игровая консоль: превращаем планшет с нерабочим тачскрином в игровой девайс из 8 кнопок и микроконтроллера Смартфон, Телефон, Идея, Своими руками, Arduino, Embedded, Встраиваемые системы, Планшет, Игры, Консоли, Самоделки, Моддинг, Android, Linux, Java, C++, Kernel, Покупка, Raspberry pi, Микроконтроллеры, Видео, Длиннопост



И написал примитивную прошивку, которая отслеживает состояние кнопок. В прошивке точно так же есть словарь, задающий ассоциацию между физическими пинами и «виртуальными» кнопками. При нажатии или отжатии кнопки, программа изменяет стейт и отсылает новое состояние планшету.

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include "pico/stdlib.h"

#include "pico/time.h"

#include "hardware/uart.h"

struct keyMap

{

int gpio;

char key;

bool pressed;

int lastTick;

};

keyMap keys[] = {

{

15,

'L',

false,

0

},

{

14,

'U',

false,

0

},

{

13,

'D',

false,

0

},

{

12,

'R',

false,

0

},

{

11,

'E',

false,

0

},

{

10,

'B',

false,

0

},

{

20,

'A',

false,

0

},

{

21,

'C',

false,

0

}

};

#define KEY_NUM 8

int main() {

stdio_init_all();

uart_init(uart0, 921600);

gpio_set_function(PICO_DEFAULT_UART_TX_PIN, GPIO_FUNC_UART);

gpio_set_function(PICO_DEFAULT_UART_RX_PIN, GPIO_FUNC_UART);

sleep_ms(1000); // Allow serial monitor to settle

for(int i = 0; i < KEY_NUM; i++)

{

gpio_init(keys[i].gpio);

gpio_set_dir(keys[i].gpio, false);

gpio_pull_up(keys[i].gpio);

}

while(true)

{

int now = time_us_32();

for(int i = 0; i < KEY_NUM; i++)

{

char buf[5];

buf[1] = ' ';

buf[3] = '\n';

buf[4] = 0;

if(!gpio_get(keys[i].gpio) && !keys[i].pressed && now - keys[i].lastTick > 15500)

{

buf[0] = 'D';

buf[2] = keys[i].key;

puts(buf);

keys[i].lastTick = now;

keys[i].pressed = true;

continue;

}

if(gpio_get(keys[i].gpio) && keys[i].pressed && now - keys[i].lastTick > 15500)

{

buf[0] = 'U';

buf[2] = keys[i].key;

puts(buf);

keys[i].pressed = false;

keys[i].lastTick = now;

}

}

}

}

Собираем всё вместе и тестируем. Хоба, всё работает, мы можем перемещаться по менюшке используя наш геймпад!

Сам себе игровая консоль: превращаем планшет с нерабочим тачскрином в игровой девайс из 8 кнопок и микроконтроллера Смартфон, Телефон, Идея, Своими руками, Arduino, Embedded, Встраиваемые системы, Планшет, Игры, Консоли, Самоделки, Моддинг, Android, Linux, Java, C++, Kernel, Покупка, Raspberry pi, Микроконтроллеры, Видео, Длиннопост



А почему бы не попробовать поиграть в какую-нибудь игру? Ну мы же консоль вроде делаем: берём эмулятор NES, биндим кнопки в настройках и наслаждаемся игрой в Марио!

❯ Заключение


Реализация этого проекта заняла у меня не так уж и много времени: всего около 3-х дней работы по вечерам. Вероятно кто-то спросит: «а чего ты просто Bluetooth геймпад не купил?». Так это не прикольно ведь. Гораздо приятнее играть в девайс, к которому ты приложил руку сам. Более того, не у всех старых планшетов есть BT. Обошёлся на данной стадии проект недорого: планшет мне подарили бесплатно (точно также у вас дома может лежать подобный), RPi Pico — 350 рублей, кнопки по 10 рублей/штучка.

В целом, я сам по себе обожаю копаться в различных железках и их софтварной части (вспомнить хотя-бы статью про перекомпиляциюu-boot из вендорских исходников для нонейм консоли), а созидать что-то свое вообще вызывает какие-то нереальные всплески эндорфина — оно и понятно! :)

Однако несмотря на то, что мы уже имеем рабочий «прототип», проект далёк от завершения: я намерен довести его до конца и окончательно перевоплотить старый планшет в автономную игровую консоль (и рассказать об этом во второй части статьи). Для этого мне понадобится распечатать корпус и кнопки на 3D-принтере. К сожалению, у меня в городе ни у кого особо нет 3D-принтеров, поэтому начну копить на Ender 3, а от вас, читателей, с удовольствием почитаю мнение в комментариях и советы касательно выбора принтера!

Статья подготовлена при поддержке TimeWeb Cloud. Подписывайтесь на меня и @Timeweb.Cloud, чтобы не пропускать еженедельные статьи про моддинг различных гаджетов!

Показать полностью 10 1
[моё] Смартфон Телефон Идея Своими руками Arduino Embedded Встраиваемые системы Планшет Игры Консоли Самоделки Моддинг Android Linux Java C++ Kernel Покупка Raspberry pi Микроконтроллеры Видео Длиннопост
33
sergsv1
2 года назад

Самый Простой Цифровой ВОЛЬТМЕТР на микроконтроллере Ардуино - Arduino практическая реализация⁠⁠

Давайте попробуем разобраться а потом создать на практике самый простой цифровой вольтметр с использованием микроконтроллера Arduino.

В этом видео. Я как вы и просили хочу показать и рассказать где покупаю микроконтроллеры я.

Нам для этих целей даже не понадобится никакой индикатор все показания мы будем выводить на экран компьютера

Электроника YouTube Arduino Радиолюбители Радиоэлектроника Радиотехника Микроконтроллеры Видео
7
Посты не найдены
О нас
О Пикабу Контакты Реклама Сообщить об ошибке Сообщить о нарушении законодательства Отзывы и предложения Новости Пикабу Мобильное приложение RSS
Информация
Помощь Кодекс Пикабу Команда Пикабу Конфиденциальность Правила соцсети О рекомендациях О компании
Наши проекты
Блоги Работа Промокоды Игры Курсы
Партнёры
Промокоды Биг Гик Промокоды Lamoda Промокоды Мвидео Промокоды Яндекс Директ Промокоды Отелло Промокоды Aroma Butik Промокоды Яндекс Путешествия Постила Футбол сегодня
На информационном ресурсе Pikabu.ru применяются рекомендательные технологии