LAKI PINGVINI<>
052018<><>

Arduino: Komunikacija sa memorijskim karticama

Gigabajti na vezi

O memorijskim karticama smo opširno pisali u SK 8/2017 i tom smo prilikom, zbog nedostatka prostora, preskočili deo koji se odnosi na opisivanje hardverskog interfejsa i funkcija njegovih kontaktnih nožica. To je u jednu ruku ispalo dobro, pošto smo taj tekst zadržali u granicama relativne jednostavnosti, dok je sa druge strane otvorilo mogućnost da se toj temi posvetimo na malo ozbiljniji način, što smo ovom prilikom i uradili na mestu gde od toga može biti više praktične koristi.

 

 
Mali broj ljudi zna da memorijske kartice u sebi imaju minijaturni mikrokontroler čija je funkcija da, između ostalog, obezbedi ispravan prenos podataka između memorijskih elemenata na kartici i uređaja koji čitaju ili zapisuju podatke u njegovoj memoriji. Saradnja tog mikrokontrolera sa eksternim uređajima se ostvaruje putem standardizovanih hardverskih protokola.

Memorijske kartice formata SD (i delimično MMC) se sa drugim uređajima mogu povezati na tri različita načina. Prvi je naš stari drugar, SPI interfejs, koji za komunikaciju koristi četiri dobro poznate linije: CS, CLK, MISO i MOSI. SD standard (ponekad se ne baš pravilno označava kao SDIO) podržava još dva načina prenosa podataka koji koriste 1-bitnu i 4-bitnu magistralu.

 
Iako bi se po nazivu moglo zaključiti da 1-bitna magistrala za komunikaciju zahteva manji broj pinova, to nije tačno i za njeno korišćenje potreban je isti broj linija kao i u slučaju SPI interfejsa. Naziv sugeriše da se za prenos podataka koristi samo linija pod nazivom DAT0. Ovaj režim rada je dosta sporan za realizaciju na 8-bitnim AVR platformama jer za to ne postoji podrška na hardverskom nivou, zahteva se CRC provera pristiglih podataka, ne postoje biblioteke napisane za podršku i zbog svega toga gubi brzinsku prednost koju taj modus inicijalno ima nad SPI magistralom. Stvar je još komplikovanija sa režimom 4-bitne magistrale, koji jeste najbrži način prenosa podataka (praktično je obavezan kod SDHC standarda), ali je u njegovom slučaju pored svih navedenih problema potrebno koristiti još dve dodatne linije za prenos podataka. Ukoliko postoji neophodnost za korišćenjem bržih režima prenosa, potrebno je koristiti mikrokontrolere veće snage koji imaju hardversku i softversku podršku za rad preko dve pomenute magistrale.

Stari dobri SPI

Dakle, jedini racionalan izbor u slučaju Arduino UNO platforme odnosi se na SPI režim povezivanja, za koji na raspolaganju imamo sva potrebna sredstva. Komunikaciju sa memorijskom karticom moguće je ostvariti na prilično jednostavan način uz pomoć komponenti do kojih nije teško doći. Iako je teorijski moguće koristiti i mikro SD kartice, zbog jednostavnosti povezivanja pinova za osnovu je mnogo praktičnije uzeti SD/MMC karticu standardnog formata ili, još bolje, adapter za mikro SD kartice. Na nožice konektora 1-7 potrebno je zalemiti žice koje će služiti za vezu sa napajanjem i mikrokontrolerom. Verovatno najpraktičniji način povezivanja se ostvaruje lemljenjem pinova sa razmakom od 2,5 milimetra, što nam posle omogućuje jednostavno korišćenje sa prototipskim pločicama. Ti konektori se mogu nabaviti po bagatelnoj ceni i vrlo često se nalaze u „borbenom kompletu” prosečnog mejkera.

 
Iako ova naša „skalamerija” izgleda iznenađujuće jednostavno, ona je praktično već spremna za korišćenje sa uređajima koji rade na naponu od 3,3 volta. Iako naš standardni Arduino Uno radi na naponu od pet volti, treba reći da mikrokontroleri porodice Atmega mogu raditi i sa naponom od 3,3 volta, samo će u tom slučaju brzina radnog takta biti dvostruko niža, odnosno osam megaherca. Postoji i zvanični Arduino model pod nazivom Pro Mini (SK 12/2017) koji ima upravo navedene radne karakteristike.

