MorganS:
Interrupts are queued. So if it occurs during the time that interrupts are disabled, it will be handled as soon as you re-enable. Note that only one of each type is queued: one timer0, one timer1, one serial, one pin-change....
But a safe copy of an int should only take 2 instructions. Not long at all.
Ok good to know. I just read it also in the link to gammon forum. -the first time I read it diagonally as I didn't have much time.
I have 1 now timer to have a fixed sample rate, now T2. This interrupt starts the first conversion. When complete, the adc results gets put into a buffer, and the next channel conversion starts. (4 channels in total).
The top signal is the toggling of T2. The bottom signal is HIGH when the ADC is busy converting.
I rewrote the program. I disabled the interrupts when changing the flag, and made a new buffer, so only 1 value gets changed in the interrupt handler.
The first thing that I noticed was that the difference between the first and the others was gone.
I have really no idea how this comes. And I'm doubting if it is because I changed my program or because I used micros().
Though I will have to do some more debugging since if I set a pin high during the handling of the adc results (in the main thread), I get no proper output, linked to the output of pin_adc.
const uint8_t length = 12;
unsigned long time_passed[length];
const uint8_t pin_sample = 0; // toggle after each period
const uint8_t pin_adc = 1; // during conversion high
struct flag {
uint8_t window_rdy:1;
uint8_t fv_finalize:1;
uint8_t sample_rdy:1;
uint8_t channel_rdy:2;
};
volatile uint8_t adc_channel;
volatile struct flag flag;
volatile T buffer_sample[N_SENS];
T buffer[3 * N_SENS];
T *ptr_buffer[N_SENS];
T feature_vector[N_TOT_FEAT];
T *ptr_fv[N_SENS];
T fv_save[N_TOT_FEAT];
T *ptr_fv_save[N_SENS];
#ifndef __FL__
T2 temp_rms[N_SENS];
Tsmall carry_mav[N_SENS];
Tsmall carry_wfl[N_SENS];
#endif
/// @brief set bit of an 8bit register
/// \param reg
/// \param bit
static inline void set_bit(volatile uint8_t *reg, uint8_t bit) {
*reg |= (1 << bit);
}
/// @brief clear bit of an 8bit register
/// \param reg
/// \param bit
static inline void clr_bit(volatile uint8_t *reg, uint8_t bit) {
*reg &= ~(1 << bit);
}
/// @brief toggle bit of an 8bit register
/// \param reg
/// \param bit
static inline void tgl_bit(volatile uint8_t *reg, uint8_t bit) {
*reg ^= (1 << bit);
}
static inline void arr_set(T *arr, T val, uint8_t n) {
#ifdef __FL__
uint8_t i = 0;
for (; i < n; ++i)
arr[i] = 0;
#else
memset(arr, val, n * sizeof(T));
#endif
}
void init_global_var() {
arr_set(feature_vector, 0, N_TOT_FEAT);
arr_set(fv_save, 0, N_TOT_FEAT);
arr_set(buffer, 0, 3 * N_SENS);
adc_channel = 0;
uint8_t i = 0;
for (; i < N_SENS; ++i) {
#ifndef __FL__
temp_rms[i] = 0;
carry_mav[i] = 0;
carry_wfl[i] = 0;
#endif
ptr_buffer[i] = buffer + N_SENS * i + 2;
ptr_fv[i] = feature_vector + N_FEAT * i;
ptr_fv_save[i] = feature_vector + N_FEAT * i;
}
}
void init_sample_timer() {
TCCR2A = 0; //T2 control register
TCCR2A |= (1 << WGM21);
TCCR2B = 0;
//OCR0A = f_clk / (f*prescale) - 1
OCR2A = 250; //set compare match register
TCNT2 = 0; //init counter value to 0
TIMSK2 |= (1 << OCIE2A); //enable T0 interrupt
}
void enable_sample_timer() {
TCCR2B |= (1 << CS22)| //set prescale 64
(0 << CS21)|
(0 << CS20);
}
void init_ADC() {
ADMUX = 0;
ADMUX |= (1 << REFS0); //AVcc voltage reference
ADMUX = 0;
ADMUX |= (1 << REFS0); //AVcc voltage reference
ADCSRA = 0;
ADCSRA |= (1 << ADPS2)| //ADC prescale = 128 -> 125kHz
(1 << ADPS1)|
(1 << ADPS0);
ADCSRA |= 1 << ADEN;
uint8_t i = 0;
for (; i < 20; ++i) {
ADCSRA |= 1 << ADSC;
while (ADCSRA & (1 << ADSC)) {};
ADCL;
}
ADCSRA = 0;
ADCSRA |= (0 << ADATE)| //auto trigger disable
(1 << ADIE)| //ADC interrupt enable
(1 << ADPS2)| //ADC prescale = 128 -> 125kHz
(1 << ADPS1)|
(1 << ADPS0);
ADCSRB = 0;
}
void enable_ADC() {
ADCSRA |= 1 << ADEN; //enable ADC
}
void disable_ADC() {
ADCSRA &= ~(1 << ADEN); //enable ADC
}
void start_conversion(uint8_t adc_ch) {
set_bit(&PORTB, pin_adc);
ADMUX = (ADMUX & 0xF0)| //safety mask
(adc_ch & 0x0F); //set ADC channel
ADCSRA |= 1 << ADSC;
}
void handle_adc_res(uint8_t adc_ch) {
#ifdef __FL__
update_feat_vec(ptr_fv[adc_ch], ptr_buffer[adc_ch]);
#else
update_feat_vec(ptr_fv[adc_ch],
carry_mav + adc_ch,
temp_rms + adc_ch,
carry_wfl + adc_ch,
ptr_buffer[adc_ch]);
#endif
}
void setup() {
Serial.begin(9600);
delay(2000);
cli();
flag.sample_rdy = 0;
flag.window_rdy = 0;
flag.fv_finalize = 0;
DDRB = 0xFF;
PORTB = 0x00;
init_global_var();
init_sample_timer();
init_ADC();
sei();
enable_ADC();
enable_sample_timer();
uint8_t i = 0;
while (i < length) {
while(!flag.sample_rdy) {}
cli();
flag.window_rdy = 0;
uint8_t ch = flag.channel_rdy;
*(ptr_buffer[ch]) = buffer_sample[ch];
sei();
unsigned long time_start = micros();
handle_adc_res(ch);
*(ptr_buffer[ch] - 2) = *(ptr_buffer[ch] - 1);
*(ptr_buffer[ch] - 1) = *(ptr_buffer[ch]);
time_passed[i] = micros() - time_start;
++i;
}
}
void loop() {
uint8_t i;
Serial.println(F("speed results"));
for (i = 0; i < length; ++i) {
Serial.print(time_passed[i]);
Serial.print("\t");
Serial.println(feature_vector[i]);
}
while(1) {}
}
// sets sampling frequency
// starts conversion of first sensor
ISR(TIMER2_COMPA_vect) {
tgl_bit(&PORTB, pin_sample);
adc_channel = 0;
start_conversion(adc_channel);
}
// interrupt handler of the adc
// saves sample + starts next sensor conversion
ISR(ADC_vect) {
clr_bit(&PORTB, pin_adc);
// read ADCL
uint8_t lsb = ADCL;
// read ADCH and save 10 bit value
buffer_sample[adc_channel] = (ADCH << 8) | lsb;
flag.channel_rdy = adc_channel;
flag.sample_rdy = 1;
if (++adc_channel < N_SENS)
start_conversion(adc_channel);
}