Forum: Projekte & Code internes files system für microcontroller [c]


von chris (Gast)


Lesenswert?

Hallo Zusammen,

bisweilen ist es von Nutzen, wenn man in einem Mikrocontroller Daten aus 
einem Filesystem nutzen kann.
Ich habe ein Programm geschrieben, welches den Inhalt eines Directories 
in ein Byte-Array umwandelt. Dieses Array kann in ein C-Programm 
eingebunden werden.
Das Ganze sieht dann so aus:
1
const uint8_t roDrive_content[]={
2
 0x68, 0x61, 0x6C, 0x6C, 0x6F, 0x2E, 0x74, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
3
 0x80, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
4
 0x68, 0x65, 0x6C, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
5
 0x9A, 0x00, 0x00, 0x00, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
6
 0x6E, 0x69, 0x78, 0x2E, 0x74, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
7
 0x9F, 0x00, 0x00, 0x00, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
8
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
9
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
10
 0x44, 0x69, 0x65, 0x73, 0x20, 0x69, 0x73, 0x74, 0x20, 0x65, 0x69, 0x6E, 0x20, 0x6B, 0x6C, 0x65, 
11
 0x69, 0x6E, 0x65, 0x72, 0x20, 0x74, 0x65, 0x73, 0x74, 0x00, 0x6C, 0x73, 0x0A, 0x0A, 0x00, 0x6E, 
12
 0x69, 0x78
13
};
14
15
16
/*
17
18
file system contents:
19
20
21
filename: hallo.txt  size:25  memory start: 128  memory end: 153
22
23
filename: help  size:4  memory start: 154  memory end: 158
24
25
filename: nix.txt  size:3  memory start: 159  memory end: 162
26
27
*/
Für den Zugriff auf diese File-System habe ich einen (fast) io.h 
kompatiblen Treiber geschrieben:
1
        extern void mx_perror (char *str);
2
        extern mx_FILE* mx_fopen (char *fileName,char *acessType);
3
        extern int16_t mx_fgetc (mx_FILE *fp);
4
        extern mx_DIR_t* mx_opendir (char * str);
5
        extern struct mx_dirent* mx_readdir (mx_DIR_t *dir);
6
        extern void mx_initFileSystem(void);

Das Ganze findet sich hier:

http://www.hobby-roboter.de/forum/download/file.php?id=132

von chris (Gast)


Angehängte Dateien:

Lesenswert?

Der Trend geht zu Python ...
Im Anhang mein erstes Python-Script, welches alle Dateien im Odner 
"files" in das oben beschrieben file.c umwandelt.

von Sven P. (Gast)


Lesenswert?

So ein paar Kleinigkeiten:
. 'true' und 'false' gibt es in <stdbool.h>.
. Es ist <string.h>, nicht "string.h", und <stdio.h>, nicht "stdio.h".
. Anstelle von <inttypes.h> wolltest du vermutlich <stdint.h>, denn dort 
sind uint8_t etc. deklariert. Auch da heißst es <stdint.h> und nicht 
"stdint.h".

Aus deinem Blog entnehme ich, dass die Sache wohl auf AVR laufen soll. 
Sollte das tatsächlich der Fall sein, dann hat dein Dateisystem 
insgesamt den ganz furchtbar blöden Nachteil, dass es stets doppelt so 
viel Speicher im Zielsystem verbraucht, als nötig. Das Dateisystem liegt 
im Programmspeicher (Flash) und wird beim Start in den Arbeitsspeicher 
(SRAM) geladen -- tödlich!

Geschickter wäre, wenn du einen Blick auf <avr/progmem.h> werfen 
würdest.

Schließlich könntest du den Zugriff ganz in <stdio.h> integrieren -- die 
Routinen hast du ja bereits fertig. Lediglich den fopen()-Aufruf 
müsstest du überarbeiten.

von chris (Gast)


Lesenswert?

