Timer interrupt together analogRead

wizarcl
Wed Apr 06, 2016 1:12 am
Hi friends.
I’m developing a protection relay to college but i can not use analogRead inside a timerInterrup. Microcontroller stops when I do it.

SerialUSB.print("Leitura ADC: \t");
SerialUSB.println(analogRead(PA1));


mrburnette
Wed Apr 06, 2016 1:42 am
I’m developing a protection relay to college but i can not use analogRead inside a timerInterrup.

And there are good reasons you should not do this.
Rather, set a global flag and restore interrupts. In your loop() you can interrogate the flag, perform the analog read inline or in a function, then reset the flag for later use.

Ray

Afterthought…
I’ve include some code written for the Attiny85 …. look carefully at how f_wdt is declared and used; that is:
volatile boolean f_wdt = 1;
then in the interrupt routine proper, this is the only active code:
f_wdt=1; // set global flag

/*
* Watchdog Sleep Example
* Demonstrate the Watchdog and Sleep Functions
* LED on digital pin 0
*
* KHM 2008 / Lab3/ Martin Nawrath [email protected]
* Kunsthochschule fuer Medien Koeln
* Academy of Media Arts Cologne
*
* Modified on 5 Feb 2011 by InsideGadgets (www.insidegadgets.com)
* to suit the ATtiny85 and removed the cbi( MCUCR,SE ) section
* in setup() to match the Atmel datasheet recommendations
*/

#include <avr/sleep.h>
#include <avr/wdt.h>

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

int pinLed = 0;
volatile boolean f_wdt = 1;

void setup(){
pinMode(pinLed,OUTPUT);
setup_watchdog(8); // approximately 4 seconds sleep
}

void loop(){
if (f_wdt==1) { // wait for timed out watchdog / flag is set when a watchdog timeout occurs
f_wdt=0; // reset flag

digitalWrite(pinLed,HIGH); // let led blink
delay(1000);
digitalWrite(pinLed,LOW);

pinMode(pinLed,INPUT); // set all used port to intput to save power
system_sleep();
pinMode(pinLed,OUTPUT); // set all ports into state before sleep
}
}

// set system into the sleep state
// system wakes up when wtchdog is timed out
void system_sleep() {
cbi(ADCSRA,ADEN); // switch Analog to Digitalconverter OFF

set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable();

sleep_mode(); // System sleeps here

sleep_disable(); // System continues execution here when watchdog timed out
sbi(ADCSRA,ADEN); // switch Analog to Digitalconverter ON
}

// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
void setup_watchdog(int ii) {

byte bb;
int ww;
if (ii > 9 ) ii=9;
bb=ii & 7;
if (ii > 7) bb|= (1<<5);
bb|= (1<<WDCE);
ww=bb;

MCUSR &= ~(1<<WDRF);
// start timed sequence
WDTCR |= (1<<WDCE) | (1<<WDE);
// set new watchdog timeout value
WDTCR = bb;
WDTCR |= _BV(WDIE);
}

// Watchdog Interrupt Service / is executed when watchdog timed out
ISR(WDT_vect) {
f_wdt=1; // set global flag
}


stevech
Wed Apr 06, 2016 4:16 am
Interrupt Service Routine (ISR) code Rule 1

a) Get in, get out really fast. ISRs live on borrowed time. Mind the mutual exclusion principles.
b) Don’t call outside the ISR without knowing the other code obeys (a).
c) Rarely let one ISR interrupt another.
d) Read (a)


RogerClark
Wed Apr 06, 2016 4:25 am
In addition to what other people have said …

Some things don’t work inside interrupts as they use interrupts in their operation.

I’d definitely not write anything out to Serial (or USB Serial) inside an ISR, and I suspect that reading the Analogue is likely to use an interrupt i.e to flag that the “conversion” is complete.

Note. I’m not sure why you are using the USBSerial class as if you are using the bootloader, “Serial” is USBSerial (Serial1 is hardware serial 1)

