output OCR1A&OCR1B in atmega16a

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

Can use of ocr1a &ocr1b at the same time?
When I use both at the same time, output frequencies are equal. For example I want to produce 1khz on ocr1a and 2khz on ocr1b, but both are 1khz.
Mode is ctc and toggle output on compare match.

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

mostafa147 wrote:
Can use of ocr1a &ocr1b at the same time?

Yes.

mostafa147 wrote:
When I use both at the same time, output frequencies are equal. For example I want to produce 1khz on ocr1a and 2khz on ocr1b, but both are 1khz.

Yes, both OCR1A and OCR1B are using the same frequency. That is how the hardware is designed. You can not have different frequencies for OCR1A and OCR1B.

"He used to carry his guitar in a gunny sack, or sit beneath the tree by the railroad track. Oh the engineers would see him sitting in the shade, Strumming with the rhythm that the drivers made. People passing by, they would stop and say, "Oh, my, what that little country boy could play!" [Chuck Berry]

 

"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

I can not see how you can get both frequencies without software intervention.
But 1kHz is pretty slow. So your 2kHz CTC can have a COMPA interrupt which sets different COM1Bxx bits for the 1kHz output.
.
Ah-ha. I am not at a PC. If toggle on OCR1B match works in CTC mode, you simply set OCR1B to OCR1A/2. Both sets of COM1xxx for toggle. I will try it.
.
David.

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

Well,  I tried toggle on both COM1yxx bits.   Of course COMPB only occurs at the same frequency as COMPA.   You simply alter the phase relationship.

So I tried the original idea:

ISR(TIMER1_COMPA_vect)
{
    static uint8_t ctr;
    if (++ctr >= 2) {
        ctr = 0;
        TCCR1A ^= (1 << COM1B0);            //alternate between Cler / Set
    }
}

void setup()
{
    DDRB |= (1 << DDB2) | (1 << DDB1);      //OC1A, OC1B output (mega328)
    TCCR1A = (1 << COM1A0) | (1 << COM1B1); //CTC, toggle OC1A, clear OC1B
    TCCR1B = (1 << WGM12) | (3 << CS10);    //CTC, div64
    TIMSK1 = (1 << OCIE1A);                 //COMPA interrupt
    OCR1A = (F_CPU / 64) / 2 / 2000 - 1;    //2 toggles) 2kHz on OC1A
    OCR1B = OCR1A;
    sei();                                  //already enabled on Uno
}

void loop()
{
}

I tested on an Arduino Uno.   The OC1x pins are different.  The TIMSK1 register is different.

Otherwise,  this should work on any 16-bit Timer1 or even an 8-bit Timer with suitable prescaler div.

 

You can alter the phase by setting OCR1B between 0 .. OCR1A.

 

David.

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

If the frequencies are fairly modest, then the "leapfrog" approach works OK.  [do we know whether the signals need to be in-phase?]

http://www.avrfreaks.net/comment...

 

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

That is effectively what my approach does.   You always end up with an ISR() every 1/2 cycle of the 2kHz.   i.e. every 250us.

 

In an ideal world,  you could set the hardware without any ISR()s.

 

Personally,  I would do 2kHz with Timer2 CTC and 1kHz with Timer0 CTC.

Or most practical apps would have a regular clock anyway.    So you could attach one of the signals to that Timer.

After all,  regular Megas have got 3 Timers.   Newer chips might have more Timers.

 

David.

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

Thanks for your guidance. I will test and reply you.

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

david.prentice wrote:
You always end up with an ISR() every 1/2 cycle of the 2kHz. i.e. every 250us.

 

Hmm--use Fast PWM, with OCR1A as TOP (mode 15, right?) to get a 500us period.  Set OCR1B to 1/2 of OCR1A, inverting or non-inverting PWM.

 

Now enable either the overflow or compare match on the A channel interrupt.  In the ISR, do a simple toggle of the desired output pin, OC1A or other.

 

You now have a [near --'16A doesn't have "write to PIN to toggle" feature] trivial ISR and ISR every 500us -- not too onerous.  Other interrupt sources enabled might give jitter on the A channel but should recover if serviced in the next 500us.

 

 

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.

Last Edited: Fri. Aug 18, 2017 - 08:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would assume that non-jitter outputs would be essential.   Hence using COM1yxx bits.  