Hallo Sven,

Danke für die Hinweise :-)
>So ein paar Kleinigkeiten:
>. 'true' und 'false' gibt es in <stdbool.h>.
Das wusste ich nicht. Das Programm entwickle ich immer mit dem GCC auf 
dem PC ( meisten Linux ). Ich hoffe, stdbool gibt es überall.

>. Es ist <string.h>, nicht "string.h", und <stdio.h>, nicht "stdio.h".
wird geändert.

>. Anstelle von <inttypes.h> wolltest du vermutlich <stdint.h>, denn dort
>sind uint8_t etc. deklariert. Auch da heißst es <stdint.h> und nicht
>"stdint.h".
Hmm, das ist bei mir historisch entstanden. Irgendwo hatte ich mal 
dieses Include gesehen und seit dem beibehalten. Ich werde es ändern.

>Aus deinem Blog entnehme ich, dass die Sache wohl auf AVR laufen soll.
>Sollte das tatsächlich der Fall sein, dann hat dein Dateisystem
>insgesamt den ganz furchtbar blöden Nachteil, dass es stets doppelt so
>viel Speicher im Zielsystem verbraucht, als nötig. Das Dateisystem liegt
>im Programmspeicher (Flash) und wird beim Start in den Arbeitsspeicher
>(SRAM) geladen -- tödlich!
>Geschickter wäre, wenn du einen Blick auf <avr/progmem.h> werfen
>würdest.

Ich habe mir sagen lassen, das eine neuere Funktion des avr-gcc den 
Zugriff auf das Flash automatisch richtig macht. Ab welcher Version das 
gilt, weiss ich allerdings nicht.
Die Schnittstelle des Filesystems ist so vorbereitet, dass der Zugriff 
über die Memory-Adresse byteweise geschieht. Die Verwendung der 
<avr/progmem.h> Funktionen ist also ohne Probleme möglich.

Das Filesystem soll universell auf Microcontrollern einsetzbar sein. Als 
erstes ziele ich auf die AVRs, die STM32F4 Discovery-Boards liegen aber 
schon hier rum. Dort macht es ja auch mehr Sinn, in 1MB Flash lassen 
sich schon ein paar Dateien packen.

>Schließlich könntest du den Zugriff ganz in <stdio.h> integrieren -- die
>Routinen hast du ja bereits fertig. Lediglich den fopen()-Aufruf
>müsstest du überarbeiten.

Das wäre vielleicht eine Idee. Ich weis aber nicht, wie es geht und ich 
vermute, dass der Integrationsaufwand für die unterschiedlichen 
Platformen steigt.

von Sven P. (Gast)


Lesenswert?

chris schrieb:
> Hallo Sven,
>
> Danke für die Hinweise :-)
>>So ein paar Kleinigkeiten:
>>. 'true' und 'false' gibt es in <stdbool.h>.
> Das wusste ich nicht. Das Programm entwickle ich immer mit dem GCC auf
> dem PC ( meisten Linux ). Ich hoffe, stdbool gibt es überall.
Das wurde mit dem C-Standard von 1999 aufgenommen. Sollte jeder aktuelle 
Compiler besitzen. Außer natürlich Microsoft, die sind 1989 
stehengeblieben... Dort müsste es aber beim C++-Compiler dabei sein.


>>. Es ist <string.h>, nicht "string.h", und <stdio.h>, nicht "stdio.h".
> wird geändert.
Hintergrund ist, dass mit den Winkeln ('<', '>') u.a. in den 
Systemheadern gesucht wird, das ist typischerweise dann '/usr/include/'. 
Mit Anführungszeichen referenzierst du Header, die zu deinem aktuellen 
Projekt gehören.


