CURSUL 09

Magistralele Sincrone: SPI și I²C

Durată: 121 min de predare Nivel: licență, anul II - recomandat după Cursul 08 Disciplină: Microcontrollere și Microprocesoare Laborator asociat: Laboratorul 06 PDF: descarcă suportul EN English version

UART-ul rezolvă bine legătura cu un singur partener, dar un sistem real are un senzor de temperatură, un accelerometru, un ceas de timp real, o memorie externă și, poate, un afișaj - toate deodată. Interfața asincronă nu poate duce această încărcătură: nu are ceas comun, deci viteza e plafonată de precizia oscilatoarelor, și e strict punct la punct, deci fiecare periferic nou cere fire noi. Cursul de față prezintă cele două magistrale sincrone care rezolvă problema, cu compromisuri opuse: I²C, minimalistă în fire dar elaborată ca protocol, și SPI, generoasă în fire dar aproape fără protocol.

1Obiectul și structura cursului6 min

Ambele magistrale sunt sincrone - transportă explicit un semnal de ceas alături de date, ceea ce elimină dintr-o lovitură problema abaterii oscilatoarelor discutată în Cursul 08. Vom urmări mecanismul electric care face posibilă partajarea firelor pe I²C, tranzacțiile complete de scriere și citire, apoi principiul registrului de deplasare circular al SPI, modurile de ceas și topologiile posibile, și în final registrele concrete ale ATmega328P pentru ambele.

Recapitulare din Cursul 08
  • Comunicația asincronă cere resincronizare la fiecare cadru, iar eroarea de ceas se acumulează - motivul pentru care viteza UART e plafonată (Cursul 08)
  • UART e strict punct la punct - fără mecanism de adresare (Cursul 08)
  • Să explicați de ce transportul unui semnal de ceas elimină problema abaterii oscilatoarelor
  • Să descrieți mecanismul colector deschis + pull-up și rolul lui în partajarea magistralei I²C
  • Să urmăriți pas cu pas o tranzacție I²C de scriere și una de citire, inclusiv rolul ACK/NACK
  • Să explicați de ce pe SPI nu se poate citi fără a scrie, pornind de la registrul de deplasare circular
  • Să identificați cele patru moduri SPI (CPOL, CPHA) și să recunoașteți simptomul unei nepotriviri
  • Să alegeți motivat între UART, SPI și I²C pentru o aplicație dată

2De ce e nevoie de o magistrală sincronă10 min

Trei limitări ale UART-ului devin vizibile de îndată ce aplicația crește. Prima: absența unui ceas comun - receptorul se agață de frontul de start și eșantionează pe încredere; dacă abaterea relativă dintre cele două oscilatoare depășește ~2,5%, ultimul bit al cadrului e eșantionat greșit. A doua, care decurge din prima: viteza e mărginită de precizia oscilatoarelor, nu de electronica liniei - o legătură UART pe rezonator ceramic devine nesigură cu mult înainte de un megabit pe secundă, insuficient pentru un afișaj grafic sau un card SD.

A treia: numărul de dispozitive. UART e strict punct la punct, fără adresare - trei dispozitive pe aceleași două fire nu au cum să știe cui îi e destinat un octet. Un ATmega328P are un singur modul USART; dacă fiecare periferic ar cere o legătură dedicată, capacitatea de extindere s-ar epuiza după câteva module.

Soluția: o magistrală, nu o legătură dedicată În loc de fire separate pentru fiecare periferic, un set redus de fire partajate de toate dispozitivele, plus un protocol care spune cine vorbește, când și cui i se adresează. I²C reduce firele la minimul absolut, doi, cu prețul unei viteze mai mici și al unui protocol mai complicat. SPI merge pe drumul opus: patru fire, protocol aproape inexistent, viteză cu un ordin de mărime mai mare. Ambele transportă explicit ceasul, ceea ce elimină plafonul de viteză impus de abaterea oscilatoarelor.

3I²C: prezentare generală, colector deschis, adresare13 min

I²C (Inter-Integrated Circuit, Philips, anii 1980) folosește două linii: SDA (Serial Data) și SCL (Serial Clock), plus masa comună. Numărul de fire rămâne același indiferent dacă sunt legate două dispozitive sau douăsprezece - marele avantaj al magistralei.

