Laboratorul 5: SPI (Serial Peripheral Interface)

1. Introducere

În cadrul acestui laborator, vom aborda protocolul de comunicație SPI, utilizat în lumea embedded pentru transmisia datelor între 2 sau mai multe dispozitive. Scopul nostru final va fi cel de a construi pe plăcuța de laborator un player audio care să citească fișiere .wav de pe un card SD și să le redea utilizând speaker-ul integrat.

2. Protocolul SPI (Serial Peripheral Interface)

SPI este un standard sincron dezvoltat de Motorola. Acesta funcționează în modul full-duplex (transferul de date are loc în ambele direcții simultan).

Dispozitivele comunică utilizând o arhitectură Master-Slave (este permis un singur dispozitiv Master și unul sau mai multe dispozitive Slave). Dispozitivul Master este cel care inițiază comunicarea.

SPI mai este numit și four wire, deoarece în cadrul acestui protocol se transmit semnale pe 4 linii independente. Cele patru semnale utilizate sunt următoarele:

  • MOSI — Master Output Slave Input (transmiterea datelor de la Master la Slave)
  • MISO — Master Input Slave Output (transmiterea datelor de la Slave la Master)
  • SCLK — Serial Clock (sincronizarea dintre dispozitive; controlat de Master)
  • CS / SS — Chip Select / Slave Select (selectarea dispozitivului Slave de către Master; valoarea LOW pentru Slave-ul selectat)

Putem vedea că există două semnale utilizate pentru transmiterea datelor: MOSI și MISO. Transmiterea datelor pe SPI se face sincron, folosind semnalul de ceas SCLK. Semnalul CS / SS este utilizat pentru a selecta dispozitivul Slave cu care dorim să comunicăm la un moment dat.

2.1 Conectarea mai multor dispozitive Slave

Mai multe dispozitive Slave pot fi conectate în același timp la un singur dispozitiv Master. Semnalele MOSI, MISO și SCLK sunt partajate. Pentru fiecare dispozitiv Slave, dispozitivul Master are câte un semnal CS / SS. Când Masterul dorește să comunice cu un Slave, dispozitivul Master setează pe LOW semnalul CS / SS care duce către dispozitivul Slave dorit (celelalte semnale CS / SS sunt puse pe HIGH). Astfel, dispozitivul Slave cu CS / SS pe LOW știe că Master-ul comunică cu el.

3. Transmiterea datelor cu SPI

Pentru a începe comunicarea, dispozitivul Master trebuie să se asigure că ceasul său este setat la o frecvență cel mult egală cu frecvența suportată de dispozitivul Slave (de obicei, până la câțiva MHz). Apoi, Master-ul selectează dispozitivul Slave dorit, punând 0 pe linia CS / SS asociată acestuia.

În timpul unui ciclu SPI, transmisia este full-duplex:

  • Dispozitivul Master trimite un bit pe linia MOSI, iar dispozitivul Slave citește acest bit.
  • Dispozitivul Slave trimite un bit pe linia MISO, iar dispozitivul Master citește acest bit.

În general, comunicarea SPI implică doi regiștrii de shiftare (unul în Master și unul în Slave), conectați circular, la fel ca în figura de mai jos.

De obicei, primul bit mutat pe MISO / MOSI este cel mai semnificativ bit, în timp ce un bit nou este adăugat la poziția cea mai puțin semnificativă din registru. După ce întregul cuvânt a fost trimis, prin shiftare, Master-ul și Slave-ul au schimbat integral valorile din cei doi regiștrii de shiftare. Dacă mai există date de transmis, procesul începe din nou. Când nu mai există date de transmis, dispozitivul Master întrerupe generarea semnalului de ceas (SCLK) și plasează semnalul CS / SS asociat cu Slave-ul pe HIGH (1 logic).

Pe tot parcursul procesului descris mai sus, dispozitivele Slave care nu au fost selectate de semnalul SS asociat vor ignora semnalele de pe SCLK și MOSI și nu vor genera nimic pe MISO. Master-ul poate selecta un singur Slave la un moment dat.

4. SPI în ATMega324

Microcontroller-ul ATMega324 pune la dispoziția utilizatorilor săi și o interfata SPI, aceasta putând funcționa atât ca master cât și ca slave.

Dupa cum ne-am obișnuit, pentru configurarea și utilizarea interfeței vom folosi regiștrii: de control, de stare și de date.

Descrierea completă a regiștrilor asociați interfeței SPI o găsiți în datasheet, capitolul SPI – Serial Peripheral Interface (pagina 214). În continuare, vom face o scurtă trecere în revistă a regiștrilor și a câmpurilor relevante din aceștia.

SPI Control Register (SPCR)

  • SPE - SPI Enable - setat pe 1 pentru activarea interfeței SPI
  • DORD - Data Order - când este, 1 bitul cel mai puțin semnificativ (LSB) de date este transmis primul, invers pentru 0
  • MSTR - Master/Slave Select - când este 1, interfața funcționează în modul Master, când este 0 aceasta funcționează în modul Slave
  • CPOL, CPHA, SPR1, SPR0 - setările pentru linia SCLK

 Registrul SPCR

