Sari la conținut
ELFORUM - Forumul electronistilor

Sa generam semnal VGA cu PIC. O istorie din 2008


Postări Recomandate

Unul din motivele pentru care provocarea cu timing-uri a lui @Liviu.Mihaiu a nimerit pe strada mea este ca acum un deceniu si putin, mi-am facut de lucru incercand sa generez semnal VGA cu un PIC. Scopul exercitiului nu a fost unul practic, ci educational, sa vad ce implica treaba asta.

 

Pentru inceput, o cautare pe internet mi-a oferit datele de baza (frecventele de sincronizare orizontala si verticala, cate linii nu sunt vizibile samd).

Un program simplu (in ASM) a dat semnalele de sincronizare cand am presupus ca trebuie, iar apoi a generat si un pattern ca sa vad ceva pe monitor. Toate temporizarile au fost facute numarand ciclii masina. Frecventa de functionare initiala a PIC-ului a fost 14.31818MHz (aveam un oscilator la indemana). Primul rezultat:
vga01.jpg
Grosimea liniilor verzi din pattern este "un ciclu masina", adica:

BSF        PORTB,2        ; RASTER - ON
BCF        PORTB,2        ; RASTER - OFF

Spatiul dintre linii este relativ mare pentru ca sunt generate intr-o bucla, decrementarea contorului si GOTO-ul dureaza si ele.

Pe vremea aia aveam osciloscop cu lampi, ca vai de el, dar tot mai bun decat nimic.

 

Per total, fara sa fac nimic altceva as avea deci vreo 80 de "pixeli" pe X la aceasta frecventa, dar daca trebuie mai multe instructiuni per pixel (conditii/citire din RAM) ar fi doar 17.. aaa.. pixeli pe linie. Deci imagine arbitrara nu se poate, dar poate se pot face niste patternuri. De exemplu cifre hexa: 0 - F. In cazul acesta ar putea fi emis pixel pattern-ul corespunzator caracterului ca o rafala de "out"-uri (BSF/BCF pe PORTB).

 

Am prestabilit pattern-uri de OUT-uri pentru fiecare linie a fiecarui caracter, facut un tabel cu ele si salt calculat in acel tabel. Alegerea paternului, saltul si intoarcerea dureaza 9 instructiuni (5 OUT-uri, GOTO, RETURN). Dupa o problema lunga cand se tot reseta PIC-ul (citeam din afara tabelei, in emulator mergea, in realitate facea crash) care a fost debug-ata cu osciloscopul si OUT-uri la alti pini, am reusit sa generez si altceva decat linii verticale.

vga02_sync.jpg

Un aspect important este ca indiferent ce face programul timingul pentru sincronizarea orizontala trebuie sa fie identic pentru fiecare linie.

vga03_good.jpg

 

Cu aceasta abordare nu pot afisa caracterele mai apropiate. Pentru a indesa totusi mai multe caractere am "overclockat" PIC-ul la 24MHz (specificatia este 20MHz maxim). Cu overclocking, plus alte optimizari am dus recordul la 12 caractere HEXA pe linie.
 

vga04_record.jpg

Rezultatul si montajul ce il genereaza

vga05_some_assembly.jpg

 

Odata obtinuta victoria, am realizat ca puteam folosi circuitul USART din PIC pentru a genera patternurile, ceea ce a simplificat semnificativ programul si a permis ceva mai multe caractere pe linie (si mai putin spatiu gol intre ele). Problema a fost ca, folosind portul USART pentru generat imaginea, nu prea mai aveam cum comunica cu uC-ul pentru a-i transmite ce sa afiseze. In cele din urma, am adaugat inca un PIC, am adaugat un protocol simplu de comunicatie intre ele si cu asta am cam incheiat temporar proiectul stiind ceva mai multe despre ce implica sa te alerge rastrul din urma. Dar despre asta in episodul urmator.

Link spre comentariu
  • Răspunsuri 9
  • Creat
  • Ultimul Răspuns

Top autori în acest subiect

M-am chinuit si eu cu asa ceva. SI banuiec ca au facut asta multi iubitori de ... nou.
Din curiozitate initial.
Cand a fost vorba de ceva serios, am pus si ceva RAM/ROM extern pe langa uC.

