Autor: tmf
Redakcja: Dondu
W wielu procesorach AVR piny wykorzystywane do programowania procesora przez interfejs ISP (ang. In-System Programming) pokrywają się z pinami wykorzystywanymi do realizacji sprzętowego interfejsu SPI (ang. Serial Peripheral Interface ). Nic zresztą dziwnego, skoro oba interfejsy mają bardzo podobną budowę.
W obu przypadkach wykorzystywane są linie:
- MISO (ang Master Input Slave Output),
- MOSI (ang. Master Output Slave Input),
- SCK (ang. Serial Clock) oraz
- SS (ang. Slave Select) – w przypadku ISP rolę pinu SS pełni pin RESET procesora.
Ponieważ ATMEL zazwyczaj stosuje te same nazwy pinów do obu interfejsów, jest to czasami źródłem poważnych pomyłek.
Dla przykładu ATMega128 posiada piny interfejsu SPI wyprowadzone na portach PB0-PB3 (dla obudowy TQFP64), natomiast piny interfejsu SPI nazywają się tu nietypowo – PDI (ang. Serial Data In), PDO (ang. Serial Data Out) i SCK, a wyprowadzone są na portach PE0, PE1 i PB1.
Wiele osób już to przyprawiło o zawrót głowy, a posty dotyczące problemów z programowaniem ATMega128 nie są rzadkością. Podobna niespodzianka może nas spotkać w przypadku procesora ATMega64 i paru innych.
Także pamiętajmy, aby zawsze dokładnie czytać noty katalogowe, a szczególnie sekcję Memory programming/SPI Serial Programming Pin Mapping.
Ale nie o tego typu problemach będzie ten artykuł.
Jak pisałem, większość procesorów AVR ma wspólnie wyprowadzone interfejsy SPI oraz ISP. Zastanówmy się, jakie to może mieć konsekwencje w sytuacji, kiedy wykorzystywane są oba interfejsy, co ilustruje poniższy schemat:
Jak widać, transceiver RFM22 został podłączony do procesora poprzez interfejs SPI. Te same piny są też wykorzystywane do programowania procesora poprzez interfejs ISP (złącze AVR ISP).
Ponieważ SPI umożliwa podłączenie dowolnej ilości urządzeń do jednej magistrali, więc wszystko powinno być ok. Jednak, jeśli ktoś zdecydowałby się na zrealizowanie układu według powyższego schematu (skądinąd całkowicie poprawnego) przeżyłby nieciekawe rozczarowanie – próba programowania procesora skończy się niepowodzeniem.
Jak to możliwe, skoro schemat jest poprawny i wszystko powinno być ok?
Ano schemat jest poprawny, ale nie do końca :-)
Jak na wstępie pisałem, rolę pinu SS, którego niski stan wybiera układ slave podłączony do magistrali SPI dla procesora (a więc w trybie ISP) pełni pin RESET. Procesor w tym układzie działa więc w dwojakiej roli – z jednej strony jest układem Master SPI w stosunku do transceivera RFM22, z drugiej strony, jest układem Slave SPI dla programatora ISP.
Ponieważ do wyboru tego ostatniego trybu pracy wykorzystywany jest pin RESET, zastanówmy się jakie są konsekwencje wprowadzenia go w stan aktywny (niski)?
Dosyć oczywistą konsekwencją jest zresetowanie procesora. Równie oczywistą konsekwencją, o której jednak często się zapomina, jest wprowadzenie wszystkich pinów IO procesora w stan wysokiej imedancji (HiZ) – piny w takim stanie nie są ani wejściami, ani wyjściami, zachowują się tak, jakby ich w ogóle nie było.
Ta ostatnia konsekwencja jest źródłem problemów. Aby interfejs SPI układu RFM22 pozostawał nieaktywny (jego pin SDO był w stanie HiZ) pin NSEL musi być w stanie wysokim (Hi). Niemniej, w czasie, kiedy sygnał RESET procesora jest aktywny, sterujący modułem RFM22 pin SS jest w stanie HiZ, a więc ani w stanie wysokim, ani niskim – mówimy, że potencjał takiego pinu pływa (ang. Floating).
W efekcie interfejs SPI układu RFM22 czasami jest odblokowany (pin SDO jest wyjściem), a czasami zablokowany (SDO jest w stanie HiZ). Efektem tego jest interferencja z pinem MISO programatora ISP – kiedy RFM22 podczas programowania jest odblokowany mamy konflikt, gdyż do jednego pinu MISO procesora mamy jednocześnie podłączone dwa aktywne wyjścia – z programatora i z układu RFM22.
Sytuacja taka uniemożliwia programowanie!
Z drugiej strony – przy odłączonym programatorze ISP, albo nieaktywnym sygnale RESET, komunikacja procesor-RFM22 będzie przebiegać prawidłowo.
Jak rozwiązać ten problem?
Otóż rozwiązania są co najmniej dwa.
Pierwsze, nie zawsze możliwe do realizacji, to zaprogramowanie procesora przed wlutowaniem modułu RFM22. Oczywiście po wlutowaniu modułu, dalsze programowanie ISP będzie niemożliwe. W sytuacji, kiedy mamy gotowy firmware, rozwiązanie takie jest sensowne.
Pewnym rozwinięciem tej koncepcji jest wgranie na tym etapie bootloadera i zaprogramowanie fusebitów. Fusebity rzadko się przestawia, a więc po ich jednorazowym ustawieniu najprawdopodobniej nie zajdzie potrzeba ponownego wykorzystania trybu ISP. Z kolei wgrany bootloader umożliwi aktualizację firmware po przylutowaniu modułu RFM22 z wykorzystaniem dowolnego innego kanału komunikacji.
Drugie rozwiązanie jest według mnie, pod wieloma względami, bardziej eleganckie. Jego wadą jest jednak konieczność modyfikacji schematu. Skoro źródłem problemów jest „pływający” potencjał pinu NSEL w czasie, kiedy sygnał RESET jest aktywny, to rozwiązaniem jest ustalenie tego potencjału. Zrealizować to można bardzo prosto przy pomocy dodatkowego rezystora polaryzującego linię NSEL, co ilustruje poniższy schemat:
Dodatkowy rezystor R1 powoduje, że w sytuacji, kiedy linia NSEL jest niewysterowana (pin SS procesora jest w stanie HiZ), rezystor ten utrzyma ją w stanie wysokim – blokując w ten sposób interfejs SPI modułu RFM22. Programowanie z wykorzystaniem ISP znowu stanie się możliwe.
Podsumowanie
Pokazane powyżej uwagi można uogólnić na każdą sytuację, w której wykorzystywany jest interfejs SPI. W sytuacji, kiedy mamy kilka urządzeń SPI slave, każdą linię SS wykorzystywaną do ich aktywacji należy podciągnąć do stanu wysokiego przy pomocy osobnego rezystora.
Jednak jak każde, także to rozwiązanie ma wady. Oczywistą wadą jest konieczność użycia dodatkowego elementu, a przede wszystkim zajęcie przez niego cennego miejsca na płytce.
Mniej oczywista wadą jest związany z tym wzrost poboru prądu. W sytuacji, kiedy pin SS jest w stanie niskim, przez rezystor R1 płynie prąd równy Vcc/R1, w naszym przypadku 0,33 mA. Niby niewiele, lecz w układach, gdzie pobór prądu jest istotny (np. zasilanych z baterii) jest to strata bardzo bolesna. Oczywiście i ten problem można rozwiązać, ale to już całkiem inna historia :-)
Zobacz także:
Ale nie o tego typu problemach będzie ten artykuł.
Jak pisałem, większość procesorów AVR ma wspólnie wyprowadzone interfejsy SPI oraz ISP. Zastanówmy się, jakie to może mieć konsekwencje w sytuacji, kiedy wykorzystywane są oba interfejsy, co ilustruje poniższy schemat:
Jak widać, transceiver RFM22 został podłączony do procesora poprzez interfejs SPI. Te same piny są też wykorzystywane do programowania procesora poprzez interfejs ISP (złącze AVR ISP).
Ponieważ SPI umożliwa podłączenie dowolnej ilości urządzeń do jednej magistrali, więc wszystko powinno być ok. Jednak, jeśli ktoś zdecydowałby się na zrealizowanie układu według powyższego schematu (skądinąd całkowicie poprawnego) przeżyłby nieciekawe rozczarowanie – próba programowania procesora skończy się niepowodzeniem.
Jak to możliwe, skoro schemat jest poprawny i wszystko powinno być ok?
Ano schemat jest poprawny, ale nie do końca :-)
Jak na wstępie pisałem, rolę pinu SS, którego niski stan wybiera układ slave podłączony do magistrali SPI dla procesora (a więc w trybie ISP) pełni pin RESET. Procesor w tym układzie działa więc w dwojakiej roli – z jednej strony jest układem Master SPI w stosunku do transceivera RFM22, z drugiej strony, jest układem Slave SPI dla programatora ISP.
Ponieważ do wyboru tego ostatniego trybu pracy wykorzystywany jest pin RESET, zastanówmy się jakie są konsekwencje wprowadzenia go w stan aktywny (niski)?
Dosyć oczywistą konsekwencją jest zresetowanie procesora. Równie oczywistą konsekwencją, o której jednak często się zapomina, jest wprowadzenie wszystkich pinów IO procesora w stan wysokiej imedancji (HiZ) – piny w takim stanie nie są ani wejściami, ani wyjściami, zachowują się tak, jakby ich w ogóle nie było.
Ta ostatnia konsekwencja jest źródłem problemów. Aby interfejs SPI układu RFM22 pozostawał nieaktywny (jego pin SDO był w stanie HiZ) pin NSEL musi być w stanie wysokim (Hi). Niemniej, w czasie, kiedy sygnał RESET procesora jest aktywny, sterujący modułem RFM22 pin SS jest w stanie HiZ, a więc ani w stanie wysokim, ani niskim – mówimy, że potencjał takiego pinu pływa (ang. Floating).
W efekcie interfejs SPI układu RFM22 czasami jest odblokowany (pin SDO jest wyjściem), a czasami zablokowany (SDO jest w stanie HiZ). Efektem tego jest interferencja z pinem MISO programatora ISP – kiedy RFM22 podczas programowania jest odblokowany mamy konflikt, gdyż do jednego pinu MISO procesora mamy jednocześnie podłączone dwa aktywne wyjścia – z programatora i z układu RFM22.
Sytuacja taka uniemożliwia programowanie!
Z drugiej strony – przy odłączonym programatorze ISP, albo nieaktywnym sygnale RESET, komunikacja procesor-RFM22 będzie przebiegać prawidłowo.
Jak rozwiązać ten problem?
Otóż rozwiązania są co najmniej dwa.
Pierwsze, nie zawsze możliwe do realizacji, to zaprogramowanie procesora przed wlutowaniem modułu RFM22. Oczywiście po wlutowaniu modułu, dalsze programowanie ISP będzie niemożliwe. W sytuacji, kiedy mamy gotowy firmware, rozwiązanie takie jest sensowne.
Pewnym rozwinięciem tej koncepcji jest wgranie na tym etapie bootloadera i zaprogramowanie fusebitów. Fusebity rzadko się przestawia, a więc po ich jednorazowym ustawieniu najprawdopodobniej nie zajdzie potrzeba ponownego wykorzystania trybu ISP. Z kolei wgrany bootloader umożliwi aktualizację firmware po przylutowaniu modułu RFM22 z wykorzystaniem dowolnego innego kanału komunikacji.
Drugie rozwiązanie jest według mnie, pod wieloma względami, bardziej eleganckie. Jego wadą jest jednak konieczność modyfikacji schematu. Skoro źródłem problemów jest „pływający” potencjał pinu NSEL w czasie, kiedy sygnał RESET jest aktywny, to rozwiązaniem jest ustalenie tego potencjału. Zrealizować to można bardzo prosto przy pomocy dodatkowego rezystora polaryzującego linię NSEL, co ilustruje poniższy schemat:
Dodatkowy rezystor R1 powoduje, że w sytuacji, kiedy linia NSEL jest niewysterowana (pin SS procesora jest w stanie HiZ), rezystor ten utrzyma ją w stanie wysokim – blokując w ten sposób interfejs SPI modułu RFM22. Programowanie z wykorzystaniem ISP znowu stanie się możliwe.
Podsumowanie
Pokazane powyżej uwagi można uogólnić na każdą sytuację, w której wykorzystywany jest interfejs SPI. W sytuacji, kiedy mamy kilka urządzeń SPI slave, każdą linię SS wykorzystywaną do ich aktywacji należy podciągnąć do stanu wysokiego przy pomocy osobnego rezystora.
Jednak jak każde, także to rozwiązanie ma wady. Oczywistą wadą jest konieczność użycia dodatkowego elementu, a przede wszystkim zajęcie przez niego cennego miejsca na płytce.
Mniej oczywista wadą jest związany z tym wzrost poboru prądu. W sytuacji, kiedy pin SS jest w stanie niskim, przez rezystor R1 płynie prąd równy Vcc/R1, w naszym przypadku 0,33 mA. Niby niewiele, lecz w układach, gdzie pobór prądu jest istotny (np. zasilanych z baterii) jest to strata bardzo bolesna. Oczywiście i ten problem można rozwiązać, ale to już całkiem inna historia :-)
Zobacz także:
Autor: tmf
Redakcja: Dondu
Świetny artykuł! Prosta rzecz, a jak bardzo istotna!
OdpowiedzUsuńBardzo ciekawy artykuł. Bardzo jestem ciekawy i proszę o informację (chociażby link), w jaki sposób można wyeliminować ew. zredukować problem poboru prądu, związany z zastosowaniem dodatkowego rezystora podciągającego przy linii SS mikrokontrolera (w urządzeniach zasilanych bateryjnie)?
OdpowiedzUsuńNa temat redukcji poboru prądu zrobimy myślę jakiś artykuł. Ale na szybko można zrobić oddzielną linię Vcc sterowaną np. P-MOSFET, z której te pull upy będą brały prąd. W trakcie normalnej pracy tranzystor odłącza zasilanie i takie rezystory są zupełnie transparentne. Prostsza możliwość to oczywiście zwiększenie wartości takiego rezystora, 100k, 470k też są ok, oczywiście ta ewentualność nie sprawdza się jeśli takich pull upów mamy wiele, efektywna rezystancja wtedy wyniesie 1/n*R, czyli dla 10 pull upów po 100k każdy już mamy tylko 10k, czyli tracimy 3V3/10k=330uA, czyli więcej niż pobiera cały procesor.
OdpowiedzUsuńWitam,
OdpowiedzUsuńmam problem z ISP. Tak mi sie wydaje. Otóż aby zaprogramować mikrokontroler muszę wyjąć go z płytki prototypowej.Tak jakbym miał wyłączone ISP (można w ogole je wyłączyć?). Może przez pomyłkę ustawiłem jakis bit w FUSE bitach (może SPIEN? Jak właściwie powinien byc ustawiony ten bit?). Zaznaczam, że nie używam magistrali SPI, nie mam również nic podłączone do pinów MISO, MOSI, SCK, RESET.
Pozdrawiam
Nie, ISP nie da sie zablokowac przy pomocy interfejsu ISP. Skoro programowanie dziala po wyciagnieciu procesora to znaczy, ze ISP dziala (no bo jak inaczej by sie programowalo), czyli problem lezy w ukladzie.
OdpowiedzUsuńWitam!
OdpowiedzUsuńSzukam po necie ale jakoś nie mogę sobie tego wszystkiego złożyć w całość. Mianowicie: czy USART to jest to samo co SPI, I2C, TWI. Tzn. czy USART też jest standardem magistrali szeregowej? Chodzi mi o to, że nie potrafię sobie tego posegregować w głowie co jest czym. Czy te wszystkie ww. standardy można wrzucić do jednego worka magistrali(interfejsów) szeregowej? USB 2.0 wykorzystuje USART tak? A RS232 też?
Pomożcie bo na prawdę juz mnie to irytuje, że nie wiem co jest czym.
Pozdrawiam
Tak to wszystko są magistrale szeregowe.
OdpowiedzUsuńAle różne.
Z wyjątkiem I2C i TWI- to jest to samo.
W książce Pana Dolińskiego widziałem przełączanie lini ISP/SPI za pomocą układu 4053. Nie stosowałem, ale rozwiązanie wygląda na ciekawe.
OdpowiedzUsuńOwszem, można przełączać sygnały ukłądem 4053, ale IMHO to trochę bez sensu. 4053 to przełącznik analogowy, skoro przełączamy sygnały cyfrowe to prościej wykorzystać zwykły multiplekser.
OdpowiedzUsuńPytanie co do 1. schematu.
OdpowiedzUsuńLinie miso, mosi, sck układu RMF oraz avr isp są zwarte i w tym problem, bo nie będzie działać programowanie procesora. A co jeśli zrealizuje to inny sposób:
1. podłącze do goldpinów miso, mosi oraz sck z CPU.
2. podłącze do kolejnego zestawu goldpinów miso, mosi, sck z układu RMF
3. podłącze to samo do kolejnego zestawu goldpinów z złącza KANDA.
Teraz jak będę chciał zaprogramować układ atmega to przełącze po prostu jumpera na goldpiny avr-isp i cpu, a jak będę chciał korzystać z układu RMF i spi to przełącze jumpera na goldpiny cpu i układu rmf?
Co o tym sądzicie, jest to dobry sposób na ominięcie takich niespodzianek?
Owszem, ale po co, skoro problem rozwiązuje jden rezystor?
OdpowiedzUsuńJak wygląda sprawa tego wyświetlacza:
OdpowiedzUsuńhttp://www.superkranz.de/christian/S65_Display/pics/circuit_orig.jpg ?
Jeśli podłącze sprzętowe spi z atmegi do tego lcd'ka oraz sprzętowe spi do programatora? Czy wystąpi kolizja podczas przesyłania danych? W sumie to wyświetlacz też korzysta z reset'u.
Owszem, korzysta z RESET, ale to nie jest ten sam sygnał RESET co RESET procesora. Dopóki będzie w czasie programowania CS w stanie wysokim żadnego konfliktu nie będzie.
OdpowiedzUsuńCzy aby nie wkradł się błąd:
OdpowiedzUsuń"Dla przykładu ATMega128 posiada piny interfejsu SPI wyprowadzone na portach PB0-PB3 (dla obudowy TQFP64), natomiast piny interfejsu SPI(winno być ISP) nazywają się tu nietypowo – PDI (ang. Serial Data In), PDO (ang. Serial Data Out) i SCK, a wyprowadzone są na portach PE0, PE1 i PB1.
???
Od dawna nurtowało mnie takie pytanie:
OdpowiedzUsuńJeśli mam kilka mikroprocesorów komunikujących się wzajemnie za pomocą SPI (np. Mega8 master i kilka takich samych slave) to jak wtedy mogę efektywnie programować je przez ISP? Oczywiście chodzi mi o jakieś bardziej wyszukane rozwiązania niż każdorazowe przełączanie przewodów magistrali. Zastanawiałem się nad jakimś sensownym rozmieszczeniem zworek, ale nie mam pojęcia jak.
Są na to różne sposoby - najprościej jest przełączać sygnał SCK - dostarczać go tylko do procesora, który ma wejść w tryb SPI - oczywiście pozostałe muszą być w stanie resetu. Są też inne możliwości. Ale najogólniej w takiej sytuacji lepiej przejść na procesory z JTAG, który umożliwia konfigurację daisy chain - wtedy nie trzeba kombinować.
UsuńMam trzy Atmegi8 wymieniające dane poprzez SPI. Jeden mikrokontroler (nazwijmy go M0) pełni rolę mastera i pobiera dane od pozostałych dwóch mikrokontrolerów (nazwijmy je S1 i S2), które są identyczne (ten sam program, takie samo podłączenie i ta sama odległość od mastera - połączenie na płytce stykowej przewodami o długości około 8 cm). A jednak z S1 komunikacja przebiega poprawnie, a z S2 nie. Znalazłem rozwiązanie problemu. Okazało się, że S2 jest taktowany zegarem 1MHz podczas gdy M0 i S1 są taktowane zegarem 8MHz. Przestawienie S2 na 8MHz eliminuje problem. Jednak i tak zastanawia mnie to, czemu komunikacja z S2 nie działa poprawnie, ponieważ od początku ustawiłem SCK na Fosc/128 (SPR0 = 1 oraz SPR1 = 1), więc wszystko powinno działać dobrze, ponieważ 8MHz/128 < 1MHz/4. Więc czemu nie działa?
OdpowiedzUsuńNajlepiej przenieść dyskusję na forum elektrody, bo problem może być złożony. Na podstawie przedstawionych informacji obstawiałbym, że slave taktowany 1 MHz się po prostu nie wyrabia z przygotowaniem danych w odpowiedzi na żądanie mastera. Trzeba pamiętać, że MCU musi mieć czas na uzupełnienie i odczyt SPDR.
UsuńWłaśnie tutaj dotarłem poszukując rozwiązania mojego problemu z Atmegą 128 i SPI.
OdpowiedzUsuńWydaje mi się, że u góry tego tekstu, w zdaniu: "Dla przykładu ATMega128 posiada piny interfejsu SPI" zamiast "SPI" powinno być "ISP".