Schwer einschätzbarer Fehler(Interrupts?)

Gast #3398044
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
}
Moderator Persönliche Seite #3398148
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.
Gast #3398340
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
Gast #3398987
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.
#3399001
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.

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