Winbond SpiFlash memóriák kezelése Bascom-ban
Winbond SpiFlash memóriák kezelése Bascom-ban
Nemrég egy mérésadatgyűjtőt kellett terveznem. A feladat az volt, hogy egy fűtési rendszer vélt anomáliáit kellett feltárni. Ez a gyakorlatban annyit jelentett, hogy egy adott helységben egy elektronikus hőmérőt kellett elhelyezni, amely folyamatosan mérte a hőmérsékletet, és azt egy memóriában tárolta.
A mérési eredményeket egy percenként kellett tárolni. Így 24 óra alatt 1440 eredmény született, ami 2880 byte/nap, hiszen az adatokat 16 biten lehet tárolni. Csakhogy a teljes mérési intervallum két hét volt, azaz 40320 bájt tárolását kellett megoldani. Mivel elképzelhető volt, hogy hosszabb, akár egy teljes hónap adatait is tárolni kell (1 382 400 bájt!), így az I2C buszos eepromok kiestek a választásból (ehhez a feladathoz kevés a kapacitásuk). Az SD vagy MMC kártyákkal pedig az volt a gond, hogy egyrészt a foglalat és a kártya többe kerül, mint a később ismertetendő memóriák, valamint a kiolvashatóság szempontjából (közvetlen elérés) csakis laptop, azaz USB csatlakozó felület jöhetett szóba. Szintén a kártya ellen szól a feladathoz képest túl nagy kapacitás (felesleges), ill. a nehézkes kezelés Bascom alól + a feladathoz képest túl "nagy" processzort igényel az AVR-DOS.
A Winbond W25... sorozatú flash ramjai rendkívül olcsóak (a 2MB-os változat ezen sorok írásakor nettó 105Ft!), és könnyen kezelhetők. Rendkívül jó adatlapokat írtak hozzájuk, így a feladatok programozása is viszonylag könnyen ment.
Azért, hogy más ne kűzdje végig magát az egyes feladatok programozásán, közreadom azokat a szubrutinokat, melyekkel a legalapvetőbb memóriakezelés megoldható. Talán másnak is szüksége lehet még rá!
A Winbond honlapján ott a teljes választék, én most csak a W25P16 kezelését részletezem (2MB), de ez alapján a kisebb/nagyobb kapacitású változatok kezelése is megoldható.
A ram adatlapját célszerű áttanulmányozni, mert itt nem fogok mindent teljes részletében ismertetni!
Folyt. köv.!
A mérési eredményeket egy percenként kellett tárolni. Így 24 óra alatt 1440 eredmény született, ami 2880 byte/nap, hiszen az adatokat 16 biten lehet tárolni. Csakhogy a teljes mérési intervallum két hét volt, azaz 40320 bájt tárolását kellett megoldani. Mivel elképzelhető volt, hogy hosszabb, akár egy teljes hónap adatait is tárolni kell (1 382 400 bájt!), így az I2C buszos eepromok kiestek a választásból (ehhez a feladathoz kevés a kapacitásuk). Az SD vagy MMC kártyákkal pedig az volt a gond, hogy egyrészt a foglalat és a kártya többe kerül, mint a később ismertetendő memóriák, valamint a kiolvashatóság szempontjából (közvetlen elérés) csakis laptop, azaz USB csatlakozó felület jöhetett szóba. Szintén a kártya ellen szól a feladathoz képest túl nagy kapacitás (felesleges), ill. a nehézkes kezelés Bascom alól + a feladathoz képest túl "nagy" processzort igényel az AVR-DOS.
A Winbond W25... sorozatú flash ramjai rendkívül olcsóak (a 2MB-os változat ezen sorok írásakor nettó 105Ft!), és könnyen kezelhetők. Rendkívül jó adatlapokat írtak hozzájuk, így a feladatok programozása is viszonylag könnyen ment.
Azért, hogy más ne kűzdje végig magát az egyes feladatok programozásán, közreadom azokat a szubrutinokat, melyekkel a legalapvetőbb memóriakezelés megoldható. Talán másnak is szüksége lehet még rá!
A Winbond honlapján ott a teljes választék, én most csak a W25P16 kezelését részletezem (2MB), de ez alapján a kisebb/nagyobb kapacitású változatok kezelése is megoldható.
A ram adatlapját célszerű áttanulmányozni, mert itt nem fogok mindent teljes részletében ismertetni!
Folyt. köv.!
Az ic - sajnos - a 3V-os eszközök családját gazdagítja, a már megszokott 5V-ot nem "szereti". Ám a teljes áramkörnek ez volt az egyetlen 3,3V-os része, így kapott egy külön stabilizátort, és a más fórumokon már ismertetett mezei ellenállásosztón keresztül kapcsolódik az AVR spi buszához, mégpedig így:
/CS : avr tetszőleges lába
DO : MISO
DI : MOSI
CLK : SCK
A /WP és a /HOLD lábakat egy-egy 10k-os ellenállással a tápfeszültség pozitív ágára kell kötni, a használatuk a saját alkalmazásomban szükségtelen volt, az adatlap részletesen leírja, mire jók ezek.
A Vcc kivezetés közelébe "illik" tenni egy 100n-os hidegítő kondit.
És ami még az elején nagyon "megszívatott": a /CS lábra kell egy felhúzó ellenállás (4,7k...10k, nem kritikus).
FONTOS!
Az AVR programozásakor a ram kivezetései ne kapjanak +5V-ot!
Ennyit a hardverről, jöhet a program!
Nem közlök teljes programot, így a változók, szubrutinok deklarálásával sem foglalkozom külön. Minimális Bascom-jártasság mellett nem okozhat problémát az alábbi programrészletek átírása, beillesztése a saját alkalmazásba! Ha valaki elakadna, keressen privátban, szívesen segítek!
Némi magyarázat: nálam Atmega 8-cal csak ebben a konfigurációban működött a memória kezelése. Ha a NOSS kapcsolót 1-re állítottam, már nem értem el a ramot.
Van két azonosító beégetve a ramba, melyet ki tudunk olvasni. Ha ez működik, akkor áramkörileg rendben van minden.
Az első a JEDEC azonosító, amely ennél a típusnál három bájt, mégpedig:
9F 20 15
A saját alkalmazásomban egy kétsoros lcd kijelző is szerepelt, így mindenféle adatot oda írattam ki.
A mem_p egy előzetesen deklarált byte típusú változó, a bejon() szintén (értelemszerűen tömb), az Stbit pedig egy másik szubrutin (a Call utasítás nem szükséges, ha nincs paraméterezve a szubrutin!), amely itt látható, és fontos feladata van:
Nos, vesézzük ki kicsit a fentieket!
A mem_p változóba a mindenkori flashramot kezelő utasítás kódja kerül. Amikor dolgozni akarunk a rammal, a Chip lábat alacsony szintre állítjuk.
Kiírjuk a parancsot, és amennyiben van visszatérő adat, azt beolvassuk valamilyen változó(k)ba. A feladat végeztével ellenőrizzük a status bitet, ami csak akkor lesz nulla, ha az adott feladatot a ram elvégezte!
Ha ez rendben, akkor a Chip láb újból magas szintre kerül.
Nagyjából minden utasítás esetén ez a procedúra zajlik le.
Az, hogy mire jó a "parameter page", és hogyan kell törölni a memóriát, illetve milyen egyéb sajátosságok vannak még, arról majd legközelebb!
/CS : avr tetszőleges lába
DO : MISO
DI : MOSI
CLK : SCK
A /WP és a /HOLD lábakat egy-egy 10k-os ellenállással a tápfeszültség pozitív ágára kell kötni, a használatuk a saját alkalmazásomban szükségtelen volt, az adatlap részletesen leírja, mire jók ezek.
A Vcc kivezetés közelébe "illik" tenni egy 100n-os hidegítő kondit.
És ami még az elején nagyon "megszívatott": a /CS lábra kell egy felhúzó ellenállás (4,7k...10k, nem kritikus).
FONTOS!
Az AVR programozásakor a ram kivezetései ne kapjanak +5V-ot!
Ennyit a hardverről, jöhet a program!
Nem közlök teljes programot, így a változók, szubrutinok deklarálásával sem foglalkozom külön. Minimális Bascom-jártasság mellett nem okozhat problémát az alábbi programrészletek átírása, beillesztése a saját alkalmazásba! Ha valaki elakadna, keressen privátban, szívesen segítek!
Kód: Egész kijelölése
'SPI konfigurálása
Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = High , Phase = 1 , Clockrate = 64 , Noss = 0
Spiinit
'Chip Select láb kezelése a D.4 portlábbal történik
'Ha a NOSS = 1, azaz a hardveres SS láb belső kezelését tiltjuk,
'nem működik a kapcsolat!
Chip Alias Portd.4
Config Pind.4 = Output
Set Chip
Van két azonosító beégetve a ramba, melyet ki tudunk olvasni. Ha ez működik, akkor áramkörileg rendben van minden.
Az első a JEDEC azonosító, amely ennél a típusnál három bájt, mégpedig:
9F 20 15
Kód: Egész kijelölése
Sub Jedec
Mem_p = &H9F
Reset Chip
Spiout Mem_p , 1
Spiin Bejon(1) , 3
Set Chip
Stbit
Cls
Lcd Hex(bejon(1)) ; " " ; Hex(bejon(2)) ; " " ; Hex(bejon(3))
Wait 1
Cls
End Sub
A mem_p egy előzetesen deklarált byte típusú változó, a bejon() szintén (értelemszerűen tömb), az Stbit pedig egy másik szubrutin (a Call utasítás nem szükséges, ha nincs paraméterezve a szubrutin!), amely itt látható, és fontos feladata van:
Kód: Egész kijelölése
Sub Stbit
St_bit = 0
Kezd:
Mem_p = &H05
Reset Chip
Spiout Mem_p , 1
Spiin Dummy , 1
Set Chip
St_bit = Dummy.0
If St_bit = 0 Then Exit Sub
Goto Kezd
St_bit = 0
End Sub
A mem_p változóba a mindenkori flashramot kezelő utasítás kódja kerül. Amikor dolgozni akarunk a rammal, a Chip lábat alacsony szintre állítjuk.
Kiírjuk a parancsot, és amennyiben van visszatérő adat, azt beolvassuk valamilyen változó(k)ba. A feladat végeztével ellenőrizzük a status bitet, ami csak akkor lesz nulla, ha az adott feladatot a ram elvégezte!
Ha ez rendben, akkor a Chip láb újból magas szintre kerül.
Nagyjából minden utasítás esetén ez a procedúra zajlik le.
Az, hogy mire jó a "parameter page", és hogyan kell törölni a memóriát, illetve milyen egyéb sajátosságok vannak még, arról majd legközelebb!
Köszönjük a részletes leírást, engem is érdekelnek az SPI Flash RAM-ok...régen
elkezdtem vele foglalkozni, de utána időhiány miatt le kellett állnom vele.
Majd nemsokára újra foglalkozom vele, akkor lehet sok kérdésem lesz feléd!
Most előljáróban annyi, hogy én Atmel 45DBXX-es szériával kezdtem, amiket a TME-től rendeltem. A kérdésem az lenne, hogy a Winbond-os chipeket honnan lehet beszerezni?
Üdv: Higgins
elkezdtem vele foglalkozni, de utána időhiány miatt le kellett állnom vele.
Majd nemsokára újra foglalkozom vele, akkor lehet sok kérdésem lesz feléd!
Most előljáróban annyi, hogy én Atmel 45DBXX-es szériával kezdtem, amiket a TME-től rendeltem. A kérdésem az lenne, hogy a Winbond-os chipeket honnan lehet beszerezni?
Üdv: Higgins
Ezeket a memóriákat a Chipcad árusítja. A W25P.. sorozattal már leállt a Winbond, helyette a W25X.. sorozatot gyártják jelenleg. Utóbbi kompatibilis a régivel, így a programot sem kell módosítani.
Nekem is van itthon egy Atmel Flash, de "érintetlen", az adatlapját összevetve a Winbond-éval, az utóbbi mellett döntöttem.
A leírást este folytatom!
Nekem is van itthon egy Atmel Flash, de "érintetlen", az adatlapját összevetve a Winbond-éval, az utóbbi mellett döntöttem.
A leírást este folytatom!
Íme a folytatás:
A flashram felépítéséről bőven találni mindenféle információt az adatlapban.
Számunkra fontos:
-Maga a "klasszikus" tárterület a W25P16 esetén 1FFFFF, azaz 2097151 bájt, másképpen 16 Mbit.
-Létezik egy 256 bájtos tárterület, amely az előzőtől teljesen függetlenül kezelhető, ez az ún. Parameter Page. A tárhelykezeléshez használtam, ami mindössze 3 bájtot foglalt le ebből, de erről majd később.
-A tárterület és a parameter page egymástól függetlenül törlendő. Azaz, ha a Chip Erase parancsot kiadjuk, a parameter page érintetlen marad. A ram teljes törléséhez utóbbit is törölni kell.
-A memória feltöltésénél elegendő a kezdő címet megadni. Utána folyamatosan lehet írni az adatokat. Arra azonban ügyelni kell, hogy az egyszer már lefoglalt tárhelyre csak egy törlést követően lehet ismételten írni!
Korábban nem foglalkoztam memóriákkal, így némi fejtörést okozott, hogy miként állapítsam meg, hogy mi volt az utolsó lefoglalt bájt címe, hogy a következő írási műveletet a következő szabad bájt címétől kezdjem. Nos, erre kiválóan alkalmas a parameter page! A cím három bájtból áll, ezt célszerűen a parameter page első három regiszterébe írom. A következő beírás előtt természetesen törölni kell a parameter page-t, de ez kb. 100ms-ot igényel, az alkalmazás működésében nem okozott zavart. A tárhely teljes törlése egyébként kb. 12s ideig tart.
Van egy nagyon fontos tulajdonság, amit szem előtt kell tartani az adatkezelés során:
A flashram alapértelmezett egysége a szó, azaz két bájt! Tehát az adatok darabszáma a beíráskor csak páros szám lehet. Így az írási művelet során a kezdő tárcímnek is páros számnak kell lennie. Egyszeri címmegadással egy lapot, azaz 256 bájtot lehet közvetlenül beírni. Ennél több adat megadásakor ismét ki kell adni az írási parancsot a tárhely címének megadásával.
Szintén fontos szabály, hogy írási műveletek előtt mindig engedélyezni kell az írást, erre a Write Enable parancs szolgál.
Holnap jönnek a hiányzó szubrutinok, és még pár gondolat a flashram kezeléséről...
A flashram felépítéséről bőven találni mindenféle információt az adatlapban.
Számunkra fontos:
-Maga a "klasszikus" tárterület a W25P16 esetén 1FFFFF, azaz 2097151 bájt, másképpen 16 Mbit.
-Létezik egy 256 bájtos tárterület, amely az előzőtől teljesen függetlenül kezelhető, ez az ún. Parameter Page. A tárhelykezeléshez használtam, ami mindössze 3 bájtot foglalt le ebből, de erről majd később.
-A tárterület és a parameter page egymástól függetlenül törlendő. Azaz, ha a Chip Erase parancsot kiadjuk, a parameter page érintetlen marad. A ram teljes törléséhez utóbbit is törölni kell.
-A memória feltöltésénél elegendő a kezdő címet megadni. Utána folyamatosan lehet írni az adatokat. Arra azonban ügyelni kell, hogy az egyszer már lefoglalt tárhelyre csak egy törlést követően lehet ismételten írni!
Korábban nem foglalkoztam memóriákkal, így némi fejtörést okozott, hogy miként állapítsam meg, hogy mi volt az utolsó lefoglalt bájt címe, hogy a következő írási műveletet a következő szabad bájt címétől kezdjem. Nos, erre kiválóan alkalmas a parameter page! A cím három bájtból áll, ezt célszerűen a parameter page első három regiszterébe írom. A következő beírás előtt természetesen törölni kell a parameter page-t, de ez kb. 100ms-ot igényel, az alkalmazás működésében nem okozott zavart. A tárhely teljes törlése egyébként kb. 12s ideig tart.
Van egy nagyon fontos tulajdonság, amit szem előtt kell tartani az adatkezelés során:
A flashram alapértelmezett egysége a szó, azaz két bájt! Tehát az adatok darabszáma a beíráskor csak páros szám lehet. Így az írási művelet során a kezdő tárcímnek is páros számnak kell lennie. Egyszeri címmegadással egy lapot, azaz 256 bájtot lehet közvetlenül beírni. Ennél több adat megadásakor ismét ki kell adni az írási parancsot a tárhely címének megadásával.
Szintén fontos szabály, hogy írási műveletek előtt mindig engedélyezni kell az írást, erre a Write Enable parancs szolgál.
Holnap jönnek a hiányzó szubrutinok, és még pár gondolat a flashram kezeléséről...
Itt a befejező rész! Ígértem a hiányzó szubrutinokat, íme:
Parameter Page kezelése:
Nos, az előző hozzászólások kapcsán talán érthető, mi történik ebben a hosszú szubrutinban. Először is kiolvassuk a parameter page első három bájtját, ahol mindig a következő szabad memória címét tároljuk.
Ha megvan a cím, és az nem FFFFFF (törölt állapot), és nem 1FFFFF (megtelt memória), akkor az ott lévő címhez kettőt hozzáadunk (vagy amennyi a saját alkalmazásunknál szükséges), és a Parameter Page törlését követően visszaírjuk az új címnek megfelelő bájtokat.
Értelemszerűen a törölt és a megtelt állapot vizsgálatánál nem feltétlenül egy lcd-re írandó szöveget kell kezelni, oda a vizsgált állapotnak megfelelő tevékenyégeknek kell kerülni.
Itt található a Parameter Page és a ram törlő szubrutinja:
Az alábbi két szubrutin engedélyezi ill. tiltja a memória írását. Egyes parancsok esetén kötelező a használatuk (lásd: a flashram adatlapja!)
Elérkeztünk a konkrét adatkezeléshez.
Ha kiolvastuk a parameter page-ből a címet, írjuk be az adatokat!
A tömb értelemszerűen bővíthető. A ténylegesen tárolandó adatok a tömb 5. elemétől kezdődően adandók meg. Ez nálam a korábban említett hőmérsékleti érték két bájtja.
Ha van tárolt adat, azt ki is kell olvasni:
A beolvasott adatok itt is egy tömbbe kerülnek. Hogy később mit kezdünk az adatokkal, az már a saját elképzelésünk függvénye.
Nos, ennyi lett volna dióhéjban.
Vannak még további parancsok, lehetőségek a flashram kezelésével kapcsolatban, ám a fentiek alapján egy adattárolást, adatkezelést már némi programozási munkával könnyedén meg lehet valósítani.
Értelemszerűen a fenti programrészleteket meg lehetett volna írni szebben, egyszerűbben, jobban, máshogy, stb. Ám a memória kezelését így is meg lehet oldani. Ha valakinek egy-egy megoldás nem szimpatikus, természetesen átformálhatja a szubrutinokat.
Ha még eszembe jut valami fontos, azt beírom majd.
Kérdezzetek bátran, ha tudok, segítek!
Parameter Page kezelése:
Kód: Egész kijelölése
Sub Parameter_page
Address = 0 'Long típusú változó!
Ki1(1) = &H53 'read parameter page
Ki1(2) = &H00 'address 3 byte
Ki1(3) = &H00 '000000
Ki1(4) = &H00
Reset Chip
Spiout Ki1(1) , 4
Spiin Bejon(1) , 3
Set Chip
Addr_u = Bejon(1)
Addr_m = Bejon(2)
Addr_l = Bejon(3)
' ------------------------------------------------------------------------------
' Cím ellenőrzése
' ------------------------------------------------------------------------------
'Parameter page törölt?
If Address = &HFFFFFF Then
Address = 0
Locate 1 , 1
Lcd "Flash: ures!"
Wait 2
Cls
Goto Zero
End If
' A memória megtelt? (Address = 1FFFFF)
If Address = &H1FFFFF Then
Locate 1 , 1
Lcd "Flash: full !!!"
End If
Address = Address + 2
Zero:
Clear_pp
Ki(1) = &H52 'parameter page write
Ki(2) = &H00 'dummy
Ki(3) = &H00 'dummy
Ki(4) = &H00 'address
Ki(5) = Addr_u 'data1
Ki(6) = Addr_m 'data2
Ki(7) = Addr_l 'data3
Ki(8) = &H00 'data4 -> üres, a páros bájtok miatt kell!
Write_en
Reset Chip
Spiout Ki(1) , 8
Set Chip
Stbit
Cls
End Sub
Ha megvan a cím, és az nem FFFFFF (törölt állapot), és nem 1FFFFF (megtelt memória), akkor az ott lévő címhez kettőt hozzáadunk (vagy amennyi a saját alkalmazásunknál szükséges), és a Parameter Page törlését követően visszaírjuk az új címnek megfelelő bájtokat.
Értelemszerűen a törölt és a megtelt állapot vizsgálatánál nem feltétlenül egy lcd-re írandó szöveget kell kezelni, oda a vizsgált állapotnak megfelelő tevékenyégeknek kell kerülni.
Itt található a Parameter Page és a ram törlő szubrutinja:
Kód: Egész kijelölése
Sub Clear_mem ' clear flash ram
Write_en
Mem_p = &HC7
Reset Chip
Spiout Mem_p , 1
Set Chip
Stbit
End Sub
Sub Clear_pp ' clear parameter page
Write_en
Mem_p = &HD5
Reset Chip
Spiout Mem_p , 1
Set Chip
Stbit
End Sub
Kód: Egész kijelölése
Sub Write_dis ' write disable
Mem_p = &H04
Reset Chip
Spiout Mem_p , 1
Set Chip
End Sub
Sub Write_en ' write enable
Mem_p = &H06
Reset Chip
Spiout Mem_p , 1
Set Chip
End Sub
Ha kiolvastuk a parameter page-ből a címet, írjuk be az adatokat!
Kód: Egész kijelölése
Sub Write_data
Adatok(1) = &H02
Adatok(2) = Addr_u
Adatok(3) = Addr_m
Adatok(4) = Addr_l
Adatok(5) = Tm
Adatok(6) = Tl
Write_en
Mem_p = &H02
Reset Chip
Spiout Adatok(1) , 6
Set Chip
Stbit
Write_dis
End Sub
Ha van tárolt adat, azt ki is kell olvasni:
Kód: Egész kijelölése
Sub Read_data
Adatok(1) = 0
Adatok(2) = 0
Ki(1) = &H03
Ki(2) = Addr_u
Ki(3) = Addr_m
Ki(4) = Addr_l
Reset Chip
Spiout Ki(1) , 4
Spiin Adatok(1) , 2
Set Chip
Stbit
End Sub
Nos, ennyi lett volna dióhéjban.
Vannak még további parancsok, lehetőségek a flashram kezelésével kapcsolatban, ám a fentiek alapján egy adattárolást, adatkezelést már némi programozási munkával könnyedén meg lehet valósítani.
Értelemszerűen a fenti programrészleteket meg lehetett volna írni szebben, egyszerűbben, jobban, máshogy, stb. Ám a memória kezelését így is meg lehet oldani. Ha valakinek egy-egy megoldás nem szimpatikus, természetesen átformálhatja a szubrutinokat.
Ha még eszembe jut valami fontos, azt beírom majd.
Kérdezzetek bátran, ha tudok, segítek!
Ejha!Köszönjük szépen az értékes információkat!Szerintem sokat segítettél ezzel másoknak! Nekem legalább is biztos!
Ha jól sejtem, akkor a leírásod alapján akár az Atmel-es 45DBXX-es szériát is lehet kezelni,legalább is hasonló gondolatmenet alapján!
Említetted, hogy a két memóriatípust összehasonlítottad. Mi volt a két memória közötti különbség, hogy végül a Winbond mellett tetted le a voksod?
Üdv: Higgins
Ha jól sejtem, akkor a leírásod alapján akár az Atmel-es 45DBXX-es szériát is lehet kezelni,legalább is hasonló gondolatmenet alapján!
Említetted, hogy a két memóriatípust összehasonlítottad. Mi volt a két memória közötti különbség, hogy végül a Winbond mellett tetted le a voksod?
Üdv: Higgins
A Dummy által közölt kódrészleteket összefésülve. És az egészet lefordítható állapotba hozva nekem 1600 Byte Flash Mem. + ehhez még hozzá jön az egészet működtető kódrész, ami alkalmazásonként más lehet. És a sok Szubrutin hívás miatt a stackok is nagyok + vannak tömbök 4*8. Ehez kevés az SRAM-is!
Szerintem sem fér bele az attiny2313-ba!
Szerintem sem fér bele az attiny2313-ba!
Miért szenvedsz?
Van a Chipcadnál 5V-os is 4KBytes 150FT!
http://www.datasheetarchive.com/25C320T ... sheet.html
Adatlap itt
Van a Chipcadnál 5V-os is 4KBytes 150FT!
http://www.datasheetarchive.com/25C320T ... sheet.html
Adatlap itt