Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[AVR][C] - Pobieranie próbek z wejścia z częstotliwością 1MHz i więcej

szulat 23 Dec 2012 03:40 1008 0
  • #1
    szulat
    Level 23  
    W wątku https://www.elektroda.pl/rtvforum/topic2449239.html padła sugestia że da się wykorzystać SPI dla pobierania próbek z szybkością dużo większą niż to jest możliwe zwykłymi metodami, postanowiłem to sprawdzić - a jako że tamten wątek został już zamknięty, opisuję moje wnioski w nowym wątku, może sie to komuś kiedyś przyda.

    1. SPI może pracować w dwóch trybach - Master i Slave. który z nich będzie przydatny? wydawałoby się że Master, bo jest "samodzielny" ale jednak okazuje sie że Slave, bo generacja sygnału zegara w Masterze wyłącza się po nadaniu bajtu i nawet jeżeli procesor od razu zareaguje i włączy nową transmisję to i tak zegar przez chwilę stoi powodując nierównomierność pobierania danych. Slave natomiast może pracować przy zegarze pracującym bez przerw.

    2. SPI Slave potrzebuje zegara, użyłem do tego timera 0 (OC0A) i trzeba też połączyć SS do masy żeby Slave był cały czas aktywny.

    3. Jaką szybkość można uzyskać? Z dokumentacji wynika że zegar SPI musi pracować wolniej niż 25% zegara procesora (stan wysoki i niski mają trwać więcej niż 2 cykle zegara). Ale tu pojawia się pytanie co robić z nadchodzącymi danymi - nie ma aż tak wiele czasu na ich obróbkę a nawet przekazanie ich dalej jest problematyczne. W oryginalnym wątku dane miały być przekazywane przez UART, którego szybkość też jest ograniczona. Moje próby przeprowadzałem właśnie na UART'cie, atmega88 z wewnętrznym oscylatorem to 8MHz co przekłada się na maksymalną szybkość 1Mbps i maksymalną liczbę jednobitowych próbek na sekundę równą 0,8 miliona (jako że 2 z każdych 10 bitów są zarezerwowane na bity startu i stopu).

    4. Program wygląda tak - oprócz właściwego zadania uruchamiam też drugi timer (timer 1) który jest źródłem sygnału testowego

    Code: c
    Log in, to see the code


    5. Efekty - to działa! I nawet nie trzeba było asemblera. Poniższa ilustracja jest dla częstotliwości próbkowania 0,8MHz, _delay_us(8) pokazuje ile jeszcze pozostaje czasu (czerwony przebieg "synchronizacja", stan wysoki to delay i w tym czasie możnaby ewentualnie robić coś innego).
    [AVR][C] - Pobieranie próbek z wejścia z częstotliwością 1MHz i więcej
    (kliknij w obrazek żeby zobaczyć animację!)

    Dla 1MHz ten sam kod też działa, natomiast powyżej tej wartości program czasem nie nadąża z uruchomieniem nowej transmisji SPI. Tak objawiają się nierównomierności gdy jeszcze nadąża: (obraz w trybie "persistence" zbierający przebiegi przez dłuższy czas)
    [AVR][C] - Pobieranie próbek z wejścia z częstotliwością 1MHz i więcej
    - impulsy "synchronizacji" bywają przesunięte ale utrzymują się w zakresie jednego cyklu.
    A dlaczego nie nadąża - oczywiście każde powtórzenie pętli trochę trwa i jeżeli sprawdzenie wykona się na chwilę przed zakończeniem transmisji to zanim nastąpi powtórne sprawdzenie to mija już za dużo czasu i kolejna transmisja jest inicjowana już po minięciu właściwego zegara, w związku z tym musi czekać na kolejny cykl. Ale można dołożyć "nopy" tak żeby sprawdzenie warunku trafiało zawsze na ten sam dobry moment (albo nawet wyrzucić sprawdzanie warunku jeżeli odpowiednio obliczymy/dobierzemy cykle) i na przykład taki wariant:
    Code: c
    Log in, to see the code

    ...działa na 8MHz procku wykonując próbkowanie 1,5MHz (i wysyłając przez UART co drugi bajt bo oczywiście wszystkich bajtów nie może), ale tu już wkraczamy w obszar zupełnie abstrakcyjny bo bardzo trudno jest wyobrazić sobie zastosowanie dla takiego mechanizmu w którym nawet nie da się wiele zrobić z danymi które tak w pocie czoła zbieramy, więc to tylko tak w ramach badania granic możliwości.
    [AVR][C] - Pobieranie próbek z wejścia z częstotliwością 1MHz i więcej
    Oznacza to również że przy 16MHz miałby 3MHz, co brzmi fajnie :) (mimo że jest równie bezużyteczne :D)