Historia prezentowanego rozwiązania ma początek czysto praktyczny. Kilkanaście miesięcy temu na portalu aukcyjnym zakupiłem w przyzwoitej cenie naprawdę niezły amplituner, czyli połączenie wzmacniacza z odbiornikiem radiowym: urządzenie marki DUAL, które jest już leciwe, ale nadal parametrami i wyglądem pozostawia w tyle wiele obecnie produkowanych sprzętów audio.
Nabyłem model CR 5950 RC – Audiophile Concept HiFi Receiver, który dysponuje mocą ok. 2×70W współpracując z kolumnami 8Ω (dużo za dużo, jeśli chodzi o niewielkie mieszkanie w bloku). Po rozpakowaniu przesyłki okazało się, że amplituner faktycznie jest w dobrym stanie oraz w pełni sprawny, jeśli nie brać pod uwagę losowego wyboru źródła sygnału po każdym włączeniu zasilania (ze wskazaniem na CD lub Tuner).
Niestety przesyłka nie zawierała niczego więcej, czyli ani dokumentacji, ani pilota. Szkoda, bo literki RC w nazwie zobowiązują, ale na usprawiedliwienie można dodać, że wzmianki o pilocie w aukcji nie pamiętam, więc jego brak nie był wielkim rozczarowaniem. W tym miejscu bieg zdarzeń nieco zwalnia, tzn. mój nabytek po wstępnym przetestowaniu został przyjęty do eksploatacji, codziennie spełnia swoją funkcję, czyli po prostu używam go jako wzmacniacza do kolumn Maestro II 180. No i może jak mawiał satyryk „to by było na tyle”, ale…
Te wspomniane wcześniej literki RC (zapewne skrót od ang. remote controlled) oraz pewna niewygoda użytkowania spowodowały, że zacząłem rozglądać się za brakującym pilotem.
VINTAGE w praktyce
Warto krótko wspomnieć o producencie. Firma DUAL była jednym z największych producentów gramofonów oraz innego sprzętu audio w Europie, a jej początki sięgają początków XX w. Z informacji znalezionych w Internecie wynika, że niemiecka firma nie wytrzymała konkurencji ze strony producentów azjatyckich i popadła w kłopoty finansowe na początku lat 80., następnie była sprzedawana kilka razy. Obecnie istnieją marki Dual Phono (nadal produkuje gramofony, teoretycznie spadkobierca technologii DUAL) oraz Dual DGC, firma sprzedaje produkty dalekowschodnie oznaczone wspomnianą marką. W Amerykach jest podobnie, chiński producent wykupił prawa do nazwy.
Nie znałem modelu pilota, jak wspomniałem, nie otrzymałem dokumentacji, ale to nie problem. W kilka minut w Internecie można znaleźć instrukcję użytkownika, która mówi, że do sterowania służy pilot o oznaczeniu RC550 (jest też zdjęcie). Kilka kliknięć później… i już wiadomo, że na „znanym portalu aukcyjnym” ofert nie ma, natomiast na innym (bardziej międzynarodowym) portalu aukcyjnym pojawiają się nieliczne oferty w granicach 50$ + przesyłka.
Robi się kosztownie, zwłaszcza że oferowane są przedmioty używane z wytartymi klawiszami w nieznanym stanie.
To może pilot uniwersalny? Po pierwsze wcześniej nie miałem do czynienia z tymi urządzeniami i wcale nie byłem pewien, czy obecnie wyprodukowany pilot poradzi sobie z amplitunerem sprzed ponad 30 lat, po drugie stylistyka, a po trzecie chyba nie potrzebuję tysiąca funkcji/przycisków, z których nigdy nie skorzystam. To rozwiązanie również odrzuciłem.
Zacząłem się zastanawiać, jak zbudowany był oryginalny pilot i czy nie warto samemu zbudować odpowiednika. Przede wszystkim potrzebowałem informacji, jaki układ scalony sterował pilotem oraz w jakim standardzie nadawał komendy. Znalezienie instrukcji serwisowej również nie jest problemem, a ta jest kopalnią skarbów.
W materiałach dodatkowych załączona jest instrukcja użytkownika z dołączoną instrukcją serwisową (materiały dodatkowe – pozycja a). Zawiera ona m.in. komplet schematów, w tym schemat interesującego mnie pilota RC550, który przedstawiono na rysunku 1. Dokładnie tego się spodziewałem, czyli właściwe jeden układ scalony, do tego kilka elementów i klawiatura matrycowa.
Następny pomysł – kupić sam układ scalony LC7461M8100, dobudować resztę i po kłopocie. Niestety ten pomysł również nie wypalił, ale po kolei. W materiałach dodatkowych znajduje się nota katalogowa (sprzed ponad 20 lat) wspomnianego układu, a dokładnie układu LC7461M (materiały dodatkowe – poz. b). Informuje ona m.in., że układ zawiera pamięć ROM (całe 7 bitów) programowaną na życzenie zamawiającego (w tym wypadku DUAL), przez Sanyo – producenta układu.
Jest to bardzo ważne, ponieważ od zawartości tej pamięci bezpośrednio zależą wysyłane kody, czyli kompatybilność z amplitunerem. Wynika z tego, że musiałbym kupić układ z końcówką oznaczenia „8100” (ten i żaden inny) i okazuje się, że teoretycznie da się znaleźć takie oferty. Nie będę już analizował, dlaczego i ta opcja odpadła. Ostatecznie zdecydowałem, że na podstawie tej dość obszernej noty katalogowej zbuduję bezpośredni zamiennik układu scalonego, a za pomocą schematu z instrukcji serwisowej amplitunera odtworzę resztę brakującego pilota RC-550.
Układ LC7461M - omówienie
Właściwie jeszcze przed decyzją o samodzielnej budowie zamiennika układu scalonego sterującego pilotem nastąpiła krótka analiza jego podstawowych parametrów. Najważniejsze w tym przypadku to zakres napięć zasilających (1,8–3,6V) i oczywiście pobór prądu w stanie czuwania (mniej niż 1uA). Nota podaje również, że w stanie aktywnym (ale bez obciążenia wyjścia) układ pobiera mniej niż 1 mA. Na rysunku 2 mamy schemat blokowy.
Do obsługi klawiatury matrycowej pilota służy 8 wyjść (Ko0 – Ko7) i 4 wejścia (Ki0–Ki3), każde z rezystorem podciągającym do masy, pilot może mieć 8×4 = 32 przyciski. Wyjście oznaczone „OUT” steruje zewnętrznym tranzystorem, który załącza diodę nadawczą podczerwieni, wydajność prądowa wyjścia typowo 8mA – 25mA, zależnie od napięcia zasilającego. Na tej nóżce wyprowadzony jest sygnał prostokątny 38kHz, modulowany danymi.
Wejścia C0–C5 pozwalają producentowi wybrać „adres” urządzenia, z którym będzie współpracował pilot. Stan wejść jest wysyłany jako część ramki sterującej. Od strony sprzętowej całość nie wygląda bardzo wymagająco. Rysunek 3 pokazuje dane, które układ scalony nadaje po wciśnięciu przycisku. Bity prezentowane są w kolejności, w jakiej są wysyłane, rysunek należy czytać od lewej. Ramka składa się z trzynastobitowego pola Custom code wysyłanego w postaci prostej i zanegowanej, czyli 2×13 bitów.
Następnie przesyłane jest ośmiobitowe pole Key Data również w postaci prostej i zanegowanej, czyli w sumie długość ramki wynosi 26 + 16 = 42 bity danych. Custom code jest częścią stałą ramki, identyfikuje urządzenie; 6 z 13 bitów tego pola (Pin-selectable) jest bezpośrednim odzwierciedleniem stanu wejść C0–C5, pozostałe 7 bitów Mask ROM jest programowana specjalnie dla odbiorcy układu scalonego. Zawartość Mask ROM, na którą reaguje mój amplituner, ustaliłem eksperymentalnie lub, jak kto woli, wykonałem atak brute force.
Nota mówi jedynie, że Sanyo kontroluje kody, aby zapobiegać powtórzeniom. Key Data to po prostu kod aktualnie wciśniętego klawisza. Przyciski włączone są tak, że wciśnięcie zwiera odpowiednią kolumnę (Ko0– Ko7) z wierszem (Ki0–Ki3), jak to przedstawiono na rysunku 3. Przyciskom przypisano kody wg załączonego rysunku – podano je dziesiętnie.
Skanowanie klawiatury odbywa się standardowo. W tym wypadku układ podaje stan wysoki na wybraną kolumnę, przykładowo na Ko0, pozostałe wyjścia są w stanie wysokiej impedancji. Gdyby wciśnięty był przycisk nr 2, wtedy na wejściu Ki2 odczytany zostałby stan wysoki, a na pozostałych stan niski wywołany wewnętrznymi rezystorami ściągającymi do masy o wartości ok. 100kΩ.
Następnie wybierana jest kolejna kolumna. Mamy 32 przyciski, więc ich stan można zapisać na 5 bitach (D0–D4), a wysyłanych jest osiem. Bity D6 oraz D7 słowa Key Data pozostają niewykorzystane (są ustawione na stałe przez producenta, tutaj zawsze 0). Wciśnięcie więcej niż jednego przycisku (tzw. Multi-press) sygnalizowane jest na bicie D5, ale sytuacja taka dozwolona jest wyłącznie w przypadku jednoczesnego naciśnięcia klawisza nr 20 oraz jednego z trzech pozostałych w kolumnie Ko5.
Szczegóły w dokumentacji. Wiadomo już, co jest wysyłane, a rysunek 4, który również pochodzi z noty katalogowej, będzie bardzo pomocny w zrozumieniu jak. Zachęcam do samodzielnej analizy. Podam tutaj tylko kilka kluczowych informacji. Częstotliwość nośna podczerwieni wynosi 38kHz, wypełnienie impulsów to ok. 33% (dioda IR włączona na 8,77μs, następnie 17,53μs wyłączona).
Odstęp pomiędzy początkami ramek wynosi zawsze 108ms, istotne jest również to, że mamy dwa typy ramek. Zawsze po naciśnięciu przycisku przesyłana jest pełna ramka danych zawierająca opisane wcześniej pola, jeśli przycisk jest przytrzymywany wtedy co 108ms powtarzana jest okrojona ramka sygnalizująca powtórzenie. Każda ramka zaczyna się bitem startu o długości 9ms, po którym następuje 4,5ms przerwa, następnie przesyłane są dane (tylko dla pierwszej ramki), na koniec mamy bit stopu.
Dla ułatwienia podczas pisania programu sterującego przyjąłem za podstawę czas trwania krótkiego „pulsu” podczerwieni T = 562,5us, czyli 2,5us dłuższy niż w specyfikacji. W takim razie logiczne zero trwa 1,125ms, czyli 2×T, puls długości T i tej samej długości przerwa. Nadanie logicznej jedynki trwa 4×T, zaczyna się pulsem o długości T, następnie przerwa 3 x T. Bit stopu kończący ramkę również trwa T. Odstęp pomiędzy początkami ramek to 192×T = 108ms.
Warto zauważyć, że sumaryczny czas trwania ramki jest stały, ponieważ przesyłane są dwa razy te same dane, tj. w postaci prostej i zanegowanej. W moim przypadku czas ten wynosi 84,9375ms = 151 * T (błąd ok. 0,6%). Podsumowując: sposób kodowania jest niezbyt popularnym wariantem protokołu NEC. Mając te informacje, zdecydowałem, że użyję procesora z rodziny STM32L0. Pasowała specyfikacja elektryczna (deklarowany minimalny pobór prądu 0,23uA) i nie bez znaczenia było to, że dysponowałem kitem NUCLEO-L053R8.
Ustalenie zawartości Mask ROM
Używając kitu NUCLEO, szybko „na brudno” napisałem procedurę kodującą ramkę. Młodsze bity pola Custom code ustaliłem za pomocą schematu z rysunku 1 (wartość 0x13), ale nadal brakowało mi 7 bitów pamięci ROM. Możliwości mamy 2^7 = 128, ramki można powtarzać co 108ms, czyli do sprawdzenia w pętli wszystkich kombinacji potrzeba ok. 14 sekund.
Stwierdziłem, że najłatwiej będzie sprawdzić reakcję amplitunera na przycisk POWER, którego kod (ustalony również dzięki rysunkowi 1) równy jest 0x00. Dla pewności diodę nadawczą przykleiłem taśmą malarską bezpośrednio do amplitunera. Po kilku dłuższych chwilach debugowania uzyskałem reakcję urządzenia. Kilka prób ograniczania zakresu pętli i niespodzianka, okazało się, że wartość Mask ROM to 0x01. W tym momencie miałem już wszystkie potrzebne informacje i zacząłem eksperymentować z przesyłaniem innych komend.
Mój zamiennik LC7461M8100
Po udanych eksperymentach z zestawem NUCLEO zdecydowałem się na mikrokontroler STM32L011K4T6 w obudowie LQFP32. Po namyśle stwierdziłem, że wykorzystam schemat oryginalnego pilota z rysunku 1. Niepotrzebne będą elementy oscylatora: X1, C1, C2. Dioda nadawcza podczerwieni użyta w moim pilocie to TSAL6100, a tranzystor Q1 to BC817-40. Na rysunku 5 przedstawiłem schemat odpowiednika układu IC1.
Jest to adapter dla mikrokontrolera, który łącznie z programem przedstawionym dalej czyni z niego odpowiednik układu scalonego LC7461M8100, kompatybilny na poziomie elektrycznym, funkcjonalnym oraz wyprowadzeń. Nie licząc niepodłączonych wejść C0–C5, których wartość i tak jest niezmienna, więc została zadeklarowana w programie jako stała. Wartości elementów: Ca, Cb – 100nF, Ra – 100Ω, Rb nie lutowano. Port PA2 umożliwia obserwację generowanego sygnału (niemodulowanego). Pozostałe niebieskie groty to podłączenie programatora.
Na marginesie: nie tak rzadkie są sytuacje, kiedy produkcja urządzenia zaprojektowanego kilka czy kilkanaście lat temu staje się problematyczna z powodu niedostępności komponentów. W takim wypadku jedną z możliwości jest dorabianie podobnych protez. Czasem okazuje się, że nowoczesny 32-bitowy mikrokontroler może być tańszy niż leciwy 8-bitowy.
Rysunek 6 pokazuje w bardziej strawnej formie przypisanie wyprowadzeń mikrokontrolera do funkcji, nazwy przycisków oraz ich kody w pilocie RC-550. W swojej wersji zrezygnowałem z montowania przycisków na szarym tle. Wyróżnione są również przyciski STA 6, STA 7 i STA 8, które umożliwiają wspomniany wcześniej Multi-press. Układ jest na tyle prosty, że zdecydowałem się na montaż na płytce uniwersalnej, a sam zamiennik z rysunku 5 został zbudowany na kawałku laminatu wyklejonego taśmą kaptonową. Szczegóły na fotografiach.
Program
Wykorzystałem środowisko System Workbench for STM32, źródła do znalezienia w materiałach dodatkowych (materiały dodatkowe – poz. c). Najlepiej przekompilować samodzielnie. W aplikacji liczy się głównie pobór prądu w stanie czuwania, gdyż okresy aktywności są bardzo krótkie. Oryginalny LC7461 pobiera nie więcej niż 1 uA w stanie standby. Nota katalogowa STM32L011x4 obiecuje, zależnie od trybu uśpienia, nawet 0,23 uA. Mnie udało się osiągnąć 0,42uA. Pomiar wykonany miernikiem Sanwa PC5000a po odłączeniu programatora (konieczne jest zresetowanie mikrokontrolera).
Działanie programu jest bardzo proste. Po konfiguracji przygotowuje on mikrokontroler do stanu STOP i do niego przechodzi. Naciśnięcie dowolnego przycisku wygeneruje event EXTI i wybudzi mikrokontroler, następnie startowane są przerwania SysTick co 562us, mikrokontroler przechodzi do stanu SLEEP, budząc się na każde przerwanie SysTick i znów wchodząc w stan SLEEP.
W przerwaniu odbywa się skanowanie klawiatury oraz nadawanie komendy do amplitunera, a w pętli głównej kodowanie ramki, przechodzenie do stanu SLEEP lub STOP. Ponowne przejście w stan STOP nastąpi po 0,5-sekundowej bezczynności. Kod starałem się komentować w języku angielskim. Poniżej pokrótce omówię kwestie charakterystyczne dla aplikacji. Zaskoczył mnie fakt, że mikrokontroler nie zawsze przechodził w stan STOP. Rozwiązaniem jest poniższa sekwencja:
__SEV(); //sztucznie ustaw event
__WFE(); //ta instrukcja spowoduje wyłącznie skasowanie eventów
__WFE(); //mamy pewność, że ta instrukcja przejdzie do stanu STOP, ponieważ eventy są skasowane
Opuszczenie stanu STOP następuje po wygenerowaniu eventu – kontroler EXTI jest ustawiony, aby generował eventy na narastające zbocze na liniach PB3-PB6 (odpowiednio Ki0-Ki3), konieczne jest aby wybudzenie następowało w przypadku naciśnięcia dowolnego przycisku. W tym celu jedną z ostatnich rzeczy, jakie robi mikrokontroler przed przejściem w stan STOP, jest ustawienie wszystkich linii kolumn (Ko0–Ko7) w stan wysoki.
Miałem problem z błędnym odczytywaniem kodów klawiszy w przypadku jednoczesnego naciśnięcia kilku. Olśnienie przyszło po paru minutach. Kolumny są wyjściami, więc pracowały w trybie PUSH-PULL, aktywna kolumna była w stanie 1, wszystkie pozostałe wystawiały 0. Błąd! One powinny „wisieć w powietrzu” i nie przeszkadzać, czyli być w stanie wysokiej impedancji, poza tym to wynika ze schematu blokowego z rysunku 2. Rozwiązanie i tu jest bardzo proste:
LL_GPIO_SetPinOutputType(GPIOA, PIN_Ko0toKo7_ALL, LL_GPIO_OUTPUT_OPENDRAIN);
LL_GPIO_SetPinOutputType(GPIOA, PIN_Ko_0 << (KeyScanCtr >> 2), LL_GPIO_OUTPUT_PUSHPULL);
Do rejestru wyjściowego wpisane są same jedynki. Przestawienie wyjść w tryb pracy OPENDRAIN spowoduje uzyskanie wysokiej impedancji, w tym trybie możliwe jest wyłącznie ściąganie do masy. Wybrana kolumna pracuje w trybie PUSH-PULL, wystawiając stan wysoki. Przy okazji warto wspomnieć, że aby naciśnięcie zostało zaliczone, stan stabilny musi trwać dwa kolejne skanowania czyli 9ms (tzw. key debouncing). Po 90ms przygotowywana jest już do nadania informacja, że przycisk jest przytrzymywany.
Programowanie. Nóżka odpowiedzialna za wybór pamięci programu „PB9-BOOT0” pozostaje niepodłączona, dlatego podczas programowania pamięci konieczne jest poprawne ustawienie bitów konfiguracyjnych. W tym celu należy wykorzystać program STM32CubeProgrammer. Rysunek 7 przedstawia odpowiednie ustawienie.
Montaż i uruchomienie pilota zdalnego sterowania
Jak wspomniałem, z uwagi na prostotę oraz „jednorazowość” układ zmontowałem na płytce uniwersalnej – fotografia 1. Mikrokontroler, również ze względu na raster wyprowadzeń, umieściłem oddzielnie. Komentarza wymaga obudowa, czyli to, czego tygryski nie lubią najbardziej. Od zawsze miałem problem z częścią mechaniczną, co jest chyba typowe dla każdego hobbysty. Zwykle kiedy elektronika była już uruchomiona, urządzenie kończyło w mało estetycznej „gotowej” obudowie.
Nie było to wielkim problemem dla urządzeń niewymagających interakcji z użytkownikiem (np. bez płyty czołowej). Tym razem było inaczej. Wiedziałem, że nie chcę, aby układ skończył w czarnej „pilotopodobnej” plastikowej obudowie. To założenie udało mi się spełnić. Co do jego estetyki, to już kwestia gustu, więc ocenę pozostawiam Czytelnikowi. Rezultat widać na fotografii tytułowej.
Część obudowy stanowi „U” wygięte z aluminiowej blachy, podstawę wykonałem z laminatu. Opisy to ręczna robota cienkopisem. Cienka pleksi przykrywająca aluminiowy wierzch zabezpiecza napisy przed ścieraniem. Liczba oraz rozmieszczenie przycisków są inne niż w oryginalnym RC-550. Te najczęściej wykorzystywane wyeksponowałem, zrezygnowałem z sześciu przycisków do zdalnego sterowania magnetofonem (którego nie mam). Poza tym nie jestem fanem pilotów z olbrzymią liczbą przycisków – zwykle i tak używa się tylko kilku. Widać to dobrze po wytarciach na pilotach hotelowych odbiorników TV.
Przedstawiony pilot pracuje bez zarzutu codziennie od ponad pięciu miesięcy bez wymiany baterii.