Мобильные экранчики в ваших проектах: большой и понятный о гайд о различных дисплеях!
Пожалуй, немалая часть моих читателей так или иначе интересуется 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 и т. д. Пожалуй, стоит сразу отметить, что некоторые люди называют регистры дисплея командами — это означает одно и тоже!
Пример инициализации. На самом деле, не все люди делают такую простыню из вывозов функций чтения/записи регистров дисплея, поскольку это кушает драгоценный ROM. На AVR, например, команды инициализации можно хранить в ROM и читать из PROGMEM.
Если дисплей инициализирован неправильно, то мы можем наблюдать некорректную развертку, артефакты на дисплее и полосы: если вы когда-нибудь прошивали смартфоны прошивками других ревизий, то могли замечать подобный эффект сами.
Набор команд для контроллеров дисплеев частично стандартизирован спецификацией MIPI DBI, которая описывает и закрепляет некоторые конкретные адреса регистров, общие для всех контроллеров дисплея. К ним относится, например, установка «окна» для записи (0x2B и 0x2A), sleepout (0x11) и некоторые другие. Проприетарными командами остаются настройки питания, развертки, контраста и самого драйвера дисплея. Ну и всяческие LUT, а также палитровые режимы (если они есть) тоже проприетарные.
Пример одной из таких стандартизированных команд:
Почти во всех дисплеях есть разделение отправляемых байтов на команду (или выборка номера регистра для чтения/записи) и на данные. Как обработать текущий байт определяет отдельный пин (или бит, в зависимости от конфигурации дисплея), называемый D/C (Data/Command), иногда также можно встретить названиеRS. Обычно, при записи команды, D/C должен быть на низком уровне, при записи данных, соответственно, на высоком. Суть простая: записываем номер команды (или регистра) при низком D/C, а затем дописываем необходимые аргументы (или конфигурацию регистра) при высоком уровне D/C.
Примерно так:
Касательно сброса, то в дисплеях обычно существуют два вида этого процесса: аппаратный сброс через соответствующий пин и программный с помощью специальной команды. Пин RESET никогда нельзя оставлять в «воздухе» (т. е. не подключенным) в надежде что «да состояние пинов МК после ресета известно, мусора на шине явно не будет». Мусора может и не будет, а вот дисплей упадет в вечный ресет, поскольку ожидает перехода сигнала RESET в высокий уровень. Тоже самое касается и пина CS, отвечающий за выбор устройства на шине. Если вам не нужен CS и у вас висит только одно устройство на шине — просто притяните его к массе. Некоторые контроллеры (например, ILI9325) адекватно реагируют на CS «в воздухе», некоторые — нет. Только после того, как RESET оказался на высоком уровне, дисплей начнёт принимать команды:
Переходим конкретно в выводу данных. Для начала вывода изображения на дисплей, нам необходимо выполнить команду 0x2C, которая переведет контроллер дисплея в режим записи данных в видеопамять. После этого, нам остаётся лишь установить высокий уровень на пине D/C и просто слать непрерывный поток пикселей. Контроллер дисплея сам инкрементирует координаты на дисплее и после того, как координаты выйдут за границы нужной области, дисплей сам их переведет в изначальные. Таким образом, достаточно лишь один раз проинициализировать дисплей и просто гонять в него данные, например, с помощью DMA.
Всё просто и понятно :)
❯ Дисплеи с шиной 8080
Пожалуй, подобные дисплеи найти проще всего, поскольку они использовались в большинстве кнопочных телефонов из нулевых. Такие экранчики можно встретить во многих моделях Nokia, Samsung, LG, Fly, Sony Ericsson и большинстве китайских телефонов. С поиском распиновки и разводкой таких дисплеев всё относительно просто и одновременно сложно: на некоторые модели телефонов (например, почти на все Nokia) можно свободно найти схему в гугле и узнать распиновку коннектора дисплея… однако этот коннектор сначала надо сдуть и развести на breakout-плате, или под микроскопом вывести перемычки. В некоторых случаях (например, Siemens S-серии), дисплей просто прижимался к контактам на плате, а сами контакты имели более чем паябельный шаг.
Из схемы на 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-битный интерфейс может быть слишком прожорилвый по числу пинов):
В случае с китайцами, иногда можно найти и схему (нажимайте на зеленую стрелку) на устройство: например, почти на все модели Fly схемы лежат в свободном доступе, где почти всегда можно найти распиновку дисплея. Иногда производитель даже выводит тестпоинты на все сигнальные линии и дисплей с тачскрином можно использовать, не выпаивая его с платы!
Распиновка на Fly IQ239. На нижней части изображения, вы можете увидеть, что такие, безусловно, здоровенные дисплеи можно купить за копейки и сейчас :)
Но задумывались ли вы когда-нибудь, откуда на тачскринах в дисплеях с «али» взялись кнопки «домой», «сообщения», «телефон»? Это ведь те самые дисплеи, которые использовались в «ноклах», просто припаянные к удобной плате! :) Кроме того, на китайские дисплеи без проблем можно найти даташит: обычно они используют контроллеры от ST или ILI, в зависимости от разрешения дисплея.
Кстати, про девайс на фото выше есть отдельная статья, где я рассказываю что такие девайсы необязательно дербанить но запчасти, ведь под них можно писать полноценные нативные программы!
Концептуально, аппаратная реализация протокола одновременно простая и понятна любому: программа устанавливает состояние каждого бита передаваемого байта на сигнальных линиях D0..D7 (либо D00..D15, если шина у нас 16-битная), а затем просто «дёргает» линию RD (Read или чтение), либо WR (Write или запись) по переходу из низкого уровня в высокий, благодаря чему контроллер дисплея понимает, что байт (или слово в случае 16-битного интерфейса) можно «забирать» с шины. По переходу из высокого уровня в низкий, контроллер снова переходит в режим ожидания следующего байта с шины.
Где взять такие дисплейчики? Да почти везде! Но лучше всего брать дисплеи с китайчиков, которые можно развести на вот таких breakout-платах, которые можно заказать на алике за пару сотен рублей.
Обратите внимание на то, как по свински припаивают подсветку на некоторых дисплеях. И это завод! Лучше сразу прозвоните прежде чем подавать питание. Я, вот, забыл, понадеялся на производителя и по итогу сжёг подсветку :(
Другой вопрос, где искать на них информацию? Помимо схем, можно просто поискать на алике «37 pin lcd tft», «39 pin tft lcd», «24 pin tft lcd» и т. п. Обычно продавцы сами выкладывают распиновку и даже прикладывают ID контроллера дисплея. Поскольку иногда различия в распиновках всё же попадаются, обращайте внимание на то, куда у вас идут дорожки от подсветки и от резистивного тачскрина (если есть), а также вызванивайте все пины с массой — это поможет подобрать правильную распиновку без логического анализатора. Вот, например, дисплейчик из китайской нерабочей реплики Nokia 130 с здоровым 2.4" дисплеем… казалось бы, вообще не понятно что за дисплей, однако воспользовавшись смекалкой, мы находим его распиновку!
❯ SPI-дисплеи
SPI-дисплеи в телефонах встречались относительно редко. В основном, подобные дисплейчики можно было найти в моделях начала 2000х годов: сименсах, моторолах, ранних сонериках T-серии и Nokia на S40. Иногда SPI-дисплеи можно встретить в современных кнопочных телефонах — обычно они имеют шлейф с менее чем 15 пинами, как некоторые модели Fly. Обычно контроллер дисплея поддерживал сразу несколько аппаратных шин, а производитель телефона ещё на этапе установки шлейфа к контроллеру дисплея замыкал необходимые IM-пины выбирая необходимую шину, поэтому программный протокол фактически идентичен дисплеям с шиной 8080.
Несомненным плюсом SPI-дисплеев можно назвать малое число пинов для работы с матрицей: достаточно всего два (плюс сигнал D/C, если дисплей не 9-битный), если повесить RESET на VIO, либо три (четыре), если хотите управлять аппаратным RESET вручную. Но есть и, в некоторой степени, минусы: например, не все микроконтроллеры умеют работать в 9-битном режиме и возможно последний бит придётся досылать «ногодрыгом» (что ломает любую возможность реализации DMA).
Многие дисплеи с этим интерфейсом задокументированы ещё в начале 2000х годов на известных форумах и сайтах, таких как VRTP, Радиокот и easyelectronics, поэтому проблем с их подключением не возникнет даже у новичка. Даже такой крутой и уважаемый дядька, как @DIHALT, когда-то писал полезный материал об использовании FSMC в STM32.
Достать их новыми можно и сейчас: различные магазины запчастей для телефонов бывают продают их по 20-30-40 рублей… Я недавно себе целую коробочку накупил, в том числе и просто для ремонта смартфонов для будущих статей :)
❯ I2C-дисплеи
Дисплеи с такой шиной — настоящая редкость и обычно попадались в телефонах самого начала нулевых годов с низким разрешением дисплея. Из известных мне — Ericsson'ы и ранние Sony Ericsson T-серии, ODM Motorola (головастики например) и… пожалуй всё.
Казалось бы, разве I2C может быть полезен для работы с дисплеями, где требуется активный вывод графики? Ведь он совсем медленный! Однако, даже он может пригодится для некоторых проектов, а в большинстве МК частенько попадается аппаратный TWI.
Кроме того, I2C дисплейчики удобно отлаживать: благодаря тому, что периферийное устройство должно отрапортовать ACK (состояние успешности получения байта) мастер-устройству, можно сразу определить обрыв линий до дисплея. Но какой-то конкретной информации по ним я не смогу написать — они все совсем разные :( Правда, полезным линком поделюсь, ребята с форума VRTP собрали хорошую таблицу с различными контроллерами дисплеев, где бывают и i2c!
❯ Подсветка
Отдельного радела стоит тема подсветки дисплеев. По первой может показаться, что тут всё просто: современным дисплеями достаточно 5В, а на старых можно замерить напряжение бустера на живом девайсе и смастерить свой DC-DC повышающий преобразователь, или взять, например, уже готовый драйвер, как известный в определенных кругах LTYN. На самом деле и тут есть свои нюансы.
Итак, каким образом реализована подсветка в том или ином устройстве? Обычно её реализация заключается в последовательном соединении двух и более светодиодов, которые формируют небольшую ленту под рассеивающей плёнкой. На современных китайских дисплейчиках, для работы в полную яркость достаточно всего лишь 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 координата и результат предыдущих операций помноженный на число байт в одном пикселе.
__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-канал вывести изображение на дисплей. Для прозрачных картинок без альфа-канала (т. е. с цветовым ключом), функция будет выглядеть так:
А вот как с этим всем работать:
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)
{
}
Запускаем и...
Можно сделать чуть комплекснее, добавив альфа-блендинг и аффинные трансформации (возможность поворота и скейла картинок), но пока-что такой задачи не стоит. Ну что, всё очень просто и понятно? :) Пример прошивки можно найти на моём GitHub!
Производительность такого способ на RP2040 можно увидеть вот в этом видосе (на Пикабу не смог залить из-за ограничения на число медиа-элементов). Обратите внимание, что подход предложенный выше больше подходит именно для динамического вывода изображения без dirty-регионов. Он подойдет для игровых консолей, камер, анимаций или устройств с выводом динамической информации по типу осциллографов. Если вам нужно обновлять картинку реже, например, если вы делаете умные часы с плеером, то нет необходимости занимать довольно большой объем ОЗУ фреймбуфером, ведь вы можете писать напрямую в видеопамять. Тут уже решать в зависимости от конкретной ситуации именно вам :)
❯ Заключение
Вот мы с вами и систематизировали информацию о том, как использовать дисплеи с мобильных телефонов в своих проектах. Надеюсь, информация была достаточно полезной для вас!
Однако, у меня к вам просьба: пожалуйста, не «дербаньте» рабочие девайсы «на запчасти» :(
Это будет не очень гуманно по отношению к нашему «технобалдежу», где мы наоборот стараемся найти применение стареньким девайсам :)
Был ли для вас материал полезен? Пишите в комментариях.
❯ Важное объявление для читателей касательно будущей рубрики
Друзья! Я, как и многие мои читатели, помимо программирования и железа обожаю тачки! Особенно те тачки, где что-то нужно доделывать самому… и речь, конечно-же, о ТАЗах! Я долго думал, но всё же решился: сейчас я коплю на будущий интересный проект, связанный с ультрабюджетным электронным дооснащением автомобиля, который старше меня в полтора раза — скорее всего, речь пойдет о ВАЗ 2108/2109/21099, причём не исключено что карбюраторной! В планах довольно крутой проект, заключающийся в следующем: мы спроектируем очень дешевый бортовой компьютер (т.е панель) для управления автомобилем на базе дешевого Б/У планшета за пару сотен рублей. Планшет будет связан с управляющим МК через UART (о подобной коммуникации через хардварные протоколы я уже писал целых две статьи: сам себе Linux смартфон, превращаем планшет с нерабочим тачскрином в игровую консоль), и с планшета мы сможем не только управлять основными системами машины (стеклоподъемники, центральный замок и соленоид багажника), но и собирать и пытаться примерно посчитать некоторую информацию о расходе, километраже и стабильности работы двигателя на карбюраторной(!) машине без электронных систем с завода!
Если вдруг двигатель машины будет живенький и заводиться с полтычка, то может и удаленный прогрев постараюсь реализовать :)
В наши задачи будет входить не только проектирование аппаратной части такого оснащения, но и разработка симпатичного интерфейса для самой панели, дабы было не хуже чем в BMW :D Всеми схемами, исходным кодом и инструкциями я буду делится с вами в каждой статье и, как обычно, расскажу обо всех деталях реализации во всех подробностях! У меня уже есть некоторые идеи и наработки. Собственно, почему-б и не попробовать? Будет новая рубрика в блоге: апгрейд автомобилей глазами электронщика и прожженного программера.
Фото не моё, из интернета
Если вам нравятся мои статьи, вас интересует развитие такой рубрики и у вас есть желание и возможность — можете помочь проекту копеечкой с помощью формы доната ниже. Пикабу позволяет остаться анонимным и донатить даже без регистрации. Сейчас у меня есть 40 тысяч рублей личных накоплений, на покупку самой машины планирую выделить 70-80 тысяч рублей (я живу в Краснодарском крае, так что здесь ещё есть шансы найти что-то +- живое за такие деньги), так что остаётся собрать около 30-35 тысяч рублей. За каждую копейку я готов отчитаться (по факту покупки машины я сделаю пост с фотографиями авто, ДКП, а также оглашу фронт будущих работ и сразу начну заниматься проектом).
Я в благородство играть не буду: как производители дешевых смартфонов закладывают срок службы в свои устройства
Во все времена существования мобильных телефонов, дешевый сегмент всегда оставался одним из самых прибыльных и массовых направлений мобильного бизнеса. Помимо «простозвонилок» в духе Nokia 1100 или 1202, на рынке есть огромный спрос к ультрабюджетным смартфонам ценой до 10 тысяч рублей. И если с дешевыми девайсами у локальных ритейлеров всё понятно (чипсеты 5+ летней давности, минимальный объём ОЗУ и ПЗУ, простенькие TN-матрицы низкого разрешения), то китайские магазины готовы предложить по этой цене устройства с небывало щедрыми характеристиками — и 8Gb RAM, и 512Gb ROM, и Snapdragon 888+. Для большинства покупателей неочевидно, что эти характеристики — обман, а девайс будет обладать лишь базовыми параметрами. Но что самое обидное, производитель закладывает программный и аппаратный срок службы в такие устройства, из-за чего более половины смартфонов выходят из строя через 4-5 месяцев после покупки, а в СЦ за ремонт просят половину цены от нового. Около года назад я купил почти новую китайскую реплику Huawei P30 Pro с родной коробкой и заводской плёнкой всего за 400 рублей, которая уже была не рабочей. Сегодня мы с вами: узнаем о том, как производители экономят и закладывают срок службы в бюджетные мобилки, на практике отремонтируем подобный девайс своими руками (причём ремонт обойдется нам в 70 рублей) и посмотрим, можно ли пользоваться таким бюджетником за 470 рублей на в 2023 на практике. Интересно? Тогда добро пожаловать под кат!
❯ Кто виноват и что нам делать?
Пожалуй, если сейчас зайти на любой маркетплейс и поискать бюджетный Android-смартфон, то мы увидим сотни приложений по вкусным ценам с какими-то небывалыми характеристиками для подобного ценового сегмента. Производители обещают топовые чипсеты Snapdragon, 8Гб DDR4 ОЗУ, 512Гб UFS ПЗУ и качественные IPS-дисплеи. А что самое интересное, эти смартфоны зачастую являются репликами крутых флагманских устройств и выглядят практически точь в точь как оригинальные девайсы.
Таким образом, производитель создаёт дополнительный психологический фактор к покупке такого бюджетного смартфона: «ведь он выглядит как флагман, характеристики флагманские, а чего б и не взять?». Принято считать, что эпоха реплик айфонов и самсунгов прошла лет 10 назад и никто не пытается выделиться за счёт дорогого флагмана, однако рынок точных копий всё ещё живёт и китайские производители продолжают выпускать реплики устройств Apple в огромных объёмах.
Заказав и получив новенький смартфон, возможны несколько реакций от новоиспеченного владельца, обычно в зависимости от его потребностей в мобильном девайсе. Если покупатель действительно ожидает флагманских характеристик от устройства, то тут его ждёт полное разочарование: на самом деле девайс имеет ультрабюджетные характеристики и работает на железе, в лучшем случае, семилетней давности. Нередки случаи выхода новых устройств на базе чипсета MediaTek MT6582 2013 года выпуска — более одиннадцатилетней давности! Огорчение ждёт пользователя и по части ОЗУ с постоянной памятью: зачастую производители ставят только 1Гб DDR2 памяти вместо обещанных 8Гб DDR4 и 8Гб постоянной памяти вместо 512Гб. В качестве ОС, вместо обещанной последней версии Android, пользователя обычно ждёт немного «перекрашенный» под фирменный интерфейс Samsung/Huawei/Apple Android 6 или 8 версии. После этого девайс обычно убирается в дальний ящик «как запасной», отдаётся ребенку или быстренько продается на барахолке за чуть меньшую цену, чем было куплено. При этом «8Gb RAM, 512Gb ROM» — это как бы часть названия устройства, а не маркетинг, так что даже к условному Авито за это не докопаться.
Если же покупателю нужен смартфон с базовым функционалом — т. е. мессенджеры типа Telegram/WhatsApp/Viber, соц. сети а-ля Facebook или VK, а также музыка и какой-то базовый серфинг в браузере, то он может и искреннее обрадоваться своей покупке, даже не обращая внимания на какие-то небольшие подлагивания интерфейса во время работы. Плюсы, помимо отличного (скопированного) дизайна, у таких девайсов тоже есть:
Дисплей: несмотря на то, что дисплеи в таких девайсах довольно низкого разрешения — обычно 540x960 (и это ограничение старого чипсета, а не экономия китайцев), зачастую в чуть более дорогие реплики устанавливают весьма неплохие IPS-матрицы на которые вполне приятно смотреть. В самых бюджетных моделях до сих пор ставят TN, но достаточно качественный, чтобы глаза «не вытекали» от углов обзора.
Звук и микрофон: обычно в подобных девайсах стоит моно-динамик, отличающийся довольно большой громкостью, но немного хромающий в плане качества звучания. Тем не менее, для слабослышащих людей это будет плюсом. В качестве микрофона в таких устройствах до сих пор устанавливаются аналоговые простые микрофоны, которые легко найти и заменить в случае неисправности, ни о каких цифровых микрофонах речи обычно не идет.
Аккумулятор: это плюсом можно назвать лишь 50/50 и зависит от модели к модели. Например, почти все китайские реплики айфонов обладают очень слабыми аккумуляторами (из-за ограничений по размерам корпуса), зачастую ёмкостью менее 2000мАч! Но в некоторые модели (например, клоны Huawei) устанавливают АКБ с честной ёмкостью ~3.000-4.000мАч, которые вполне неплохо держат, учитывая низкое потребление старых бюджетных чипсетов. Ещё один важный момент — в некоторых подобных смартфонах намеренно стоит упрощённая BMS (защитная плата аккумулятора), которая даёт уйти АКБ в глубокий разряд (т. е. ниже 2.8В), что пагубно сказывается на ёмкости аккумулятора, если девайс долго лежит разряженным.
И казалось бы, если взвесить на чаше весов плюсы и минусы девайса, то получается вполне неплохой ультрабюджетный смартфон: как раз купить маме/бабушке/ребенку или себе для базовых задач и пользоваться, не зная проблем! Но есть в бочке мёда две больших ложки дёгтя, связанные с тотальной экономией, которая выливается в поломку устройства спустя несколько месяцев после активного использования. «Бонусом» для производителя — эта ложка дёгтя закладывает самый настоящий «срок службы» девайса.
Первая ложка дёгтя не особо критичная и связана исключительно с программными приколами. Фактически, 8Гб постоянной памяти — это минимум, необходимый для работы относительно свежих версий Android и современных приложений. Поэтому, установив банковский клиент, WhatsApp, Telegram с кучей каналов, которые флудят картинками и VK, пользователь быстро обнаруживает, что памяти осталось очень мало и система предлагает удалить некоторые приложения для её освобождения.
Если проигнорировать это предупреждение и позволить приложениям дальше засорять память, Android со временем вывалится в софтлок, показывая диалог освобождения места при попытке запуска любого приложения — даже настроек! Освободив память, смартфон всё равно не получится сбросить даже через настройки, только через рекавери, что выливается в софтлок — из-за чего неопытные пользователи уже думают, что девайс «сломался» и несут его в сервис/идут покупать новый.
Происходит это из-за того, что китайцы пытаются обмануть Android, подменяя везде объём памяти с реальных 8Гб на 256/512/1024Гб. Android по каким-то причинам не руководствуется фактическим размером раздела /data/, а используют данные в конфигах системы, из-за чего девайс уходит вот в такой софтлок, из которого невозможно выйти обычными средствами. Увы!
Но большинство моих читателей и сами смогут скинуть устройство до заводских настроек через рекавери или просто загуглят, как это сделать. Однако есть и вторая ложка дёгтя — аппаратная, гораздо более серьёзная. Что же это за ложка такая? Узнаем в практической части нашей статьи!
❯ Экономия на чипах памяти
В один прекрасный момент устройство может зависнуть и перезагрузка тут не поможет. Смартфон в это время может перезагружаться, а может и просто висеть, при этом продолжая заряжаться и подавая все признаки рабочего устройства.
Первым делом опытные читатели попытаются его скинуть через рекавери — и даже если не увидят ошибок при вайпах, смартфон всё равно откажется загружаться.
Ещё более опытный пользователь загуглит прошивку для устройства запросом вида «P40 Pro Clone MT6580 firmware» и скачает прошивку для своего девайса с первого попавшегося сайта. По пути, товарищ скачает SP Flash Tool и установит драйверы. Однако при попытке прошить устройство, можно столкнуться с тем, что оно нормально прошилось, но теперь не запускается совсем/зависает с артефактами на экране/перезагружается. А при попытке прошиться ещё раз, увидит вот такое окно:
Увы, теперь Flash Tool не может переразметить внутреннюю память и записать новую таблицу разделов (тот самый GPT) в USER-раздел памяти. Восстановить девайс программными средствами не получится — и это не вина читателя/опытного пользователя.
Происходит это потому что чип флэш-памяти eMMC окончательно износился и ушёл в режим Read-only (только чтение, без возможности записи), дабы пользователь окончательно не потерял свои данные, которые вытащить могут только в СЦ и обычно только со специальным оборудованием. Чип eMMC имеет собственный контроллер, который мониторит физическое состояние секторов памяти и число бэдблоков — эдакий S.M.A.R.T. Когда контроллер решает, что у чипа слишком много испорченных блоков — он частично (т. е. какие-то операции записи всё равно проходят, из-за чего и повреждается GPT) отключает возможность перезаписи данных, из-за чего часть данных уже может быть повреждена, а система начинает вести себя нестабильно — и в случае Android, банально виснуть на заставке.
Иногда контроллер eMMC слишком рано приговаривает всю флэш-память и с помощью специального оборудования (например, z3x) и тестовых пинов на чипе памяти. Насколько мне известно, иногда такие флэши снова «поднимают» с помощью программатора и они могут прослужить ещё долгие годы своим владельцам.
Одним из примеров таких «заумных» контроллеров — eMMC в смартфонах Samsung Galaxy S3, Galaxy S4, Galaxy S4 Mini — у этих девайсов повально «вылетала» память и они висли с теми же симптомами, что описаны в статье.
Ранее проблемами с eMMC страдали флагманские Samsung (из-за ошибки разработчиков), HTC (некачественные чипы памяти) и некоторые другие девайсы. Но почему же эта проблема носит массовый характер на ультрабюджетных смартфонах? Узнаем на примере популярной в 2020 году реплики Huawei P30 Pro на базе чипсета MT6570, которую я купил год назад всего за 400 рублей в состоянии практически новой. Девайс был в коробочке, на нём была заводская плёнка, а его состояние было околоидеальным! Само собой я не удержался прикупить его себе :)
Девайс реально неплохо скопировали, за исключением больших рамок. Дизайн очень симпатичный как по мне. За 400 рублей — отличная покупка, самое время его оживить!
❯ Ремонтируем красавца
Разбирается довольно просто: необходимо отклеить заднюю крышку (осторожно, она очень хрупкая из-за согнутой формы. Я лично, несмотря на всю аккуратность и наличие фена, всё равно её треснул :c. Может у кого есть донор?), используя фен и тонкое лезвие, либо нить. Перед нами открывается вид на плату и аккумулятор:
Теперь нам необходимо снять среднюю часть корпуса, которая держится на винтиках. Не забываем вытащить сим-лоток, задняя часть корпуса (в районе платы с портом зарядки) может отщелкиваться немного туговато — это нормально. Не потеряйте толкатели кнопок — они ничем тут не закреплены.
Теперь можно отпаять АКБ, шлейф с кнопками и отключить шлейф дисплея и нижней платы. Отпаиваем вибромотор и разговорный динамик и вытаскиваем плату:
С обратной стороны чипсет, контроллер питания и флэш-память закрывает металлический экран, который припаян к плате. Его не нужно ничем выдирать, он замечательно сдувается феном на 350 попугаях без нижнего подогрева и риска что-либо угреть. При снятии экрана не заденьте обвязку и не уроните его на чипы, а то потом придется перекатывать КП/проц :)
Обратите внимание на Hynix H9TP32A8JDBC — это eMCP чип памяти, который содержит в одном корпусе 1Гб DDR2 ОЗУ и 8Гб флэш-памяти. Присмотритесь к его маркировке, маркировке на процессоре (MT6570A) и контроллере питания (MT6350V). На чипе памяти она вся в каких-то потертостях и повреждениях. Незадолго до написания статьи, читатель из Краснодара подарил мне еще один клон P30 Pro с идентичной платой и точно такими же проблемами (отвал флэши), там картина была абсолютно идентичная.
Само собой в процессе производства памяти далеко не все чипы получаются рабочими, некоторая часть из них — брак. На заводах есть автоматизированное тестирование, которое относит к бракам ту память, где сектор слишком быстро изнашивается и подвергается ECC (коррекции ошибок) после определенного числа стирания и записи определенных данных.
Из этого мы можем сделать вывод, что производители ради экономии ставят либо Б/У чипы памяти, выпаянные с утилизированных телефонов (H9TP — классическая eMMC, которая использовалась в современных смартфонах более 5 лет назад. Сейчас смартфоны используют UFS), которые уже были изношены на неопределенный процент и могут проработать как много лет, так и пару месяцев, либо отбраковку с заводов, которую, скорее всего, сгружают в общую корзину даже без блистера и затем продают по дешевке производителям смартфонов.
Как же это исправить? Правильно: установить новый чип памяти. Причём необязательно ставить идентичный, подойдет любой, который поддерживается Preloader'ом устройства.
Preloader — первичный загрузчик в смартфонах на базе чипсетов MediaTek, который занимается инициализацией контроллера ОЗУ. Поскольку производителем предполагается использование чипов eMCP — т. е. eMMC и ОЗУ в одном корпусе, в Preloader добавляется поддержка сразу многих чипов памяти. Preloader для выбора конфигурации контроллера ОЗУ использует CID устройства — поэтому, если в нём нет поддержки определенной CID, то устройство откажется включаться. Именно поэтому возникает ошибка DA_LOAD_FAILED при записи неправильного прелоадера!
CID текущей флэши можно узнать в логах SP Flash Tool, а список поддерживаемой памяти конкретным прелоадером можно узнать с помощью программы Wwr MTK.
Наш девайс поддерживает следующие чипы eMMC, оригинальный чип имеет корпус BGA183:
TYC0FH121626RA
TYD0FH221627RA
TYD0FH221618RA
KMK5X000VM-B314
H9TP32A8JDR_KGM
H9TP32A4GDR_KDM
H9TP32A8JDR_KG
H9DP32A4JJACGR_KEM
H9TP32A4GDBCPR_KGM
H9TP32A8JDACPR_KGM
H9TP32A8JDBCPR_KGM
KMK5U000VM-B309
KMKJS000VM-B309
KMQ72000SM-B316
H9TQ64A8GTMCUR_KUM
KMQ7X000SA-B315
H9TP64A8JDR_KGM
Сдуваем старый чип памяти с помощью фена. Не заденьте проц при снятии, плата теплоемкая, поэтому даже без нижнего подогрева проц будет очень легко «качаться»! После этого снимаем остатки старых шаров с пятачков с помощью оплетки (пятаки здесь крепкие, но если не хотите рисковать — то можно и шарик припоя покатать по площадкам).
Для замены я заказал несколько чипов памяти, точно таких же, как и в оригинале, по 70 рублей каждый, абсолютно новые. Чипы, особенно в такой липкой изнутри упаковке желательно сразу перекатать, иначе могут и не встать с первого раза.
Наносим тонкий слой флюса, дабы чип не уехал, центрируем его и ставим новую флэшу на место при температуре ~330 попугаев. Если флюса нанесено достаточно, то чип не уедет и сам встанет на место — вы сами увидите это. Опытные мастера скажут «ты шо, кукухой поехал? Угреешь же при 330гр.!». Но судя по всему, по настоящему угревается и помирает только уже полумертвая флэша.
Вприпрыжку бежим подсобирать девайс и подключать его к USB. Определится ли девайс? Сможет ли Flash Tool прошить его?
И… да! Флэша встала на место нормально :)
Включаем девайс и не можем нарадоваться: у нас появилось изображение! Правда, девайс всё ещё не грузится: некоторые прошивки сделаны из дампов и не содержат в себе разделов userdata.img и cache.img (обратите внимание на скриншот выше). После замены флэш-памяти, эти разделы оказались забиты нулями и Android не может примонтировать их, из-за чего устройство виснет.
Поправить легко: нужно зайти в рекавери и сделать вайпы. Происходит это из-за того, что некоторые дампы "нарезаны" без раздела userdata и cache. Если они будут забиты нулями, то система не сможет примонтировать эти разделы и зависнет. После перечисленных действий девайс загружается и работает!
❯ Фиксим программные болячки
Однако тут есть важный момент, который я специально предусмотрел для этой статьи: я не делал бэкап NVRAM. Поскольку новая флэша у нас забита нулями и мы прошили только те разделы, которые напрямую связаны с системой, настройки Wi-Fi, Bluetooth и IMEI оказались забиты нулями, из-за чего смартфон даже в 112 не дозвониться. При попытке набрать *#06# мы увидим «Неправильный IMEI», а в Wi-Fi останется сеть с ошибкой NVRAM Warning = 0x10.
Поскольку я предполагаю, что и у вас нет бэкапа NVRAM, то действовать можно следующим путем: попробовать прошить раздел NV от другого устройства на том же чипсете, восстановить NVRAM и IMEI с помощью MetaMAUI с помощью BPLG-файла, а также воспользоваться софтом для СЦ, дабы восстановить IMEI. Девайсы на 6570 и 6580 по каким-то причинам вообще никак не хотят цепляться к в MetaMode, поэтому воспользуемся Miracle Thunder. Нажимаем Ctrl + Shift + M, дабы у нас появились опции для записи IMEI, выбираем IMEI и делаем себе крутые имеи на обе SIM :)
Возвращать нужно только родной IMEI-устройства, который можно найти, например, на сим-лотке. Подделка IMEI является незаконной!
Включаем смартфон, пытаемся позвонить куда-нибудь и ура — всё работает :)
Портируем рекавери, накатываем рут — и у нас есть полноценный разлоченный девайс!
❯ Как девайс себя проявляет теперь?
Предлагаю взглянуть на смартфон после того, как мы его оживили! Посмотрим, какие задачи он сможет выполнять, с какой производительностью будет работать и стоило ли его покупать в год выхода — т. е. 2020 году.
CPUID говорит нам о следующих характеристиках и даже здесь его вводят китайцы в заблуждение. ОЗУ никаких не 4Гб, а 1Гб, а флэш-памяти всего 8Гб. Подобные спецификации могут показаться скромными в 2024 году.
Переходим к серфингу сети. И тут уже чувствуется затык по производительности в устройстве. Современные тяжелые сайты девайс откровенно не тянет, а в каких-то ситуациях браузер может даже крашнуться. Увы!
А как же мессенджеры? Ну, буквально на днях «протухли» сертификаты, из-за чего все девайсы до Android 5.1 частично потеряли возможность серфить такие сайты, как, например, ВК. Но и Kate Mobile, и Telegram работают весьма сносно на такой реплике. Тоже самое касается и WhatsApp, однако с тенденциями раз в год-два выкидывать поддержку старых версий Android, мессенджер не проживёт долго на этом девайсе :(
Ну и куда-ж без игр! Залетаем в классику начала десятых и понимаем, что девайс с ней весьма неплохо справляется.
Ну и дабы радовать вас не только скриншотами, прикладываю видео с производительностью работы девайса. Устраивает ли вас такой перформанс? Решать вам!
❯ Заключение
Сегодня мы с вами узнали, каким же именно образом некоторые производители закладывают срок службы в смартфоны. Быстро помирающая флэш-память стала давним бичом даже для флагманских устройств, чего уж говорить о бюджетных китайских репликах. Но как говорят некоторые мастера — девайс всегда можно восстановить, если плата не раскрошена пополам, а я на практике вам подробно рассказал о причинах и показал процесс оживления такого китайчика :)
Стоимость такого ремонта в СЦ составит около 3-4 тысяч рублей, что составляет чуть ли не половину цены нового устройства. Однако не стоит винить мастеров в дороговизне такой операции: новые чипы памяти обычно сами по себе стоят как минимум рублей 400-500, чипы чаще всего перекатывают с заводских шаров на новые, время спецов тоже стоит денег. Моя задача была в том, чтобы доказать вам, что такой девайс можно и дома самостоятельно отремонтировать, имея относительно небольшой набор оборудования.
Возможно вы ранее видели мои посты, где я ищу китайские реплики и подделки на айфоны/самсунги/макбуки и т. п. для будущего контента, даже нерабочие. Как вы и сами видите — эти реплики попадают в хорошие руки :)
Если хотите что-то задонатить из подобных девайсов — пишите в тг @monobogdan, буду благодарен и не забуду вас упомянуть в статье!
Стоит ли девайс своих 470 рублей и затраченных сил? Пользуетесь ли китайскими репликами? Пишите в комментариях, будет интересно почитать! Интересен подобный материал? Подписывайтесь на мою телегу: там есть бэкстейдж статей, различные мысли и солюшки по подобному ремонту, а также всегда вовремя публикуются ссылки на статьи!
Материал подготовлен при поддержке TimeWeb Cloud. Подписывайтесь на меня и @Timeweb.Cloud, дабы не пропускать свежие статьи каждую неделю!
Суровый моддинг из нулевых: как энтузиасты увеличивали объём ОЗУ в коммуникаторах?
Моддинг девайсов — тема очень широкая и невероятно интересная. При желании, чего только не сделаешь со своим любимым устройством: можно кастомизировать и преобразить интерфейс девайса, портировать свежую версию системы, прошить ядро с разгоном ЦПУ… Однако помимо программного моддинга, существует и аппаратный: умельцы умудряются наращивать объем ОЗУ и постоянной памяти, менять дисплеи на более качественные и даже добавлять поддержку беспроводной зарядки/квикчарджа! Предлагаю вам взглянуть на относительно редкую, дорогую, но такую желаемую в нулевых модификацию: наращивание ОЗУ на КПК аж в два раза! Сегодня мы с вами: узнаем предысторию моддинга телефонов в нулевых, самостоятельно перепаяем чипы ОЗУ на модули большего объёма, а также разберемся в программной стороне этого вопроса. Интересно? Тогда добро пожаловать под кат!
❯ Предыстория
Пожалуй, КПК и коммуникаторы на Windows Mobile можно назвать одними из самых интересных девайсов из середины нулевых годов. Пока подавляющее число пользователей только-только пересело на кнопочные телефоны с цветными дисплеями и поддержкой WAP-интернета, владельцы КПК носили в кармане полноценный компьютер, который мог выполнять многие задачи своего «большого брата». Сёрфинг полноценного Web 2.0 интернета, редактирование и просмотр документов, прослушивание музыки и воспроизведение видео и конечно-же игры — для портативного девайса в середине нулевых это было очень круто!
i-Mate jasjar
Характеристики КПК были практически идентичными на всех устройствах: большинство девайсов работало на базе ARMv5 процессоров Intel PXA 27x с частотой 400-600МГц, Samsung S3C6410 ~400МГц, а также TI OMAP 850 на частоте ~200МГц, оснащались ~64Мб встроенной Flash-памяти и 64-128Мб оперативной памяти SDRAM. Самым ценным ресурсом была оперативная память: большинство устройств на базе PocketPC 2003 так или иначе не могли использовать встроенную Flash-памяти для хранения пользовательских данных. Девайсы с 128Мб ОЗУ ценились гораздо выше более доступных устройств с 64Мб ОЗУ.
Происходило это из-за того, что Flash-память в те годы была слишком медленной, что негативно сказывалось бы на производительности всей системы. Поэтому производители устройств пошли на хитрый шаг: они решили использовать некоторый объём ОЗУ в качестве диска для пользовательских данных, а дабы пользователь не потерял важные ему файлы при, например, замене аккумулятора, они реализовали схему отдельного запитывания модуля обновления DRAM от резервной батарейки.
Динамическая RAM устроена так, что требует процедуру регулярного обновления (термин называется RAM refresh) данных во всей банке памяти в определенные промежутки времени. Упрощенно эта процедура выглядит так: контроллер памяти в чипсете вычитывает информацию из каждой банки, а затем записывает обратно, благодаря чему информация в банке памяти не теряется. Именно для этого контроллеру ОЗУ необходимы настройки таймингов, а также для процесса, именуемый «тренировкой памяти».
Поэтому в Windows Mobile был предусмотрен отдельный «бегунок», отвечающий за объём памяти, выделенный для программ и для пользовательских данных. Хочешь запустить одновременно TouchFlo, Скайп, Аську, PocketIE и гонять в фоне музыку? Готовься переносить фотографии любимого кота на SD-флэшку и тянуть бегунок в сторону программной памяти! По умолчанию, система выделяла около 32Мб памяти под пользовательские данные и остальные 32Мб под программы. Пользователь мог выделить до ~48Мб ОЗУ для программ, чего действительно хватало для параллельной работы нескольких относительно тяжелых программ в фоне!
Однако КПК на «винде» — отнюдь не современные устройства на Android и iOS и сами программы без крайней необходимости из памяти не выгружают. В iOS и Android практикуются «скриншоты» программ, когда в диспетчере задач мы видим сохраненное состояние приложения, но по тапу приложение снова запускается и быстренько восстанавливается из ранее сохраненного состояния. Поэтому, если в устройстве заканчивалась память для программ, уже открытые приложения могли крашиться, а новые не запускаться из-за слишком малого объёма свободной ОЗУ.
Устройства на WinMobile замечательно поддавались моддингу: некоторые энтузиасты портировали более свежие версии системы, другие выпускали собственные сборки системы, подчищенные от ненужных, по их мнению, программ, дабы освободить ещё немного ОЗУ под собственные приложения. Программный моддинг был очень развит: вспомнить только «кухни» — специальные наборы программ для модификации прошивок устройств и целые ветки на форуме 4pda, где обсуждалось добавление нового функционала в девайс. Чего-уж говорить, я сам год назад добавлял поддержку Direct3D Mobile в WM2003 и подкидывал софтварный рендерер от Intel в устройство на OMAP850!
Год назад я за пару дней запилил «тридэ» леталку, использующую D3DM — софтварный рендерер в Windows Mobile.
Однако другое дело — это аппаратный моддинг, связанный с физическим вмешательством в плату устройства. Самым частым модом была замена вечно ломающегося концевого выключателя (маленький рычажок, который прижимает задняя крышка устройства. Без него девайс чаще всего не включался) на обычную перемычку, дабы девайс не подвёл в самые ответственные моменты. Другой мод — перепаковка аккумуляторов для увеличения его ёмкости. Были ещё и другие, специфические модификации — насколько я знаю, на некоторых коммуникаторах Rover радиомодуль частенько «отваливался», а девайс уходил в белый экран. Радиомодуль либо выпаивали, либо грели (а то и перекатывали), дабы он ещё поработал какое-то время. Однако самым редким, дорогим и желанным многими модом было увеличение объёма ОЗУ! Данная процедура довольно простая, однако проводилась чаще всего в мастерских: старые чипы памяти выпаивались, а на их замену припаивались новые, большего объёма. На словах все просто, однако на деле далеко не каждый мог провести такую процедуру дома: необходимо было купить чипы памяти (которые стоили около 500 рублей за один), а сами они были в корпусе BGA и для пайки необходим был паяльный фен (на строительный тоже можно было посадить — но рискованнее) и адекватный флюс для BGA (хотя я слышал истории, как мастера в нулевых сажали чипы «на пузо» чуть ли не на таблетке аспирина).
Как видите, цена на работу в СЦ была не менее 3.000 рублей, время работы — полчаса-час. Теперь вспомните, что в некоторых регионах зарплата была около 6-7 тысяч рублей в месяц… вот так вот :)
Недавно я и сам заинтересовался таким видом моддинга и решил повторить опыт умельцев из нулевых: мне удалось найти НОВЫЕ (не реклама, это единственный магазин где можно купить эти чипы в РФ) чипы памяти в блистере по 100 рублей за штучку. Давайте же проапгрейдим легендарный коммуникатор своих лет — QTek S100 aka O2 Xda Mini II aka MDA Compact!
❯ Апгрейдим
Подобному апгрейду поддаются далеко не все девайсы. К сожалению, фактически проапгрейдить можно устройства только на базе чипсетов Intel PXA, например Asus P525/550, ранние HTC и многие HP iPaq. Устройства на базе Samsung S3C6410 имеют 64Мб ОЗУ прямо на одной подложке с чипом без площадок под дополнительную память на плате, а про устройства на OMAP 850 известно мало: скорее всего, чип не поддерживает возможность использования сразу четырех банок памяти одновременно.
Этого красавца проапгрейдить не выйдет :(
Изначально с завода, на большинстве устройств с чипсетом PXA используется два чипа мобильной SDRAM памяти типа HYB25L256160AC, производства Infineon, в корпусе BGA, по 32Мб каждый. Однако существует 64Мб версия того же чипа с идентичной распиновкой, где в одном чипе расположилось сразу две банки памяти, по 32Мб каждая. По итогу нам остается только сдуть старые чипы с помощью фена, почистить посадочные площадки от остатков старых шаров и установить новые чипы памяти с помощью всё того же фена. Давайте приступим!
Я купил свой QTek S100 два года назад в состоянии «как из помойки», всего за 100 рублей. Без шуток, возможно продавец действительно посещал свалки и потом продавал по дешевке различные интересные девайсы! Лично для меня в этом нет ничего брезгливого: корпус помыть с мылом, плату почистить спиртом и вот — крутейший девайс снова в рабочем состоянии и вполне чистенький :)
Аккумулятора у меня не было вообще и найти донора под перепаковку я даже не надеялся, поэтому запитывал девайс от BL-4C.
Разбираем девайс и видим плату с защитным экраном над процессором и ОЗУ. Сам экран съёмный, выпаивать его не нужно, но дабы аккуратно выпаять чипы памяти и не сдуть обвязку, придётся удалить лезвием «перекладину» на экране.
Выдавливаем под пузо чипов памяти немного флюса для BGA, берём прецизионный пинцет, фен, выставляем небольшой поток воздуха, температуру в 350 попугаев и начинаем выпаивать память по отдельности. Оба чипа сидят на бессвинце, поэтому для того, чтобы чип начал покачиваться, необходимо погреть его некоторое время. Как только чип начал «плавать» при покачиваниях пинцетом, его можно осторожно снимать пинцетом. Если снесли мелочуху, то её можно аккуратно выравнять пинцетом и поставить тем же феном обратно: поверхностное натяжении притянет элемент обратно и он встанет на место ровно, как и должно быть.
Я сначала не думал пилить контент об апгрейде памяти, поэтому фоточка совсем всратая :( Извините
Зачищаем площадку от старых шаров с помощью паяльника на 350гр и оплетки. Впрочем, шары достаточно большие — можно просто покатать шарик припоя и собрать излишки на паяльник, идеально ровно зачищать их не нужно.
Наносим флюс на посадочные площадки, примерно центрируем чип на плате и начинаем греть. Если вы не перелили флюса, благодаря поверхностному натяжению чип сам встанет на место!
Почти по заводу!
Но девайс не увидит всей ОЗУ, если не поставить резистор номиналом ~0.33Ом на линию CS1 - именно она отвечает за выбор второй банки в одном чипе памяти. Можно попробовать и просто перемычку поставить, но я не гарантирую результат.
Но это не весь моддинг на сегодня! Чуть позже я кинул нормальную, красивую перемычку вместо концевого выключателя, а также перепаковал аккумулятор, установив банку от BL-4C. Она, конечно, меньшей емкости, но девайс всё равно с ней держит довольно неплохо. Обратите внимание, что BMS (плату защиты) BL-4C необходимо выпаять: коммуникатор при поиске сети потребляет довольно много, из-за чего BMS BL-4C уходит в защиту.
Включаем девайс и… он работает!
Лучше перепрошить девайс официальной прошивкой: я даунгрейдился еще до замены памяти (до этого стояла прошивка WM6.5 от Cotulla), однако после апгрейда «винда» не всегда загружалась нормально, при том что сама ОЗУ инициализировалась правильно, без каких либо проблем и ребутов. После прошивки всё снова стало нормально. Если хотите накатить кастом — то ставить нужно версию с поддержкой 128Мб ОЗУ.
Обратите внимание, что флэшер вполне честно заявляет о времени обновления в 20 реальных минут времени. В этом вина как USB 1.1, так и медленной флэши.
❯ Программная сторона вопроса
Сейчас мы рассмотрели только физическую часть замены памяти. Но некоторые читатели наверняка спросят, каким же образом коммуникатор определяет всю установленную память, если конфигурация DDR статически слинкована с первичным загрузчиком?
На ПК у нас есть SPD— Serial Presence Detection, специальная небольшая флэш-память, в которой хранится конфигурация чипов и общий объём памяти на планке. В embedded-окружении чаще всего конфигурация контроллера памяти хранится в первичном загрузчике (после BootROM) — известном также как SPL.
Загрузчик HTC на устройствах PXA поддерживает несколько конфигураций ОЗУ — как минимум 64Мб и 128Мб. И судя по всему, на манер BIOS на ранних x86 машинах, загрузчик ещё на этапе тренировки ОЗУ проверяет всё доступное адресное пространство: если доступны «верхние» 64Мб ОЗУ, тогда загрузчик передаёт в Windows CE информацию о том, что установлено 128Мб памяти.
На коммуникаторах Asus, загрузчик патчили для поддержки 128Мб.
Очевидно что без установки второго чипселекта (линии CS1), контроллер DRAM не сможет обратиться ко второй банке памяти в одном чипе, поэтому его установка обязательна. Иначе загрузчик не видит верхние 64Мб ОЗУ и считает, что в устройстве установлено лишь 32Мб.
❯ Каково пользоваться девайсом теперь?
Давайте глянем, как же девайс работает теперь. Пожалуй, сразу стоит упомянуть то, что у девайса изначально были перспективы к увеличению производительности: помимо возможности увеличения ОЗУ, чипсет легко разгоняется до 624МГц с стоковых 412. Очень даже бодрый результат.
Сначала я решил поиграть в классику. AoE замечательно шла и на устройствах с ~32Мб ОЗУ (т.е ранних КПК), очевидно что и на гораздо более шустром девайсе она будет идти очень хорошо. Хороший способ ознакомиться с классикой RTS, кстати!
Переходим сразу к тяжелой артиллерии. Самыми тяжелыми играми для ранних коммуникаторов считались PocketFallout и Heroes Mobile: они кушали довольно большой объём ОЗУ и что-то запустить параллельно с ними было проблематичным. Не менее тяжелой была Quake 1: игра аллокейтит для себя кучу (динамическая память) в 16Мб. Это был уже серьезный удар по свободной ОЗУ на устройствах с 64Мб памяти, QIP и PocketIE уже придется закрыть:
Но будем честны: ради игр можно было закрыть почти все приложения в диспетчере задач. А как насчет повседневных задач? Давайте откроем кучу приложений и узнаем, какое у нас будет потребление ОЗУ и общая производительность системы:
Не хило, да? Коммуникаторы и сейчас подойдут в качестве звонилок с функционалом смартфона, однако приложения под себя придётся допиливать самому. Благо API очень знакомое: в WinMobile и WinCE у нас самый обычный WinAPI, очень схожий с десктопным, а также есть немного урезанный .NET!
❯ Заключение
Вот таким был аппаратный моддинг девайсов в нулевых. Столько всего можно было сделать, имея лишь базовое оборудование! А ведь если включить смекалку, то можно заюзать КПК и в качестве одноплатников: на подавляющем числе девайсов UART без проблем можно получить с разъема для док-станции, а сама шина без проблем доступна из юзерспейса. Постараюсь развить эту тему в одной из будущих статей.
Информации по апгрейду памяти на КПК очень мало (ведь когда-то это был хлеб для СЦ) и сейчас её можно найти исключительно в архивах. Однако чем больше я посещаю паблики посвященные ретро девайсам, профильные каналы в Телеге и форумы по ремонту девайсов, я вижу всё больше упоминаний таких любимых нами наладонников! Поэтому я постарался систематизировать и собрать в кучу всю необходимую информацию для того, чтобы любой читатель мог и сам провести такую операцию в домашних условиях.
Сейчас мы привыкли с вами, что в смартфонах объём ОЗУ зачастую больше, чем в некоторых десктопных машинах. 6, 8, 12Гб — куда дальше!? А ведь когда-то и 128Мб уже было за счастье :)
А какие модификации КПК были у вас и как использовали свой девайс вы? Может вы сами апгрейдили КПК? Пишите в комментариях!
P. S.: Друзья! Время от времени я пишу пост о поиске различных китайских девайсов (подделок, реплик, закосов на айфоны, самсунги, сони, HTC и т. п.) для будущих статей. Однако очень часто читатели пишут «где ж ты был месяц назад, мешок таких выбросил!», поэтому я решил в заключение каждой статьи вставлять объявление о поиске девайсов для контента. Есть желание что-то выкинуть или отправить в чермет? Даже нерабочую «невключайку» или полурабочую? А может, у этих девайсов есть шанс на более интересное существование! Смотрите в соответствующем посте, что я делаю с китайскими подделками на айфоны, самсунги, макбуки и айпады!
Понравился материал? У меня есть канал в Телеге, куда я публикую бэкстейдж со статей, всякие мысли и советы касательно ремонта и программирования под различные девайсы, а также вовремя публикую ссылки на свои новые статьи. 1-2 поста в день, никакого мусора!
Материал подготовлен при поддержке TimeWeb Cloud. Подписывайтесь на меня и @Timeweb.Cloud, дабы не пропускать новые статьи каждую неделю!
Помогите выбрать ноут
Думаю выбрать модель gigabyte g 5 i5 12500 h 4500 gtx 16 Гб. Какие аналоги либо конкуренты по цене качеству есть ах да ssd на 512
Продолжение поста «Игровая легенда из 90-х: Как работала 3dfx Voodoo "под капотом"? Пишем 3D-приложение нуля на Glide (1/2)»
Это вторая часть лонга про 3dfx Voodoo. Пришлось разбить его на две части из-за ограничений в 30.000 символов на пост у Пикабу. Сначала читайте первую часть.
Скрин с криво-наложенной текстурой: здесь уже был настроен сэмплер, но неправильно. А ещё тут видно артефакты отсутствия Z-сортировки наглядно.
Пока не впечатляет, да? Где же текстуры? А об этом — в следующей главе!
❯ Текстуры
Плоские модельки без текстур — это не очень круто. Ну что можно сделать с плоскими моделями, пусть даже они будут с освещением?
Те читатели, которые имеют опыт программирования графики наверняка знают, что видеодрайвер сам распоряжается видеопамятью с точки зрения аллокатора (механизм, управляющий выделением динамической памятью — т. е. той памятью, которая может быть выделена под объект, освобождена и затем занята другим объектом). Программист лишь создаёт текстуру, указывает число мипов и выгружает её на видеокарту — сейчас даже генерация мипов это задача видеодрайвера и самой видеокарты.
Но в Glide всё было иначе — ведь там не было понятия текстуры как объекта! Как-так? Glide позволял нам получить верхнюю и нижнюю границу адресного пространства памяти одного конкретного TMU и программист волен был выгружать текстуру куда угодно! Затем программист сохранял указатель на текстуру в видеопамяти и передавал её… в комбайнер, дабы он мог использовать текстуру по назначению! При этом TMU даже характеристики текстур не знал — эту информацию отсылал программист.
TMU поддерживает множество пиксельформатов: RGB332 (8 бит на пиксель), RGB565 (16 бит на пиксель), палитровый и собственный формат сжатия с NCC-компрессией. Тем не менее, 565 у 3dfx требует какого-то особого формата пикселей, иначе текстуры превращаются в кашу. Благо для загрузки текстур с диска, в Glide есть удобные функции и тулза texUS для создания текстур и всего набора мипов для них — gu3dfGetInfo и gu3dfLoad. Кроме того, есть функция grTexCalcMemRequired для расчета необходимого размера для текстуры в видеопамяти с учетом мипов, формата и выравнивания.
Я не стал писать сложный аллокатор, поскольку игра не требует динамической видеопамяти и может сразу загрузить уровень «пачкой», а при загрузке следующего — просто освободить всю память.
После этого, нам необходимо загрузить текстуру в видеопамять юнита с помощью grTexDownloadMipMap.
Как же теперь указать текстуру для сэмплинга, ведь glBindTexture здесь нет? Для этого есть функция glTexSource, которая принимает адрес первого мипа и конфигурацию текстуры — которая хранится на стороне ЦПУ!
Но если мы сейчас запустим программу, то никакой текстуры мы не увидим. Потому что сначала нужно настроить сэмплер и комбайнеры!
Для этого, мы настраиваем комбайнеры на сэмплинг текстур напрямую, без умножения на цвет вершины. Альфа-канал мы не трогаем вообще — у нас нет альфа-буфера для него.
Запускаем программу и вот результат:
Да, первая полноценная 3D-модель с текстурой! Мы реализовали половину работы видеодрайвера вручную, однако по концовке всё равно очень приятно! Игры здесь пока ещё нет — материал вышел бы слишком большим.
❯ А где практика?
К сожалению, сегодня без практической части :( Изначально я думал что у меня всё схвачено и моя материнка на 478 с AGP-слотом вполне справиться с ролью тестового стенда для нашей демки. Однако, я не учел важный факт — существовало несколько физических версий AGP и на 478 уже поздний вариант с 1.5в/0.8в уровнями.
Материал был обещан в четверг на 11 утра, времени на заказ через почту у меня не было (новый год, посылки 1.5-2 недели задерживаются только на сортировке в Краснодаре), поэтому я начал написывать всем сервисникам у себя в городе, в надежде что у кого-то лежит на складе материнка на PGA370… в любом состоянии.
И материнка нашлась! Ей оказалась поздняя ECS P6IPAT на 815 чипсете с универсальным AGP-разъемом, который поддерживал все стандарты AGP одновременно. Продавал её мужичок всего за 100 рублей, сразу с процом и охладом :) Однако возникли определенные проблемы с поднятием платы (все электролиты необходимо менять «вкруг», а нужных номиналов под рукой не оказалось, плата стартовала раза с 3го) и накатыванием винды (помер IDE-привод), поэтому практическая часть немного откладывается…
❯ Заключение
И мы приходим к выводам, что для написания 3D-игры, программист в 90-х годах должен был как минимум:
Иметь представлении о трансформации геометрии, что такое матрицы (геометрию можно трансформировать и без матриц, однако это не очень удобно).
Понимать, как работает конвейер видеокарты, что такое стейты, комбайнеры, каким образом происходит управление памятью, организация фреймбуфера и Depth-буфера.
Иметь представление об основных техниках в растеризации 3D-графики: что такое перспективное деление, Z-буфер, форматы вершин, фильтрация текстур, мипмаппинг, затенение по Гуро, какие-либо методы анимации, если была необходимость и т. п.
Материал получился очень объёмным, для меня это абсолютный рекорд. Я старался собрать всю информацию о 3dfx Voodoo, которую изучил и поделится с вами не только архитектурой конкретно видеокарт, но и рассказать о программировании графических API на низком уровне и подробно рассказать, как же строится изображение «под капотом» и вашей видеокарты.
Касательно баек насчет 3dfx в СНГ: я лично родился в 2001 году, так что могу судить исключительно из услышанных мной баек и историй. А какая история с 3dfx Voodoo была у вас? Пишите в комментах!
Надеюсь, материал был вам интересен. :) Статья писалась несколько бессонных ночей, дабы успеть под новый год! Больше бэкстейджа, мыслей и проектов у меня вTelegram.
Материал подготовлен при поддержке TimeWeb Cloud. Подписывайтесь на меня и @Timeweb.Cloud, дабы не пропускать новые статьи каждую неделю!
Игровая легенда из 90-х: Как работала 3dfx Voodoo «под капотом»? Пишем 3D-приложение нуля на Glide (1/2)
Полагаю, многие мои читатели так или иначе знакомы с такими видеокартами, как 3dfx Voodoo. Эти легендарные графические ускорители из середины\конца 90-х годов был чуть ли не в каждой второй сборке для игр, а о их производительности слагали легенды. До сих пор есть относительно небольшое сообщество фанатов ретро-игр, которые ценят, любят и собирают с цветмета те немногие видеокарты от 3dfx, что остались в СНГ. Однако обзоров на 3dfx Voodoo много, тестов игр — тоже, а вот материала «простыми словами» о его внутренней архитектуре и более того, практической части с написанием 3D-игры практически нет! Недавно я прикупил себе Voodoo 3, и начал зубрить Programmer's Manual с желанием запилить что-нибудь эдакое… Статью я долго и упорно готовил дабы успеть к новому году и сегодня у нас с вами: краткая история компании 3dfx, подробный разбор архитектуры видеочипов 3dfx «под капотом», что должен был уметь программист 3D-графики в 90х и написание 3D-приложения на Glide полностью с нуля. Интересно? Тогда жду вас в статье!
❯ Предисловие
Материал про архитектуру S3 ViRGE показал, что рубрика с разбором «подкапотки» видеочипов 90-х годов оказалась довольно интересной. Многие люди приходят почитать, поностальгировать в комментариях, а иногда даже пишут в личку и спрашивают детали реализации конкретных видеочипов! Думаю, эта рубрика станет одной из основных, в будущем году, мы рассмотрим с вами:
PSP;
PS1 (как раз читатель недавно задарил фаточку и слимку);
ATI Rage;
Вероятно, GeForce 2.
Само собой, я не мог пройти мимо 3dfx Voodoo. И дело не только в ценности и легендарности данных видеочипов, но и во внутренней архитектуре, которая очень сильно отличается от современных GPU. Про 3dfx я знаю уже более 10 лет, ещё с самой юности, а знакомство произошло в одном из выпусков «16-бит тому назад», однако прикупить себе один экземпляр решился только сейчас.
Чем же был обусловлен культовый статус 3dfx Voodoo с точки зрения игрока? В первую очередь, 3dfx Voodoo вышел достаточно рано и стал одним из первых (наряду с Rendition Verite) потребительских GPU с оптимальной производительностью и ценой для 3D-игр тех лет. Игры с полноценной 3D-графикой существовали и ранее: вспомнить хотя бы PS1, N64, или японские игровые автоматы из 90-х, однако в играх на ПК в те годы практически всегда был софтварный рендерер, а 3dfx Voodoo позволял достичь графики на уровне, а то и лучше домашних консолей тех лет. За год до выхода Voodoo 1, на рынке появился NVidia NV1 — мультимедийный чип, одной из задач которого было ускорение 3D-графики. Однако, он оперировал не треугольной геометрией, как это принято сейчас, а квадами — т.е прямоугольниками и не был совместим с основными графическими API тех лет, посему и популярности не получил.
Помимо этого, видеокарты Voodoo были модульными и состояли как минимум из нескольких чипов, что положительно сказывалось на возможных конфигурациях и цене конечных устройств:
Один FBI: Чип, отвечающий за обмен данными с хост-ПК через PCI/AGP и растеризацию треугольников. Это главный чип в видеокарте, который может работать в паре с другим FBI, образовывая систему из двух видеокарт — SLI.
До трёх TMU: Один или несколько чипов, отвечающий за сэмплинг — нанесение текстуры на треугольник. В процессе отрисовки геометрии, FBI передаёт на каждый из указанных программистом TMU данные о текстуре, которую требуется наложить и параметры наложения (фильтрация, мипы и.т.п).
Именно в те годы появилась гонка за объемами видеопамяти на борту и разделение их по классу. Видеокарта с общим объёмом памяти в 16Мб считалась гораздо круче видеокарты с 8Мб: и ведь действительно, больший объём VRAM позволял загрузить текстуры с более высоким разрешением, при этом на частоту видеоядра тогда смотрели гораздо реже.
Другим интересным моментом было собственное графическое API. В те годы доминировал OpenGL, пришедший к нам с профессиональных графических станций: SGI выделили собственное API в отдельную спецификацию, выкинули оттуда различные функции, не касающиеся вывода графики и сделали полностью открытой. В 1996 году, DirectX 2.0 с первой версией Direct3D только-только появился и был достаточно нестабильным GAPI (даже Кармак его ругал), а больше вариантов и не было. Результатом стало появление 3dfx Glide — низкоуровневого графического API, которое позволяло управлять видеокартой похожим на OpenGL путём, но при этом на ещё более низком уровне, имея возможность тонкой настройки всего конвейера. Одной из важных фишек Glide стала поддержка не только Windows, но и DOS, что было достаточно редким, если не уникальным случаем для тех лет.
Игры для 3dfx Voodoo не заставили себя ждать. Благодаря относительной простоте Glide и понятному мануалу, а также открытости SDK, начали появляться игры с поддержкой данного GAPI: Tomb Raider, MechWarrior, Quake — какие-то игры работали через прослойку (как вышеупомянутая квака, которая реализовывала прослойку Glide -> минимальное подмножество OpenGL, которого хватало для работы игры), какие-то нативно. Выход игр с поддержкой 3dfx Glide обеспечил успех новой видеокарте, поскольку игры зачастую не просто работали шустрее, но и выглядели гораздо симпатичнее.
После выхода первой 3dfx Voodoo, компания сосредоточилась на улучшении Glide и доработке архитектуры видео-ускорителей. В 1998 году, спустя два года после выхода первой Voodoo, компания выпустила Voodoo 2 с объемами памяти 8Мб (по 2Мб на TMU) или 12Мб (по 4Мб на TMU), которая архитектурно была похожа на первый видеочип, однако несла в себе несколько серьезных изменений:
64-битная шина для обмена данными с TMU. Помимо этого, 3dfx отмечала то, что благодаря широкой шине, ей удалось реализовать сэмплинг сразу двух текстур за такт.
Поддержка Clip-Space координат. Прошлый видеочип рисовал треугольники в абсолютных координатах экрана, а не нормализованных, что в некоторой степени негативно влияло на производительность. При этом для обратной совместимости, поддержка абсолютных координат была оставлена.
Поддержка SLI для объединения двух видеокарт для обработки одного кадра. При этом каждая видеокарта работала над своим набором сканлайнов — строк на экране. То есть, первый видеочип мог обрабатывать нечетные строки, а второй четные.
Но тем не менее, 3dfx Voodoo оставались именно видео-ускорителями и полностью заменить видеокарту не могли, поскольку у них не было блока для работы с 2D-графикой (этот блок, в свою очередь, помимо софтварной поддержки VESA-режимов должен включать в себя аппаратное ускорение BitBLT, рисования некоторых примитивов и.т.п). По этой же причине, игры с использованием Glide нельзя было свернуть с помощью Alt-Tab (на самом деле можно, но хаком) и они не могут быть запущены в оконном режиме. По сути, 3dfx Voodoo подключался к полноценной 2D-видеокарте (которой мог быть и ATI Rage, и S3 ViRGE, и ISA-видеокарта с VGA) и полностью переключал сигнал на выход из своего RAMDAC при запуске игры. В общем, игры на Glide с точки зрения системы были простыми консольными приложениями — даже без собственных окон!
Немного позже, 3dfx добавила модуль 2D ускорения, сделав полноценную видеокарту, которая могла работать в системе в одиночку. В 1999 году, через год после релиза 3dfx Voodoo 2, вышла Voodoo 3, которая стала системой на кристалле и объединила FBI и два TMU в один кристалл. Видеокарта стала гораздо меньше и обзавелась интерфейсом AGP (который очень близок к PCI сам по себе).
Конкуренты у 3dfx Voodoo были серьезные, пожалуй, самым серьезным был ATI Rage: это была небольшая система на кристалле, которая помимо ускорения 3D-графики обладала декодером видео DVD-качества (в те времена, посмотреть видео в 480p и нормальном качестве с софтварным декодером возможно было далеко не на всех процессорах. Насколько мне известно, 486 и Pentium 1 сразу в пролете), умела выводить изображение на телевизор (сам себе домашняя игровая консоль!) и поддерживала не только D3D и OpenGL (причем насколько мне известно, OpenGL поддерживался плохо и такая тенденция сохранялась до покупки ATI компанией AMD), но и собственное проприетарного GAPI ATI CIF (C Interface), которое обладало весьма широкими возможностями и было… ну очень низкоуровневым, приходилось вручную создавать контекст DirectDraw, аттачить его к 3D-контексту, вручную делать backface-отсечение и т. п.
Нельзя не вспомнить и за Riva TNT: очень шустрая видеокарта для своих лет, которая также обладала ТВ-выходом и хорошей поддержкой OpenGL. Кроме того, Riva TNT гораздо лучше себя проявляла при 24-х битном цвете: 3dfx Voodoo отрисовывала всё в 16-битном формате. Вон, люди на Riva TNT как-то даже в Морровинд играли!
Ну и конечно же была конкуренция в бюджетном сегменте рынка. 3dfx поставляла OEM-видеокарты для сборщиков ПК, в том числе и недорогие. Тут уж конкуренция была серьезнее: и PowerVR с десктопной видеокартой, и Intel с i740 (эдакий предок GMA), и видеокарты от SiS, и конечно же S3 Graphics!
В пост-советском пространстве, 3dfx Voodoo была достаточно дорогой и для некоторых оставалась мечтой. Ситуация изменилась ближе к 1999-2001 годам, когда 3dfx с Voodoo 4 и Voodoo 5 была на грани банкротства из-за отсутствия T&L и программируемых шейдеров, а NV и AMD взяли верх, то и Voodoo начали стоить адекватных денег на вторичке: тут уже и GeForce 3 с шейдерами подоспевал, но более бедные геймеры все еще могли поиграть в Quake 3 и другие игры с приемлемым FPS!
Наш сегодняшний герой будет на 3 года меня старше — мой выбор пал на 3dfx Voodoo 3 на 8Мб в AGP-версии, которая среди любителей видеокарт 3dfx считается «не трушной» и посему, самой дешевой. Основной причиной выбора Voodoo 3 была достаточно низкая цена на конкретно это поколение видео-ускорителей — я заплатил 3.400 рублей. 1 и 2 Voodoo стоят в среднем от 4-5 тысяч рублей, а цены Voodoo 4 улетают в космос. Так что скромненько, конечно, но тоже нормально :)
Придя домой и распаковав посылку, я сразу же установил Glide SDK и принялся изучать Programmers Manual, дабы запилить что-нибудь интересное…
❯ Архитектура «под капотом»
Но сначала давайте поговорим об архитектуре 3dfx Voodoo «под капотом», на более низком уровне, дабы было общее понимание, что и как работает. Без этого, понять принцип работы GAPI и видеокарты в целом может быть сложно. Предлагаю рассмотреть FBI, TMU и RAMDAC по отдельности:
FBI — FrameBuffer Interface. Как уже было сказано выше, этот модуль является основой видеоускорителя: в его задачи входит коммуникации через PCI/AGP, растеризация примитивов, клиппинг, расчет вершинного освещения, подготовка текстур к заливке на TMU, перспективная коррекция, альфа-блендинг и работа с Z-буфером, а также двойная/тройная буферизация и управление самим фреймбуфером.
В Voodoo 3, под радиатором находится система на кристалле, где FBI и TMU находятся в одном чипе.
FBI делились на несколько поколений — SST-1 (3dfx Voodoo 1), SST-96 (3dfx Voodoo 2) и.т. п. Судя по всему, у одного FBI могло быть несколько ревизий, но в чем их отличие — неизвестно.
Для нужд FBI выделено строго 2Мб видеопамяти, которые используются для 3 буферов, один из которых можно использовать для произвольных целей. Первые два буфера называются Front и Back буферами и отображают то, что сейчас находится на экране, а третий является aux-буфером с 16-битным форматом цвета, который можно использовать для альфа-блендинга, либо как Z-буфер. Видеокарта поддерживает несколько форматов фреймбуфера, однако «под капотом» все расчёты ведутся в 16-битном RGB565 — что когда-то и стало «визитной карточкой» видеокарт 3dfx. Программист может получить прямой доступ к записи в буфер экрана с помощью lfb-функций (аналог в OpenGL — glCopyPixels/glReadPixels).
Для FBI выделен отдельный чип памяти на 2Мб или 4Мб. При 2Мб, максимальное разрешение с Aux-буфером составляло 640x480, без Aux-буфера — 800x600, при 4Мб можно было создать буфер с разрешением 800x600, при этом с Aux-буфером.
Ключевой особенностью растеризатора FBI в SST-1 была в том, что вся отрисовка геометрии происходила в абсолютных оконных координатах. В 3D-графике принято все расчеты проводить в т. н. Clip-Space координатах, которые представляют из себя нормализованные экранные координаты (NDC) в пределах -1..1. То есть, точка 0 — центр экрана, -1 — левая сторона экрана, 1 — правая. В SST-1 же все вершины рисовались сразу же в экранных координатах, то есть так:
В 3dfx Voodoo 2 ввели расчеты в Clip-Space, пояснив что растеризация в абсолютных оконных координатах слишком медленная для будущих поколений видеокарт. По итогу, если программисты хотели, чтобы их игра работала на 3dfx Voodoo 1, им нужно было выбирать «старый» режим работы и преобразовывать Clip-Space координаты в оконные вручную.
Как уже было сказано выше, вся видеопамять выделялась отдельным TMU и FBI. Но где-же тогда хранилась геометрия? Опытный читатель помнит про такие функции, как glBegin/glEnd. В те годы, видеопамять было принято считать именно текстурной, а геометрию пересылал процессор каждый кадр вручную — причём сразу же трансформированную, подготовленную для вывода на экран. Для каждой вершины в примитиве был свой набор регистров, задающий координаты, цвет и UV для текстур, что и позволяло сделать гибкий формат вершин, чем активно пользуется Glide.
Если говорить совсем уж просто, то 3dfx Voodoo был растеризатором треугольников, который ко всему прочему умел Backface-отсечение. Например, не было Near-clipping'а — процесса перестроения примитивов, вершины которых частично уходят за камеру. Если этого не делать — то когда примитив уйдет за камеру, мы все равно продолжим видеть его на экране, а если это дело аппроксимировать, отсекая целые примитивы — некоторая геометрия будет пропадать, если расположена слишком близко к камере. Многие концепции отрисовки 3D-графики программист должен был знать заранее, никаких упрощений, как с современными GAPI, не было.
TMU — Texture Mapping Unit. Как уже было сказано ранее, этот чип отдельно отвечал за сэмплинг текстур, а также управление своими банками видеопамяти и отправкой конечного результата обратно FBI.
Ключевой особенностью TMU была поддержка комбайнеров — своеобразная альтернатива пиксельных шейдеров в те годы. Программист мог задать функцию и параметры работы каждого TMU, дабы он мог выполнять операции умножения текстуры на цвет, или, например, использовать текстуру как маску, манипулировать её альфаканалом и сэмплить сразу две текстуры за один проход! В те годы сама возможность отрисовать геометрию с несколькими текстурами за один проход (т.е за один вызов DrawTriangle) была прорывом и позволяла, например, вместо двух вызовов отрисовки стен в квейке (один проход для текстурированной стены, второй, отрисованный с блендингом, для лайтмапы) рисовать стены за один проход:
Максимальный размер текстуры — 256x256 пикселей, также была поддержка текстур с нестандартным соотношением сторон и мипмаппинга (техника, которая позволяет убрать рябь на дальних текстурированных объектах с помощью снижения разрешения текстуры в зависимости от дистанции до наблюдателя). Поддержки Non Power Of Two (не кратные степени двойки) текстур не было вообще. Поддерживалась билинейная и Point-фильтрация. По какой-то причине, 3dfx не могли сделать поддержку текстур большего разрешения чем 256х256, в то время как первая Riva TNT уже умела в текстуры 1024х1024.
Память у каждого TMU была отдельной, а Glide как GAPI не предоставлял никакого аллокатора для хранения текстур, программист должен был распоряжаться видеопамятью полностью сам. При этом каждый TMU может сэмплить текстуры только из своей памяти.
Текстуры загружались сразу в виде набора мипмап, однако сам сет мипов мог быть не полным и мог быть расположен в нескольких регионах памяти «вразброс». Таким образом, частично решалась проблема фрагментации памяти. Тем не менее, в те годы динамическая загрузка ресурсов на уровне — весьма нечастое явление, поэтому все текстуры можно было линейно загрузить в память и не заморачиваться с менеджментом.
DAC — RAMDAC производства компании ICS. Данный чип служит для вывода определенной части видеопамяти, т.е фреймбуфера на монитор. Дело в том, что старые VGA-мониторы с ЭЛТ, по электрической части были аналоговыми: на входе было три сигнала — красный, зеленый и синий, а также сигнальные линии горизонтальной и вертикальной синхронизации. Поскольку многие видеокарты не имели на борту ЦАП'а, в 90-х и начале нулевых устанавливались отдельные RAMDAC'и для фактического вывода картинки на дисплей. При этом вывод на ТВ с помощью «тюльпанов» мог реализовываться ещё одним RAMDAC'ом — уже специально для ТВ.
Сами по себе ЭЛТ-мониторы формально не имели такого понятия, как разрешение, однако существовало несколько общепринятых «пиксельклоков» — частот стробов HSYNC и VSYNC, которые и задавали виртуальное разрешение дисплея. Управляя настройками RAMDAC, FBI мог настраивать разрешение картинки, частоту синхронизации и иные параметры — например, настройки гаммы. Именно от используемого RAMDAC зависело качество изображение на ЭЛТ-мониторе, с плохим RAMDAC картинка как-бы «плыла».
❯ Настраиваем окружение
Дабы пилить игры под 3dfx Voodoo, необязательно иметь ПК на WinXP и тулчейн уровня VC98. Строго говоря, даже самой видеокартой обладать необязательно — существует множество эмуляторов Glide, которые перехватывают вызовы игр к GAPI и преобразуют их в вызовы отрисовки D3D или Vulkan, что позволяет отлаживать ваши игры в профайлере.
Glide в его нативном виде работает под Windows XP. Поэтому минимальный тулчейн, который можно использовать — это VC2015 с поддержкой Windows XP. Но если вы хотите максимальной «трушности» и иметь возможность запускать софт на Win98/Win95 — нужно использовать Visual Studio 2005. При этом, совершенно необязательно отказываться от плюшек современных IDE: Visual Studio автоматически подхватывает все установленные тулчейны в системе, достаточно лишь выбрать нужный:
Далее, по классике добавляем либы, которые без проблем слинкуются относительно современным линкером с вашими бинарниками.
Ну что ж, на этом интро-часть материала закончена. Самое время перейти от теории к практике!
❯ Инициализация
Концептуально Glide очень близок к OpenGL, поэтому тем людям, кто имел опыт программирования 3D-графики, сам процесс настройки стейтов и рисования примитивов будет знаком. Однако поскольку основной целью Glide было создание облегченного GAPI, которое только рисует примитивы и управляет текстурными юнитами, мы не найдем здесь utility-функций (в Glide 2.x они были, причем очень даже полезные, но в 3.x gu убрали), таких как работа с матрицами — множество вещей нужно реализовывать самому, полностью с нуля. Однако я постараюсь подробно и понятно всё объяснить, в свойственной мне манере!
Наша игра начинается с инициализации и конфигурации контекста Glide, который может быть только один в системе. Связано это с тем, что каждое приложение эксклюзивно занимает ВСЕ ресурсы видеочипа для себя — возможности рисовать в отдельное окно, напоминаю, нет. Инициализация очень простая: сначала нужно проверить количество видеочипов в системе, а затем выбрать один из них как основной и создать контекст. Все сниппеты будут на pastebin.com - у Pikabu нет тега "код", а число картинок ограничено :(
Параметры нашего контекста: разрешение 640x480 в формате RGBA и частотой обновления 60Гц, два буфера для двойной буферизации и один aux-буфер для Z-буфера.
Всё! Ни окон создавать не нужно, ни ловить события через WndProc. Просто создал контекст — и уже можно в цикле продолжать работу. После этого, нам нужно настроить состояние контекста — базовая концепция в программировании графики, которая заключается в том, что у видеокарты есть множество стейтов, которые управляют выводом итоговой картинки на экран. Примеры стейтов: цвет освещения, ширина линий, Z-буфер и Color-буфер.
Для того, чтобы наша игра работала даже на первых видеоускорителях 3dfx, нам необходимо выбрать абсолютную координатную систему, а также настроить Depth-буфер и Cull-mode. Cull-mode, или Backface culling позволяет отсекать примитивы, если они повернуты к камере обратной стороной — это позволяет не рисовать лишние фрагменты. Именно из-за этой техники, залетая внутрь модельки простенького здания или персонажа, внутри она оказывается прозрачной!
Буфер глубины — это дешевая screen-space техника отрисовки перекрываемой друг другом геометрии без фактической сортировки примитивов по отдалению от камеры. Суть простая: каждая вершина треугольника имеет собственную координату Z, которая и обозначает дальность вершины от камеры. При растеризации треугольника, Z-значение интерполируется и записывается в картинку точно таких-же размеров, как и основное игровое окно, только вместо цвета записывается это самое Z-значение.
При отрисовке следующих примитивов, видеокарта проверяет Z-координату рисуемых треугольников с Z-координатами в буфере и если Z-координата фрагмента больше (т.е объект за другим объектом), видеокарта просто не рисует пиксель.
В классических GAPI принято использовать режимы сравнения LEQUAL и LESS, однако с буфером глубины в Glide есть особенности: в самой видеокарте они хранятся в виде целочисленного 16-битного short (т.е до 65535 значений), причем обратного (1 / z). Поэтому в нашем случае, чем объект дальше от камеры, тем меньше его Z-координаты, а посему для корректной сортировки нужно необходимо выставлять режим сравнения GREATER. Но об этом немного позже — когда дойдем до фактической отрисовки треугольников.
Переходим к настройкам формата вершины.
Как я уже говорил ранее, 3dfx Voodoo оперирует координатами в абсолютных экранных координатах, про 3D он формально ничего не знает. Создать трёхмерное представление — задача программиста. X и Y — координаты треугольника в экранных координатах, Z-значение — для указания дальности вершины от камеры и сортировки, Q — т. н/ W-координата, необходимая для перспективного деления и перспективно-корректного текстурирования (про второе позже). R, G, B, A — цвет вершины. Позволяет, например, раскрасить ландшафт с помощью комбайнера в несколько проходов, или просто сделать модельку любого цвета, а TmuVertex — UV-координаты для корректного наложения текстур. Подробнее об этом будет в разделе текстур.
Кроме этого, нам необходимо каждый кадр очищать буфер цвета и глубины, а в конце рисования сцены — поменять передний буфер с задним, дабы мы могли увидеть нашу картинку на экране.
Это по сути минимальная инициализация Glide для рисования трёхмерной графики. После создания контекста, мы увидим синий экран. Нормальный синий экран/ :)
❯ Рисуем примитивы
Теперь переходим к самому интересному — рисованию треугольников! Однако до полноценного 3D-представления нам пока ещё рано. Сначала хотя-бы просто научиться выводить примитивы на экран.
Впрочем, ничего сложного в этом нет.
Перед рисованием геометрии, нам необходимо очистить (т. е. залить одним цветом) бэкбуфер и Depth-буфер. Бэкбуфер необходимо очищать только если ваша сцена не перекрывает весь экран — т. е. в ней есть не закрашенные участки. На современных видеокартах эта операция бесплатная, однако на видеокартах 90х от нее есть некоторый оверхед. Если бэкбуфер не чистить, то при передвижении камеры, мы будем наблюдать т.н «эффект зеркал» — поскольку новая геометрия рисуется поверх старой, то мы будем видеть старый кадр внахлест с новым:
grBufferClear(RGB(0, 128, 0), 0, 0);
Треугольники рисуются одной-единственной функций: grDrawTriangle, которая принимает ссылку на три структуры с описанием вершины. Формат вершины мы уже указали при инициализации, поэтому для отрисовки нам нужно лишь заполнить их данными:
Откуда же берутся текстуры, окраска и освещение, спросите вы? Может, есть какая-то система материалов как в Unity/UE? Дойдем и до этого, уже совсем скоро!
Уже после отрисовки сцены, нам необходимо поменять бэкбуфер и фронтбуфер местами — таким образом, мы избежим мерцания при отрисовке следующего кадра.
grBufferSwap(1);
Теперь у нас есть треугольник, выведенный средствами 3dfx Voodoo! Уже неплохое начало, но… где обещанное 3D!? Об этом — в следующем разделе!
❯ Математика и трансформации
Приготовьтесь, этот раздел будет звучать как учебник по матану — относительно сложно, но я постарался объяснить как можно проще и понятнее :) Если всё таки окажется сложновато — переходите к коду, понять будет гораздо проще. Строго говоря, по началу вам вообще необязательно знать детали реализации перемножения матриц и самих матриц трансформации, поскольку есть очень удобные математические библиотеки (glm и DXMath, например).
Важной составляющей в 3D-графике являются трансформации и матрицы. Если говорить простыми словами, то матрицы — многомерный массив чисел (в 3D-графике матрицы обычно имеют размерность 4х4), который позволяет представить трансформацию нашей будущей геометрии — например, модельки кораблика или героя. Например, умножив матрицу поворота на матрицу перемещения:
Matrix.RotationY(Math.DegToRad(90)) * Matrix.Translation(0, 0, 10);
Мы передвинем персонажа на 10 юнитов и повернем его на 90 градусов по оси Y. Например, компонент Transform в Unity строит мировую матрицу на основе позиции, поворота и масштабирования, которые вы задаете в инспекторе/коде.
В 3D-графике есть три основные матрицы, которые отвечают за положение объекта в мире и его представление из глаз наблюдателя:
Мировая матрица/матрица модели (OpenGL) — Положение рисуемой геометрии в глобальных мировых координатах. Пример с передвижением и поворотом относится именно к мировой матрице.
Матрица вида — Положение камеры в игровом мире. Трансформация камеры в мире имеет инвертированную систему координат — поскольку все передвижения объектов в глазах игрока — это как-бы вычитание позиции камеры из позиции объекта. Это значит, что для соответствия систем координат, все углы поворота и координаты необходимо инвертировать (-x, -y, -z). Умножив мировую матрицу на матрицу вида — мы получим координаты геометрии в пространстве наблюдателя.
Матрица проекции — Самая непонятная для некоторых матрица. Именно она преобразует координаты из пространства наблюдателя в Clip-Space (т.е абсолютные координаты треугольников в пространстве окна) и выдает нам W-координату, необходимую для перспективной проекции!
Таким образом, перед тем как быть нарисованной на экране, каждая вершина должна быть умножена на три матрицы — World/Model, View, Projection. Затем, на полученную матрицу необходимо умножить координаты самой вершины (в свою очередь, координаты вершины — это само строение 3D-модели):
vertex * (model * view * projection)
Насколько мне известно, с математической точки зрения это неверно — матрицы могут быть умножены только на матрицы той-же размерности. 4х-мерный вектор матрицой вообще не является, но там используется своя формула. Пожалуй, совсем уж в детали реализации математики не буду — это за рамками содержания статьи, но для общего понимания принципа работы 3D-графики, не только на 3dfx Voodoo, это необходимо.
Переходим к деталям реализации, здесь уже всё гораздо проще. Ниже приведена примитивнейшая, неэффективная и неоптимизированная «матлиба». Ну а что вы хотели, у нас таргет — Pentium MMX, там даже SIMD не было. :) Зато вполне наглядно.
И вот, наконец-то мы переходим к отрисовке самой графики!
❯ Рисуем 3D-модель!
Итак, что мы поняли из предыдущих разделов? Первым делом, нам нужно умножить каждую вершину на матрицу ModelViewProjection и исходя из позиционирования в абсолютных координатах, перевести координаты из Clip space в оконные. Ничего сложного!
Но сначала, давайте загрузим модельку. Я быстренько состряпал конвертер из SMD (собственный загрузчик, который таскаю из проекта в проект) в свой формат моделей.
И написал загрузчик. Обратите внимание, что формат вершин для Glide и для ваших вершин должен отличаться!
Теперь, когда у нас есть 3D-модель, её можно нарисовать.
Сначала нам необходимо трансформировать каждую вершину геометрии в Clip-space, матрица — ModelViewProj. Обратите внимание, что на этом этапе, нормальный рендерер реализовывает клиппинг геометрии. У нас его нет, используется аппроксимация, что обязательно будет выливаться в пропадание геометрии, если одна из её вершин уходят «назад» за камеру. Современные видеокарты делают клиппинг аппаратно:
После того, как мы подготовили вершины, необходимо преобразовать их из Clip-Space в абсолютные координаты окна и посчитать для них UV в координатной системе 3dfx Voodoo:
Обратите внимание на то, что каждая координата в Clip-Space делится на координату W — это называется перспективным делением, благодаря которому вершины отдаляются и приближаются в зависимости от позиции относительно глаз игрока! Здесь же рассчитывается координата Z для отрисовки перекрытой геометрии.
Перевод из Clip-Space в абсолютные координаты:
#define XVALUE_TO_WINDOW_SPACE(srcX, width) (width / 2) + (srcX * width);
#define YVALUE_TO_WINDOW_SPACE(srcY, width) width - ((width / 2) + (srcY * width));
И теперь, мы наконец-то, готовы нарисовать 3D-модель! Обратите внимание, что UV-координаты переводятся из 0..1 в 0..255 из-за особенностей TMU.
Вторая часть материала вот здесь. Пришлось бить на две части из-за ограничения в 30.000 символов.
Больше бэкстейджа, мыслей и проектов у меня вTelegram.
Дешевые китайские консоли с «AliExpress» — на чём работают бюджетные игровые гаджеты «за тыщу»?
Совсем недавно ярассказывалвам о такой популярной в прошлом консоли, как Тетрис и подробно описал возможности процессора, который в нём использовался. Думаю вам, моим читателям, тематика с разбором «подкапотки» различных редких девайсов как минимум достаточно интересна. Полагаю, многие мои читатели, которые увлекаются играми, а особенно ретро-геймингом, видели на маркетплейсах типа AliExpress «новодельные» игровые консоли с названиями X7, X12 и т. п, которые внешне повторяют Nintendo Switch и предлагают кучу пиратских ромов прямо из коробки! Сегодня мы с вами: выясним, что из себя представляют эти консоли изнутри, на каком чипсете они работают, узнаем немного об их программной платформе и разберемся, причём здесь MP5-плееры из нулевых. Интересно? Тогда жду вас в статье!
❯ Небольшая предыстория
Честно сказать, игровые консоли с эмуляторами ретро-систем были популярны всегда, это отнюдь не какой-то современный тренд. Начиная с их появления в середине-конце нулевых, эти девайсы постоянно сметались с полок магазинов благодаря какой-то неадекватной дешевизне, огромному количеству предварительно загруженных игр и неплохому функционалу, помимо, собственно, эмуляции игр. Основной ЦА таких девайсов предполагаются дети: в более юном возрасте все мы были не искушены вариативным геймплеем или крутой графикой, для многих из нас за счастье было попрыгать, играя за Марио, хотя среди пользователей очень часто находились и взрослые люди, которые хотели бы испытать те же эмоции, что испытывали когда-то сидя перед экраном советского телевизора.
Вообще, принято считать, что основными устройствами на рынке портативных систем являются консоли от Nintendo и Sony. Однако в наше время, это не совсем так: сейчас производители ретро-консолей создают свои собственные бренды и выходят на рынок с гораздо более интересными устройствами: вспомнить хотя-бы Miyoo, которые работают на базе собственного дистрибутива Linux, для которого можно писать свой нативный софт помимо запуска эмуляторов, или устройства от Anbernic, которые совмещают в себе функционал Android-смартфона и портативного игрового гаджета. Можно также вспомнить Sup GameBox — нашумевшая ультрадешёвая (~800 рублей или ~8$ на момент написания статьи) консоль с кучей игр для NES (Денди), возможностью подключения к телевизору, а также игры вдвоём с помощью дополнительного геймпада.
История «эмуляторных» консолей достаточно богата на события и устройства. Те, кто крутится в теме эмуляции достаточно давно, помнят такие легендарные устройства как Dingoo A320: очень популярная в своё время консоль с возможностью запуска сторонних эмуляторов и нативных игр (в основном, от китайских студий). Известна большим количеством несовместимых с ней клонов. Толчок популярности дал порт Linux: энтузиасты портировали ядро на MIPS-чипсет Ingenic JZ4760, благодаря чему появилось большое количество эмуляторов и портов игр, которые используют библиотеку SDL. Вышла в 2009 году.
Также была популярна консоль Ritmix RZX-50, которая являлась духовным наследником A320 и работала на базе того же чипсета от Ingenic. Отличия заключались в увеличенном объёме ОЗУ и более удобном дизайне: «кирпичик» A320 нравился не всем. Вышла в 2012 году.
Ближе к 2012-2013 году, стали появляться «эмуляторные» консоли на базе планшетного железа и ОС Android. Эти устройства работали на базе самых разных чипсетов: чаще всего использовались чипсеты Amlogic AML8726-M3 (1 ядро, 1ГГц, Cortex-A9, Mali 400), где-то использовались процессоры AllWinner (я видел только A10: одно ядро, 1ГГц, Cortex A8, Mali 400), в совсем топовых устройствах использовались чипы от Rockchip (и эти устройства были самыми ненадежными). Можно сказать, это было «новое дыхание» для этого рынка: во первых, помимо эмуляторов они тянули большинство Android-игр тех лет. В 2012 году, далеко не у всех были устройства на Android, многие ещё продолжали ходить с тачфонами или кнопочниками а-ля Samsung SGH-E250 и игры на смартфонах для них создавали вау-эффект. А во вторых, эти устройства вполне заменяли планшеты: у них был Wi-Fi, а иногда и 3G, благодаря чему покупатель потенциально получал сразу два устройства: консоль с эмуляторами и физическими кнопками + планшет для серфинга в интернете. Из подобных устройств вспоминаются устройства от JXD и их локализации в РФ: Exeq, Func, Smaggi и иные бренды.
Подобные устройства могут представлять игровую ценность и сейчас: на вторичке они очень быстро дешевеют до «шапки сухарей» — рабочий девайс можно взять в пределах 500 рублей.
И это я не говорю об огромном количестве «безымянных» устройств, которые просто выходили на рынок, локализовывались и продавались за довольно небольшой прайс. Относительно недавно рынок заполонили очень дешевые игровые консоли, которые формой и расцветкой напоминают PS Vita и Nintendo Switch. Брендов у этих устройств нет: обычно используются названия X7, X12 и т. п. — каждая обозначает, видимо, размер дисплея. При этом в программном плане они отличаются, в устройствах с одинаковым корпусом могут встретиться разные прошивки. Производитель обещает тысячи встроенных игр, а также кучу мультимедийных возможностей типа видео-плеера и даже… камеры. На «алике» и российских маркетплейсах стоят они достаточно недорого: в среднем 2-3 тысячи рублей за новое устройство. На барахолках новое или почти новое устройство можно взять за 1.000-1.500 (~10$) рублей — вполне лояльный прайс. Так поступил и я: взял X12 Plus за 1.000 рублей с интересующей меня прошивкой.
Правда я взял девайс с небольшим нюансов: левый аналоговый стик не работал по направлению вниз и на дрифт это не было похоже.
И вот, консоль пришла. Самое время её распаковать!
❯ Распаковка
Устройство поставляется в небольшой коробочке, где вкратце описаны характеристики устройства. Весьма забавляет маркетинг производителя: заявляется о «профессиональном» игровом чипе, большом количестве игр и т. п. В целом, производитель нигде не лукавит: в девайсе действительно предустановлено большое количество ромов, некоторые из них даже вынесены в основное меню.
Комплектация девайса не особо богатая: зарядка, кабель для подключения к телевизору (TV-Out, однако чипсеты этого производителя точно умеют HDMI и возможно на других ревизиях консоли он тоже распаян), инструкция и конечно же сама консоль. Сам девайс ощущается действительно большим, после классического форм-фактора PSP.
У девайса есть кнопка включения и рычажок питания, который видимо напрямую коммутирует массу с аккумулятора: дабы не портить АКБ при долгом простое.
❯ Что внутри?
Предлагаю разобрать девайс и узнать что у него внутри. Как я уже говорил, продавец заявил о нерабочем направлении «вниз» на левом стике, помимо этого, у консоли также туго нажимался левый триггер. Самое время посмотреть, на чем она работает под капотом и обслужить консоль! Разбирается девайс довольно просто — выкручиваем 4 винтика и снимаем крышку с клипс.
Разобрав девайс мы увидим следующую картину: приклеенный к плате аккумулятор, припаянный динамик (причём на корпусе есть место под второй динамик, а на плате пятачки под него — зависит от ревизии), на некоторых устройствах припаянный коаксиал с антенной. В целом, сборка консоли и разводка платы нареканий не вызывает — процесс производства таких консолей отлажен более 10 лет назад.
У устройств подобного плана высокая ремонтопригодность: резинки для кнопок можно попытаться найти в донорских устройствах, спикеры подходят от некоторых планшетов, в качестве АКБ вообще можно использовать хоть BL-4C, а про дисплеи мы поговорим немного позже.
А вот и причина плохой работоспособности нашего триггера. Боковые SMD-кнопки имеют свойство отваливаться, если их сильно и часто нажимать. Кнопки имеют два сигнальных контакта с обратной стороны и две крепежных ножки — именно они чаще всего выламываются. Пофиксить легко: некоторые снимают шелкографию и добавляют дополнительный припой для лучшего крепления, некоторые садят на клей. Я чаще капаю клей под «пузо» кнопки и запаиваю — работает нормально.
Переходим к стикам, которые взаимозаменяемы и их без проблем можно выпаять из донорских китайских консолей — они полностью идентичны. Конструкция их довольно простая: по сути, это два переменных резистора, которые выдают напряжение от 0в до 3.3в (референсное, может быть любым) по каждой оси. Разбираются они легко: поддеваем металлические крепления с длинной стороны (не с короткой!) и аккуратно разбираем стик. Здесь его достаточно почистить и всё будет работать нормально.
Однако несмотря на то, что стик фактический аналоговый, в большинстве подобных устройств он обрабатывается какцифровой— т. е. влево, вправо, вниз и вверх. Причём далеко не всегда есть возможность одновременно зажать несколько кнопок направления — что может стать проблемой в некоторых играх.
Самое интересное у устройства находится с обратной стороны. Отпаиваем аккумулятор, откручиваем винтики, крепящие плату, отсоединяем шлейфы и вытаскиваем материнку. Характеристики нашего устройства следующие:
Чипсет: ATJ2279B.
ОЗУ: Одна банка DDR1 NANYA на 64Мб. Эти чипы уже очень давно не производятся.
NAND: Infineon 29FI6808CCMEI. На чипе стоит маркировка ©'09. Потенциально, этот чип лежал на складе аж с 2009 года — более 14 лет! Даташит на этого чип не нашлось, на этикетке консоли написано 16Гб, по факту система видит 8Гб.
Дисплей: На этот раз, довольно «свежая» матрица MLHD5 2022 года выпуска.
Сам по себе ATJ2279B — это полноценная система на кристалле, которая уходит корнями аж в 2010 год. Да, никаких изменений за 13 лет в этих устройствах не произошло, кроме портирования новых эмуляторов. На данный чип естьподробный даташит, который описывает его возможности.
Вычислительное ядро: MIPS, на частоте до 450МГц с 16Кб кэша данных и 16Кб кэша инструкций.
GPU: 2D-графический ускоритель с поддержкой OpenVG 1.0. В прошивке, похоже, не используется — анимации тормозные.
Память: Контроллер DDR1/DDR2 памяти с максимальным объёмом до 256Мб и контроллер NAND-памяти с автоматической коррекцией ошибкой и ремаппингом бэдблоков. Теоретически, на данном чипсете можно запустить Android — поддерживаемый объём ОЗУ и производительность ядра позволяли это сделать, но производительность была бы достаточно низкой.
Дисплей: Поддержка TTL-матриц с разрешением до 1024x1024.
Ввод: Матричная клавиатура + резистивный тачскрин
ТВ: TVOut + HDMI в чипсете (однако на самой плате, HDMI не разведен).
USB: OTG хост + ведомое устройство.
Питание: 3.3-4.2в, встроенный контроллер для зарядки литий-ионных АКБ + ADC для мониторинга вольтажа аккумулятора при зарядке.
В начале статьи я говорил о том, что данные консоли имеют кое-что общее с MP5-плеерами нулевых. Процессоры компании Actions Semiconductor когда-то использовались в подобных устройствах именно как мультимедийные — они включали в себя DSP-сопроцессор для декодирования звука и работы с видео. Компания славилась тем, что предоставляла исходный код прошивки (на базе RTOS UCOS-II) с готовым плеером, драйверами и.т.п — благодаря чему, на рынке появилось много дешевых устройств, где производителям оставалось лишь кастомизировать интерфейс под себя. Со временем, производители портировали на эту прошивку различные эмуляторы, а сама прошивка научилась запускать сторонние бинарники — мне на флешке попадались so-библиотеки эмуляторов.
Так и появилось кучу самых разных мультимедийных игровых консолей за копейки. Процессоры Actions Semiconductor понемногу развивались — была даже вариацияG1000, которая имелся даже отдельный 3D GPU — Vivante GC и тянул игры уровня PS1, однако серьезного буста в производительности он не давал.
JXD5000 на базе G1000.
Производитель предлагал собственный SDK для разработки игр и эмуляторов под устройства на базе этих чипов. Китайские студии делали игры под эти устройства, но в публичный доступ утекало только SDK на Dingoo A320 и есть homebrew SDK для SPMP8k (консоль на котором я ищу). Естьнекий SDKс частичным исходным кодом прошивки: инструкций по сборке нет, но попробовать разобраться можно.
Отдельно хочется сказать про дисплей — их можно было найти в бюджетных планшетах 2010-2014 годов, в основном на базе чипов WM8650, AllWinner A10/A13, AMLogic AML8726-M и дешевых Rockchip. Поскольку родной дисплей по качеству очень «так себе», можно провести апгрейд, взяв матрицу с какого-нибудь нерабочего планшета за 100 рублей с юлито. 100% подходят матрицы от китайских реплик первого iPad с диагональю 7". Это повышает ремонтопригодность гаджета — битые планшеты на всяких скупках можно найти почти в каждом городе. Главное обращайте внимание на форму шлейфа, перед покупкой гуглите "<модель планшета> матрица" и сверяйте с своим. В остальном они должны быть совместимы.
Родная матрица.
Подкинул дисплей от реплики iPad.
Общение с дисплеем идёт по протоколу RGB, 60 пиновый шлейф, распиновка стандартная: её я прикладываю ниже. Дисплеи 40pin (навигаторы), 50pin (планшеты), 60pin (чуть более свежие планшеты с отдельной подсветкой) хорошо стандартизированы и обычно без каких либо проблем взаимозаменяемы:
Собираем девайс обратно. Самое время протестировать устройство в играх!
❯ Играем
При включении устройства, нас встречает забавная анимация и главное меню, которое предлагает следующие возможности:
Какие эмуляторы у нас есть? Давайте смотреть:
NES
SNES
SMD
GB
GBA
В целом — весьма неплохо. Но как у них с производительностью? Давайте посмотрим:
Эмулятор GBA идёт отлично. Даже довольно тяжелые 3D-игры типа NFSU2 идут без каких либо проблем и «рваного» звука. Не могу ничего сказать насчет серьезного пропуска кадров, но в целом этот ром играется неплохо, как и например Street Fighter II:
Эмулятор SMD идёт плюс-минус нормально. Видны кое-где корректировки пропуска кадров, но в целом вполне играбельно. Что странно: при таком объеме встроенной памяти, в консоли всего чуть больше 40 ромов для NES и среди них нет ни Earthworm Jim, ни Sonic The Hedgehod! Ну как так-то! 2.5D игры идут неплохо.
Эмулятор SFC (SNES) идёт сносно. Ромов реально довольно много и среди них попадаются такие занимательные игры, как Metal Warriors: Run & Gun сайдскроллер про огромного меха. Игры идут вполне хорошо, правда я не тестировал более тяжелые игры для SNES, которые могут использовать альфа-канал, например.
Ну и эмулятор NES, с учетом того, что SNES и GBA здесь идут нормально, тоже работает хорошо. Для этой консоли здесь больше всего ромов: как минимум, несколько сотен. Возможности поиска (вроде-бы нет), поэтому навигация по играм может быть не очень удобной.
В целом, консоль весьма неплохо справляется с прямым предназначением — эмуляцией. Кое-где есть слабые места, но это не так критично. Консоль умеет прикидываться USB-флэшкой, благодаря чему на неё можно залить новые ромы или, например, музыку, видео или электронные книги (дисплей здесь очень «так себе» для чтения, глаза быстро устанут). С музыкой есть нюанс: возможно мне попался брак, илиу моих наушников джек слишком короткий, но в моей консоли работает только один канал на звук. Качество вполне неплохое, на уровне MP3-плееров начала 2010х готов, но с Hi-Fi плеерами очевидно не сравнится.
❯ Заключение
Лично как по мне, платформа сама по себе перспективная, как и вся задумка в целом, но подкачала реализация. Если бы китайцы выпустили нормальное SDK для инди-разработчиков, то авось выходили бы порты новых эмуляторов и весьма интересных игр. Конечно на этой консоли можно без проблем поменять дисплей на более качественный, или поставить АКБ побольше (благо места в корпусе просто завались), но экспиренс от игры улучшается совсем незначительно. Если у вас небольшой бюджет, я порекомендую смотреть в сторону старых консолей на Android: у них обычно и дисплеи гораздо лучше, и производительность отличная и они вполне могут послужить и планшетом: клиенты ВК и YouTube на Android 4.x есть.
Вот так работают игровые консоли «под капотом». Эти устройства практически не поменялись за 10 лет, да и зачем? Свою функцию ультрадешевых устройств они выполняют нормально, а это самое главное. Конечно хотелось бы иметь версию с чуть-более качественным IPS-дисплеем и нормальным аналоговым стиком, но если так посмотреть — они уже есть и от более именитых производителей. Причем в разных форм-факторах: кому-то нравится GBA, а кому-то PSP.
Покупать ли такой девайс себе? В качестве основного устройства для игры — я бы не стал, ребенку — вполне возможно. Решайте сами :)
Статья подготовлена при поддержке TimeWeb Cloud. Подписывайтесь на меня и @Timeweb.Cloud , чтобы не пропускать новые статьи каждую неделю!