U prošlom broju smo se dotakli teme sinhronizacije uređaja koji rade na različitim naponima. Rekli smo da je u slučaju korišćenja prototipskih breadboard pločica najjednostavnije koristiti naponske šiftere, koji znatno olakšavaju povezivanje. Prikazali smo kako je to moguće uraditi uz pomoć otpornika. Prateća shema povezivanja memorijske kartice sa Arduinom Uno demonstrira u praksi ono o čemu smo prethodno govorili. Ako malo bolje pogledamo šemu, videćemo da se parovi otpornika za regulaciju napona nalaze samo na tri od ukupno četiri linije SPI interfejsa. Razlog nepostojanja otpornika na liniji između Arduino pina D12 (MISO) i sedmog pina na memorijskoj kartici (DO) jeste taj što je pin DO izlaznog tipa, tako da uređaju ne preti opasnost pregorevanja od napona pristiglog sa Arduina. Sa druge strane, standard određuje da uređaji koji rade na naponu od pet volta mogu da prepoznaju signal logičke jedinice ukoliko se on kreće u opsegu od dva do pet volti, tako da će naš Uno bez problema prihvatiti dolazeće podatke.

Gotovi moduli

 
Jedna od važnih stvari koje su Arduino učinile veoma popularnim jeste i postojanje velikog broja gotovih modula koji se priključuju na jednostavan način i korisnika lišavaju mnoštva problema oko konstrukcije i izgradnje tih uređaja. Pošto mnogi zaljubljenici u elektroniku, iz ovog ili onog razloga, nemaju mogućnost da se bave vlastitom realizacijom komponenti, gotovi moduli predstavljaju idealno rešenje koje i početnicima omogućuje da za kratko vreme sagrade relativno kompleksne sklopove koji obavljaju neku praktičnu funkciju. Kao i u mnogo slučajeva do sada, proizvođači i prodavci sa Dalekog istoka nam za veoma malo novca nude gotova rešenja. Cene većine SD modula su izuzetno povoljne i kreću se u opsegu od 40-80 američkih centi. Stvari su malo komplikovanije kada sa radi o modulima koji podržavaju rad sa pomenutim SD magistralama od jedan i četiri bita, pošto su im cene znatno veće i kreću se u rasponu od tri do deset dolara. Takvi modeli obično imaju po devet pinova za priključivanje .

Generalno bismo module koji rade preko SPI magistrale mogli podeliti u dve osnovne kategorije. U prvu kategoriju spadaju moduli koji nude podršku za memorijske kartice standardnog SD formata. Osim prepoznatljivog slota, one se u najvećem broju slučajeva karakterišu i sa šesnaest (dva reda po osam) pinova namenjenih za priključivanje na SPI interfejs. Razlog za postojanje dva reda je veoma misteriozan (na internetu nije moguće pronaći informaciju o tome), ali je poznato da su svi parovi pinova međusobno povezani, tako da je priključivanje moguće ostvariti preko oba reda. U drugu kategoriju spadaju moduli namenjeni podršci karticama mikro SD formata. O njima se ne može reći ništa posebno zanimljivo, osim da su nešto manjih dimenzija i da pored regulatora za napon od 3,3 volta na sebi imaju integralno kolo za konverziju napona između 3,3 i pet volti. Za povezivanje sa drugim uređajima koristi se šest pinova, i to četiri za SPI interfejs i dva za dovođenje struje. Još jedan detalj karakteriše najrasprostranjeniji modul ovoga tipa i odnosi se na oznaku MOSO za signal MISO, što predstavlja tipografsku grešku. Pitanje izbora između ove dve vrste modula je uglavnom lične prirode. Ukoliko korisnik na raspolaganju ima veći broj starijih SD kartica, za njega bi model sa standardnim SD gnezdom mogao biti bolji izbor.

 
Treba istaći da realna brzina prenosa podataka zavisi od više faktora i može da se kreće od nekoliko desetina do nekoliko stotina kilobajta u sekundi. To je evidentno mnogo manje nego u radu sa istim tipom memorije na računarima i drugim uređajima, ali treba imati na umu da se radi o različitim kategorijama proizvoda. Postoje brojni trikovi da se poveća brzina čitanja, zapisa i prenosa podataka preko SPI magistrale, ali bi i ove osnovne vrednosti trebalo da budu sasvim dovoljne za najveći broj primena.

