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)
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.
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.. ;)
@ 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
voidlesen_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.
@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_tbuffer1[512];
2
uint8_tbuffer2[512];
3
4
uint8_t*volatileactiveBuffer;// welches ist der active Buffer
5
uint8_t*volatileotherBuffer;// und welches ist der andere
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
intbuffer[2][512];
2
volatileintbuffer_voll;
3
4
intmain(){
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
staticintcnt;
16
staticintbufferwahl;
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.
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.
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.
@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.
@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 :-)
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.
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