Go Down

### Topic: Interrupts and time handling problems. (Read 3991 times)previous topic - next topic

#### jano

##### Feb 14, 2011, 06:23 am
hi!

i want to have a couple of square oscillators (and some other stuff), but i have problems with the timing. this part of the code give me a square wave on pin 7 with variable frequency by connecting a potentiometer in analog0, but the 'resolution' of frequency is not enough, the max frequency is about 29khz  (i have no problem with this) but the step to the next is too big (15khz - 10khz - 7khz, etc, the idea is to control it trough midi+cv), i want something more smooth. because that i want to use the TIMER0_COMPA_vect (as i understood the timer go until the number in OCR0A and generates the interrupt when done) seems easy to change the resolution of the frequency counter, but it don't change the frequency out on pin 7 when i put other number in OCR0A, the output of the pin 6 can vary from 31250 to 8Mhz but the frequency on 7 remains unchanged. anyone have an idea about this? thanks in advance, and i sorry for my bad english  :~

Code: [Select]
`#include <avr/pgmspace.h>#include <avr/interrupt.h>#include <pins_arduino.h>#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))//para el generador de frecuenciaint freq_1=100;  // frecuencia osc 1float t_high_1=1;  // tiempo alto osc 1int t_low_1=1;   // tiempo bajo osc 1int pot=0;volatile byte icnt1;             // var inside interruptvolatile byte c4ms;              // counter boolean high_1=true;  // determinacion del tiempo actualboolean high_2=true;  // en los dos osciladoresconst int high_bit_7=B10000000;  //salida de oscilador 1 en pin 7 puerto Dconst int low_bit_7=B01111111;const int high_bit_4=B00010000;  //salida de oscilador 2 en pin 4 puerto Dconst int low_bit_4=B11101111;void setup() {  pinMode(5,OUTPUT);    // pin5=  PWM para correccion de la rampa 1 - timer 0 - OC0A  pinMode(6,OUTPUT);  pinMode(7,OUTPUT);    // pin7= salida de frecuencia oscilador 1 PORTD7 - timer 1  pinMode(4,OUTPUT);    // pin4= salida de frecuencia oscilador 2 PORTD4 - timer 1  cli();  Setup_timer0();  sbi (TIMSK0,OCIE0A);          //habilita la interrupcion del timer 0 en compare match con OCR0A  sbi (TIMSK0,OCIE0B);  sbi (TIMSK0,TOIE0);    sei();}void loop () {    if (c4ms > 10) {                      c4ms=0;     pot=analogRead(0)+20;      // lee el potenciometro conectado en 0     freq_1=pot/5;             }    t_low_1=freq_1/2;  }void Setup_timer0() {// Timer0 Clock Prescaler to : 1  sbi (TCCR0B, CS20);  cbi (TCCR0B, CS21);  cbi (TCCR0B, CS22);//modos de comparacion de los registros OCR    sbi (TCCR0A, COM0A0);  // toggle pin 6 en Compare Match con OCR0A  cbi (TCCR0A, COM0A1);  sbi (TCCR0A, COM0B0);  // toggle pin 4 en Compare Match con OCR0B  cbi (TCCR0A, COM0B1);    // Timer0 modo CTC  cbi (TCCR0A, WGM00);    sbi (TCCR0A, WGM01);  cbi (TCCR0A, WGM02);}ISR(TIMER0_COMPA_vect) {    OCR0A=145;    if (high_1==true){    PORTD = PORTD | high_bit_7;    t_high_1--;    if (t_high_1==0){     high_1=false;     t_high_1=t_low_1;    }  }  if (high_1==false){   PORTD = PORTD & low_bit_7;   t_high_1--;   if (t_high_1==0){     high_1=true;     t_high_1=t_low_1;   }  }      if (icnt1++ == 125) {  // increment variable c4ms     c4ms++;    icnt1=0;   } }ISR(TIMER0_OVF_vect) {   }`

#### LuthiersDrapaires

#1
##### Feb 14, 2011, 12:39 pm
Ey Jano!
aqui el santi....

i think the problem is with the analog read, which makes everything go slower... it happened to me once...
(it is better explained here: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1208715493/11)

