Obsługa sprzętowego mudułu SPI w mikrokontrolerach AVR

Wpis w kategorii [ AVR ]

SPIInterfejs SPI jest szybkim, dupleksowym, synchronicznym interfejsem szeregowym. Jest on stosowany do łączenia układu nadrzędnego (Master), sterującego transmisją z urządzeniami podrzędnymi (Slave). W rozpatrywanym przypadku funkcję nadrzędną pełni mikrokontroler. Urządzeniem podrzędnym może być np. pamięć EEPROM, zegar RTC, wyświetlacz LCD i wiele innych peryferiów wyposażonych w ten interfejs.

Przewagą SPI nad innymi interfejsami szeregowymi stosowanymi w mikrokontrolerach jest jego szybkość oraz prostota. Wadą może się okazać ilość sygnałów, które musimy zastosować do transmisji (co najmniej 3 dla transmisji dupleksowej). Nie jest ich co prawda dużo, ale czasami zbyt wiele.

Opisywana implementacja interfejsu dotyczy wykorzystania sprzętowego modułu SPI dostępnego w mikrokontrolerach AVR (nie we wszystkich). Istnieje możliwość wykorzystania modułu USI (Universal Serial Interface), ale o tym innym razem.

1. Dedykowane rejestry

Rejestr SPCR

SPCR

SPCR

Znaczenie poszczególnych bitów jest następujące:

  • SPIE – aktywacja obsługi przerwań dla modułu SPI,
  • SPE – włączenie modułu SPI,
  • DORD – ustawienie tego bitu oznacza, że jako pierwszy, transmitowany jest najmniej znaczący bit (LSb), natomiast skasowanie tego bitu oznacza transmisję od najbardziej znaczącego bitu (MSb),
  • MSTR – wybór pomiędzy trybem Master (1), a Slave (0). Jeśli pin SS skonfigurowany jest jako wejście i pojawi się na nim stan niski, gdy MSTR ustawiony jest na 1, to MSTR zostanie wyzerowany i ustawiony zostanie znacznik SPIF w rejestrze SPSR. Aby ponownie włączyć tryb master, należy wpisać 1 do MSTR.
  • CPOL – polaryzacja zegara, dokładne wyjaśnienie znajduje się na poniższym rysunku i w tabeli 1,
  • CPHA – faza zegara, uwaga j.w.
  • SPR1, SPR0 – częstotliwość taktowania transmisji. Opis w tabeli 2.
CPHA=0

CPHA=0

CPHA=1

CPHA=1

Tabela 1. Tryby działania modułu SPI.
Tryb SPI CPOL CPHA SCK w czasie oczekiwania SCK w momencie próbkowania
0 0 0 niski zbocze narastające
1 0 1 niski zbocze opadające
2 1 0 wysoki zbocze opadające
3 1 1 wysoki zbocze narastające
Tabela 2. Prędkości transmisji SPI.
SPI2X SPR1 SPR0 Częstotliwość SCK
0 0 0 fosc/4
0 0 1 fosc/16
0 1 0 fosc/64
0 1 1 fosc/128
1 0 0 fosc/2
1 0 1 fosc/8
1 1 0 fosc/32
1 1 1 fosc/64

Rejestr SPSR

SPSR

SPSR

  • SPIF – flaga przerwania od modułu SPI. Ustawiana, gdy transmisja zostanie ukończona.
  • WCOL – flaga kolizji zapisu. Ustawiana, gdy SPDR jest zapisywana podczas transmisji danych,
  • SPI2X – gdy flaga ta jest ustawiona (1), prędkość transmisji SPI w trybie master jest podwojona.

Rejestr SPDR

Jest to rejestr pośredniczący w zapisie i odczycie danych z rejestru przesuwnego modułu SPI. Zapis do tego rejestru rozpoczyna transmisję, natomiast jego odczyt powoduje przepisanie informacji z rejestru przesuwnego.

2. Piny

Poszczególne mikrokontrolery różnią się od siebie rozmieszczeniem wyprowadzeń modułu SPI. Warto więc wprowadzić niezależne nazwy za pomocą dyrektywy define.

#define SPI_HW_PORT PORTB
#define SPI_HW_DIR DDRB
#define SPI_HW_PIN PINB
 
#define SPI_HW_SCK PB5
#define SPI_HW_MISO PB4
#define SPI_HW_MOSI PB3
#define SPI_HW_CS PB2B

3. Tryb nadrzędny (Master)

Włączenie modułu SPI nie powoduje ustawienia pinów MOSI, MISO i SCK w odpowiednim trybie – należy zrobić to ręcznie. MOSI, SCK należy ustawić jako wyjścia, natomiast MISO jako wejście. Pin CS nie jest obsługiwany przez moduł SPI, więc wymaga sterowania ręcznego.

static inline void spi_hw_init(uint8_t conf)
{
	SPI_HW_DIR |= (_BV(SPI_HW_CS) | _BV(SPI_HW_SCK) | _BV(SPI_HW_MOSI));
	SPCR = conf;
}

