Autor prezentowanego poniżej projektu, przy przejściu do nowej pracy otrzymał od firmy między innymi opaskę fitnessową, pokazaną po lewej stronie. Abstrahując od przydatności takiego urządzenia podczas ćwiczeń fizycznych, opaska sama w sobie jest niezwykle ciekawa pod względem technicznym. Wynika to z szeregu kwestii, między innymi:
* Naprawdę niewielki rozmiar (około 15 mm x 40 mm)
* Interfejs Bluetooth low energy (BLE)
* Wyświetlacz OLED (o rozdzielczości 96 x 32 piksele)
* Wbudowany akumulator
* Ładowanie poprzez USB
* Zintegrowany akcelerometr
* Silniczek do wibracji
* Cena zaledwie około 10 dolarów
Jedyne co identyfikuje urządzenie na obudowie to identyfikator FCC - "FCC ID: 2AHFTID115". Wyszukiwanie tego numeru w Google daje całkiem dużo informacji, jeśli się postaramy. Urządzenie nazywa się ID115, a przynajmniej pod taką nazwą znajdziemy je w Internecie. Dodatkowo można znaleźć kilka ciekawych zdjęć - zwłaszcza wnętrza urządzenia. Jeśli dobrze się przypatrzymy, to dostrzeżemy na nich układ scalony opisany N51822. Sugeruje to nam, że układ oparty jest o mikrokontroler nRF51822 firmy Nordic. Jest to 32-bitowy procesor z rdzeniem ARM-M0 i z wbudowanym wsparciem dla BLE. Mikrokontroler ten dosyć łatwo można by przeprogramować, aby zmusić opaskę do realizacji innych funkcji, co ograniczone jest tylko naszą wyobraźnią.
Przed rozbieraniem opaski autor poszukał jeszcze innych opasek opartych o ten układ. Jest ich kilka na rynku, część już została z powodzeniem przeprogramowana. Jest nawet projekt, który opisuje całą procedurę. Jest to zatem możliwe. Przejdźmy więc do działania.
Otwarcie urządzenia nie jest zbyt proste. Czarny plastikowy element osłaniający elektronikę jest sklejony z szarym tyłem urządzenia. Dobrze jest potraktować urządzenie suszarką, aby klej zmiękł, a następnie z pomocą noża otworzyć obudowę, dzięki czemu nie uszkodzimy plastikowych elementów.
Po otwarciu naszym oczom ukaże się układ scalony - nRF51822, tak jak przypuszczaliśmy. Nie jest to jednak takie oczywiste, bo autor projektu nabył podobną bransoletkę jakiś czas później i w niej znajdował się mikrokontroler firmy Texas Instruments. Warto być świadomym istniejących różnic.
Dogadanie się z mikrokontrolerem
Dokumentacja tego mikrokontrolera mówi, że można go zaprogramować poprzez interfejs SWD, wykorzystujący dwa piny. Tego rodzaju innterfejs programowania jest bardzo popularny w układach ARM. Aby z niego skorzystać, musimy:
* Posiadać programator z interfejsem SWD - w tej roli skorzystamy z J-Linka firmy Segger
* Zlokalizować miejsca podłączenia pinów mikrokontrolera - SWDIO (dane) oraz SWDCLK (zegar).
Piny te są często wyprowadzone w postaci pól itp., aby umożliwić programowanie, testowanie i weryfikację działania zegarka w fabryce. Tak jest też w tym przypadku; dosyć łatwo było odnaleźć je na płytce drukowanej, jak widzimy na zdjęciach po prawej stronie.
Dokładniej widać je na zdjęciach wykonanych z pomocą prostego mikroskopu na USB. Na zdjęciu oznaczono ścieki, którymi biegną sygnały od mikrokontrolera do padów do programowania:
Odnalezienie tych sygnałów nie jest takie proste - płyta drukowana tego układu jest wielowarstwowa, sporo ścieżek jest także w jej środku, podobnie jak przelotki itp. Sprawdzając przebieg ścieżek na szczęście udało się prześledzić tor sygnałów i potwierdzić, że pole opisane CLK na płytce drukowanej to w istocie zegar interfejsu SWD, a pin obok niego, który nie ma etykiety, to SWDIO, czyli pin danych. W ten sposób zbudowano tabelkę z rozpisanymi wyprowadzeniami do programowania:
Chirurgia na otwartym układzie
Gdy mamy już dostęp do pinów interfejsu SWD, musimy przylutować do wyeksponowanych padów cienkie druciki, którymi podłączymy układ do programatora. Następnie będziemy mogli przetestować układ z jakimś prostym programem - aby to było jednak możliwe, musimy po kolei:
* Sprawdzić, czy poprawnie odnaleźliśmy piny SWDIO i SWDCLK.
* Sprawdzić, czy posiadany przez nas programator SWD poprawnie komunikuje się z układem.
* Sprawdzić, czy kompilator jaki wykorzystujemy poprawnie działa z SDK do układów Nordica.
* Sprawdzić, czy poprawnie wgrywamy program do pamięci Flash układu.
* Sprawdzić, czy układ poprawnie startuje i ładuje nasz program.
Blinky
W tym przypadku najlepszym startowym programem będzie proste zapalanie i gaszenie diody LED. Nie jest to jednak takie proste, jak się wydaje, jako że w układzie nie ma żadnych diod LED, które moglibyśmy zapalać i gasić. Oznacza to, że musimy dołączyć do układu zewnętrzne diody, a to dodaje kolejny etap, gdzie coś może być źle. Autor podłączył dwie diody LED do pól P1 i P2 mikrokontrolera.
Oprogramowanie i sterowniki do programatora J-Link SWD można pobrać ze strony Seggera. Jeśli wykorzystujemy do programowania dodatkowo jakieś makra czy własne skrypty, to w caskroom/drivers/segger-jlink znajdziemy odpowiednie skrypty, które umożliwią wykorzystanie interfejsu SWD w programatorze poprzez komendy wydawane do JLinkExe.
Gdy już zainstalujemy powyższe sterowniki, musimy pobrać i zainstalować SDK od Nordica dla układów z rodziny nRF5 (autor korzysta z wersji 12.3.0). Oczywiście samo SDK nam nie wystarczy, dlatego kolejnym krokiem jest doinstalowanie odpowiedniego kompilatora - tutaj wybór padł na gcc-arm-embedded.
Po szybkiej analizie SDK i przykładów zawartych m.in. na forum Nordica, autor spostrzegł, iż SDK jest zazwyczaj używane z płytkami rozwojowymi itp. tego producenta. SDK dostarczane jest w prekonfigurowanej postaci, dopasowanej do kilku z wariantów płytek uruchomieniowych. W tym przypadku, jako że korzystamy bezpośrednio z mikrokontrolera, musimy wprowadzić w SDK pewne zmiany.
Jak pisze autor, zrozumienie ekosystemu układów nRF5 zajęło mu sporo czasu, ale w końcu się udało. Na filmie powyżej widzimy dwie mrugające diody LED. Aby uprościć prezentację programów i utrzymać trochę porządku, autor założył repozystorium na Githubie. Znajdziemy tam działające programy na nRF51822 oraz Makefile. Układ, z którym pracuje autor, ma zaledwie 16 kB pamięci RAM, co wymagało sporej gimnastyki w skrypcie linkera, aby to uwzględniał.
Cyfrowe IO
Aby mrugać diodami LED, konieczne było znalezienie wyjść cyfrowych - w tym przypadku P1 i P2, do których podłączone zostały diody LED. Po podłączeniu diod autor w programie po prostu cyklicznie zmieniał ich wartość z niskiej na wysoką i odwrotnie. Ku wielkiemu zaskoczeniu, także silniczek odpowiedzialny za wibracje układu cyklicznie się załączał. Na podstawie tego eksperymentalnego programu autor stworzył prostą tabelkę, w której zebrał informacje dotyczące wyprowadzeń cyfrowych układu:
printf
Możliwość pobierania informacji z układu jest niezwykle istotna podczas debuggowania. J-Link posiada wsparcie dla Real-Time Transfer (RTT), który umożliwia wysyłanie i odbieranie danych przez mikrokontroler i komputer. Aby skorzystać z tego interfejsu, dodajemy do programu odpowiednią bibliotekę:
a w kodzie programu korzystamy z funkcji:
Aby odczytywać informacje na komputerze, używamy CLI w jlinkrttlogger, które znajduje się w oprogramowaniu do J-Linka.
Wyświetlacz OLED
Kolejnym dużym wyzwaniem było uruchomienie wbudowanego wyświetlacza OLED. Większość tego rodzaju ekranów na rynku wykorzystuje kontroler ssd1306, który komunikuje się z mikrokontrolerem szeregowo - poprzez interfejs SPI lub I²C.
Takiego wyświetlacza jak w układzie nie udało się znaleźć w żadnym sklepie w Internecie. Rozmiar 96 x 32 także nie jest zbyt popularny. Poszukiwanie informacji na temat wyświetlacza oznaczonego "QT1316P01A" dało jedynie informacje na temat kolejności wyprowadzeń w układzie:
Jeśli dokumentacja nie kłamie, to obecność pinów SCL, SDA i RES# wskazuje, że mamy do czynienia z interfejsem I²C. Teraz wystarczy prześledzić podłączenie od pinów wyświetlacz OLED do mikrokontrolera, aby sprawdzić, czy nasz strzał jest poprawny. Wracamy do mikroskopu.
Po sprawdzeniu ścieżek na płytce drukowanej układu możemy uzupełnić kolejną tabelę połączeń:
Protokół I²C wymaga całkiem dużo zaangażowania programistycznego niż prostsze interfejsy, takie jak na przykład UART. Istotną jego zaletą z drugiej strony jest fakt, że pozwala on na jednym interfejsie, przy jednym urządzeniu w trybie master, komunikować się z wieloma układami typu slave. Komplikuje to jego działanie i zwiększa nakład wysiłków na uruchomienie komunikacji pomiędzy mikrokontrolerem a urządzeniami dookoła niego.
Oprócz fizycznej lokalizacji pinów, musimy poznać jeszcze adres naszego wyświetlacza, aby móc się z nim komunikować. Aby go poznać, autor zdecydował się na wykorzystanie skanera interfejsu I²C, jaki dostępny jest w ramach SDK dla układów nRF5. Program ten, mówiąc w skrócie, skanuje wszystkie adresy logiczne, wysyłając do każdego zapytania i informując, który z nich odpowiedział. Autor zmodyfikował go nieznacznie (program dostępny jest tutaj). W odpowiedzi układ daje nam:
Co oznacza, że istotnie nasz wyświetlacz działa na I²C i ma adres 0x3C - popularny wśród tego rodzaju kontrolerów.
Znając interfejs i logiczny adres wyświetlacza, możemy spróbować coś na nim wyświetlić. Póki co nie mamy dostępu do biblioteki z jakąś wyższą warstwą abstrakcji. Skorzystać możemy z dokumentacji do ssd1306, aby dowiedzieć się, w jaki sposób należy wysyłać dane do wyświetlacza. Proces ten składa się z serii komend konfigurujących go - ustawiana jest m.in. orientacja wyświetlacza, tryb zapisu itp. Następnie sekwencje danych zapisywane są do pamięci graficznej kontrolera (GDDRAM), która mapowana jest bezpośrednio na wyświetlacz.
Aby poprawnie skonfigurować wyświetlacz, autor wykorzystał część bibliotek dla ssd1306 dostarczanych przez Adafruit. Oprogramowanie na mikrokontroler Nordica będzie teraz reagować na podobne komendy co w przypadku wyświetlaczy Adafruit. Realizacja tego zadania była bardzo czasochłonna - to chyba najbardziej zajmujący etap całego projektu. Udało się uruchomić wyświetlacz, ale czasami działa on w trudny do wyjaśnienia (i zrozumienia) sposób.
Kod programu do tego testu znajdziemy tutaj
W obecnej konfiguracji wyświetlacz podzielony jest na 4 rzędy (strony) po 96 kolumn. Strony są wysokie na osiem pikseli. Pierwszy nadesłaby bajt zajmie pierwszą kolumnę na ekranie, drugi drugą, trzeci trzecią i tak dalej aż do 96 kolumny. Wtedy dane będą się zawijać na drugą stronę GDDRAM, która obsługuje kolejne kolumny na ekranie.
Oczywiście opisany powyżej algorytm to tylko teoria. Jak widać na filmie poniżej zdarza się czasami tak, że najpierw wypełniane są nieparzyste kolumny, a następnie parzyste, a dopiero potem dane się zawijają.
Autor spędził sporo czasu na zrozumieniu czemu tak się dzieje i próbach naprawy tego stanu rzeczy. Finalnie i tak skończyło się na tym, że ten dziwny sposób wyświetlania obrazu został skompensowany programowo, dzięki czemu dało się normalnie wyświetlać na ekranie znaki.
Wycieczka do krainy Arduino
Podczas debugowania wyświetlacza autor zajrzał - jako pomoc - do biblioteki Adafruit dla ssd1306. Bardzo chciał wtedy, aby możliwe było zaimplementowanie kodu Arduino na nRF51822. Okazuje się, że nie tylko on chciał tak zrobić - ludzie, o wiele bardziej znający się na programowaniu mikrokontrolerów także, w związku z czym po prostu to zrobili. Taką rolę pełni projekt arduino-nRF5. Implementuje on podstawowe biblioteki wykorzystując SDK do nRF5.
Dzięki temu projektowi, możemy uruchomić Arduino IDE, wybrać płytkę nRF5 i pisać programy na ten układ, korzystając z wielu zalet ekosystemu Arduino. Autor projektu zrobił forka tego projektu, w którym zaimplementował wsparcie dla swojej bransoletki. Może ona być wybrana w Arduino IDE w menu Tools > Board > ID115 Fitness Bracelet (nRF51822).
Oznacza to też, że teraz można wykorzystać dostępne biblioteki Adafruit do sterowania wyświetlaczem OLED. Ich wykorzystanie dało taki sam, dziwny sposób sterowania wyświetlaczem, co udało się obejść z zastosowaniem dodatkowej logiki w kodzie. W ten sposób osiągnęliśmy pewien poziom abstrakcji sprzętowej i możemy wykorzystać funkcje wyższego poziomu, na przykład narzędzia do rysowania czy renderowania tekstu na wyświetlaczu:
Wejścia analogowe
Oprócz wyjść cyfrowych, mikrokontroler nRF51822 posiada jeszcze dziesięć wejść analogowych. Są one bardzo użyteczne np. do pomiaru napięcia baterii w systemie przenośnym. Jak wynika z dokumentacji wbudowany przetwornik analogowo-cyfrowy ma rozdzielczość 10 bitów i odnosi się do napięcia zasilania - wejście na poziomie VCC daje kod 1023.
Autor wykonał prosty eksperyment - podawał różne wartośc i sygnały na wejście analogowe i sczytywał wartość analogową w kodzie programu. Na poniższym wykresie znajdują się najciekawsze z rezultatów:
Z pokazanej powyżej prostej analizy wynika, że pin P.0.05 najpewniej wykorzystywany jest do monitorowania stanu naładowania akumulatora, a P0.26 podłączony jest do jednego z wyjść akcelerometru, jako że dynamicznie zmienia wartość podczas potrząsania urządzeniem. Piny P0.03 oraz P0.04 także najpewniej podłączone są do akcelerometru, aczkolwiek zmiany na tych pinach mogą wynikać z jakichś innych efektów.
Na wykresie po lewej warto też zwrócić uwagę, jak zmienia się napięcie na baterii podczas potrząsania urządzeniem - wynika to z faktu zwiększania się zużycia prądu podczas wykorzystywania akcelerometru.
Powyższe próby pozwoliły uzupełnić opis kilku kolejnych linii w układzie:
Przycisk
Oryginalny firmware opaski reagował na naciśnięcie ekranu, załączając wyświetlacz. Przytrzymanie go dłużej włączało stoper. Nie jest to fizyczny przycisk, a sensor pojemnościowy. Autorowi udało się zidentyfikować sposób w jaki podłączony jest do mikrokontrolera i jak można go obsłużyć w naszym programie:
Kod źródłowy do powyższego przykładu znaleźć można tutaj.
Bluetooth low energy (BLE)
Funkcjonalność BLE zaimplementowana jest w układach nRF5 z wykorzystaniem tzw. SoftDevice. Jest ro prekompilowana binarka, która zawiera w sobie stos BLE. Powinna być niezależnie wgrana do pamięci układu. Istnieje wiele wersji SoftDevice, zależnie od tego jaki mamy układ i jakie SDK. W dokumentacji dostępna jest macierz kompatybilności. Wynika z niej, że dla SDK 12.3 używanego przez autora projektu i dla układu z steppingiem QFAAH0, jaki jest w opasce, użyć należy SoftDevice s130.
W używanym SDK znaleźć można szereg przykładów implementacji z wykorzystaniem s130.
Programowane układu z wykorzystaniem SoftDevice różni się jedną istotną rzeczą od normalnego programowania - na etapie flashowania, wgrywamy swój program nie zaczynając od adresy 0x0; zaczynamy od 0x01b000, aby zostawić miejsce na SoftDevice. Autor przygotował oprogramowanie, oparte na przykładzie z mrugającą diodą, które dodatkowo wgrywa SoftDevice. Układ działa tak samo, ale w mikrokontrolerze znajduje się już stos BLE.
Programowanie mikrokontrolera musimy zacząć od manualnego wgrania SoftDevice:
Od tego momentu opaska jest wykrywana przez urządzenia z BLE dookoła. Nie jest w stanie nadawać ani odbierać, ale może pełnić rolę radiolatarni Bluetooth.
BLE + Arduino
Po uruchomieniu przykładów z BLE z SDK nRF5 i wiedząc o sztuczkach, jakie trzeba zrobić z RAMem i oscylatorem, aby uruchomić moduł Bluetooth, można było przenieść się do środowiska Arduino. Po raz kolejny wystarczyło skorzystać z gotowego projektu sandeepmistry/arduino-BLEPeripheral i korzystać z BLE w programach tworzonych w środowisky Arduino.
Źródło: https://rbaron.net/blog/2018/05/27/Hacking-a-cheap-fitness-tracker-bracelet.html
* Naprawdę niewielki rozmiar (około 15 mm x 40 mm)
* Interfejs Bluetooth low energy (BLE)
* Wyświetlacz OLED (o rozdzielczości 96 x 32 piksele)
* Wbudowany akumulator
* Ładowanie poprzez USB
* Zintegrowany akcelerometr
* Silniczek do wibracji
* Cena zaledwie około 10 dolarów
Jedyne co identyfikuje urządzenie na obudowie to identyfikator FCC - "FCC ID: 2AHFTID115". Wyszukiwanie tego numeru w Google daje całkiem dużo informacji, jeśli się postaramy. Urządzenie nazywa się ID115, a przynajmniej pod taką nazwą znajdziemy je w Internecie. Dodatkowo można znaleźć kilka ciekawych zdjęć - zwłaszcza wnętrza urządzenia. Jeśli dobrze się przypatrzymy, to dostrzeżemy na nich układ scalony opisany N51822. Sugeruje to nam, że układ oparty jest o mikrokontroler nRF51822 firmy Nordic. Jest to 32-bitowy procesor z rdzeniem ARM-M0 i z wbudowanym wsparciem dla BLE. Mikrokontroler ten dosyć łatwo można by przeprogramować, aby zmusić opaskę do realizacji innych funkcji, co ograniczone jest tylko naszą wyobraźnią.
Przed rozbieraniem opaski autor poszukał jeszcze innych opasek opartych o ten układ. Jest ich kilka na rynku, część już została z powodzeniem przeprogramowana. Jest nawet projekt, który opisuje całą procedurę. Jest to zatem możliwe. Przejdźmy więc do działania.
Otwarcie urządzenia nie jest zbyt proste. Czarny plastikowy element osłaniający elektronikę jest sklejony z szarym tyłem urządzenia. Dobrze jest potraktować urządzenie suszarką, aby klej zmiękł, a następnie z pomocą noża otworzyć obudowę, dzięki czemu nie uszkodzimy plastikowych elementów.
Po otwarciu naszym oczom ukaże się układ scalony - nRF51822, tak jak przypuszczaliśmy. Nie jest to jednak takie oczywiste, bo autor projektu nabył podobną bransoletkę jakiś czas później i w niej znajdował się mikrokontroler firmy Texas Instruments. Warto być świadomym istniejących różnic.
Dogadanie się z mikrokontrolerem
Dokumentacja tego mikrokontrolera mówi, że można go zaprogramować poprzez interfejs SWD, wykorzystujący dwa piny. Tego rodzaju innterfejs programowania jest bardzo popularny w układach ARM. Aby z niego skorzystać, musimy:
* Posiadać programator z interfejsem SWD - w tej roli skorzystamy z J-Linka firmy Segger
* Zlokalizować miejsca podłączenia pinów mikrokontrolera - SWDIO (dane) oraz SWDCLK (zegar).
Piny te są często wyprowadzone w postaci pól itp., aby umożliwić programowanie, testowanie i weryfikację działania zegarka w fabryce. Tak jest też w tym przypadku; dosyć łatwo było odnaleźć je na płytce drukowanej, jak widzimy na zdjęciach po prawej stronie.
Dokładniej widać je na zdjęciach wykonanych z pomocą prostego mikroskopu na USB. Na zdjęciu oznaczono ścieki, którymi biegną sygnały od mikrokontrolera do padów do programowania:
Odnalezienie tych sygnałów nie jest takie proste - płyta drukowana tego układu jest wielowarstwowa, sporo ścieżek jest także w jej środku, podobnie jak przelotki itp. Sprawdzając przebieg ścieżek na szczęście udało się prześledzić tor sygnałów i potwierdzić, że pole opisane CLK na płytce drukowanej to w istocie zegar interfejsu SWD, a pin obok niego, który nie ma etykiety, to SWDIO, czyli pin danych. W ten sposób zbudowano tabelkę z rozpisanymi wyprowadzeniami do programowania:
nRF51822 Pin | Pad | Opis |
SWDIO | IO | Pin danych dla programatora z interfejsem SWD |
SWDCLK | CLK | Pin zegara dla programatora z interfejsem SWD |
Chirurgia na otwartym układzie
Gdy mamy już dostęp do pinów interfejsu SWD, musimy przylutować do wyeksponowanych padów cienkie druciki, którymi podłączymy układ do programatora. Następnie będziemy mogli przetestować układ z jakimś prostym programem - aby to było jednak możliwe, musimy po kolei:
* Sprawdzić, czy poprawnie odnaleźliśmy piny SWDIO i SWDCLK.
* Sprawdzić, czy posiadany przez nas programator SWD poprawnie komunikuje się z układem.
* Sprawdzić, czy kompilator jaki wykorzystujemy poprawnie działa z SDK do układów Nordica.
* Sprawdzić, czy poprawnie wgrywamy program do pamięci Flash układu.
* Sprawdzić, czy układ poprawnie startuje i ładuje nasz program.
Blinky
W tym przypadku najlepszym startowym programem będzie proste zapalanie i gaszenie diody LED. Nie jest to jednak takie proste, jak się wydaje, jako że w układzie nie ma żadnych diod LED, które moglibyśmy zapalać i gasić. Oznacza to, że musimy dołączyć do układu zewnętrzne diody, a to dodaje kolejny etap, gdzie coś może być źle. Autor podłączył dwie diody LED do pól P1 i P2 mikrokontrolera.
Oprogramowanie i sterowniki do programatora J-Link SWD można pobrać ze strony Seggera. Jeśli wykorzystujemy do programowania dodatkowo jakieś makra czy własne skrypty, to w caskroom/drivers/segger-jlink znajdziemy odpowiednie skrypty, które umożliwią wykorzystanie interfejsu SWD w programatorze poprzez komendy wydawane do JLinkExe.
Gdy już zainstalujemy powyższe sterowniki, musimy pobrać i zainstalować SDK od Nordica dla układów z rodziny nRF5 (autor korzysta z wersji 12.3.0). Oczywiście samo SDK nam nie wystarczy, dlatego kolejnym krokiem jest doinstalowanie odpowiedniego kompilatora - tutaj wybór padł na gcc-arm-embedded.
Po szybkiej analizie SDK i przykładów zawartych m.in. na forum Nordica, autor spostrzegł, iż SDK jest zazwyczaj używane z płytkami rozwojowymi itp. tego producenta. SDK dostarczane jest w prekonfigurowanej postaci, dopasowanej do kilku z wariantów płytek uruchomieniowych. W tym przypadku, jako że korzystamy bezpośrednio z mikrokontrolera, musimy wprowadzić w SDK pewne zmiany.
Jak pisze autor, zrozumienie ekosystemu układów nRF5 zajęło mu sporo czasu, ale w końcu się udało. Na filmie powyżej widzimy dwie mrugające diody LED. Aby uprościć prezentację programów i utrzymać trochę porządku, autor założył repozystorium na Githubie. Znajdziemy tam działające programy na nRF51822 oraz Makefile. Układ, z którym pracuje autor, ma zaledwie 16 kB pamięci RAM, co wymagało sporej gimnastyki w skrypcie linkera, aby to uwzględniał.
Cyfrowe IO
Aby mrugać diodami LED, konieczne było znalezienie wyjść cyfrowych - w tym przypadku P1 i P2, do których podłączone zostały diody LED. Po podłączeniu diod autor w programie po prostu cyklicznie zmieniał ich wartość z niskiej na wysoką i odwrotnie. Ku wielkiemu zaskoczeniu, także silniczek odpowiedzialny za wibracje układu cyklicznie się załączał. Na podstawie tego eksperymentalnego programu autor stworzył prostą tabelkę, w której zebrał informacje dotyczące wyprowadzeń cyfrowych układu:
nRF51822 Pin | Pad | Opis |
P0.30 | P1 | Wyjście GPIO |
P0.00 | P2 | Wyjście GPIO |
P0.01 | - | Silnik wibracji |
printf
Możliwość pobierania informacji z układu jest niezwykle istotna podczas debuggowania. J-Link posiada wsparcie dla Real-Time Transfer (RTT), który umożliwia wysyłanie i odbieranie danych przez mikrokontroler i komputer. Aby skorzystać z tego interfejsu, dodajemy do programu odpowiednią bibliotekę:
Code: c
a w kodzie programu korzystamy z funkcji:
Code: c
Aby odczytywać informacje na komputerze, używamy CLI w jlinkrttlogger, które znajduje się w oprogramowaniu do J-Linka.
Wyświetlacz OLED
Kolejnym dużym wyzwaniem było uruchomienie wbudowanego wyświetlacza OLED. Większość tego rodzaju ekranów na rynku wykorzystuje kontroler ssd1306, który komunikuje się z mikrokontrolerem szeregowo - poprzez interfejs SPI lub I²C.
Takiego wyświetlacza jak w układzie nie udało się znaleźć w żadnym sklepie w Internecie. Rozmiar 96 x 32 także nie jest zbyt popularny. Poszukiwanie informacji na temat wyświetlacza oznaczonego "QT1316P01A" dało jedynie informacje na temat kolejności wyprowadzeń w układzie:
Jeśli dokumentacja nie kłamie, to obecność pinów SCL, SDA i RES# wskazuje, że mamy do czynienia z interfejsem I²C. Teraz wystarczy prześledzić podłączenie od pinów wyświetlacz OLED do mikrokontrolera, aby sprawdzić, czy nasz strzał jest poprawny. Wracamy do mikroskopu.
Po sprawdzeniu ścieżek na płytce drukowanej układu możemy uzupełnić kolejną tabelę połączeń:
nRF51822 Pin | Pad | Opis |
P0.21 | - | Pin SDA wyświetlacza OLED |
P0.22 | - | Pin SCL wyświetlacza OLED |
P0.24 | - | Pin RES# wyświetlacza OLED |
Protokół I²C wymaga całkiem dużo zaangażowania programistycznego niż prostsze interfejsy, takie jak na przykład UART. Istotną jego zaletą z drugiej strony jest fakt, że pozwala on na jednym interfejsie, przy jednym urządzeniu w trybie master, komunikować się z wieloma układami typu slave. Komplikuje to jego działanie i zwiększa nakład wysiłków na uruchomienie komunikacji pomiędzy mikrokontrolerem a urządzeniami dookoła niego.
Oprócz fizycznej lokalizacji pinów, musimy poznać jeszcze adres naszego wyświetlacza, aby móc się z nim komunikować. Aby go poznać, autor zdecydował się na wykorzystanie skanera interfejsu I²C, jaki dostępny jest w ramach SDK dla układów nRF5. Program ten, mówiąc w skrócie, skanuje wszystkie adresy logiczne, wysyłając do każdego zapytania i informując, który z nich odpowiedział. Autor zmodyfikował go nieznacznie (program dostępny jest tutaj). W odpowiedzi układ daje nam:
Code: bash
Co oznacza, że istotnie nasz wyświetlacz działa na I²C i ma adres 0x3C - popularny wśród tego rodzaju kontrolerów.
Znając interfejs i logiczny adres wyświetlacza, możemy spróbować coś na nim wyświetlić. Póki co nie mamy dostępu do biblioteki z jakąś wyższą warstwą abstrakcji. Skorzystać możemy z dokumentacji do ssd1306, aby dowiedzieć się, w jaki sposób należy wysyłać dane do wyświetlacza. Proces ten składa się z serii komend konfigurujących go - ustawiana jest m.in. orientacja wyświetlacza, tryb zapisu itp. Następnie sekwencje danych zapisywane są do pamięci graficznej kontrolera (GDDRAM), która mapowana jest bezpośrednio na wyświetlacz.
Aby poprawnie skonfigurować wyświetlacz, autor wykorzystał część bibliotek dla ssd1306 dostarczanych przez Adafruit. Oprogramowanie na mikrokontroler Nordica będzie teraz reagować na podobne komendy co w przypadku wyświetlaczy Adafruit. Realizacja tego zadania była bardzo czasochłonna - to chyba najbardziej zajmujący etap całego projektu. Udało się uruchomić wyświetlacz, ale czasami działa on w trudny do wyjaśnienia (i zrozumienia) sposób.
Kod programu do tego testu znajdziemy tutaj
W obecnej konfiguracji wyświetlacz podzielony jest na 4 rzędy (strony) po 96 kolumn. Strony są wysokie na osiem pikseli. Pierwszy nadesłaby bajt zajmie pierwszą kolumnę na ekranie, drugi drugą, trzeci trzecią i tak dalej aż do 96 kolumny. Wtedy dane będą się zawijać na drugą stronę GDDRAM, która obsługuje kolejne kolumny na ekranie.
Oczywiście opisany powyżej algorytm to tylko teoria. Jak widać na filmie poniżej zdarza się czasami tak, że najpierw wypełniane są nieparzyste kolumny, a następnie parzyste, a dopiero potem dane się zawijają.
Autor spędził sporo czasu na zrozumieniu czemu tak się dzieje i próbach naprawy tego stanu rzeczy. Finalnie i tak skończyło się na tym, że ten dziwny sposób wyświetlania obrazu został skompensowany programowo, dzięki czemu dało się normalnie wyświetlać na ekranie znaki.
Wycieczka do krainy Arduino
Podczas debugowania wyświetlacza autor zajrzał - jako pomoc - do biblioteki Adafruit dla ssd1306. Bardzo chciał wtedy, aby możliwe było zaimplementowanie kodu Arduino na nRF51822. Okazuje się, że nie tylko on chciał tak zrobić - ludzie, o wiele bardziej znający się na programowaniu mikrokontrolerów także, w związku z czym po prostu to zrobili. Taką rolę pełni projekt arduino-nRF5. Implementuje on podstawowe biblioteki wykorzystując SDK do nRF5.
Dzięki temu projektowi, możemy uruchomić Arduino IDE, wybrać płytkę nRF5 i pisać programy na ten układ, korzystając z wielu zalet ekosystemu Arduino. Autor projektu zrobił forka tego projektu, w którym zaimplementował wsparcie dla swojej bransoletki. Może ona być wybrana w Arduino IDE w menu Tools > Board > ID115 Fitness Bracelet (nRF51822).
Oznacza to też, że teraz można wykorzystać dostępne biblioteki Adafruit do sterowania wyświetlaczem OLED. Ich wykorzystanie dało taki sam, dziwny sposób sterowania wyświetlaczem, co udało się obejść z zastosowaniem dodatkowej logiki w kodzie. W ten sposób osiągnęliśmy pewien poziom abstrakcji sprzętowej i możemy wykorzystać funkcje wyższego poziomu, na przykład narzędzia do rysowania czy renderowania tekstu na wyświetlaczu:
Wejścia analogowe
Oprócz wyjść cyfrowych, mikrokontroler nRF51822 posiada jeszcze dziesięć wejść analogowych. Są one bardzo użyteczne np. do pomiaru napięcia baterii w systemie przenośnym. Jak wynika z dokumentacji wbudowany przetwornik analogowo-cyfrowy ma rozdzielczość 10 bitów i odnosi się do napięcia zasilania - wejście na poziomie VCC daje kod 1023.
Autor wykonał prosty eksperyment - podawał różne wartośc i sygnały na wejście analogowe i sczytywał wartość analogową w kodzie programu. Na poniższym wykresie znajdują się najciekawsze z rezultatów:
Z pokazanej powyżej prostej analizy wynika, że pin P.0.05 najpewniej wykorzystywany jest do monitorowania stanu naładowania akumulatora, a P0.26 podłączony jest do jednego z wyjść akcelerometru, jako że dynamicznie zmienia wartość podczas potrząsania urządzeniem. Piny P0.03 oraz P0.04 także najpewniej podłączone są do akcelerometru, aczkolwiek zmiany na tych pinach mogą wynikać z jakichś innych efektów.
Na wykresie po lewej warto też zwrócić uwagę, jak zmienia się napięcie na baterii podczas potrząsania urządzeniem - wynika to z faktu zwiększania się zużycia prądu podczas wykorzystywania akcelerometru.
Powyższe próby pozwoliły uzupełnić opis kilku kolejnych linii w układzie:
nRF51822 Pin | Pad | Opis |
P0.05 | - | Wejście analogowe - Monitorowanie pracy ładowarki |
P0.26 | - | Wejście analogowe - Jedna z osi akcelerometru |
P0.03 | - | Wejście analogowe - Jedna z osi akcelerometru (chyba) |
P0.04 | - | Wejście analogowe - Jedna z osi akcelerometru (chyba) |
Przycisk
Oryginalny firmware opaski reagował na naciśnięcie ekranu, załączając wyświetlacz. Przytrzymanie go dłużej włączało stoper. Nie jest to fizyczny przycisk, a sensor pojemnościowy. Autorowi udało się zidentyfikować sposób w jaki podłączony jest do mikrokontrolera i jak można go obsłużyć w naszym programie:
Kod źródłowy do powyższego przykładu znaleźć można tutaj.
Bluetooth low energy (BLE)
Funkcjonalność BLE zaimplementowana jest w układach nRF5 z wykorzystaniem tzw. SoftDevice. Jest ro prekompilowana binarka, która zawiera w sobie stos BLE. Powinna być niezależnie wgrana do pamięci układu. Istnieje wiele wersji SoftDevice, zależnie od tego jaki mamy układ i jakie SDK. W dokumentacji dostępna jest macierz kompatybilności. Wynika z niej, że dla SDK 12.3 używanego przez autora projektu i dla układu z steppingiem QFAAH0, jaki jest w opasce, użyć należy SoftDevice s130.
W używanym SDK znaleźć można szereg przykładów implementacji z wykorzystaniem s130.
Programowane układu z wykorzystaniem SoftDevice różni się jedną istotną rzeczą od normalnego programowania - na etapie flashowania, wgrywamy swój program nie zaczynając od adresy 0x0; zaczynamy od 0x01b000, aby zostawić miejsce na SoftDevice. Autor przygotował oprogramowanie, oparte na przykładzie z mrugającą diodą, które dodatkowo wgrywa SoftDevice. Układ działa tak samo, ale w mikrokontrolerze znajduje się już stos BLE.
Programowanie mikrokontrolera musimy zacząć od manualnego wgrania SoftDevice:
Code: bash
Od tego momentu opaska jest wykrywana przez urządzenia z BLE dookoła. Nie jest w stanie nadawać ani odbierać, ale może pełnić rolę radiolatarni Bluetooth.
BLE + Arduino
Po uruchomieniu przykładów z BLE z SDK nRF5 i wiedząc o sztuczkach, jakie trzeba zrobić z RAMem i oscylatorem, aby uruchomić moduł Bluetooth, można było przenieść się do środowiska Arduino. Po raz kolejny wystarczyło skorzystać z gotowego projektu sandeepmistry/arduino-BLEPeripheral i korzystać z BLE w programach tworzonych w środowisky Arduino.
Źródło: https://rbaron.net/blog/2018/05/27/Hacking-a-cheap-fitness-tracker-bracelet.html
Cool? Ranking DIY