try attaching this code at the top, it will make the reading faster:

Code: [Select]
` // defines for setting and clearing register bits#ifndef cbi#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))#endif#ifndef sbi#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))#endif// set prescale to 16sbi(ADCSRA,ADPS2) ;cbi(ADCSRA,ADPS1) ;cbi(ADCSRA,ADPS0) ;`

#### jano

#2
##### Feb 15, 2011, 01:22 am
oeee!! santi!

i just tried it, but it's the same, even if i disable the analog read and adjust the divisor 't_low_1' at the lowest 1 the output on pin 7 is 28khz, the next step 14khz, next 9.7khz, and in the out pin 6 (OCR0A) the frequency right now is 500khz (OCR0A=15), the question is: why the out in pin 7, if i use 1 as divisor of the count is not the half of OCR0A? or it don't works in that way?

Code: [Select]
`#include <avr/interrupt.h>#include <pins_arduino.h>#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))//para el generador de frecuenciaint freq_1=10;  // frecuencia osc 1float t_high_1=1;  // tiempo alto osc 1int t_low_1=20;   // tiempo bajo osc 1int pot=0;byte icnt1;             // var inside interruptbyte c4ms;              // counter long count=0;boolean high_1=true;  // determinacion del tiempo actualboolean high_2=true;  // en los dos osciladoresconst int high_bit_7=B10000000;  //salida de oscilador 1 en pin 7 puerto Dconst int low_bit_7=B01111111;const int high_bit_4=B00010000;  //salida de oscilador 2 en pin 4 puerto Dconst int low_bit_4=B11101111;void setup() {  pinMode(5,OUTPUT);    // pin5=  PWM para correccion de la rampa 1 - timer 0 - OC0A  pinMode(6,OUTPUT);  pinMode(7,OUTPUT);    // pin7= salida de frecuencia oscilador 1 PORTD7 - timer 1  pinMode(4,OUTPUT);    // pin4= salida de frecuencia oscilador 2 PORTD4 - timer 1  //Serial.begin(9600);  PORTD=high_bit_7;    cli();  // set prescale to 16  sbi(ADCSRA,ADPS2) ;  cbi(ADCSRA,ADPS1) ;  cbi(ADCSRA,ADPS0) ;  Setup_timer0();  sbi (TIMSK0,OCIE2A);          //habilita la interrupcion del timer 0 en compare match con OCR0A  sbi (TIMSK0,OCIE2B);  sbi (TIMSK0,TOIE2);    sei();}void loop () {    if (c4ms > 10) {                      c4ms=0;     t_low_1=(analogRead(0)+2)/2;                 }       }void Setup_timer0() {// Timer0 Clock Prescaler to : 1  sbi (TCCR0B, CS20);  cbi (TCCR0B, CS21);  cbi (TCCR0B, CS22);//modos de comparacion de los registros OCR    sbi (TCCR0A, COM0A0);  // toggle pin 6 en Compare Match con OCR0A  cbi (TCCR0A, COM0A1);  sbi (TCCR0A, COM0B0);  // toggle pin 4 en Compare Match con OCR0B  cbi (TCCR0A, COM0B1);    // Timer0 modo CTC  cbi (TCCR0A, WGM00);    sbi (TCCR0A, WGM01);  cbi (TCCR0A, WGM02);}ISR(TIMER0_COMPA_vect) {      if (t_high_1==0){    PORTD = ~PORTD;    t_high_1=t_low_1;    } t_high_1--;       if (icnt1++ == 125) {  // increment variable c4ms     c4ms++;    icnt1=0;   }     OCR0A=15;}ISR(TIMER0_OVF_vect) {   }`

#### Senso

#3
##### Feb 15, 2011, 04:44 am
Variables that are shared with a function/main and an ISR must be declared volatile, so for example your c4ms should be declares this way:
volatile byte c4ms;

And using the Atmega adc at 1Mhz seems a bit nonsense, because at that speed you may have something like 3-4 bits of usefull data, the rest is just noise.

#### jano

#4
##### Feb 15, 2011, 06:46 am
hi!

