Я не кодирую для STM32 , поэтому даже код выглядит для меня чуждо, однако звучит так, будто вы жестко кодируете отдельные пиксели с таймером ... и генерируете сигнал VGA с помощью некоторого GPIO. Эта комбинация методов проблематична c для использования в программируемой графике.
Я использую AVR32 ( UC3A с гораздо более медленными по сравнению с вашими часами) для создания изображения VGA с использованием:
экранный буфер (видеорам)
просто у меня все изображение экрана хранится в памяти MCU. Таким образом, вы можете просто изменить его содержимое без изменения выходного кода VGA ...
Проблема в том, что вам необходимо иметь достаточно памяти для изображения (закодировано таким образом, чтобы обеспечить прямую передачу на разъем VGA). Я использую AVR32 с 16 + 32 + 32 КБ ОЗУ, но у большинства микроконтроллеров гораздо меньше ОЗУ (изображения STATI c могут быть сохранены в СППЗУ, но тогда будет невозможно изменить вывод изображения). Таким образом, в случае, если вам не хватает либо более низкого разрешения для размещения в памяти, либо для добавления внешней памяти в вашу систему.
используйте встроенную периферийную периферию HW для генерации сигнала VGA
У меня работает больше версий генерации сигнала VGA:
- SDRAM ... с использованием интерфейса SDRAM MCU
- SM C ... с использованием SM C интерфейс MCU
- SS C ... с использованием синхронного последовательного интерфейса
Все сводится к копированию экранного буфера в интерфейс ввода-вывода на VGA Точечные часы (~ 30 МГц) . Затем на стороне HW, объединяя используемые выводы MCU в сигналы VGA
для скорости, вы можете использовать DMA.
Помимо всего этого вам нужно генерировать сигналы syn c, и это все .
Посмотрите на таблицу данных MCU и найдите интерфейс, способный к синхронной передаче как минимум 3-битных данных (R, G, B) с тактовой частотой VGA. Чем ближе часы к точечным часам VGA, тем лучше (поскольку некоторые VGA-мониторы и ЖК-дисплеи не допускают слишком большой разницы)
синхросигналы c могут быть жестко закодированы или даже закодированы в видеопамяти.
Самый быстрый способ - использовать последовательный интерфейс, но на выходе получается только черно-белый, а не RGB (если вы не получили 3 SS C единиц / каналов), однако вы можете отправлять целые 8/16/32 пикселей одновременно или напрямую через DMA поэтому у MCU есть время для других вещей, а также требуется гораздо меньше VRAM.
Мой любимый интерфейс SDRAM (используя только его шину данных)
Здесь изображение из моей системы :
![AVR32 VGA output](https://i.stack.imgur.com/8ZM6w.jpg)
Взаимосвязь шахты выглядит следующим образом (с использованием версии интерфейса MCRs SDRAM):
VGA <- AT32UC3A0512
R PX10 (EBI_D0)
G PX09 (EBI_D1)
B PX08 (EBI_D2)
Bright PX07 (EBI_D3)*
HS PA03
VS PA04
Здесь соответствующий источник:
VGA_EBI_SDRAM C .h:
//------------------------------------------------------------------------------------------------
#define _PA_VGA_HS 8
#define _PA_VGA_VS 16
#define _PAmo 24
volatile avr32_gpio_port_t *port_PA=&GPIO.port[AVR32_PIN_PA00>>5];
volatile U8 *SDRAM=(U8*)AVR32_EBI_CS0_ADDRESS;
//------------------------------------------------------------------------------------------------
//--- VGA 640x480x4 60Hz -------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
#define VRAM_xs 304
#define VRAM_ys 400
#define VRAM_bs 4
#define VRAM_ls (VRAM_xs>>1)
U8 VRAM[VRAM_ls*VRAM_ys];
U8 VRAM_empty[VRAM_ls];
// Horizontal timing [us]
#define VGA_t0 3
#define VGA_t1 5
#define VGA_t2 32
// Vertikal timing [lines ~31.817us] aby voslo viac bodov tak je to natiahnute na 32us++
#define VGA_ys 525
#define VGA_VS 2
#define VGA_y0 (36+40)
#define VGA_y1 (VGA_y0+VRAM_ys)
//------------------------------------------------------------------------------------------------
void VGA_init();
void VGA_screen();
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
void VGA_init()
{
system_init();
Disable_global_interrupt();
gpio_configure_pins(port_PA,_PAmo,GPIO_DIR_OUTPUT|GPIO_INIT_HIGH);
static const gpio_map_t EBI_GPIO_MAP[] =
{
{ AVR32_EBI_DATA_0_PIN, AVR32_EBI_DATA_0_FUNCTION},
{ AVR32_EBI_DATA_1_PIN, AVR32_EBI_DATA_1_FUNCTION},
{ AVR32_EBI_DATA_2_PIN, AVR32_EBI_DATA_2_FUNCTION},
{ AVR32_EBI_DATA_3_PIN, AVR32_EBI_DATA_3_FUNCTION},
};
gpio_enable_module(EBI_GPIO_MAP, sizeof(EBI_GPIO_MAP) / sizeof(EBI_GPIO_MAP[0]));
AVR32_SDRAMC.mr=0; // normal mode
AVR32_SDRAMC.tr=0; // no refresh (T=0)
AVR32_SDRAMC.cr=
(AVR32_SDRAMC_CR_NC_11_COLUMN_BITS <<AVR32_SDRAMC_CR_NC_OFFSET)
|(AVR32_SDRAMC_CR_NR_13_ROW_BITS <<AVR32_SDRAMC_CR_NR_OFFSET)
|(AVR32_SDRAMC_CR_NB_TWO_BANKS <<AVR32_SDRAMC_CR_NB_OFFSET)
|(AVR32_SDRAMC_CAS_ONE_CYCLE <<AVR32_SDRAMC_CR_CAS_OFFSET)
|(AVR32_SDRAMC_DBW_16_BITS <<AVR32_SDRAMC_CR_DBW_OFFSET)
|(0 <<AVR32_SDRAMC_TWR_OFFSET)
|(0 <<AVR32_SDRAMC_TRC_OFFSET)
|(0 <<AVR32_SDRAMC_TRP_OFFSET)
|(0 <<AVR32_SDRAMC_TRCD_OFFSET)
|(0 <<AVR32_SDRAMC_TRAS_OFFSET)
|(0 <<AVR32_SDRAMC_TXSR_OFFSET);
AVR32_SDRAMC.hsr=AVR32_SDRAMC_HSR_DA_MASK;
AVR32_SDRAMC.mdr=AVR32_SDRAMC_MDR_MD_SDRAM;
// map SDRAM CS -> memory space
AVR32_HMATRIX.sfr[AVR32_EBI_HMATRIX_NR]|=1<<AVR32_EBI_SDRAM_CS;
AVR32_HMATRIX.sfr[AVR32_EBI_HMATRIX_NR];
U32 a;
for (a=0;a<VRAM_ls*VRAM_ys;a++) VRAM[a]=0;
for (a=0;a<VRAM_ls;a++) VRAM_empty[a]=0;
}
//------------------------------------------------------------------------------------------------
void VGA_screen()
{
U32 a,x,y,c,PA,t0;
wait_start(t0);
for (;;)
{
for (PA=_PAmo,a=0,y=0;y<VGA_ys;y++)
{
wait_start(t0);
if (y== 0) PA^=_PA_VGA_VS; else PA^=0; // VS on
if (y==VGA_VS) PA^=_PA_VGA_VS; else PA^=0; // VS off
PA^=_PA_VGA_HS; // HS on
port_PA->ovrc=PA^_PAmo;
port_PA->ovrs=PA;
wait_us(t0,VGA_t0);
PA^=_PA_VGA_HS; // HS off
port_PA->ovrc=PA^_PAmo;
port_PA->ovrs=PA;
wait_us(t0,VGA_t1);
*SDRAM=0; // blank (black)
if ((y>=VGA_y0)&&(y<VGA_y1))
for (x=0;x<VRAM_ls;x++)
{
c=VRAM[a];
*SDRAM=c>>4; // write pixel into SDRAM interface (address is ignored as I use only data bus pins)
a++;
*SDRAM=c; // write pixel into SDRAM interface (address is ignored as I use only data bus pins)
}
*SDRAM=0; // blank (black)
wait_us(t0,VGA_t2);
}
}
}
//------------------------------------------------------------------------------------------------
Main. cpp:
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
#include "System\include.h"
#include "pic_zilog_inside.h"
//#include "VGA_EBI_SMC.h"
#include "VGA_EBI_SDRAMC.h"
//#include "VGA_SSC.h"
//------------------------------------------------------------------------------------------------
void pic_copy(U8 *dst,U32 dst_xs,U32 dst_ys,U32 dst_bs,U8 *src,U32 src_xs,U32 src_ys,U32 src_bs)
{
U32 x0,y0,a0,l0;
U32 x1,y1,a1,l1;
U32 a; U8 c,m;
l0=1; l1=1;
if (dst_bs==1) l0=dst_xs>>3;
if (dst_bs==2) l0=dst_xs>>2;
if (dst_bs==4) l0=dst_xs>>1;
if (dst_bs==8) l0=dst_xs;
if (src_bs==1) l1=src_xs>>3;
if (src_bs==2) l1=src_xs>>2;
if (src_bs==4) l1=src_xs>>1;
if (src_bs==8) l1=src_xs;
for (a0=0;a0<dst_ys*l0;a0++) dst[a0]=0;
for (y0=0;y0<dst_ys;y0++)
{
y1=(y0*(src_ys-1))/(dst_ys-1);
a0=l0*y0;
a1=l1*y1;
for (x0=0;x0<dst_xs;x0++)
{
x1=(x0*(src_xs-1))/(dst_xs-1);
c=0;
if (src_bs==1)
{
c=src[a1+(x1>>3)];
c>>=7-(x1&7);
c&=1;
}
if (src_bs==4)
{
c=src[a1+(x1>>1)];
if (U32(x0&1)==0) c>>=4;
c&=15;
}
if (dst_bs==1)
{
c<<=7-(x0&7);
a=a0+(x0>>3);
dst[a]|=c; if (!c) dst[a]^=c;
}
if (dst_bs==4)
{
if (c) c=15;
if (U32(x0&1)==0) { c<<=4; m=0x0F; } else m=0xF0;
a=a0+(x0>>1);
dst[a]&=m;
dst[a]|=c;
}
}
}
}
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
int main(void)
{
VGA_init();
pic_copy
(
(U8*)VRAM,
VRAM_xs,
VRAM_ys,
VRAM_bs,
(U8*)pic_zilog_inside,
pic_zilog_inside_xs,
pic_zilog_inside_ys,
pic_zilog_inside_bs
);
VGA_screen();
}
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
pic_zilog_inside.h:
const U32 pic_zilog_inside_xs=640;
const U32 pic_zilog_inside_ys=480;
const U32 pic_zilog_inside_bs=1;
const U32 pic_zilog_inside[]= // hard coded image
{
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
...
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
};
Функция pic_copy
просто копирует жестко закодированное изображение в VRAM.
Функция VGA_screen()
создает бесконечный сигнал VGA l oop, поэтому другие задачи должны быть закодированы в ISR или жестко закодированы в код паузы или между отдельными кадрами (однако это действительно требует моей настройки, так как я получил небольшие тактовые частоты MCU, поэтому нет много места для других дел). VRAM кодируется в 16 цветах (4 бита на пиксель)
8 4 2 1
Brightness B G R
Яркость должна просто добавить некоторое напряжение к R, G, B с небольшим количеством резисторов и диодов, но более новая реализация реализована на стороне HW, вместо этого у меня есть эта схема (только 8 цветов):
![VGA](https://i.stack.imgur.com/xzwHv.png)
Диоды должны быть быстрыми при одинаковом барьерном напряжении, а конденсаторы - 1 нФ. Это позволяет избежать сбоев изображения из-за использованной синхронизации интерфейса шины данных. Также диоды необходимы для яркости, если они будут добавлены в будущем, для получения дополнительной информации см. Проблему тока R2R здесь: