Forum: Compiler & IDEs Schwer einschätzbarer Fehler(Interrupts?)


von Mirkolski (Gast)


Lesenswert?

Hallo zusammen,

ich sitze schon seit Stunden an folgendem Code:
1
int istTemp = 113;//convert2degree(adc_get(6));
2
3
uart_putc(STX);
4
uart_putc('c');
5
uart_puts(itoa(istTemp, NULL, 10));
6
uart_putc('t');
7
uart_puts(itoa((UART_SEND_RATE * counter)/100, NULL, 10));
8
uart_putc(ETX);
9
10
sreg_local = SREG;
11
cli();
12
N3310_ClearLcd();
13
N3310_goto(0, 0); N3310_PutStr(PSTR("Temp1"));
14
N3310_goto(42, 0); N3310_PutInt(adc_get(6));
15
//N3310_goto(42, 12); N3310_PutInt(istTemp);
16
SREG = sreg_local;

N3310 ist ein LCD Display. Der Code Ausschnitt wird alle 250ms 
durchgeführt.
Auf dem Display erscheint der Text nicht sauber. Wenn ich die vorletzte 
Zeile auskommentier, dann erscheint der Text auf dem LCD für 9sekunden 
sauber und danach nicht mehr. Wenn ich cli() und sei() weg lasse erhalte 
ich keinen Unterschied. nur wenn ich kein Zeichen über den UART sende 
läuft der Code ohne Probleme. Die Uart Ausgabe läuft über einen 
Interrupt. Für mich ist diese Phänomen absolut unverständlich. Ich hoffe 
jemand von euch kann mir das erklären. Die Interrupt Routine sieht so 
aus:
1
ISR (UART0_TRANSMIT_INTERRUPT)
2
/*************************************************************************
3
Function: UART Data Register Empty interrupt
4
Purpose:  called when the UART is ready to transmit the next byte
5
**************************************************************************/
6
{
7
    unsigned char tmptail;
8
9
    
10
    if ( UART_TxHead != UART_TxTail) {
11
        // calculate and store new buffer index
12
        tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK;
13
        UART_TxTail = tmptail;
14
        // get one byte from buffer and write it to UART
15
        UART0_DATA = UART_TxBuf[tmptail];  // start transmission
16
    }else{
17
        // tx buffer empty, disable UDRE interrupt
18
        UART0_CONTROL &= ~_BV(UART0_UDRIE);
19
    }
20
}

von Oliver S. (oliverso)


Lesenswert?

Na ja, wenn das der ganze Code ist, wirst du da noch länger dran sitzen. 
Wenn nicht, zeig den Rest. Glaskugeln sind aus.

Ganz prinzipiell ist C-Code, der am sreg rumfummelt, immer suspekt.

Oliver

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Mirkolski schrieb:

> uart_puts(itoa(istTemp, NULL, 10));

Lies nochmals aufmerksam die Doku zu itoa!

Du mußt genügend Platz für das Ergebnis der Umwandlung zur Verfügung 
stellen.  NULL tut dies keinesfalls, die schreibst irgendwo in der SFR- 
oder GPR-Bereich.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Oliver S. schrieb:
> Ganz prinzipiell ist C-Code, der am sreg rumfummelt, immer suspekt.

Er rettet und restauriert das SREG ja nur.

Sowas kann seine Berechtigung haben (wenn Code sowohl aus einem
Interrupt- als auch regulären Kontext gerufen wird), aber in 99 % der
Fälle weiß man eigentlich vorher, ob man aus einem Interruptkontext
gerufen wird oder nicht, und kann dann hart cli()/sei() rufen.

von Oliver (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> in 99 % der Fälle

ist das vor allem ein Zeichen dafür, daß der Code unverstanden aus 
irgendwelchen veralteten oder fragwürdigen Quellen übernommen wurde.

Das muß jetzt hier nicht der Fall sein, aus dem gezeigten Codeschnipsel 
lässt sich ja nichts erkennen.

> Mirkolski schrieb:
>> uart_puts(itoa(istTemp, NULL, 10));

Kommt drauf an, wie NULL definiert ist ;)
Wenn NULL aber tatsächlich 0 ist, schreibt er in die Register ab R0. Das 
hat schon was ;)

Oliver

von Mirkolski (Gast)


Lesenswert?

Die uart_putc Methode sieht so aus:
1
/*************************************************************************
2
Function: uart_putc()
3
Purpose:  write byte to ringbuffer for transmitting via UART
4
Input:    byte to be transmitted
5
Returns:  none          
6
**************************************************************************/
7
void uart_putc(unsigned char data)
8
{
9
    unsigned char tmphead;
10
11
    
12
    tmphead  = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;
13
    
14
    while ( tmphead == UART_TxTail ){
15
        ;/* wait for free space in buffer */
16
    }
17
    
18
    UART_TxBuf[tmphead] = data;
19
    UART_TxHead = tmphead;
20
21
    /* enable UDRE interrupt */
22
    UART0_CONTROL    |= _BV(UART0_UDRIE);
23
24
}/* uart_putc */

könnte es sein, das diese Schleife
1
while ( tmphead == UART_TxTail ){
2
        ;/* wait for free space in buffer */
3
}
ununterbrochen ausgeführt wird wenn die Interrupts ausgeschaltet werden, 
denn der Buffer wird ja nur in der Interrupt Methode geleert?
Aber eigentlich ist das bei mir nicht der Fall, denn die Zeichen auf dem 
Display werden plötzlich falsch dargestellt. Das Display kommuniziert 
über SPI, aber ohne Interrupts. Das ganze ist mir sehr schleierhaft.

von Karl H. (kbuchegg)


Lesenswert?

Mirkolski schrieb:

> Könnte es sein ...
> denn der Buffer wird ja nur in der Interrupt Methode geleert?

Nein.
Welchen Teil von:
1
   itoa(istTemp, NULL, 10))
"du kannst hier keinen NULL Pointer nehmen"
verstehst du nicht.

Du bügelst hier über die Register drüber. Ab diesem Zeitpunkt werden 
keine Wetten mehr angenommen, was danach alles im Detail passiert bzw. 
nicht mehr funktioniert.

itoa braucht eine Speicherfläche, in der es die Textrepräsentierung 
aufbaut. Es ist DEIN Job, einen entsprechenden Speicher dafür bereit zu 
stellen.

PS: Das heißt nicht, dass es nicht noch mglw. weitere Probleme gibt. 
Aber das ist mit Sicherheit dein erstes Problem. Und wenn ich hinzufügen 
darf, ist es ein Hinweis darauf, dass in deinem C-Verständnis sich eine 
ganz große Lücke auftut. Konkret: wie funktioniert Speicherverwaltung im 
allgmeinenen bzw. Stringverarbeitung im besonderen.

: Bearbeitet durch User
von Mirkolski (Gast)


Lesenswert?

Manchmal ist das Ziel so nah und der Weg dort hin... auch ;)
Vielen Dank

von Mark B. (markbrandis)


Lesenswert?

Harter Zugriff auf den NULL pointer... sieht man auch nicht alle Tage 
;-)

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.