bodo_b Postat Martie 16, 2012 Partajează Postat Martie 16, 2012 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 spre comentariu
Rabulea Sergiu Postat Martie 16, 2012 Partajează Postat Martie 16, 2012 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 spre comentariu
bodo_b Postat Martie 16, 2012 Autor Partajează Postat Martie 16, 2012 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 spre comentariu
Rabulea Sergiu Postat Martie 16, 2012 Partajează Postat Martie 16, 2012 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 spre comentariu
bodo_b Postat Martie 16, 2012 Autor Partajează Postat Martie 16, 2012 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 spre comentariu
Rabulea Sergiu Postat Martie 18, 2012 Partajează Postat Martie 18, 2012 Da, memoria asteapta semnalul de clock pentru a trimite datele. Link spre comentariu
bodo_b Postat Martie 20, 2012 Autor Partajează Postat Martie 20, 2012 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 spre comentariu
Liviu M Postat Martie 20, 2012 Partajează Postat Martie 20, 2012 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 spre comentariu
bodo_b Postat Martie 20, 2012 Autor Partajează Postat Martie 20, 2012 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 spre comentariu
Liviu M Postat Martie 20, 2012 Partajează Postat Martie 20, 2012 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 addressDaca 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 spre comentariu
bodo_b Postat Martie 20, 2012 Autor Partajează Postat Martie 20, 2012 Da, domnule :-? pare cat se poate de clar si logic. Am intuit eu ca citeste din 2 in 2 dar nu mi-am dat seama si de ce ... cu toate ca era simplu :-j.Multumesc pentru explicatii ! Link spre comentariu
Postări Recomandate
Creează un cont sau autentifică-te pentru a adăuga comentariu
Trebuie să fi un membru pentru a putea lăsa un comentariu.
Creează un cont
Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!
Înregistrează un nou contAutentificare
Ai deja un cont? Autentifică-te aici.
Autentifică-te acum