Forum: Mikrocontroller und Digitale Elektronik AVR32: Pointerübergabe überschreibt falsche Daten


von Matthias X. (current_user)


Lesenswert?

Hallo,
Ich bin jetzt schon seit einigen Stunden am verzweifeln. Ich habe mir 
eine Funktion geschrieben die einen externen ADC ausliest. Ich übergebe 
der Funktion die Adresse des Puffers:
1
      // Definition: unsigned short ext_ADC_val[8];
2
         read_adc_complete(&ext_ADC_val[0]);
Die Funktion besteht aus drei Teilen: Daten werden vom GPIO geholt und 
in lokale Variablen geladen. Inhalt der Variablen wird an die Adresse 
des Puffers geschrieben. Die lokale Variablen werden zum Debuggen 
ausgegeben.
Jetzt das Problem: Wenn ich den zweiten Teil, die Übergabe an den Puffer 
mithilfe von Pointern weglasse, dann funktioniert die Funktion. Wenn ich 
den mittleren Teil jedoch nicht auskommentiere, dann werden falsche 
Daten in den Puffer geschrieben und auch die Debugausgabe funktioniert 
nicht mehr. Das obere Byte ist dann immer FF aber das untere ist 
richtig. Das passiert sowohl in der Debug, als auch in der Release 
Einstellung.
µC: AVR32, Software: Atmel Studio 6
1
void read_adc_complete(unsigned short *adresse )
2
{
3
  unsigned short adc0,adc1,adc2,adc3,adc4,adc5,adc6,adc7;
4
  ADC_EXTERN_START_LOW; //Ab jetzt wird gesampelt
5
  ADC_EXTERN_START_HIGH; //Ab jetzt wird konvertiert
6
  ADC_EXTERN_CS_LOW;
7
  ADC_EXTERN_RD_LOW; // CH0 
8
  adc0=ADC_EXTERN_GET_PORT;
9
  ADC_EXTERN_RD_HIGH; //
10
  ADC_EXTERN_RD_LOW; // CH1     
11
  adc1=ADC_EXTERN_GET_PORT;
12
  ADC_EXTERN_RD_HIGH; //
13
  ADC_EXTERN_RD_LOW; // CH2     
14
  adc2=ADC_EXTERN_GET_PORT;
15
  ADC_EXTERN_RD_HIGH; //
16
  ADC_EXTERN_RD_LOW; // CH3     
17
  adc3=ADC_EXTERN_GET_PORT;
18
  ADC_EXTERN_RD_HIGH; //
19
  ADC_EXTERN_RD_LOW; //CH4  
20
  adc4=ADC_EXTERN_GET_PORT;
21
  ADC_EXTERN_RD_HIGH; //
22
  ADC_EXTERN_RD_LOW; //CH5
23
  adc5=ADC_EXTERN_GET_PORT;
24
  ADC_EXTERN_RD_HIGH; //
25
  ADC_EXTERN_RD_LOW; //CH6     
26
  adc6=ADC_EXTERN_GET_PORT;
27
  ADC_EXTERN_RD_HIGH; //
28
  ADC_EXTERN_RD_LOW; //CH7    
29
  adc7=ADC_EXTERN_GET_PORT;
30
  ADC_EXTERN_RD_HIGH; //
31
  ADC_EXTERN_CS_HIGH; //ADC abwählen
32
//Übergabe der Variableninhalten an die Adresse des Puffers
33
    *adresse = adc0;   adresse++;
34
    *adresse = adc2;   adresse++;
35
    *adresse = adc4;   adresse++;
36
    *adresse = adc6;   adresse++;
37
    *adresse = adc1;   adresse++;
38
    *adresse = adc3;   adresse++;
39
    *adresse = adc5;   adresse++;
40
    *adresse = adc7;
41
//Debug Ausgabe
42
  usart_debug_write_16bitInt(adc0);
43
  usart_debug_write_16bitInt(adc1);
44
  usart_debug_write_16bitInt(adc2);
45
  usart_debug_write_16bitInt(adc3);
46
  usart_debug_write_16bitInt(adc4);
47
  usart_debug_write_16bitInt(adc5);
48
  usart_debug_write_16bitInt(adc6);
49
  usart_debug_write_16bitInt(adc7);
50
}

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Zeig alles.
An dem geposteten ist soweit erstmal nichts falsch. Dein Problem liegt 
wo anders.

