Oto krótka prezentacja wnętrza mikrowieży z odtwarzaczem CD i USB firmy Blaupunkt model MS8BK. Sprawdzę tutaj jak jest ona zbudowana, spróbuję przeanalizować jej firmware z nieznanego mikroprocesora i określić jego architekturę w Ghidra, a potem uruchomię jej wyświetlacz z Arduino.
Wnętrze MS8BK
Sprzęt trafił do mnie zdekompletowany, więc prezentacja nie obejmuje zasilacza. Z samej płytki mogę wywnioskować, że zapewniał on standardowe napięcia, takie jak 5 i 12 V. Pewnie to był już zasilacz impulsowy w topologii flyback - tego typu rozwiązania widuję we współczesnych sprzętach. W starszych wieżach audio były klasyczne transformatory na 50/60 Hz, teraz już coraz rzadziej je spotykam.
Płyta główna opiera się procesor Mediatek, zostawię go na koniec. Tuż obok niego widać pamięć Flash 2 MB, na której być może znajduje się program, a w rogu jest też pamięć EEPROM - może dla konfiguracji.
Na płytce znajduje się osobny czterokanałowy procesor do audio - PT7314E, główne CPU steruje nim przez I2C:
Osobno mamy wzmacniacz - podwójny 7W+7W, TDA7266SA, zamontowany na dużym radiatorze zapewniającym odpowiednie chłodzenie:
W rogu przykuł jeszcze moją uwagę rezonator kwarcowy zegarkowy i mały układ - początkowo myślałem, że to RTCC, ale tam prowadzi antenka. To pewnie układ odbiorczy radia. Może dałoby się go luzem uruchomić?
No i został główny MCU:
Mediatek MT8309QLN. Nie znalazłem o nim konkretnych informacji w sieci, choć ktoś umieścił już z niego wsad na innym forum:
Spoiler:
Czyli MS12BT ma bardzo podobną budowę.
Płytka z wyświetlaczem jest o wiele prostsza. Laminat jest jednostronny, od strony ścieżek przylutowany powierzchniowo jest tylko główny kontroler, CD1628. Obsługuje on przyciski i wyświetlacz 7-segmentowy. Dodatkowo na płytce mamy odbiornik IR, enkoder i diodę standby.
Analiza pamięci Flash
Pamięć Flash wylutowałem za pomocą gorącego powietrza i odczytałem programatorem CH341.
Binwalk nic ciekawego w niej nie znajdywał. Zacząłem przeglądać ją w xvi32. Nie widać żadnej struktury nagłówka bądź partycji. Pamięć zaczyna się od bajtów 02 1F E0, co przypomina instrukcję skoku 8051:
0x02 to kod instrukcji, 0x1FE0 to adres skoku.
Na offsecie 03 znów mamy instrukcję skoku 02 21 D0. Pasuje to z pozycją przerwania 8051. Wygląda na to, ze rzeczywiście mamy tu użyty ten klasyczny rdzeń.
Spróbujemy to zdekompilować, ale jeszcze warto poszukać napisów w formacie ASCII, mogą one dużo zdradzić o firmware.
XVID, 3IV1, MP4S, M4S2 - kodeki.
Nic więcej o bootowaniu i linii komend nie ma, więc pewnie UART nie uruchomimy. UPGRAD sugeruje jedynie aktualizacje wsadu. Ciekawe skąd tam SCOTT - czy to podpis autora?
MT1369? Nazwa wewnętrzna układu? Chyba coś się nie zgadza? Chociaż tu i tu Mediatek...
https://www.elektroda.pl/rtvforum/find.php?q=MT1369
Wygląda na układ z DVD, dziwne. Może to wewnętrznie jest ten sam procesor.
Pora jednak przejść dalej. Załadowałem flash do dekompilatora Ghidra i zdekodowałem go jako instrukcje 8051. Operacje wyglądają poprawnie, najpierw mamy skok do właściwego programu z adresu 0x0, bo na początku mamy wektory przerwań:
Pierwsza funkcja przypomina inicjalizację trzech pinów oraz pamięci:
Kod: C / C++
Udało mi się znaleźć też osobną funkcje inicjujące timer, to dobitnie pokazuje, że instrukcje są dekodowane poprawnie:
Szukałem też komend powiązanych z UART, ale nie znalazłem niczego co by przypominało bezpośrednio wysyłanie bądź odbiór, mimo iż standardowe rejestry UART z 8051 są dobrze udokumentowane i znane.
Porównanie ze wsadem z MT1369?
Zaciekawiło mnie jednak to, czemu wedle naszego forum ten sam napis występuje w zrzutach pamięci z DVD.
Pobrałem kopię wsadu z tego postu:
https://www.elektroda.pl/rtvforum/topic467658.html#2627620
To chyba ten sam proces inicjalizacyjny (bądź bootloader). Szybkie porównanie obu firmware w Ghidra pokazuje bardzo duże podobieństwo.
Kod: C / C++
To potwierdza mocne powiązanie obu firmware i układów, choć głębszej analizy już nie wykonywałem.
Podjąłem jeszcze próbę skompilowania w SDCC prostego blink dla 8051 ale nie udało mi się wykryć żadnego migania na portach mojego nieznanego procesora. Nie wiem jednak, czy wcześniej on działał - radio rzekomo miało zasilanie a nie startowało, więc może już wcześniej coś było z nim nie tak.
Pierwszy krok z wyświetlaczem
Moduł z wyświetlaczem jest bardzo atrakcyjny i przydatny - nie wymaga wielu pinów do sterowania, a w sam raz pasuje na zegarek. Jest dużo cyfr, są dwa dwukropki, warto będzie powalczyć.
Zacząć trzeba od noty katalogowej CD1628. Na szczęście jest ona dostępna:
CD1628 sterowany jest trzema pinami - DIO (dane we/wy), CLK (zegar) oraz STB (strobe, wybór układu).
Protokół jest opisany w PDF:
Krótka lektura noty wskazuje nam, że to zasadniczo jest taki sam układ jak znana rodzina TM1628, TM1637, TM1650, itd:
Uruchamiamy sterownik wyświetlacza/przycisków HD2015 po inżynierii wstecznej, porównanie z TM1637itd
Wyświetlacze 7-segmentowe na TM1637 - 4 i 6 cyfr - Arduino, protokół
Zasadnicza różnica jest taka, że zamiast generować tu warunki startu i stopu w stylu I2C, operujemy tu pinem STB.
Pora wpisać to w kod - dla uproszczenia wybrałem Arduino:
Najpierw piny - 0 i 1 to RX/TX, więc zacząłem od 2:
Kod: C / C++
Potem wysyłanie danych - zgodnie z notą katalogową.
Bity są wczytywane na rosnącym zboczu zegara, dlatego najpierw ustawiam zegar na stan LOW (niski), potem ustawiam stan DIO, a następnie odczekuję moment i przywracam zegar na stan wysoki.
Kod: C / C++
Strobe musi być w stanie niskim na czas komunikacji, więc dodałem pomocniczą funkcję wysyłającą komendę:
Kod: C / C++
To jest podstawowy budulec wysyłania.
Teraz pytanie co trzeba wysyłać.
Adresy rejestrów i komendy są takie same jak w TM1650 i podobnych.
Kolejno:
- Command 1 - ustawienie trybu wyświetlacza (ile segmentów, ile siatek)
- Command 2 - ustawienie trybu pracy (tryb normalny)
- Command 3 - ustawienie adresu wyświetlania oraz dane (segmenty)
- Command 4 - ustawienie kontroli wyświetlacza (poziom jasności, stan on/off)
Kod: C / C++
Tu jedyna niewiadomą jest pierwsza komenda - bo mamy cztery tryby pracy, skąd można wiedzieć, który jest użyty na płytce? Czy trzeba śledzić ścieżki?
Moim zdaniem niekoniecznie - po prostu sprawdziłem każdą z 4 opcji i przystałem na tą, która z moim testowym kodem ustawiającym wszystkie dane naprzemiennie na 1 i 0 zapala i gasi wszystkie fragmenty.
Kod: C / C++
Rezultat - najpierw bez ustawienia poprawnej konfiguracji siatek/segmentów (0x03):
Z poprawną konfiguracją:
Segmenty
Potem zacząłem eksperymentować jak kontrolować segmenty. Okazało się, że segmenty jednej cyfry rozrzucone są po różnych rejestrach. To znaczy, taki kod:
Kod: C / C++
gasi pierwszą cyfrę:
Zostało tylko ręcznie sprawdzić, która pozycja odpowiada któremu segmentowi - potem w oparciu o to można utworzyć maski cyfr.
Cyfry
Określiłem też potem, które rejestry w ogóle są powiązane z cyframi - nie wszystkie, zasadniczo co drugi:
Kod: C / C++
Powyżej zrealizowane jest proste przewijanie cyfr.
Przeróbka na wspólny bufor, ikonki i odliczanie
Teraz można by zrobić już normalne odliczanie lub zegar, ale jeszcze trzeba wydzielić bufor tak, by był wspólny z ikonkami. To dlatego, że tablica, która jest teraz, reprezentuje wszystkie segmenty - nie tylko same cyfry.
Tablica on jest teraz globalna, a funkcja drawText odpowiednio zapala lub gasi wszystkie segmenty cyfr. Dodatkowo wydzieliłem funkcję pomocniczą setIcon która zapala lub gasi dany segment określony indeksem bajtu i bitu.
Co najważniejsze, setIcon można wywołać raz a kolejne drawText nie nadpiszą zmian.
Udało się też znaleźć oba dwukropki.
Kod: C / C++
Pomocnicze funkcje dla ikonek:
Kod: C / C++
Zostało zdekodować klawisze.
Odczyt jest bardzo prosty. Po prostu wysyłamy odpowiednią komendę a potem odczytujemy dane z tego samego pinu którym je wysyłaliśmy. Kontroler wystawia dane na zboczu opadającym.
Tu też jest ciekawa sprawa, bo CD1628 zwraca nam 5 bajtów, a tylko wybrane ich bity dotyczą klawiszy - reszta jest bez znaczenia. Nie wiem, skąd taka decyzja projektowa.
Zrezygnowałem z określania tych bitów, po prostu trzymam tablicę pięciu bajtów i z każdym odczytem sprawdzam, które bity się zmieniły, a potem wywołuję funkcje obsługujące zdarzenia, osobno wciśnięcie i zwolnienie klawisza.
Kod: C / C++
Rezultat:
W ten sposób można zrobić funkcjonalny zegar bądź kontroler urządzenia z wyświetlaczem. Można by jeszcze uruchomić enkoder i jego też zaprząc do pracy.
Podsumowanie
Sprzęt trafił do mnie niekompletny, choć na pewno wiem, że zasilacz był sprawny i przydał się pierwszemu właścicielowi.
Oprócz zasilacza była jeszcze płyta główna oraz frontowe PCB z wyświetlaczem.
Płyta główna okazała się być dość ciekawa, udało się zgrać pamięć Flash, określić architekturę MCU, przeanalizować jego firmware a nawet odnaleźć jego powiązania z układami z odtwarzaczy DVD. Chciałem też wgrać na niego prosty "blink LED", ale ten niestety nie ruszył - nie eksperymentowałem z tym jednak dalej, bo podejrzewam, że coś wcześniej mogło być uszkodzone.
Płyta frontowa również mnie zainteresowała, i w tym przypadku udało się ją łatwo uruchomić z Arduino. Prawie cała jest zrealizowana w oparciu o układ CD1628, czyli jednolity sterownik wyświetlacza i klawiatury podobny do popularniejszych TM1650, TM1637, TM1636, itd. Nawet adresy rejestrów się zgadzają.
Podsumowując, przygoda była ciekawa.
Załączam zgrany wsad 2MB, może ktoś też chce go otworzyć w Ghidra:
https://github.com/openshwprojects/FlashDumps/commit/dae69584d40094af235c3fbebc51254746f39f4e
Fajne? Ranking DIY Pomogłem? Kup mi kawę.