USB tömegtároló eszközosztály
A fejezet tartalma: Az USB tömegtároló eszközosztályba (USB mass storage class) azok az USB eszközök tartoznak, amelyek az USB Implementers Forum által definiált kommunikációs protokollt használva fájlok átvitelét teszik lehetővé az általuk kezet tároló és a gazdagép között. Az USB tömegtároló eszköz tehát a gazdagép felől nézve külső USB-s háttértárolónak látszik. Az eszköz felismerését és kezelését a legtöbb operációs rendszer alapértelmezetten támogatja (nem kell hozzá külön meghajtóprogramot telepíteni).
A számítógépekhez használt USB tömegtároló eszközök például:
- Külső mágneses merevlemez tárolók
- Külső optikai tárolók (CDROM, DVD)
- Hordozható flash tárolók (közismertebb nevén: pendrive, vagy USB kulcs)
- Külső szilárdtest meghajtók (SSD eszköz)
- Kártyaolvasók (SD, CF, MMC, XD, Istick stb. kártyákhoz)
- Digitális kamerák
- Hordozható hang- és médialejátszók
- Mobiltelefonok
- Végül, de nem utolsósorban ilyen USB tömegtároló
eszközként mutatkozik az mbed kompatibilis FRDM-KL25Z kártyánk
programozója is, amelybe a letöltendő programot csak bele
kell másolnunk a beégetéshez.
Az USBMSD objektumosztály
Az USBMSD objektumosztály emulálja a tömegtároló eszközt az USB kapcsolaton keresztül. Az USBMSD osztály kezeli az MSD protokollt, tisztán virtuális függvények hívásán keresztül (mint például disk_initialize, disk_write vagy disk_read) kezeli a tárolóeszközt. Az USBMSD objektumosztály önmagában nem használható: ez csupán egy generikus objektumosztály, amelynek létre kell hozni egy olyan leszármazottját, amelyben valamilyen konkrét tárolóeszköz (SD kártya, SPI flash memóris stb.) kezelését ténylegesen kidolgozzuk.A konkrét eszközhöz kidolgozandó objektumoszály tehát az USBMSD leszármazottja legyen, s az abból megörökölt, alább felsorolt virtuális függvényeket kell definiálnunk:
virtual int disk_read(uint8_t * data, uint64_t block): egy blokk beolvasása
virtual int disk_write(const uint8_t * data, uint64_t block): egy blokk írása
virtual int disk_initialize(): a tárolóeszköz inicializálása
virtual uint64_t disk_sectors(): visszaadja az adatblokkok számát
virtual uint64_t disk_size(): visszaadja a memória méretét
virtual int disk_status(): visszaadja a tárolóeszköz állapotát (0: OK, 1: nincs inicializálva,
2: nincs lemez a meghajtóban, 4: írásvédelem be van kapcsolva)
Ezek a függvények kompatibilisek a FAT fájlrendszer kezelésre szolgáló könyvtárral, így ahhoz is használhatjuk ezeket. Akár az is elképzelhető, hogy ugyanabban a programban az USB-n keresztül és helyileg is kezeljük a tárolóeszközt, csak vigyáznunk kell a kettős hozzáférésből adódó konfliktusok elkerülésére. A disk_status() felhasználásával például kialakíthatunk egy master/slave (mester/szolga) rendszert. Egy ilyen mintapélda az mbed.org oldalán is található SD_USB_FS_HelloWorld néven.
Mihelyt a fentebb felsorolt függvényeket definiáltuk, meghívhatjuk az USBMSD osztály connect() tagfüggvényét (például a leszármazott osztály konstruktorának a végén), hogy csatlakoztassuk az eszközt a gazdagéphez. A connect() meghívásakor először a disk_status() kerül meghívásra, majd a connect() függvény begyűjti a blokkok számára és a memória méretére vonatkozó információt (a megfelelő függvények meghívásával).
Az USBMSD_SD objektumosztály
Az USBMSD_SD objektumosztály egy mintapélda az USBMSD-ből leszármazott osztályra, ami egy, a mikrovezérlőnkhöz kötött SD memóriakártyát kezel. Ennek a példának a felhasználásával akár saját osztálykönyvtárat is készíthetünk, például egy memóriachip kezeléséhez.Az USBMSD_SD objektumosztálynak nincsenek olyan tagfüggvényei, amelyeket nekünk kellene meghívni, így kizárólag a konstruktorral kerülünk kapcsolatba.
Függvénynév |
Rövid leírás |
---|---|
USBMSD_SD (PinName mosi, PinName miso, PinName sclk, PinName cs ) |
SD kártya
fájlrendszerének kezelése az SPI porton keresztül |
A paraméterek:
mosi - az SPI port adatkimenete (Master Out - Slave In), a FRDM-KL25Z kártyánál ez a PTD2 kivezetés.
miso - az SPI port adatbemenete (Master In - Slave Out), a FRDM-KL25Z kártyánál ez a PTD3 kivezetés.
sclk - az SPI port órajele (SPI Clock), a FRDM-KL25Z kártyánál ez a PTD1 kivezetés
cs - az SPI port eszközkiválasztó jele (Chip Select), tetszőlegesen választott digitális kimenet.
A hardveres SPI használata miatt tehát a négy paraméterből három eleve kötött, a negyediket pedig célszerű a többi szomszédságában felvenni, így természetes választás lehet például a PTD0 kivezetés.
Mintapélda: kártyaolvasó az USBMSD_SD használatával
Az alábbi példában egy SD kártyát kezelő kártyaolvasót eszkábálunk össze, ami jól jöhet olyan esetben, amikor egy SD kártyát kellene kiolvasnunk, de nincs a számítógépünkben kártyaolvasó. A programhoz az USBMSD_SD objektumosztályt használjuk, s a konstruktor meghívásán kívül tulajdonképpen mással nem is kell foglalkoznunk.A mintaprogramot és az USBMSD_SD objektumkönyvtárat Samuel Mokrani felhasználói lapjáról vettük.
Hardver követelmények:
- FRDM-KL25Z kártya
- Egy SD kártyafoglalat a FRDM-KL25Z
kártyához csatlakoztatva
- A KL25Z USB jelzésű aljzat csatlakoztatása a számítógéphez
Bekötési vázlat:
1. ábra: Az SD kártya csatlakoztatása a FRDM-KL25Z kártyához.
Megjegyzések:
- Az SD kártya bekötésénél vigyázzunk, hogy a tápfeszültség és a jelszintek egyaránt 3,3 V-osak legyenek!
- Az ábrán látható feliratoknál DI a MOSI, DO pedig a MISO jelet jelenti.
1. lista: A 14_USBMSD_SD/main.cpp program listája
#include "mbed.h"
#include "USBMSD_SD.h"
//USBMSD_SD(PinName mosi, PinName miso, PinName sclk, PinName cs);
USBMSD_SD sd(PTD2, PTD3, PTD1, PTD0);
int main() {
while(1);
}
Sikeres programfeltöltés és csatlakozás után első alkalommal a számítógép az új eszköz felismerésére utaló felirat jelenik meg. Felismerés után a megjelenő új meghajtót megnyithatjuk és fájlműveleteket végezhetünk (mintha USB pendrive volna).
2. ábra: Az eszköz sikeres felismerése és használatba vétele
Az USBMSD_Ram objektumosztály
Az USBMSD_SD objektumosztályhoz hasonlóan a RAM_DISK (más néven USBMSD_Ram) is egy, az USBMSD-ből leszármazott osztály. Annyi a különbség, hogy ebben a FRDM-KL25Z kártya MKL25Z128VLK4mikrovezérlőjének RAM memóriájában hozunk létre egy minimális méretű (mindössze 32 x 512 bájt) FAT fájlrendszert, amelyet az USB kapcsolaton keresztül kiajánlunk a gazdagépnek. Gyakorlati haszna természetesen nincs ennek a minimalista megoldásnak, pusztán azért mutatjuk be, mert ennek felhasználásával SD kártya nélkül is kipróbálhatjuk az USBMSD eszközosztály működését.A teljes forráskód bemutatásra itt nem vállalkozunk. A lényeg a fejezet elején, az USBMSD objektumosztálynál említett virtuális függvények implementálása, ami a a 2. listán látható. A függvények a disk_image nevű adattömböt kezelik, amelyet kezdeti tartalmát inicializáláskor a flash memóriából töltjük fel egy memcpy() függvényhívással. Amint láthatjuk, a virtuális függvények többsége egyetlen programsorral megvalósítható, a szektor írása vagy olvasása, pedig csupán egy-egy memcpy() függvényhívással elintézhető.
2. lista: Az USBMSD_Ram objektumosztály implementációja (részlet a forráskódból)
...
USBMSD_Ram::USBMSD_Ram() {
//no init
_status = 0x01;
memcpy(disk_image, disk, 512*5);
connect();
}
int USBMSD_Ram::disk_initialize() {
// OK
_status = 0x00;
return 0;
}
int USBMSD_Ram::disk_write(const uint8_t * buffer, uint64_t block_number) {
memcpy((void *)&disk_image[block_number*512], buffer, 512);
return 0;
}
int USBMSD_Ram::disk_read(uint8_t * buffer, uint64_t block_number) {
memcpy(buffer, &disk_image[block_number*512], 512);
return 0;
}
int USBMSD_Ram::disk_status() { return _status; }
int USBMSD_Ram::disk_sync() { return 0; }
uint64_t USBMSD_Ram::disk_sectors() { return 32; }
uint64_t USBMSD_Ram::disk_size() { return 32*512;}
Mintapélda: Virtuális "kártyaolvasó" USBMSD_Ram használatával
Az alábbi példában egy virtuális USB kulcsot vagy kártyaolvasót készítünk, amely a FRDM-KL25Z kártya MKL25Z128VLK4 mikrovezérlőjének RAM memóriájában tárol adatokat. Ezt a mintapéldát arra az esetre ajánljuk, ha nincs kéznél SD kártya foglalt, amit a FRDM-KL25Z kártyához csatlakoztatnánk. A RAM természetesen csak addig őrzi a beleírt adatokat, amíg a tápfeszültséget meg nem szüntetjük, vagy a mikrovezérlő újra nem indul. A nyúlfarknyi főprogram gyakorlatilag semmit sem csinál. Az érdemi tevékenység (az adatok kiajánlása az USB kapcsolaton keresztül) az USBMSD_Ram programkönyvtárban történik.A mintaprogramot és az USBMSD_Ram objektumkönyvtárat Richard Green felhasználói lapjáról vettük át.
Hardver követelmények:
- FRDM-KL25Z kártya
- A KL25Z USB jelzésű aljzat csatlakoztatása a számítógéphez
#include "mbed.h"
#include "USBMSD_Ram.h"
USBMSD_Ram sd;
int main() {
while(1);
}