Protocolul e maestru-sclav: maestrul (de regulă microcontrolerul) generează ceasul, inițiază fiecare transfer și decide când se încheie. Sclavii (senzori, memorii, ceasuri de timp real) nu vorbesc niciodată nesolicitați - răspund doar la cerere.

Colectorul deschis și rezistoarele de ridicare

Dacă mai multe dispozitive sunt legate la același fir, cine impune un nivel când altul impune opusul? Soluția: etajul de ieșire al fiecărui dispozitiv e de tip colector deschis - un singur tranzistor, între linie și masă. Când conduce, trage linia la zero; când e blocat, o eliberează. Niciun dispozitiv nu poate forța linia în unu logic. Fiecare linie e legată la alimentare printr-un rezistor de ridicare (pull-up), care readuce linia în unu logic atunci când nimeni nu o trage în jos - rezultatul e o funcție ȘI cablată: linia e în unu numai dacă toate dispozitivele o eliberează.

De ce coliziunea electrică devine imposibilă Nu există două surse care se opun - există cel mult mai multe tranzistoare care trag în aceeași direcție. Valoarea rezistoarelor e un compromis: prea mare încetinește frontul crescător (risc ca tranziția să nu ajungă la nivel înainte de următorul front de ceas); prea mic crește curentul absorbit la tragerea liniei jos. Valori uzuale: ~4,7 kΩ pentru 100 kHz, ~2,2 kΩ pentru 400 kHz sau magistrale cu mai multe dispozitive. Pe Arduino Uno, SDA/SCL sunt pe A4/A5 (PC4/PC5).
Module comerciale cu pull-up propriu, legate în paralel

Multe module au deja rezistoarele montate pe placa lor - patru sau cinci astfel de module pe aceeași magistrală pun rezistoarele în paralel, coborând rezistența echivalentă sub un kiloohm, crescând curentul și putând destabiliza magistrala. Remediu: îndepărtați rezistoarele de pe toate modulele în afară de unul.

Adresarea pe șapte biți

Fiecare sclav are o adresă pe 7 biți (128 combinații, din care 112 utilizabile, restul rezervate). Tot transferul începe cu emiterea acestei adrese - toți sclavii ascultă, compară cu adresa proprie, iar numai cel care se recunoaște continuă dialogul. Adresa e stabilită de producător, nu de proiectant; unele circuite au pini de configurare a ultimilor biți, pentru mai multe exemplare pe aceeași magistrală.

Adresa pe 7 biți vs. octetul emis pe magistrală

Cei 7 biți de adresă sunt urmați de un al optulea bit de sens (0=scriere, 1=citire). Aceeași adresă apare uneori ca 0x68 (convenția pe 7 biți, folosită de bibliotecile Arduino, care fac deplasarea) și alteori ca 0xD0 (octetul complet emis pe fir) - o confuzie frecventă care face dispozitivul să nu răspundă deloc.

Viteze standardizate: modul standard 100 kHz, modul rapid 400 kHz, variante mai recente 1 MHz și 3,4 MHz - toate sunt maxime, nu valori impuse; maestrul poate merge mai lent fără nimic să se strice, tocmai pentru că ceasul e transmis, nu presupus.

Dimensionarea rezistoarelor de ridicare pe magistrala I2C

4Condițiile de start, de stop și confirmarea ACK/NACK11 min

Rămâne de rezolvat delimitarea mesajelor. Regula generală: SDA are voie să-și schimbe starea numai când SCL e jos; cât timp SCL e sus, datele trebuie stabile, pentru că exact atunci le eșantionează receptorul. O tranziție a lui SDA cât SCL e sus e, prin definiție, imposibilă în timpul transportului de date - poate fi deci folosită ca semnal de control.

Condițiile de start, stop și start repetat
Start: SDA din 1 în 0 cât SCL e sus - semnalizează tuturor că magistrala a fost ocupată și că urmează o adresă.
Stop: SDA din 0 în 1 cât SCL e sus - eliberează magistrala.
Start repetat: identic cu start, dar fără stop înainte - permite schimbarea sensului transferului fără eliberarea magistralei, evitând ca un alt maestru să se strecoare între cele două jumătăți.

