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)?
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
Edit:
If I could cheat somehow with those controls then that would help, but 328P only has one ADC converter
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
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