FPGA:0005 – Tekstinis displėjus

Papaišėm spalvotus fonus. Bet jei norime parodyti kokį nors tekstą, panašiai kaip senoviniam tekstiniam displėjuje? Aišku galima! Viena iš pirmųjų minčių- prikabinti didelį video RAMą kaip šiuolaikinėse video plokštėse ir nuo RAM turinio keisti vaizdą. Aišku taip galima, bet mes neturim tiek atminties. Netgi naudojant po 4 bitus vienai spalvai, gaunasi: 1024x768x3x4/8=1179648 baitai (1.125 megabaito). Tačiau mums užtenka tekstinio displėjaus. Jį sudaro tekstinė atmintis, šrifto atmintis ir spalvų atmintis (kartais paletizuota). Kadangi tingiu paišyti ir ieškoti internete, panaudosiu 8 bitų ATARI kompiuterio šriftą, kurį savo laiku ištraukiau iš to kompo ROMo. Šis šriftas skirtas TV ekranui, todėl jis toks pastorintas. Šriftas užima 8×8 matricą, tačiau iš šonų visada yra tušti pixeliai raidžių atskirimui. Senoviški ekranai naudodavo mažesnes matricas, o tarpelius tarp raidžių darydavo hardwariškai. Gal apseisim be šito.

Šriftas laikomas ROM (galima ir RAM) atmintyje. Nors FPGA turi simbolį ROM, bet fiziškai tai bus RAM. Nes visa FPGA veikia RAM principų ir ją galima perprogramuoti neribotą skaičių kartų- ji gi įjungiant prietaisą susiprogramuoja.
Mums reikia išmokti susikurti ROM ir RAM elemetus. Galima juos aprašyti programavimo kalboje, bet męs nelabai mokam, o štai megawizardas leidžia tai padaryti labai greitai, o dar galima per JTAG operatyviai keisti tos atminties turinį veikiančioje schemoje.
Pradžiai susikuriam šrifto ROM. Kadangi aš norių rodyti tik skaičius, mano šriftas minimalizuotas ir jam reikia 10*8 baitų atminties. Megawizardinis ROMas gali turėti kartotinį dydį pagal adresų kojos ilgį. T.y. 8 kojos tai 256 baitai. Tačiau taupant FPGA atminties bitus, galima rankomis įvesti egzotiškus dydžius. Nors rodo, kad atminties blokas 128×8, įvedus 90×20 galutiniam kompiliavimo rezultate matosi skirtumas: 1024 vs. 720 bitų iš 165888 galimų. Čia ne atminties, o viso projekto sunaudojimas. Prieš darant ROM reikia pasigaminti ROM turinį- šriftą. Programa supranta du formatus MIF ir HEX. (Čia jums paruoštas FONT ROMAS.)

