CH341 to popularny interfejs USB, który umożliwia komunikację z urządzeniami SPI, I²C, UART oraz bezpośrednią kontrolę pinów GPIO. Dzięki temu modułowi można np. programować pamięci Flash, czy odczytywać dane z różnych czujników. Tutaj pokażę, jak można go samodzielnie obsłużyć z poziomu kodu w C#. Wykorzystamy gotową bibliotekę CH341DLL, dostarczoną przez producenta, aby przeprowadzić zarówno operacje SPI, jak i podstawową obsługę GPIO.
Nawiązanie komunikacji
Zacznijmy od całkowitych podstaw. Do zaimportowania funkcji z biblioteki DLL w C# służy DllImport. Musimy podać sygnaturę funkcji, sposób jej wywołania oraz jej argumenty. Informacje o tym możemy znaleźć w dokumentacji albo w nagłówkach dostarczonych przez producenta DLL (np. w plikach .h). Przykładowo, jeśli chcemy otworzyć urządzenie CH341 i uzyskać jego uchwyt, możemy zadeklarować funkcję CH341OpenDevice w C# tak:
Kod: C#
W tym przykładzie CH341OpenDevice zwraca wskaźnik (IntPtr) do otwartego urządzenia, który następnie wykorzystujemy przy dalszych wywołaniach funkcji, np. do wysyłania i odbierania danych SPI. Po zakończeniu pracy wywołujemy CH341CloseDevice, aby zwolnić zasoby.
Przetestujmy to:
Kod: C#
Wszystko działa, -1 oznacza niepowodzenie. Na zrzucie ekranu podłączyłem konwerter do komputera w trakcie działania programu:
Obsługa GPIO
Teraz pójdziemy o krok dalej. Mając otwarty CH341 można już wykonywać proste operacje.
Zacznijmy od GPIO. Pozwala to sterować wybranymi pinami jako wejście/wyjście. Deklaracja przykładowych funkcji:
Kod: C#
- iIndex – numer urządzenia (jeżeli podłączonych jest kilka CH341).
- iEnable – włączenie/wyłączenie sterowania GPIO (1 = aktywne, 0 = nieaktywne).
- iSetDirOut – ustawienie kierunku pinów (1 = wyjście, 0 = wejście) dla poszczególnych linii GPIO (wartość bitowa, np. 0b00001111 dla 4 pierwszych pinów jako wyjścia).
- iSetDataOut – ustawienie stanu logicznego pinów wyjściowych (wartość bitowa, np. 0b00000101 ustawi pierwszy i trzeci pin w stan wysoki).
Można również odczytywać stan pinów GPIO przy użyciu funkcji:
Kod: C#
Można to wykorzystać np. do resetowania zewnętrznego MCU. W tym przypadku użyłem do tego pinu D2:
Nie jest on wyprowadzony na mojej płytce, więc do niego dolutowałem przewód:
Animacja przedstawia resetowany w kółko mikrokontroler:
Obsługa SPI
Teraz można przejść do właściwej części tematu, czyli SPI. CH341 obsługuje różne tryby SPI. W C# możemy zadeklarować funkcję do ustawienia parametrów SPI:
Kod: C#
Funkcja CH341SetStream służy do konfiguracji trybu pracy urządzenia. Parametr iMode określa m.in. kolejność bitów (MSB/LSB), szybkość zegara SPI, ilość pinów SPI
Funkcja CH341StreamSPI4 umożliwia wysyłanie i odbieranie danych w trybie SPI. Parametry mają znaczenie następujące:
- iIndex – numer urządzenia CH341 (jeżeli podłączonych jest kilka)
- iChipSelect – numer linii CS (chip select) używanej do wybranego urządzenia SPI
- iLength – liczba bajtów do przesłania
- oBuffer – wskaźnik do bufora danych, który zostanie przesłany lub do którego zostaną zapisane odebrane dane
Przykład 1: Odczyt ID pamięci
Do programatora podłączyłem kość pamięci Flash z interfejsem SPI. Takie są na płytach głównych z różnych urządzeń, telewizorów, laptopów, itd.
Kod: C#
Komenda 0x9F wysłana przez SPI odczytuje identyfikator pamięci - określenie producenta oraz rozmiar. W tym przypadku pamięć zwróciła 00-0B-40-16
Można to potwierdzić w narzędziu takim jak NeoProgrammer.
Przykład 2: Odczyt zawartości pamięci
W podobny sposób można wysłać komendę 0x03 - odczyt danych. Poniżej przykład takiego odczytu w pętli:
Kod: C#
Działa:
Kolejne operacje - rejestr stanu, kasowanie, zapis...
Tu można by się rozpisywać i kolejno tłumaczyć osobne operacje, ale... ja to w zasadzie już zrobiłem - z poziomu MCU komendy są takie same. Zapraszam zatem do tematu:
Dodatkowa pamięć Flash na pomiary za darmo? Protokół komunikacji, zapis, odczyt, kasowanie
Podsumowanie
CH341 okazuje się być potężniejszy niż myślałem. Mamy tu zasadniczo pełen dostęp - SPI i GPIO, można w oparciu o nie tworzyć zaawansowane mechanizmy i obsługiwać różne układy, w tym czujniki i wyświetlacze. Być może wkrótce coś więcej na ten temat pokażę.
Czy próbowaliście w podobny sposób sterować układem CH341?
PS: Materiały źródłowe:
https://github.com/command-tab/ch341eeprom/blob/master/ch341docs/CH341DLL.H
EDIT link do YTEC-info usunięty - materiały dałem do załączników po ich sprawdzeniu
Załączam mój eksperymentalny kod w C# - w zasadzie tam jest odczyt i niekompletny zapis pamięci Flash z dodatkowym wprowadzeniem układu Beken w tryb Flash. Może komuś sie przyda.
Fajne? Ranking DIY Pomogłem? Kup mi kawę.