Ulterior si un CPLD. Apoi un FPGA.
Dar eu zic sa o luam incet.
Chiar sunt interesat sa vad cum ai evoluat tu si proiectul tau.
Apoi, poate public si eu ceva.
 

Editat de Vizitator
Link spre comentariu

Da, la RAM am ajuns si eu in cele din urma (1 bucata SRAM recuperat de pe o placa de 386/486), plus niste 74xxx-uri pe langa (aka CDB-uri). Nu am ajuns mai departe de caractere (episodul 3 este text 80x25 cu posibilitate neimplementata de grafica si cu "snow" atunci cand se scrie in RAM-ul video)

 

Nu am ajuns la FPGA sau alte stufosenii pentru ca nu am avut nevoie de "ceva serios", a fost doar dorinta de a intelege mai bine ce implica tarasenia (intre altele am inteles de ce pe vremuri VGA-ul avea "planuri" video). Desigur, faptul ca nu stiu nici Verilog nici VHDL nu are nimic de-a face cu decizia mea... :jytuiyu

 

Va mai dura putin pana la episodul 2, momentan sunt in concediu undeva cu internet pe sponci.

Am uitat sa precizez: tarasenia din primul episod a fost facuta cu un PIC 16F628.

 

De asemenea as striga de pe acoperisuri de-as putea: lume lume, soro lume, bagati naibii comentarii in proiectele voastre, ca Lucifer mai stie ce-ati facut acolo cand va uitati dupa 13 ani la surse! NB: La vremea respectiva nici jurnal nu prea tineam.

Also: daca o constanta are sens in binar, nu o scrieti zecimal in sursa. Idem hex, samd!

As baga exemplificare dar sigur nu ajuta pe nimeni. Poate dau sursele la episodul 2 cu disclaimer: do not use this at home or work, necesita mai mult efort intelegerea lor decat scrierea de la 0!

 

La buna recitire!

Link spre comentariu
14 minutes ago, Hawkuletz said:

Also: daca o constanta are sens in binar, nu o scrieti zecimal in sursa. Idem hex, samd!

Guilty as charged! Eu prefer HEX-ul.

 

Iubesc sa scriu ca:

OSCCON     =   0x78                   ' 16MHz

 

14 minutes ago, Hawkuletz said:

... necesita mai mult efort intelegerea lor decat scrierea de la 0!

D-aia se folosesc comentariile pe marginea codului. E adevarat, cu trecerea timpului si refolosirea codului dintr-un program in altul... cam treci cu vederea de ce ai facut ce ai facut acolo, ca acuma nu mai are asa de mult sens.

Link spre comentariu
19 hours ago, Hawkuletz said:

Desigur, faptul ca nu stiu nici Verilog nici VHDL nu are nimic de-a face cu decizia mea

Am tot citit si eu pana sa ajung sa stiu cate ceva.
Si am gasit acum ceva ani (mai multi ) https://www.fpga4fun.com/

De la ei cumparat prima placa cu un FPGA si am 'furat' primele programele HDL.
A fost o mare bucurie la vrea aia.
 

Link spre comentariu
  • 1 lună mai târziu...

Episodul 2
8 culori posibile, 4 randuri * 16 caractere, 2 microcontrollere

v02_init.jpg

 

Odata realizata prima varianta (si intelese limitarile), m-am gandit la cateva posibile imbunatatiri. Principala idee a fost trecerea de la generat pattern prin succesiune de instructiuni BSF/BCF (SET/CLEAR bit) la utilizarea portului serial inclus in uC (USART).
avantajul a fost trecerea de la asta:

; *** START RASTER ***
        MOVF    SC0,W
        CALL    TBLPX   ; this call ALONE takes 12 cycles
; +13
        MOVF    SC1,W
        CALL    TBLPX

        MOVF    SC2,W
        CALL    TBLPX

        MOVF    SC3,W
        CALL    TBLPX

        MOVF    SC4,W
        CALL    TBLPX

        MOVF    SC5,W
        CALL    TBLPX

        MOVF    SC6,W
        CALL    TBLPX

        MOVF    SC7,W
        CALL    TBLPX

        MOVF    SC8,W
        CALL    TBLPX

        MOVF    SC9,W
        CALL    TBLPX

        MOVF    SCA,W
        CALL    TBLPX

        MOVF    SCB,W
        CALL    TBLPX