Confirmarea ACK/NACK

Spre deosebire de UART, I²C cere confirmare după fiecare octet. Fiecare octet ocupă 9 perioade de ceas: opt pentru date (MSB primul), a noua pentru confirmare. La a noua perioadă, emițătorul eliberează SDA; dacă receptorul acceptă octetul, trage linia la masă (ACK); dacă nu face nimic, rezistorul de ridicare menține linia sus (NACK).

NACK are sens diferit în funcție de context După octetul de adresă: NACK înseamnă că niciun sclav de pe magistrală nu poartă acea adresă - principiul scanării magistralei. După un octet de date trimis de maestru: NACK înseamnă că sclavul nu mai poate prelua date (buffer plin). La citire: rolul se inversează - maestrul confirmă fiecare octet primit, dar trimite deliberat NACK după ultimul octet dorit, semnalând sclavului să se oprească. Un maestru care ar confirma și ultimul octet ar spune sclavului să continue la nesfârșit.

5Tranzacții I²C: scriere, citire, arbitraj13 min

Toate elementele de mai sus se combină în două tipare pe care orice bibliotecă I²C le execută.

Tranzacția de scriere

Pentru a scrie 0x1F în registrul 0x07 al unui sclav la adresa 0x68: maestrul generează start, emite 0xD0 (adresă+scriere), citește ACK; emite 0x07 (numărul registrului, o convenție a perifericului, nu a magistralei), citește ACK; emite 0x1F (valoarea), citește ACK; generează stop. Pentru protocolul I²C, transferul e: start, adresă cu scriere, trei confirmări, doi octeți de date, stop - interpretarea „registru + valoare" ține de foaia de catalog a perifericului.

Tranzacția de citire

Mai subtilă, pentru că de obicei trebuie mai întâi spus sclavului ce vrem, ceea ce înseamnă o scriere. Faza 1: start, adresă cu scriere (0xD0), ACK, numărul registrului (0x07), ACK - sclavul și-a poziționat pointerul intern, dar n-a trimis nimic. Faza 2: start repetat, adresă cu citire (0xD1), ACK - rolurile pe SDA se inversează, sclavul devine emițător, maestrul receptor, dar maestrul continuă să genereze ceasul. La fiecare octet primit, maestrul confirmă cu ACK dacă mai vrea date, sau cu NACK dacă a fost ultimul dorit, apoi generează stop.

Ordinea NACK-apoi-stop e obligatorie

Dacă maestrul ar emite stop imediat după un ACK, sclavul ar putea rămâne cu ieșirea activă, ținând SDA la masă - magistrala rămâne blocată până la oprirea alimentării. Dacă microcontrolerul se resetează în mijlocul unei citiri, sclavul continuă să țină SDA jos, așteptând ceasul; maestrul nu mai poate genera nici măcar un start. Deblocarea: generarea manuală, prin software, a până la nouă impulsuri pe SCL, urmate de o condiție de stop.

Citirea unui registru de la un sclav I2C: puneti pasii in ordine

Arbitrajul și întinderea ceasului

Arbitrajul rezolvă coliziunea când doi maeștri încep simultan: fiecare emite biții adresei și citește simultan SDA - dacă citește 0 când a emis 1, altcineva trage linia, iar el se retrage imediat, fără pierdere de biți. Câștigă maestrul cu adresa numeric mai mică (zero domină). Întinderea ceasului (clock stretching) rezolvă sclavul lent: SCL e tot colector deschis, deci un sclav care are nevoie de timp o ține trasă jos după ce maestrul a eliberat-o; maestrul, care verifică nivelul real înainte de a considera perioada încheiată, așteaptă. E un mecanism de control al fluxului pe care nici UART, nici SPI nu-l au.

6SPI: registrul de deplasare circular11 min

SPI (Serial Peripheral Interface) pornește din premise opuse - nu economisește fire, transferă cât mai repede și cu cât mai puțină logică. Nu are o specificație oficială unică; e un mecanism hardware de schimb de biți peste care fiecare periferic definește propriile convenții.

