Forum: Mikrocontroller und Digitale Elektronik FatFs mit Fifo Bibliothek von Falk Brunner, Fifo behält trotz Auslesen und read_bursted Restdaten.


von Daniel N. (natulo)


Lesenswert?

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
    }

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@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.

von Daniel N. (natulo)


Lesenswert?

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!

von Falk B. (falk)


Lesenswert?

@ 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.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.