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
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).
(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)
- 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:
...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.
Oznacza to również że przy 16MHz miałby 3MHz, co brzmi fajnie
(mimo że jest równie bezużyteczne
)
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
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 [AVR][C] - Pobieranie próbek z wejścia z częstotliwością 1MHz i więcej](https://obrazki.elektroda.pl/1302357600_1356224893_thumb.jpg)
(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 [AVR][C] - Pobieranie próbek z wejścia z częstotliwością 1MHz i więcej](https://obrazki.elektroda.pl/7978999600_1356227155_thumb.jpg)
- 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
...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 [AVR][C] - Pobieranie próbek z wejścia z częstotliwością 1MHz i więcej](https://obrazki.elektroda.pl/3252235500_1356228706_thumb.jpg)
Oznacza to również że przy 16MHz miałby 3MHz, co brzmi fajnie

