2025.03.28
Na Arduinu generuju kompozitní signál pro monitor a čtu PS/2 klávesnici. Generování kompozitního signálu znamená každých 16 taktů poslat na výstup další byte. Základní čtení PS/2 dat se mi podařilo rozložit na části, které během generování jednoho řádku zkontrolují PS/2 3x. Ale mimo generování řádků (při horizontálních a vertikálních pulzech) stihnou hodiny PS/2 projít několik tiků, takže je potřeba PS/2 sledovat i v té době. Zároveň je to jediná doba, kdy může běžet hlavní program, takže ji nemůžu celou zabrat busy-wait cykly. Tak jsem zvolil pověsit interrupt na změnu pinu A0 (kde jsou hodiny PS/2) a sledovat změnu jen při změně hodin. Ale zjistil jsem, že se mi takřka pro každý scan kód (11 pulsů PS/2) zavolá při každém z těch 11 pulzů. Což asi není dobře, protože většina pulsů by měla spadnout do oblasti řádků a tady být ošetřena tam. Tyto interrupty na začátku každého řádku zakazuju a na konci každého řádku povoluju, ale mažu pending příznak. Níže je příslušný kus kódu. Zdá se, že to nefunguje tak, jak bych předpokládal - mám chybu v úvahách, nebo v provedení?
Zakázání PCMSK1 &= ~(1 << PCINT8); // Disable interrupt for A0 Povolení PCIFR |= bit (PCIF1); // clear any outstanding interrupts PCMSK1 |= (1 << PCINT8); // Enable interrupt for A0 Počáteční nastavení PCMSK1 |= (1 << PCINT8); // Enable PCINT8 (A0 is PC0) PCIFR |= (1 << PCIF1); // clear any outstanding interrupts PCICR |= (1 << PCIE1); // Enable Pin Change Interrupt for PCINT[14:8] (Port C)
Nakonec se na osciloskopu ukázalo, že vlastně všechno funguje správně, ale těch 11 pulzů u PS/2 je 22 hran a z nich asi tak 2/3 spadly do řádku a 1/3 - tedy 7 mimo a byla správně zachycena interruptem. V reálném čase ta čísla byla nepřesná a trochu matoucí. A chyby ve výstupu na monitor byly způsobené tím, že jak zobrazování, tak PS/2 mimo řádky jdou přez interrupty a pokud se ty interrupty nešikovně sešly, tak se o kus odsunuly a řádek byl nakreslen špatně. Takže to bude chtít řešit jinak. Ale možná půjde zakázat PS/2 interrupt už při sync pulzu, pokud následuje řádek, a takto vzniklá mezera už nedovolí propadnutí pulzu, ale zabrání kolizi interruptů. A čtení bufferu bude muset být pořešeno s ohledem na interrupty nějak zabezpečeně, nebo naopak vtipně. (Čtení mění ocas, zápis hlavu, ale v systému je jen jedno čtení a jeden zápis bez ohledu na interrupty.)
2025.03.27 Matrix a databáze lines
Trochu jsem to dočesal, přidal operátor << a převedl to na něj, přidal Matrix jako screensaver a přidal jednoduché rejdění šipkama a vypadá to docela dobře. Do loga jsem přidal aktuální volnou RAM a FLASH, bude to ještě chtít dořešit čmouhy při psaní (a ujistit se, že to chodí i na RCA) - pro debug můžu třeba místo LEDek měnit znaky na obrazovce, dlouhodobě se to vždycky ukáže, takže můžu přejít na styl vyšších počítačů :)
Rozchodil jsem jednoduchou databázi pro ukládání dat lines, kterou plánuju už kdoví jak dlouho, pomocí flask to bylo překvapivě snadné - jednoduchá webovka je hotová raz-dva a dá se používat, složitosti později, časem.
from flask import Flask, request, render_template, redirect, url_for import pymysql app = Flask(__name__) # Připojení k databázi def get_db_connection(): return pymysql.connect( host='localhost', user='gilhad', password='gilhad', database='grafana' ) @app.route('/<path:path>') def static_file(path): return app.send_static_file(path) @app.route('/', methods=['GET']) def index(): return render_template('index.html') @app.route('/vahy', methods=['GET', 'POST']) # {{{ def vahy(): if request.method == 'POST': value = request.form['value'] if value: conn = get_db_connection() cursor = conn.cursor() cursor.execute('INSERT INTO vahy (value) VALUES (%s)', (value,)) conn.commit() cursor.close() conn.close() # Při GET nebo po odeslání nové hodnoty zobrazení posledních 5 hodnot conn = get_db_connection() cursor = conn.cursor(pymysql.cursors.DictCursor) cursor.execute('SELECT value, timestamp FROM vahy ORDER BY timestamp DESC LIMIT 5') last_values = cursor.fetchall() cursor.close() conn.close() return render_template('value.html', values=last_values, Title="vahy") # }}} # .... if __name__ == '__main__': app.run(debug=True)
templates/value.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{Title}}</title> <link rel="stylesheet" href="./css/css.css"> <link rel="icon" href="./favicon.ico"> </head> <body> <a href="/">index</a><br> <H1>{{Title}}</H1> <table> <tr><td class="right"> <form method="POST"> <button type="submit">Odeslat</button></td><td class="right"> <label for="value">Value:</label> <input type="float" id="value" name="value" required> </form></td> </tr> {% for entry in values %} <tr><td class="right">{{ entry.timestamp }} </td><td class="bold right"> {{ entry.value }} </td></tr> {% endfor %} </table> </body> </html>
static/css/css.css
static/favicon.ico
a hotovo jedem :)
2025.03.22 Arduino Day
Byl jsem na Arduino dni a bylo to príma. Včera jsme tam tahali stoly, přez noc jsem konečně rozchodil PS2-RCA-VGA pro Nano na breadboardu (minimálně po HW stránce, SW ještě potřebuje dost práce) a dnes jsem se tím mohl chlubit :)
Vypadá to teď nějak takhle - breadboard-008-PS2-RCA-VGA-Nano.pdf - to schéma je určeno pro úpravy breadboardu, proto je spíš ve tvaru, jak to tam leží. Napájení jsem moc nekreslil.

