Jump to content
ELFORUM - Forumul electronistilor

Comunicatie SPI


Recommended Posts

Va salut !M-am apucat sa invat despre acest tip de comunicatie luand o carte in care sunt si exemple numai ca m-am blocat undeva, nu inteleg o chestie. In mare am inteles principiul cum functioneaza numai ca in exemplul din carte nu am inteles ceva la o functie (ex. de acolo este dat pentru conexiunea microcontrolerului cu o memorie <25LC256>).Codul sursa, scris in C (C30 din MPLAB), este urmatorul:/*** Modulul SPI2*/#include #define SPI_MASTER 0x0120 // selecteaza 8-bit master mode, CKE=1, CKP=0#define SPI_ENABLE 0x8000 // activeaza portul SPI, sterge STATUS#define CSEE PORTDbits.RD12 // linia de selectie pentru EEPROM#define TCSEE TRISDbits.TRISD12 // controleaza pinul CSEE// comenzi pentru memoria EEPROM 25LC256#define SEE_WRSR 1 // write status register#define SEE_WRITE 2 // write command#define SEE_READ 3 // read command#define SEE_WDI 4 // write disable#define SEE_STAT 5 // read status register#define SEE_WEN 6 // write enable// trimite un byte de date si primeste unul in acelasi timpint writeSPI2(int data) { SPI2BUF = data; // scrie in buffer pentru TX while(!SPI2STATbits.SPIRBF); // asteapta ca transferul sa se termine return SPI2BUF; // citeste valoarea primita }main(){int i;// 1. initializeaza SPITCSEE = 0; // TCSEE iesireCSEE = 1; // deseleacteaza EEPROMulSPI2CON1 = SPI_MASTER; // modul de lucruSPI2STAT = SPI_ENABLE; // activeaza SPI// 2 verifica reg. STATUS al mem. EEPROMCSEE = 0; // selecteaza memoria EEPROMwriteSPI2(SEE_STAT); // trimite comanda de citire a reg. statusi = writeSPI2(0); // trimite "dummy" (cum zice el acolo in carte), citeste data AICI NU AM INTELESCSEE =1; // termina comanda}// mainFunctia writeSPI2() am inteles ce face, si conform datasheetului memoriei, ca sa faci o citire este simplu: trimiti comanda de citire si imediat microcontrolerul primeste de la memorie informatia respectiva. Pana aici totul pare de bun simt. Dar in sectiunea 2 a codului apare ceva mai straniu, unde am si comentat linia ciudata. Nu era mai logic ca in loc de:// 2 verifica reg. STATUS al mem. EEPROMCSEE = 0; // selecteaza memoria EEPROMwriteSPI2(SEE_STAT); // trimite comanda de citire a reg. statusi = writeSPI2(0); // trimite "dummy" (cum zice el acolo in carte), citeste data. AICI NU AM INTELESCSEE =1; // termina comandasa fie:// 2 verifica reg. STATUS al mem. EEPROMCSEE = 0; // selecteaza memoria EEPROMi = writeSPI2(SEE_STAT); // trimite comanda de citire a reg. statusCSEE =1; // termina comandaca doar functia imi returneaza ceva. El practic a ignorat datele citite si a venit cu linia "i = writeSPI2(0);" care nu am inteles ce face, pentru memorie valoarea 0 nu reprezita nicio comanda.Ma puteti lamuri? Multumesc!

Link to comment
  • Replies 10
  • Created
  • Last Reply

Top Posters In This Topic

Conform datasheetului memoriei, pentru a citi registrul status sunt necesari 16 biti.In primii 8 se trimite instructiunea de citire a registrului, iar in urmatorii 8 memoria trimite continutul registrului.Pentru ca microcontrolerul sa "produca" al doilea tren de 8 impulsuri de clock necesar pentru primirea datelor se vace un dummy write.

Link to comment

