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 | }
|
Zeig alles.
An dem geposteten ist soweit erstmal nichts falsch. Dein Problem liegt
wo anders.
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 | }
|
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.
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?
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!
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.
|