>>. Anstelle von <inttypes.h> wolltest du vermutlich <stdint.h>, denn dort
>>sind uint8_t etc. deklariert. Auch da heißst es <stdint.h> und nicht
>>"stdint.h".
> Hmm, das ist bei mir historisch entstanden. Irgendwo hatte ich mal
> dieses Include gesehen und seit dem beibehalten. Ich werde es ändern.
Ist auch effektiv nicht falsch, denn <inttypes.h> bindet ihrerseits 
<stdint.h> ein. Allerdings gehören die Datentypen selbst zu <stdint.h> 
und <inttypes.h> liefert dann noch eine Reihe Makros dazu, etwa zur 
Konvertierung und so. Man will/soll ja auf kürzestem Wege zum Ziel 
kommen, daher ist es sinnvoller, auch das zu schreiben, was gemeint 
ist :-)


>>Aus deinem Blog entnehme ich, dass die Sache wohl auf AVR laufen soll.
>>Sollte das tatsächlich der Fall sein, dann hat dein Dateisystem
>>insgesamt den ganz furchtbar blöden Nachteil, dass es stets doppelt so
>>viel Speicher im Zielsystem verbraucht, als nötig. Das Dateisystem liegt
>>im Programmspeicher (Flash) und wird beim Start in den Arbeitsspeicher
>>(SRAM) geladen -- tödlich!
>>Geschickter wäre, wenn du einen Blick auf <avr/progmem.h> werfen
>>würdest.
>
> Ich habe mir sagen lassen, das eine neuere Funktion des avr-gcc den
> Zugriff auf das Flash automatisch richtig macht. Ab welcher Version das
> gilt, weiss ich allerdings nicht.
Ja, die Zeiger werden auf drei Bytes verlängert und funktionieren dann 
quasi wie früher Segment:Offset. Anhand der höchsten paar Bits kann dann 
entschieden werden, wohin (RAM/ROM) der Zeiger zeigt.

Dazu musst du die Daten dann aber trotzdem noch explizit ins ROM (err, 
Flash) verschieben. Der GCC hat dazu irgendein Attribut, glaube ich.

>>Schließlich könntest du den Zugriff ganz in <stdio.h> integrieren -- die
>>Routinen hast du ja bereits fertig. Lediglich den fopen()-Aufruf
>>müsstest du überarbeiten.
>
> Das wäre vielleicht eine Idee. Ich weis aber nicht, wie es geht und ich
> vermute, dass der Integrationsaufwand für die unterschiedlichen
> Platformen steigt.
Ist recht simpel. Du musst lediglich eine fopen-Routine umsetzen. Die 
beschränkt sich einfachstenfalls auf ein Makro, dem du eine 
Lese-Zeichen- und eine Schreibe-Zeichen-Funktion übergibst. In deinem 
Fall nur eine Lese-Zeichen-Funktion.
Dadurch hast du dann gleich das ganze Repertoire mit scanf() erschlagen.

Der Effizienz halber wirst du ja ohnehin irgendwie auf 
Präprozessor-Schalter setzen müssen. Allein schon wegen der Sache mit 
ROM und RAM. Da könnte man das dan gut unterbringen.

von chris (Gast)


Lesenswert?

Hallo Sven,

hier habe ich die meisten von dir vorgeschlagenen Änderungen gemacht:
http://www.hobby-roboter.de/forum/download/file.php?id=133

Das File System habe ich für den Arduino portiert. Es war mehr Arbeit 
als ich dachte, weil ich Probleme mit dem Zusammenkompilieren der 
Arduino cpp-Files und meinen in C-geschriebenen Routinen hatte. Das 
Debugging gestaltet sich auf dem Arduino auch etwas schwieriger als auf 
dem PC.
Nichts desto trozt läuft es jetzt. Das Ganze ist für die Arduino IDE 1.0 
und müsste für die älteren IDEs mit den *.pde files neu kompiliert 
werden. Das Besondere an der IDE 1.0 ist, dass die Files im Klartext 
vorligen. Das Main-File hat die Endung *.ino statt *.cpp.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.