Comunicația e full-duplex, maestru-sclav, pe patru linii: SCLK (ceas, generat exclusiv de maestru), MOSI (Master Out Slave In), MISO (Master In Slave Out), și SS (Slave Select, activ pe zero logic - un sclav neselectat își pune MISO în înaltă impedanță).

Ideea centrală: nu e o transmisie, e un schimb Maestrul și sclavul au fiecare un registru de deplasare pe 8 biți, legate cap la coadă prin MOSI și MISO, formând un singur registru circular pe 16 biți. La fiecare impuls de ceas, un bit iese pe MOSI și intră în sclav, iar un bit iese pe MISO și intră în maestru - simultan. După opt impulsuri, cele două dispozitive au schimbat între ele câte un octet.
Pe SPI nu se poate citi fără a scrie, și invers

Deplasarea în cele două registre e comandată de același ceas - nu există „doar transmisie" sau „doar recepție". Dacă maestrul vrea doar să trimită, primește oricum înapoi octetul din registrul sclavului (de regulă ignorat). Dacă vrea doar să citească, trebuie totuși să trimită un octet fictiv (dummy byte), pentru că altfel n-ar avea de ce să genereze impulsuri de ceas. De aici forma tuturor funcțiilor de bibliotecă SPI: o singură funcție de transfer, care primește un octet și întoarce un octet.

A doua consecință: sclavul nu poate răspunde imediat. Octetul pe care îl trimite e cel deja pregătit în registru la începutul transferului, nu unul calculat pe baza octetului primit simultan. Dialogul obișnuit are două etape: primul transfer trimite o comandă și primește un octet fără valoare; al doilea trimite un octet fictiv și primește răspunsul la comanda anterioară. Cine ignoră acest decalaj citește sistematic răspunsul cu o poziție întârziere.

Linia SS are două roluri: selectează sclavul, și delimitează tranzacția - multe periferice își resetează logica internă la fiecare front descrescător al selecției, iar comenzile lor sunt interpretate relativ la începutul tranzacției.

7Modurile SPI: polaritate și fază11 min

Un registru de deplasare are nevoie de ambele fronturi ale ceasului, pentru operații diferite: pe unul, ieșirea e actualizată (bitul următor iese pe linie); pe celălalt, intrarea e eșantionată (bitul prezent e capturat). Cele două se fac obligatoriu pe fronturi opuse, la jumătate de perioadă distanță, altfel receptorul ar citi linia exact în momentul comutării.

CPOL și CPHA
CPOL (polaritatea): starea liniei SCLK în repaus - 0 = jos (primul front e crescător), 1 = sus (primul front e descrescător).
CPHA (faza): care front eșantionează - 0 = eșantionare pe primul front, schimbare pe al doilea; 1 = invers.
ModCPOLCPHAEșantionare
000front crescător (primul)
101front descrescător (al doilea)
210front descrescător (primul)
311front crescător (al doilea)
Potriviti fiecare mod SPI cu comportarea liniei de ceas
Cele patru moduri SPI - alegeti CPOL si CPHA

Modurile 0 și 3 sunt cele mai răspândite - în ambele, eșantionarea se face pe frontul crescător, diferă doar starea de repaus. Modul 0 e implicit pentru biblioteca Arduino și pentru majoritatea memoriilor, cardurilor SD și convertoarelor.

Un mod SPI greșit e eroarea silențioasă prin excelență

Dacă maestrul e în modul 0 (scoate pe descrescător, citește pe crescător) și sclavul e în modul 1 (invers), toată succesiunea se deplasează cu o jumătate de perioadă - sclavul capturează bitul următor în loc de cel curent. SPI nu are paritate, sumă de control sau confirmare - registrul maestrului se umple cu opt biți la fel de conștiincios ca și cum totul ar fi corect. Simptomul: un senzor raportează valori absurde, un afișaj arată pixeli împrăștiați, un card SD nu se inițializează, iar erorile pot apărea intermitent, în funcție de întârzierile parazite ale traseului. Diagnostic: foaia de catalog a perifericului, un osciloscop, sau încercarea metodică a celor patru moduri.

