Forum: Mikrocontroller und Digitale Elektronik Fehler in Bascom?


von Michael L. (nightflyer88)


Lesenswert?

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.

von Klaus D. (kolisson)


Lesenswert?

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

von MWS (Gast)


Lesenswert?

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.

von Michael L. (nightflyer88)


Lesenswert?

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.

von holger (Gast)


Lesenswert?

>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.

von Hannes L. (hannes)


Lesenswert?

Michael L. schrieb:
> Mache ich statt der Multiplikation, 5 mal
> eine Addition, so stimmts immer.

Framesize groß genug für Multiplikation?

...

von Klaus D. (kolisson)


Lesenswert?

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

von Michael L. (nightflyer88)


Angehängte Dateien:

Lesenswert?

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 ?

von Michael L. (nightflyer88)


Angehängte Dateien:

Lesenswert?

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 ?

von Hannes L. (hannes)


Lesenswert?

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.

...

von Michael L. (nightflyer88)


Angehängte Dateien:

Lesenswert?

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 ....

von MWS (Gast)


Lesenswert?

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.

von Michael L. (nightflyer88)


Lesenswert?

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.

von Hannes L. (hannes)


Lesenswert?

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.

...

von MWS (Gast)


Lesenswert?

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.

von Michael L. (nightflyer88)


Lesenswert?

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 ?

von Hannes L. (hannes)


Lesenswert?

Michael L. schrieb:
> ob Befehle die mehr
> als ein Takt benötigen, ein Interrupt verzögern können ?

Das können sie.

...

von MWS (Gast)


Lesenswert?

Michael L. schrieb:
> ob bei einer Multiplikation in Bascom die
> interrupts auch kurz AUS/EIN geschaltet werden,

Nein.

von c-hater (Gast)


Lesenswert?

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...

von Charly B. (charly)


Lesenswert?

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

von Michael L. (nightflyer88)


Lesenswert?

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 ?

von c-hater (Gast)


Lesenswert?

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.

von Michael L. (nightflyer88)


Lesenswert?

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

von Charly B. (charly)


Lesenswert?

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

von Charly B. (charly)


Lesenswert?

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

von Hannes L. (hannes)


Lesenswert?

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
Noch kein Account? Hier anmelden.