U procesu razrade praktičnih projekata koji će u sebe uključivati modul za rad sa SD karticama posebnu pažnju je potrebno obratiti na potrošnju struje, koja prilikom zapisivanja podataka može da dostiže vrednosti od 100 do 200 miliampera. Kada je reč o čitanju, situacija je znatno bolja i potrošnja se kreće u granicama 50-80 miliampera, dok je u stanju neaktivnosti ona tek 0,2 miliampera.

Kodiranje

 
Postoji priličan broj različitih biblioteka za rad sa SD karticama, koje se razlikuju u kvantitetu podržanog hardvera, podršci različitim fajl-sistemima, broju realizovanih programskih funkcija, kao i zauzeću memorijskih resursa mikrokontrolera. Mi smo za demonstraciju izabrali standardnu Arduino biblioteku koja dolazi uz IDE, iako postoje varijante koje su mnogo bolji izbor za praktičnu realizaciju. Prilikom kompajliranja jednostavnog primera koji vraća podatke o veličini logičke particije na kartici i izlistava njen sadržaj, utrošeno je 10940 bajtova (32%) fleš skladišta i čak 1276 bajtova (62%) SRAM-a.

#include <SPI.h>

#include <SD.h>

Sd2Card SDC; // kartica

SdVolume disk; // disk na kartici

SdFile rootdiska; // korenski direktorijum

const uint8_t CSpin = 10; // Chip Select pin Arduina

void setup() {

Serial.begin(9600);

Serial.println("\nInicijalizacija...");

if (!SDC.init(SPI_HALF_SPEED, CSpin)) { //postavi SCK na F_CPU/4

Serial.println("\ninicijalizacija nije uspela!");

while (1); // neuspeh, beskonacna petlja

} else {

Serial.println("Uspesna konekcija.");

}

// odredjujemo tip SD kartice

Serial.println();

Serial.print("Tip kartice: ");

switch (SDC.type()) {

case SD_CARD_TYPE_SD1: // SD1, SD2 i SDHC su vrste SD standarda

Serial.println("SD1");

break;

case SD_CARD_TYPE_SD2: // SD2 je SD standard V2

Serial.println("SD2");

break;

case SD_CARD_TYPE_SDHC: // SDHC je standard V3

Serial.println("SDHC");

break;

default:

Serial.println("nepoznat tip");

}

// pokusavamo inicijalizovati karticu

if (!disk.init(SDC)) {

Serial.println("Na kartici nije FAT16/FAT32 particija.\nFormatirajte karticu");

do {} while (1); // neuspeh, beskonacna petlja

}

Serial.print("Broj klastera: ");

Serial.println(disk.clusterCount());

Serial.print("Blokova x klastera: ");

Serial.println(disk.blocksPerCluster());

Serial.print("Ukupno Blokova: ");

Serial.println(disk.blocksPerCluster() * disk.clusterCount());

Serial.println(\n);

Serial.print("Fajl sistem: FAT");

Serial.println(disk.fatType(), DEC); // dodaj verziju FAT

//podaci o velicini skladista

uint32_t velicina = (disk.blocksPerCluster()* disk.clusterCount()) / 2;

Serial.print("Obim kartice (Kb): ");

Serial.println(velicina);

Serial.print("Obim kartice (Mb): ");

velicina /= 1024;

Serial.println(velicina);

Serial.print("Obim kartice (Gb): ");

Serial.println((float)velicina / 1024.0);

Serial.println("\nfajlovi na kartici (naziv, datum i velicina u bajtovima): ");

rootdiska.openRoot(disk);

// izlistaj sve fajlove sa nazivom, datumom i velicinom

rootdiska.ls(LS_R | LS_DATE | LS_SIZE);

}

void loop(void) { // glavnu petlju ne koristimo

}

