Forum: Mikrocontroller und Digitale Elektronik Wie könnte man 2 Unterprogramme verlustlos "gleichzeitig" verarbeiten?


von Wolle G. (wolleg)


Angehängte Dateien:

Lesenswert?

Es werden im Abstand von 5ms (soll später mal auf 2ms verringert werden) 
EKG-messwerte gelesen und diese in einem [Feld] gesammelt.
Wenn 512 Bytes erreicht wurden, werden diese über SPI in einem Sektor 
einer SD-Karte abgespeichert.
Der Vorgang  des Abspeicherns dauert je nach Kartentyp ca 40 bis zu 
100ms.
Bei meinem aktuellen Programm wartet der Timer so lange, bis der Vorgang 
des Abspeicherns beendet ist. Damit wird aber ein Teil der Messwerte 
unterdrückt, was die EKG-Kurve teilweise verfälscht.
Jetzt die Frage: Könnte man durch geschicktes Programmieren den 
Schreibvorgang bei einem Timerinterrupt unterbrechen, um einen 
Lesevorgang  eines Messwertes  zu ermöglichen?
Oder macht man das ganz anders?
Im Anhang einige Auszüge aus meinem Programm. (für MSP430F1611)

von San L. (zwillingsfreunde)


Lesenswert?


von Karl H. (kbuchegg)


Lesenswert?

Der Teil
1
auf_SD_karte_schreiben();

muss da raus
1
#pragma vector=TIMERA0_VECTOR
2
__interrupt void Timer_A (void)  
3
{
4
lesen_kanal_1();                                                  
5
zwischenspeichern();
6
auf_SD_karte_schreiben(); 
7
}

du benutzt 2 buffer.
Wenn der eine voll ist, wird auf den anderen umgeschaltet und dort im 
Interrupt reingeschrieben, während die SD Routinen den gefüllten Buffer 
auf die Karte schreiben. Der Interrupt läuft während des SChreibens 
weiter. Das sollte keine Probleme aufwerfen, da das eigentliche 
SChreiben die Karte selbst macht, d.h. du musst dazu auf µC Seite kein 
Timing auf die µs genau einhalten. WEnn da kurzzeitig mal von einem 
Interrupt unterbrochen wird, ist das kein Problem.

Du musst nur sicherstellen, dass das rausschreiben schneller geht, als 
der Interrupt dir den jeweils anderen Buffer anfüllen kann.

: Bearbeitet durch User
von dunno.. (Gast)


Lesenswert?

Karl H. schrieb:
> Der Interrupt läuft während des SChreibens
> weiter. Das sollte keine Probleme aufwerfen, da das eigentliche
> SChreiben die Karte selbst macht, d.h. du musst dazu auf µC Seite kein
> Timing auf die µs genau einhalten. WEnn da kurzzeitig mal von einem
> Interrupt unterbrochen wird, ist das kein Problem.

Solange sensor und SD-Karte an verschiedenen SPIs hängen.. ;)

von Karl H. (kbuchegg)


Lesenswert?

:-)

Interessant
1
     if ((P2IN & BIT7) == BIT7) //prüft, ob SD-Karte eingesteckt ist
2
     {
3
      Fehlermeldung_ausgeben();
4
      mmcWriteSector(sector,mmc_buffer);
5
      t=0;
6
      sector=sector+1;
7
    }

wie schreibt man mittels mmcWriteSector auf eine nicht vorhandene SD 
Karte?

von Falk B. (falk)


Lesenswert?

@ wolle g. (wolleg)

>Es werden im Abstand von 5ms (soll später mal auf 2ms verringert werden)
>EKG-messwerte gelesen und diese in einem [Feld] gesammelt.
>Wenn 512 Bytes erreicht wurden, werden diese über SPI in einem Sektor
>einer SD-Karte abgespeichert.
>Der Vorgang  des Abspeicherns dauert je nach Kartentyp ca 40 bis zu
>100ms.

Dazu kommen noch sporadische Pausen mit 300ms und mehr, Stichwort Wear 
Leveling.

>Bei meinem aktuellen Programm wartet der Timer so lange, bis der Vorgang
>des Abspeicherns beendet ist.

Schon mal falsch. So programmiert man nicht mit Interrupts, denn so 
bekommt man kein Multitasking hin.

> Damit wird aber ein Teil der Messwerte
>unterdrückt, was die EKG-Kurve teilweise verfälscht.

Es ist Murks!

>Jetzt die Frage: Könnte man durch geschicktes Programmieren den

Ja.

>Schreibvorgang bei einem Timerinterrupt unterbrechen, um einen
>Lesevorgang  eines Messwertes  zu ermöglichen?

Das ist der Normalfall.

>Oder macht man das ganz anders?

Zeitritische Dinge (EKG Datenaufnahme) passieren in einem passenden 
Timer-interrupt. Zeitunkritische, vor allem langandauernde Dinge 
(Schreiben auf SD-Karte) in einer normalen Funktion im Hauptprogramm. 
Dazwischen gibt es einen Puffer, ggf. in Form eines FIFOs. Damit 
erreicht man sehr hohe Datendurchsätze trotz Echtzeitanforderungen. 
Praktisches Beispiel. Ich hab mal einen DMX-Rekoder gebaut, dort wird 
mit 250kBaud lückenlos gesendet oder empfangen (25 kB/s!) und parallel 
dazu die Daten auf SD-Karte geschrieben bzw. von dort gelesen. Mit 
deinen 500 Samples/s ist das umso leichter.