la asta:
 

RASTERLOOP
            MOVF    INDF,W
            MOVWF   TXREG
            GOTO    $+1
            INCF    FSR
            DECFSZ  CNT1,F
            GOTO    RASTERLOOP

In prima versiune nu puteam folosi o bucla pentru ca totul dureaza timp si rastrul merge, nu asteapta. In a doua, intrucat serializarea se face in hardware, mi-am putut permite acest lux, ba inca ar mai fi loc de 2 instructiuni (GOTO $+1 e acolo doar ca intarziere). Fiecare linie e repetata de 6 ori pentru a avea pixeli aproximativ patrati, dupa care datele sunt inlocuite in buffere pe durata unei linii (intre fiecare rand de "pixeli" ai caracterelor e o linie neagra).

 

O problema cu portul serial este ca atunci cand este IDLE este in 1 logic (+5v), deci semnalul trebuie inversat hardware.

 

A doua probelma: fara USART, comunicarea e mai dificila. Am mai adaugat un uC (uC2) care sa reprezinte un soi de interfata de comunicatie intre generatorul video (uC1) si lumea exterioara. uC2 asigura un soi de memorie video constand in 64 de cifre hexa si 4 atribute de culoare. Ambele sunt uC-uri sunt PIC 16F628A.

  • uC1 - genereaza semnale de sincro, pattern, "culori" (per rand)
  • uC2 - comunicatie cu lumea exterioara, trimite la uC1 ce e de generat folosind o magistrala de date pe 4 biti

Protocolul de comunicatie e rudimentar, dar are o viteza rezonabila. Ambele uC-uri fiind conectate la acelasi generator de tact functioneaza sincron. Magistrala de date consta in 4 biti (PORTA 0:3) plus inca un semnal (sa il numim CRQ de la Communication ReQuest) pentru initierea conexiunii. CRQ este conectat la RB0/INT al uC2 si configurat sa genereze intrerupere pe frontul crescator.

Comunicatia se desfasoara pe durata unui scanline astfel:
uC1

  • dupa zona de rastru (cele 4 randuri de cifre hexa), dupa HSYNC trimite un impuls pe CRQ
  • pregateste variabile si trimite pe BUS un byte cu offsetul de la care vrea sa citeasca
  • citeste 6 bytes si ii incarca in bufferul propriu
  • delay calculat a.i. urmatorul HSYNC sa vina cand trebuie

uC2

  • in rutina de intrerupere citeste adresa de pe BUS
  • citeste offset si pregateste FSR
  • transmite 6 bytes
  • RETFIE (RETURN din interupere)

Procedura de mai sus se repeta pentru un total de 36bytes (6 scanlines). O problemuta este ca atunci cand am scris rutinele de comunicatie intre uC-uri am uitat sa salvez contextul (registrii cei mai importanti, in special W, STATUS si FSR) iar dupa ce am realizat asta erau toti tactii numarati si mi-a fot lehamite sa refac socotelile. Ca atare, atunci cand uC2 face orice altceva decat sa astepte, trebuiesc dezactivate intreruperile (perioada in care continutul ecranului este nedefinit).
 

Culori

Treaba cu inversorul hardware mi-a mai dat o idee - daca tot mai sunt pini disponibili si bag si TTL-uri in ecuatie, ce-ar fi sa adaug un rudiment de culoare? Mai ales ca aveam 32 de bytes dar transferul e multiplu de 6, deci 4 bytes ramaneau nefolositi. Ca atare, pinul RB1/DT (serial data) nu ajunge direct la monitor ci este distribuit in 3 porti de tip NOR (7402). Celelalte intrari ale portilor sunt conectate la RB5,RB6,RB7 (B,G,R), iar iesirile, prin rezistente de 1K merg la monitor. E experiment, deci nu e cazul de adaptari de impedanta iar rezistentele au adus semnalul video in limite rezonabile. (Liniile de semnal VGA au rezistente de 75ohmi in monitor; ar trebui sa fie la fel si le generator dar...)

 

Din cei 4 bytes cu atribute de culoare se folosesc doar bitii de jos (0,1,2) ca inhibitori pentru culorile R,G,B. Inhibitori, pentru ca utilizarea portii NOR (musai trebuie inversat semnalul) inseamna ca atunci cand un bit este 1, culoarea respectiva este stinsa. Modificarea iesirilor RB5-RB7 functie de valoarea din ATTRx se face in liniile fara rastru dintre randurile cu caractere.
 

