Zegary i Arduino

Genezą tego tekstu była wątpliwość mojego znajomego dotycząca częstotliwości pracy zegara kupionego przez niego klona Arduino UNO. Na płytce zauważył wielki oscylator opisany jako 12.000 – w oryginalnych UNO znalazł podobny, ale z napisem 16.000. Czy zatem jego kontroler (w odróżnieniu do oryginałów) chodzi tylko na 12MHz?!

Czy to jest zegar Arduino?
Na elemencie pisze 12.000; czy to jest zegar klona Arduino UNO R3?

Nie. Kwarc na który kolega się zapatrzył… nie ma nic wspólnego z głównym procesorem (kontrolerem, jak zwał). Jego rolą jest taktowanie czipu CH340G sterującego wysyłaniem danych do portu USB. Przyjrzymy się temu problemowi na kilka sposobów, odpowiadając na pytania:

  • Jak może być taktowany Arduino?
  • Co to są fuse-bity? Jakie są ich domyślne ustawienia? Jak je zmienić?
  • Czy możemy zobaczyć pracę zegara?

Sprzęt laboratoryjny

W tym tekście użyłem:

  • Arduino UNO R3 – klon z CH340 i 12MHz kwarcem
  • Arduino UNO R3 – oryginał z ATMega16U2 i 16MHz kwarcem
  • Siglent 1100CML – oscyloskop cyfrowy (sondy pasywne)
  • Programator USBasp2

Fusy

Nasze rozważania warto rozpocząć od spojrzenia na tzw. fuse bity. Są to wyspecjalizowane komórki pamięci, które służą do przechowywania pewnych ustawień kontrolera. Normalnie nie musicie się o nie martwić – producent ustawia ich wartości na domyślne. Co więcej: jeżeli nie jesteście pewni, lepiej w nich nie grzebać.

Pewne ustawienia fuse-bitów mogą wyłączyć możliwość programowania Arduino

Dostęp do nich jest możliwy przez port szeregowy i Arduino IDE (programowanie poprzez kabel USB i plik konfiguracji platform) – ja jednak wolę używać do tego  programatora ICSP – USBasp2.
W świecie fusów wartość „1” oznacza, że dany bit nie jest zaprogramowany (ustawiony). Wartość „0” – że jest zaprogramowany (czyli dana funkcja jest wybrana). Liczą się właściwe trzy fusy a ich wartości domyślne wyglądają tak:

Arduino UNO R3 Arduino Mega2650
Niski (low) 0xFF 0xFF
Wysoki (high) 0xDE 0xD8
Rozszerzony (extended) 0x05 0xFD

Możecie je odczytać podłączając programator ICSP do Arduino.

Arduino UNO i programator ICSP USBasp2
Arduino UNO i programator ICSP USBasp2

Żeby wyświetlić ustawienia fusów otwórzcie linię poleceń i wpiszcie:

$ cd "C:\Program Files (x86)\Arduino\"
$ hardware\tools\avr\bin\avrdude -C "c:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf" -c usbasp -v -p m328p
...
avrdude: safemode: lfuse reads as FF
avrdude: safemode: hfuse reads as DE
avrdude: safemode: efuse reads as 5

W rozważanym przez nas przypadku zajmiemy się tylko fuse’em odpowiedzialnym za ustawienia zegara. Ustawienia te znajdziecie w „niskim” fuse (ang. low-fuse) pod 4-ma bitami 3..0 (CKSEL3, CKSEL2, CKSEL1, CKSEL0).

 Low-fuse, Arduino 328p
Bit 7 6 5 4 3 2 1 0
Nazwa CKDIV8 CKOUT SUT1 SUT0 CKSEL3 CKSEL2 CKSEL1 CKSEL0
Opis Ustawiony: dzielenie zegara przez 8 Ustawiony:  wyprowadzenie sygnału zegara na pin 2 Ustawiony:  opóźnienie startu czipa w celu ustabilizowania zegara Źródło zegara
Domyślnie dla Uno/Mega (0xFF) 1 1 1 1 1 1 1 1
Modyfikacja na potrzeby eksperymentu: 0xBF 1 0 1 1 1 1 1 1

Dla AtMega328P domyślna wartość wynosi „0xFF” („0b11111111”). Zmodyfikujemy ją tak, żeby sygnał zegarowy został wyprowadzony na pin CLK0 aka PB0 aka 8. Umożliwi nam to obserwowanie jego zachowania na oscyloskopie.

