ADC interrupt not firing

Hello I have a problem with my program - I’m running timer 2 to cyclicaly start my main loop (as TIMER2_COMPA_vect) - I’m doing so to sample ADC at a constant frequency and do some math with the data.
While I have a version of the program that works with simple non blocking ADC code (start conversion, do some instructions, check if conversion is done) - I’d like to be able to do whatever math I can while conversion happens, then to get ADC_vect interrupt to read the registers. I have a blocking while(ADCdone); statement to wait for the conversion if it would happen slower than instructions that I’m executing.
This is running on Arduino Nano type board.
Problem is that ADC_vect interrupt never happens - I have a debug function on pin 13 and it just goes high - that means that the timer interrupt fires once and sets 13 to high, while when the code would end 13 shoud go low.

Any idea what I’m doing wrong?

My code:

static uint8_t ADCdone = 1;
static int16_t ADCsample = 0;

ISR(TIMER2_COMPA_vect) {
	static int16_t output_sample = 0;
	static uint8_t i = 1;

	PORTB = 0x20;

	sei();

	//ADC mux to 0
	ADMUX = 0b01000000;
	//start conversion
	ADCSRA |= 0b01001000;

	OCR1A = output_sample;

	delayUpdatePointers();
	updateLFOs();
	//wait for conversion to end
	while(ADCdone);
	ADCdone = 1;

	//iterate
	i += 1;
	if(i >= 5) i = 1;

	//ADC mux to control input i
	ADMUX |= i;
	//start conversion
	ADCSRA |= 0b01001000;

	//write sample to delay line
	ADCsample -= 512;
	ADCsample >>= 2;
	writeDelay(ADCsample);

	//read sample from delay line
	output_sample = readDelay();
	if(output_sample >= 126) output_sample = 126;
	if(output_sample <= -127) output_sample = -127;
	output_sample += 128;

	//wait for conversion to end
	while(ADCdone);
	ADCdone = 1;

	//update controls
	if(i == 1)
	{
		a = 493 + ADCsample;
	}
	if(i == 2)
	{
		b = ADCsample;
	}
	if(i == 3)
	{
		c = ADCsample;
	}
	if(i == 4)
	{
		d = ADCsample;
	}

	PORTB = 0x00;
}

ISR(ADC_vect) {
	//read ADC
	ADCsample = ADCL;
	ADCsample |= (ADCH << 8);
	ADCdone = 0;
}

//The setup function is called once at startup of the sketch
void setup()
{
	//setup ADC
	PRR = 0;
	//500kHz ADC clock for faster conversion, we should be able to do 2 conversions per program loop
	ADCSRA = 0b10001101;
	//5V reference voltage
	ADMUX = 0b01000000;
	//PB1 is PWMOUT (timer 1 output A), PB5 is debug pin (MCU % time taken)
	DDRB |= (1 << PB1) | (1 << PB5);
	//enable timer 1, 8-bit resolution, 62.5kHz
	OCR1A = 128;
	TCCR1A = (1 << COM1A1) | (1 << WGM10);
	TCCR1B = (1 << WGM12) | (1 << CS10);
	//sampling engine interrupt @15.625kHz
	TCCR2A = (1 << WGM21);
	TCCR2B = (1 << CS21) | (1 << CS20);
	OCR2A = 31;
	//enable timer 2 interrupt
	TIMSK2 = (1 << OCF2A);
}

// The loop function is called in an endless loop
void loop()
{
	;
}

Okay... I just got it - my timer ISR was restarting because the amount of computations was too high for the allocated time... When I changed the sampling rate to 7.8125kHz there was 57-65% MCU load.
Back to the drawing board then, I realy want that higher sampling rate.
Any idea how to read potentiometers and not interfere with my sampling (without external ADC)?

What resolution do you need at what rate?

TheMemberFormerlyKnownAsAWOL:
What resolution do you need at what rate?

15.625kHz at 8 bits would be the sweet spot, I don’t have that much memory to use for the buffer anyway.
What I’m doing is a tripple chorus emulation, the old code works nice, but I hoped that using conversion end ISR would let me do something more with my samples. Nice thing is that you can use only one delay line for the effect instead of the classical 3 in analog implementation (because you just move pointers around with the code :-)).
I could probably just live with ~8kHz sampling rate and change my antialiasing and reconstruction filters for lower ft. But I hoped for that higher sampling rate :wink:

Edit:
If I could cheat somehow with those controls then that would help, but 328P only has one ADC converter :frowning:

Edit 2:
BTW I tried something like this:

ISR(TIMER2_COMPA_vect) {
	if(startLoop) startLoop = 0;
}

ISR(ADC_vect) {
	//read ADC
	ADCsample = ADCL;
	ADCsample |= (ADCH << 8);
	ADCdone = 0;
}

void loop()
{
	static int16_t output_sample = 0;
	static uint8_t i = 1;
	sei();
	while(startLoop);
	startLoop = 1;

	PORTB = 0x20;

	//ADC mux to 0
	ADMUX = 0b01000000;
	//start conversion
	ADCSRA |= 0b01000000;

	OCR1A = output_sample;

	delayUpdatePointers();
	updateLFOs();
.
.
.

But then the program hangs completely and doesn’t drive pin 13 even once, what gives?

If you want rotary controls why not use rotary encoders which are easier to handle (no analogReads)
in code whilst your data acquisition is running as you simply need to run a little logic on some
digital pins every so often.

MarkT:
If you want rotary controls why not use rotary encoders which are easier to handle (no analogReads)
in code whilst your data acquisition is running as you simply need to run a little logic on some
digital pins every so often.

Don't have any on hand, but I did think about that. Pot's have haptic feedback of the end stops though :smiley:
What would be the best way of implementing the encoders - pin change interrupt or just plain old pooling of ports? (I'm not all that bright when it comes to embedded, or software for that matter, I do industrial automation for a living, on the hardware side mostly, some PLC debugging here and there).

Edit:
What I can do is to save current encoder inputs for next loop (or interrupt), then check if they are the same = no change, if changed then there are 8 combinations possible - 4 each for increment or decrement of controled value.

Edit 2:
I found why snippet form above didn't work - should have used volatile for startLoop and ADCdone variables.

Edit 3:
Code with ADC_vect interrupt is slower o_0

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.