"Comunicare pe care"
In 2008 am cam macelarit codul pentru primele experimente cu tastaturi PS/2 (mai tarziu concretizate in https://hawk.ro/stories/rs_kbd/) si nu am pastrat versiuni intermediare. In consecinta am refacut acum partea de comunicare doar pe serial (ca sa nu ma complic din nou cu tastaturi samd).

 

Comunicarea se desfasoara pe serial, la 9600bps. uC2 genereaza prompt "> " si asteapta comenzi constand dintr-un singur caracter (fara enter). Comenzile recunoscute sunt:

  • a<addr><val> unde addr si val sunt valori hexa reprezentand offset in buffer si valoare - modifica 1 byte la adresa
  • f<val00><val01>...<val35> (f urmat de 36 bytes hexa) - incarca tot bufferul cu valori

Citirile sunt validate, nu se accepta alte caractere decat 0-f; daca adresa e in afara bufferului, nu este acceptata. Din acest motiv primele caractere sunt mai usor de modificat (f urmat de n valori valide; primul caracter invalid iese din citire).
 

I/O uC1:

  • PORTB
    • 7 - R
    • 6 - G
    • 5 - B
    • 4 - CRQ (->uC2 INT)
    • 3 - Vsync
    • 2 - (serial Clock, nefolosit)
    • 1 - Video pattern
    • 0 - Hsync
  • PORTA
    • 7 - Osc In
    • 6
    • 5
    • 4
    • 3 - Data bus
    • 2 - Data bus
    • 1 - Data bus
    • 0 - Data bus

I/O uC2:

  • PORTB
    • 7
    • 6
    • 5
    • 4
    • 3
    • 2 - Tx
    • 1 - Rx
    • 0 - INT (uC2 COMM RQ ->)
  • PORTA
    • 7 - Osc In
    • 6
    • 5
    • 4
    • 3 - Data bus 
    • 2 - Data bus 
    • 1 - Data bus 
    • 0 - Data bus 

v02_generator.jpgv02_commands.jpgv02_output.jpg

 

PS: Am refacut montajul pentru ca aveam niste neclaritati in amintiri si la vremea respectiva nu prea notam in jurnal. A fost un exercitiu interesant sa imi amintesc cum lucram pe atunci.

 

Sursele nu sunt prea pieptanate, dar daca vrea cineva sa vada ce balarii sunt pe acolo, sa dea o strigare.

Editat de Hawkuletz
Link spre comentariu

Interesant. Felicitari.
Prin aceste intrebari, raspunsuri si (uneori) realizari am trecut si eu.
Eu citesc cu interes.
Sunt curios cand ajungi la capitolul "blinking cursor" :)

 

 

Link spre comentariu

Mulțumesc de apreciere. Acum, refăcând montajul din ep. 2, am realizat că de fapt și acesta ar fi putut fi modificat să afișeze tot setul ASCII, sau chiar Latin-2 (eventual cu virgulițe unde trebuie :)) )

 

Episodul 3 (ultimul din serie) va fi ceva între artă moderna si horror. Nu am făcut cursor clipitor, deși am avut un rudiment de TTY. Din pacate, acela a fost mult mai efemer, fiind realizat pe breadboard, cu un pogon (mă rog, vreo duzină) de integrate, dar tot PIC based, ca deh, puterea obișnuinței.

 

Nu prea cred că voi reface montajul acela (era mai bine dacă îl faceam și pe el cu letconul dar la câte fire avea...)

 

PS: După divagația cu Latin-2 am făcut un efort și am adăugat diacritice la mesaj :)

Link spre comentariu

Creează un cont sau autentifică-te pentru a adăuga comentariu

Trebuie să fi un membru pentru a putea lăsa un comentariu.

Creează un cont

Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!

Înregistrează un nou cont

Autentificare

Ai deja un cont? Autentifică-te aici.

Autentifică-te acum



×
×
  • Creează nouă...

Informații Importante

Am plasat cookie-uri pe dispozitivul tău pentru a îmbunătății navigarea pe acest site. Poți modifica setările cookie, altfel considerăm că ești de acord să continui.Termeni de Utilizare si Ghidări