3.1. Mikrokontroléry

OpenMV Cam běží na mikrokontroléru (MCU): jediném čipu, který kombinuje CPU, pracovní paměť (RAM), úložiště programu (flash paměť) a sadu periferií – hardwarových bloků pro interakci s okolním světem.

Periferie jsou tou zajímavou částí. Každá z nich je kus křemíku vyhrazený jednomu úkolu: nastavení pinu do vysoké nebo nízké úrovně, měření analogového napětí, odesílání bajtů po sériové sběrnici. CPU každou periferii konfiguruje a čte prostřednictvím registrů – pevných adres v paměti, které hardware sleduje a aktualizuje.

MicroPython tyto registry zabaluje do tříd uvnitř modulu machine. machine.Pin(...) vrací objekt řídicí univerzální vstupně/výstupní (GPIO) pin – vodič, který čip může držet ve vysoké úrovni (kolem 3,3 V) nebo nízké úrovni (kolem 0 V), případně jej číst jako jeden z těchto dvou stavů, když jej ovládá něco externího. machine.ADC(...) zpřístupňuje analogově-digitální převodník, který měří napětí na pinu a hlásí jej jako číslo. machine.UART(...) provozuje univerzální asynchronní přijímač/vysílač (UART) – periferii, která odesílá a přijímá bajty po jednom bitu přes dvojici vodičů, TX (vysílání) a RX (příjem). Další třídy pokrývají zbylé periferie. Skript čte a zapisuje objekty Pythonu; MicroPython každý přístup přeloží na odpovídající čtení a zápisy registrů, a ty pohybují bity na fyzických vodičích.

Obrys jediného čipu obsahující popsané bloky -- CPU, RAM, flash paměť a řadu periferních bloků (GPIO, ADC, Timer/PWM, UART/SPI/I2C, CAN) propojených vnitřní sběrnicí, se šipkami vedoucími z každé periferie ven z čipu k popisům fyzických pinů.

MCU sdružuje CPU, paměť a periferie do jediného čipu. Každá periferie je Pythonu zpřístupněna třídou v modulu machine.

3.1.1. Hlavní smyčka

Téměř každý program pro mikrokontrolér má stejný tvar: jednorázové nastavení na začátku skriptu (import modulů, konfigurace pinů, otevření sběrnic) a poté nekonečná smyčka while True: na konci. Uvnitř smyčky program čte vstupy, rozhoduje se a aktualizuje výstupy, znovu a znovu. Smyčka je program; když skript skončí, zařízení přestane cokoli dělat.

# setup, runs once
from machine import Pin
led = Pin("P0", Pin.OUT)

# main loop, runs forever
while True:
    led.value(1)
    # ... do work ...
    led.value(0)
    # ... do other work ...

Tento tvar – jednou nastavit, pak donekonečna opakovat – je vzorec hlavní smyčky. Vše, co následuje, se týká toho, co je uvnitř ní.

3.1.2. Řízení v reálném čase

Program na stolním počítači běží vedle mnoha dalších. Operační systém plánuje jeho práci napříč jedním nebo více vlákny – nezávislými proudy provádění, mezi kterými přepíná milisekundu po milisekundě. Když jedno vlákno čeká na I/O (disk, síť, pohyb myší uživatele), OS předá CPU jinému. Program je převážně řízen událostmi: správce oken zavolá váš kód, když dorazí vstup, knihovna HTTP obnoví váš kód, když na soketu dorazí bajty. Volá vás něco většího.

Program pro mikrokontrolér je opakem. Ve výchozím stavu zde není žádný operační systém, žádný plánovač a žádné jiné vlákno. Právě ukázaná hlavní smyčka je jedinou smyčkou. Periferie vyvolávají přerušení nebo zpřístupňují stavové příznaky; smyčka je dotazuje nebo přerušení zpracovává přímo. Pokud se smyčka zastaví v time.sleep_ms(1000), zařízení po tuto sekundu nedělá nic; není zde žádné jiné vlákno, které by mezeru vyplnilo.

Vyplývají z toho dva důsledky, které platí všude:

  • Čas je skutečný. Dvojí přečtení pinu v těsné smyčce trvá mikrosekundy; spánek po dobu deseti milisekund znamená deset milisekund, během nichž se neděje nic jiného. Odpovědí je vzorec neblokujícího časování.

  • Hardware je skutečný. Nastavení machine.Pin.value na 1 přivede na fyzický vodič zhruba 3,3 V; nastavení na 0 tam přivede zhruba 0 V. Ostatní části obvodu toto napětí vidí okamžitě – včetně všech součástek, které pin může poškodit, pokud je řízen nesprávně.