Forum: Mikrocontroller und Digitale Elektronik FatFs mit Fifo Bibliothek von Falk Brunner, Fifo behält trotz Auslesen und read_bursted Restdaten.
Guten Tag,
ich benutze in einem AVR Programm FatFS zusammen mit der FIFO
Bibliothek von Falk Brunner.
Die grundsätzliche Idee war:
Ein AD Wandler misst eine Spannung und im ADC Interrupt wird der Wert in
den Fifo geschrieben. Hat der Fifo einen gewissen "Füllstand" erreicht,
schreibe ich die Werte mit FatFS auf eine SD Karte, sofern das Schreiben
aktiviert ist.
Ist das Schreiben nicht mehr aktiviert, es befinden sich aber noch Daten
im Fifo, so sollen diese auch auf die SD Karte geschrieben werden.
Den Schreib- und Lesezugriff auf den Fifo habe ich aus der Beispieldatei
main_fifo.c übernommen.
Nachdem ich im normalen Betrieb Daten auf die Karte geschrieben und dann
den Schreibmodus deaktiviert habe, sollten eigentlich die im Fifo
verbliebenen Restdaten einmalig auf die SD Karte geschrieben werden.
Danach wird der Füllstand des Fifos aktualisiert und er sollte nach
meinem Verständnis leer sein.
Das Problem ist, dass der Füllstand des Fifos in meinem Programm laut
fifo_get_level() allerdings nie den Wert 0 erreicht. Der Programmteil,
der die Restdaten eigentlich nur einmalig abspeichern soll, wird
fortlaufend aufgerufen.
Nach meinem Verständnis sollte der Füllstand nach dem Schreiben mit
f_write und der Korrektur des Lesezeigers mit fifo_read_bursted
eigentlich den Wert 0 erreichen. Das tut er aber nicht.
Scheinbar übersehe ich irgendetwas oder benutze die Fifo Funktionen
falsch.
Wäre schön wenn jemand einen Blick auf den Code werfen könnte und mir
zeigt, was ich falsch mache.
Ich kann mir das Verhalten im Augenblick nicht so recht erklären.
In der fertigen Textdatei sieht das dann so aus: (steht alles
hintereinander, zur Verdeutlichung leicht gekürzt und formatiert) 1 | abcbccccccccc[...]bcccccccccbccc (617 Zeichen/Byte)
| 2 | x(NUL)[...]404 "NUL"[...](NUL)abcbccccccccc[...]bcccccccccbccc (617 Zeichen/Byte)
| 3 | xxx(NUL)[...]402 "NUL"[...](NUL)abcbccccccccc[...]bcccccccccbccc (617 Zeichen/Byte)
| 4 | xxxxx(NUL)[...]400 "NUL"[...](NUL)abcbccccccccc[...]bcccccccccbccc (617 Zeichen/Byte)
| 5 | xxxxxxx(NUL)[...]398 "NUL"[...](NUL)abcbccccccccc[...]bcccccccccbccc (617 Zeichen/Byte)
| 6 |
| 7 | usw.
|
Man sieht einen Zusammenhang zwischen den zunehmenden "x" und den
abnehmenden "NUL".
Aber woher zieht er die "NUL", die er auf die Karte schreibt und wieso
steigt die Anzahl der "x"?
Die UART Ausgaben im Code ergeben: 1 | 00507 // Ausgabe des Fifo Füllstandes mittels "uart_uint(fifo_get_level(&fifo),5);"
| 2 | 00512
| 3 | Schreibvorgang: 00512
| 4 | 00005
| 5 | 00010
| 6 | 00015
| 7 | 00020
| 8 | 00025
| 9 | 00030
| 10 | 00035
| 11 | 00040
| 12 | 00045
| 13 | 00050
| 14 | 00055
| 15 | 00060
| 16 | 00065
| 17 | 00070
| 18 | 00075
| 19 | 00080
| 20 | 00085
| 21 | 00090
| 22 | 00095
| 23 | 00100
| 24 | 00105 // Hier wird der Schreibvorgang manuell beendet, Schreiben der Reste soll beginnen
| 25 | Restdaten speichern: 00105 //fifo_get_level unmittelbar nach Eintritt, kurz danach wird das 'x' in den Fifo
| 26 | blocksize 00512 // Wert von fifo_block_size
| 27 | wrapsize 00512 // Wert von fifo_wrap_size
| 28 | level ende 00618 // fifo_get_level nach der Korrektur des Lesezeigers durch fifo_read_bursted
| 29 | Restdaten speichern: 00618 // Funktion wird neu aufgerufen
| 30 | blocksize 00512
| 31 | wrapsize 01024
| 32 | level ende 00107
| 33 | Restdaten speichern: 00107
| 34 | blocksize 00512
| 35 | wrapsize 00512
| 36 | level ende 00620
| 37 | Restdaten speichern: 00620
| 38 | blocksize 00512
| 39 | wrapsize 01024
| 40 | level ende 00109
| 41 | Restdaten speichern: 00109
| 42 | blocksize 00512
| 43 | wrapsize 00512
| 44 | level ende 00622
| 45 | Restdaten speichern: 00622
| 46 | blocksize 00512
| 47 | wrapsize 01024
| 48 | level ende 00111
| 49 | Restdaten speichern: 00111
| 50 | blocksize 00512
| 51 | wrapsize 00512
| 52 | level ende 00624
| 53 | Restdaten speichern: 00624
| 54 | blocksize 00512
| 55 | wrapsize 01024
| 56 | level ende 00113
|
Der Code sieht in Auszügen so aus:
Main.h: 1 | #define fifo_buffersize 1024
| 2 | #define fifo_writesize 512
|
Main.c: 1 | fifo_t fifo;
| 2 | fifo_data_t fifo_bufferarray[fifo_buffersize];
| 3 |
| 4 |
| 5 | ISR(ADC_vect){
| 6 | if(SDcard_ready && AnalogChannel.WriteEnable){
| 7 | if(fifo_get_free_ISR(&fifo)){
| 8 | if(fifo_write_code0&(1<<i)){
| 9 | fifo_write_ISR(&fifo,'a'); // bei Start des Schreivorgangs
| 10 | fifo_write_code0&=~(1<<i);
| 11 | } else if ((AnalogChannel.Abtastfreq==1)||fifo_write_code1&(1<<i)){ // jede Sekunde
| 12 | fifo_write_ISR(&fifo,'b');
| 13 | fifo_write_code1&=~(1<<i);
| 14 | } else {
| 15 | fifo_write_ISR(&fifo,'c');
| 16 | }
| 17 | }
| 18 | }
| 19 | }
| 20 |
| 21 |
| 22 | int main(){
| 23 | [...]
| 24 | fifo_init(&fifo, fifo_bufferarray,sizeof(fifo_bufferarray)/sizeof(fifo_data_t));
| 25 | uint16_t fifo_wrap_size;
| 26 | uint16_t fifo_block_size=fifo_writesize;
| 27 |
| 28 | while(1){
| 29 | [...]
| 30 |
| 31 | // Normaler Schreibvorgang auf SD Karte
| 32 | if(SDcard_ready && (fifo_get_level(&fifo)>=fifo_block_size) && writeEnableCheck()){
| 33 | uart_puts("Schreibvorgang:\t");
| 34 | uart_uint(fifo_get_level(&fifo),5);
| 35 | uart_putc('\n');
| 36 |
| 37 | fifo_wrap_size = fifo_get_read_wrap(&fifo);
| 38 |
| 39 |
| 40 | if (fifo_block_size > fifo_wrap_size) {
| 41 | // split action into two blocks due to pointer wrap around
| 42 | f_write(&file1, (uint8_t*)fifo.read_p, fifo_wrap_size * sizeof(fifo_data_t), &fatfs_bytes_written);
| 43 | fifo_read_bursted(&fifo, fifo_wrap_size);
| 44 | fifo_block_size -= fifo_wrap_size;
| 45 | }
| 46 | // no pointer wrap around in block or second half of block operation
| 47 |
| 48 | f_write(&file1, (uint8_t*)fifo.read_p, fifo_block_size * sizeof(fifo_data_t), &fatfs_bytes_written);
| 49 | fifo_read_bursted(&fifo, fifo_block_size);
| 50 |
| 51 | }
| 52 |
| 53 |
| 54 |
| 55 | // Inhalt des Fifo auf Karte schreiben, wenn kein Kanal mehr loggt, aber noch Daten im Fifo liegen
| 56 | if( !writeEnableCheck() && SDcard_ready && fifo_get_level(&fifo)){
| 57 | uart_puts("Restdaten speichern:\t"); // UART "Restdaten speichern"
| 58 | uart_uint(fifo_get_level(&fifo),5);
| 59 | uart_putc('\n');
| 60 |
| 61 | fifo_write(&fifo,'x'); // hier kommt das x her
| 62 |
| 63 | fifo_wrap_size = fifo_get_read_wrap(&fifo);
| 64 |
| 65 | uart_puts("blocksize\t"); // UART "Blocksize"
| 66 | uart_uint(fifo_block_size,5);
| 67 | uart_putc('\n');
| 68 |
| 69 | uart_puts("wrapsize\t"); // UART "Wrapsize"
| 70 | uart_uint(fifo_wrap_size,5);
| 71 | uart_putc('\n');
| 72 |
| 73 |
| 74 | if (fifo_block_size > fifo_wrap_size) {
| 75 | // split action into two blocks due to pointer wrap around
| 76 |
| 77 | f_write(&file1, (uint8_t*)fifo.read_p, fifo_wrap_size * sizeof(fifo_data_t), &fatfs_bytes_written);
| 78 | fifo_read_bursted(&fifo, fifo_wrap_size);
| 79 | fifo_block_size -= fifo_wrap_size;
| 80 |
| 81 | uart_puts("wrapsize gtlvl\t");
| 82 | uart_uint(fifo_get_level(&fifo),5);
| 83 | uart_putc('\n');
| 84 |
| 85 | }
| 86 | // no pointer wrap around in block or second half of block operation
| 87 |
| 88 | f_write(&file1, (uint8_t*)fifo.read_p, fifo_block_size * sizeof(fifo_data_t), &fatfs_bytes_written);
| 89 | fifo_read_bursted(&fifo, fifo_block_size);
| 90 |
| 91 | uart_puts("level ende\t"); // UART "Level Ende"
| 92 | uart_uint(fifo_get_level(&fifo),5);
| 93 | uart_putc('\n');
| 94 |
| 95 | f_sync(&file1);
| 96 |
| 97 | }
|
@Michael N. (natulo)
>ich benutze in einem AVR Programm FatFS zusammen mit der FIFO
>Bibliothek von Falk Brunner.
Schön. Aber ist der Betreff deines Beitrag nicht ein "wenig" lang? ;-)
>Die grundsätzliche Idee war:
Die Idee ist grundsätzlich richtig. Sie muss aber auch korrekt umgesetzt
werden.
Wie schnell arbeitet dein ADC (Abtastrate)?
>Ist das Schreiben nicht mehr aktiviert, es befinden sich aber noch Daten
>im Fifo, so sollen diese auch auf die SD Karte geschrieben werden.
Hier wird es schwammig.
>Nachdem ich im normalen Betrieb Daten auf die Karte geschrieben und dann
>den Schreibmodus deaktiviert habe, sollten eigentlich die im Fifo
>verbliebenen Restdaten einmalig auf die SD Karte geschrieben werden.
>Danach wird der Füllstand des Fifos aktualisiert und er sollte nach
>meinem Verständnis leer sein.
Nö, denn parallel zum Schreiben auf SD-Karte kommen ja neue Daten vom
AD-Wandler.
>Das Problem ist, dass der Füllstand des Fifos in meinem Programm laut
>fifo_get_level() allerdings nie den Wert 0 erreicht.
Logisch.
>Der Programmteil,
>der die Restdaten eigentlich nur einmalig abspeichern soll, wird
>fortlaufend aufgerufen.
Programmfehler.
>Nach meinem Verständnis sollte der Füllstand nach dem Schreiben mit
>f_write und der Korrektur des Lesezeigers mit fifo_read_bursted
>eigentlich den Wert 0 erreichen. Das tut er aber nicht.
Siehe oben.
Ich glaube der Fehler liegt in deinem 2. Abschnitt.
1 | // Inhalt des Fifo auf Karte schreiben, wenn kein Kanal mehr loggt, aber noch Daten im Fifo liegen
| 2 | if( !writeEnableCheck() && SDcard_ready && fifo_get_level(&fifo)){
| 3 | uart_puts("Restdaten speichern:\t"); // UART "Restdaten speichern"
| 4 | uart_uint(fifo_get_level(&fifo),5);
| 5 | uart_putc('\n');
| 6 |
| 7 | fifo_write(&fifo,'x'); // hier kommt das x her
| 8 |
| 9 | fifo_wrap_size = fifo_get_read_wrap(&fifo);
| 10 |
| 11 | uart_puts("blocksize\t"); // UART "Blocksize"
| 12 | uart_uint(fifo_block_size,5);
| 13 | uart_putc('\n');
| 14 |
| 15 | uart_puts("wrapsize\t"); // UART "Wrapsize"
| 16 | uart_uint(fifo_wrap_size,5);
| 17 | uart_putc('\n');
| 18 |
| 19 |
| 20 | if (fifo_block_size > fifo_wrap_size) {
| 21 | // split action into two blocks due to po
|
Hier darfst du natürlich NICHT mit fifo_block_size Daten lesen, sondern
nur den Rest! Eher so.
1 | // Inhalt des Fifo auf Karte schreiben, wenn kein Kanal mehr loggt, aber noch Daten im Fifo liegen
| 2 | if( !writeEnableCheck() && SDcard_ready && fifo_get_level(&fifo)){
| 3 | uart_puts("Restdaten speichern:\t"); // UART "Restdaten speichern"
| 4 | uart_uint(fifo_get_level(&fifo),5);
| 5 | uart_putc('\n');
| 6 |
| 7 | fifo_write(&fifo,'x'); // hier kommt das x her
| 8 |
| 9 | fifo_wrap_size = fifo_get_read_wrap(&fifo);
| 10 |
| 11 | rest_size = fifo_get_level(&fifo);
| 12 | uart_puts("restsize\t"); // UART "Blocksize"
| 13 | uart_uint(rest_size,5);
| 14 | uart_putc('\n');
| 15 |
| 16 | uart_puts("wrapsize\t"); // UART "Wrapsize"
| 17 | uart_uint(fifo_wrap_size,5);
| 18 | uart_putc('\n');
| 19 |
| 20 |
| 21 | if (rest_size > fifo_wrap_size) {
| 22 | // split action into two blocks due to pointer wrap around
| 23 |
| 24 | f_write(&file1, (uint8_t*)fifo.read_p, fifo_wrap_size * sizeof(fifo_data_t), &fatfs_bytes_written);
| 25 | fifo_read_bursted(&fifo, fifo_wrap_size);
| 26 | rest_size -= fifo_wrap_size;
| 27 |
| 28 | uart_puts("wrapsize gtlvl\t");
| 29 | uart_uint(fifo_get_level(&fifo),5);
| 30 | uart_putc('\n');
| 31 |
| 32 | }
| 33 | // no pointer wrap around in block or second half of block operation
| 34 |
| 35 | f_write(&file1, (uint8_t*)fifo.read_p, rest_size * sizeof(fifo_data_t), &fatfs_bytes_written);
| 36 | fifo_read_bursted(&fifo, fifo_block_size);
| 37 |
| 38 | uart_puts("level ende\t"); // UART "Level Ende"
| 39 | uart_uint(fifo_get_level(&fifo),5);
| 40 | uart_putc('\n');
| 41 |
| 42 | f_sync(&file1);
| 43 |
| 44 | }
|
Kleiner Tip. Die Sequenz mit den 2 Blöcken für den FIFO-Zugriff und
SD-zugriff packt man besser in eine Funktion. Denn sie wird 2 mal
verwendet und ist recht lang. Damit wird deine Hauptschleife kürzer und
übersichtlicher.
Hallo Falk, vielen Dank für die Antwort!
Falk B. schrieb:
> @Michael N. (natulo)
>
> Schön. Aber ist der Betreff deines Beitrag nicht ein "wenig" lang? ;-)
>
Ich wusste nicht wie ich das Problem auf den Punktbringen soll, daher
wollte ich möglichst viele Informationen in den Titel stopfen damit
direkt erkennt, worum es in dem Thema geht.
>>Die grundsätzliche Idee war:
>
> Die Idee ist grundsätzlich richtig. Sie muss aber auch korrekt umgesetzt
> werden.
>
> Wie schnell arbeitet dein ADC (Abtastrate)?
>
Über einen 1ms Interrupt mit 1/10/100/1000Hz jeweils als Einzelwandlung.
>>Ist das Schreiben nicht mehr aktiviert, es befinden sich aber noch Daten
>>im Fifo, so sollen diese auch auf die SD Karte geschrieben werden.
>
> Hier wird es schwammig.
>
Da SD Karten erst bei Vielfachen von 512 Byte richtig schnell schreiben,
war die Idee einen Fifo mit z.B. 2048 Byte Größe anzulegen, in den dann
die Wandlerwerte geschoben werden.
Wenn der Füllstand des Fifo dann z.B. 1024 Byte übersteigt, sollen diese
auf die SD Karte geschrieben werden. Das wäre der "normale"
Schreibvorgang.
Wenn ich den Schreibmodus beende, aber erst z.B. 240 Byte im Fifo sind,
sollen diese auf die SD Karte geschrieben werden, auch wenn noch nicht
die z.B. 1024 Byte voll sind. Daher das Schreiben der "Restdaten".
Zumindest ist das mein aktueller Ansatz.
>>Nachdem ich im normalen Betrieb Daten auf die Karte geschrieben und dann
>>den Schreibmodus deaktiviert habe, sollten eigentlich die im Fifo
>>verbliebenen Restdaten einmalig auf die SD Karte geschrieben werden.
>>Danach wird der Füllstand des Fifos aktualisiert und er sollte nach
>>meinem Verständnis leer sein.
>
> Nö, denn parallel zum Schreiben auf SD-Karte kommen ja neue Daten vom
> AD-Wandler.
>
Der AD-Wandler läuft zwar weiter, die Ergebnisse werden aber nur in den
Fifo geschrieben wenn die jeweilige "WriteEnable" Variable gesetzt ist.
(if-Abfrage im ADC Interrupt)
Beim Deaktivieren des Schreibmodus wird die Variable auf 0 gesetzt.
>>Der Programmteil,
>>der die Restdaten eigentlich nur einmalig abspeichern soll, wird
>>fortlaufend aufgerufen.
>
> Programmfehler.
>
Korrekt.
>
> Ich glaube der Fehler liegt in deinem 2. Abschnitt.
>
Ebenfalls korrekt. Als ich deine Antwort gelesen habe, hat mich
sinnbildlich der Blitz getroffen.
Wenn man sich in Ruhe verdeutlicht was das Programm da macht, ist das
einer dieser "logisch, wieso habe ich das nicht gesehen?" Fehler.
Was ich gemacht habe:
Es sind z.B. 100 Byte an Restdaten im Fifo, schreibe fifo_block_size =
512 Byte aus dem Fifo auf die SD Karte und korrigiere den Lesezeiger um
512 Byte. Da braucht man sich dann auch nicht wundern, wieso das schief
geht.
Richtig und logisch ist natürlich deine Korrektur:
Guck wie viele Restdaten noch im Fifo sind, merk dir die Anzahl und
schreibe dann diese Anzahl an Bytes auf die SD Karte und korrigiere
entsprechend den Lesezeiger.
Mit dem korrigierten Code klappt es. 1 | if( !writeEnableCheck() && SDcard_ready && fifo_get_level(&fifo)){
| 2 | fifo_wrap_size = fifo_get_read_wrap(&fifo);
| 3 |
| 4 | rest_size = fifo_get_level(&fifo);
| 5 |
| 6 | if (rest_size > fifo_wrap_size) {
| 7 | // split action into two blocks due to pointer wrap around
| 8 |
| 9 | f_write(&file1, (uint8_t*)fifo.read_p, fifo_wrap_size * sizeof(fifo_data_t), &fatfs_bytes_written);
| 10 | fifo_read_bursted(&fifo, fifo_wrap_size);
| 11 | rest_size -= fifo_wrap_size;
| 12 |
| 13 | }
| 14 | // no pointer wrap around in block or second half of block operation
| 15 |
| 16 | f_write(&file1, (uint8_t*)fifo.read_p, rest_size * sizeof(fifo_data_t), &fatfs_bytes_written);
| 17 | fifo_read_bursted(&fifo, fifo_block_size); // Anm.: hier dann natürlich ebenfalls rest_size
| 18 |
| 19 | f_sync(&file1);
| 20 | }
|
>
> Kleiner Tip. Die Sequenz mit den 2 Blöcken für den FIFO-Zugriff und
> SD-zugriff packt man besser in eine Funktion. Denn sie wird 2 mal
> verwendet und ist recht lang. Damit wird deine Hauptschleife kürzer und
> übersichtlicher.
Danke für den Tipp, werde ich machen!
@ Michael N. (natulo)
>> Schön. Aber ist der Betreff deines Beitrag nicht ein "wenig" lang? ;-)
>Ich wusste nicht wie ich das Problem auf den Punktbringen soll, daher
>wollte ich möglichst viele Informationen in den Titel stopfen damit
>direkt erkennt, worum es in dem Thema geht.
Nicht sinnvoll, das gehört in den 1. Beitrag. Die Überschrift sollte
eher kurz und prägnant sein.
Problem mit FATfs + FIFO
>Da SD Karten erst bei Vielfachen von 512 Byte richtig schnell schreiben,
>war die Idee einen Fifo mit z.B. 2048 Byte Größe anzulegen, in den dann
>die Wandlerwerte geschoben werden.
Ja, aber das macht FATfs schon, das hat einen 512 Byte Sektorpuffer.
Beitrag "Re: Geschwindigkeitsfrage AVR auf SD"
>Wenn der Füllstand des Fifo dann z.B. 1024 Byte übersteigt, sollen diese
>auf die SD Karte geschrieben werden. Das wäre der "normale"
>Schreibvorgang.
Ist OK.
>Wenn ich den Schreibmodus beende, aber erst z.B. 240 Byte im Fifo sind,
>sollen diese auf die SD Karte geschrieben werden, auch wenn noch nicht
>die z.B. 1024 Byte voll sind. Daher das Schreiben der "Restdaten".
Schon klar.
>Ebenfalls korrekt. Als ich deine Antwort gelesen habe, hat mich
>sinnbildlich der Blitz getroffen.
;-)
>Wenn man sich in Ruhe verdeutlicht was das Programm da macht, ist das
>einer dieser "logisch, wieso habe ich das nicht gesehen?" Fehler.
Das ist das "ich sehe den Wald vor lauter Bäumen nicht"-Problem.
>Mit dem korrigierten Code klappt es.
Heureka!
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|