Forum: Compiler & IDEs AtMega1284P: 0x12 + 0x01 = 0x03 (WTF?)


von Tobias S. (Firma: none) (tobimc) Benutzerseite


Lesenswert?

Hi,

ich habe ein ziemlich komisches Problem....
Ich versuche gerade, eine ADC-ISR zu programmieren, die 2 ADC-Kanäle des 
AVRs im Wechsel ausliest.
Zunächst zu den Rahmenbedingungen:

Hardware: AtMega1284P @ 20MHz bei 3,3V (clean) auf eigener Platine
IDE/Toolchain: Atmel Studio 6 mit integrierter Toolchain
Gedebuggt habe ich mit meinem Dragon.

Hier mal mein Code:
1
#define F_CPU 20000000
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <util/delay.h>
6
7
#include <stdlib.h>
8
9
10
11
#define LED_SET         PORTB |= (1<<1);
12
#define LED_CLR         PORTB &= ~(1<<1);
13
#define LED_TOG         PORTB ^= (1<<1);
14
15
16
volatile uint32_t sumA = 0;
17
volatile uint32_t sumB = 0;
18
volatile uint16_t count = 0, maxcount = 0;
19
volatile uint32_t count2 = 0, countA = 0, countB = 0, countC = 0;
20
21
uint8_t uartstate = 0;
22
23
24
uint8_t init_uart(uint16_t ubrr){  //UART initialisieren
25
26
  UBRR0L = (uint8_t) (ubrr & 0xFF);   //Baudrate
27
  UBRR0H = (uint8_t) ((ubrr & 0xF00) >> 8); 
28
  UCSR0B |= ((1<<TXEN0) | (1<<RXEN0));   //Tx- und RxEnable
29
  UCSR0C |= ((1<<UPM00) | (3<<UCSZ00));   //Parity, STOP usw...
30
31
  uartstate = 1;     //Statusvariable: UART offen (!= 0).
32
33
  return 0; 
34
}
35
36
uint8_t uart_puts(const char *string){  //Sendet einen String
37
  uint8_t currentchar = 0;
38
39
  if(uartstate != 0){    //UART-Status.
40
    while((uint8_t)string[currentchar] != 0){  
41
      while(!(UCSR0A & (1<<UDRE0)));  //Überprüfen ob der UART was hat, gegebenenfalls warten
42
      UDR0 = (uint8_t) string[currentchar];  //Senden, zur sicherheit noch in BYTE umwandeln.
43
44
      currentchar++;
45
    } 
46
  }else{      //UART nicht initialisiert?
47
    return 1;  //ERROR!!
48
  } 
49
50
  return 0; 
51
}
52
53
uint8_t startAQ(uint8_t samplesCH){
54
55
    if(count != 0){
56
        sumA = 0;
57
        sumB = 0;
58
        count = 0;
59
        maxcount = samplesCH * 2;
60
    
61
  ADMUX = ((3<<REFS0) | 0); 
62
        ADCSRA = ((1<<ADIE) | (1<<ADSC) | (1<<ADEN) |  (7<<ADPS0));
63
    
64
        return 1;
65
    }else{
66
        return 0;
67
    }
68
69
    return 0;
70
}
71
72
73
int main(void){
74
    uint16_t foo = 0;
75
    char txt[20];
76
77
    init_uart(10);
78
79
    DDRB = (1<<1);
80
81
    ADCSRB = 0;
82
    ADMUX = ((3<<REFS0) | (0x1E<<0));
83
    ADCSRA = ((1<<ADEN) | (1<<ADSC) |  (7<<ADPS0));
84
85
    while(ADCSRA & (1<<ADSC));
86
    foo = ADC;
87
    foo++;
88
89
    count = 100;
90
91
    sei();
92
93
    while(1){
94
95
96
        //DEBUG-OUTPUT (prae-Dragon)
97
        uart_puts("count2 ");
98
        utoa(count2, txt, 10);
99
        uart_puts(txt);
100
        uart_puts("\t");
101
102
        uart_puts("countA ");
103
        utoa(countA, txt, 10);
104
        uart_puts(txt);
105
        uart_puts("\t");
106
107
        uart_puts("countB ");
108
        utoa(countB, txt, 10);
109
        uart_puts(txt);
110
        uart_puts("\t");
111
112
        uart_puts("countC ");
113
        utoa(countC, txt, 10);
114
        uart_puts(txt);
115
        uart_puts("\t");
116
117
        uart_puts("sumA ");
118
        utoa((uint32_t)sumA, txt, 10);
119
        uart_puts(txt);
120
        uart_puts("\t");
121
122
        uart_puts("sumB ");
123
        utoa((uint32_t)sumB, txt, 10);
124
        uart_puts(txt);
125
        uart_puts("\n");
126
127
        while(PIND & (1<<3)); //warten bis knopf gedrückt...
128
        while(!(PIND & (1<<3))); //...und wieder losgelassen
129
130
        count2 = 0; //reset
131
        countA = 0;
132
        countB = 0;
133
        countC = 0;
134
//Hier wirds interessant:
135
        startAQ(10);  //Start der Aquise, s.o.
136
137
        while(count < maxcount); //abwarten bis alle Messwerte gesammelt wurden.
138
139
    }
140
141
    while(1);
142
143
    return 0;
144
}
145
146
ISR(ADC_vect){
147
    char txt[20];
148
149
count2 = count2 + 1; //count2++; //auch ohne erfolg
150
151
  count = countA + countB;
152
153
    if(count < maxcount){
154
155
        if(ADMUX & 1){
156
            sumA += ADC;
157
            countA++;
158
            ADMUX = ((3<<REFS0) | 0);
159
        }else{
160
            sumB += ADC;
161
            countB++;
162
            ADMUX = ((3<<REFS0) | 1);
163
        }
164
165
        ADCSRA |= (1<<ADSC);
166
167
    }else{
168
        countC++;
169
        ADCSRA &= ~((1<<ADIE) | (1<<ADSC));
170
    }
171
172
}