Na početku procesa ispitujemo da li Arduino preko SPI magistrale ima komunikaciju sa modulom. Parametar SPI_HALF_SPEED, kako se i može zaključiti iz njegovog naziva, smanjuje brzinu SPI magistrale na polovinu takta Arduina Uno, što sa jedne strane rezultuje smanjenjem brzine prenosa podataka, ali sa druge pozitivno utiče na smanjenje grešaka. To podešavanje postavlja takt SCL pina na vrednost F_CPU/4. Za razliku od njega, parametar SPI_FULL_SPEED postavlja vrednost SCK na F_CPU/2, dok SPI_QUARTER_SPEED deli F_CPU sa 8. Generalno je moguće eksperimentisati sa ovim parametrima kako bi se postigao optimalan odnos brzine prenosa i suzbijanja grešaka koje nastupaju tokom tog procesa. Konstanta CSpin ukazuje na broj Arduino Uno pina koji će biti zadužen za slanje CS signala. U našem slučaju je to pin D10, ali je po potrebi moguće izabrati i neki drugi.

Ukoliko inicijacija nije uspela, program ulazi u beskonačnu petlju koja traje do restartovanja mikrokontrolera. Demonstrirana upotreba while sa parametrom 1 je često korišćen način za blokiranje rada u embedded programiranju i radi se o skraćeno napisanoj varijanti petlje Do..While, čiji je uslov uvek ispunjen.

Nakon uspešne inicijalizacije prelazimo na detekciju tipa priključene SD kartice. U okviru switch..case petlje ispitujemo tri vrste standarda. Sledi blok za inicijalizacije kartice koji funkcioniše slično procesu inicijalizacije modula. Ukoliko je on uspešno završen, pozivamo metode za utvrđivanje parametara diska, kao i tipa fajl-sistema. Posle toga sledi blok za prikazivanje kapaciteta kartice u kilobajtima, megabajtima i gigabajtima. Svaki naredni red veličine dobijamo deljenjem sa 1024. Sledi inicijalizacija korenskog direktorijuma i izlistavanje njegovog sadržaja sa podacima o nazivu, datumu i veličini datoteka.

 
Što se tiče podrške za memorijske kartice, ona obuhvata kapacitete do dva gigabajta za kartice rađene po standardima SD 1 i 2, pa do 32 gigabajta za SDHC kartice. U celu priču je potrebno uvesti i kalkulaciju vezanu za fajl-sisteme. Naime, u radu sa Arduinom podržani su FAT16 i FAT32 (postoje i biblioteke sa podrškom za druge fajl-sisteme). Uglavnom ćemo u praksi koristiti FAT16 za kartice kapaciteta do dva gigabajta i FAT32 za kartice do 32 gigabajta. Ovu rečenicu je potrebno uzeti uslovno, pošto je upotreba fajl-sistema FAT32 u većini slučajeva optimalniji izbor zbog manje veličine klastera. U pratećoj tabeli navodimo vrednosti veličine klastera za FAT16 i fAT32 u zavisnosti od veličine diska.

Kod za čitanje i pisanje podataka je, kako smo to već navikli, jednostavan i logičan. Pri mer čitanja bi mogao da izgleda ovako:

#include <SPI.h>

#include <SD.h>

File fajl;

const uint8_t CSpin = 10;

void setup() {

Serial.begin(9600);

Serial.print("\nInicijalizacija...\n");

if (!SD.begin(CSpin)) {

Serial.println("inicijalizacija nije uspela!");

while (1);

}

Serial.println("inicijalizacija je zavrsena.\n");

fajl = SD.open("tekst.txt"); // otvaramo fajl

if (fajl) { //ako je sve OK

while (fajl.available()) { // dok ima teksta...

Serial.write(fajl.read()); // ...citaj sadrzaj fajla

}// i ispisuj ga u terminal

fajl.close(); // zatvaramo fajl

} else { // ako nema fajla ili je greska

Serial.println("tekst.txt nije dostupan");

}

}