Darom atmintį:
Pasileidžiam megawizardą, sukurti naują detalę, NEXT. Pavadinimas koksnors ROMIKAS, pasirenkam “memory compiler”, ROM: 1-PORT. NEXT.
Užsidega jau matytas spalvotas langas, kur kairėje formuojasi detalės simbolis, dešinėje parametrai. Programa klausia atminties dydį ir plotį. Mums reikia 8 bitų pločio ir maždaug 80 žodžių (words) ilgio. 10 simbolų po 8 baitus. Jei dar tarpas, tai +8. Kol kas pasirenkam “standartizuota” 128 words. Dešinėje matosi, kad adresų laidas pasidarė address[6..0] t.y. tik septyni laideliai. Kiti parametrai lieka “auto”,single clock. NEXT.
Dabar klausia, ar išėjimą reikia “sinchronizuoti” per registrus. Čia toks momentas, kad atminties veikia kiek lėčiau ir signalas ateina kažkiek ns pavėlavęs. Kiek neišku. Todėl išėjimo signalą galima sinchronizuoti su clock signalu. Tai duos… signalo vėlavimą, tačiau griežtai apibrėžtu laiku. Galite paklausti: Nanosekundės…. pfe, ką jos reiškia?. Nu jo elektra ir šviesa per nanosekunde nubėga gal per sprindį. Tačiau žaidžiant su greitais aparatais kaip FPGA tai jau reiškia. Netgi su šiuo LCD ekranu tai jau kažką reiškia: vienas pixelis tai tik maždaug 15.4ns. Pavėluosim ir nepataikysim į reikalingą pixelio vietą ir vaizdas bus nekoks. Taigi varna ant ‘q’ output port register. NEXT.
Dabar nurodom kuom užpildyti mūsų ROM failą. Ir pasižymim (bent jau pradžiai): Allow In-System Memory Content Editor to capture… bla bla. Ten paryškėja laukelis “The ‘Instance ID’ of this ROM”. Čia ROMo vardas, kad galima būtų atskirti kurį ROMą redaguojam. NEXT, NEXT. FINISH. Taip gavo atminties mikroschemą su šriftu.
Monitoriaus ekranas rodo vaizdą nuosekliai, o mūsų ROMas išmetą visą vaizdelį po 8 pixelius iš karto. Reikia paimti pixelius paeiliui. Seni kompai, kad ir iš žurnalo Radio (ОРИОН-128) naudoja 8 bitų paraleliai užkraunamus, nuosekliai “išstumiamus” registrus. Tačiau toks metodas reikalauja clock signalo išstumimui ir clock signalo lygiagrečiam duomenų užkrovimui. Daug vargo. Gerai kad ciklonas ir softas turi tokį stebūkla kuris vadinasi “LPM_CLSHIFT”. Jis guli megawizarde, “gates” pogrupyje- tai “konbinacinės logikos” (be clock) tvarinys. Mums tereikia pasirinkti “rotate” ir “always shift left”, rezultatas 8 bitai (per daug), “auto”. Be “pipeline”- gryna logika. Ir turim detalę, kuri paslenka tiek bitų kiek nurodysim pradinį rezultatą. T.y. jei į šią detalę paduosim informacija iš šrifto, o į postumį paduosim pirmus x koordinatės bitus (x[2..0]), tai per išėjimo laidelį rezult[0] gausim tiksliai signalus kurie atitiks ekrano koordinates.
Dar viena detalė- toks mini matematinis modulis. Paprasčiausia kombinatorinė logika:

module skaiciuoklis(input [7:0]x, input [7:0]y, input [2:0]mini_y, output [6:0]qq);
wire [10:0]tmp_x;
wire [10:0]tmp_y;

assign tmp_x[2:0]=0; //tik del tvarkos.
assign tmp_y[2:0]=0; // default vistiek 0.

assign tmp_x[10:3]=x;
assign tmp_y[10:3]=y;
assign qq=tmp_x+tmp_y+mini_y;
endmodule

Komanda “wire” taip kaip koks “lokalinis laidas”- aliuzija į “lokalinis kintamasis”. Gal šioje schemoje buvo galima prasiskukti be tarpinių kintamųjų, bet taip vaizdžiau.
Nulinių reikšmių priskyrimas nebūtinas, programa ir taip padarytu ten nulius, bet būtų įspėjimas. Dabar tuos mažesniusius bitus užnulinam. O poto paprasta matematika- simbolio X ir Y koordinates sudedam, tačiau naudojam perstumtus bitus- gaunasi kaip daugyba iš 8. Taip apsibrėžiam kad simbolio koordinatė yra kartotina simbolio dydžiui (8 pixeliai). O kad pamatyti visą pixelį, pridedam ekrano koordinatės mažiausias y reikšmes. Taip galime pasiskaičiuoti ROM adresą šriftui.
Kartu su prieš tai aprašytu elementu tai suformuoja toki tuščią tekstinį “grafinį adapterį”. Sujungiam viską į vieną vietą ir pridedam su ankstesnės pamokos video generatorium. Gaunam tokią schemą (dalis jos matosi):
Text mode VGA in FGPA
(schema pasididina)