von Matthias X. (current_user)


Lesenswert?

Vielen Dank. Welchen Teil brauchst du?
Hier ist mal die Portauslesefunktion. (Als Inline) Der ADC hängt an den 
Ports 0..7 und 11..18. (Danke Atmel für die Anordnung der Ports am 
Gehäuse!)
1
inline unsigned short adcExternGetPort ()
2
{
3
  int tmp = AVR32_GPIO.port[ADC_EXTERN_PORT].pvr;
4
  int tmph = (0xFF00 & (tmp>>(3)));
5
  int tmpl = (0xFF & (tmp>>0));
6
  return (tmph | tmpl);
7
}

von Karl H. (kbuchegg)


Lesenswert?

Matthias xxx schrieb:
> Vielen Dank. Welchen Teil brauchst du?

Alles was relevant ist.

Idealfall: ein in sich komplettes Minimalprogramm, welches den 
beobachteten Effekt zeigt.

> Hier ist mal die Portauslesefunktion.

Die dürfte ziemlich sicher nicht zum Problem beitragen. Denn die liefert 
ja ihre Werte korrekt.

Minimalprogramm, welches ein main zeigt, in dem
UART initialisierst wird
ADC initialisiert wird
in der Hauptschleife der Aufruf in deine ADC Funktion statt findet
Ausgabefunktion auf die UART


Wenn du extra ein Programm dafür zurecht machen musst, dann klär vorher 
ab, ob du in diesem Minimalprogramm den beschriebenen Effekt noch siehst 
oder nicht.

von Matthias X. (current_user)


Lesenswert?

Ich glaube ich nähere mich dem Fehler:

Ich hab jetzt mal die Variablen adc0..adc7 weggelassen und schreib die 
Daten direkt in den Puffer:
1
inline unsigned short adcExternGetPort ()
2
{
3
  int tmp = AVR32_GPIO.port[ADC_EXTERN_PORT].pvr;
4
  int tmph = (0xFF00 & (tmp>>(ADC_EXTERN_DATA_HIGH-8))); // >> 11-8
5
  int tmpl = (0xFF & (tmp>>ADC_EXTERN_DATA_LOW)); // >> 0
6
  return (tmph | tmpl);
7
}
1
...       
2
        ADC_EXTERN_CS_LOW;
3
     ADC_EXTERN_RD_LOW; //CH0
4
        asm volatile ("nop");
5
 //  adc0=ADC_EXTERN_GET_PORT;
6
     *adresse=adcExternGetPort();
7
  adresse++;
8
  ADC_EXTERN_RD_HIGH; 
9
...

daraus macht der compiler:
1
asm volatile ("nop");
2
800007FC  nop      
3
  int tmp = AVR32_GPIO.port[ADC_EXTERN_PORT].pvr;
4
800007FE  ld.w R11, R7[1120]     //liest das Register ein
5
  return (tmph | tmpl);
6
80000802  asr R12, R11, 3     //das High byte um 3 nach rechts
7
80000806  andl R12, 0xff00, COH     // & 0xFF00 
8
8000080A  or R11, R12, R11 << 0     // Oderverknüpfung High und Low
9
  *adresse=adcExternGetPort();
10
8000080E  st.h R9[0], R11     //Speichern an die Adresse im Puffer
11
  ADC_EXTERN_RD_HIGH; //
12
80000810  st.w R7[1108], R8

Wo ist da die die implementierung für
    int tmpl = (0xFF & (tmp>>ADC_EXTERN_DATA_LOW)); // >> 0
?????
Ok das um 0 nach rechts schieben kann sich der compiler sparen, aber 
nicht die 0xFF Verknüpfung??


Wenn ich ohne Pointer arbeite und die den Inhalt der Variable nicht in 
den Puffer schreibe, dann macht der Compiler:
1
usart_debug_write_16bitInt((adc4));
2
80000848  lddsp R12, SP[0xc]  //Portinhalt wurde vorher in den Stack geschrieben   
3
8000084A  lsr R12, 3     //um 3 nach rechts
4
8000084C  andl R12, 0xff00, COH     // & 0xFF00
5
80000850  castu.b R3     //  & 0xFF
6
80000852  or R12, R3     //High und Low zusammenbringen
7
80000854  castu.h R12     
8
8000085A  mcall 0x800008c0  //Aufruf UART senden

