Графический VGA-модуль для микроконтроллеров

В статье Текстовый VGA-модуль для микроконтроллеров я рассказывал о доработанном варианте терминала 64х30 символов. 15 цветов. Всё хорошо, сделал плату, допилил софт под себя, но текст это текст. Только символы и только 8х16. Можно конечно рисовать псевдографикой. Таблички выходят на ура. Я даже написал колхозную функцию увеличения цифр. Работает достаточно шустро:

И что-то можно изобразить похожее на интерфейс

 (данное фото сделано на тапок)

Но, черт возьми, как рисовать диагональные линии ? В принципе, если хорошенько дунуть пораскинуть мозгами, то можно из этой таблицы символов

выкинуть всё не нужное и заменить на своё. Как собственно это сделано с логотипом Microchip. (Символы с кодами с 0x80 по 0x98, выстроенные в 5 рядов по 5 символов, образуют графическое изображение логотипа Microchip.) Ну то есть взять и выкинуть например английский алфавит. Или русский. Или всякие стрелочки и параграфы с тильдами и стрелочками. Получаем кучу символов, которые можно перерисовать и сделать части окружностей, дуг, диагональные линии и.т.д. Потом наколбасить библиотеку, которая будет рисовать кривые этой псевдографикой. Но что-то это сильно пахнет адским геморроем и я начал искать варианты с графикой.

Конечно, выводить на VGA-монитор информацию средствами микроконтроллера — это жесть. Те, кто знает что для этого нужно делать и с какой скоростью, меня поймут. А тем, кто не знает, 2 варианта: 1) читать принцип формирования vga-сигналов 2) поверить на слово, что борьба идет за каждый такт.

Поиск дал неутешительные результаты. Есть разработки 800*600, но опять только текстовый режим. Есть графический цветной, но 128*96 (Черт возьми, представил себе 19″ монитор с картинкой такого разрешения). Есть какой-то мутный проект на ATmega644P якобы 640*480 256 цветов, что при 20МГц атмеге просто не реально. К этому видео отключены комментарии. Есть проект 40*30 символов и 320*240 на dsPIC33E. Кроме как побаловаться и поизобретать Dendy лично я никаких перспектив не вижу. Есть на STM32F103 проект 256×192 с 64 цветами. Тоже сега мега драйв… и еще один на этом же камне 400*200 черно-зеленый. Есть проекты на микроконтроллере STM32F4. Выход: 800х600 60 Гц, разрешение 400х300. Очень жирное железо для такой задачи, и то не справляется. И туева хуча проектов аля «тестер монитора». Это можно соорудить и на pic12f629, тупо закрасив весь экран в один цвет. Толку от такой «видеокарты» мало. Почему-то все эти проекты делают упор на сохранение многоцветности и/или использование двойной буферизации. Отсюда и расход памяти, отсюда и низкое разрешение. Конечно быстрее протолкнуть 400*300 чем 800*600. Аж в 4 раза быстрее 🙂 Нет, есть проекты даже с буфером в SDRAM и какими-то (даже углубляться не стал) микрухами с аппаратным формированием сигналов vga, но сложность этих схем, громоздкость и стоимость перечеркивают всё на корню. Кому нахрен нужен модуль вывода графики c микроконтроллера на монитор через HDMI в FullHD и 16М цветов за 158$ ? Микроконтроллер же не успеет ничего формировать. Ну сколько у вас займет чтение с SD-карты фотографии 2-3Мб на 8-и битной ардуине и проталкивание этого добра в модуль? А именно такие объемы и захочется. Иначе зачем полноцветный 1080p?

В этом плане RaspberryPi Zero и дешевле и функциональнее. Как же так ? Неужели невозможно по-простому сделать выход 640*480 с разрешением 640*480 ? Просто сделать дисплей 12864 так, чтобы он был 640480 🙂 Для ч/б варианта это 38,4кБ памяти. (видимая область). Вообще ни о чем по нынешним меркам. То есть diy-мейкеры довольствуются дисплейчиками 1602, 2004, 12864 и всякими 0.96″ OLED. Нет, ну я тоже их использую, когда это необходимо. Но только когда это необходимо и достаточно.

