Hallo Leute,
ich habe ein Problem. Im Zuge meiner BA - Arbeit möchte ich ein SD
Karten Modul in ein Systemtelefon integrieren. Im Systeltelefon wird ein
8051 Modell verwendet (AT89C51RB2). Hier wird mit dem Keil C51 Compiler
gearbeitet.
Ich möchte nun gerne die beiden Informationsregister CID und CSD der SD
Karte auslesen. Diese sind jeweils 16 (+ 2 Byte CRC) Byte lang. Beide
Register schreibe ich in globale unsigned char Felder v_cid[18] und
v_csd[18]. Die beiden Felder beinhalten nun die ausgelesenen Daten der
SD Karten Register.
Die 16 Byte Daten des CID Registers beinhalten Informationen, wobei
einige Informationen ein Byte lange sind, andere nur wenige Bits. Um
besser an diese Informationen heranzukommen, habe ich eine Struktur
definiert:
1
typedefstruct{
2
t_ucharm_id;
3
t_ucharoem[2];
4
t_ucharpnm[5];
5
t_ucharprv;
6
longpsn;
7
unsigned:4;
8
unsignedyear:8;
9
unsignedmonth:4;
10
unsignedcrc7:7;
11
unsigned:1;
12
unsignedcrc16:16;
13
unsigned:0;
14
}T_cid;
In einer Funktion möchte ich mir nun die Informationen ausgeben lassen.
Dafür folgender Code:
1
T_cid*V_cid=(T_cid*)&v_cid[0];
Damit habe ich meine Struktur nun "über" das Feld gelegt, worin meine
Daten liegen.
Lasse ich mir nun den string "pnm" ausgeben (indem ich V_cid->pnm
anspreche), so beinhaltet dieser den product name der SD Karte. Dieser
stimmt auch mit dem Inhalt von v_cid überein.
Lasse ich mir hingegen mit V_cid->year das Jahr, bzw. mit V_cid->month
den Monat anzeigen, so stehen da falsche Werte.
Damit ihr alles nachvollziehen könnt, hier die Daten die in v_cid drin
stehen (im HEX Format):
03 53 44 53 44 30 32 47 80 70 FA 11 ED 0 0 99 4F EE E1
Die Fett markierten Hex - Ziffern sollten eigentlich das Jahr und den
Monat enthalten.
09 -> Jahr
9 -> September
Beim Zugriff erhalte ich folgende Daten:
V_cid->year = 09
V_cid->month = 00
V_cid->crc7 = 6e
Wie ihr seht steht da nicht wirklich das drin, was ich gerne hätte.
Gleiches mit dem CSD Register und dem v_csd Feld. Diesmal sieht die
Struktur so aus:
1
typedefstruct{
2
unsigned:8;
3
unsignedtaac:8;
4
unsignednsac:8;
5
unsignedtran_speed:8;
6
unsignedccc:12;
7
unsignedread_bl_len:4;
8
unsignedread_bl_part:1;
9
unsignedwrite_blk_mis:1;
10
unsignedread_blk_mis:1;
11
unsigneddsr_imp:1;
12
unsigned:2;
13
unsignedc_size:12;
14
unsignedvdd_r_cur_min:3;
15
unsignedvdd_r_cur_max:3;
16
unsignedvdd_w_cur_min:3;
17
unsignedvdd_w_cur_max:3;
18
unsignedc_size_mult:3;
19
unsignederase_blk_len:1;
20
unsignedsector_size:7;
21
unsignedwp_grp_size:7;
22
unsignedwp_grp_enable:1;
23
unsigned:2;
24
unsignedr2w_factor:3;
25
unsignedwrite_bl_len:4;
26
unsignedwrite_bl_part:1;
27
unsigned:5;
28
unsignedfile_form_grp:1;
29
unsignedcopy:1;
30
unsignedperm_w_prot:1;
31
unsignedtmp_w_prot:1;
32
unsignedfile_format:2;
33
unsigned:2;
34
unsignedcrc7:7;
35
unsigned:1;
36
unsignedcrc16:16;
37
unsigned:0;
38
}T_csd;
Die Hex-Daten im Feld v_csd sehen folgendermaßen aus:
00 26 00 32 5F 5A 83 AE FE FB CF FF 92 80 40 DF 9F C5
Ich hab das auch mal aufgeschlüsselt:
00h --> reserved bits
26h --> TAAC
00h --> NSAC
32h --> TRAN_SPEED
5fh 0101b --> CCC
1010b --> READ_BL_LEN
1b --> READ_BL_PARTIAL
0b --> WRITE_BLK_MISALIGN
0b --> READ_BLK_MISALIGN
0b --> DSR_IMP
00b --> reserved bits
11b 1010b 1110b 11b --> C_SIZE
111b --> VDD_R_CURR_MIN
110b --> VDD_R_CURR_MAX
111b --> VDD_W_CURR_MIN
110b --> VDD_W_CURR_MAX
111b --> C_SIZE_MULT
1b --> EREASE_BLK_LEN
0011111b --> SECTOR_SIZE
1111111b --> WP_GRP_SIZE
1b --> WP_GRP_ENABLE
00b --> reserved bits
100b --> R2W_FACTOR
1010b --> WRITE_BL_LEN
0b --> WRITE_BL_PARTIAL
00000b --> reserved bits
0b --> FILE_FORMAT_GRP
1b --> COPY
0b --> PERM_WRITE_PROTECT
0b --> TMP_WRITE_PROTECT
00b --> FILE_FORMAT
00b --> reserved bits
dfh --> CRC7 (+ LSB = 1)
9fh c5h --> CRC16
Beim auslesen der Daten mit V_csd kommt folgendes heraus:
V_csd->taac = 00
V_csd->tran_speed = 00
V_csd->read_bl_len = 05
V_csd->c_size_mult = 07
Wie ihr seht, passt auch hier nichts wirklich überein!
Hat irgendeiner einen Tip für mich, wie ich das nun besser hinbekomme?
Bzw. weis jemand woran das liegt?
MfG BlueMorph
Also in deinem geposteten Werten sind einige Ungereimtheiten drin.
Erstens besteht das CID aus 128 Bit im SPI und 136 Bit im SD Modus, was
genau 16/17 Bytes entsprechen. Du hast aber eine 18 Byte lange Folge für
deine CID Daten gepostet und auch bisher nicht erwähnt, in welchem Modus
du die Karte ansprichst.
Dann ist in deinem Struct am Ende ein crc16 Feld, welches es im CID
Register nicht gibt. Danach folgt noch ein leeres Feld der Länge 0 Bits,
was keinen Sinn hat.
In deinem Struct für das CSD Register hast du am Ende ebenfalls eine
CRC16 und ein 0 Bit Platzhalter, die es nicht gibt.
Lies dir mal die offizielle "Physical Layer Simplified Specification
Version 2.00" von sdcard.org [1] durch bezüglich der CID und CSD
Register.
Du solltest deine Structs erst mal korrigieren und schauen, dass du auch
nur 128 Bits für das CID und CSD Register ausliest und nicht mehr.
Ich habe bisher immer ohne struct die Daten aus den 128Bit rausgezogen
gehabt. Aber wenn ich mir so deine Structs anschaue sieht es doch
deutlich übersichtlicher aus damit zu arbeiten als dauernd mit den Bits
herumzuschubsen. :)
Ciao,
Rainer
[1] http://www.sdcard.org/developers/tech/sdcard/pls/
Hallo Leute,
@AkkiSan, vielen Dank für deine Links. Nach einigem Suchen bin ich auch
selbst auf das Dokument http://www.keil.com/support/docs/1948.htm
gestoßen. Da steht eindeutig drin, warum mein Vorhaben nicht einfach so
umzusetzen ist. Der Keilcompiler speichert eine Bitleisten Structur
einfach ziemlich doof ab (zumindest für meinen Fall).
@Fox Mulder, danke auch dir für deinen Beitrag. Zum CID / CSD Register
gehört natürlich nicht die 16 Bit CRC Checksumme, da hast du recht.
Allerdings bleibt es ja mir überlassen, was ich in meiner Structur mit
einfließen lasse. Da ja nun mal nach dem CID / CSD Register eine CRC16
Checksumme folgt habe ich diese einfach mit in die Struktur aufgenommen.
1
...
2
unsigned:0;
3
}
Das bedeutet, dass ein memoryalignment gemacht wird. Sprich, das nächste
Bit, die nächste Variable, die nächste Structur (was auch immer) beginnt
nun wieder an einer neuen Wortgrenze.
Um nun gewisse Informationen aus den Registern auszulesen habe ich mir
nun eine Funktion geschrieben, der man das Quell Datenfeld, ein
Startbit, eine Länge und ein Zielpointer übergeben kann. Dann wird die
Information aus dem Quellfeld an die Zieladresse kopiert.
MfG und vielen Dank für eure Mithilfe!
BlueMorph
Benny Nestler schrieb:> Da steht eindeutig drin, warum mein Vorhaben nicht einfach so> umzusetzen ist. Der Keilcompiler speichert eine Bitleisten Structur> einfach ziemlich doof ab (zumindest für meinen Fall).
Hallo Benny,
bitte erkläre mal genau, warum es bei dir nicht geht. Ich lege auch
structs aus Bitmasken über Datenfelder. Dazu nutze ich unions, das spart
den cast, und deklariere die Bit Strukturen mit pragma pack.
???
Als Beispiel nehme ich nun mal das Byte 14 und 15 des CID Registers
einer SD Karte. Diese beiden Bytes sind folgendermaßen eingeteilt (in
Bits):
Byte 14: 0000 yyyy
Byte 15: YYYY mmmm
y/Y - Bits enthalten "Year" - Informationen
m - Bits enthalten "month" - Informationen
die vier Nullen im Byte 14 sind reserved Bits und sind nicht mit zu
beachten.
Würde ich nun die folgende Struktur über Byte 14 und 15 legen, würde ich
diese also so deklarieren:
typedef struct {
unsigned int dontneed : 4;
unsigned int year : 8;
unsigned int month : 4;
} T_date;
Der Compiler würde nun folgendes ablegen:
- in dontneed : yyyy
- in year : 0000 mmmm
- in month : YYYY
Wie du siehst sind also über eine Union / structur die Daten nicht
wirklich zu erreichen! Zumindest ist es bei mir so. Ich betreibe die SD
Karte im SPI Mode (mit Software SPI, da der benutzte uProzessor kein SPI
hat).
Ist das okay so?
MfG BlueMorph
Warum deklarierst du die Bit Strukturen mit "int", das geht doch mit
"char" auch. Dann erübrigt sich das Problem mit der Byte Stellung.
Ich werde es die Tage mal ausprobieren.
???
Ich nehme an, dass auch wenn ich statt unsigned int, unsigned char nehme
dasselbe Problem haben werde, da der Compiler trotzdem immer mit dem LSB
eines jeden Bytes anfangen wird.
Demnach würde es den selben Effekt geben, egal, ob ich nun ein unsigned
int oder ein unsigned char nehme. Denke ich zumindest.
Mir ist gerade auch aufgefallen, dass ich im vorigen Beitrag was falsch
geschrieben habe. Ich denke der Inhalt der Strukturwerte müsste
eigentlich so aussehen:
- in dontneed : mmmm
- in year : YYYY 0000
- in month : yyyy
Wähle ich stattdessen unsigned chars, müsste die Struktur wie im vorigen
Beitrag geschrieben abgelegt werden. Also nochmal so:
- in dontneed : yyyy
- in year : 0000 mmmm
- in month : YYYY
Mit pragma pack habe ich es allerdings nocht nicht probiert! Im
Handbuch was ich über den Keil Compiler hatte, stand nichts von einem
pack! Was genau mach das #pragma pack?
MfG BlueMorph
Okay, ich bin nicht fündig geworden, ob der C51 Keil Compiler die
#pragma pack Direktive unterstützt. Laut den Erläuterungen des Keil
Forums (http://www.keil.com/support/docs/1689.htm) würde ich denken,
dass die Füll - Bytes ausgelassen werden. Da allerdings der 8051 ein 8
bit Prozessor ist, hätte ich gedacht, dass der Compiler sowieso
byteorientiert und nicht wortorientiert (2 - Byte, auf dem 8051)
arbeitet.
MfG BlueMorph