>Im Anhang einige Auszüge aus meinem Programm. (für MSP430F1611)

Die schon mal zeigen, daß dein Grundkonzept nicht stimmt.
Tu dir einen Gefallen und nutze ein fertige FAT Bibliothek für den 
SD-Kartenzugriff. Ich kann die von Elm Chan empfehlen, die geht sehr 
gut.

SD-Card

von Karl H. (kbuchegg)


Lesenswert?

dunno.. schrieb:
> Karl H. schrieb:
>> Der Interrupt läuft während des SChreibens
>> weiter. Das sollte keine Probleme aufwerfen, da das eigentliche
>> SChreiben die Karte selbst macht, d.h. du musst dazu auf µC Seite kein
>> Timing auf die µs genau einhalten. WEnn da kurzzeitig mal von einem
>> Interrupt unterbrochen wird, ist das kein Problem.
>
> Solange sensor und SD-Karte an verschiedenen SPIs hängen.. ;)

Autsch
1
void lesen_kanal_1(void)
2
{
3
K1UB=SPI_Config_CMD_16Bit(0xB900);
4
K1MB=SPI_Config_CMD_16Bit(0xB800);
5
K1OB=SPI_Config_CMD_16Bit(0xB700); //liest Kanal 1 aus Register 0x37 (unteres Byte)
6
}

ja, dieses mögliche Problem hab ich tatsächlich nicht gesehen.

Da wird man noch eingreifen müssen, wenn beide SPI-Geräte über dieselben 
Pins abgehandelt werden.

von Falk B. (falk)


Lesenswert?

@ Karl Heinz (kbuchegg) (Moderator)

>> Solange sensor und SD-Karte an verschiedenen SPIs hängen.. ;)

Upps.

>ja, dieses mögliche Problem hab ich tatsächlich nicht gesehen.

Me too!

>Da wird man noch eingreifen müssen, wenn beide SPI-Geräte über dieselben
>Pins abgehandelt werden.

Ja, da muss man halt auf 2 getrennte SPI ausweichen, den EKG-Sensor mit 
500 Hz kann man im Zweifelsfall problemlos per Soft-SPI auslesen. Das 
ist alles deutlich einfacher, als eine FAT-Lib umzustricken.

von Noch einer (Gast)


Lesenswert?

Du brauchst gar nicht einen ganzen Sektor auf einmal schreiben. Du 
kannst auch auf Bereitschaft testen, das Kommando zum Schreiben absetzen 
und dann jeweils einen Wert schreiben, nachdem du ihn gemessen hast. Das 
mmcWriteSector() ist trivial.

Ob das wirklich weiter hilft? Die Messwerte in den 40-100ms Wartezeit 
musst du trotzdem zwischenspeichern.

von Jim M. (turboj)


Lesenswert?

Noch einer schrieb:
> Ob das wirklich weiter hilft? Die Messwerte in den 40-100ms Wartezeit
> musst du trotzdem zwischenspeichern.

Du solltest >500 ms Puffer vorsehen, SD Karten haben manchmal längere 
Wartezeiten. Worst case war hier mal eine Karte mit ca 1 Sekunde Pause 
beim Schreiben. Das war IIRC eine "Verbatim" aus dem Supermarkt (also 
eher noname).

von Jim M. (turboj)


Lesenswert?

Noch einer schrieb:
> Du brauchst gar nicht einen ganzen Sektor auf einmal schreiben. Du
> kannst auch auf Bereitschaft testen, das Kommando zum Schreiben absetzen
> und dann jeweils einen Wert schreiben, nachdem du ihn gemessen hast. Das
> mmcWriteSector() ist trivial.

Nur leider funktioniert das nicht mehr, wenn die Karte fragmentiert ist. 
Das passiert schnell, z.B. wenn man ein altes File löscht und ein neures 
stehen lässt. Übrigens bräuchte man für diesen Fall noch mehr Puffer, 
denn man müsste im Worst Case etliche 100KB FAT32 bis zum nächsten 
freien Sektor lesen, das dauert...

von Falk B. (falk)


Lesenswert?

@Jim Meba (turboj)

>> und dann jeweils einen Wert schreiben, nachdem du ihn gemessen hast. Das
>> mmcWriteSector() ist trivial.

>Nur leider funktioniert das nicht mehr, wenn die Karte fragmentiert ist.

Jo.

>Das passiert schnell, z.B. wenn man ein altes File löscht und ein neures
>stehen lässt. Übrigens bräuchte man für diesen Fall noch mehr Puffer,
>denn man müsste im Worst Case etliche 100KB FAT32 bis zum nächsten
>freien Sektor lesen, das dauert...

Dafür sollte man VORHER die Datei mit maximaler Länge anlegen, dann 
klappt das (cluster preallocation). Sogar noch schneller, wenn man dann 
noch die Cluster Link Map Table anlegt. Der Meister aus dem fernen Osten 
macht es vor.

http://elm-chan.org/fsw/ff/en/lseek.html

von W.S. (Gast)


Lesenswert?

wolle g. schrieb:
> Es werden im Abstand von 5ms (soll später mal auf 2ms verringert werden)
> EKG-messwerte gelesen und diese in einem [Feld] gesammelt.
> Wenn 512 Bytes erreicht wurden, werden diese über SPI in einem Sektor
> einer SD-Karte abgespeichert.
> Der Vorgang  des Abspeicherns dauert je nach Kartentyp ca 40 bis zu
> 100ms.