Następnie włączamy moduł SPI działający w trybie nadrzędnym z częstotliwością SCK zależną od parametru przekazanego funkcji spi_hw_init().

Można jeszcze wyczyścić rejestry poprzez ich odczytanie.

Sterowanie CS

  • ustawienie CS w stanie wysokim
    	SPI_HW_PORT |= _BV(SPI_HW_CS);
  • ustawienie CS w stanie niskim
    	SPI_HW_PORT &= ~(_BV(SPI_HW_CS));

Pozostaje tylko funkcja, która realizuje zapis i jednoczesny odczyt danych

static inline uint8_t spi_hw_data_send(uint8_t data)
{
	SPDR = data;
	while((SPSR & _BV(SPIF)) == 0);
 
	SPSR |= _BV(SPIF);
 
	return SPDR;
}

4. Przykład

Żeby lepiej zrozumieć sposób obsługi sprzętowego modułu SPI przygotowałem program, który zapisuje i odczytuje przykładowe dane z zewnętrznej pamięci EEPROM. Pamięć zastosowana w przykładzie to 25C040 komunikująca się z otoczeniem za pomocą interfejsu SPI.

#include <spi\spi_hw.h>
#include <uart\uart.h>
#include <util\delay.h>
 
#ifndef F_CPU
#define F_CPU 16000000UL // zegar w Hz
#endif
 
#define RS_BAUD 9600
#define RS_UBRR F_CPU / 16 / RS_BAUD - 1
 
int main()
{
	uart_init(RS_UBRR);
 
	uart_puts("ATMega168 SPI test\r\n");
	uart_puts("mikrokontroler.info\r\n");
 
 
	spi_hw_init(_BV(SPE) | _BV(MSTR) | _BV(CPOL) | _BV(CPHA) | _BV(SPR1) | _BV(SPR0));
 
	uart_puts("Zapis... ");
	spi_hw_cs_low();
	spi_hw_data_send(0x06);
	spi_hw_cs_high();
 
	_delay_us(1);
 
	spi_hw_cs_low();
	spi_hw_data_send(0x02);
	spi_hw_data_send(0x00);
 
	spi_hw_data_send('m');
	spi_hw_data_send('i');
	spi_hw_data_send('k');
	spi_hw_data_send('r');
	spi_hw_data_send('o');
	spi_hw_data_send('k');
	spi_hw_data_send('o');
	spi_hw_data_send('n');
	spi_hw_data_send('t');
	spi_hw_data_send('r');
	spi_hw_data_send('o');
	spi_hw_data_send('l');
	spi_hw_data_send('e');
	spi_hw_data_send('r');
	spi_hw_cs_high();
 
	_delay_ms(5);
 
	uart_puts("OK.\r\nOdczyt: ");
	spi_hw_cs_low();
	spi_hw_data_send(0x03);
	spi_hw_data_send(0x00);
 
	for(int i = 0; i < 14; i++)
		uart_putc(spi_hw_data_send(0x00));
 
	spi_hw_cs_high();
}

W przykładzie wykorzystane zostały funkcje obsługujące sprzętowy moduł portu szeregowego RS232.

Moduł SPI uruchamiany jest w trybie Master, wariant 3 (CPOL = 1, CPHA = 1) z częstotliwością SCK równą fosc / 128 czyli 125 kHz. Następnie wysyłana jest instrukcja zezwalająca na zapis WREN (szczegóły w dokumentacji układu 25C040). W kolejnym kroku zapisywane są dane (znaki ASCII tworzące słowo: mikrokontroler). Zapis dokonywany jest po zmianie poziomu CS z niskiego na wyskoki. Według dokumentacji czas zapisu wynosi maksymalnie 5ms i tyle należy odczekać przed rozpoczęciem kolejnych operacji.

Gdy dane są już zapisane, następuje ich odczyt i wysłanie portem szeregowym.

Wynik działania programu przedstawia się następująco:

terminal.jpg" rel="lightbox[roadtrip]">Wynik działania programu SPI test

Wynik działania programu SPI test

5. Podsumowanie

Przedstawiony opis pokazuje jak w prosty sposób uruchomić interfejs SPI w mikrokontrolerach AVR. Poniżej dostępne są pliki zawierające wszystkie powyższe funkcje. Wystarczy dołączyć je do projektu i stosować SPI już od zaraz.

Oceń ten wpis:
1 gwiazdka2 gwiazdki3 gwiazdki4 gwiazdki5 gwiazdek (głosów: 7, średnia ocen: 5,00)
Loading ... Loading ...
Wyświetleń: 9 168
Tagi: [ , , ]

Podobne artykuły

Możesz śledzić komentarze do tego wpisu poprzez kanał RSS 2.0. Możesz także dodać własny komentarz, lub trackback z własnej strony WWW.

Dodaj komentarz