Důležité úpravy proti původnímu projektu jsou, že dodržuju výstupní úrovně 0 - 0.3 - 1.0 V a okolo synchronizačních pulzů to není vyvýšené, jak to bylo předtím, kdy tam byl připojený neaktivní pin, takže teď není problém co je synchronizační pulz a co je hodně černá černá. Takže výstup v Tx má HW pulldown asi 1.3 kΩ (ono je to celkem jedno kolik přesně) a jde ještě do AND hradla, které to znormalizuje na buď 0, nebo 5V. Druhý vstup do AND je suppress pin, který je pořád jako OUTPUT a buď má 1 (volno), nebo 0 (suppress). Za AND (NAND+NOT = půlka 7400) pak je čistý výsledek. Ten přez odpor 440 Ω a 1 kΩ pullup tvoří dělič pro 75 Ω monitor a logická nula vyjde na 0.3V, zatímco logická jednička na 1.0V. A tranzistor S8050 to uzemní pro synchronizažní pulzy na čistých 0V. (A díky 440 Ω jde tranzistorem, i hradlem maximálně nějakých 12mA). Časem se asi ještě podívám na délky těch pulzů, ale to už je SW problém.
Během dne jsem ještě na to zkonvertoval Blocks (tetris) a nějak to chodí (jako technologické demo, do rozumného použití tomu chybí ještě dost - demo-breadboard-008-PS2-RCA-VGA-Nano.tar.gz) - F12 přepíná režim, F1 a F2 vypisují různými způsoby 0..255 na obrazovku, F3 popíše celou obrazovku jedním znakem a pak dalším a dalším, F4 je tetris a Esc popíše obrazovku znakem stiskuntým před tím Esc.
Na composite video ještě nějak "drhnou" scankódy - musím zkontrolovat, zda se správně zapíná přerušení mimo kreslení řádek. A trochu učesat tu rutinu, aby nebyly problémy s autorepeatem a delšími scankódy. A aby se nepřepínalo dvakrát. A aby Esc nepožral další klávesu. A aby šel přepínat režim i během tetrisu. A třeba i z tetrisu nějak vyskočit. A tak podobně - no, je to jen první nástřel :)
2025.03.20 Arduino composite upřesnění
- Umělák tvrdí něco jako, že:
- Typický kompozitní videosignál má špičkovou hodnotu 1 V (od špičky k špičce) při impedanci 75 Ω.
- To zahrnuje synchronizační pulzy, které obvykle dosahují úrovně 0 V, černá úroveň je 0.3V, zatímco maximální úroveň bílé je 0,7 V nad černou úrovní tedy 1V. Synchronizační pulzy jsou nezbytné pro správné zobrazení obrazu, protože určují začátek každého řádku a snímku.
- Pro evropský standard PAL je horizontální frekvence 15 625 Hz (64 µs na řádek) a vertikální frekvence 50 Hz. Každý řádek začíná horizontálním synchronizačním pulzem trvajícím přibližně 4,7 µs, po kterém následuje tzv. "back porch" (časový úsek před začátkem viditelné části řádku) o délce zhruba 5,7 µs, a poté samotná viditelná část signálu.
- https://www.youtube.com/watch?v=xeh48wK4TOw
- Tady zase tvrdí, že řádek horizontálním pulzem končí hned po datech
NTSC | PAL | |
Field duration | 1/60 sec | 1/50 sec |
Vertical blanking | 1333 us | 1600 us |
Line loss due to vertical blanking | 21 lines | 25 lines |
Line duration | 63.5 us | 64 us |
Horizontal blanking | 10.2 us | 10.25 us |
Visible trace time | 53.3 us | 53.75 us |
- A tady je detailně popsané časování - asi zatím nejlepší, na co jsem narazil.
- Moje shrnutí zatím
- sync pulzy jdou na nulu, jinak to má být mezi 0.3V a 1.0V
- krátká černá před sync pulzem, i za ním - viz timing obrázky
- 75 Ω na monitoru
- při černé = 0.3V tím teče 0.3 / 75 = 4 mA
- při bílé = 1V tím teče 1 / 75 = 13.3 mA
- 5V / 13.3mA = 375 Ω - 300 Ω od pinu + 75 Ω do monitoru
- použiju uměláka a ošklivý brute force a vyjde mi dělič takový: R1=75 Ω, R2 = 430 Ω, R3 = 992.31 Ω, Voltage on divider = 0.30 V a 1.0V - odhadem proč ne, zapojíme vyzkoušíme
- 220/3=73 Ω, 1 kΩ a 440 Ω dá podobnou děličku, 0.3V a 0.9V je ok v rámci improvizace a přesnosti měření.
- pro sync použiju mosfet na nulu a ono to snad nějak něco
2025.03.02 Arduino + PS/2 + VGA + RCA composite video
Rozchodil jsem Arduino + PS/2 + VGA + RCA composite video, teda zatím kompozit a VGA zvlášť, naráz to nepoběží, není dost výkonu, ale chtěl bych to časem umět i přepínat. Jak při startu, tak i za chodu. viz HW/PS2-RCA-VGA. Asi to taky sjednotím na VGA rozměr 40x25 (RCA umí asi 46x29, ale správně s PS/2 pracuje pro 43x29 a míň, jinak to při použití klávesnice skáče) a použiju ten jeho os::něco přístup. Budu si taky chtít upravit znaky, nevyhovují mi tak úplně ani na jednom. A asi bych to měl rád jako normálně kompilované, tedy přez něco jako Sudar Makefile raději než přez arduino-cli s jejich přístupem ke knihovnám a podobně. Udělal jsem si taky repozitář MakeArduino a chtěl bych to tam nějak rozběhat.
A upravil jsem si fonty v Gimpu - 2048x8(nebo 9) bitů obrázky, vodorovně zazrcadlené (protože je shiftuju ven počínaje LSB) a vyexportované jako *.bmx jsou přesně to C pole, které potřebuju .. }}}
2025.02.25 Nový rok
- Přehodil jsem Blog na nový rok a snad to letos dotáhnu dál
- Rozchodil jsem VGA+PS/2 na Arduinu
- Umím z VirtualBoxu vypalovat PLDčka