Aceeași categorie de erori silențioase: ordinea biților Majoritatea perifericelor așteaptă bitul cel mai semnificativ primul, dar unele lucrează invers - hardware-ul AVR permite ambele prin bitul DORD. Cu ordinea greșită, se recepționează exact aceiași opt biți, dar în oglindă: 0x01 devine 0x80, iar programul nu are cum să observe diferența.

8Topologii SPI și modulul SPI al ATmega328P13 min

Cazul cu un singur sclav leagă cele patru linii direct - SS poate fi uneori legat permanent la masă, dacă perifericul o acceptă. Configurația cu selecție independentă: toți sclavii împart SCLK, MOSI, MISO, dar fiecare are propria linie SS - independență completă, dar costă 3+n pini pentru n sclavi. Înlănțuirea (daisy chain): MISO al primului merge la MOSI al celui de al doilea ș.a.m.d., SCLK și SS comune tuturor; registrele formează un singur lanț lung - numărul de pini rămâne 4 indiferent de câți sclavi, dar dispozitivele nu mai pot fi adresate individual, iar durata unui transfer crește proporțional. Se folosește doar pentru dispozitive identice care se actualizează oricum împreună (un șir de drivere de afișaj), niciodată pentru senzori diferiți.

Modulul SPI al ATmega328P

Patru pini fizici: PB2 (SS), PB3 (MOSI), PB4 (MISO), PB5 (SCK) - pinii 10-13 pe Arduino Uno.

RegistruBitRol
SPCRSPE / MSTRactivare modul / rol (1=maestru)
SPCRCPOL / CPHA / DORDmod de funcționare, ordinea biților
SPCRSPR1:0prescalare ceas: f_osc/4, /16, /64, /128
SPSRSPIFtransfer încheiat (8 impulsuri consumate)
SPSRSPI2Xdublează frecvența, până la f_osc/2
SPDR-registrul de date - scrierea pornește transferul, citirea întoarce octetul primit
PB2 (SS) trebuie configurat ca ieșire, chiar dacă selecția se face pe alt pin

Dacă rămâne intrare și cineva îl trage jos, modulul comută automat din maestru în sclav, ștergând bitul MSTR - un mecanism prevăzut pentru sisteme cu mai mulți maeștri, dar care, într-o aplicație obișnuită, produce o defecțiune greu de explicat: comunicația se oprește brusc, fără motiv aparent.

void SPI_MasterInit(void) {
    DDRB |= (1<<PB3)|(1<<PB5)|(1<<PB2);   /* MOSI, SCK, SS: iesiri */
    DDRB &= ~(1<<PB4);                     /* MISO: intrare */
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);  /* maestru, ceas f_osc/16 */
    PORTB |= (1<<PB2);                      /* SS inactiv (High) */
}
uint8_t SPI_MasterTransfer(uint8_t data) {
    PORTB &= ~(1<<PB2);         /* selecteaza sclavul */
    SPDR = data;                  /* scrierea porneste transferul */
    while (!(SPSR & (1<<SPIF))) { }
    PORTB |= (1<<PB2);
    return SPDR;                  /* octetul primit de la sclav */
}
Exercițiu rezolvat - alegerea prescalerii pentru un periferic la ≤2 MHz

ATmega328P la 16 MHz, periferic limitat la 2 MHz pe SCLK.

Vezi rezolvarea

Divizoarele disponibile (fără SPI2X): 4, 16, 64, 128, dând 4 MHz, 1 MHz, 250 kHz, 125 kHz. Prima valoare (4 MHz) depășește limita - se alege divizarea cu 16 (SPR0=1, SPR1=0), ceas de 1 MHz. Perioada unui bit: 1 µs, deci opt biți se transferă în 8 µs. La viteze mari, cheltuiala de program (scrierea în SPDR, testarea SPIF, comanda liniei de selecție) devine comparabilă cu durata transferului propriu-zis, iar rata utilă efectivă rămâne sensibil sub cea teoretică.

9Bibliotecile SPI și Wire, scanarea magistralei I²C9 min

Biblioteca SPI pune la dispoziție noțiunea de tranzacție, care declară viteza, ordinea biților și modul cerut de periferic:

SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
digitalWrite(PIN_SS, LOW);
SPI.transfer(adresa | 0x80);        /* comanda; bitul 7 marcheaza citire */
uint8_t valoare = SPI.transfer(0x00);  /* octet fictiv, primeste raspunsul */
digitalWrite(PIN_SS, HIGH);
SPI.endTransaction();

Selecția rămâne comandată explicit de program (numărul pinului depinde de montaj); cele două transferuri reflectă exact decalajul discutat mai devreme.

Biblioteca Wire, pentru I²C, implementează tranzacțiile discutate:

Wire.beginTransmission(ADRESA);    /* pregateste START + adresa + W */
Wire.write(reg);
Wire.endTransmission(false);        /* false = START repetat, fara STOP */
Wire.requestFrom(ADRESA, (uint8_t)1);
if (Wire.available()) valoare = Wire.read();

beginTransmission nu trimite nimic - acumulează octeții într-un buffer intern; abia endTransmission generează start, adresă, date și (dacă nu i se dă false) stop. Valoarea întoarsă e codul de eroare: 0=succes, 2=NACK la adresă (periferic absent), 3=NACK la date.

Scanarea magistralei I²C

Decurge direct din mecanismul de confirmare: start + adresă + stop, fără date - dacă vine ACK, există un dispozitiv la acea adresă; dacă NACK, nu există.

for (uint8_t adresa = 8; adresa < 120; adresa++) {
    Wire.beginTransmission(adresa);
    if (Wire.endTransmission() == 0) {
        Serial.print("Gasit la 0x"); Serial.println(adresa, HEX);
    }
}
Interpretarea rezultatului scanării

Un rezultat gol: verificați inversarea SDA/SCL, lipsa masei comune, absența pull-up-urilor. Un rezultat cu dispozitive la toate adresele: indică de obicei o linie SDA blocată în zero logic - fiecare interogare pare confirmată.

Exercițiu rezolvat - configurarea TWBR pentru 100 kHz și 400 kHz

ATmega328P la 16 MHz. Modulul TWI: f_SCL = f_osc / (16 + 2·TWBR·4^TWPS).

Vezi rezolvarea

Cu TWPS=0 (4^0=1): f_SCL = f_osc/(16+2·TWBR).

Pentru 100 kHz: 16×10⁶/100000 = 160 = 16+2·TWBR ⇒ TWBR=72.

Pentru 400 kHz: 16×10⁶/400000 = 40 = 16+2·TWBR ⇒ TWBR=12.

Ambele valori sunt întregi, exacte. Spre deosebire de UART, unde eroarea ratei e o problemă permanentă, aici o abatere de la nominal n-ar avea nicio consecință funcțională - sclavii urmăresc ceasul primit, oricare ar fi el, cu condiția să nu depășească limita lor maximă.

10Comparație între UART, SPI și I²C6 min

CriteriuUARTSPII²C
Fire23 comune + n selecție2
Ceas comunnudada
Viteză uzuală9600-115200 bpspână la 10 Mbit/s100-400 kHz
Dispozitive2, punct la punct1 maestru + n sclavipână la 112 adrese
Confirmaredoar paritate opționalăniciunaACK/NACK per octet
Utilizare tipicăcalculator, depanarememorii, SD, afișaje rapidesenzori lenți, RTC, EEPROM
Regula practică de alegere Dacă partenerul e departe, un calculator, sau vorbește oricum asincron: UART. Dacă transferul e mare și rapid, iar numărul de periferice e mic: SPI - un afișaj grafic sau un convertor care eșantionează de mii de ori pe secundă nu au altă opțiune rezonabilă. Dacă perifericele sunt multe, mici și lente, iar pinii sunt puțini: I²C - un senzor citit o dată pe secundă nu are nevoie de un megabit pe secundă, iar economia de pini e decisivă.

Cele trei coexistă fără conflict pe același microcontroler, pentru că folosesc module hardware și pini diferiți - un proiect obișnuit are simultan UART către calculator pentru depanare, I²C cu doi-trei senzori, și SPI către un card de memorie sau un afișaj.

