sobota, 30 stycznia 2021

CAP1296 - sterownik dotyku od Microchipa i pierwsze uruchomienie na najnowszym PIC18F47Q84.


Sterownik CAP1296 umożliwia w prosty sposób zrealizowanie dotykowego interfejsu sterującego w naszych projektach. Do dyspozycji mamy 6 kanałów. Sterownik umożliwia dostep do takich funkcjonalności jak Press and Hold , Power Button, Proximity, Multiple Button Pattern Detection .Rozmowa ze sterownikiem odbywa się za pomocą interfejsu I2C , dostępna jest prędkość 400 kHz. Sterownik pracuje w ekosystemie napięciowym 3.3V oraz 5V. Obudowa jaką ja wybrałem do testów tego sterownika to SOIC14.

Sterowanie dotykowe chciałem zaaplikować do swojego kosmicznego zegarka jaki mam w zamiarze skonstruować. Aby zegarek nie był nudny postanowiłem wyposażyć go w technologie rzadziej lub wcale nie spotykane w zegarkach. Ponieważ z dotykiem nie miałem dotychczas w swoich projektach do czynienia dlatego postanowiłem najpierw przetestować tą technologię w wydaniu Microchipa. Jako platformę testową wykorzystałem standard Mikroelektroniki i wykonałem w tym standardzie płytkę testową . Płytkę wepniemy w gniazdo mikroBUS dowolnej płytki wykonanej w tym standardzie. W przypadku moich płytek to praktycznie 100%. W gniazdo to bardzo często wyposażone są również płytki developerskie Microchipa. Zrobiona przezemnie płytka prezentuje się jak poniżej :



Na płytce mamy dwa "Touch-e" i dwie diody LED do współpracy z nimi. Płytka jest malutka , filigranowa , piękna w swojej prostocie. Do testów jej wykorzystam moją uniwersalną platformę dla MCU 8-bitowych obsadzoną jakimś nowym i ciekawym MCU PIC18.

Jakiś taki ostatnio mam sentyment do 8-bitów :)

MCU na jakim będę uruchamiał moduł dotyku to jeden z najnowszych MCU 8-bitowych Microchipa PIC18F47Q84 MCU ten wyróżnia się z tłumu tym, że na pokładzie ma CAN-FD , który możemy w bardzo prosty sposób skonfigurować do pracy za pomocą wtyczki MCC. Trzeba przyznać , że te nowe konstrukcje 8-bitowe Microchipa są coraz bardziej ciekawe. Podsumujmy zatem zabawki jakimi będę się posługiwał w piaskownicy przy pierwszym uruchomieniu mojego modułu dotykowego :

- płytka bazowa dla MCU 8-bit Microchipa. Mojej konstrukcji rzecz jasna. 

PIC18F47Q84 w obudowie DIP40

- programator MPLAB SNAP

- moduł dotyku z CAP1296

- analizator stanów logicznych

Komplet prezentuje się jak na zdjęciu poniżej :

Warstwa programowa to narzędzia Microchipa :

- MPLABX IDE + doinstalowana wtyczka MCC.

- kompilator XC8

Dokumentacja : 

- datasheet CAP1296

Schemat elektryczny modułu dotykowego :

Na podstawie schematów modułu i płytki bazowej dla MCU ustalam przyporządkowanie pinów :

Moduł - Płytka bazowa MCU

Alert --> RB0 / INT0

SCL --> RC3

SDA --> RC4

LED1 -> RC1

LED2 -> RC0

Zabawę zaczynam od stworzenia nowego projektu w MPLABX IDE i konfiguracji zasobów MCU do współpracy z modułem dotyku. Tutaj pokażę jak skonfigurowałem poszczególne piny w MPLABX IDE i MCC.. 

Na marginesie mała dygresja, pisząc ten artykuł nie wiem co mnie czeka u celu tej podróży bo moduł dotyku uruchamiam pierwszy raz. i na obecnym etapie nie wiem jaki będzie efekt końcowy tego :)

Odpalam MPLABX IDE , tworzę nowy projekt np. pic18f47q84_CAP1296 i przechodzę od razu do MCC.

Ustawiam zegar :

