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)
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
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.. ;)
:-) 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?
@ 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
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.
@ 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.
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.
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).
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...
@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
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.
Hast du eine bessere Story dazu, die das Prinzip mindestens genaus so gut rüberbringen kann? Dann schreib sie. W.S.
@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 . . .
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 :-)
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.
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
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?
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
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.
@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.
@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.
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
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
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? ;-)
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.
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.
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.
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
@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 ;-)
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
@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 ;-)
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.
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
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.
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.
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.
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.)
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
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.
@ 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.
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)
@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!
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.