Но это всё «синяя изолента». О проекте контроллера для сауны напишу позднее.

Вот в нем планировалось использование этих дисплеев. А как же развитие ? А как же стремление вперед ? То есть крайности какие-то. Или быстро, дешево и убого 2″, или медленно и дорого, но в полном разрешении и цветности. 21-ый век на дворе, а с ардуины мы можем максимум куда вывести изображение — это на модуль 320*240, который 5″ LCD, задействуя кучу ног. О быстродействии не буду судить, ибо даже не пытался. Причем это как минимум должна быть arduino mega на Atmega2560. Для нее шилд и делался. Младшие довольствуются вышеупомянутыми сине-белыми штуками. Есть Nextion HMI, но опять же цена. Проще купить самый дешевый планшет и забыть про микроконтроллеры, погрузившись в программирование под Андройд.

Отвлекся я сильно. Вижу что утомил 🙂 Ну так вот… Тот же самый Игорь прислал мне «в подарок» на ДР схему графического терминала 640*480 одноцветный. И код к ней!. Как знал что я мучаюсь…

Уж не знаю, его это разработка или нет, не суть, все равно большое человеческое спасибо за идею. На тот момент для меня vga конечно был темный лес, но код-то на СИ! Ух я сейчас развернусь!… и развернулся. Как обычно, прога была не доделана, но, как известно, дареному коню в зубы не смотрят 🙂 Такое чувство, что в порыве стремления к прекрасному люди просто в какой-то момент перегорают идеей и бросают. Резко и навсегда. Тут надо помнить про Леонардо да Винчи, который 12 лет губы Моны Лизы рисовал. Потому-что часто отвлекали: то сделай им водокачку, то кран подъёмный, то летать хотим… 🙂 Это наверное про теорию «80/20». Когда 80% работы делается за 20% времени. Остальные 20% работы делается за 80% времени. Но уже лень столько времени тратить ради мизерного результата по сравнению с уже сделанным. За собой тоже такое замечал, но нашел по-моему гениальный выход из этого адского круга: всеми своими проектами я занимаюсь по спирали. Перегорел одним — пошел развивать другой. Потом вернулся. Ну, например, свежая мысль пришла.

Итак, опять схема без платы… Геморрой… (то же мне, любитель всего готовенького) Ну ничего 🙂 По-быстрому наваял рисунок, сделал плату, как обычно, в духе адского минимализма.

А заодно, раз уж управление VGA-модулем подразумевается через UART, развел на плате FT232RL чтобы можно было прямо из программы-терминала посылать команды в виртуальный COM-порт. Мозг уже рисовал в воображении, что можно ведь несколько таких модулей подключить по USB и выводить на несколько мониторов информацию из своей программы на том же C#. Благо команды однобайтные и никакого труда не составит воплотить клиента на любом языке программирования.

Как-то вот так оно и подключалось: с одной стороны USB, с другой, блин… Монитор! 🙂

Сам удивляюсь как смог всё разместить на плате таких размеров. И тут понеслось… Во-первых код написан как псевдомногозадачная система. Отдельная задача на UART, отдельная задача на изменение буфера, и.т.д. А сам вывод в монитор через DMA. 2 таймера для синхронизаций и весь массив буфера строк непрерывно валится в SPI. Любое фоновое изменение массива моментально отображается на экране. Это гениально. Но мог бы и сам догадаться… наверное… сильно позже. Во-вторых в какой-то момент произошел взрыв срыв. Я удалил всё что было в коде, оставив только инициализацию переменных и DMA. А всё остальное написал заново. Ну не могу я в чужом коде копаться, особенно когда он не дописан. Точнее заточен именно на вывод текста а не графики. Текст меня как-то мало интересовал уже.

// отображение пикселя
case WORK_PUT_PIXEL:
break;

Ну как так-то ? 🙂 Это же самое главное 🙂 А если учесть что 640 это больше чем 1 байт, то для передачи координат одного пикселя нужно использовать 2 байта на X и 2 байта на Y… И писал я долго и упорно…