Yes,  interrupt latency should not be a problem.    The next Match is a a long way off.

 

Leapfrog would work fine.   I have shown that COM1B0 toggling works fine too.

Toggling an output pin in an ISR() will always have latency.

 

I bet someone will come up with a fully hardware non-interrupt solution.

 

David.

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

Remember if you are using an interrupt, the interrupt gets thrown on the next cycle after the match, so if you want the interrupt to happen after 100 cycles you have to set OCRnA = 99.  This is discussed in the Output Compare Unit section of the data sheet under the timer you are interested in.  This probably doesn't happen on toggle.  I'm not sure.  You can set OCRnA to a small number like 3 or 4 to test, and see the frequency you get on a scope.  For large values of OCRnA it is hard to tell the difference of 1 in the time between interrupts.

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

For example I want to produce 1khz on ocr1a and 2khz on ....

Perhaps OP just picked those for the purpose of the question....if the freqs are non-integer multiples (say 1234 Hz& 7433 Hz) , more complicated--use two timers is easiest (but how fun is that) 

Atmel should consider an avr with a small dds core (with all respect to Jesper).  I suppose you could just wire one up to spi,  (but how fun is that).

When in the dark remember-the future looks brighter than ever.

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

I used two timer(0,1) in ctc mode.but out put of ocr0 is correct and output of ocr1 is just 1Hz!
Frequency for timer0 selected 1200Hz and for timer1 selected 2300Hz.
I think, can't use two timer in ctc mode at same time. Is this correct?

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

The two timers are independent. I'd suggest something is wrong with your code.

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

Yes,  you can use all 3 Timers in CTC mode at the same time.

 

Just remember that Timer0 and Timer2 are only 8-bit.   So when you calculate

OCRnA = F_CPU / PRESCALERn / 2 / freq - 1;  //must be 0-255 for 8-bit timers
//OCRnA = 16000000 / 1 / 2 / 2300 - 1;  // = 3478.26 - 1 = 3477
//OCRnA = 16000000 / 8 / 2 / 2300 - 1;  // = 434.78 - 1 = 433
//OCRnA = 16000000 / 64 / 2 / 2300 - 1;  // = 54.35 - 1 = 53
//OCRnA = 16000000 / 256 / 2 / 2300 - 1;  // = 13.59 - 1 = 12
//OCRnA = 16000000 / 1024 / 2 / 2300 - 1;  // = 3.40 - 1 = 2

Clearly only div64 will work in an 8-bit Timer.   div256 and div1024 will work but give large errors.

Even with a 16-bit Timer1 and div1,  you will not get a perfect 2300Hz.

 

Only you know what frequencies you actually want.   Only you know whether jitter is important.   For example you can obtain a long term average frequency by changing an occasional cycle period like you add leap seconds on a clock.

 

David.

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

mostafa147 wrote:
Frequency for timer0 selected 1200Hz and for timer1 selected 2300Hz.

And here I was thinking of clever ways to get 1x and 2x frequencies out of the same timer!

 

mostafa147 wrote:
I think, can't use two timer in ctc mode at same time. Is this correct?
Kartman wrote:
The two timers are independent. I'd suggest something is wrong with your code.

+1.  Let's see the code, and the test results.

 

Post a complete test program that demonstrates the symptoms.  Tell AVR model, and clock speed.  Tell language, toolchain, version, and optimization settings.

 

Tell what you expect to happen, and tell what >>is<< happening.

 

[I should make that my signature.  I've typed it enough times.]

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

And here I was thinking of clever ways to get 1x and 2x frequencies out of the same timer!

I was wondering if he used a "bad example" which would mislead us into non-applicable simplifications.  Often, things get mis-stated...I was told to provide a high freq range, say 41200 to 48000 Hz ,adjustable within 2%...no problem.  Then it turned out it was really supposed to be adjustable within 2Hz steps (not 2%), a completely different undertaking* (more like a DDS).

 

*to resolve 2Hz at 41200Hz with just a timer clock/divider requires a clock of approx 810 MHz

When in the dark remember-the future looks brighter than ever.

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

According to your description, I want to make changes to the my program. I want to apply 54600Hz pulse to T1 pin of ATmega8A and use counter1 mode. then produce 1300Hz and 2100Hz pulses.that is 54600/42=1300Hz and 54600/21=2100Hz.How I can this two pulses produce on two separate pins?

 

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

This code simultaneously produces 1300Hz on pin OC1A and 2100Hz on pin OC1B with the chip running on a 16MHz crystal. You do not need external signals.

 

#include <io.h>

#define OCR1A_reload (16000000/1300/2)
#define OCR1B_reload (16000000/2100/2)

// Timer1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
    static unsigned int reload_value;

	reload_value = reload_value + OCR1A_reload;
    OCR1AH = reload_value >> 8;
    OCR1AL = reload_value & 0x00ff;
}

