Interruption each 1ms

Go To Last Post
16 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello, I'm trying to generate interruption each 1ms. To be able to use the function millis(), as in arduino.

 

 #include <avr/io.h>
    #include <stdlib.h>
    #include <avr/interrupt.h>

    #define CLOCK 8000000UL

    #define prescaler 1

    #if prescaler   == 1 // no prescaler
        #define pS 0x01

    #elif prescaler == 8 // CLOCK/8
        #define pS 0x02

    #elif prescaler == 64 // CLOCK/64
        #define pS 0x03

    #elif prescaler == 256 // CLOCK/256
        #define pS 0x04

    #elif prescaler == 1024 // CLOCK/1024
        #define pS 0x05
    #endif

    #define comparator ((0.001*CLOCK) / prescaler)
    #define debug 1

volatile long long millis=0;
ISR(TIMER0_COMPA_vect) //call interruption
{
	millis++;

}
int main(void)
{
	#if debug == 1
	#    warning "Debbug!!"
		DDRB = 0x20;
	#endif


    /* Configure the OCR0A. That is 1ms*CLOCK/Prescaler
	To get an interrupt each 1ms. To be able to use the millis function.*/
	OCR0A  = comparator;

	TCCR0A  = 0x00;
	TCNT0   = 0x00;

	TCCR0B |= pS; //Configure the clock source to prescaler
	/*When this bit is one and I-flag in the status register is set the Timer counter1
	output compare a match interrupt is enabled. 0x0016 program adress for interrupt.*/
	TIMSK0 |= 0x02;
    // TIFR0  |= 0x02;
    //TCCR0B |= 1<<WGM02;


	sei();
    while (1)
    {
       if(millis>15000){ //Closest I got from a second
           TCNT0  = 0x00;
           millis = 0;
           #if debug == 1
             PORTB ^= 0x20;
           #endif
       }
	}
}

 

 

 

AnonEngineer

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

Please post a specific question (or several).

If you have problems with your code not working, please tell us the symptoms - what you are actually observing.

Please tell us what AVR model you are using.

Please tell us what clock source you are using.

Please tell us how you've set the AVR fuses to utilize that clock source.

 

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry, the problem is on if(millis>15000). Millis is an variable to incremete each interruption, i want one interruption each 1ms, to be able use to function millis as in arduino. Therefore should be if(millis>1000) to have 1 seconds and not millis>15000.
I set it up the OCR0A to (0.001*CLOCK)/prescaler to know how many cycles i need to have 1ms. 

I'm using atmega 328 without external clock
I set it up bootloader to 8Mhz using arduino uno as isp, and burn the hex with avrdude and arduino uno board.
About fuses, i don't know.

 

 

AnonEngineer

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1
    #define CLOCK 8000000UL

    #define prescaler 1

...
    #define comparator ((0.001*CLOCK) / prescaler)

...
	OCR0A  = comparator;

AnonEngineer wrote:
I'm using atmega 328
So how do you expect 8000 to fit into an 8 bit register?

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So i'm using prescaler, i was waiting 64 as prescaler, to have 125, but not working

 

 

AnonEngineer

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

AnonEngineer wrote:
So i'm using prescaler, i was waiting 64 as prescaler, to have 125, but not working
Define "not working".

 

BTW: If you let the timer run in normal mode, then you always get the same interval no matter what OCR0A actually contains.

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If (millis> 1000). The led seems to flash in a range greater than 1 second.

 

 

AnonEngineer

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

AnonEngineer wrote:
If (millis> 1000). The led seems to flash in a range greater than 1 second.
Yes, with your code I would expect roughly 2 seconds (because of the "BTW").

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, I see double, why? what is it?

 

 

AnonEngineer

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

AnonEngineer wrote:

Yes, I see double, why? what is it?

Wrong timer mode. Use CTC.

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

Also no atomic protection when accessing the long long millis

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First off I recommend using fast pwm mode 7 along with the TIMER0_OVF_vect ISR instead because it'll simplify everything

 

OCRA will allow us to change the frequency but we need to calculate it

 

Thankfully we can get 1000Hz which will give 1ms interrupt timing

 

FCPU / (Prescaler * OCR0A) = 1000Hz

 

8MHz / 64 * 125 = 1000hz

 

OCR0A = 124 (because 125 will trigger the overflow interrupt)

 

so let's take a look at some code

 

volatile unsigned int millis; //long long = 64 bits, you'll be wasting a ton of time in the ISR, unsigned int will give you 65.536 seconds max

#define pS_64 0x03

ISR(TIMER0_OVF_vect) 
{
	millis++;

}

int main(void)
{
	
        millis  =  0;

        DDRB    =  0x20;

	TCNT0   =  0x00;

	OCR0A   =  124;
	TIMSK0  =  0x01; //turn on OVF interrupt

	TCCR0A  =  0x03; //configure timer0 to mode 7,
	TCCR0B  =  0x08 | pS_64; //configure timer0 to mode 7 + turn on the prescaler

    while (1)
    {
       cli();
       if(millis>=1000){ 
		
           millis = 0;
           PORTB ^= 0x20;         
       }
       sei();
    }
}

I tested the code on a simulation and it had an issue where 

 

if(millis>=1000)

 

would trigger when millis = 768

 

For some reason it works perfectly fine when using ==1000

using the cli and sei commands made >= work again

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

Cyclonus101 wrote:
I tested the code on a simulation and it had an issue where    if(millis>=1000)   would trigger when millis = 768   For some reason it works perfectly fine when using ==1000 using the cli and sei commands made >= work again

That's the effect of not protecting the access to the shared variable. It will also be horribly random.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 Well, Kartman hinted twice  you should have a look at http://www.atmel.com/webdoc/avrl... -millis is shared with IT; another variable should be a copy of millis -it is fast to copy : only this part of the main should not be interrupted...-

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was getting way lost, since I didn't read the OP in the >>Arduino forum<< closely enough:

AnonEngineer wrote:
Hello, I'm trying to generate interruption each 1ms. To be able to use the function millis(), as in arduino.

 

I guess I saw the millis() and assumed it was some manipulation of the built-in counter.

 

But a thread re-read after getting confused seems to indicate OP isn't living in the Arduino world at all?

 

In any case, a quick Google search for millis() source code uncovered

https://ucexperiment.wordpress.c... (and others).  A very good explanation/tutorial, IMO.  Even if OP doesn't want to lift the entire thing directly, it goes step-by-step through timer setup and correction for partial milliseconds ... and atomic access to the counter.

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Did you really mean to revive this thread?