Dodaję moduł przerwań zewnętrznych  EXT-INT, wykorzystam jedno z trzech dostępnych przerwań w MCU do współpracy z wyjściem Alert modułu dotykowego. Na przerwaniu INT0 podczepiony jest pin RB0 czyli tak jak potrzebuję. Moduł EXT-INT dodajemy z okienka Device Resources , po kliknięciu plusika moduł przeniesiony zostanie automatycznie w przestrzeń okna Project Resources.


Przerwanie INT0 będzie reagowało na zbocze opadające. Na razie podejrzewam, że CAP1296 na opadającym zboczu sygnalizuje zdarzenia , potem doczytam w datasheet czy tak jest :).
Dezaktywuję przerwania INT1 i INT2 bo nie korzystam. W tym celu przełączam się na zakładkę Registers w okienku EXT-INT i odznaczam odpowiednie "ptaszki".


Ustawiam piny RC1 i RC0 do współpracy z LED-ami znajdującymi się na module dotykowym czyli LED1 - RC1 i LED2 - RC0. W tym celu :
- zamykam kłódki dla RC1 i RC0 w wierszu output,
- przełączam widok na Pin Module,
- odznaczam ptaszki w kolumnie Analog,
- nadaję pinom przyjazną nazwę LED1 i LED2 w kolumnie Custom Name

powyższe czynności wykonane na obrazku poniżej :



Dodaję moduł I2C do projektu bo w tym standardzie będziemy "rozmawiać" z CAP1296. SCL pojawi nam się na pinie RC3 a SDA na pinie RC4. Po dodaniu modułu I2C nic nie musimy w nim ustawiać, no prościej już się nie da. Efekt widoczny na obrazku poniżej :


Ostatnie spojrzenie na konfigurację pinów :


Zabawę z konfiguracją sprzętowej warstwy MCU za pomocą wtyczki MCC mamy za sobą. Szybko łatwo i bardzo przyjemnie. No ale mózg nam nie zapracował i to jest wada :).

Generujemy ustawienia za pomocą zakładki Generate , znajdziemy ją w górnym lewym okienku Projects Resources. Zamykamy MCC "klikając" jeden raz w ikonkę MCC na górnej belce narzędziowej. Przełączamy się na widok Projects. Kompilujemy projekt. Struktura naszego projektu z otwartym plikiem main.c widoczna na obrazku poniżej :


Nic jeszcze nie napisaliśmy kodu a tutaj już tyle kodu wskoczyło do naszego projektu :). Wśród tego kodu znajdziemy m.in gotową biblioteczkę od Microchipa do osbługi I2C. Przyznam tutaj, że zawsze sam rzeźbiłem swoją obsługę I2C i nie korzystałem z biblioteki Microchipa. Czas iść z postępem i korzystać z gotowych narzędzi :)

Teraz jest dobry moment aby zajrzeć do datasheet CAP1296 i zerknąć na spis rejestrów bo na pewno jakieś musi mieć :). Na stronie 23 znajdujemy początek tabelki ze spisem rejestrów i przyporządkowanym im wartością HEX. Na podstawie tej tabelki tworzymy sobie w programie plik nagłówkowy o nazwie np.cap1296.h i do niego pakujemy definicje rejestrów z datasheet-a..


U mnie to wygląda jak poniżej :


7-bitowy adres CAP1296 potrzebny do komunikacji po I2C, również bez problemu wykontycypujemy na podstawie danych z dokumentacji (0101 000).Jak dotąd żadnej filozofii nie ma. Mając definicje rejestrów wewnętrznych  CAP1296, możemy przystąpić do dumania nad funkcjami do odczytu rejestrów i zapisu. Takie dwie podstawowe funkcje musimy mieć aby porozmawiać na konkretne tematy z CAP1296. Już miałem się brać do pisania takich funkcji ale zauważyłem , że w bibliotece Microchipa do obsługi I2C, która została nam do projektu dołączona automatycznie, są funkcje uniwersalne do rozmowy z rejestrami urządzeń w formacie 8 bitów i 16 bitów. Chciałoby się powiedzieć rewelacja no ale znowu mózg nie zapracuje :). Funkcje o których mowa znalazłem tutaj :


