Vielleicht gibt es hier ja noch jemand anderen der mit
Padauk-Controllern immer wieder mal "spielt". Mir vergeht aber für den
Moment etwas die Laune, weil ich ein Problem mit dem Timerinterrupt beim
PFS154 habe... immer wieder einmal.
Ich möchte ein an sich sehr einfaches Würfelprogramm erstellen. Unter
anderem soll das Programm auch Zahlensystem "lehren" und weil es
gebräuchliche Zahlensystem zur Basis 2, 10 und 16 genügend gibt hier
dann natürlicherweise zur Basis 6.
Also möchte ich einen 3-fach Würfel erstellen und dann eben nicht nach
guter, alter Väter Sitte jede einzelne Würfelstelle bis 6 zählen und
dann die nächste Stelle erhöhen, sondern von 0..215 (das sind (6^3)-1).
Hierzu habe ich dann etwas einfaches programmiert:
1
void int2dices(uint8_t val, uint8_t *buf)
2
{
3
volatile uint8_t i, dice, divi;
4
5
__disgint();
6
divi= 36;
7
for (i= 0; i< 3; i++)
8
{
9
dice= 0;
10
while(val >= wivi)
11
{
12
dice++;
13
val -= divi;
14
}
15
*buf= dice+1;
16
buf++;
17
wivi = divi / 6;
18
}
19
__engint();
20
}
Die Volatile-Variablen sind der "Fehlersuche" geschuldet, genauso wie
das ab- und anschalte der globalen Interrupts.
Diese Funktion funktioniert auf Systemen (getestet) mit MCS-51, AVR,
STM8, STM32.
Auch auf dem Padauk PFS154 läuft das, wenn auf dem Padauk KEIN
Timerinterrupt läuft.
Das angehängte C-Programm ist in der Main etwas "zerfahren" weil ich
hier Nebeneffekte untersuchen möchte.
Ein Hochzählen der einzelnen Stellen (wie ich es eben nicht möchte)
funktioniert. Ginge es nur um eine Würfel, könnte man diesen so
realisieren (aber eigentlich will ich die Zufallszahl nicht durch eine
unterbrochene Zählschleife, sondern über einen
Pseudozufallszahlengenerator mit linear rückgekoppeltem Schieberegister
realisieren).
Soweit so gut (oder schlecht). Wird die Funktion "int2dices" in die
Endlosschleife der Main eingehängt, hängt sich diese auf. Der Interrupt
wird jedoch weiter abgearbeitet, weil die Würfelanzeigen weiterhin
gemultiplext werden. Ich gehe (fälschlicherweise?) davon aus, dass auch
keine 16-Bit Operation unterbrochen wird, weil ich schlicht keine
verwende. Selbst ein Abschalten der Interrupts in "int2dices" hilft
nicht.
Ich mache (so glaube ich) garantiert etwas mit der Timerinitialisierung
und oder im Interruptvektor falsch:
Wie gesagt: auf anderen Systemen funktioniert die Vorgehensweise ohne zu
murren, nur auf dem PFS154 nicht (hier habe ich aber auch glaube ich
nicht alle Informationen, die es evtl. bräuchte).
Verwendeter Compiler sind SDCC 4.1.0 und SDCC 4.3.0 (beide zeigen
gleiches Verhalten, so denke ich, liegt der Fehler bei mir)
Weiß hier jemand etwas weiterführendes zu den Interrupts beim PFS154 ?
Wie schnell läuft der PFS154? Könnte es sein, dass die Interruptroutine
soviel Zeit braucht, dass der Prozessor nicht mehr dazu kommt, das
Hauptprogramm auszuführen?
Wozu das __disgint() und __engint() im Interrupt-Handler? Letzteres
würde doch Interrupts wieder einschalten, bevor der Interrupthandler
zurückkehrt, so dass dieser, falls er nicht schnell genug ist, durch
einen weiteren Interrupt unterbrochen würde, was dann einen
Stack-Overflow ergäbe.
Ralph S. schrieb:> Wird die Funktion "int2dices" in die Endlosschleife der Main eingehängt,> hängt sich diese auf.
Ja, warum wohl? Nachdem die Schleife zwei Durchläufe gemacht hat, steht
in "val" der Wert der niedrigsten Stelle. Also kein Grund ein drittes
mal die Schleife zu durchlaufen. Wenn die niedrigste Stelle null ist,
bleibt das Programm im "while" hängen.
Hallo Philipp, super vielen Dank fürs melden...
Philipp Klaus K. schrieb:> Wie schnell läuft der PFS154? Könnte es sein, dass die Interruptroutine> soviel Zeit braucht, dass der Prozessor nicht mehr dazu kommt, das> Hauptprogramm auszuführen?
Das wäre eine Möglichkeit, an die ich auch gedacht hatte. Laut EasyPdk
und den Compilerangaben sollte der Chip mit 8 MHz laufen. Dies ist die
Standardeinstellung meiner Toolchain und hab ich bei anderen Programmen
schon überprüft, werde ich hier aber auch machen in dem ich per
Timerinterrupt einen Pin wackeln lasse und oszillographiere. Auf einem
AVR und einem STM8 lief die Funktion mit natürlich anderem
Interruptvektor unauffällig.
Philipp Klaus K. schrieb:> Wozu das __disgint() und __engint() im Interrupt-Handler? Letzteres> würde doch Interrupts wieder einschalten, bevor der Interrupthandler> zurückkehrt, so dass dieser, falls er nicht schnell genug ist, durch> einen weiteren Interrupt unterbrochen würde, was dann einen> Stack-Overflow ergäbe.
:-) , das ist der "Verzweiflung" geschuldet und habe ich hier noch nicht
rausgenommen. Beim ersten Entwurf waren __disgint und __engint noch
nicht drin. Ich hatte hier "einfach nur" verschiedene Dinge ausprobiert
um zu nachzuforschen. Von daher: Wenn man "dumm" ist (like me) und nicht
weiß, warum etwas nicht funktioniert, macht man Dinge, von denen man
weiß dass sie auch nicht funktionieren, probiert sie aber dennoch aus
(ich sag ja: dumm).
Mario M. schrieb:> Ja, warum wohl? Nachdem die Schleife zwei Durchläufe gemacht hat, steht> in "val" der Wert der niedrigsten Stelle. Also kein Grund ein drittes> mal die Schleife zu durchlaufen. Wenn die niedrigste Stelle null ist,> bleibt das Programm im "while" hängen.
Auch hier hat sich beim Einstellen hier ein Fehler eingeschlichen (die
gepostete Funktion würde sich gar nicht übersetzen lassen, weil das
umbenennen von Variablen meinerseits nicht vollständig war). Aber, das
nicht korrekte Funktionieren ist nicht die Schuld von "int2dices".
Überprüft wurde das mit (Konsolenprogramm Linux):
Ralph S. schrieb:> Auch hier hat sich beim Einstellen hier ein Fehler eingeschlichen
Deswegen fügt man immer genau den vollständigen Quelltext als Anhang
ein, den man wirklich compiliert und getestet hat!
Mehrere Dateien kann man in ein Zip packen.
Das Einfügen in den Post ist nur in seltenen Ausnahmen sinnvoll. Und
auch da immer nur mit C&P, nie aus dem Gedächtnis nachgeschrieben und
auf keinen Fall ungetestet!
Peter D. schrieb:> Deswegen fügt man immer genau den vollständigen Quelltext als Anhang> ein, den man wirklich compiliert und getestet hat!> Mehrere Dateien kann man in ein Zip packen.
Asche über mein Haupt, du hast eben recht
Ralph S. schrieb:> Aber, das> nicht korrekte Funktionieren ist nicht die Schuld von "int2dices".
Ja, jetzt sehe ich es auch. Divi ist beim letzten Durchlauf "1", die
While-Schleife bleibt nicht hängen. Unnütz ist er trotzdem, der Rest der
"Division" ist schon in "val".
Kaum macht man alles (hoffentlich) richtig, schon funktioniert auch
alles !
Nachdem ich mein Linux erneuert habe auf Kernel 6.5.5 und GLIBC 2.35
(ich weiß, wir sind momentan bei Kernel 6.12.1 und GLIBC 2.40) konnte
ich dann auch den SDCC Version 4.4.4 #15109 installieren.
An der SDCC-Version lag es aber (wie ich eh angenommen hatte) aber
nicht.
Der Fehler war, dass mein Interrupt eine Delay-Schleife unterbrochen
hat, die die Taktimpulse zaehlt und in Assembler codiert ist. Hierin hat
sich mein Programm dann tatsächlich aufgehängt.
Gelöst habe ich das dann in der Art, dass im Timerinterruptvektor ein
Millisekundenzähler implementiert ist. Eine neue Delay-Funktion bedient
sich dann aus diesem Zähler und zählt nicht die Taktimpulse.
Was habe ich gelernt?
- Bei scheinbar einfachen Sachen ist meistens weder das System noch der
Compiler schuld. Nach der Korrektur läuft mein Programm auch noch, wenn
es mit SDCC 4.0.3 compiliert wird.
- wenn der Fehler logisch nicht an den Stellen sein kann an denen ich
suche: Suche woanderst.
- traue dir selbst nicht und auch deiner eigenen Toolchain nicht. Es
kann irgendwo ein Fehler sein, der noch nicht aufgetreten ist.
- poste immer alles was zum Programm gehört, damit andere dir helfen
können (ich hoffe ich halte mich daran !)
Bei der Fehlersuche hatte ich den 16-Bit Timer verwendet (Timer 2 war,
wie ich jetzt weiß nicht das Problem) und habe diesen im Code belassen
und Timer 2 entfernt.
Im Anhang ist die komplette Toolchain inklusive abgespecktem SDCC 4.4.4
welcher nur Padauk Controller übersetzen kann, sowie die Uploadprogramme
für EasyPdkProgrammer und den Arduino basierenden Programmer. Die
Lizensbedingungen zum SDCC sind natürlich enthalten.
Mit dem Installieren von SDCC 4.4.4 tut sich ein neues - kleineres
Problem - mit der Assemblerzählschleife "delay" auf, die mir eine
Warnung ausgibt, aber dennoch funktioniert. Bevor ich das "Problem"
schildere versuche ich dem aber erst auf den Grund zu gehen.
Vielen Dank an Philipp Klaus K. (pkk) und Peda D. (peda)