Im Debugger läuft der Code ohne Weiteres, bis auf ein mal die Variable 
count2 (a.k.a. R24, s.u.) z.B. von 0x12 auf 0x03 springt. Der Fehler 
scheint irgendwie zur Laufzeit zu passierten, denn es scheint nicht vom 
Wert von count2 abhängig, auch wenn der Fehler nie bei Werten unterhalb 
0x10 passiert (vllt. wichtig?).

Das disassembly von count2 = count2 + 1; sieht folgendermaßen aus:
1
count2 = count2 + 1;
2
000001B7  LDS R24,0x013D    Load direct from data space 
3
000001B9  LDS R25,0x013E    Load direct from data space 
4
000001BB  LDS R26,0x013F    Load direct from data space 
5
000001BD  LDS R27,0x0140    Load direct from data space 
6
7
000001BF  ADIW R24,0x01    Add immediate to word 
8
000001C0  ADC R26,R1    Add with carry 
9
000001C1  ADC R27,R1    Add with carry 
10
11
000001C2  STS 0x013D,R24    Store direct to data space 
12
000001C4  STS 0x013E,R25    Store direct to data space 
13
000001C6  STS 0x013F,R26    Store direct to data space 
14
000001C8  STS 0x0140,R27    Store direct to data space

Der Fehler passiert bei ADIW R24,0x01. R24 wurde davor aus dem RAM mit 
(z.B.) 0x12 geladen, und wenn ADIW R24,0x01 ausgeführt wird steht da in 
R24 z.B. statt 0x13 0x03.
Es hat fast den Anschein, als wäre das obere Nibble auf dem Weg von der 
ALU zurück abanden gekommen...

Ich bin jetzt ehrlichgesagt ratlos.
Habt ihr ne Idee? (Auch wie man der ganzen Sache noch näher auf den Zahn 
fühlen könnte...? -> ich dachte zuerst an einen unerlaubten RAM-Zugriff, 
aber das konnte ich durch einen Data-Breakpoint ausschließen...)

Danke euch,
Tobi

von holger (Gast)


Lesenswert?

>Es hat fast den Anschein, als wäre das obere Nibble auf dem Weg von der
>ALU zurück abanden gekommen...

Ja, so ist es. Auf Variablen die grösser 8Bit sind und die
in einem Interrupt verändert werden sollte man beim AVR
ausserhalb eines Interrupts nur mit Interruptsperre zugreifen.

Beispiel:

cli();
count2 = 0; //reset
sei();

von chris (Gast)


Lesenswert?

Tobias Schlegel schrieb:
> AtMega1284P @ 20MHz bei 3,3V

damit bewegst du dich übrigens bereits außerhalb der Spezifikation des 
Prozessors.
Dein Problem muss zwar nicht unbedingt daran liegen, aber Fehlfunktionen 
durch die zu niedrige Versorgungsspannung sind trotzdem nicht 
auszuschließen.

 Speed Grades
– 0 - 4 MHz @ 1.8 - 5.5V
– 0 - 10 MHz @ 2.7 - 5.5V
– 0 - 20 MHz @ 4.5 - 5.5V


lg
Chris

von Tobias S. (Firma: none) (tobimc) Benutzerseite


Lesenswert?

Hi,

holger schrieb:
> Auf Variablen die grösser 8Bit sind und die
> in einem Interrupt verändert werden sollte man beim AVR
> ausserhalb eines Interrupts nur mit Interruptsperre zugreifen.
Zugegeben, ist nicht gerade guter Stil, generell eine ISR ohne 
Interruptsperre zu implementieren, allerdings ist es geplant die ADC-ISR 
als 'NOBLOCK' laufen zu lassen, da der AVR in dem eigentlichen Programm 
noch 2 Phasenanschnittstreiber mit 100Hz bedienen soll, also noch andere 
wichtige Dinge zu tun hat...
Der Debugger hat auch keinen Hinweis darauf geliefert, dass die ISR 
durch einen anderen Interrupt unterbrochen wurde. Ausserdem passiert das 
Malheur während 1 einzigen Instruktion.

chris schrieb:
> damit bewegst du dich übrigens bereits außerhalb der Spezifikation des
> Prozessors.
Whoops, da hast du recht!

chris schrieb:
> Dein Problem muss zwar nicht unbedingt daran liegen, aber Fehlfunktionen
> durch die zu niedrige Versorgungsspannung sind trotzdem nicht
> auszuschließen.
Yep, ich werde das trotzdem gleich morgen mal mit 5V Versorgungsspannung 
gegenchecken. Wäre ja schon doof wenns daran liegen würde...

Dann bräuchte ich zwar nen Pegelwandler fürs TFT ... naja.
Einen Tod muss man sterben...

Danke, ich werde das mal testen...
Tobi

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.