Zanim przyjrzę się funkcją Microchipa do rozmowy po I2C z naszym CAP1296. Najpierw zerknijmy jak wygląda proces komunikacji. Bardzo ładnie jest to opisane w datasheet CAP1296 od strony 12 :


Aby sprawdzić czy komunikujemy się prawidłowo z CAP1296 musimy użyć analizatora stanów logicznych i upewnić się , że np w procesie odczytu jakiegoś rejestru (wybierzemy sobie jakiś ale o tym później) ) otrzymujemy sygnał ACK po wysłaniu adresu urządzenia . A co to jest ten sygnał ACK ? to jest fizycznie stan niski wystawiony na magistralę I2C przez urządzenie Slave (CAP1296) na zboczu narastającym zegara SCL dla 9 bitu (7-bitów leci adres urządzenia + 1 bit w/r potem 9-bit na którym musimy otrzymać ACK). Poprzednie zdanie będzie nieprawdziwe w przypadku urządzeń o adresie 10 bitowym bo takie też są w naszej galaktyce.

Przystępuję do pierwszych testów. Procedura testowa polegać będzie na odczycie rejestru o nazwie  Product ID. Adres rejestru odczytany z tabelki z datasheet to 0xFD ,spodziewana wartość jaką odczytamy to 0x69 (patrz tabelka str 26 datasheet CAP1296). Funkcja odczytująca to uniwersalna funkcja z biblioteki I2C Microchipa. Mój kod testowy wygląda jak poniżej i jest prosty jak świński ogon :


Dioda LED jaką odpalam po każdym zapytaniu wysłanym do CAP1296 to dioda LED1 z mojego modułu dotyku. Jeśli dioda mi zamiga to znaczy, że nic się nie blokuje i z grubsza jest wszystko oki. Program wgrany do MCU i dioda LED  miga . Wstępnie mogę podejrzewać, że funkcja Microchipa do odczytu rejestrów coś tam działa  .



Czas podpiąć analizator i zobaczyć przepływ informacji na własne oczy. Efekt na obrazku poniżej :




Analizator pokazuje nam, że transmisja jakaś po I2C idzie ale efekty nie są takie jakich byśmy oczekiwali. Adres jaki przesyłam bitowo to 0b01010000 a na obrazku powyżej widzimy , że jest 0b10100010.
Tak na krzywe  oko coś nam poprzesuwało adres . Szukam podejrzanych za ten stan rzeczy. Pierwszym podejrzanym jest funkcja I2C Microchipa do odczytywania rejestrów no bo za jej pomocą ten adres wysyłałem. W sumie jednak to największym podejrzanym jestem ja bo nie przejrzałem dokładniej biblioteki I2C Microchipa tylko działam na rympał :).

Już wiem, funkcje jakie zaproponował w swojej bibliotece I2C, Microchip a w szczególności funkcje z pliku i2c_example tej biblioteki, nie we wszystkich zastosowaniach się sprawdzą. W moim przypadku się nie sprawdziły. Zatem stając przed wyborem przerabiania funkcji Microchipa a napisania swoich własnych funkcji, wybrałem wariant drugi.

Studjując życie wewnętrzne PIC18F47Q84 a w szczególności moduł sprzętowy I2C. Natknąlem się na niespotykany dotychczas w PIC-ach rejestr do obsługi  I2C Bus Timeout Clock . Ma to zastosowanie w przypadku kiedy transmisja I2C utknie w martwym punkcie np. Slave zdechnie. Aby wyrwać z tego punktu MCU ,mamy do dyspozycji sprzętowego "watchdoga" w module I2C. To jak go obsłużymy zależy tylko od nas. Jest to moim zdaniem bardzo porządana w I2C funkcjonalności , której dotychczas brakowało nie tylko w MCU Microchipa ale i u innych producentów MCU. Brawo Panie Microchip. Gdybym nie zajrzał do rejestrów modułu I2C nie miałbym zielonego pojęcia o takim postępie w "technologii" :).

