PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] XMega ADC arbeitet nicht korrekt



Kampi
30.09.2012, 14:00
Hallo Forum,

ich programmiere gerade etwas an einem XMega rum und will mit dem ADC eine Spannung messen und diese Spannung über den UART ausgeben.
Der UART funktioniert problemlos, nur der ADC macht ein paar Probleme.
Er gibt nicht das richtige Ergebnis raus. Als Spannungsquelle habe ich ein Labornetzteil genommen und der ADC sollte ja dann bei einer Spannung von 3,3V den maximalen Wert ausgeben, was er aber nicht tut. Stattdessen gibt er den Wert 3 raus.
Den höchsten Wert (131) habe ich bei einer Spannung von 1,5V.
Wo habe ich einen Fehler gemacht?
Ich finde ihn nicht....



#define CPU_SPEED 32000000
#define BAUDRATE 100000
#define TWI_BAUD(F_SYS, F_TWI) ((F_SYS / (2 * F_TWI)) - 5)
#define TWI_BAUDSETTING TWI_BAUD(CPU_SPEED, BAUDRATE)


// Lese- und Schreibadresse vom EEPROM
#define EEPROM_W_Adresse 0xA0;
#define EEPROM_R_Adresse 0xA1;


#include <avr/io.h>
#include <avr/interrupt.h>
#include <string.h>
#include <stddef.h>
#include <avr/pgmspace.h>
#include <stdlib.h>





// Peripherie
unsigned char ADCA_Conversion(char Channel);
void DACB_Conversion(int Voltage);
int LeseKalibrationsbyte(int Index);


// Variablen
volatile int ADC_Value = 0x00;
volatile int Voltage = 0x00;
volatile int Compare = 0x6000;
volatile int ADC_Calibrationbyte;
volatile int Zaehler = 1;
char Text[50] = "Interrupt!";


int main(void)
{
Clock_init();
PLL_init();
//RTC_init();
//RTC_config();
Int_init();
DACB_Cal();
DACB_init();
ADCA_Cal();
ADCA_init();
TimerC0_init();
TimerF0_init();
Port_init();
UART_init()
DMA_init(); TWIF_init();

while(1)
{
}
}


int LeseKalibrationsbyte(int Index)
{
int result;


NVM_CMD = NVM_CMD_READ_CALIB_ROW_gc;
result = pgm_read_byte(Index);
NVM_CMD = NVM_CMD_NO_OPERATION_gc;
return(result);
}

void ADCA_init()
{
ADCA.CTRLB = ADC_RESOLUTION_12BIT_gc;
ADCA.REFCTRL = ADC_REFSEL_AREFA_gc;
ADCA.CTRLA = ADC_ENABLE_bm;
}

void Clock_init(void)
{
OSC.CTRL |= OSC_RC32MEN_bm;
while(!(OSC.STATUS & OSC_RC32MEN_bm));
CCP = CCP_IOREG_gc;
CLK.CTRL = CLK_SCLKSEL_RC32M_gc;
}



void UART_init(void)
{
USARTC0.BAUDCTRLB = 0;
USARTC0.BAUDCTRLA = 0x84;
USARTC0.CTRLA = USART_RXCINTLVL_HI_gc;
USARTC0.CTRLB = USART_TXEN_bm | USART_RXEN_bm;
USARTC0.CTRLC = USART_CHSIZE_8BIT_gc;
}

void TimerC0_init()
{
TCC0.CTRLA = TC_CLKSEL_DIV1024_gc;
TCC0.CTRLB = 0x00;
TCC0.INTCTRLA = 0x03;
}

void TimerC0_Freq(int TTW)
{
TCC0.PER = TTW;
}


void Send_UART(char data[])
{
char Counter;
char lenght = 0x00;

lenght = strlen(data);

while(Counter < lenght)
{
while (!(USARTC0.STATUS & USART_DREIF_bm));
USARTC0.DATA = data[Counter];
Counter++;
}

Counter = 0x00;
while (!( USARTC0.STATUS & USART_DREIF_bm));
USARTC0.DATA = 0x0A;
while (!( USARTC0.STATUS & USART_DREIF_bm));
USARTC0.DATA = 0x0D;
}

unsigned char ADCA_Conversion(char Channel)
{
ADCA_CH0_MUXCTRL = (Channel << 3);
ADCA.CH0.CTRL = 0x81;
return ADCA_CH0RES;
}


void ADCA_Cal(void)
{
ADCA.CALL = LeseKalibrationsbyte(offsetof(NVM_PROD_SIGNATURES_ t, ADCACAL0));
ADCA.CALH = LeseKalibrationsbyte(offsetof(NVM_PROD_SIGNATURES_ t, ADCACAL1));
}

ISR(TCC0_OVF_vect)
{
PORTR.OUT ^= 0x01;
Zaehler++;
Voltage = Voltage + 100;
Compare = Compare + 100;

ADC_Value = ADCA_Conversion(0);
itoa(ADC_Value, Text, 10);
Send_UART(Text);
}








Danke für die Hilfe!

Che Guevara
30.09.2012, 14:14
Hi,

laut Datenblatt von meinem ATXMEGA64A3 (du hast ja nicht angegeben, welchen du verwendest) darf AREF höchstens mit VCC-0.6V beschaltet werden. Somit kannst du eine Spannung von 3.3V gar nicht messen?!
Auch ist für mich nicht ersichtlich, welche Referenz du im Programm gewählt hast, da ich kein (zu wenig) C kann. Mach doch noch genauere Angaben (welcher µC, welche Referenz), damit man mehr sagen kann ;)

Gruß
Chris

Kampi
30.09.2012, 14:26
Stimmt! Ganz vergessen.
Also ich verwende einen XMega128A1 auf einem AVR XPlained 128A1 Board.
Als Taktfrequenz verwende ich den 32MHz Oszillator den ich auf 41MHz gestellt habe (mittels PLL).
Die Referenzspannung von 3,3V ist Boardbedingt schon an den passenden Pin angeschlossen.

Edit......ich Idiot. Ich hab gerade gesehen das nur AVCC am Board angeschlossen ist aber nicht AREF. Von daher messe ich gerade ohne Referenzspannung.
Ich glaube das Problem hat sich damit erledigt -.-
Aber selbst für den XMega128 darf man nur eine max. Referenzspannung von Vcc - 0,6V nehmen.
Danke für den Hinweis :)

Noch ein Edit:
Aber das komische Verhalten bleibt weiterhin bestehen.
Ich habe an meinem Labornetzteil nun eine Spannung von 0,2V eingestellt und das Terminal gibt 125 aus.

Che Guevara
30.09.2012, 14:41
Was für eine Referenz hast du den nun?
Ich bin mir grade nicht sicher, ob der ADC auch einen Offset bei Single-ended Inputs hat, aber dem würde ich auf jeden Fall mal nachgehen ;)

Gruß
Chris

Kampi
30.09.2012, 14:53
Die interne 1V Referenz:

ADCA.REFCTRL = ADC_REFSEL_INT1V_gc;

Aber ein Offset würde das Ergebnis ja erhöhen. Ich hab ja den Fall das es teilweise niedriger wird wenn ich die Spannung hochdrehe.

Che Guevara
30.09.2012, 15:06
Hm, das hört sich komisch an ...
GND ist verbunden?
ADC ist auf Single-ended eingestellt?
Die Spannung stimmt auch?
Wie hoch ist den der Prescaler des ADC? Laut DB darf der mit maximal 2Msps laufen, bei deinen 41MHz muss der Prescaler >= 32 sein. Ich würde es aber erstmal zum testen sowieso mit 512 probieren, da es dadurch genauer wird. Den MUX Kanal hast du auch richtig einstellt?

Sorry für meine doofe Fragerei, aber aufgrund meiner beschränkten C-Kenntnisse kann ich dir so besser helfen.

Gruß
Chris

Kampi
30.09.2012, 15:34
Ja GND ist verbunden und der ADC ist auf Singleended eingestellt.
Die Versorgungsspannung ist mittels USB gegeben und wird auf 3,3V runtergeregelt.
Den Prescaler hatte ich jetzt nicht drin, aber hab ihn mal mit einem Wert von 512 hinzugefügt.
Ins MUXCTRL Register schreibe ich eine 0 rein, sprich es ist Kanal 0 ausgewählt da ich als Input Mode 0:1, also Singleended gewählt habe.
In das ADC.CH0 Register schreibe ich eine 0x81 rein, sprich ich aktiviere Kanal 0 und stelle den Inputmode auf 01.

Che Guevara
30.09.2012, 15:40
Scheint ja alles richtig zu sein.. Dann kann ich dir momentan leider auch nicht weiterhelfen, aber wenn mir was einfällt, lasse ich es dich wissen ;)

Gruß
Chris

Kampi
30.09.2012, 19:21
Ok nun funktioniert es endlich!
Das "Problem" war einfach, dass ich den ADC auf 12Bit laufen lasse aber das Ergebnis der Wandlung in einen Char reinquetschen wollte der nur 8Bit groß ist.
Die 140 oder so die immer angezeigt wurden waren im Endeffekt das Rauschen des ADCs + ein paar Fetzen des eigentlichen Ergebnisses. Ich habe den Rückgabewert nun als Int deklariert und schwups funktionierte es :)