Du denkst noch falsch, nämlich prozedural. Früher hat man dazu nen PAP 
gemalt und alles war klar - bis auf die tatsächliche Realisierung. 
Deshalb mein Rat: lerne nichtblockierend zu programmieren.

Also nicht so:
Anfang:
 while Nixtunzeit < 5ms do nothing;
 Lies EKG Werte
 Speicher sie ins Feld
 sind 512 Werte zusammen?
 nein: goto Anfang
 ja: speichere sie auf SD Karte; goto Anfang;

sondern etwa (sinngemäß) so:
Anfang:
 ist Nixtunzeit >= 5ms?
 ja: Lies EKG werte
     Speichere sie ins Feld
     setze Nixtunzeit = 0;
 nein: nix;
 sind im Puffer 512 Werte oder mehr vorhanden?
 ja: ist SD-Karte da und benutzbar?
     ja: ist Datei bereits eröffnet?
         nein: Eröffne Datei zum Schreiben
         ja: ist letzter Schreibvorgang erledigt?
         nein: goto Anfang;
         ja: Starte das Schreiben der ältesten 512 Werte in Datei
 goto Anfang;

Dafür solltest du dir ein Ergebnisfeld für deine Werte kreieren, was 
deutlich größer ist als 512 Stück. Z.B. 2000 oder so (falls der RAM das 
mitmacht). Das Ergebnisfeld ist natürlich ein Ringpuffer, in den man 
stückweise hineinschreiben und ebenso stückweise herauslesen kann.

Kurzum: Trampele niemals auf der Stelle, sondern benimm dich in deiner 
Firmware etwa so, wie ein einzelner Beamter im Amt.

Huch?

Naja, stell dir vor, im Amt ist nur ein Bamter, die anderen feiern alle 
krank. Also rennt der eine Beamte ins 1. Amtszimmer an den Schreibtisch, 
gucjt dort, ob es was zu tun gibt und falls ja, veranlaßt er dienstgemäß 
die Erledigung. Dann hechter er zum 2. Amtszimmer und tut dort das 
Gleiche. Ebenso im Amtszimmer 3...xxx, dann geht's wieder zum Amtszimmer 
1.

So erledigt dieser eine Beamte alle Arbeiten des ganzen Amtes, und so 
etwa kann man auch die Arbeit seiner Firmware organisieren. Man muß bloß 
in jedem Amzszimmer eine Notiz hinterlassen, in welchem Zustand die 
Abarbeitung des Anstehenden ist.

W.S.

von Falk B. (falk)


Lesenswert?

Einen Beamten als Beispiel für Multitasking zu wählen ist wohl ein 
wenig weltfremd ;-)

von W.S. (Gast)


Lesenswert?

Hast du eine bessere Story dazu, die das Prinzip mindestens genaus so 
gut rüberbringen kann? Dann schreib sie.

W.S.

von Falk B. (falk)


Lesenswert?

@W.S. (Gast)

>Hast du eine bessere Story dazu, die das Prinzip mindestens genaus so
>gut rüberbringen kann? Dann schreib sie.

Dann lies mal den Artikel Multitasking und schau dir an, wer die 
AVR-Beispiele geschrieben hat . . .

von Karl H. (kbuchegg)


Lesenswert?

W.S. schrieb:
> Hast du eine bessere Story dazu, die das Prinzip mindestens genaus so
> gut rüberbringen kann? Dann schreib sie.
>

Ich nehm immer Hausfrau, die zwischen Herd, Waschmaschine und 
Staubsauger hin und her flitzt. Die gelten allgemein als fleissig :-)

von W.S. (Gast)


Lesenswert?

Falk B. schrieb:
> Dann lies mal den Artikel Multitasking und schau dir an, wer die
> AVR-Beispiele geschrieben hat . . .

Kannst du vergessen, alles über AVR liegt weit hinter mir, da fasse ich 
nix mehr an.

Aber wir sollten nicht allzu weit abdiften.

höchtens (ausnahmsweise)  zu einem geschunken-gekrochenen Kröver 
Nacktarsch.

Wohlsein!

W.S.

von Paul B. (paul_baumann)


Lesenswert?

W.S. schrieb:
> Aber wir sollten nicht allzu weit abdiften.
Geht schon los -mit dem abriften, abdiften ,äh....LALL!
> höchtens (ausnahmsweise)  zu einem geschunken-gekrochenen Kröver
> Nacktarsch.

So in der Art wie der "Klöbener Krötenpfuhl"
Original verkorkt und abgefüllt von Pahlgruber & Söhne
> Wohlsein!
Wohlsein!

MfG Paul

von Wolle G. (wolleg)


Lesenswert?

Zwischenzeitlich ist ja einiges an Ratschlägen zusammengekommen und man 
kommt kaum hinterher, alles zu verarbeiten.
Gleich mal am Anfang: Programmieren ist nicht gerade meine Stärke und 
einige Ratschläge sind deshalb für mich schwer verständlich.
Trotzdem möchte ich mein Problem lösen.

Zunächst muss ich wohl noch einiges erläutern, was ich alles so 
angestellt habe.

Karl H. schrieb:
> Interessant     if ((P2IN & BIT7) == BIT7) //prüft, ob SD-Karte
> eingesteckt ist
>      {
>       Fehlermeldung_ausgeben();
>       mmcWriteSector(sector,mmc_buffer);
>       t=0;
>       sector=sector+1;
>     }

>> wie schreibt man mittels mmcWriteSector auf eine nicht vorhandene SD
>> Karte?

Die Prüfung, ob die Karte steckt, stammt aus einer Anwendung, wo z.B. 
alle 4s Temp.-Messwerte (einer Heizung) gesammelt werden. Dadurch kann 
ich die SD-Karte kurz herausnehmen, um die Datei, die auf der SD-Karte 
angelegt wurde, für eine Zwischenauswertung zu lesen.
Sollte dies zulange dauern, dann wird zwar ein Sektor nicht beschrieben, 
aber  die Sektornummer wird erhöht. Zusätzlich wird beim Einstecken an 
P2.7 ein  Interrupt ausgelöst und die SD-Karte wird neu initialisiert.

Karl H. schrieb:
>> Der Teil auf_SD_karte_schreiben();
>
>> muss da raus

> #pragma vector=TIMERA0_VECTOR
> __interrupt void Timer_A (void)
> {
> lesen_kanal_1();
> zwischenspeichern();
> auf_SD_karte_schreiben();
> }
>
Wie könnte man das machen. Irgendwo müsste man doch prüfen, ob 512 Bytes 
erreicht wurden.
evtl so, wie in <int main(void)>  XXXX  schleife ??? ();
int main(void)
   {
    WDTCTL = WDTPW + WDTHOLD;    // Stop watchdog timer
    P2IE   = 0x83;       // an  P2.0 und P2.1 + P2.7 Interruptfreigabe ;
    P2IES  = 0x80;   // auf L/H Flanke  an P2.0 und P2.1 festlegen 
//+ P2.7 für Einsteckkkontrolle H/L
    text_init();                 // Initialisiert FKA
    Timer_einstellen();
    starten();
   XXXX  schleife ??? ();    // prüfen (wie ?), ob
                             // 512 Bytes erreicht wurden und auf 
SD-Karte schreiben
    for(;;);       //Warteschleife  (Timer)
   }

Karl H. schrieb:
> Da wird man noch eingreifen müssen, wenn beide SPI-Geräte über dieselben
> Pins abgehandelt werden.

nicht notwendig, da Soft-SPI für die Kommunikation  mit dem EKG-IS 
ADS1293 verwendet wird,

Falk B. schrieb:
> Dafür sollte man VORHER die Datei mit maximaler Länge anlegen, dann
> klappt das (cluster preallocation). Sogar noch schneller, wenn man dann
> noch die Cluster Link Map Table anlegt. Der Meister aus dem fernen Osten
> macht es vor.

Bei meinen Anwendungen (nicht nur EKG) wird auf einer frisch 
formatierten SD-Karte eine Datei bestimmter Größe (z.B 100MB) angelegt.
In diese Datei werden die Messwerte zu jeweils 512 Bytes = 1 Sektor 
geschrieben. Diese Datei wird bei Bedarf auf den PC kopiert
und mit einem in Delphi geschrieben Programm gelesen und so bearbeitet, 
dass die Messwerte in Form einer Tabelle.txt zur Weiterverarbeitung 
vorliegen.
Das ist für mich der einfachste Weg.

Viele Wege führen bekanntlich nach Rom.
Könnte der Weg, der oben mit "XXXX  schleife ??? (); // prüfen ob 512 
Bytes erreicht wurden und auf SD-Karte schreiben" zum Ziel führen?
Wenn ja, wie sollte die Schleife, oder was auch immer, konkret aussehen?

von Karl H. (kbuchegg)


Lesenswert?

wolle g. schrieb:

> Die Prüfung, ob die Karte steckt, stammt aus einer Anwendung, wo z.B.
> alle 4s Temp.-Messwerte (einer Heizung) gesammelt werden. Dadurch kann
> ich die SD-Karte kurz herausnehmen, um die Datei, die auf der SD-Karte
> angelegt wurde, für eine Zwischenauswertung zu lesen.
> Sollte dies zulange dauern, dann wird zwar ein Sektor nicht beschrieben,
> aber  die Sektornummer wird erhöht.


Das ist ja alles gut und schön.
Aber was glaubst du, was die Funktion die einen Sektor schreiben soll 
mit dir macht, wenn keine SD Karte vorhanden ist?

Wenn du kein Papier hast, dann kannst du auch nichts drauf schreiben. Ob 
du einen Schreibversuch zählen willst oder nicht, ist deine Sache. Aber 
schreiben kannst du nicht.


> Wie könnte man das machen.

