Forum: Mikrocontroller und Digitale Elektronik EFM32 ADC und USB


von Robert S. (gips1gott)


Lesenswert?

Moin Leute,

ich möchte ADC Werte über USB ausgeben. Mein aktuelles Programm nimmt 
ADC-Werte auf und gibt diese auch über USB aus. Das Problem ist, dass 
die ADC-Werte nicht stimmen. Das Programm ohne Timer1 und USB gibt 
allerdings richtige ADC-Werte aus. Unten sind die wichtigsten Zeilen 
meines Programmes.

Init:
1
static void EFM32_Init(void)
2
{
3
4
  CDC_Init();
5
  SegmentLCD_Init(false);
6
7
  CMU_OscillatorEnable(cmuOsc_HFXO, true, false);
8
  CMU_ClockSelectSet( cmuClock_HF, cmuSelect_HFXO );
9
10
  CMU_ClockEnable(cmuClock_HFPER, true);
11
  CMU_ClockEnable(cmuClock_ADC0, true);
12
  CMU_ClockEnable(cmuClock_TIMER1, true);
13
14
  USBD_Init(&usbInitStruct);
15
16
  TIMER_Init(TIMER1, &timerInit);
17
18
  TIMER_IntEnable(TIMER1, TIMER_IF_OF);
19
20
  NVIC_EnableIRQ(TIMER1_IRQn);
21
22
  TIMER_TopSet(TIMER1, TOP);
23
24
  TIMER1->CNT=0;
25
26
}

sowie:
1
static void ADCConfig(void)
2
{
3
  ADC_Init_TypeDef       init       = ADC_INIT_DEFAULT;
4
  ADC_InitSingle_TypeDef singleInit = ADC_INITSINGLE_DEFAULT;
5
6
  init.timebase = ADC_TimebaseCalc(0);
7
8
  init.prescale = ADC_PrescaleCalc(7000000, 0);
9
10
  ADC_Init(ADC0, &init);
11
12
  singleInit.reference  = adcRef5VDIFF;
13
  singleInit.input      = adcSingleInputCh0;/
14
  singleInit.resolution = adcRes12Bit;
15
16
  init.warmUpMode     = adcWarmupKeepScanRefWarm;
17
18
  singleInit.acqTime = adcAcqTime32;
19
20
  ADC_InitSingle(ADC0, &singleInit);
21
22
}

sowie:
1
void TIMER1_IRQHandler(void)
2
{
3
4
  TIMER_IntClear(TIMER1, TIMER_IF_OF);
5
  
6
  ADC_Start(ADC0, adcStartSingle);
7
              
8
  while (ADC0->STATUS & ADC_STATUS_SINGLEACT);
9
10
  ergebnis = ADC_DataSingleGet(ADC0);
11
}

von Nop (Gast)


Lesenswert?

Jan S. schrieb:
> while (ADC0->STATUS & ADC_STATUS_SINGLEACT);

In Interrupts warten ist nie eine gute Idee. Wieso liest Du nicht 
einfach den ADC-Wert ohne Warteschleife aus und stößt direkt danach die 
nächste Messung an? Diese wird dann im nächsten Timer-Interrupt 
ausgelesen. Solange die Timerfrequenz geringer als die Wandlungszeit 
ist, geht das (wenn nicht, geht das alles eh nicht).

Die Werte sind dann zwar um eine Timerperiode veraltet, aber wenn Du das 
dann eh paketiert über USB schickst, wird das wohl keine so große Rolle 
spielen.

von Jim M. (turboj)


Lesenswert?

Ich sehen in Deinem Code oben keinen Aufruf für ADCConfig(). Das muss an 
der korrekten Stelle stehen.

Ich sehe aber noch mehr:
1
  CDC_Init();
2
  SegmentLCD_Init(false);
3
4
  CMU_OscillatorEnable(cmuOsc_HFXO, true, false);
5
  CMU_ClockSelectSet( cmuClock_HF, cmuSelect_HFXO );

CDC_Init würde ich immer erst nach den Oszillatoren machen, sonst 
stimmt eventuell die Baudrate nicht. Dito SegmentLCD_init().

USB verwendet einen der Timer, aber IIRC nicht Timer1.

Da Du den HFXO direkt verwenden willst, besser:
1
CMU_OscillatorEnable(cmuOsc_HFXO, true, true);

Die Änderung von init.warmUpMode hat keinen Effekt, da sie nach 
ADC_Init() erfolgt.

Damit hast Du das Problem mit dem überlaufenden Referenzzähler im Warmup 
bei 48 Mhz (siehe Manual/Errata), was die schlechten ADC Werte erklären 
könnte.

von Robert S. (gips1gott)


Lesenswert?

Moin Leute,

ich habe die ADC Abfrage nun außerhalb des Interrupts gelegt sowie die 
Initialisierungsschritte wie Jim Meba beschrieben hat durchgeführt. 
Vielen Dank erstmal dafür! Sicherlich habe ich auch hier Fehler gemacht. 
Die ADC-Config ist bei mir auch in der main(). Nach meinen 
Verbesserungen hat das Programm leider immer noch nicht wünschenswert 
gearbeitet. Nach einigen Messungen an den I/O-Pins fiel mir auf, dass 
ich auf CH0 3V im ADC Diff Modus mit CH0 und CH1 anliegen habe. Daher 
habe ich meinen ADC auf CH6 und CH7 gelegt und siehe da - es 
funktioniert. Vielen Dank an euch!

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.