Warum lässt der Compiler das "castu.b" oben weg?

von Matthias X. (current_user)


Lesenswert?

Letzter Versuch, dann geh ich schreiend nach Hause:

Beim Auslesen des ADCs speichere ich die Portbelegung jetzt direkt als 
unsigned int:
adc0 = AVR32_GPIO.port[ADC_EXTERN_PORT].pvr;
Das Einlesen funktioniert auch. Der Compiler liest die 8 Kanäle in 
jeweils ein Register.

Nachdem alles ausgelesen wurde mache ich die Operationen:
Pins 11..18 sollen der Highteil meines 16bit ADC Wert sein
Pins 0..7 sollen der Lowteil meines 16bit ADC Wert sein

das realisiere ich mit:
1
*adresse=(unsigned short) ((0xFF00 & (adc0>>3)) | (0xFF & adc0));
2
adresse++;
3
*adresse=(unsigned short) ((0xFF00 & (adc1>>3)) | (0xFF & adc1));
4
adresse++;
5
*adresse=(unsigned short) ((0xFF00 & (adc2>>3)) | (0xFF & adc2));
6
adresse++;
7
*adresse=(unsigned short) ((0xFF00 & (adc3>>3)) | (0xFF & adc3));
8
adresse++;
9
*adresse=(unsigned short) ((0xFF00 & (adc4>>3)) | (0xFF & adc4));
10
adresse++;
11
*adresse=(unsigned short) ((0xFF00 & (adc5>>3)) | (0xFF & adc5));
12
adresse++;
13
*adresse=(unsigned short) ((0xFF00 & (adc6>>3)) | (0xFF & adc6));
14
adresse++;
15
*adresse=(unsigned short) ((0xFF00 & (adc7>>3)) | (0xFF & adc7));

daraus macht der Compiler:
1
  *adresse=(unsigned short) ((0xFF00 & (adc0>>3)) | (0xFF & adc0));
2
800007AA  lsr R8, R3, 3     
3
800007AE  andl R8, 0xff00, COH     
4
800007B2  or R3, R8, R3 << 0     
5
800007B6  mov R8, R5     
6
800007B8  st.h R8++, R3     
7
  *adresse=(unsigned short) ((0xFF00 & (adc1>>3)) | (0xFF & adc1));
8
800007BA  lsr R5, R4, 3     
9
800007BE  mov R7, R5     
10
800007C0  andl R7, 0xff00, COH     
11
800007C4  mov R5, R4     
12
800007C6  or R4, R7, R5 << 0     
13
800007CA  casts.h R4     
14
800007CC  st.h R8++, R4     
15
  *adresse=(unsigned short) ((0xFF00 & (adc2>>3)) | (0xFF & adc2));
16
800007CE  lsr R3, LR, 3     
17
800007D2  mov R7, R3     
18
800007D4  andl R7, 0xff00, COH     
19
800007D8  mov R5, R7     
20
800007DA  or LR, R7, LR << 0     
21
800007DE  st.h R8++, LR     
22
  *adresse=(unsigned short) ((0xFF00 & (adc3>>3)) | (0xFF & adc3));
23
800007E0  lsr LR, R6, 3     
24
800007E4  andl LR, 0xff00, COH     
25
800007E8  or R6, LR, R6 << 0     
26
800007EC  casts.h R6     
27
800007EE  st.h R8++, R6

Ich verstehe das absolut nicht. Da fehlt doch die 0xFF Verknüpfung!

von Matthias X. (current_user)


Lesenswert?

Konnte mich doch nicht von dem Problem lösen;)

ich habe folgendes geändert:
1
(0xFF00 & (data>>3)) | (0xff & data)

ergibt im ASM:
1
lsr R8, R12, 3     
2
andl R8, 0xff00, COH     
3
or R12, R8, R12 << 0

geändert in:
1
(0xFF00 & (data>>3)) + (0xff & data)
1
lsr R8, R12, 3     
2
andl R8, 0xff00     
3
castu.b R12     
4
add R12, R8

Mathematisch gesehen macht hier die Addition das gleiche wie die 
Oderverknüfung. Aber nur wenn ich addiere, dann castet der Compiler auch 
mein Low-byte richtig. Ist das ein Bug?

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.