wie gesagt. Zum Beispiel mit 2 Buffern. Um jetzt nur eine einfache 
Lösung zu nennen.
1
uint8_t buffer1[512];
2
uint8_t buffer2[512];
3
4
uint8_t * volatile activeBuffer;   // welches ist der active Buffer
5
uint8_t * volatile otherBuffer;    // und welches ist der andere
6
uint8_t  storedBytes;
7
8
volatile uint8_t doWrite;
9
10
interrupt ....
11
{
12
  activeBuffer[storedBytes++] = SPI_Config_CMD_16Bit(0xB900);
13
  activeBuffer[storedBytes++] = .....;
14
  activeBuffer[storedBytes++] = .....;
15
  activeBuffer[storedBytes++] = .....;
16
17
  if( storedBytes == 512 ) {
18
    // voll. Die Buffer tauschen die Plätze
19
    uint8_t * volatile tmp;
20
    tmp = activeBuffer;
21
    activeBuffer = otherBuffer;
22
    otherBuffer = tmp;
23
24
    // im jetzt activen geht es wieder von vorne los
25
    storedBytes = 0;
26
27
    // und wir benachrichtigen, dass es was zu schreiben gibt
28
    doWrite = 1;
29
  }
30
}
31
32
int main()
33
{
34
  ....
35
36
  activeBuffer = buffer1;
37
  otherBuffer = buffer2;
38
  storedBytes = 0;
39
  doWrite = 0;
40
41
  while( 1 ) {
42
43
    ....
44
    if( doWrite ) {
45
      doWrite = 0;
46
47
      // otherBuffer ist gefüllt. Den schreiben wir auf die Karte
48
      // während der Interrupt in activeBuffer die nächsten Daten
49
      // sammelt.
50
      mmcWriteSector( sector, otherBuffer );
51
      sector++;
52
    }
53
54
    ....
55
  }
56
}

: Bearbeitet durch User
von Gerd E. (robberknight)


Lesenswert?

Man kann für so ein Problem auch ein RTOS verwenden.

Darin kannst Du dann verschiedene Threads starten (z.B. einen zum 
Einlesen und einen anderen zum Schreiben). Jeder Thread ist für sich 
eine Funktion mit eigenem Stack etc. und das RTOS schaltet dann nach von 
Dir vorgegebenen Regeln zwischen denen um. Den Zugriff auf gemeinsam 
genutzte Ressourcen (wie den Puffer oder den einen SPI-Bus) kannst Du 
mit verschiedenen Konstrukten (z.B. Mutex) organisieren.

Der Vorteil ist, daß die einzelnen Threads für sich genommen 
übersichtlicher programmiert werden könnnen, als wenn man einen 
Codeblock hat, der sich um alles kümmert und zwischen den verschiedenen 
Codepfaden hin- und herspringt wie es W.S. oben vorgeschlagen hat.

von Falk B. (falk)


Lesenswert?

@wolle g. (wolleg)

>Gleich mal am Anfang: Programmieren ist nicht gerade meine Stärke und

Merkt man ;-)

>Zunächst muss ich wohl noch einiges erläutern, was ich alles so
>angestellt habe.

>Die Prüfung, ob die Karte steckt, stammt aus einer Anwendung, wo z.B.
>alle 4s Temp.-Messwerte (einer Heizung) gesammelt werden. Dadurch kann
>ich die SD-Karte kurz herausnehmen, um die Datei, die auf der SD-Karte
>angelegt wurde, für eine Zwischenauswertung zu lesen.
>Sollte dies zulange dauern, dann wird zwar ein Sektor nicht beschrieben,
>aber  die Sektornummer wird erhöht. Zusätzlich wird beim Einstecken an
>P2.7 ein  Interrupt ausgelöst und die SD-Karte wird neu initialisiert.

Das funktioniert so nicht wirklich akzeptabel. Beim EKG sind die Daten 
weg, wenn man keine sehr großen Buffer hat. Ausserdem kommt eine FAT-Lib 
aus dem Tritt.

>Wie könnte man das machen. Irgendwo müsste man doch prüfen, ob 512 Bytes
>erreicht wurden.

Sicher, im Zähler in der ISR. Muss man aber mal in einem Beispiel 
zeigen.
Mal GANZ einfach.
1
int buffer[2][512];
2
volatile int buffer_voll;
3
4
int main() {
5
   alles_einstellen()
6
   while(1) {
7
     if (buffer_voll) {
8
       buffer_auf_sd_schreiben();
9
       buffer_voll=0;
10
     }
11
   }
12
}
13
14
ISR (2ms_timer) {
15
  static int cnt;
16
  static int bufferwahl;
17
18
  ekg=ekg_lesen();
19
  buffer[bufferwahl][cnt] = ekg;
20
  cnt++;
21
  if (cnt==512) {
22
    cnt = 0;
23
    buffer_voll=1;
24
    bufferwahl++;
25
    if (bufferwahl==2) {
26
      bufferwahl=0;
27
    }
28
  }
29
}


>Bei meinen Anwendungen (nicht nur EKG) wird auf einer frisch
>formatierten SD-Karte eine Datei bestimmter Größe (z.B 100MB) angelegt.

Jaja, der übliche Bastler-Murks. Das ist nicht mehr wirklich zeitgemäß. 
Nimm eine gescheite FAT-Lib. Du wirst es nicht bereuen.

von Falk B. (falk)


Lesenswert?

@Gerd E. (robberknight)

>Man kann für so ein Problem auch ein RTOS verwenden.

Ob das für einen Programmierlaien der rechte Weg ist?

>Der Vorteil ist, daß die einzelnen Threads für sich genommen
>übersichtlicher programmiert werden könnnen, als wenn man einen
>Codeblock hat, der sich um alles kümmert und zwischen den verschiedenen
>Codepfaden hin- und herspringt wie es W.S. oben vorgeschlagen hat.

Wer das nicht per kooperativen Multitasking und Interrupt auf die Reihe 
kriegt, kommt auch mit einem bequemeren RTOS nicht weiter.

von Gerd E. (robberknight)