Nuo praeitos pamokos skiriasi tik tuo, kad aš atjungiau raudoną spalvą nuo x ir y skaitliukų ir per “primityvus” WIRE sujungiau į vieną vietą ir prijungiau prie šrifto generavimo. Grafinis primityvas WIRE leidžia sujungti skirtingų pavadinimų laidus į vieną vietą arba signalą perkelti iš vienaip uždvadinto laido į kitaip užvadintą laidą. Tai patogus įrankis kai daromi eksperimentai. O tai dažnai būna kaip kuriamas kažkas ir dar neaišku kaip ten bus sujungta. Aš šias pamokas darau “gyvai” t.y. berašydamas į weblogą kartu, kitame monitoriuje viską ir kuriu. Todėl kartais net nežinau ką su kuo jungsiu. 🙂
Kas čia turėjo gautis? Nu ant ekrano, raudonom raidėm turi matytis simbolinių koordinačių sumos mažiausia skiltis. Ir dar rodoma 16-tainėje sistemoje. Tiesa matysim tik 10 simbolių, nes kiti nenupaišyti šrifte. Nieko nesupratot? Nu turi gautis taip:
text mode LCD vga fpga
text mode LCD vga fpga
Pažiūrėjus per padidinimo stiklą matosi, kad raudonos raidės kiek neryškios. Tai įtakoja labai jau grubus DACas, ilgi laidai ir tai, kad mano video vaizdas kiek vėluoja palyginus su pixel_clock. Tai blogai. Netgi pažiūrėjus atidžiau, matosi, kad spalvoti foniniai kvadratėliai paišosi kiek anksčiau nei šriftas. Tai natūralu- kad paišyti kvadratėlius užteko tik pasiimti x ir y koordinačių skaičius, tuo tarpu šriftui buvo atlikta žymiai daugiau veiksmų ir net skaitymas iš atminties. Tai užtruko apie vieną pixelį laiko (kiek ten? 15ns?). Va čia ir prasideda subtilybės darbui su greitais signalais- dažnai megėjas tokių dalykų niekur nenaudoja. Užtat daugelis tikrai pastebėjo tokio darbo ekstremumą- suvingiuotus takelius meandru ant kokio DDR ram modulio ar ant kompo motininės. Ten aišku jau pikosekundiniai bajeriai, bet vistiek įdomu. Šią, negražaus vaizdo problemą išspresim per kitą pamoką (tikiuosi), o dabar pabaigai pašnekėsim apie ROM modifikavima per JTAG.
Veikianti schema, prijungta per JTAG prie kompo, jei numatyta, gali būti debuginama ir keičiami parametrai. Apie debuginimą vėliau, o štai RAM/ROM reguliavimas labai paprastas: meniu Tools, papunktis “In system Memory Content Editor”. Pasileidus jis praskanuoja JTAG grandinę, suranda galimas atmintis. Pasižymim norimą atmintį, spaudžiam F5 ir turime informaciją. Ją galime redaguoti. Po paspaudžiam F7 ir viskas surašoma į atmintį. O galima paspausti F6 ir sistema bandys kiek galima didesniu greičiu “realiu” laiku skaityti atminties turinį. Tai irgi kartais labai patogu. Dabar galima šrifte nusipaišti trūkstamas raides.

Šioje pamokoje išmokom kurti atmintį, ją redaguoti, ją skaityti “gyvai”. Susipažinom su keliais sisteminės bibliotekos elementais, sužinojom biški apie taimingus ir apie tai, kad Levui ne viskas iškarto gražiai gaunasi.

P.S. nedažlibinat raidžių ant ekrano? 🙂 Pasikeiskit “skaičiuoklio” įėjimo laidus į: X[10..3], Y[11..4], o mini_y į Y[3..1]. Gausit dvigubai aukštesnes raides. Dar permažos? X[11..4], Y[11..4],Y[3..1] ir į shifterį X[3..1]. Raidės gausis dvigubos tiek per aukštį, tiek per plotį. Dabar labai gerai matosi, kad raidė nepataiko per 2 pixelius į X koordinatę.

2 replies on “FPGA:0005 – Tekstinis displėjus”

  1. Labas rytas,
    Gal kartais teko susidurti su “lader” programomis, kur pramoniniai PLC programuojas. Kur kokį normalesnį pradžiamokslį surast? Reikia pasiaiškinti, kodėl vieni išėjimai įsijungia tokia o ne kitokia tvarka ir kaip tai pakesiti. Softą turiu pasikūręs, matau veiksmą programoje realiu laiku, tik nesugaudau kintamųjų, kas nuo ko valdosi.

Leave a Reply

Your email address will not be published. Required fields are marked *