Meerdere keren ADC uitlezen ATxMega128

Goedemiddag,

code geschreven: Amel studio 7
Development board: XMEGA A1U Xplained board Pro
Atmel device: ATxMega128A1U

Ik kan de functie read_ADC precies 252 keer aanroepen, daarna hangt de uC. Ik zo mij vermoedens dat het iets is met de interrupts, zou dat kunnen? Heeft iemand enig idee?

Grz.

code:


#include <asf.h>

#define MY_ADC    ADCA
#define MY_ADC_CH ADC_CH0
#define MY_ADC_CH1 ADC_CH1
#define MY_ADC_CH2 ADC_CH2
#define MY_ADC_CH3 ADC_CH3

#include "SRAM_functions.h"

void adc_init(void)
{
	//Init ADC
	struct adc_config adc_conf;
	struct adc_channel_config adcch_conf;
	adc_read_configuration(&MY_ADC, &adc_conf);
	adc_set_conversion_parameters(&adc_conf, ADC_SIGN_OFF, ADC_RES_12, ADC_REF_BANDGAP);
		//ADC_SIGN_OFF		==> /** Unsigned conversions. */
		//ADC_RES_12		==> /** 12-bit resolution, right-adjusted. */
		//ADC_REF_BANDGAP	==> /** Internal 1 V from bandgap reference. */

	adc_set_conversion_trigger(&adc_conf, ADC_TRIG_MANUAL, 1, 0);
													//ADC_TRIG_MANUAL	==>	/** Manually triggered conversions */
	adc_set_clock_rate(&adc_conf, 100000UL);		//veranderd!!	
													//	adc_set_clock_rate(&adc_conf, 100000UL);//veranderd!!	
	adc_write_configuration(&MY_ADC, &adc_conf);


	//Init ADC channel 0 ==> ADCCH_POS_PIN0 = PA0_ADC0 
	adcch_read_configuration(&MY_ADC, MY_ADC_CH, &adcch_conf);
	adcch_set_input(&adcch_conf, ADCCH_POS_PIN0, ADCCH_NEG_NONE, 1);
	adcch_write_configuration(&MY_ADC, MY_ADC_CH, &adcch_conf);
	
	//Init ADC channel 1 ==> ADCCH_POS_PIN0 = PA0_ADC0 
	adcch_read_configuration(&MY_ADC, MY_ADC_CH1, &adcch_conf);
	adcch_set_input(&adcch_conf, ADCCH_POS_PIN0, ADCCH_NEG_NONE, 1);
	adcch_write_configuration(&MY_ADC, MY_ADC_CH1, &adcch_conf);
	
	//Init ADC channel 2 ==> ADCCH_POS_PIN0 = PA0_ADC0 
	adcch_read_configuration(&MY_ADC, MY_ADC_CH2, &adcch_conf);
	adcch_set_input(&adcch_conf, ADCCH_POS_PIN0, ADCCH_NEG_NONE, 1);
	adcch_write_configuration(&MY_ADC, MY_ADC_CH2, &adcch_conf);
	
	//Init ADC channel 3 ==> ADCCH_POS_PIN0 = PA0_ADC0 
	adcch_read_configuration(&MY_ADC, MY_ADC_CH3, &adcch_conf);
	adcch_set_input(&adcch_conf, ADCCH_POS_PIN0, ADCCH_NEG_NONE, 1);
	adcch_write_configuration(&MY_ADC, MY_ADC_CH3, &adcch_conf);
}

uint16_t ui16_Counter;