Lesenswert?

Falk B. schrieb:
> @Gerd E. (robberknight)
>
>>Man kann für so ein Problem auch ein RTOS verwenden.
>
> Ob das für einen Programmierlaien der rechte Weg ist?

Keine Ahnung. Beim RTOS musst Du Dich unbedingt mit so Dingen wie 
Critical Sections, Thread-Prioritäten etc. beschäftigen, ansonsten geht 
gar nichts. Du kannst Dich also nicht so leicht durchwurschteln. Für 
manche reicht das als Ansporn sich mit den Konzepten zu beschäftigen, 
die Probleme zu verstehen und daraus dann eine bessere Lösung 
umzusetzen.

Auch findet man in den Dokus von so manch einem RTOS ein paar gute 
Erklärungen und Beispiele für solche Probleme.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Gerd E. schrieb:
> Falk B. schrieb:
>> @Gerd E. (robberknight)
>>
>>>Man kann für so ein Problem auch ein RTOS verwenden.
>>
>> Ob das für einen Programmierlaien der rechte Weg ist?
>
> Keine Ahnung. Beim RTOS musst Du Dich unbedingt mit so Dingen wie
> Critical Sections, Thread-Prioritäten etc. beschäftigen, ansonsten geht
> gar nichts. Du kannst Dich also nicht so leicht durchwurschteln.

Oh doch.
(Soll heissen: Du sollst nicht, aber du kannst. Mit dem entsprechenden 
Ergebnis)

Hab hier so einen, der auch meinte ein Multitasking Betriebssystem löst 
alle seine Probleme. Semaphoren, was ist das?
Und ich darf mir jetzt die Zeit damit vertreiben, seine ganzen Race 
Conditions zu finden (und nebenbei seine ganzen Casts kontrollieren, bei 
der er sich einen huge Pointer auf einen normalen Pointer runter 
gestrippt hat)
Hätte er round robin einfach einen Haufen State-Machines verbaut, wäre 
alles viel einfacher. Die Aufgabenstellung hätte das sogar recht simpel 
hergegeben.

OK. Einen Ethernet Stack schüttle ich auch nicht einfach so aus dem 
Ärmel. Von daher hat das OS schon seinen Sinn. Aber deswegen muss ich 
nicht gleich zu Multitasking greifen, wenn ich das nicht beherrsche.

: Bearbeitet durch User
von Konrad S. (maybee)


Lesenswert?

Falk B. schrieb:
> Einen Beamten als Beispiel für Multitasking zu wählen ist wohl ein
> wenig weltfremd ;-)

Na dann eben als Beispiele für Idle und Sleep!
Upps, haben meine Finger das wirklich getippt? ;-)

von Gerd E. (robberknight)


Lesenswert?

Karl H. schrieb:
>> Gerd E. schrieb:
>> Du kannst Dich also nicht so leicht durchwurschteln.
>
> Oh doch.
> (Soll heissen: Du sollst nicht, aber du kannst. Mit dem entsprechenden
> Ergebnis)
>
> Hab hier so einen, der auch meinte ein Multitasking Betriebssystem löst
> alle seine Probleme. Semaphoren, was ist das?

Stimmt schon. Wenn man wirklich will geht das schon. Aber es fliegt 
einem dann halt auch recht schnell um die Ohren. Und das sollte man dann 
als Anstoß nehmen zu lernen wie man es richtig macht.

> Und ich darf mir jetzt die Zeit damit vertreiben, seine ganzen Race
> Conditions zu finden (und nebenbei seine ganzen Casts kontrollieren, bei
> der er sich einen huge Pointer auf einen normalen Pointer runter
> gestrippt hat)

Warum ist das jetzt Dein Job? So lernt derjenige das doch nie.

Bis bei uns in der Firma die Praktikanten ihren ersten größeren 
Codeblock in master gemerged bekommen, sind eigentlich immer einige 
Review-Runden zu drehen. Beim nächsten Block geht das dann schon 
schneller.

von Karl H. (kbuchegg)


Lesenswert?

Gerd E. schrieb:

> Warum ist das jetzt Dein Job? So lernt derjenige das doch nie.

Weil derjenige das Handtuch geschmissen hat und jetzt in Neuseeland 
Schafe züchtet. Ernsthaft.

von Gerd E. (robberknight)


Lesenswert?

Karl H. schrieb:
> Weil derjenige das Handtuch geschmissen hat und jetzt in Neuseeland
> Schafe züchtet. Ernsthaft.

Selbsterkenntnis. Das ist ok. Besser als die, die erst weggelobt & 
befördert werden müssen.

von Karl H. (kbuchegg)


Lesenswert?

Gerd E. schrieb:
> Karl H. schrieb:
>> Weil derjenige das Handtuch geschmissen hat und jetzt in Neuseeland
>> Schafe züchtet. Ernsthaft.
>
> Selbsterkenntnis. Das ist ok. Besser als die, die erst weggelobt &
> befördert werden müssen.

Die letzten Gerüchte besagen allerdings, er wäre jetzt nach 4 Jahren 
Schafe bei Siemens gelandet. Überzeugend auftreten konnte er schon 
immer. Auch ernsthaft.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@Karl Heinz (kbuchegg) (Moderator)

>>> Weil derjenige das Handtuch geschmissen hat und jetzt in Neuseeland
>>> Schafe züchtet. Ernsthaft.
>
>> Selbsterkenntnis. Das ist ok. Besser als die, die erst weggelobt &
>> befördert werden müssen.

