AVR-Laptop: Een 8-bit MCU ver buiten de oorspronkelijke ontwerpdoelen drijven

Systeemoverzicht

Hardware

Het apparaat is gehuisvest in een 3D-geprinte behuizing met afmetingen van 12 × 11 × 3,4 cm. De interne componenten bestaan uit:

  • Een zelfgemaakt QWERTY-toetsenbord.
  • Een monochroom 128 × 64 LCD-scherm.
  • Een VS1053 audio-decoder met luidsprekers.
  • Een microSD-kaartlezer.
  • Een Real-Time Clock (RTC).
  • Een 18650-batterij.

Software en Functionaliteiten

De firmware is gebaseerd op FreeRTOS. De laptop beschikt over de volgende mogelijkheden:

  • Multitasking: Echte multitasking met Alt-Tab schakelen. Het is mogelijk om bijvoorbeeld een video te starten en deze te minimaliseren; het geluid blijft spelen terwijl de gebruiker een spel zoals Sokoban speelt.
  • UI Engine: Een interface met formulieren, knoppen, selectievakjes, lijsten, invoervelden en dialoogvensters. De engine regelt toetsaanslagen, tabbing, het opnieuw tekenen van het scherm en het verzenden van events naar de actieve taak.
  • Applicaties: Een set aan taken waaronder een bestandsbeheerder, videospeler, muziekspeler, klok, rekenmachine, Sokoban, Snake en Game of Life.
  • Videospeler: Ondersteunt videobeelden van 24 fps (en hoger) met geluid, gebruikmakend van een aangepast bestandsformaat: een XBM-stream en MP3 in één enkel bestand.

Technische Beperkingen en Architectuur

Het gehele systeem draait op slechts 8 KB RAM, waarvan de helft al wordt ingenomen door globale variabelen (zoals de video- en SD-buffers, FreeRTOS en servicevariabelen). Deze extreme schaarste aan geheugen bepaalt de volledige architectuur, van de datastructuur tot de opbouw van de taken.

De architectuur is desondanks open voor uitbreiding. Een nieuwe taak is een klasse met setup en loop (vergelijkbaar met een standaard Arduino-sketch), aangevuld met methoden voor het menu en een icoon. De shell regelt de registratie, stack, switching en events. Taken zijn onafhankelijk van elkaar; ze communiceren via de UI engine.

---

Projectlogboeken

Overstap naar FreeRTOS en de UI Engine

Tijdens de ontwikkeling van de bestandsbeheerder (met functies als kopiëren, verwijderen en mappen maken) ontstond de noodzaak voor een gestandaardiseerde gebruikersinterface. Voorheen moest elke taak eigen knoppen en velden tekenen en toetsaanslagen parseren, wat leidde tot veel dubbele code.

De oplossing was een UI-engine waarbij de taak beschrijft wat getoond moet worden, terwijl het tekenen, de focus en event-handling door één centraal mechanisme worden afgehandeld.

Daarnaast was er een structureel probleem met de timing van het scherm. Het scherm vereist regelmatige updates via de lcd.service() methode. In een single-tasking model blokkeerden taken (bijvoorbeeld bij het wachten op een "ja/nee" bevestiging) de shell, waardoor het scherm niet meer werd bijgewerkt. Coroutines werden overwogen, maar verworpen omdat de code dan niet meer sequentieel leesbaar was.

Uiteindelijk is gekozen voor FreeRTOS. Dit vereiste een volledige herschrijving van het project. De nieuwe structuur bevat:

  • Basis-widgets: knoppen, selectievakjes en invoervelden.
  • Containers: formulieren die widgets beheren, met een stack van formulieren zodat nieuwe schermen over huidige schermen kunnen worden geopend.
  • Standaarddialoogvensters: berichtenboxen, waarde-invoer en bestandsdialogen (openen/opslaan).

Vanwege de overstap naar multitasking moest het geheugengebruik drastisch worden geoptimaliseerd door task-stacks te verkleinen en datastructuren te herzien.

Videoweergave en Audio

De mogelijkheid om video af te spelen ontstond nadat bleek dat het scherm snel genoeg kon worden ververst. Na optimalisaties van de dataoverdracht werd de ververstijd per frame teruggebracht van 40 ms naar ongeveer 32 ms.

Het videoproces:

  1. Een Python-converter extraheert frames uit een videobestand.
  2. De frames worden via brightness thresholding omgezet naar monochroom 128 × 64.
  3. Op het apparaat worden de frames in blokken van 1024 bytes vanaf de microSD gelezen naar de videobuffer en naar het scherm gestuurd.
  4. Om de beeldkwaliteit te verbeteren, is temporele dithering toegepast: pixels knipperen tussen frames om grijstinten te simuleren.

Audio-integratie en CPU-optimalisatie: Voor audio is de VS1053 decoder gebruikt. Een uitdaging was dat de VS1053 constant gevoed moet worden met data, terwijl de CPU tijdens het versturen van een videoframe naar het display (32 ms per frame) grotendeels wacht op de hardware. Uit metingen bleek dat de CPU 99% van de tijd niets deed tijdens het wachten op het display.

De oplossing hiervoor is een tweeledig systeem:

  • ISR op Timer 5: Een Interrupt Service Routine die elke 8 $\mu$s wordt aangeroepen om te controleren of het display klaar is voor het volgende byte.
  • Functie service(): Deze wordt regelmatig aangeroepen. Als er een "dirty line" (een gewijzigde regel) wordt gevonden, stuurt deze de adrescommando's naar het display en start Timer 5.

Constructie van het Toetsenbord

Het toetsenbord is een volledige QWERTY-indeling met 64 toetsen, georganiseerd in een 8 × 8 matrix (fysiek een 11 × 6 rechthoek). De PCB is ontworpen in EasyEDA en gefreesd op een CNC3018.

Technische details van het toetsenbord:

  • Scanning: De microcontroller activeert per kolom de pinnen en leest de status van de rijen. Softwarematige debouncing voorkomt valse triggers.
  • Revisie: In een latere versie zijn diodes per toets toegevoegd voor betrouwere detectie van toetscombinaties en is een 4-naar-16 decoder gebruikt voor de kolomselectie. Hierdoor zijn slechts vier pinnen nodig voor de kolommen, wat ruimte laat voor toekomstige uitbreidingen.
  • Labeling: Na experimenten met 3D-printen, lasers en UV-maskers, is er gekozen voor de toner transfer methode voor scherpe en duurzame tekens op de toetsen.

Ontstaan van het Project

Het project is voortgekomen uit een interesse in computergeschiedenis en retro-computers. De vraag was: wat kan een AVR-microcontroller van 16 MHz vandaag de dag doen in vergelijking met computers uit het i386-tijdperk?

Ontwerpprocessen:

  • Controller: Er is gekozen voor de Mega 2560 Pro Mini vanwege het compacte formaat en de reproduceerbaarheid voor anderen.
  • Display Driver: Er is een eigen driver geschreven voor het ST7920-scherm in parallelle modus voor maximale snelheid. Er is een video-buffer van 1 KB in het SRAM toegewezen.
  • Tekstrendering: De grootste uitdaging was de implementatie van fonts van verschillende groottes (tot 16 × 16). Omdat tekst vanaf een willekeurige horizontale positie kan beginnen, moet de driver werken met complexe shifts en masks om data correct in de bytes van de videobuffer te schrijven.
  • Shell: Na de graphics-functies is een shell gebouwd met een menu en een basis Task klasse.