No dobrze , pogrzebałem sobie trochę w rejestrach I2C (PIC18F47Q84) i zażyłem przygody intelektualnej :). Trochę mi czasu zajęło zrozumienie co "poeta miał na myśli" z nowymi funkcjonalnościami w zakresie realizacji protokołu I2C w PIC18F47Q84 . No ale gdyby wszystko było łatwe , lekkie i przyjemne to szybko by się znudziło :). Teraz od ogółu do szczegółu czyli co chcę zrobić i jak to zrobiłem :). Najpierw rysunek z datasheet CAP1296 przedstawiający format rozmowy po I2C Mastera (MCU) ze Slave'm (CAP1296) w przypadku odczytu zawartości rejestru z CAP1296.


Teraz przetłumaczę pismo obrazkowe na tekst . Aby odczytać zawartość rejestru z CAP1296 musimy kolejno wykonać następujące czynności :

- Master (MCU) wysła sygnał START na "magistralę" I2C ,czyli High na SCL, zmiana z High na Low na linii SDA.
 

- Master wysyła (na linię SDA) bajt - adres Slave'a(CAP1296) (bin: 01010000) / (hex: 0x50) gdzie ostatni bit r/w = 0.
 
- Slave potwierdza odebranie swojego adresu wysyłając na linię SDA w 9 cyklu zegara ACK czyli ustawiając linię SDA w stan niski. Jeśli adres byłby nieprawidłowy to w 9 cyklu zegara SCL będzie stan wysoki zamiast niskiego.

- Master wysyła (na linię SDA) bajt danych reprezentujący adres rejestru w CAP1296, ja przy pierwszym teście komunikacji wysyłam adres 0xFD (Product ID)

 
- Slave potwierdza odebranie  bajtu wysyłając na linię SDA w 9 cyklu zegara ACK czyli ustawiając linię SDA w stan niski. 
 
- Master (MCU) wysła sygnał START na "magistralę" I2C ,czyli High na SCL, LOW na SDA. W szczególności ten moment to RESTART-em .
 
Master wysyła (na linię SDA) bajt - adres Slave'a(CAP1296) (bin: 01010001) / (hex: 0x51) gdzie ostatni bit r/w = 1.
 
- Slave potwierdza odebranie  bajtu wysyłając na linię SDA w 9 cyklu zegara ACK czyli ustawiając linię SDA w stan niski. 
 
 - Slave wysyła bajt danych na linię SDA reprezentujący zawartość adresu rejestru w naszym przypadku ta wartość będzie wynosić 0x69 (patrz datasheet - tabelka z rejestrami CAP1296)

- Master w 9 cyklu zegara SCL wysyła na linię SDA sygnał NACK czyli High na SDA.

- Master (MCU) wysyła sygnał STOP na "magistralę" I2C ,czyli High na SCL, zmiana sygnału z Low na High na  linii SDA.
 
 

I tu kończymy przepis na dialog MCU z CAP1296 po I2C w zakresie odczytania danej z rejestru CAP1296.

Teraz musimy spojrzeć na ten dialog przez pryzmat rejestrów modułu I2C w naszym MCU. Czyli rzeźbimy funkcję, która zrealizuje nam fizycznie nasz dialog.
Jeśli chodzi o konfigurację samego modułu I2C i jej inicjalizację w programie to załatwi za nas kod wygenerowany przez MCC w MPLABX IDE. Czyli jakby połowę roboty mamy za sobą i można się skupić na realizacji naszego dialogu. Funkcje do odczytu i zapisu udało mi się wyrzeźbić przy pomocy samych rejestrów czyli w stylu  Bare Metal :) . I taki styl rozmowy z MCU jest nabliższy mojemu sercu. 

Poniżej efekt odczytu zawartości rejestru o adresie 0xFD (Product ID) oczekiwana wartość to 0x69:


Rozważmy teraz zapis danej do rejestru w CAP1296.


Aby wpisać daną do rejestru z CAP1296 musimy kolejno wykonać następujące czynności :

Master (MCU) wysyła sygnał START na "magistralę" I2C ,czyli High na SCL, zmiana z High na Low na linii SDA.
 

Master wysyła (na linię SDA) bajt - adres Slave'a(CAP1296) (bin: 01010000) / (hex: 0x50) gdzie ostatni bit r/w = 0.
 
Slave potwierdza odebranie swojego adresu wysyłając na linię SDA w 9 cyklu zegara ACK czyli ustawiając linię SDA w stan niski. Jeśli adres byłby nieprawidłowy to w 9 cyklu zegara SCL będzie stan wysoki zamiast niskiego.