Pytanie: dlaczego nie można podłączyć się oscyloskopem bezpośrednio do oscylatora ?
Odpowiedź: można, ale potrzebne są do tego sondy FET – o bardzo niskiej pojemności. Kosztują setki złotych za sztukę. Zwykłe sondy pasywne mogą tak zakłócić pomiar, że stanie się niemiarodajny. Łatwiej wyprowadzić sygnał na jeden z pinów.

Przyjrzyjmy się teraz szczegółom niskiego fusa.

CKDIV8 dzielnik zegara (ang. clock divide)

Ustawienie tego bitu sprawia, że sygnał zegara wewnętrznego jest dzielony przez 8. Czyli nawet jak sobie 16 MHz ustawicie, w rzeczywistości układ bedzie działał jedynie z na 2MHz. Ale za to zużyje wiele mniej prądu:) To jest domyślne ustawienie fabryczne na wielu czipach.

CKOUT: wyjście zegara (ang. clock output)

Ustawienie tego bitu sprawia, że sygnał zegarowy pojawi się na porcie PORTD3 Arduino. Jest to właściwość którą wykorzystamy do sprawdzenia częstotliwości z jaką chpdzi nasze Arduino

SUT: opóźnienie czasu startu (ang. start-up delay)

Do poprawnego działania, oscylator potrzebuje stabilnego napięcia. Przy włączaniu układu do zasilania, jakiś czas upływa, zanim to napięcie się ustali. Może to powodować niedokładności w działaniu oscylatora. Bity SUT pozwalają na opóźnienie czasu startu układu aż do momentu ustabilizowania się pracy oscylatorów.

CKSEL: źródło zegara (ang. clock source)

Element Znaczenie
Zegar zewnętrzny (ang. external clock) Oznacza zewnętrzny czip dostarczający sygnał zegarowy. Nie używajcie tego ustawienia (chyba że dokładnie wiecie, co robicie)
Rezonator wewnętrzny (ang. internal clock) Oznacza wewnętrzny oscylator, który znajduje się w środku czipu. Nie jest zbyt dokładny (częstotliwość może trochę zmieniać się wraz z np. grzaniem się układu), ale w wiekszości wypadków wystarczający.
AtMega ma wbudowane 2 wewnętrzne oscylatory:

  • 128kHz (oscylator RC): CKSEL3..CKSEL0: 0011
  • Skalibrowany (RC): CKSEL3..CKSEL0: 0010

Używanie czipu np. z częstotliwości 128kHz pozwala na znacznie obniżenie poboru mocy.

Zewnętrzny oscylator (ang. external crystal) Gdy potrzebujecie zegara o dużej stabilności (lub specyficznym takcie), używa się do tego zewnętrznych oscylatorów krystalicznych lub rezonatorów ceramicznych. Są to dodatkowe elementy, które trzeba dolutować na płytce z kontrolerem

Szczegóły ustawień CKSEL:

Ustawienie CKSEL3 CKSEL2 CKSEL1 CKSEL0 Komentarz
Zegar zewnętrzny (External Clock) 0 0 0 0 Nie używaj, chyba że wiesz co robisz
Wewnętrzne
Wewnętrzny 128kHz 0 0 1 1
Wewnętrzny ~8MHz 0 0 1 0
Zewnętrzny oscylator niskiej mocy (podłączony do XTAL1-INPUT i XTAL2-OUTPUT)
Zewnętrzny oscylator niskiej mocy 0.4-0.9 MHz 1 0 0 1
Zewnętrzny oscylator niskiej mocy 0.9-3.0 MHz 1 0 1 1
Zewnętrzny oscylator niskiej mocy 3-8 MHz 1 1 0 1
Zewnętrzny oscylator niskiej mocy 8-16 MHz 1 1 1 1  Domyślne dla Arduino
Zewnętrzny oscylator (full-swing)
0.4-20MHz 0 1 1 1
Zewnętrzny oscylator niskiej częstotliwości
SUT: 1k CK 0 1 0 1
SUT: 32k CK 0 1 0 0

Widać stąd, że wartość low-fuse kontrolera wskazuje na wykorzystanie zewnętrznego oscylatora o częstotliwości 8-16MHz podłaczonego do pinów XTAL1 i XTAL2. Więcej o odczytywaniu fusów z kontrolera znajdziecie tutaj

Modyfikacja low-fuse