thanks Senso for let me know what for is the 'volatile', but this is not the problem, neither the a/d conversion, i can delete this part of the code and put the value of t_low_1 'by hand' and have the same result
the question is more like: should the timer work in that way? because as i understand the datasheet of atmel168 the timer should stop and generate the interrupt COMPA, and since the interrupt count up 1 (at the end of the pot, or manually writen) the frequency out of the pin 7 should be the half of the OCR0A (pin 6), but if i put i.e. 60 on OCR0A the pin 6 runs at 131khz and the pin 7 at 25khz, others values of OCR0A make the same, so what i missing?

#### jano

#5
##### Feb 16, 2011, 06:16 am
hi again!

not completely, but i have some approach to the solution: asm in the interrupt vector handling (yes that ugly thing), right now i can have up to 165khz on pin7, is not enough smooth as i want and the duty cycle is about 48% (i don't know why), but i need to remember more asm
the code is:

Code: [Select]
`#include <avr/interrupt.h>#include <pins_arduino.h>#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))//para el generador de frecuenciavolatile int freq_1=10;  // frecuencia osc 1volatile int t_high_1=1;  // tiempo alto osc 1volatile int t_low_1=9;   // tiempo bajo osc 1volatile int pot=0;volatile byte icnt1;             // var inside interruptvolatile byte c4ms;              // counter volatile long count=0;volatile boolean high_1=true;  // determinacion del tiempo actualvolatile boolean high_2=true;  // en los dos osciladoresvoid setup() {  pinMode(5,OUTPUT);    // pin5=  PWM para correccion de la rampa 1 - timer 0 - OC0A  pinMode(6,OUTPUT);  pinMode(7,OUTPUT);    // pin7= salida de frecuencia oscilador 1 PORTD7 - timer 1  pinMode(4,OUTPUT);    // pin4= salida de frecuencia oscilador 2 PORTD4 - timer 1  //Serial.begin(9600);     cli();  // set prescale to 16  sbi(ADCSRA,ADPS2) ;  cbi(ADCSRA,ADPS1) ;  cbi(ADCSRA,ADPS0) ;  Setup_timer0();  sbi (TIMSK0,OCIE2A);          //habilita la interrupcion del timer 0 en compare match con OCR0A  sbi (TIMSK0,OCIE2B);  sbi (TIMSK0,TOIE2);    sei();}void loop () {    if (c4ms > 10) {                      c4ms=0;     t_low_1=(analogRead(0)+1);                 }       }void Setup_timer0() {// Timer0 Clock Prescaler to : 1  sbi (TCCR0B, CS20);  cbi (TCCR0B, CS21);  cbi (TCCR0B, CS22);//modos de comparacion de los registros OCR    sbi (TCCR0A, COM0A0);  // toggle pin 6 en Compare Match con OCR0A  cbi (TCCR0A, COM0A1);  sbi (TCCR0A, COM0B0);  // toggle pin 4 en Compare Match con OCR0B  cbi (TCCR0A, COM0B1);    // Timer0 modo CTC  cbi (TCCR0A, WGM00);    sbi (TCCR0A, WGM01);  cbi (TCCR0A, WGM02);  }ISR(TIMER0_COMPA_vect) {  //asm("cli");    if (high_1==true){    asm("sbi 0x0B,7"); //pone el bit 7 del puerto D en alto    asm("dec %[retval]":[retval]"+r"(t_high_1));    if (t_high_1==0){     high_1=false;     t_high_1=t_low_1;    }  }  if (high_1==false){   asm("cbi 0x0B,7"); //pone el bit 7 del puerto D en bajo   asm("dec %[retval]":[retval]"+r"(t_high_1));   if (t_high_1==0){     high_1=true;     t_high_1=t_low_1;   }  }  /*    if (icnt1++ == 125) {  // increment variable c4ms     c4ms++;    icnt1=0;   }   */  // asm("ldi %0,0x01":"=r"(TCNT0));//  TCNT0=0x01;  OCR0A=10;//asm("sei");}ISR(TIMER0_OVF_vect) {   }`

#### jano

#6
##### Feb 18, 2011, 06:10 am
well, i start to write in asm the interrupt handling vector, but there is more than 15 years since i don't touch asm and i don't remember too much
i read the inline assembler cookbook, but i miss some...
here is the code:

Code: [Select]
`#include <avr/interrupt.h>#include <pins_arduino.h>#include <avr/io.h>#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))//para el generador de frecuenciavolatile int freq_1=10;  // frecuencia osc 1volatile int t_half_p=1;  // tiempo alto osc 1volatile char high_1=0xFF;  // determinacion del tiempo actual del oscilador (flag t_high, t_low)void setup() {  pinMode(5,OUTPUT);    // pin5=  PWM para correccion de la rampa 1 - timer 0 - OC0A  pinMode(6,OUTPUT);  pinMode(7,OUTPUT);    // pin7= salida de frecuencia oscilador 1 PORTD7 - timer 1  pinMode(4,OUTPUT);    // pin4= salida de frecuencia oscilador 2 PORTD4 - timer 1  //Serial.begin(9600);  cli();  Setup_timer0();  sbi (TIMSK0,OCIE2A);          //habilita la interrupcion del timer 0 en compare match con OCR0A  sbi (TIMSK0,OCIE2B);  sbi (TIMSK0,TOIE2);  sei();}void loop () {}void Setup_timer0() {  // Timer0 Clock Prescaler to : 1  sbi (TCCR0B, CS20);  cbi (TCCR0B, CS21);  cbi (TCCR0B, CS22);  //modos de comparacion de los registros OCR    sbi (TCCR0A, COM0A0);  // toggle pin 6 en Compare Match con OCR0A  cbi (TCCR0A, COM0A1);  sbi (TCCR0A, COM0B0);  // toggle pin 4 en Compare Match con OCR0B  cbi (TCCR0A, COM0B1);  // Timer0 modo CTC  cbi (TCCR0A, WGM00);    sbi (TCCR0A, WGM01);  cbi (TCCR0A, WGM02);}ISR(TIMER0_COMPA_vect) {  asm volatile("mov r7, %[thalf]"::[thalf]"r"(t_half_p):   //register7<--t_half               "mov r6, %[thigh]"::[thigh]"r"(high_1):     //register6<--high_1               "mov r5, r7"                                //r5=auxiliar register contains half period, redundant?               "HIGH: tst r6, #0xFF"                        //is high_1 up?  --the statement label HIGH is right?               "brne LOW"                                  //if not jump to LOW               "sbi 0x0B,7"                                // we are on high time, so pin7 portD<-1               "dec r7"                                    //decrement r7 (thalf)               "tst r7, #0x00"                             //is r24 ==0?   (half period finished?)                            "mov r6, #0x00"                             //if yes the low time start               "LOW: tst r6, #0x00"                         //is high_1 low? -- again the statemen label LOW is right?               "brne HIGH"                                 //if not jump to HIGH               "cbi 0x0B,7"                                // we are on low time, so pin7 portD<-0               "mov r7, r5"                                //load the half period again               "dec r7"                                    //again decrement7               "tst r7, #0x00"                             //until the half of period finishes                   );                                                      //should be done  /*   );   if (high_1){   asm("sbi 0x0B,7"); //pone el bit 7 del puerto D en alto   asm("dec %[retval]":[retval]"+r"(t_high_1));   if (!t_high_1){   high_1=false;   t_high_1=t_low_1;   }      }   if (!high_1){   asm("cbi 0x0B,7"); //pone el bit 7 del puerto D en bajo   asm("dec %[retval]":[retval]"+r"(t_high_1));   if (!t_high_1){   high_1=true;   t_high_1=t_low_1;   }   }      */  OCR0A=1;}ISR(TIMER0_OVF_vect) {}`

is supposed the asm par is a translation of the commented part after
but the compiler says:
timer_0_OCR0A_freq.cpp: In function 'void __vector_14()':
timer_0_OCR0A_freq:73: error: expected `)' before '::' token

so i delete some...

Code: [Select]
`#include <avr/interrupt.h>#include <pins_arduino.h>#include <avr/io.h>#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))//para el generador de frecuenciavolatile int freq_1=10;  // frecuencia osc 1volatile int t_half_p=1;  // tiempo alto osc 1volatile char high_1=0xFF;  // determinacion del tiempo actual del oscilador (flag t_high, t_low)void setup() {  pinMode(5,OUTPUT);    // pin5=  PWM para correccion de la rampa 1 - timer 0 - OC0A  pinMode(6,OUTPUT);  pinMode(7,OUTPUT);    // pin7= salida de frecuencia oscilador 1 PORTD7 - timer 1  pinMode(4,OUTPUT);    // pin4= salida de frecuencia oscilador 2 PORTD4 - timer 1  //Serial.begin(9600);  cli();  Setup_timer0();  sbi (TIMSK0,OCIE2A);          //habilita la interrupcion del timer 0 en compare match con OCR0A  sbi (TIMSK0,OCIE2B);  sbi (TIMSK0,TOIE2);  sei();}void loop () {}void Setup_timer0() {  // Timer0 Clock Prescaler to : 1  sbi (TCCR0B, CS20);  cbi (TCCR0B, CS21);  cbi (TCCR0B, CS22);  //modos de comparacion de los registros OCR    sbi (TCCR0A, COM0A0);  // toggle pin 6 en Compare Match con OCR0A  cbi (TCCR0A, COM0A1);  sbi (TCCR0A, COM0B0);  // toggle pin 4 en Compare Match con OCR0B  cbi (TCCR0A, COM0B1);  // Timer0 modo CTC  cbi (TCCR0A, WGM00);    sbi (TCCR0A, WGM01);  cbi (TCCR0A, WGM02);}ISR(TIMER0_COMPA_vect) {  asm volatile("mov r7, %[thalf]"::[thalf]"r"(t_half_p):);    //register7<--t_half  asm volatile("mov r6, %[thigh]"::[thigh]"r"(high_1):);      //register6<--high_1  asm volatile("mov r5, r7");                            //r5=auxiliar register contains half period, redundant?  asm volatile("HIGH: tst r6, #0xFF");                    //is high_1 up?  --the statement label HIGH is right?  asm volatile("brne LOW");                                  //if not jump to LOW  asm volatile("sbi 0x0B,7");                                // we are on high time, so pin7 portD<-1  asm volatile("dec r7");                                    //decrement r7 (thalf)  asm volatile("tst r7, #0x00");                             //is r24 ==0?   (half period finished?)               asm volatile("mov r6, #0x00");                             //if yes the low time start  asm volatile("LOW: tst r6, #0x00");                        //is high_1 low? -- again the statemen label LOW is right?  asm volatile("brne HIGH");                                 //if not jump to HIGH  asm volatile("cbi 0x0B,7");                                // we are on low time, so pin7 portD<-0  asm volatile("mov r7, r5");                                //load the half period again  asm volatile("dec r7");                                    //again decrement7  asm volatile("tst r7, #0x00");                         //until the half of period finishes                                                                           //should be done  /*   );   if (high_1){   asm("sbi 0x0B,7"); //pone el bit 7 del puerto D en alto   asm("dec %[retval]":[retval]"+r"(t_high_1));   if (!t_high_1){   high_1=false;   t_high_1=t_low_1;   }      }   if (!high_1){   asm("cbi 0x0B,7"); //pone el bit 7 del puerto D en bajo   asm("dec %[retval]":[retval]"+r"(t_high_1));   if (!t_high_1){   high_1=true;   t_high_1=t_low_1;   }   }      */  OCR0A=1;}ISR(TIMER0_OVF_vect) {}`

and when try to compile says:
/tmp/ccrQdvyh.s: Assembler messages:
/tmp/ccrQdvyh.s:226: Error: garbage at end of line
/tmp/ccrQdvyh.s:246: Error: garbage at end of line
/tmp/ccrQdvyh.s:251: Error: garbage at end of line
/tmp/ccrQdvyh.s:256: Error: garbage at end of line
/tmp/ccrQdvyh.s:281: Error: garbage at end of line

but the file /tmp/xxxxxxxxx.s is deleted immediately after the compiler print this text so i was unable to 'know' was happens on this files

some clues on it?

Go Up

Please enter a valid email to subscribe