Master wysyła (na linię SDA) bajt danych reprezentujący adres rejestru w CAP1296, ja w ramach testu wysyłam adres 0x21 (Sensor Input Enable)

 
- Slave potwierdza odebranie  bajtu wysyłając na linię SDA w 9 cyklu zegara ACK czyli ustawiając linię SDA w stan niski. 
  
-  Master wysyła (na linię SDA) bajt z danymi , który zostanie wpisany w CAP1296 pod adres rejestru (patrz wyżej), ja w ramach testu zapisuję do rejestru o adresie 0x21 wartość 0x03, więc w tym punkcie wysyłamy bajt 0x03.
 
- Slave potwierdza odebranie  bajtu wysyłając na linię SDA w 9 cyklu zegara ACK czyli ustawiając linię SDA w stan niski. 
 
Master (MCU) wysyła sygnał STOP na "magistralę" I2C ,czyli High na SCL, zmiana sygnału z Low na High na  linii SDA.
 
 

I tu kończymy przepis na dialog MCU CAP1296 po I2C w zakresie zapisania danej do rejestru CAP1296.

Poniżej wynik działania zapisu do rejestru o adresie 0x21 ( Sensor Input Enable), wartości 0x03.


Funkcje do rozmowy po I2C z CAP1296 mam gotowe, działają zgodnie z oczekiwaniem co potwierdził mi analizator. Czas zacząć zabawę z rejestrami CAP1296 . Idea (ogólna) działania CAP1296 jest taka, że skanuje on w czasie rzeczywistym pola dotykowe (6 sztuk) i w chwili wykrycia zmiany pojemności na jednym (lub kilku naraz) polu dotykowym, sygnalizuje to podaniem stanu niskiego na wyjście ALERT. Od strony MCU musimy obsłużyć takie zgłoszenie, ja użyłem do tego przerwania INT0. "Obsłużenie" polega na wysłaniu zapytania do CAP1296 , które pole lub pola zostały aktywowane "paluchem" a następnie skasowania flagi przerwania w odpowiednim rejestrze CAP1296. Warto tu nadmienić , że CAP1296 rozpoznaje pojedynczy kontakt z "paluchem" jak i kontakt z "wielopaluchem" czyli możemy sobie rozpoznawać sekwencje. Do tego jak dodamy rozpoznanie długiego kontaktu (z regulowanym czasem) czyli naciśnięcie i przytrzymanie to okazuje się , że CAP1296 jest genialnym małym wynalazkiem , który z powodzeniem zastąpi nam klasyczne przyciski .  W klasycznych przyciskach zmorą są drgania styków , w przypadku dotyku pozbywamy się tej uciążliwości.

No dobrze koniec lania wody zabieramy się za konkrety. Najpierw musimy rozpoznać co jest nam potrzebne do inicjalizacji CAP1296. Ponieważ na mojej płytce używam tylko dwóch pól dotykowych CS1 i CS2 dlatego w konfiguracji muszę  uwzględnić ten aspekt i wyłączyć pozostałe cztery wejścia. Rejestr w którym aktywujemy lub dezaktywujemy poszczególne pola to SENSOR INPUT ENABLE REGISTER :


Adres rejestru to 0x21 wartość domyślna to 0x3F . Ja tutaj chcę zapisać wartość 0x03. Czyli mamy już jeden element potrzebny do konfiguracji. Drugim elementem konfiguracji który chciałbym uwzględnić, to ustawienie czułości. Zrobimy to za pomocą wpisu w rejestr  SENSITIVITY CONTROL REGISTER :


Widzimy, że czułość możemy zmieniać w dosyć sporym zakresie, to niewątpliwie duża zaleta. Standardowo ustawiona wartość czułości to x32, ja to zmienię na x8 . Czyli do rejestru o adresie 0x1F wpisywać będę wartość 0x4F.
Kolejnym elementem konfiguracji będzie coś związane z kalibracją . Widzę , że aspekt kalibracji jest ważny w dotyku dlatego znalazłem odpowiedni rejestr do tego a jest nim  CALIBRATION ACTIVATE AND STATUS REGISTER :