e.g. I have some code that runs on a 100Hz extrernal interrupt trigger (AC mains freq x 2), and I need to read data from SPI after I get an interrupt.
But I don’t read from SPI in the ISR, I set a global volatile flag and then handle the SPI read in the main loop next time it checks the flag variable


wizarcl
Wed Apr 06, 2016 10:07 am
Thanks for your support guys.

I dont need to use Serial class in timer interrupt, I used it to verify what value is returned by analogRead. I tried to collect data from analogRead each xxx microseconds.
amostrasSinal[indexAmosta] = analogRead(PA1);
indexAmosta++; // Incrementa ponteiro
if(indexAmosta >= SAMPLES){ // Se alcançar a quantidade de amostras configuradas, zerar
indexAmosta = 0;
}


RogerClark
Wed Apr 06, 2016 10:36 am
Depends whats happening in your main loop

If its not doing anything else, then just setting a flag in the ISR will get picked up really quickly in the main loop.

I recall someone else posted a question about something similar and @ddrown posted a reply showing how you need to defined the flag variable as volatile and how many instructions this takes to process a tight while loop

The STM32 running at 72Mhz is quite a fast processor, so setting a flag in the ISR and processing it in the main loop is unlikely to give a massive delay.


wizarcl
Wed Apr 06, 2016 1:12 pm
I’ll try, but i have a lote of code in main loop(). I used this in past, but in main loop isn’t deterministic. Depending of program, loop takes 12 microseconds or more, so if I need a analogRead each 20 microseconds, using flag, microcontroller will run make measurements after 24 microseconds….

zmemw16
Wed Apr 06, 2016 2:33 pm
silly questions time
60Hz is approx 16.666mS
show user how & what exactly?

say 100 samples, so every 3.6 degrees is 0.166mS or 166uS / sample
at 20usec sampling, that’s ( 16.666*1000uS )/20uS = 8333 samples

adc conversion takes how long?
didn’t someone do something with adc & dma recently? pig-o-scope

arduino loop executes every 24uS, really?

anybody else also puzzled?

srp


wizarcl
Wed Apr 06, 2016 9:13 pm
zmemw16 wrote:silly questions time
60Hz is approx 16.666mS
show user how & what exactly?

stevech
Wed Apr 06, 2016 9:29 pm
Calling Arduino libraries (or most any) from an ISR – you need to know how long that code will run.
Generally unwise.

RogerClark
Wed Apr 06, 2016 10:43 pm
It sounds like for the level of timing accuracy that you want, that you may need to directly interface with the hardware and not rely on Maple API calls.

In fact you may need to re-code in assembler if timing is that critical, as its the only way you are going to be able to get more precise timings

NB.

All Micro’s does is miltiply the number of millis by 1000, and work out how long there is between the call to micros and the next millis tick (systick which occurs after 72,000 clock cycles

So Micro’s its self has quite a lot of overhead.

Perhaps if you explained exactly what you were trying to achieve with all these complex timings, we may be able to advise if you are just looking at the whole problem in the wrong way.


stevech
Thu Apr 07, 2016 4:42 am
RogerClark wrote:All Micro’s does is miltiply the number of millis by 1000, and work out how long there is between the call to micros and the next millis tick (systick which occurs after 72,000 clock cycles

So Micro’s its self has quite a lot of overhead.


wizarcl
Sun Apr 10, 2016 11:17 pm
Sorry friends, I make a big mistake. I forgot to declare my variable as volatile and use of serial in interruption is a bad idea. Now I looking for mor information about ADC clock. In leaflabs documentation I dont founded, I looking in included files… If someone have more information, please, share. :)

RogerClark
Sun Apr 10, 2016 11:54 pm
Leaflabs moved their wiki but I’m not sure if its online any more.

But I doubt you would find the information you need in the wiki

You will need to refer to the programming manual for the STM32F103 called RM0008 , which I think you can download from here http://www.st.com/web/en/resource/techn … 171190.pdf


Leave a Reply

Your email address will not be published. Required fields are marked *