void read_ADC (void)
{
	ui16_Counter = 0;
	adc_enable(&MY_ADC);
	adc_start_conversion(&MY_ADC, MY_ADC_CH);
	//adc_wait_for_interrupt_flag(&MY_ADC, MY_ADC_CH);
	//result = adc_get_result(&MY_ADC, MY_ADC_CH);
}

  ISR(ADCA_CH0_vect)			//Interrupt: ADCA_CH0_vect
 {
	 uint16_t result;
	 uint8_t result_low;
	 uint8_t result_high;

	 //udi_cdc_putc(ui8_Counter);
	 //udi_cdc_putc(result_high);
	 //udi_cdc_putc(result);

	 result = adc_get_result(&MY_ADC, ADC_CH0);
	 result_high = result >> 8;
	 SRAM_WriteData(ui16_Counter, result);

 }
  ISR(ADCA_CH1_vect)			//Interrupt: ADCA_CH1_vect
 {
	 	 uint16_t result;
	 	 uint8_t result_low;
	 	 uint8_t result_high;
	 	 result = adc_get_result(&MY_ADC, ADC_CH1);
	 	 result_high = result >> 8;
	 	 SRAM_WriteData(ui16_Counter, result);
	 	 ui16_Counter = ui16_Counter + 1;
 } 
  ISR(ADCA_CH2_vect)			//Interrupt: ADCA_CH2_vect
 {
	 	 uint16_t result;
	 	 uint8_t result_low;
	 	 uint8_t result_high;
	 	result = adc_get_result(&MY_ADC, ADC_CH2);
	 	result_high = result >> 8;
	 	SRAM_WriteData(ui16_Counter, result);
	 	ui16_Counter = ui16_Counter + 1;
 }
  ISR(ADCA_CH3_vect)			//Interrupt: ADCA_CH3_vect
 {
	 	 uint16_t result;
	 	 uint8_t result_low;
	 	 uint8_t result_high;
	 	result = adc_get_result(&MY_ADC, ADC_CH3);
	 	result_high = result >> 8;
	 	SRAM_WriteData(ui16_Counter, result);
	 	ui16_Counter = ui16_Counter + 1;
	 	 if (ui16_Counter < 8000 )  
	 {
		 adc_start_conversion(&MY_ADC, MY_ADC_CH);	 
	 }
	 else
	 {
		ui16_Counter = 8001;
	 }
 }





Die xMega is een 8-bit processor. En ui16_Counter is een 16-bit register. Dus de processor heeft meerdere instrukties nodig om die op te hogen. Als je dat in meerdere interrupt handlers gaat doen, dan krijg je het effect dat de ene interrupt de andere interrumpeert terwijl die nog bezig is met het ophogen. Er lastig allemaal.

Daar zijn 2 oplossingen voor:
- Een enkele interrupt gebruiken om alle 4 de kanalen uit te lezen.
- Zorgen dat de interrupts elkaar niet kunnen interrumperen.

En voor de goede werking moet je die counter ook volatile declareren. Anders weet de compiler niet dat die spontaan (tgv interrupts) van waarde kan veranderen.

Dat klinkt eerder als een stack overflow. Wacht je wel steeds tot het resultaat binnen is? in read_ADC start je alleen de conversie, die is nog niet klaar als je uit die functie komt. De eerste regel die uit staat (comment) zou, volgens de naam, wachten op de interrupt, maar waarom zou je dan uberhaupt interrupts gebruiken, als je toch gaat staan wachten?!?

Weet je zeker dat het niet mis gaat in die SRAM_WriteData functie? Heb je die er al eens uitgehaald?

Heb je een debugger? Daarmee zou je precies kunnen zien wat er mis gaat, zeker als je een dummy if-statement schrijft zodat je een breakpoint kunt zetten op de 251-ste iteratie.

@deKees: ik mag toch aannemen dat de global interrupt flag uit staat zolang je in een ISR zit, aangezien de TS die zelf niet terug aan zet, en dan zijn ISRs dus niet interruptable.

[Bericht gewijzigd door SparkyGSX op 20 juli 2019 11:54:34 (13%)]

Een manager is iemand die denkt dat negen vrouwen in één maand een kind kunnen maken

Nee, de global interrupt blijft aktief binnen de ISR.

Zo een Xmega is veel meer advanced dan een gewone AVR. Deze heeft uitgebreide instel mogelijkheden voor zijn interrupts inclusief priority levels enz.

Hoe het precies werkt is afhankelijk van de instelingen, en die laat TS hier niet zien.

PE9SMS

Special Member

Op een XMega kun je prioriteiten voor interrupts configureren. Dus afhankelijk daarvan kunnen interrupts elkaar interrumperen. En als je 4 ADC steeds tegelijk een conversie laat doen heb je alleen een ISR voor de laatste ADC nodig. Die conversies vinden netjes op volgorde plaats namelijk.

Klopt, dus alleen interrupts voor channel 3 enabelen en in de ISR alle 4 kanalen uitlezen.

Opgelost,

"adc_enable(&MY_ADC)" moet niet in "void read_ADC (void)" maar in de "void adc_init(void)".

Pfff... Dank iedereen

Maar hoe verklaard dat de symptomen?

Een manager is iemand die denkt dat negen vrouwen in één maand een kind kunnen maken