void loop() {

}

 
Nakon inicijalizacije, koja je donekle slična onoj u prvom primeru, sledi otvaranje fajla čije ime navodimo kao parametar metoda open(). Petlja while proverava da li postoji još nepročitanog teksta u fajlu, i sve dok je tako, ona čita njegov sadržaj i odmah ga ispisuje preko serijskog monitora. Kada bude pročitan i poslednji znak, datoteka se zatvara. Tokom rada sa Arduinom moguće je istovremeno raditi sa samo jednim otvorenim fajlom i ako nameravamo koristiti neki drugi, prethodno moramo zatvoriti onaj koji koristimo. Primer zapisivanja u fajl nije ništa komplikovaniji:

#include <SPI.h>

#include <SD.h>

File fajl;

void setup() {

Serial.begin(9600);

Serial.print("Inicijalizacija...\n");

if (!SD.begin(10)) {

Serial.println("\ninicijalizacija nije uspela!");

while (1);

}

Serial.println("inicijalizacija uspesno zavrsena\n");

fajl = SD.open("senzor.txt", FILE_WRITE); // otvaramo fajl

if (fajl) {

Serial.println("Fajl je uspesno otvoren\n");

} else {

Serial.println("\nGreska, fajl nije otvoren");

while (1);

}

}

void loop() {

int senzor1, senzor2;

Serial.print("SEMPL ULAZ 1 ULAZ 2\n"); // zaglavlje tabele

Serial.println("======================");

fajl.print("SEMPL,ULAZ 1, ULAZ 2\n");

fajl.println("===================");

for (int sempl = 0; sempl < 100; sempl++) // upisujemo 100 vrednosti

{

senzor1 = analogRead(0); // citamo analogne

senzor2 = analogRead(1); // portove

// pisanje podataka na karticu i na ekran

fajl.print(sempl); Serial.print(sempl);

fajl.print(",\t"); Serial.print(",\t");

fajl.print(senzor1); Serial.print(senzor1);

fajl.print(",\t"); Serial.print(",\t");

fajl.println(senzor2);Serial.println(senzor2);

delay(2000); // pauza izmedju semplova

}

Serial.println("Zavrseno prikupljanje podataka");

fajl.close(); // zatvaranje fajla

while (1);

}

Ovde smo koristili analogne pinove A0 i A1 za očitavanje vrednosti koje zapisujemo na karticu. Analogni pinovi se često koriste za povezivanje raznih vrsta senzora i vraćaju rezultate u opsegu 0-1023. Za potrebe našeg primera mogli smo da koristimo bilo koji senzor, ali za demonstraciju uopšte ne moraju da se koriste. Naime, analogni pinovi se nalaze u stanju visoke impedanse, tako da se napon na njima koleba u zavisnosti od elektromagnetskih uticaja iz okoline. To je lako proveriti prinošenjem nekog izvora tog zračenja ili jednostavno dodirivanjem pinova rukom, što izaziva znatnije promene očitanih vrednosti. Podatke sa dva ulaza svake dve sekunde upisujemo u fajl i ispisujemo na ekranu, zajedno sa brojem sempla koji dobijamo iz For..Next petlje. U okviru koda smo često koristili znakove „\n” (newline) i „\t” (tab), koji su nam od koristi prilikom prikazivanja podataka u tabelama i za prelazak u novi red bez korišćenja naredbe println(). Ostatak inicijalizacijskog koda je sličan potrebnim primerima i nije ga potrebno komentarisati.

Igor S. RUŽIĆ

 
Neptune 5.1
KmPlot 1.2.1
Spice-up 1.3.0
Arduino: Komunikacija sa memorijskim karticama
Šta mislite o ovom tekstu?
Arduino: DIY – Meteo Station (3)
Štitovi Arduina (8)
Arduino: Touch Inputi
Home / Novi brojArhiva • Opšte temeInternetTest driveTest runPD kutakCeDetekaWWW vodič • Svet igara
Svet kompjutera Copyright © 1984-2018. Politika a.d. • RedakcijaKontaktSaradnjaOglasiPretplata • Help • English
SKWeb 3.22
Opšte teme
Internet
Test Drive
Test Run
PD kutak
CeDeteka
WWW vodič
Svet igara



Naslovna stranaPrethodni brojeviOpšte informacijeKontaktOglašavanjePomoćInfo in English

Svet kompjutera