Zapisem do powyższego rejestru wymuszamy procedurę kalibracji na wybranych wejściach , nas interesuje tutaj CS1_CAL i CS2_CAL. Czyli do rejestru o adresie 0x26 wpiszemy wartość 0x03
Jeszcze jeden rejestr nawinął mi się na oczy do konfiguracji , mianowicie  INTERRUPT ENABLE REGISTER :


Tutaj zostawimy aktywne przerwania tylko dla wybranych pinów CS1 i CS2. Zatem do rejestru o adresie 0x27 wpiszemy wartość 0x03.

Na tym chyba zakończę moją pierwszą testową konfigurację CAP1296. Reszta to doktoryzowanie się z rejestrów i zapoznawanie się z różnymi funkcjonalnościami jakie oferuje nam ten niepozorny a mocarny układzik.

Przechodzę zatem do mojego poligonu doświadczalnego, ustawiam kod do konfiguracji CAP1296 i patrzę co się stanie. A jeszcze mała dygresja odnośnie przerwania INT0 w MCU. Przerwanie jak już wspominałem chyba gdzieś wyżej musi reagować na zbocze opadające. Ja do ciała funkcji obsługi przerwania INT0 wygenerowanej automatycznie przez MCC (a w szczególności do funkcji callback) dam sobie ustawienie flagi o nazwie np . intFlag. W pętli głównej programu będę sprawdzał czy flaga ta jest ustawiona, jeśli tak to sprawdzam które pole dotykowe zostało aktywowane jeśli Touch1 to zapalam diodę LED (na mojej płytce z MCU) jeśli Touch2 to gaszę diodę LED.  Na koniec wysyłam do CAP1296 polecenie skasowania flagi przerwania wewnętrznego INT . Flagę INT (w CAP1296) kasujemy w rejestrze o nazwie :
MAIN CONTROL REGISTER :


Kasowanie flagi INT polega na wysłaniu wartości 0 do pola bitowego B0 powyższego rejestru.
 
Jakiego efektu spodziewam się?. Jeśli wszystko będzie w porządku to każde naciśnięcie pola dotykowego Touch1 zapali diodę LEDTouch2 zgasi diodę LED na mojej płytce z MCU. Mój program testowy w pliku main.c wygląda jak poniżej :



a efekt działania programu poniżej na filmiku :



Dotyk działa bardzo pewnie i szybko reaguje na kontakt z palcem po prostu jak na razie działa to rewelacyjnie. Dodatkowo cieszę się, że moje funkcje do obsługi I2C wyrzeźbione na rejestrach  ruszyły i działają pewnie bo miałem z tym na początku mały problemik. No ale nauka bez rozwiązywania problemów to nie nauka.

Podsumowując . Moje pierwsze wrażenia ze sterownikiem dotyku CAP1296 firmy Microchip są bardzo pozytywne. Układ jest prosty w oprogramowaniu,, mamy tutaj duże możliwości konfiguracyjne , rozszerzona funkcjonalność w tym m.in sprzętowa funkcja repeat w reakcji na przytrzymanie pola dotykowego z regulowanym czasem czy wykrywanie sekwencji równoczesnego dotyku kilku pól. .Dokumentacja jest czytelna. Na razie nie widzę wad i z przyjemnością wykorzystam ten sterownik w jakiś najbliższych projektach.
 
Odnośnie MCU z nowej serii PIC18FxxQ84 warto wspomnieć, że występuje on w mniejszych obudowach np. PIC18F27Q84 -  obudowa 28-pin typu SOIC. Generalnie te nowe konstrukcje 8-bitowe  Microchipa są coraz bardziej ciekawe i coraz bardziej wyrafinowane a ich ogromną zaletą w stosunku do ekosystemu 32-bit jest brak narzutu takch tworów jak biblioteki HAL (STM32) czy ASP (ATSAM), które znacząco zamulają sprzęt i które kastrują mikrokontrolery z ich największej zalety jaką jest szybkość działania i wykonywania operacji. Pozatym w/w biblioteki chowają przed nami to co w mikrokontrolerach jest najpiękniejsze czyli ich bogate wnętrze i "duszę" :) .  Howgh !

 
Pozdrawiam

PICmajster
picmajster.blog@gmail.com

 

Linki:

CAP1296

PIC18F47Q84

1 komentarz: