Forum: Mikrocontroller und Digitale Elektronik ADC im SAMD21


von adc (Gast)


Lesenswert?

Hallihallo,

ich stehe gerade etwas auf dem Schlauch :D
Ich möchte Spannungen am ADC des SAMD21J17D messen.
Folgende Einstellungen gelten für den ADC:
VRef = 3,3V / 2
Resolution 12 Bit
Hardwaremäßiger Mittelwertbildung (1024 mal gemessen und addiert, dann 
durch 1024 geteilt)

Mein Oszi sagt je nachdem was ich einstelle liegen -80mV .. 1,9V an.
Das eingestelltes ADC sagt mir (raw werte) 470 für 0V und etwa 
1000..1024 für 1,5V an. Erhöhe ich die Spannung nur leicht, dann scheint 
es einen wrap around zu geben und er springt gegen 0.

Ich verstehe nicht was hier passiert. Musste der ADC-Wert um die 0V 
nicht 0 sein?
Sollte nach der Überschreitung der Referenzspannung der ADC-Wert nicht 
sättigen?
Müsste der Maximalwert bei 12Bit nicht bei 2^12 = 4096 liegen?


Ich hab das spaßenhalber mal auf 8bit umgeschalten. da habe ich die 
gleichen effekte nur, dass der wrap-around bei 64 stattfinden...

von Stefan F. (Gast)


Lesenswert?

Zeige mal den Quelltext, damit wir sehen wie du den ADC konfiguriert 
hast.

Der Code mit dem du den Mittelwert bildest wäre auch von Interesse.

> Müsste der Maximalwert bei 12Bit nicht bei 2^12 = 4096 liegen?
ja

von adc (Gast)


Lesenswert?

1
void adc_init() {
2
3
4
/*  Temperature Sensor Enable bit          VREF.TSEN
5
   Bandgap Reference Voltage Generator       VREF.BGOUTEN */
6
  REG_SYSCTRL_VREF = 6; // BGOUTEN | TSEN
7
8
  REG_ADC_CTRLA = 1; // reset ADC
9
  while(REG_ADC_STATUS);
10
  
11
  
12
  #define REFCTRL_INT1V  0x00
13
  #define REFCTRL_INTVCC0  0x01
14
  #define REFCTRL_INTVCC1  0x02
15
  #define REFCTRL_VREFA  0x03
16
  #define REFCTRL_VREFB  0x04
17
  REG_ADC_REFCTRL = REFCTRL_INTVCC1;    
18
  while(REG_ADC_STATUS);
19
  
20
  
21
  #define AVGCTRL_AVG1  0x0
22
  #define AVGCTRL_AVG8  0x3 || 0x03 << 4;
23
  #define AVGCTRL_AVG128  0x7 || 0x04 << 4;
24
  #define AVGCTRL_AVG1024  0xA || 0x04 << 4;
25
  REG_ADC_AVGCTRL = AVGCTRL_AVG1024;
26
  while(REG_ADC_STATUS);
27
  
28
  
29
  REG_ADC_SAMPCTRL = 0;  // Sample_Time = 2 * (val + 1) / (F_ADC)
30
  while(REG_ADC_STATUS);
31
  
32
  REG_ADC_INTENSET = 1; // enable RESRDY (result ready interrupt)
33
  while(REG_ADC_STATUS);
34
35
  #define PRE_DIV4    0 << 8
36
  #define PRE_DIV64    4 << 8
37
  #define PRE_DIV512    7 << 8
38
  #define RESSEL12BIT    0 << 4
39
  #define RESSEL16BITAVG  1 << 4
40
  #define RESSEL10BIT    2 << 4
41
  #define RESSEL8BIT    3 << 4
42
  #define CORREN      1 << 3  // Digital Correction Logic Enabled
43
  #define FREERUN      1 << 2
44
  #define LEFTADJ      1 << 1  //  Left-Adjusted Result
45
  #define DIFFMODE    1 << 0
46
  REG_ADC_CTRLB = RESSEL12;
47
  while(REG_ADC_STATUS);
48
}
1
ui8 adc_get(ui16*adc_val, ui32 inputctrl) {
2
3
  REG_ADC_INPUTCTRL = inputctrl;
4
  while(REG_ADC_STATUS);  
5
6
  REG_ADC_CTRLA = 2; // enable ADC
7
  while(REG_ADC_STATUS);
8
    
9
  REG_ADC_SWTRIG = 2; // start conversion
10
  while(REG_ADC_STATUS);
11
    
12
  wait(1000);
13
  
14
  if(REG_ADC_INTFLAG & 1) {
15
    REG_ADC_INTFLAG = 0xf;
16
    *adc_val = REG_ADC_RESULT;
17
    state = init1;
18
    result = TRUE;
19
  }
20
  
21
  return 0;
22
}

der Aufruf zum messen  (INPUTCTRL im zweiten Argument):

adc_get(&adc_value, 0x05 | (0x19 << 8) | 0xf << 24);

von Stefan F. (Gast)


Lesenswert?

Für mich sieht das alles stimmig aus, außer der von dir beobachtete 
Fehler. Ich kann ihn nicht erklären.

von adc (Gast)


Lesenswert?

Danke sehr,
ich schaue es mir morgen noch einmal ganz genau an :)

von adc (Gast)


Lesenswert?

Hallo,

Ich bin ein Stückchen weiter. Den Offset kann ich beseitigen indem ich 
den Prescaler erhöhe. Ka weshalb. Im Datenblatt steht leider auch nichts 
dazu welchen mindestwerte im Prescaler vorliegen sollen.

Die anderen Fehler waren Folgefehler, in einem Codeschnippsel den ich 
hier nicht veröffentlicht habe. Ich habe die adc werte aufsummiert und 
durch die anzahl geteilt. hier hätte ich besser aufpassen müssen, denn 
auch irgendwann ist einmal eine 32bit variable übergelaufen und .. das 
war der wrap around :D

von adc (Gast)


Lesenswert?

Aber ich verstehe nicht wieso der offset größer wird, wenn der ADC mit 
nen schneller takt  läuft.

von Stefan F. (Gast)


Lesenswert?

Der ADC basiert ja darauf, dass er schrittweise mit einem DAC Spannungen 
zum Vergleich erzeugt und diese mittels Komparator mit deinem Input 
vergleicht.

Wenn das zu schnell passiert, vergleicht er Grütze mit deinem Input. 
Oder die Ausgabe des Komparator wird zu früh verarbeitet, während er 
noch mit Vergleichen beschäftigt ist.

Das Resultat sind ziemlich zufällige Ergebnisse.

von mariush (Gast)


Lesenswert?

...kommt ggf. auch drauf an, was Du da misst und wie der ADC Eingang 
beschaltet ist.

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.