В итоге функция рисования линии по двум точкам стала одной функцией а не тремя. (Хотя я понимаю, это было для быстродействия). Мой код в этом нисколько не проиграл. Функцию рисования окружностей сделал по алгоритму Брезенхэма. У Этого дядьки окружности более округлые. Переписал все команды по-своему, а их там 31. Сделал рисование не только белым, но и черным. Задаваемую толщину линий. Закраску прямоугольников и окружностей. Встроил второй громадный шрифт. Запилил пропорциональное увеличение шрифта 8*16 на заданную величину множителя. Убил весь обратный вывод в UART. Не нужно ничего отвечать на команды. Просто рисуй быстрее. Одно подтверждение обработки команды тормозит вывод графики в десятки раз. Естественно добавил кольцевой буфер на 1024 байта. Конечно UART в этом смысле достаточно убогий по скорости интерфейс, но зато более универсальный. Во-первых, в микроконтроллере их может быть несколько, а во-вторых, можно и в ПК воткнуть. I2C интерфейс убил по-этой же причине. Да и в скорости он не сильно выигрывает, особенно софтварный.

Далее пошли первые тесты. (фотографировал на тапок)

Округлые окружности

Прямоугольнички

А дальше пошел писать библиотеку для ардуино. В этом плане всё проще. Берем стандартный класс SoftwareSerial и наследуемся от него, добавляя свои функции.

#include "VgaSoftwareSerial.h"
VgaSoftwareSerial::VgaSoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false): SoftwareSerial(receivePin, transmitPin, inverse_logic = false) {}

Можно конечно юзать и HardwareSerial, но их в ардуине гораздо меньше чем SoftwareSerial 🙂 Cофтовый UART спокойно работает на 115200 и в arduino nano (Atmega328) и в arduino pro micro (Atmega32u).

class VgaSoftwareSerial : public SoftwareSerial {
public:
VgaSoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false);

void cls(void);
void pixel(int x1, int y1, uint8_t color);
void setcolor(uint8_t color);
void setcursor(uint8_t x1, uint8_t y1);
void line(int x1, int y1, int x2, int y2, uint8_t color);
void rectangle(int x1, int y1, int x2, int y2, uint8_t color, uint8_t filling);
void circle(int x1, int y1, uint8_t color, uint8_t radius, uint8_t filling);
int version(void);

private:
};

Собственно всё рисование сводится к последовательной подаче байт в UART.

Пиксель:

void VgaSoftwareSerial::pixel(int x1, int y1, uint8_t color)
{
    uint8_t buf[] = {0x11, // команда установки X1 Lo
                       x1, // значение X1 Lo
                     0x10, // команда установки X1 Hi
                  x1 >> 8, // значение X1 Hi
                     0x13, // команда установки Y1 Lo
                       y1, // значение Y1 Lo
                     0x12, // команда установки Y1 Hi
                  y1 >> 8, // значение Y1 Hi
                     0x03, // команда установки цвета пикселя
                    color, // значение цвета пикселя
                     0x0A  // команда рисования пикселя
                    }; 
    VgaSoftwareSerial::write(buf, 11);
}

А так рисуется линия:

void VgaSoftwareSerial::line(int x1, int y1, int x2, int y2, uint8_t color)
{
uint8_t buf[] = {0x11, x1, 0x10, x1 >> 8, 0x13, y1, 0x12, y1 >> 8, 0x15, x2, 0x14, x2 >> 8, 0x17, y2, 0x16, y2 >> 8, 0x03, color, 0x0B};
VgaSoftwareSerial::write(buf, 19);
}

В самом скетче всё еще проще:

#include "VgaSoftwareSerial.h"
VgaSoftwareSerial MonitorOne(8, 9);
VgaSoftwareSerial MonitorTwo(10, 11);
MonitorOne.pixel(320, 240, 1);
MonitorTwo.pixel(320, 240, 1);

И на обоих мониторах рисуется точка по центру.

Обкатанные платы были заново отрисованы в DipTrace и отправлены на завод.

Изменилась схема питания. Применен прекраснейший DC-DC преобразователь LM3671MF. Платы стали еще меньше.

И это, на минуточку, PIC32. Расту над собой 🙂

Такими же нехитрыми командами был наколбашен тест всего что есть в модуле.

