Hallo Zusammen Ich habe ein seltsames Problem: In einem Hauptprogramm mache ich eine Berechnung b = b * 5, nun gibt es ab und zu eine fehlberechnung. Mache ich statt der Multiplikation, 5 mal eine Addition, so stimmts immer. Kann mir jemand sagen woran das liegt ? Ich verwende Bascom 2.0.7.3 b ist ein integer. Der Chip ist ein Attiny85. Zusätzlich tritt ab und zu ein interrupt auf, in der dazugehörigen ISR werden aber alle Register und das SREG gesichert.
Michael L. schrieb: > Zusätzlich tritt ab und zu > ein interrupt auf, in der dazugehörigen ISR werden aber alle Register > und das SREG gesichert. Dann würde ich an deiner Stelle zunächst dort suchen. Bascom hat zwar je nach Version viele Fehler aber es ist nicht sinnvoll anzunehmen dass die bei einer Multiplikation auftreten. Versuch mal "Poppall" für deine ISR. Gruss Klaus
Klaus De lisson schrieb: > Versuch mal "Poppall" für deine ISR. Da muss er aber vorher ein Pushall machen, sonst wird's lustig. Aber das ist sowieso in Zusammenhang mit ISRs nur für Single und Double notwedig.
Die ganze ISR ist in ASM geschrieben. In dieser wird nur das r17, r30, r31 und das SREG benötigt, entsprechend werden diese auch mit push/pop gesichert. Die ISR ist in Basom mit nosave deklariert. Sollte das SREG nicht korrekt gesichert werden, so würde auch die addition nicht funktioniern. Morgen stelle ich dann mal den ganzen Code rein.
>Die ISR ist in Basom mit nosave deklariert. >Sollte das SREG nicht korrekt gesichert werden, Sollte, könnte, müsste.. Beschissene Vermutungen sind der Anfang allen Übels. Funktioniert die Multiplikation ohne die ISR, ja oder nein? Probier es aus, dann hast du eine Stelle weniger zum suchen.
Michael L. schrieb: > Mache ich statt der Multiplikation, 5 mal > eine Addition, so stimmts immer. Framesize groß genug für Multiplikation? ...
Michael L. schrieb: > Die ISR ist in Basom mit nosave deklariert. Da ziehe mal meine erste Aussage mit Popall und pushall zurück. Das war wohl etwas unüberlegt. (habe auch länger nix mit Bascom gemacht) Dir, Michael empfehle ich mal das "nosave" wegzulassen. Im Laufe der Jahre, wo ich Bascom verwende sind mir nur die Register 23 und 24 als relativ sicher aufgefallen. Diese Sicherheit ändert sich aber massiv wenn z.B. LCD oder sonstwelche LIBS einbindet. Daher der Tipp: verzichte auf "nosave" wenn du INLINE verwendest. Wenn alles gut läuft kannst du "Nosave" probieren. Leider ändert sich die Verwendung der Register durch Bascom Updates gerne mal. Eine Betriebssicherheit erreicht du damit nicht. Gruss Klaus
Also wie versprochen der Code Das ganze ist ein i2c Slave, der das Atmel USI verwendet. Es gibt zwei interrupts zur kommunikation mit dem i2c. Leider kann ich bei der ISR I2c_read_write das nosave nicht weglasen, da sonst zuviel zeit benötig wird, wenn bascom alle register sichern will. Deshalb habe ich die ganze ISR in ASM geschrieben. Die Framesize ist auf 24 eingestellt. Ich habe keine Ahnung ob das zu viel oder zuwenig ist ! Wie gross sollte diese den sein ? Allen Variablen habe ich mit overlay, manuel eine Adresse im SRAM vergeben. Bascom legt doch auch irgendwelche Werte oder Stack im SRAM ab, kann es sein dass sich da was überschneidet ?
Habe nun das ganze im Simulator angeschaut. Bei einer Multiplikation ändert sich im Blau markierten Bereich ständig etwas. Bei einer Addition nicht. Habe den HW und SW Stack auf je 50 definiert und Framesize auf 100. Funktionieren tut die Multiplikation trotzdem nicht. So wie es ausschaut überläuft irgend ein Stack oder wird durcheinander gebracht, wenn ein Interrupt auftritt. Ich begreife jetzt nicht genau wo den überhaupt der HW, SW Stack und Framesize im SRAM beginnt ?
Michael L. schrieb: > ch begreife jetzt nicht genau wo den überhaupt der HW, SW Stack und > Framesize im SRAM beginnt ? Dann schau Dir die Report-Datei ("*.rpt") an. ...
Ok, super habs gesehen.... sollte also mit Stack und Framesize passen. Habe die Datei mal angehängt, sieht da sonst noch jemand was, was irgendwie komisch ist ? Ich kann mir einfach nicht erklären warum das nicht funktioniert ....
1 | B = 513 - B |
2 | '******hier ist die Berechnung, addition funktioniert einwandfrei |
3 | C = B + B |
4 | C = C + B |
5 | C = C + B |
6 | C = C + B |
7 | '******alternativ mit Multiplikation funktioniert nicht zuverlässig |
8 | 'C = C * 5 |
Wenn "alternativ" wörtlich zu nehmen ist, dürfte es gar nicht funktionieren, da es C = B * 5 lauten müsste.
Oh ja, von der ganzen probiererei mit anderen Variablen ist mir da ein kleiner fehler passiert. Natürlich sollte es C = b * 5 heissen, aber auch so funktionierts nicht, respektive rechnen tuts schon richtig, nur wenn halt genau während der berechnung ein Interrupt auftritt, entsteht der fehler.
Michael L. schrieb: > nur > wenn halt genau während der berechnung ein Interrupt auftritt, entsteht > der fehler. Vergleiche mal beide ISRs. In I2C_start sicherst Du das SREG nicht. ...
Hannes Lux schrieb: > Vergleiche mal beide ISRs. In I2C_start sicherst Du das SREG nicht. Er verwendet auch keine Befehle, die das SReg verändern.
In der I2C_start ISR werden keine flags benötig, deshalb hab ich das SREG auch nicht gesichert, habe es aber trotzdem versucht und es wird nicht besser. Ich muss vielleicht noch anfügen, dass ich den berechneten Wert direkt per i2c auslese. Den Fehler konnte ich nun auf eine andere art reproduzieren, und zwar wenn ich im Hauptprogramm kurz die Interrupts AUS und direkt wieder EIN schalte, passiert das gleiche (falscher Wert wird gelesen). Der Code des Hauptprogramms: Do c = 50 $asm NOP NOP NOP CLI SEI NOP NOP NOP $end asm Disable Usi_start Strom = c Spannung = c enable Usi_start Loop So wie es jetzt ausschaut tritt der fehler nicht bei der berechnung auf, sondern bei der übertragung per i2c. Mir ist bewust, dass die I2c_read_write ISR sehr zeitkritisch ist. Meine frage ist nun, ob bei einer Multiplikation in Bascom die interrupts auch kurz AUS/EIN geschaltet werden, oder ob Befehle die mehr als ein Takt benötigen, ein Interrupt verzögern können ?
Michael L. schrieb: > ob Befehle die mehr > als ein Takt benötigen, ein Interrupt verzögern können ? Das können sie. ...
Michael L. schrieb: > ob bei einer Multiplikation in Bascom die > interrupts auch kurz AUS/EIN geschaltet werden, Nein.
Michael L. schrieb: > Meine frage ist nun, ob bei einer Multiplikation in Bascom die > interrupts auch kurz AUS/EIN geschaltet werden, oder ob Befehle die mehr > als ein Takt benötigen, ein Interrupt verzögern können ? Natürlich. Jede AVR-Instruktion ist "atomar", wird also zwingend bis zum Ende abgearbeitet, bevor ein Interrupt zum Zuge kommen kann. Beim größten Teil der Produktpalette (ausgenommen die ganz kleinen Tinys ohne echten Stack und die Megas mit externem Speicherinterface) kanst du mit 3 Takten variabler Interruptlatenz und 4 Takten konstanter Latenz rechnen. Natürlich darf dafür nirgendwo im Code ein "cli" vorkommen. Sonst kann die variable Latenz natürlich quasi beliebig länger werden...
Michael L. schrieb: > Meine frage ist nun, ob bei einer Multiplikation in Bascom die > interrupts auch kurz AUS/EIN geschaltet werden, oder ob Befehle die mehr > als ein Takt benötigen, ein Interrupt verzögern können ? warum sollte das passieren? wenn das ganze so zeitkritisch ist warum verwendest du die multiplikatio? die dauert ueber 200 Tcyclen, die addition nur 80 Tcyclen Alternativ: cli C = B * 5 sei vG Charly
Also habe das eigentliche Problem gefunden: Da die I2c_read_write ISR sehr zeitkritisch ist, d.h. wenn ich im Hauptprogramm zu lange "warte" bis ich in die ISR springe entsteht eine Fehlübertragung, und es sieht aus als ob falsch gerechnet wird. Wenn also in der Multiplikation Befehle vorkommen die 3 oder 4 Takte benötigen, entstand schon der Fehler. Ich habe nun die ISR optimiert, so das ich 10 Takte "warten" kann, bis ich in die ISR springe. Ein kleiner Test, der funktioniert: Do 'Hauptprogramm B = 300 B = 513 - B C = B * 5 B = 500 D = B * 50 D = D / 26 Disable Interrupts $asm nop nop nop nop nop nop nop nop nop nop nop $end Asm Enable Interrupts Disable Usi_start Strom = C Spannung = D Enable Usi_start Loop Jetzt habe ich aber wieder ein Problem: Will ich den ADC auslesen, entsteht der Fehler trotzdem wieder ?! Admux = &B00000011 'ADC3 aktivieren Adcsra = &B11000111 'ADC ON, ADC Start, Prescaler 128 Waitms 1 C = Adcl B = Adch 'ADC Daten Register auslesen Shift B , Left , 8 B = B + C alternativ mit dem Bascom Befehl B = Getadc(3) funktionierts auch nicht. Die Frage ist jetzt wieder, ob irgendetwas zuviel Zeit verbraucht, damit das Interrupt verzögert wird ? Oder ist der ADC falsch konfiguriert ?
Michael L. schrieb: > Da die I2c_read_write ISR sehr zeitkritisch ist, d.h. wenn ich im > Hauptprogramm zu lange "warte" bis ich in die ISR springe Wenn schon variable Latenzen in der Größenordnung von drei Takten zu Fehlverhalten führen, dann betreibst du einfach deinen I2C-Bus mit einer zu hohen Taktfrequenz für die Leistungsfähigkeit deines Slave. > Ich habe nun die ISR optimiert, so das ich 10 Takte "warten" kann, bis > ich in die ISR springe. Naja, Optimierung von ISRs ist immer eine gute Idee. > Will ich den ADC auslesen, entsteht der Fehler trotzdem wieder ?! > alternativ mit dem Bascom Befehl B = Getadc(3) funktionierts auch nicht. > Die Frage ist jetzt wieder, ob irgendetwas zuviel Zeit verbraucht, damit > das Interrupt verzögert wird ? Könnte höchstens Waitms sein. Kann es sein, daß das Teil die Interrupts blockiert, um eine exakte Zeitspanne warten zu können? Warum benutzt du überhaupt Waitms? Die Hardware stellt doch ein Flag bereit, mit dem du abfragen kannst, ob die Wandlung fertig ist. Warte doch einfach auf dieses Flag.
Also habe mal die ganze ADC geschichte in ASM geschriben. Frage ich nur ein ADC ab, funktioniert alles einwandfrei. Frage ich beide nacheinander ab, kommt totaler Misst raus. Auch wenn ich den i2c bus weglasse, und die daten per RS232 ausgebe, kommt der gleiche Misst raus. Irgend etwas ist in dem ADC code falsch, aber was ?? Das ganze sieht etwa so aus: Do 'Hauptprogramm $asm 'Strom messen push r18 ldi r18 , &B00000011 Out Admux , R18 ldi r18 , &B11000111 Out Adcsra , R18 Wait_adc_3: sbis Adcsra , 4 rjmp Wait_adc_3 in r18, Adcl sts &H65, r18 in r18, Adch sts &H66, r18 pop r18 $end Asm C = 513 - C C = C * 5 $asm 'Spannung messen push r18 ldi r18 , &B00000010 Out Admux , R18 ldi r18 , &B11000111 Out Adcsra , R18 Wait_adc_2: sbis Adcsra , 4 rjmp Wait_adc_2 in r18, Adcl sts &H67, r18 in r18, Adch sts &H68, r18 pop r18 $end Asm D = D * 50 D = D / 26 Print #1 , C; Print #1 , " "; Print #1 , D Waitms 500 Loop
Michael L. schrieb: > Wenn > also in der Multiplikation Befehle vorkommen die 3 oder 4 Takte > benötigen, entstand schon der Fehler. > also 3 Tcyclen sind grad mal 0.375 µS , wenn das ganze WIRKLICH so zeitkritisch ist dann bist du mit den µC und Bascom auf dem ABSOLUT falschen Loesungsweg.... vG Charly
Michael L. schrieb: > > Do 'Hauptprogramm > $asm 'Strom messen > push r18 > ldi r18 , &B00000011 &B00000011 ????????????????????????????????? > Out Admux , R18 > ldi r18 , &B11000111 &B11000111 ?????????????????????????????????? > Out Adcsra , R18 > Wait_adc_3: > sbis Adcsra , 4 ??????????????????????????????????????????? usw. usw. meinst du ich/(wir) suche hier wechles bit welche bedeutung hat nur weil du zu faul bist das vernuenftig zu kommentieren? meiner Meinung nach ist es eine Frechheit so ein Code hier einzustellen und Hilfe zu verlangen, ist meine Einstellung, ich kaempfe mich nicht durch solchen Code, und ich wuerde wetten nach spaetestens einer Woche weisst du selber nicht mehr was du da 'gekotet' hast ..... vlG Charly
Michael L. schrieb: > ldi r18 , &B00000010 > Out Admux , R18 > ldi r18 , &B11000111 > Out Adcsra , R18 > Wait_adc_2: > sbis Adcsra , 4 > rjmp Wait_adc_2 > in r18, Adcl Da kannst Du auch "Getadc()" benutzen, denn das ist genauso blockierend. Man kann den ADC auch "vorausschauend" benutzen. Dazu stellt man die Quelle in ADMUX nicht erst dann ein, wenn man das Ergebnis haben will, sondern bereits vorher. Denn man weiß ja schon im Vorfeld, welche Quelle man als nächstes messen will. Dummerweise lässt sich dieser effiziente Umgang mit dem ADC nicht ohne Zugeständnisse in die in Hochsprachen angestrebte Funktions-Struktur packen. ...
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.