Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi

p.kaczmarek2 04 Nov 2022 21:09 1161 5
  • BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi
    BK7231 zazwyczaj programujemy przez UART - pozwala na to wgrany przez producenta bootloader. W wyjątkowych sytuacjach jednak możemy niechcący ten bootloader nadpisać - wtedy musimy użyć trybu programowania SPI by odratować zablokowany układ. Tutaj opiszę, jak działa tryb SPI w BK7231 oraz przedstawię prosty kod własnego prymitywnego programatora SPI dla Beken. "Programator" będzie napisany w Pythonie i zostanie uruchomiony na Raspberry Pi (no dobra, tutaj na Banana Pi - ale na Raspberry jest bardzo podobnie).

    Interfejs SPI w BK7231
    Rozważmy wyprowadzenia BK7231:
    BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi
    Widzimy piny: SPI_MISO, SPI_CSN, SPI_MOSI, SPI_SCK. Nie jest to wbrew pozorom interfejs zewnętrznej pamięci, tak jak np. w ESP8266, tutaj sam Beken jest pamięcią.
    Beken jest pamięcią SPI i identyfikuje się jako 00 15 70 1C, czyli wygląda na kość podobną do EN25QH16B - i to nota katalogowa EN25QH16B z operacjami odczytu/zapisu może nam tu nieco rozjaśnić sytuację.
    BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi
    Poniżej zapowiedź trzech komend z EN25QH16B których użyjemy.
    Odczyt strony - page read (komenda 0x03):
    BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi
    Usunięcie sektoru - sector erase (komenda 0x20):
    BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi
    Programowanie (zapis danych) do strony - page program (komenda 0x02):
    BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi
    Dodatkowo może przydać się dostęp do rejestru statusu (by sprawdzić, czy np. operacja się wykonała):
    BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi
    Warto podkreślić, że zapis do strony wymaga najpierw jej usunięcia. Erase strony ustawia jej bity na 1, a zapis potrafi 'zgasić' wybrane bity. Zapis nie potrafi tych bitów 'zapalić' - po to jest erase. Co ciekawe, pozwala to na różne kombinacje z oszczędzaniem cykli usunięcia strony flash, ale o tym innym razem..
    W BK jest podobnie - zobaczmy jak.
    Tylko, że najpierw trzeba uruchomić w ogóle tryb SPI...

    Jak wprowadzić BK7231 w tryb SPI?
    Algorytm jest prosty. Poniższy algorytm wykona mój skrypt.
    - inicjujemy SPI w trybie 3 (0b11 mode), częstotliwość 30kHz (szybsze u mnie nie działały)
    - ustawiamy CEN w stan niski
    - czekamy 1 sekundę
    - ustawiamy CEN w stan wysoki
    - wysyłamy 250 razy D2 po SPI
    - oczekujemy odpowiedzi raz D2, potem 249 razy 00
    Od tego momentu Beken jest w trybie SPI. Można to sprawdzić wysyłając zapytanie o ID - 9F 00 00 00. Oczekiwana odpowiedź:
    00 15 70 1C.
    Następnie można operować na pamięci Flash - odczytywać ją bądź do niej zapisywać (zapis poprzedzać musi jej wykasowanie). Zarówno odczyt, jak i zapis odbywa się per-page, czyli po 256 bajtów.
    Format komend zapisu i odczytu jest prosty - najpierw jeden bajt komendy (jak wspominałem - 0x02 zapis strony, 0x03 odczyt, itd) a potem 3 bajty adresu.
    Na czym najprościej to wykonać? Chyba na Raspberry PI. Sam użyłem Banana Pi, bo takie miałem pod ręką.

    Pacjent z tematu
    Oto wspomniany moduł z uszkodzonym bootloaderem - BK7231T na płytce z łatwo dostępnymi sygnałami od SPI.
    BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi
    W ramach uzupełnienia dodam, że na zdjęciu powyżej mamy piny:
    - TX i RX (zwykłe programowanie UART)
    - TX2 i RX2 (log UART)
    - IO0 - to chyba pozostałość po ESP, nie wiem do czego służy
    - RST - nie sprawdzałem do czego służy, ale pewnie to RESET
    - CE (CEN) - to jest ten pin którym ja resetuję BK7231
    - SO, SI, SCK, CSN - interfejs SPI
    - masa i zasilanie 3.3V - wiadomo

    Przygotowanie Banana Pi
    Użyta wersja to dokładnie Banana Pi BPI-M1+, choć mam nadzieję, że nie ma to tutaj znaczenia. Na popularnych Raspberry powinno być dość analogicznie.
    Zacząłem całkiem od 0. Pobrałem Armbiana. Użyta wersja to:
    Armbian_22.08.7_Bananapi_bullseye_current_5.15.74.img
    https://www.armbian.com/banana-pi-plus/
    Wgrałem go na kartę SD poprzez Etchera.
    Od strony hardware, piny SPI wziąłem stąd:
    https://wiki.banana-pi.org/Banana_Pi_BPI-M1%2B#Hardware_interface
    BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi
    BK7231T już jest podłączony:
    BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi
    Do kontroli SPI użyłem spidev (dostepne zarówno na Banana Pi, jak i Raspberry Pi):
    https://pypi.org/project/spidev/
    Dla ułatwienia zastosowałem wirtualne środowisko Pythona. Komendy jak na ekranie, kolejno:
    - python3 -m venv env - komenda tworzy wirtualne środowisko
    - source env/bin/activate - komenda je aktywuje (po restarcie systemu też należy znów je aktywować, a przynajmniej ja musiałem za każdym razem...)
    - python -m pip install spidev - komenda instaluje paczki; na zdjęciu ekranu zawiera jeszcze tqdm i pyserial, ale ostatecznie nie były potrzebne
    Oto instalacja spidev (i nie tylko):
    BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi
    Trzeba było też włączyć SPI. Początkowo myślałem, że starczy zmiana w "armbian-config" (ta komenda wywołuje takie narzędzie):
    BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi
    BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi
    BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi
    Ale nie. Trzeba było dopisać jeszcze w edytorze pliku jeszcze jedną linijkę do /boot/armbianEnv.txt:
    BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi
    Dopisałem param_spidev_spi_bus=0 do /boot/armbianEnv.txt.


    Brakowało też biblioteki GPIO. Musiałem użyć RPi.GPIO_BP jako zamiennik RPi.GPIO dla BananaPi, stąd:
    https://github.com/LeMaker/RPi.GPIO_BP
    Wykonałem kopię repozytorium i chciałem zainstalować zgodnie z instrukcją z repo, ale nie obyło się bez problemów.
    Miałem mnóstwo problemów multiple definition of , błędy linkera.
    Rozwiązaniem było dodanie -fcommon do CFLAGS.
    BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi


    Pisanie programu w Pythonie
    Teraz już pora na właściwe programowanie. Program pisałem na komputerze z Windowsem poprzez klienta FTP - Filezille i edytor tekstu Notepad++. Wszelkie testy, uruchamianie robiłem już na Banana Pi.

    Uruchomienie SPI i GPIO w Pythonie
    Mój program flashera SPI zaczyna się od konfiguracji SPI oraz pinu CEN:
    Code: python
    Log in, to see the code

    Do GPIO użyłem trybu adresowania RAW, gdyż na Banana Pi nie mogłem znaleźć informacji o innych sposobach adresowania pinów. SPI uruchamiam w trybie 3, z częstotliwością 30000, gdyż w przypadku większych częstotliwości nie byłem w stanie odczytać ID pamięci.
    Pora teraz uruchomić tryb SPI w BK...

    Nawiązanie komunikacji w trybie SPI
    Najpierw ustawiamy stan niski na CEN na sekundę:
    Code: python
    Log in, to see the code

    A potem wysyłamy 250 razy bajt 0xD2:
    Code: python
    Log in, to see the code

    Warto jeszcze jakoś zweryfikować, czy aby na pewno tryb SPI został ustawiony, oraz czy nasza wybrana prędkość komunikacji nie jest zbyt duża. Najprościej zrobić to odpytując o ID pamięci Flash, czyli komenda 0x9F 0x00 0x00 0x00:
    Code: python
    Log in, to see the code

    Powyższy kod sprawdza co odebraliśmy - oczekujemy ID 0x00 0x1c 0x70 0x15 i w zależności od tego zwracamy 1 lub 0.
    To pozwoli nam wcześnie wykryć ewentualne problemy z komunikacją.
    Kod można by ulepszyć - w razie niepowodzenia np. próbować ponownie z mniejszą szybkością transferu.
    Zdjęcie przedstawia pierwszy sukces nawiązania komunikacji SPI:
    BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi

    Odczyt pamięci SPI
    Szczegóły odczytu danych można znaleźć albo w dokumentacji pamięci SPI oraz w SDK Tuya.
    Code: python
    Log in, to see the code

    Odczyt pamięci sprowadza się do wysyłania komend 0x03 wraz z odpowiednio zakodowanym adresem. Adres kodowany jest jako 3 bajty, a pierwszym bajtem jest właśnie kod komendy - 0x03. 0x03 to jest odczyt całej strony.
    Przy okazji odczytu zapisuję dane do pliku - zmienna 'f'.


    Zapis do pamięci SPI
    Wcześniej odczytywaliśmy pamięć strona po stronie, teraz jest pora na 'page write'.
    Niestety tu najpierw trzeba będzie też usuwać sektor - czyli potrzebujemy dwóch komend:
    Code: python
    Log in, to see the code

    Pomocnicze funkcje, do oczekiwania na ukończenie operacji oraz do wykonania enable (w pętli while; tego kroku już tak dokładnie nie opisywałem, ale tu też jest analogicznie jak w SPI):
    Code: python
    Log in, to see the code

    Oto pełna funkcja:
    Code: python
    Log in, to see the code

    Tak jak wcześniej - jeden bajt komendy, trzy bajty adresu. Najpierw kasujemy zawartość pamięci, potem do niej zapisujemy.


    Programowanie BK7231 przez SPI
    Mamy już prawie wszystko - wystarczy tego użyć.
    Dzięki temu odzyskamy BK7231 z nadpisanym bootloaderem UART.
    Zasadniczo mamy teraz dwie możliwości.
    1. pełne wgranie OpenBeken - potrzebujemy wsadu w wersji QIO, z bootloaderem. Wersja UA się nie nadaje, gdyż nie zawiera bootloadera i zaczyna się od offsetu 0x11000.
    Code: python
    Log in, to see the code

    2. możemy też przywrócić oryginalny wsad zgrany przez np. bkWriter 1.60, który domyślnie czyta z offsetu 0x11000. W tym celu bierzemy z QIO sam bootloader, a potem wgrywamy oryginalny wsad:
    Code: python
    Log in, to see the code

    Jeśli nasz plik REST.bin zawiera oryginalne oprogramowanie Tuya, to ten zabieg je przywróci na naszym BK7231.

    Gotowy program na Githubie
    Pełny program możecie pobrać na moim repozytorium. Możecie również go usprawnić i otworzyć nowe pull request:
    https://github.com/openshwprojects/BK7231_SPI_Flasher

    Podsumowanie
    Tym prostym programem można przywrócić BK7231 do życia, choć należy pamiętać, że bez wyprowadzonych pinów SPI może być ciężko.
    Moim programem udało mi się przywrócić do życia już dwa BK7231.
    Ktoś mógłby się jeszcze zastanawiać, czemu nie próbowałem użyć niekompletnego kodu Tuya z hid_download_py? Po prostu u mnie nie działał - w teorii wspierać ma on kilka wersji układów Beken, ale moim zdaniem jest zbyt skomplikowany i problematyczny. Wysypywał się jeszcze gdzieś przed SPI, na jakiejś dziwniejszej procedurze resetowania.
    Załączam notę katalogową pamięci Flash na której m. in. bazowałem - może ona wyjaśnić nieco więcej niż temat, warto do niej zajrzeć, każda komenda jest tam dokładniej opisana, tak jak rejestr statusu.

    Cool? Ranking DIY
    Can you write similar article? Send message to me and you will get SD card 64GB.
    About Author
    p.kaczmarek2
    Level 28  
    Offline 
  • #2
    danaia
    Level 2  
    Próbowałem tej metody, aby wskrzesić BK7231T, jak dotąd bez powodzenia. Używam Raspberry Pi Zero, SPI wydaje się działać (przetestowane za pomocą spi_test).
    Przylutowałem przewody do pinów SPI_* na chipie (po prawej stronie schematu). Zauważyłem jednak, że ten przewodnik określa, że mają być użyte szpilki FLASH_* (znajdujące się na górze schematu). Czy możesz określić, które piny mają być użyte? Dziękuję
  • #3
    p.kaczmarek2
    Level 28  
    Witam @danaia, wygląda na to, że masz rację. To musi być błąd edycji. Wszystkie moje deski używane do eksperymentów mają już wyłamane szpilki, więc tego nie weryfikowałem. Powinieneś wypróbować te szpilki:
    BK7231 programowanie przez SPI w trybie pamięci flash - Python i Banana Pi
    Zgłoś tutaj, czy to działa, czy nie.
  • #4
    danaia
    Level 2  
    Zadziałało! Mam płytkę WBLC5, więc mogłem użyć jej dostarczonych padów zamiast lutowania bezpośrednio do chipa.
    Identyfikator urządzenia nie był poprawny przy skonfigurowanym 30000Hz, więc spróbowałem kilku losowych wartości i zakończyłem sukcesem przy 3000Hz.
    Dzięki za przewodnik!
  • #5
    p.kaczmarek2
    Level 28  
    3000 Hz jest bardzo wolne. Zastanawiam się, czy zadziałałoby to dla Ciebie w trybie 20 000 Hz czy coś takiego, ale i tak najważniejsze jest to, że się udało! Dobra robota, cieszę się, że pomogłem.
    Czy jest jeszcze coś, w czym mogę ci pomóc?
  • #6
    danaia
    Level 2  
    Hahah tak, to na pewno nie było szybkie, ale nie chciałem tego przerywać, gdy już się zaczęło :D
    Nie teraz, dzięki :) Większość diod LED działa, więc opublikuję ponownie, jeśli coś pojawi się dalej.