// Timer1 output compare B interrupt service routine
interrupt [TIM1_COMPB] void timer1_compb_isr(void)
{
    static unsigned int reload_value;

	reload_value = reload_value + OCR1B_reload;
    OCR1BH = reload_value >> 8;
    OCR1BL = reload_value & 0x00ff;

}

void main(void)
{
    // Crystal Oscillator division factor: 1
    #pragma optsize-
    CLKPR=(1<<CLKPCE);
    CLKPR=(0<<CLKPCE) | (0<<CLKPS3) | (0<<CLKPS2) | (0<<CLKPS1) | (0<<CLKPS0);
    #ifdef _OPTIMIZE_SIZE_
    #pragma optsize+
    #endif


    // Port D initialization
    // Function: Bit7=In Bit6=In Bit5=Out Bit4=Out Bit3=In Bit2=In Bit1=In Bit0=In
    DDRD=(0<<DDD7) | (0<<DDD6) | (1<<DDD5) | (1<<DDD4) | (0<<DDD3) | (0<<DDD2) | (0<<DDD1) | (0<<DDD0);
    // State: Bit7=T Bit6=T Bit5=0 Bit4=0 Bit3=T Bit2=T Bit1=T Bit0=T
    PORTD=(0<<PORTD7) | (0<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (0<<PORTD1) | (0<<PORTD0);

    // Timer/Counter 1 initialization
    // Clock source: System Clock
    // Clock value: 16000.000 kHz
    // Mode: Normal top=0xFFFF
    // OC1A output: Toggle on compare match
    // OC1B output: Toggle on compare match
    // Noise Canceler: Off
    // Input Capture on Falling Edge
    // Timer Period: 4.096 ms
    // Output Pulse(s):
    // OC1A Period: 8.192 ms Width: 4.096 ms
    // OC1B Period: 8.192 ms Width: 4.096 ms
    // Timer1 Overflow Interrupt: Off
    // Input Capture Interrupt: Off
    // Compare A Match Interrupt: On
    // Compare B Match Interrupt: On
    TCCR1A=(0<<COM1A1) | (1<<COM1A0) | (0<<COM1B1) | (1<<COM1B0) | (0<<WGM11) | (0<<WGM10);
    TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (1<<CS10);
    TCNT1H=0x00;
    TCNT1L=0x00;
    ICR1H=0x00;
    ICR1L=0x00;
    OCR1AH=0x00;
    OCR1AL=0x00;
    OCR1BH=0x00;
    OCR1BL=0x00;


    // Timer/Counter 1 Interrupt(s) initialization
    TIMSK1=(0<<ICIE1) | (1<<OCIE1B) | (1<<OCIE1A) | (0<<TOIE1);

    // Globally enable interrupts
    #asm("sei")

	while (1)
	{
		;
	}
}

 

 

 

 

***NOTE 1 - the actual frequencies produced, assuming a totally accurate 16MHz crystal, are 1300.18Hz and 2100.29Hz. Close enough for jazz.

 

***NOTE 2 - this was written for Codevision running on a 1284P. You'll need to make appropriate changes to suit your toolchain and chip used.

'This forum helps those who help themselves.'

 

pragmatic  adjective dealing with things sensibly and realistically in a way that is based on practical rather than theoretical consideration.

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

mostafa147 wrote:
According to your description, I want to make changes to the my program. I want to apply 54600Hz pulse to T1 pin of ATmega8A and use counter1 mode. then produce 1300Hz and 2100Hz pulses.that is 54600/42=1300Hz and 54600/21=2100Hz.How I can this two pulses produce on two separate pins?

This would be a lot more fun if I know what the purpose of this game is.

 

50kHz is ~20us per count.  Fast, but not out of possibility if that is all the AVR is doing.

 

Why a Mega16, and not the more feature-rich M4ega164 family, that also has a higher max clock rate?

 

Speaking of which, have you ever told us what speed your AVR is running at?

 

If this functionality is so important, then why not just use discrete logic to divide down your master frequency?

 

mostafa147 wrote:
54600/42=1300Hz

1300 times 42 is indeed 56400.  But with 56400 "clock" and a desired output frequency of 1300Hz with 50% duty cycle, then you need to divide by 84 and generate the half-on/half-off.

 

mostafa147 wrote:
54600/21=2100Hz.

 

Now, that one is more interesting...  2100 times 21 is not 54600.  And the divisor isn't even -- 26.857...  and again you'd need half that.

 

 

 

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

theusch wrote:

This would be a lot more fun if I know what the purpose of this game is.

 

I'm guessing that it's related to the OP's other recent post...

 

http://www.avrfreaks.net/forum/o...

 

There, the OP said...

Quote:

I want to create a train pulse of 1300&2100Hz square wave with duration 12.5Hz.I made 1300&2100 with division 54600Hz by 42&26 scale.train pulse fed to q1 and 12.5Hz fed to q2 for switching in other section.now I need a suitable voltage buffer for output FETs.

 

...to which I replied...

 

Quote:

You could do all of that inside one 328.

 

'This forum helps those who help themselves.'

 

pragmatic  adjective dealing with things sensibly and realistically in a way that is based on practical rather than theoretical consideration.

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

theusch wrote:
1300 times 42 is indeed 56400. But with 56400
I believe you swapped some digits there, should be 54600.

 

54600/2100 = 26 (for half cycle would be 13) -> (54600/13)/2 = (4200)/2 = 2100

54600/1300 = 42 (for half cycle would be 21) -> (54600/21)/2 = (2600)/2 = 1300

 

David (aka frog_jr)

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

Brian Fairchild wrote:
I'm guessing that it's related to the OP's other recent post...

But the "why" or "what for"?

 

HART protocol e.g. uses (IIRC) an old modem signalling system, with numbers that I first thought were OP's -- but not:

Process measurement and control devices can communicate via the conventional 4- to 20-mA current loop by utilizing the highway addressable remote transducer (HART) protocol. This protocol uses frequency-shift keying (FSK) with the frequencies of 1200 Hz and 2200 Hz.

frog_jr wrote:
I believe you swapped some digits there, should be 54600.

So there is a Dog, after all. ;)

 