>Die letzten Gerüchte besagen allerdings, er wäre jetzt nach 4 Jahren
>Schafe bei Siemens gelandet. Überzeugend auftreten konnte er schon
>immer. Auch ernsthaft.

Der Weg zur Erkenntnis ist lang und steinig. Und führt manchmal über 
Neuseeland ;-)

von Karl H. (kbuchegg)


Lesenswert?

Was ich aus dem Code schon alles an ... mir fällt da jetzt gar kein Wort 
dafür ein ... rausgeholt habe, das könnte Bücher füllen. Aber der 
Compiler ist ja sooooo fehlerhaft.
Na ja. Im Moment funktioniert eigentlich fast alles. Irgendwo gibt es 
noch einen Speicherüberschreiber, der dafür sorgt, dass unmotiviert 
irgendwann mal ein Zeichen am LCD auftaucht, das da nicht hingehört. 
Sauschwer zu finden, was da los ist. Auch, oder gerade wegen 
Multitasking. Die Idee ist ja nicht schlecht: im Speicher gibt es einen 
virtuellen Bildschirm und ein Task schaufelt geänderte Zeichen aufs LCD. 
Aber finde da jetzt mal den Übeltäter, der irgendwann in einem anderen 
Task genau 1 Byte da drinn niederbügelt. Ich schätze mal, er hat wieder 
irgendwo einen huge Pointer runtergecastet und damit das Segmentregister 
verloren. Aber was weiss ich schon. On Chip Debugger gibts keinen, sonst 
hätt ich einen Watch Point auf das Byte gelegt. So muss ich halt zu den 
klassischen Methoden greifen.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@Karl Heinz (kbuchegg) (Moderator)

>irgendwann mal ein Zeichen am LCD auftaucht, das da nicht hingehört.
>Sauschwer zu finden, was da los ist. Auch, oder gerade wegen

Bau doch einen selbstgestrickten Debugger ein. Prüfe deinen virtuellen 
LCD an der speziellen Stelle auf das spezielle Zeichen und gib ein 
Signal nach aussen. Damit sollte man sich der Sache nähern können. Oder 
kommentier die diversen Stellen mit Schreibzugriffen auf den virtuellen 
LCD schtrittweise aus. Du schaffst das, bist doch ein alter Hase.

>Task genau 1 Byte da drinn niederbügelt. Ich schätze mal, er hat wieder
>irgendwo einen huge Pointer runtergecastet und damit das Segmentregister
>verloren. Aber was weiss ich schon.

Klingt nach good, ole 8051 ;-)

von Gerd E. (robberknight)


Lesenswert?

Karl H. schrieb:
> im Speicher gibt es einen
> virtuellen Bildschirm und ein Task schaufelt geänderte Zeichen aufs LCD.
> Aber finde da jetzt mal den Übeltäter, der irgendwann in einem anderen
> Task genau 1 Byte da drinn niederbügelt.

Wenn noch genug Speicher über ist, könntest Du den virtuellen 
Bildschirmbereich von der Speicheradresse her lassen wo er ist und einen 
zweiten in der selben Größe zusätzlich an anderer Stelle reservieren. 
Dann im Programm aktiv nur den neuen vewenden und jetzt im Debugger nen 
Breakpoint für den Zugriff auf den alten Bildschirmbereich setzen.

von Karl H. (kbuchegg)


Lesenswert?

Falk B. schrieb:
> @Karl Heinz (kbuchegg) (Moderator)
>
>>irgendwann mal ein Zeichen am LCD auftaucht, das da nicht hingehört.
>>Sauschwer zu finden, was da los ist. Auch, oder gerade wegen
>
> Bau doch einen selbstgestrickten Debugger ein. Prüfe deinen virtuellen
> LCD an der speziellen Stelle auf das spezielle Zeichen und gib ein
> Signal nach aussen.

Was glaubst du, was ich gemacht hab :-)

Nur das es die spezielle Stelle nicht gibt. Die eigentliche Ausgabe geht 
von einem virtuellen LCD aufs echte und das macht ein anderer Task. Ich 
hab keinen blassen, welche anderen der 25 anderen Tasks davor gelaufen 
sind.
Mir bleibt nichts anderes übrig, als das Teil mit Überwachungssequenzen 
zu spicken und abzuwarten.

Teil des Problems ist, dass ich den Fehler nicht forcieren kann. 
Manchmal dauert es Tage, bis er auftritt. Manchmal nur Minuten.

> kommentier die diversen Stellen mit Schreibzugriffen auf den virtuellen
> LCD schtrittweise aus. Du schaffst das, bist doch ein alter Hase.

Ich bin ziemlich sicher, dass das nicht über die LCD Funtkionen geht. 
Stichwort: Array Überlauf oder schreiben im falschen Speichersegment.
Ein japanisches Zeichen wird ganz sicher nirgends ausgegeben :-)

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Gerd E. schrieb:

> jetzt im Debugger nen
> Breakpoint für den Zugriff auf den alten Bildschirmbereich setzen.

Nochmal. Dafür hab ich kein Werkzeug. Leider.
Wenn ich den Speicher aktiv überwachen lassen könnte, wäre das Ding 
schon dingfest gemacht.

von Gerd E. (robberknight)


Lesenswert?