В дальнейшем использовал сей девайс для отрисовки приборной панели для второй версии автомобильчика.

Ну и 3D до кучи:

Данный VGA-модуль доступен в 4х вариантах исполнения и вы можете его приобрести в соответствующем разделе.

Буду рад вопросам и комментариям. Еще больше буду рад рационализаторским предложениям.

Об авторе demid

Однажды открыл для себя микроконтроллеры и с тех пор не отпускает...
Запись опубликована в рубрике VGA-модуль. Добавьте в закладки постоянную ссылку.

10 комментариев на «Графический VGA-модуль для микроконтроллеров»

  1. bubastic говорит:

    Добрый день,
    отличное решение, но цена слишком велика для железа подобного типа.
    т.е. я не имю ввиду, что Вы задорого продаете, а скорее, что подобный шилдик должен стоить 500-600 руб. и это самый максимум.
    Честно говоря, когда пошел посмотреть цену так и думал руб. 600, но за 1700… я подожду распродаж 😜, или дед мороза.

    • demid говорит:

      Готов продать дешевле. Если найдете аналогичный товар дешевле.
      Исходные данные для поиска: графический, одноцветный, 640х480
      Вы мне ссылку — я вам цену ниже того, что вы найдете.

  2. Глеб говорит:

    Согласен с предыдущим человеком, очень дорого. Рублей 500-600 адекватная цена, прибыль количеством возьмете.

  3. Алексей говорит:

    bubastic правильно говорит. Нельзя быть таким жадиной))
    Лично я черно белую графику и за 500 не купил бы)
    Для вывода какой никакой цветной информации на VGA дисплей подойдет проект из двух ардуино nano за 300 рублей на все про все.
    https://habr.com/ru/post/348380/
    https://www.instructables.com/id/Arduino-Basic-PC-With-VGA-Output/

    А если более серьезно подойти к вашей теме то самый разумный вариант купить
    ESP32 за те же 300 рублей
    и получить разрешение пусть и 640×350 но зато 8 цветов!
    Только посмотрите какая красота всего за 300 рублей!
    https://www.youtube.com/watch?v=TRQcIiWQCJw
    И все это даром позволяет библиотека FabGL посмотрите сколько всего интересного и не нужно никакие 1400-1700 рублей.
    http://www.fabglib.org/index.html
    И Глеб правильно говорит, лучше брать количеством, это лучше чем ничего или мало 🙂

    • demid говорит:

      Повторюсь, если вам нужен vga-адаптер 20х10 символов — делайте его на ардуино.
      Если вам нужен 640*200 и 8 цветов — берите ESP32 и делайте на ней.
      Как только у вас будет коммерческий проект а не просто поиграться и забыть —
      берите stm32 или pic32 и делаете самостоятельно 640*480. Это будет качественнее
      чем тормозные 320*240 глубенькие дисплеи.
      Простите, не готов продавать за 500р железку, в которой только МК стоит 400.
      Если кто-то готов за 100р работать — позвоните мне. Я вам дам работу.

  4. Михаил говорит:

    Здравствуйте.Очень понравилась Ваша отктовенность.100% с Вами согласен.
    Обидно когда критикуют своими фонтазиями а не реальной разработанной рабочей конструкцией.Очень возмутили коментарии.
    Я простой пенсионер,немного на асм-е програмирую pic16F,только для себя
    Я не занимаюсь комерцией.
    Извините ,отнял Ваше время на пустое отступление.
    Главное У меня появилась идея куда применить устаревшие мониторы благодаря Вашей разрабтке.т.е. добавить затраты 3,5 евро и уверен девайс пойдет на ура.
    У меня рабочий образец на фото и видео ,если Вас заинтересует все покажу

    Надеюсь на ответ и сотрудничество
    С уважением Михаил

  5. Игорь говорит:

    Попытался все это добро запустить на esp-wroom-32 и не очень то это получилось!
    Хорошо конечно хоть что то отражает на экране, значит платка работает, но
    библиотека SoftwareSerial тут (под ESP32) видимо не такая т.к. последний параметр пришлось выпилить, а без него видимо на экран получаем чушь.
    Под капот пока сильно не лез, но видимо придется, хочется задействовать данный девайс!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

*

code