If there is indeed a common denominator, then OP would let timer1 free-run clocked from T1 and use the leap-frog method on compare A and B channels, letting the CPU toggle the pin.  That would give a few hundred microseconds to "catch up" each time; should be enough unless the AVR is heavily loaded.

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

If the OP's requirements is 40ms of 1300Hz and 40ms of 2100Hz, it's really quite easy to do it using one 16-bit timer, with glitch-free switching between frequencies...

 

'This forum helps those who help themselves.'

 

pragmatic  adjective dealing with things sensibly and realistically in a way that is based on practical rather than theoretical consideration.

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

I access to mega8 and 16 only in my region and could not do all of that inside one micro for this reason I used several mega for frequency division.(54600-->1300&2100, These frequencies must be make from 54600 hz).
 

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

mostafa147 wrote:

I access to mega8 and 16 only in my region and could not do all of that inside one micro for this reason I used several mega for frequency division.(54600-->1300&2100, These frequencies must be make from 54600 hz).

 

Timer 1 in a mega8 is a 16-bit timer and has two compare channels. It will do what I did above.

 

Why do you have to use 54600Hz?

'This forum helps those who help themselves.'

 

pragmatic  adjective dealing with things sensibly and realistically in a way that is based on practical rather than theoretical consideration.

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

theusch wrote:
But the "why" or "what for"?

https://en.wikipedia.org/wiki/IT...

V.23 Mode 2 AFSK uses a 1300 Hz tone (FZ) for mark (typically a binary 1) and 2100 Hz (FA) for space (typically a binary 0), and a 1700 Hz center frequency (F0.)

We haven't heard about the "center frequency" yet.

 

This would have been a lot easier if the problem statement explained the requirement for one frequency and then the other.

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.