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


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Matthias X. (current_user)


Bewertung
0 lesenswert
nicht 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:
      // Definition: unsigned short ext_ADC_val[8];
         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
void read_adc_complete(unsigned short *adresse )
{
  unsigned short adc0,adc1,adc2,adc3,adc4,adc5,adc6,adc7;
  ADC_EXTERN_START_LOW; //Ab jetzt wird gesampelt
  ADC_EXTERN_START_HIGH; //Ab jetzt wird konvertiert
  ADC_EXTERN_CS_LOW;
  ADC_EXTERN_RD_LOW; // CH0 
  adc0=ADC_EXTERN_GET_PORT;
  ADC_EXTERN_RD_HIGH; //
  ADC_EXTERN_RD_LOW; // CH1     
  adc1=ADC_EXTERN_GET_PORT;
  ADC_EXTERN_RD_HIGH; //
  ADC_EXTERN_RD_LOW; // CH2     
  adc2=ADC_EXTERN_GET_PORT;
  ADC_EXTERN_RD_HIGH; //
  ADC_EXTERN_RD_LOW; // CH3     
  adc3=ADC_EXTERN_GET_PORT;
  ADC_EXTERN_RD_HIGH; //
  ADC_EXTERN_RD_LOW; //CH4  
  adc4=ADC_EXTERN_GET_PORT;
  ADC_EXTERN_RD_HIGH; //
  ADC_EXTERN_RD_LOW; //CH5
  adc5=ADC_EXTERN_GET_PORT;
  ADC_EXTERN_RD_HIGH; //
  ADC_EXTERN_RD_LOW; //CH6     
  adc6=ADC_EXTERN_GET_PORT;
  ADC_EXTERN_RD_HIGH; //
  ADC_EXTERN_RD_LOW; //CH7    
  adc7=ADC_EXTERN_GET_PORT;
  ADC_EXTERN_RD_HIGH; //
  ADC_EXTERN_CS_HIGH; //ADC abwählen
//Übergabe der Variableninhalten an die Adresse des Puffers
    *adresse = adc0;   adresse++;
    *adresse = adc2;   adresse++;
    *adresse = adc4;   adresse++;
    *adresse = adc6;   adresse++;
    *adresse = adc1;   adresse++;
    *adresse = adc3;   adresse++;
    *adresse = adc5;   adresse++;
    *adresse = adc7;
//Debug Ausgabe
  usart_debug_write_16bitInt(adc0);
  usart_debug_write_16bitInt(adc1);
  usart_debug_write_16bitInt(adc2);
  usart_debug_write_16bitInt(adc3);
  usart_debug_write_16bitInt(adc4);
  usart_debug_write_16bitInt(adc5);
  usart_debug_write_16bitInt(adc6);
  usart_debug_write_16bitInt(adc7);
}

: Bearbeitet durch Moderator
von Karl H. (kbuchegg) (Moderator)


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

von Matthias X. (current_user)


Bewertung
0 lesenswert
nicht 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!)
inline unsigned short adcExternGetPort ()
{
  int tmp = AVR32_GPIO.port[ADC_EXTERN_PORT].pvr;
  int tmph = (0xFF00 & (tmp>>(3)));
  int tmpl = (0xFF & (tmp>>0));
  return (tmph | tmpl);
}

von Karl H. (kbuchegg) (Moderator)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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:

inline unsigned short adcExternGetPort ()
{
  int tmp = AVR32_GPIO.port[ADC_EXTERN_PORT].pvr;
  int tmph = (0xFF00 & (tmp>>(ADC_EXTERN_DATA_HIGH-8))); // >> 11-8
  int tmpl = (0xFF & (tmp>>ADC_EXTERN_DATA_LOW)); // >> 0
  return (tmph | tmpl);
}
...       
        ADC_EXTERN_CS_LOW;
     ADC_EXTERN_RD_LOW; //CH0
        asm volatile ("nop");
 //  adc0=ADC_EXTERN_GET_PORT;
     *adresse=adcExternGetPort();
  adresse++;
  ADC_EXTERN_RD_HIGH; 
...

daraus macht der compiler:
asm volatile ("nop");
800007FC  nop      
  int tmp = AVR32_GPIO.port[ADC_EXTERN_PORT].pvr;
800007FE  ld.w R11, R7[1120]     //liest das Register ein
  return (tmph | tmpl);
80000802  asr R12, R11, 3     //das High byte um 3 nach rechts
80000806  andl R12, 0xff00, COH     // & 0xFF00 
8000080A  or R11, R12, R11 << 0     // Oderverknüpfung High und Low
  *adresse=adcExternGetPort();
8000080E  st.h R9[0], R11     //Speichern an die Adresse im Puffer
  ADC_EXTERN_RD_HIGH; //
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:
usart_debug_write_16bitInt((adc4));
80000848  lddsp R12, SP[0xc]  //Portinhalt wurde vorher in den Stack geschrieben   
8000084A  lsr R12, 3     //um 3 nach rechts
8000084C  andl R12, 0xff00, COH     // & 0xFF00
80000850  castu.b R3     //  & 0xFF
80000852  or R12, R3     //High und Low zusammenbringen
80000854  castu.h R12     
8000085A  mcall 0x800008c0  //Aufruf UART senden

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

von Matthias X. (current_user)


Bewertung
0 lesenswert
nicht 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:
*adresse=(unsigned short) ((0xFF00 & (adc0>>3)) | (0xFF & adc0));
adresse++;
*adresse=(unsigned short) ((0xFF00 & (adc1>>3)) | (0xFF & adc1));
adresse++;
*adresse=(unsigned short) ((0xFF00 & (adc2>>3)) | (0xFF & adc2));
adresse++;
*adresse=(unsigned short) ((0xFF00 & (adc3>>3)) | (0xFF & adc3));
adresse++;
*adresse=(unsigned short) ((0xFF00 & (adc4>>3)) | (0xFF & adc4));
adresse++;
*adresse=(unsigned short) ((0xFF00 & (adc5>>3)) | (0xFF & adc5));
adresse++;
*adresse=(unsigned short) ((0xFF00 & (adc6>>3)) | (0xFF & adc6));
adresse++;
*adresse=(unsigned short) ((0xFF00 & (adc7>>3)) | (0xFF & adc7));

daraus macht der Compiler:
  *adresse=(unsigned short) ((0xFF00 & (adc0>>3)) | (0xFF & adc0));
800007AA  lsr R8, R3, 3     
800007AE  andl R8, 0xff00, COH     
800007B2  or R3, R8, R3 << 0     
800007B6  mov R8, R5     
800007B8  st.h R8++, R3     
  *adresse=(unsigned short) ((0xFF00 & (adc1>>3)) | (0xFF & adc1));
800007BA  lsr R5, R4, 3     
800007BE  mov R7, R5     
800007C0  andl R7, 0xff00, COH     
800007C4  mov R5, R4     
800007C6  or R4, R7, R5 << 0     
800007CA  casts.h R4     
800007CC  st.h R8++, R4     
  *adresse=(unsigned short) ((0xFF00 & (adc2>>3)) | (0xFF & adc2));
800007CE  lsr R3, LR, 3     
800007D2  mov R7, R3     
800007D4  andl R7, 0xff00, COH     
800007D8  mov R5, R7     
800007DA  or LR, R7, LR << 0     
800007DE  st.h R8++, LR     
  *adresse=(unsigned short) ((0xFF00 & (adc3>>3)) | (0xFF & adc3));
800007E0  lsr LR, R6, 3     
800007E4  andl LR, 0xff00, COH     
800007E8  or R6, LR, R6 << 0     
800007EC  casts.h R6     
800007EE  st.h R8++, R6     

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

von Matthias X. (current_user)


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

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

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

geändert in:
(0xFF00 & (data>>3)) + (0xff & data)
lsr R8, R12, 3     
andl R8, 0xff00     
castu.b R12     
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?

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.