SPI Status Register (SPSR)

  • SPIF - SPI Interrupt Flag - este pus pe 1 când s-a terminat o transmisie

 Registrul SPSR

SPI Data Register (SPDR)

Acesta este registrul din care citim datele pe care le-am primit / în care scriem datele pe care vrem să le transmitem. Scrierile în acest registru inițiază o nouă transmisie atunci când interfața funcționează în module Master. Datele citite din acestu registru vin din registrul de shiftare.

 Registrul SPDR

5. FAT SD Card

Plăcuța de laborator este dotată cu un cititor de carduri SD care poate comunica cu microprocesorul nostru prin protocolul SPI, acesta fiind și usecase-ul la care vom lucra astăzi.

Figura de mai jos ilustrează modul de conectare al cititorului SD la microprocesor. După cum se poate observa, pentru a seta semnalele descrise în secțiunea 2 a laboratorului, ne putem folosi de o parte din pinii cu care am lucrat și în laboratoarele trecute.  Schemă conectare card SD cu ATmega324

Cardurile SD cu care vom lucra astăzi sunt formatate cu sistemul de fișiere FAT32. Pentru a ușura lucrul cu acest sistem de fișiere, ne vom baza pe biblioteca Petit FAT Filesystem, atât datorită dimensiunii mici (2-4KB), cât și faptului că folosește un minim de memorie RAM (46 octeți plus stivă).

API-ul expus de bibliotecă oferă următoarele funcții:

FRESULT pf_mount (FATFS*);			// Mount / Unmount pentru un volum
FRESULT pf_open (const char*);			// Deschide un fișier
FRESULT pf_read (void*, WORD, WORD*);		// Citește dintr-un fișier
FRESULT pf_write (const void*, WORD, WORD*);	// Scrie într-un fișier
FRESULT pf_lseek (DWORD);			// Mută pointer-ul de citire/scriere
FRESULT pf_opendir (DIR*, const char*);		// Deschide un director
FRESULT pf_readdir (DIR*, FILINFO*);		// Citește un director

Atunci când folosești pf_write pentru a scrie date, este necesar să apelezi și

pf_write(NULL, 0, &w)

ca să finalizezi scrierea (flush).

Dacă nu faci acest pas, citirile ulterioare pot eșua cu o eroare de tip disk error.

6. Exerciții

Lab5_Skel

1. SPI Control (2p total)

Implementați funcțiile de bază care asigură comunicarea microcontroller-ului prin SPI: SPI_init() și SPI_exchange() din fișierul spi.c. Urmați comentariile TODO1 și țineți cont de următoarele:

  • PB4 trebuie setat ca output și inițial HIGH.
  • Configurați SPI ca master, cu SCLK = fosc/16.
  • Folosiți exemplele din datasheet (pagina 217).
  • SPDR0 conține octetul transmis și apoi cel recepționat.

CHECKPOINT (1p): SPI_exchange() trebuie să trimită și să primească date corect.

2. SD Card Control (2p total)

Implementați funcțiile SD_init(), SD_receive() și SD_transmit() din sd.c. Urmați TODO2.

  • PA2 este pinul SS pentru SD Card, se setează ca output.
  • Pentru citire, transmiteți 0xFF (octet dummy).

CHECKPOINT (1p): LCD ar trebui să afișeze 'Mounted!' după câteva secunde.

3. Citirea temperaturii (2p)

Configurați ADC-ul și citiți temperatura de la un senzor analog. Implementați adc_init() și adc_read().

  • Referință AVcc, prescaler 8.
  • Convertiți valoarea ADC în tensiune, apoi în °C (ex: LM35D).
  • Afișați temperatura pe LCD.
  • Verificați citirea temperaturii și prin USART.

4. Logarea temperaturii pe cardul SD (2p)

Tineti cont ca nu puteti crea sau mari size-ul unui fisier folosind PFF, asa ca va trebui sa va incadrati in marimea fisierului deja existent pe sdcard

Implementați init_log_display() și log_temperature() în lab5.c astfel încât să logați valorile citite de la senzor într-un fișier CSV.

  • Folosiți SD_log_data() pentru scrierea valorilor.
  • Afișați temperatura pe LCD și trimiteți-o prin USART.
  • La apăsarea butonului PD6, salvați o nouă intrare.

5. Navigarea prin loguri (2p total)

Implementați next_log_entry() pentru a citi fișierul log.csv linie cu linie.

  • Afișați fiecare linie pe LCD.
  • La apăsarea butonului PB2, treceți la următoarea linie.
  • Când ajungeți la final, reveniți la început.

CHECKPOINT (1p): Trebuie să puteți naviga prin toate logurile.

4. Linkuri utile

5. Responsabili laborator

pm/lab/lab5-2023-2024.txt · Last modified: 2025/04/08 18:06 by andrei.batasev
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0