Uwaga: nieumiejętne wykonanie niektórych z poniższych instrukcji może doprowadzić do zablokowania procesora; robicie to na własną odpowiedzialność

Skoro już tyle wiemy, czas przerutować sygnał zegara na pin 8. Podłączyłem Arduino do programatora, uruchomiłem linię komend (Win8.1) i:

$ cd "C:\Program Files (x86)\Arduino\"
$ hardware\tools\avr\bin\avrdude -C "c:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf" -c usbasp -v -p m328p -U lfuse:w:0xBF:m

i sprawdzenie:
$ hardware\tools\avr\bin\avrdude -C "hardware\tools\avr\etc\avrdude.conf" -c usbasp -v -p m328p
avrdude: Version 6.0.1, compiled on Jan 15 2015 at 16:58:43
Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
Copyright (c) 2007-2009 Joerg Wunsch
...
Reading | ################################################## | 100% 0.02s
avrdude: verifying ...
avrdude: 1 bytes of lfuse verified
avrdude: safemode: lfuse reads as BF
avrdude: safemode: hfuse reads as DE
avrdude: safemode: efuse reads as 5
...
avrdude done. Thank you.

Czas na oscyloskop. Najpierw mała kompensacja sondy:

Ta sonda musi być skompensowana
Ta sonda musi być skompensowana

Teraz OK:
lead_compensation_1
Podłączamy uziemienie sondy do GND a bagnet do portu 8. Klon UNO (12 MHz na dużym kwarcu):

Mierzymy klona UNO
Mierzymy klona UNO

I bardziej oryginalne Arduino (16MHz na dużym kwarcu):

Oryginalne Arduino - mierzenie zegara
Oryginalne Arduino – mierzenie zegara

Oto co uzyskałem na ekranie oscyloskopu – w przypadku obydwóch R3 – było prawie takie samo (minimalne odchylenia przebiegów):

16MHz zegara na klonie Arduino
16MHz zegara na klonie Arduino

Więc jednak: czysty zegar o częstotliwości 16MHz.

A tak nawiasem mówiąc:

  • Po ustawieniu CKDIV8 i CKOUT (low fuse 3F):

    Zegar klona Arduino ustawinego na divider (2MHz) - wyjście dużo stabilniejsze niż 16MHz
    Zegar klona Arduino ustawinego na divider (2MHz) – wyjście dużo stabilniejsze niż 16MHz
  • Mierzone przez podłączone do gniazd GND-8 kabelki męsko-męskie (daje do myślenia):

    Zegar Arduino - mierzony przez kabelki męsko-męskie
    Zegar Arduino – mierzony przez kabelki męsko-męskie

Widać stąd, że na płytce musi znajdować się jeszcze jeden rezonator. I tak właśnie jest – polecam sprawdzić, dokąd prowadzą nóżki XTAL1 i XTAL2 głównego scalaka:)

CH340G a AtMega16u2

Grzebiąc dalej, dokumentacja do chipu CH340 specyfikuje, że układ ten wymaga zegara 12MHz na wejści FCLK (patrz. 6.3). Z „oryginalną” AtMega16U2 jest podobnie jak w przypadku głównego AtMega328p. Tu również mamy do czynienia z fusami. Sprawdziłem to w tym wpisie. lfuse miał tam wartość 0xFF – czyli podobnie jak układ główny zewnętrzy zegar 8-16MHz.

Pozdrawiam

Źródła

Domyślne ustawienia fusów
Datasheet Atmel 328P
Kalkulator fusuf
Ustawienia domyślne dla Arduino
dokumentacja do chipu CH340
dokumentacja do chipu AtMega16u2
Tutaj…
Tutaj…
Tutaj…
Tutaj…

3 myśli w temacie “Zegary i Arduino”

  1. Jestem raczkującym fanem platformy arduino… i takie obszerne wyjaśnienie FUSów to dla mnie nie lada rarytas w sieci zważywszy na ilość śmieci i partacko napisanych artykułów 😉 DZIĘKI.

    Próbowałem znaleźć Twojego maila i napisać na priva 😉 ale nie znalazłem…
    W każdym razie w zdaniu „Używanie czipu np. z częstotliwości 128MHz pozwala na znacznie obniżenie poboru mocy.” Powinno być chyba 128kHz 😉

    Zaczynam się dopiero wczytywać w Twojego bloga i mam nadzieję, że nie obniżasz lotów i będą się pojawiały nowe artykuły 😉 Zapisuję sobie RSSa 😉

Dodaj komentarz