Morgen zusammen!
Ich habe ein Problem mit einer Variablen meines structs.
Hier erstmal das struct:
1
struct// Struct contains information used for communication with EEPROM
2
{
3
uint16_taddress;// Address to be read or written
4
uint8_tbyte[8];// Byte 1 to 8 for complete page write
5
uint8_tbytecount;// Number of bytes to read or written
6
uint8_tnextbyte;// Next byte to be transmitted
7
uint8_teeprom_nr;// Selects between different EEPROMs
8
}eeprom;
Und hier die Interrupt-Routine:
1
#pragma vector = USCIAB0TX_VECTOR
2
__interruptvoidusciab0vector(void)
3
{
4
if(IFG2&UCB0TXIFG)// Byte successfully read from USCB0-TX-Buffer
5
{
6
7
if(eeprom.bytecount!=1)// More than one byte
8
{
9
eeprom.nextbyte+=1;
10
if(eeprom.nextbyte<eeprom.bytecount)
11
{
12
UCB0TXBUF=eeprom.byte[eeprom.nextbyte];
13
}
14
else
15
{
16
eeprom.nextbyte=0;
17
EE1_WP;// Write protect enabled
18
EE1_DES;// Deselect EEPROM
19
}
20
}
21
22
}// End if (IFG2 & UCB0TXIFG)
23
}
Und zwar möchte ich damit mein EEPROM Interrupt-gesteuert beschreiben.
In der Interrupt-Routine soll jedesmal automatisch das nächste Byte
geladen werden. Insgesamt halt 8 Bytes für einen Page-Write.
Mein Problem: Jedesmal, wenn die ISR aufgerufen wird, also jedesmal,
wenn der uC das Byte aus dem Sendepuffer entfernt hat und bereit für das
nächste ist, ist meine Variable
1
eeprom.nextbyte
wieder 0! Somit wird natürlich jedesmal dasselbe Byte verschickt.
Während die ISR abgearbeitet wird, wird die Variable erhöht, aber sie
ist nächstes mal nciht mehr da.
Das struct ist global deklariert, wenn ich es zusätzlich als volatile
deklariere, oder seine Kompnenten, dann gibts ne Warnung.
Hat jemand nen Tip?
Überleg nochmal, ob dein 2. if in deiner ISR wirklich die Bedingung
prüft, die du willst. Das Kommentar dahinter sagt nämlich was
anderes....
Dann müsste es heißen:
if (eeprom.bytecount > 1)
Gruß
Mandrake
lege ich hier fest, dass es 5 Bytes sind, die übertragen werden sollen.
Dann wird das erste in den TX-Buffer geschrieben und nach erfolgreichem
Lesen aus dem TX-Buffer wird die ISR aufgeruen und das zweite Byte soll
gesendet werden.
1
if(eeprom.bytecount!=1)// More than one byte
2
{
3
eeprom.nextbyte+=1;
4
if(eeprom.nextbyte<eeprom.bytecount)
5
{
6
UCB0TXBUF=eeprom.byte[eeprom.nextbyte];
7
}
8
else
9
{
10
eeprom.nextbyte=0;
11
EE1_WP;// Write protect enabled
12
EE1_DES;// Deselect EEPROM
13
}
14
}
Die if-Anweisung stellt nur sicher, dass wenn nur ein Byte zum
Übertragen war, kein neuer Wert in den Puffer geschrieben wird und somit
auch kein neuer Interrupt vom USCI-Modul kommt.
Also ab zwei Bytes ght das Programm in die Anweisung rein und soll nun
den
1
eeprom.nextbyte
um 1 erhöhen, wodurch aus dem Array das Byte 1 (also das Zweite
gesendet werden soll. Das funktioniert auch, Der TX-Buffer bekommt
1
byte[1]
.
Nächste if-Anweisung ist auch wahr, da 1 < 5 und der TX-Buffer wird
neugeladen. So, bei der nächsten ISR ist
1
eeprom.nextbyte
jedoch nicht mehr 1, sondern wieder 0 und ab da drehts sich natürlich
rum und rum...
Mandrake schrieb:> Dann müsste es heißen:> if (eeprom.bytecount > 1)
Ja, OK, das stimmt, hat den selben Effekt, schließt nur auch noch die 0
mit ein, obgleich ich den Sendebefehl natürlich nicht aufrufe, wenn
nichts zum Senden da ist.
A. K. schrieb:> Und wie so oft fehlt volatile.
Nein, das fehlt nicht, habe es jetzt in verschiedenen Varianten
ausprobiert, habe erst das gesamte struct als volatile deklariert, gibts
ne Warnung mit undefined behaviour. Erstmal ignoriert -> selbes Ergebnis
Dann habe ich die einzelnen Komponenten im struct als volatile
deklariert, selbe Warnung -> selbes Ergebnis
Dann mal nur die betroffene Variable als volatile -> keine Warnung, aber
selbes Ergebnis
Hat da niemand nen Tip für mich?
Ist ja nicht Controller bezogen, ist ja mehr generell irgendein Fehler
in meinem C Quelltext.
Ich ste grad echt aufm Schlauch, probiere hier um, aber kriegs nicht
hin.
Da hilft nur Reduktion.
Schmeiss mal alles aus dem Programm raus, was nicht unbedingt für das
EEProm schreiben nötig ist und stell dann das komplette Teil mal hier
rein.
Ich vermute mal, du überschreibst dir irgendwo ganz anders die Variable
bytecount.
Sascha schrieb:> UCB0CTL0 = UCCKPH + UCMSB + UCMST + UCSYNC;
Ich habe in diesem Fall keine Ahnung, aber das sieht für mich komisch
aus (repräsentativ für ähnliche Konstrukte).
Das soll doch hoffentlich kein Zusammensetzen eines Steuerbytes sein.
Ich kenne das eher als
1
UCB0CTL0=UCCKPH|UCMSB|UCMST|UCSYNC
Es kann natürlich in diesem Fall anders sein.
Wenn ja, bitte erklären. Ich lerne gerne neues dazu.
Was genau wird wiederholt?
Nur ein Zeichen oder die ganze Sequenz?
Ich würde mir auf jeden Fall hier
1
if(eeprom.bytecount>0)// More than one byte
2
{
3
eeprom.nextbyte+=1;
4
if(eeprom.nextbyte<eeprom.bytecount)
5
{
6
UCB0TXBUF=eeprom.byte[eeprom.nextbyte];
7
}
8
else
9
{
10
eeprom.nextbyte=0;
11
eeprom.bytecount=0;
12
EE1_WP;
13
EE1_DES;
14
}
den Bytecount auch noch auf 0 setzen (und auch auf größer 0 testen).
Denn genau das ist ja passiert: Es sind keine Daten mehr zu versenden.
So wie du das hast, darf die UART keine Zeichen für sich puffern. Sobald
die UART selbt noch ein Zeichen zwischenspeichert, geht dein Mechanismus
schief, weil du nach dem Erkennen des Endes (und nicht mehr Einstellen
eines Bytes) noch einen Interrupt kriegst.
Mit deinem Meschanismus, so wie er jetzt ist, hast du keine Möglichkeit
anhand der Variableninhalte festzustellen, ob du überhaupt noch etwas zu
versenden hast. nextbyte auf 0 zu setzen reicht nicht. Du kannst dann
die Fälle "Senden hat gerade erst begonnen" nicht vom Fall "Senden ist
beendet" unterscheiden.
...also jede Runde, wo die ISR aufgerufen wird, komme ich da an. Und da
ist jedesmal halt die Variable wieder auf 0. Die ersten zwei Bytes
werden gesendet, danach nurnoch das zweite immer wieder in Folge, weil
diese Variable immer wieder "0" ist.
Byte eins wird ja noch aus der main() gesendet, bzw. aus der
eeprom_write() und ab da wird das nächste Byte ja in jeder ISR
verschickt, sollte zumindest, beim zweiten klappt das ja auch noch, weil
da dann byte[1] verschickt wird, ab da dann halt immer byte[1]
Karl heinz Buchegger schrieb:> Sobald> die UART selbt noch ein Zeichen zwischenspeichert, geht dein Mechanismus> schief, weil du nach dem Erkennen des Endes (und nicht mehr Einstellen> eines Bytes) noch einen Interrupt kriegst.
Ich bekomme noch einen Interrupt, klar, aber der geht ja mit
1
if(eeprom.bytecount>1)
ins leere, weil ich den ja nach dem letzten Byte auf "0" gesetzt habe.
Der USART speichert ein Byte zwischen klar, aber er ruft die ISR ja auf,
wenn er bereit für ein neues Zeichen ist, das bekommt er dann, bzw. soll
es sich selber nehmen.
Der UART generiert ja immer ein Interrupt, wenn er seinen Puffer frei,
das vorige Byte jetzt versenden wird und für einen nahtlosen Datenstrom
schonmal das nächste im Puffer haben will.
> ...also jede Runde, wo die ISR aufgerufen wird, komme ich da an.
Ist dein Optimizer eingeschaltet?
Wenn ja, dann kannst du der Anzeige des Debuggers nicht unbedingt
trauen.
Hats du die Variante
1
struct// Struct contains information used for communication with EEPROM
2
{
3
volatileuint16_taddress;// Address to be read or written
4
volatileuint8_tbyte[8];// Byte 0 to 7 for complete page write
5
volatileuint8_tbytecount;// Number of bytes to be read or written
6
volatileuint8_tnextbyte;// Next byte to be transmitted
7
volatileuint8_teeprom_nr;// Selects between different EEPROMs
Ja, ich habe alles durch! Habe auch schon die Variable aus dem struct
genommen und sie einzeln deklariert - keine Änderung. Aber ich sehe es
auf dem Oszi ja auch, die beiden ersten Bytes gehen, danach nurnoch das
Zweite fortlaufend. Wenn er in den Reset gehen würde, dann müsste ja
erstmal wieder das Erste kommen.
Christian H. schrieb:> Das soll doch hoffentlich kein Zusammensetzen eines Steuerbytes sein.> Ich kenne das eher als UCB0CTL0 = UCCKPH | UCMSB | UCMST | UCSYNC
Doch genau das ist es und auch völlig OK.
Das wird in den Code-Examples auch so gemacht.
Sascha schrieb:> Christian H. schrieb:>> Das soll doch hoffentlich kein Zusammensetzen eines Steuerbytes sein.>> Ich kenne das eher als UCB0CTL0 = UCCKPH | UCMSB | UCMST | UCSYNC>> Doch genau das ist es und auch völlig OK.
UCCKPH und Konsorten sind offenbar irgendwelche Konstante, in denen die
richtigen Bits gesetzt sind. Solange es keine Bitüberschneidungen bei
einzelnen Konstanten gibt, ist das ok
0x01 + 0x02 -> 0x03
0x01 | 0x02 -> 0x03
Aber
0x01 | 0x03 -> 0x03
0x01 + 0x03 -> 0x04
> Das wird in den Code-Examples auch so gemacht.
Das ist kein guter Grund.
Aber das hab ich mich auch schon gefragt, jedoch ist es in jedem
Code-Example von TI so gehalten. Weiß nicht, ob es speziell im Header
des uCs definiert ist, oder im IAR.
Sascha schrieb:> Ich weiß schon, was du meinst,
Offenbar nicht.
Das das in den TI Beispielen auch so gemacht wird, ist kein guter Grund.
Ein guter Grund wäre, dass man in den Header Files die entsprechenden
#define rausgesucht hat und verifiziert hat, dass es zu keinen
Überschneidungen kommt.
Nur weil andere etwas so machen, ist das noch lange kein Grund es auch
so zu machen. Vor allen Dingen, wenn es bei
FLAG1 + FLAG2
eine Fehlermöglichkeit existiert, die bei
FLAG1 | FLAG2
nicht existiert.
Wenn beide Versionen im Nicht-Fehler Fall das gleiche Ergebnis liefern,
im Fehlerfall die eine aber immer noch ein richtiges Ergebnis liefert
und die andere nicht, dann nehm ich zumindest lieber die Version, die
auch dann noch funktioniert.
Sascha schrieb:> Ich weiß schon, was du meinst, aber ich kann auch:>> P1OUT &= ~(LED1 + LED2);
Und wenn du dich vertust und schreibst
1
P1OUT&=~(LED1+LED2+LED1);
dann liefert diese Version etwas nicht Beabsichtigtes, während
1
P1OUT&=~(LED1|LED2|LED1);
immer noch das Beabsichtigte macht. LED1 wird halt quasi '2 mal
abgeschaltet'. Macht aber nichts. Abgeschaltet ist abgeschaltet und mehr
als abgeschaltet kann die LED nicht sein.
Nennt sich 'defensives programmieren'. Man rechnet als Programmierer
damit, dass man selbst Fehler macht und gestaltet seinen Code so, dass
der Code einige der Programmierfehler von alleine abfangen kann und sie
sich nicht auswirken.
Aber das ist jetzt nicht unbedingt der springende Punkt.
Deine Interrupt Steuerung ist das Problem.
OK, sehe ich vollkommen ein, es funktioniert auch mit OR. Dann werde ich
das ab jetzt benutzen, Wir haben in der Fachhochschule das Thema
Mikrocontroller nur sehr kurz angeschnitten und mussten uns eigentlich
alles anhand der Examples von TI beibringen. Da hat sich das irgendwie
so festgesetzt.
Aber Recht hast du natürlich!
Trotzdem haben alles diese Einstellungen leider keinen Bezug auf die ISR
:) Der Hund liegt woanders begraben. Nur kann ich ihn nicht
ausbuddeln...
Karl heinz Buchegger schrieb:> ist dein kompletter Code?
Ja ist er. Mit dem IR-Handler für RXIFG ist vielleicht ein Punkt mit dem
du Recht haben könntest. Das werde ich mal ausprobieren. Leider erst
morgen, hab das nebenbei bei der Arbeit geschrieben (in der Pause
natürlich :))
Ich werde das Ergebnis berichten!
Danke schonmal!
Wenn soviele Leute den Code ankucken und keine Fehler finden, gibt es
noch die Möglichkeit eines Compiler-Fehlers, d.h. der Compiler generiert
falschen Code. Ist zwar sehr selten, kommt aber vor.
Wenn möglich schau dir mal in einem Listing den generierten
Assembler-Code an, ob der Sinn macht.
Ich kenne mich mit Deiner CPU nicht aus.
Aber wenn Du was mit nem Interrupt machst, dann solltest Du erst den
Interrupt sperren, die Struct mit gültigen Daten füllen und als letztes
den Interrupt wieder freigeben.
D.h. der Interupt darf nicht mit ner halb vollen Struct schon irgendnen
Mumpitz machen dürfen.
Wenn Du denkst, daß der Interrupt die Struct zerstört, dann gib mal die
komplette Struct vor und nach dem Interrupt aus:
- Interrupts global sperren
- warten bis Interruptflag gesetzt
- Struct ausgeben
- Interrupts global freigeben
- NOP (Interrupt ausführen)
- Interrupts global sperren
- Struct ausgeben
usw.
Peter
Guten morgen zusammen,
so, neues Spiel, neues Glück - ES LÄUFT!
Karl-Heinz hat den ehler gefunden. Es lag tatsächlich daran, dass mein
RXIFG freigeschlatet war und ich keinen Handler dafür definiert hatte.
Jetzt wird alles wie gwünscht hochgezählt.
Vielen Dank an alle!
Eine letzte Frage noch: Wie schon erwähnt, gibt der Compiler mir bei
einer kompletten volatile-Deklaration des structs eine Warnung mit
"undefined behaviour" aus - soweit ich das verstehe, liegt es daran,
dass er zwei volatile-Variablen miteinander vergleicht, und zwar in der
Zeile
1
if(eeprom.nextbyte<eeprom.bytecount)
Ist das schlimm, bzw. wie werde ich diese Warnung noch los?
Sascha schrieb:> Ist das schlimm, bzw. wie werde ich diese Warnung noch los?
Leg die beiden Werte vor dem Vergleich in eine lokale Variable.
Das ist sowieso anzuraten da der Compiler bei jedem Zugriff alles neu
aus derm Speicher holen muß.
DU könntest also erstmal eeprom.nextbyte und eeprom.bytecount am Anfang
lokal holen, und am ende in den Strukt zurückschreiben.