Wenn noch genug Speicher über ist: 2 Bildschirmspeicher reservieren und 
in beide gleichzeitig schreiben lassen. Dann regelmäßig vergleichen. 
Wenn die nicht mehr übereinstimmen, muss der Bug aufgetreten sein.

von Gerd E. (robberknight)


Lesenswert?

Karl H. schrieb:
> Nochmal. Dafür hab ich kein Werkzeug. Leider.

Da war ich zu langsam: als ich meine Antwort geschrieben hab, war der 
Text mit "kein Debugger" noch nicht da.

von Karl H. (kbuchegg)


Lesenswert?

Gerd E. schrieb:
> Karl H. schrieb:
>> Nochmal. Dafür hab ich kein Werkzeug. Leider.
>
> Da war ich zu langsam: als ich meine Antwort geschrieben hab, war der
> Text mit "kein Debugger" noch nicht da.

Meine Schuld.

Trotzdem. Danke für die Anteilnahme. Warum bin ich nicht einfach 
Strassenkehrer geworden. Das Leben könnte so schön einfach sein .....

(Nö. Um nix in der Welt möchte ich was anderes machen. Alleine das geile 
Gefühl, wenn nach Wochen/Monaten dann alles so läuft, wie ich mir das 
vorgestellt habe.)

von Gerd E. (robberknight)


Lesenswert?

Gerd E. schrieb:
> Wenn noch genug Speicher über ist: 2 Bildschirmspeicher reservieren und
> in beide gleichzeitig schreiben lassen. Dann regelmäßig vergleichen.
> Wenn die nicht mehr übereinstimmen, muss der Bug aufgetreten sein.

oder ne Prüfsumme über den Bildschirmspeicher berechnen. Problem wird 
nur sein, ohne Debugger aus dem Trigger-Signal die kurz vorher 
aufgerufenen (und damit verdächtigen) Funktionen herauszufinden. 
Vielleicht im Scheduler jedes Enter/Exit eines Threads in einen 
Ringpuffer schreiben. Wenn der Prüfsummencheck fehlschlägt den 
Ringpuffer ausgeben.

> (Nö. Um nix in der Welt möchte ich was anderes machen. Alleine das geile
> Gefühl, wenn nach Wochen/Monaten dann alles so läuft, wie ich mir das
> vorgestellt habe.)

jupp, das kenn ich.

: Bearbeitet durch User
von Wolle G. (wolleg)


Lesenswert?

Zumindest die letzten Beiträge sind offensichtlich für "echte" 
Programmierer gedacht und übersteigen meinen Horizont.
Deshalb werde ich zunächst erst einmal mit den Programmbeispielen von 
Karl Heinz und Falk arbeiten, um mein Problem zu lösen.

Falk B. schrieb:
> Jaja, der übliche Bastler-Murks. Das ist nicht mehr wirklich zeitgemäß.
> Nimm eine gescheite FAT-Lib. Du wirst es nicht bereuen.

Das kann ja sein. Aber ob das bei der Generation 70++ noch sinnvoll ist, 
erscheint mir fraglich.

von Falk B. (falk)


Lesenswert?

@ wolle g. (wolleg)

>> Jaja, der übliche Bastler-Murks. Das ist nicht mehr wirklich zeitgemäß.
>> Nimm eine gescheite FAT-Lib. Du wirst es nicht bereuen.

>Das kann ja sein. Aber ob das bei der Generation 70++ noch sinnvoll ist,
>erscheint mir fraglich.

Da ist es umso sinnvoller!

Beitrag "Re: Elm Chan FatFs SD Karte auf Keil MCB2300 LCP2378"

Das geht auch auf dem MSP430 ruck zuck!

Allerdings ist es zugegeben erst einmal einfacher, mit deiner 
bestehenden Funktion mmc_write() das in eine gescheite Form zubringen. 
Das wird den wesentlichen Schritt nach vorn bringen, der Rest ist eher 
Kosmetik.

von Wolle G. (wolleg)


Lesenswert?

Mein Problem konnte jetzt Dank Eurer Hilfe gelöst werden.

Nach kleinen Änderungen (Datentyp) läuft bei mir der Vorschlag von Karl 
Heinz.
Falk`s GANZ einfachen Vorschlag habe ich nicht zum Laufen gebracht, da 
mir offensichtlich die Programmiergrundlagen fehlen. (z.B. der Umgang 
mit 2-dimensionalen Feldern)

von Falk B. (falk)


Lesenswert?

@wolle g. (wolleg)

>Mein Problem konnte jetzt Dank Eurer Hilfe gelöst werden.

Gut. Dann poste doch mal das neue Programm und lass es begutachten.

>Falk`s GANZ einfachen Vorschlag habe ich nicht zum Laufen gebracht,

Der war auch unvollständig, es war nur eine Skizze.

>mir offensichtlich die Programmiergrundlagen fehlen. (z.B. der Umgang
>mit 2-dimensionalen Feldern)

Aua. Das solltest du schleunigst nachholen, das ist das KLEINE 1x1!

von Paul B. (paul_baumann)


Lesenswert?

Falk B. schrieb:
> ....Umgang
>>mit 2-dimensionalen Feldern)
>
> Aua. Das solltest du schleunigst nachholen, das ist das KLEINE 1x1!

Mit 3-dimensionalen Felder dann das kleine 1x1x1
;-)
MfG Paul

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.