11Erori frecvente4 min

  • „Am legat SDA și SCL fără rezistoare de pull-up - dispozitivele oricum au pini de alimentare." Fals - fără rezistoarele de ridicare, liniile eliberate de toate dispozitivele rămân în aer, la un nivel nedefinit, în loc de unu logic. Fiecare linie I²C cere un rezistor de ridicare, extern sau de pe un modul deja prezent pe magistrală.
  • „Perifericul SPI nu răspunde bine, dar codul pare corect - trebuie să fie o problemă de alimentare." Adesea nu - e un mod SPI (CPOL/CPHA) nepotrivit, care nu generează niciun mesaj de eroare, doar date greșite. Verificați foaia de catalog pentru modul cerut și încercați metodic cele patru combinații dacă nu e specificat clar.
  • „Am confirmat (ACK) și ultimul octet la o citire I²C, ca să fiu sigur că totul a mers bine." Fals - ACK pe ultimul octet spune sclavului să continue transmisia, nu că totul e în regulă. Trimiteți NACK deliberat după ultimul octet dorit, apoi generați condiția de stop.

12Rezumat și glosar5 min

Ambele magistrale rezolvă limitele UART-ului transportând explicit un semnal de ceas. SPI o face cu patru linii și aproape fără protocol: maestrul și sclavul formează, prin MOSI și MISO, un singur registru de deplasare circular, iar la fiecare impuls un bit iese și un bit intră simultan - citirea și scrierea sunt inseparabile. Cele patru moduri (CPOL, CPHA) trebuie potrivite exact între maestru și sclav, altfel apar date greșite fără nicio semnalizare. Selecția independentă consumă un pin per sclav; înlănțuirea economisește pini cu prețul adresării individuale. I²C face același lucru cu două linii, plătind cu un protocol elaborat: colectorul deschis și rezistoarele de ridicare fac magistrala partajabilă fără conflicte, condițiile de start/stop folosesc singurele tranziții interzise în timpul datelor, iar confirmarea ACK/NACK după fiecare octet oferă un control de flux pe care nici UART, nici SPI nu îl au. Alegerea între ele nu e preferință, ci cerințe: viteză pentru SPI, economie de pini pentru I²C, distanță și compatibilitate pentru UART.

Colector deschis
etaj de ieșire care poate doar trage linia la masă, niciodată la alimentare.
ACK / NACK
confirmare / neconfirmare pe I²C, generată de receptor prin colectorul deschis.
Registru de deplasare circular
mecanismul SPI prin care maestrul și sclavul schimbă simultan câte un bit.
CPOL / CPHA
polaritatea și faza ceasului SPI, care definesc cele patru moduri.
Octet fictiv
octet trimis fără valoare utilă, doar pentru a genera impulsurile de ceas necesare unei citiri SPI.
Clock stretching
întinderea ceasului de către un sclav I²C lent, prin menținerea SCL jos.

13Întrebări de verificare7 min

  1. Explicați de ce o legătură UART nu poate lega trei dispozitive pe aceleași fire, în timp ce I²C poate lega zece. Ce element al protocolului face diferența?
  2. De ce transportul explicit al ceasului elimină problema abaterii oscilatoarelor?
  3. Descrieți ce s-ar întâmpla electric pe SDA dacă un dispozitiv ar avea ieșire în contratimp în loc de colector deschis, iar un al doilea ar trage linia la masă simultan.
  4. Explicați de ce condiția de start nu poate fi confundată cu un bit de date oarecare.
  5. Un maestru citește cinci octeți de la un sclav I²C. Cine confirmă fiecare octet, și ce se întâmplă dacă maestrul confirmă și ultimul?
  6. Justificați afirmația că pe SPI nu se poate citi fără a scrie, pornind de la registrul de deplasare circular.
  7. Un periferic SPI cere modul 2, programul îl configurează pe modul 0. Ce se întâmplă la nivelul fronturilor, și de ce nu apare niciun mesaj de eroare?

14Direcții de aprofundare2 min

Cursurile următoare trec de la mecanismele individuale ale perifericelor la proiectarea unei aplicații complete: cum se aleg și se combină resursele discutate până acum - porturi, întreruperi, timere, ADC, comunicație - într-un sistem funcțional, testat și documentat.

Configurarea SPI, protocolul I²C și scanarea magistralei din acest curs devin montaj real în Laboratorul 06.