Interrupts and time handling problems.

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 :~

#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 frecuencia
int freq_1=100;  // frecuencia osc 1
float t_high_1=1;  // tiempo alto osc 1
int t_low_1=1;   // tiempo bajo osc 1
int pot=0;
volatile byte icnt1;             // var inside interrupt
volatile byte c4ms;              // counter 


boolean high_1=true;  // determinacion del tiempo actual
boolean high_2=true;  // en los dos osciladores
const int high_bit_7=B10000000;  //salida de oscilador 1 en pin 7 puerto D
const int low_bit_7=B01111111;
const int high_bit_4=B00010000;  //salida de oscilador 2 en pin 4 puerto D
const 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) {
 
  
}

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:

 // 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 16
sbi(ADCSRA,ADPS2) ;
cbi(ADCSRA,ADPS1) ;
cbi(ADCSRA,ADPS0) ;

oeee!! santi! :smiley:

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?

#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 frecuencia
int freq_1=10;  // frecuencia osc 1
float t_high_1=1;  // tiempo alto osc 1
int t_low_1=20;   // tiempo bajo osc 1
int pot=0;
byte icnt1;             // var inside interrupt
byte c4ms;              // counter 
long count=0;

boolean high_1=true;  // determinacion del tiempo actual
boolean high_2=true;  // en los dos osciladores
const int high_bit_7=B10000000;  //salida de oscilador 1 en pin 7 puerto D
const int low_bit_7=B01111111;
const int high_bit_4=B00010000;  //salida de oscilador 2 en pin 4 puerto D
const 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) {

 
  
}

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.

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?

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 :slight_smile:
the code is:

#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 frecuencia
volatile int freq_1=10;  // frecuencia osc 1
volatile int t_high_1=1;  // tiempo alto osc 1
volatile int t_low_1=9;   // tiempo bajo osc 1
volatile int pot=0;
volatile byte icnt1;             // var inside interrupt
volatile byte c4ms;              // counter 
volatile long count=0;

volatile boolean high_1=true;  // determinacion del tiempo actual
volatile boolean high_2=true;  // en los dos osciladores


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();

  // 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) {

 
  
}

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 :frowning:
i read the inline assembler cookbook, but i miss some...
here is the code:

#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 frecuencia
volatile int freq_1=10;  // frecuencia osc 1
volatile int t_half_p=1;  // tiempo alto osc 1


volatile 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...

#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 frecuencia
volatile int freq_1=10;  // frecuencia osc 1
volatile int t_half_p=1;  // tiempo alto osc 1


volatile 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: bad expression
/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?