Pai este un pic aiurea :-? In primul rand ... nu stiu cum as fi putut sa imi dau seama singur de chestia asta. Nu ar fi trebuit ca modulul SPI sa aiba implementat hardware clock-ul astfel incat sa fie activ si pentru receptionarea datelor? In al doilea rand de ce a mai scris functia asa:int writeSPI2(int data){SPI2BUF = data; // scrie in buffer pentru TXwhile(!SPI2STATbits.SPIRBF); // asteapta ca transferul sa se terminereturn SPI2BUF; // citeste valoarea primita <----- PARTEA ASTA NU AR FI PUTUT LIPSI ? ... din moment ce nu mai are clock}... daca tot urma sa scrie:i = writeSPI2(0); // trimite dummy

Link to comment
Pai este un pic aiurea :-? In primul rand ... nu stiu cum as fi putut sa imi dau seama singur de chestia asta

In datasheetul memoriei respectiv al pic-ului sunt trecute niste diagrame ale semnalelor de comunicatie.

Nu ar fi trebuit ca modulul SPI sa aiba implementat hardware clock-ul astfel incat sa fie activ si pentru receptionarea datelor?

Din pacate clockul pic-ului este legat de bufferul de date. In momentul in care se pun date in buffer acesta si porneste comunicatia si implicit clockul

In al doilea rand de ce a mai scris functia asa:

int writeSPI2(int data){SPI2BUF = data; // scrie in buffer pentru TXwhile(!SPI2STATbits.SPIRBF); // asteapta ca transferul sa se terminereturn SPI2BUF; // citeste valoarea primita <----- PARTEA ASTA NU AR FI PUTUT LIPSI ? ... din moment ce nu mai are clock}

Cel care a facut softul a facut o subfunctie generala pentru comunicatia SPI, si a conceput-o sa returneze orice date se primesc pe bus, chiar daca nu urmeaza sa fie folosite.

Comunicatia SPI este bidirectionala, adica in momentul in care trimite date pe un pin, pe celalalt le citeste (concomitent), iar bufferul modulului SPI este rescris cu datele primite in momentul terminarii comunicatiei.

Modulul SPI din acest PIC poate transmite respectiv receptiona 8 biti de date.

Pentru a transmite, receptiona 16 biti se foloseste de trucul din program, adica trimite 8 biti reprezentand comanda, iar datele primite le "arunca", dupa aceea incarca bufferul cu 0 in cazul de fata doar pentru a porni semnalul de clock, iar datele primite in buffer le foloseste mai departe.

Link to comment

Cred ca am inteles :-? Dar mai am o nelamurire: atunci cand lipseste semnalul de clock memoria eeprom sta in idle si asteapta clock-ul pentru a trimite datele ? Pentru ca de cand este setat steguletul SPIRBF si pana cand se cheama functia pentru a trimite dummy si a receptiona datele mai trece ceva timp.

Link to comment

Am mai gasit ceva, sper ca nu devin stresant dar nu vreau sa trec mai departe pana nu inteleg tot ce avrut sa faca acolo. In functia:

int iReadNVM( int address){ // read a 16-bit value starting at an even address            int lsb, msb;// wait until any work in progress is completed      while ( ReadSR() & 0x3);                // check the two lsb WEN and WIP// perform a 16-bit read sequence (two byte sequential read)      CSEE = 0;                                   // select the Serial EEPROM      WriteSPI2( SEE_READ);                 // read command      WriteSPI2( address>>8);               // address MSB fi rst      WriteSPI2( address & 0xfe);           // address LSB (word aligned)      msb = WriteSPI2( 0);                    // send dummy, read msb      lsb = WriteSPI2( 0);                     // send dummy, read lsb      CSEE = 1;return ( (msb<<8)+ lsb);}//iReadNVM

Este o functie pentru a citit datele de la o anumita adresa din memoria eeprom. (Adresele sunt de 16 biti => 2 trimiteri a cate 8 biti, intai MSB, apoi LSB cf. datasheetului)

(sa zicem ca address = 11001110 11111111)

WriteSPI2( address>>8);               // address MSB first

Shifteaza address, MSB devin LSB ca sa poata trimite MSB intai. address devine: 11111111 11001110.

 

WriteSPI2( address & 0xfe);           // address LSB (word aligned)

Aici nu am inteles:

1. address din argumentul functiei are valoarea initiala (11001110 11111111) sau valoarea shiftata (11111111 11001110)?

2. daca tot urma sa trimita LSB nu putea lasa address asa cum era (11001110 11111111) oricum erau trimisi bitii 11111111. Facand un 'si' pe biti cu valoarea 0xfe pierde MSB(care oricum nu are nevoie de el in cazul asta pentru ca vrea sa trimita LSB) si ultimul bit, doar daca nu se nimereste sa fie un 0. Nu putea inmulti cu 0xFF daca tot vroia sa scape de MSB?

Link to comment

Cand shiftezi, locurile "goale" sunt umplute cu 0, nu cu 1. Da' asta e mai putin important, important e ca se transmit de fiecare data 8 biti. Asa ca in urma operatiei de shiftare, bitii transmisi (8 la numar) sunt cei ai MSByte.

La aplicarea operatiei de shiftare in apelul functiei, valoarea lui address ramane nemodificata, asa ca la la doilea apel al functiei write

WriteSPI2( address & 0xfe);           // address LSB (word aligned)
lucrezi cu valoarea originala a address.

La mascare (address & 0xFE) scopul nu e sa scape de MSByte (asa cum ai remarcat si tu, MSbyte se pierde oricum), ci de bitul 0. Ca sa afli de ce scapa de bitul 0, trebuie vazut in protocolul de comunicatie al memoriei ce inseamna acest bit(poate ca adresarea e numai pe 15 biti?).

 

LE & nu e chiar inmultire, e operatie logica (bit cu bit). De obicei se foloseste pentru a seta anumiti biti din byte - operatie numita mascare. Daca vrei sa faci un bit 0 aplici & cu o masca corespunzatoare byteului care-l contine , daca vrei sa-l faci 1 folosesti | (or).

Link to comment

Am inteles, multumesc!Am mai citit in datasheetul memoriei, adresarea se face pe 16 biti. (chiar daca ar fi fost pe 15 biti datale se transmit de la bitul 0 la 7, asa ma gandesc eu ca ar fi logic, si l-ar include oricum). Dar la 16 biti de adresa acel bit este LSB iar cu acel & 0xFE face sa limiteze numarul maxim de adrese pe care il poti accesa, ba chiar mai mult ... :-? daca vreau sa fac o citire succesiva de 10 adrese sa zic ... nu va face ceva de genul: adresa 0, adresa 2, adresa 4, adresa 6 ... etc ?Multumesc inca o data!

Link to comment

N-ai citit prea bine. Unul din biti e ignorat (don't care):

The device is selected by pulling CS low. The 8-bit

READ instruction is transmitted to the 25XX256

followed by the 16-bit address, with the first MSB of the

address being a “don’t care” bit.

Problema e ca in data sheet se vorbeste de MSB.

Pe de alta parte, in comentariul de la inceputul codului tau scrie exact ce face functia - citeste 16 biti. Cum memoria e pe 8 biti, asta inseamna ca sunt citite 2 adrese deodata. Asa ca citirea de la adrese pare pare "logica":

{ // read a 16-bit value starting at an even address
Daca vrei sa citesti mai multe adrese, trebuie sa dai comanda citire urmata de adesa primei locatii citite. Memoria incrementeaza auomat adresele atata timp cat primeste clock (si CS nu trece in 1).

The data stored in the memory at the next

address can be read sequentially by continuing to

provide clock pulses. The internal Address Pointer is

automatically incremented to the next higher address

after each byte of data is shifted out...

The read operation is terminated by raising the CS pin (

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now



×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.Terms of Use si Guidelines