Fehler bei volatile-variable und ISR

OP #765783
Lesenswert?

Hallo zusammen,

basierend auf dem SoftwareUART und dem RC5 Librarys von PeDa versuche 
ich mit einem Tiny13 einen RC5-Decoder zu bauen, welcher seine Daten 
decodiert per rs232 an den PC liefert. Die RC5-Routine läuft prima, 
jedoch habe ich Probleme beim SoftwareUART.
Dabei geht es weniger um ein programmspezifisches Problem, sondern um 
ein allg. Datenaustauschproblem zwischen ISR und dem Hauptprogramm.

Im Hauptprogramm habe ich eine globale Variable (stx_counter) vom Typ 
unsigned char, in welcher die Anzahl der noch zu sendenden Bits 
gespeichert ist. Diese Variable ist volatile-deklariert, damit sie 
innerhalb der ISR und im Hauptprogramm verwendet werden kann.
Ändere ich diese Variable nun im Hauptprogramm (in sputchar()) auf 10, 
so wird mir das im Simulator auch so angezeigt. Sobald kurz danach aber 
die zur Abarbeitung notwendige ISR gestartet wird, ist die Variable aber 
auf einmal 0!

Das macht mich noch total wahnsinnig. Ich komme einfach nicht darauf 
warum.

Auszug aus dem Code an besagter Stelle:
1
void sputchar(unsigned char val )  // send byte
2
{
3
  while( stx_counter );      // until last byte finished
4
  stx_data = ~val;      // invert data for Stop bit generation
5
  stx_counter = 10;      // 10 bits: Start + data + Stop
6
}
7

8
void sputs(unsigned char* txt)    // send string
9
{
10
  while( *txt )
11
    sputchar( *txt++ );
12
}
13

14
ISR( SIG_OUTPUT_COMPARE0B )    // tx bit
15
{
16
  unsigned  dout;
17
  unsigned char mycount;
18

19
  OCR0B += BIT_TIME;      // next bit slice
20
  mycount = stx_counter;
21

22
  if( mycount ){
23
    mycount = --stx_counter;    // count down
24
    dout = 1<<COM0B1;      // set low on next compare
25
    if( mycount != 9 ){      // no start bit
26
      if( !(stx_data & 1) )    // test inverted data
27
  dout = 1<<COM0B1^1<<COM0B0;  // set high on next compare
28
      stx_data >>= 1;      // shift zero in from left
29
    }
30
    TCCR0A |= dout;
31
  }
32
}

Ich hoffe es hat jemand einen Rat für mich. Den gesamten Code habe ich 
auch noch angehägt. Hänge nun schon seit 2 Nächten daran...

Danke

Lorenz
Angehängte Dateien:
OP #766194
Lesenswert?

Okay, danke für den Stacktipp. Der scheint mir Probleme zu machen. So 
merke ich beim Einzelschrittdebugging (bisher nur Breakpoints benutzt) 
einige Resets des ProgramCounters. Nach dem Abarbeiten der Init-Routinen 
bleibt er mir ab und zu hängen und fängt dann von vorne an... In der 
Simulation kann ich jedoch keinen genauen Zusammenhang erkennen - mal 
gehts, mal nicht.

Trotzdem stehe ich immer noch vor einem unlösbaren Problem. Ich habe 
einfach keine Ahnung was ich sonst noch ändern könnte. Variablen habe 
ich so weit wie möglich reduziert und nur die nötigsten als "volatile" 
deklariert. Aber selbst bei einer golbalen und einer volatile-variablen 
kommt er aus dem Tritt.

Gibt's da irgendeine besonders geeignete Debuggingmethode solchen 
Fehlern auf die Schliche zu kommen?

Danke

Lorenz

PS: die Dateien SUART.* im zip-file sind unnötig, der Inhalt ist in der 
main.c integriert.
Gast #766405
Lesenswert?

... mal bei K&R nachlesen was das Attribut "volatile" bedeuted. Es wird 
lediglich die Optimierung der Sequenz unterbunden, aber nicht 
automatisch eine Interrupt-Sperre gesetzt. Wenn du also weiterhin mit 
globalen Variablen in verschiedenen Kontexten arbeiten möchtest, dann 
kommst du nicht umhin die "Critical Sections" mit Interrupt-Sperren zu 
schützen.

Vielleicht ist's ja z.Zt. wirklich der Stack, aber inkonsistente Daten 
auf Grund fehlender rmw-Protection sind hier nur eine Frage der Zeit.

Bj
OP #769222
Lesenswert?

Hallo,

also ich habe das Projekt mittlerweile erfolgreich zum Laufen gebracht.
Zuerst habe ich die Aufteilung auf mehrere Funktionen rückgängig 
gemacht. So wird z.B. der Init direkt im Hauptprogramm durchgeführt, 
nicht mehr in einer Unterroutine. Das hat bei den Sprüngen schon mal gut 
geholfen, der Stack läuft nun nicht mehr über.
Was Bj mit dem Hinweis auf "volatile" meint ist mir rätselhaft. Wie das 
genutzt wird ist schon klar, jedoch ist meinem Code keine critical 
secion wovor die IRQs deaktiviert werden sollten. Aber egal, hat mein 
Interesse geweckt, da werde ich mich gleich mal einlesen.

Danke für eure Ratschläge

Gruß

Lorenz
Gast #769653
Lesenswert?

...wenn du einen K&R zur Hand hast, dann lese !

Ansonsten sei dir erklärt dass eine Compiler keine Ahnung von Hardware 
hat. Wenn man also nun auf Port's oder Hardware-Zellen zugreift, dann 
ist es für die Toolchain nur eine Schreib/Lese Operation auf eine 
Speicherzelle, mehr nicht. Um nun dem Optimizer mitzuteilen, das eine 
Sequenz genau so abgearbeitet werden soll wie im Quellcode geschrieben, 
erklärt man die "Variablen", die eigentlich eine Hardware ansprechen als 
"volatile".

Liest man z.B. von einem Port, rechnet etwas und liest erneut von dem 
Port, so können diese Daten durchaus verschieden sein da ja die Signale 
in der Zwischenzeit anders sein können. Teilt man das dem 
Compiler/Optimizer nicht mit, so erkennt dieser lesen von Adr. XXXX und 
eine Zeit später wieder lesen von XXXX und wird das zusammenfassen, da 
ja zwischenzeitlich im Speicher nichts an Adresse XXXX passiert ist. Um 
das sinnvolle zweifache Lesen zu erzwingen musst du dem Tool halt 
mitteilen, dass die Daten volatil sind.

Das hat rein gar nichts mit deiner Interpretation zu tun (Diese Variable 
ist volatile-deklariert, damit sie innerhalb der ISR und im 
Hauptprogramm verwendet werden kann.)

Weiterhin gibt es fast immer Critial Sections bei Verwendung von 
globalen Variablen in Foreground und Interrupt. Schalte mal die 
Optimierung aus und schaue das Assembler-Listing an. 
Variablen-Manipulation ist fast ausnahmslos read-modify-write. Wird 
diese nicht-atomare Sequenz unterbrochen, dann kann es durchaus 
vorkommen dass der "write" was anders zurückschreibt als das "modify" 
generiert hat. Kenne zwar den Befehlssatz des AVR nicht auswendig, man 
möge mich aber korrigieren wenn die CPU direkt im Speicher manipulieren 
kann.

Bj

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren