10

I am trying to use Timer1 of Atmel AVR microcontroller, either AtMega328 as used in the Arduino, or the ATTiny85, to output two clock signals which are mirror images of each other. The frequency I am trying to generate is a variable 1 MHz to 2 MHz or more which are too high to do this using code to toggle the output pins unless I want to do almost nothing else in the controller. So I want to use the timer output directly on the associated pins. I am using GCC toolchain so not limited by arduino libraries or language.

Timer1 in the Atmega328 has two pins associated with it and I can get two identical 1MHz to 2MHz signals out of them. Though the datasheet seems to say I can get an inverted waveform, it is confusing me. I am also able to get two signals which are different duty cycles at 1 MHz, using the PWM settings with Timer1, but both signals go high at the same time, the shorter one goes low earlier. This does not serve my project. I do not even need the PWM pulse width variation, I just need two identical "clock" type signals of opposite phase, that's all.

I am not asking for anyone to write code for me to do this, I just need someone to tell me which mode / flags of the timer should give me a simple inverted waveform on one of the two pins associated with the timer. If possible I want to avoid using an external inverting circuit for one of the outputs unless that is only option.

If this is possible at all in the ATTiny, that will be even better. The ATTiny also has 2 pins associated with one timer, but I am not sure it has the same options as the ATMega.

I already have a 20 MHz crystal and capacitors connected on the PCB and 20 MHz clock is working reliably on the ATMega328. On ATTiny85 PCB I have a 8 MHz crystal and that is also working reliably.

Please help. Thank you.


UPDATE: There are some invalid assumptions in the answers and comments so far so maybe I should clarify: Note that in my original post I have stated that I am using a 20 MHz clock, not 8 MHz, and also that I do not need PWM.

The only mode that gives a high enough output frequency seems to be CTC mode because PWM modes are not working for 2 MHz output. Is there a way to invert either Timer 1 output A, or output B, in CTC mode?

I have now switched to a standard Arduino Uno (ATMega328, 16 MHz) instead of my own 20 MHz board to check my code, and this is my code for a nice steady 2 MHz clock in CTC mode from pins 9 and 10, the Timer 1 output pins:

#define tick 9
#define tock 10

void setup() {
  pinMode(tick, OUTPUT);  
  pinMode(tock, OUTPUT); 

  TCCR1A = _BV(COM1A0) | _BV(COM1B0) ;   // activate both output pins 
  TCCR1B = _BV(WGM12)| 1;                // set CTC mode, prescaler mode 1

  // various frustrating attempts to invert OC1B failed. What do I put here?

  OCR1A = 3;                             // set the counter max for 2 MHz

}

void loop() {
}

The oscilloscope traces for both pins are identical and in sync, how can I get either of the two signals inverted? The invert mode in the datasheet appears to do nothing in CTC mode. Am I reading the datasheet wrong, or will I be forced to use a lower frequency and PWM mode after all?

To add a specific "bounty" question to my original query:
So what changes do I need to make to my code above, to make it give perfectly inverted signals at pin 9 and 11 at the highest possible frequency for a 16 MHz clock, whether that is 2 MHz or not?

I will stick with a standard Arduino Uno for now, so that there is no error mode being introduced by my homespun board, and so that anyone with an arduino can try my code above and confirm that it works as I have mentioned and not as I need!

ExcitingProjects
  • 672
  • 7
  • 19
  • 1
    Looking at page 97-98 of the atmega8L [datasheet](http://www.atmel.com/images/doc2486.pdf), there is a table of the modes of operation. Page 108 states "The COM21:0 bits control whether the PWM out- put generated should be inverted or not (inverted or non-inverted PWM)". Keep us posted on your success! – Vorac Nov 26 '12 at 12:22
  • Why not use a simple transistor inverter for the mirrorred outputs? – Christoph B Dec 04 '12 at 21:03

2 Answers2

10

From the ATtiny85 Datasheet:

The mode of operation, i.e., the behavior of the Timer/Counter and the Output Compare pins, is defined by the combination of the Waveform Generation mode (WGM0[2:0]) and Compare Output mode (COM0x[1:0]) bits. The Compare Output mode bits do not affect the counting sequence, while the Waveform Generation mode bits do. The COM0x[1:0] bits control whether the PWM output generated should be inverted or not (inverted or non-inverted PWM).

Table 11-5 shows how to set the Mode.

Mode   WGM  WGM  WGM  Timer/Counter Mode    TOP      Update of    TOV Flag
c0     02   01   00   of Operation                   OCRx at      Set on
==========================================================================
0      0    0    0    Normal                0xFF     Immediate    MAX(1)
1      0    0    1    PWM, Phase Correct    0xFF     TOP          BOTTOM
2      0    1    0    CTC                   OCRA     Immediate    MAX
3      0    1    1    Fast PWM              0xFF     BOTTOM       MAX
4      1    0    0    Reserved              –        –            –
5      1    0    1    PWM, Phase Correct    OCRA     TOP          BOTTOM
6      1    1    0    Reserved              –        –            –
7      1    1    1    Fast PWM              OCRA     BOTTOM       TOP

You want a Fast PWM mode (so either mode 3 or mode 7). If you want to vary the duty cycle, and it sounds like you do, you want mode 7 and vary duty cycle by setting OCRA.

Table 11-3 shows how to set the compare output mode for Fast PWM mode.

COM0A1/   COM0A0/
COM0B1    COM0B0     Description
===============================================================================
0         0          Normal port operation, OC0A/OC0B disconnected.
0         1          Reserved
1         0          Clear OC0A/OC0B on Compare Match, set OC0A/OC0B at BOTTOM
                     (non-inverting mode)
1         1          Set OC0A/OC0B on Compare Match, clear OC0A/OC0B at BOTTOM
                     (inverting mode)

That is to say, you can set the OC0A output to go low when the Timer value == OCR0A and high when the Timer value == 0x00 by setting COM0A1:COM0A0 = 0b10. Or vise versa by setting COM0A1:COM0A0 = 0b11. And likewise for OC0B, OCR0B, COM0B0, COM0B1.

The PWM frequency is determined by the I/O Clock (8MHz it sounds like for you) and your timer prescaler setting. And the equation is given as f_clk_IO / (N * 256) for Fast PWM mode.

So you can use OC0A for "normal" polarity and OC0B for "inverted" polarity by setting OCR0A and OCR0B to the same value and setting COM0A1:COM0A0 = 0b10 and COM0B1:COM0B0 to 0b11.

UPDATE

Given you want to toggle the output as fast as possible and you are using the Mega328 operating at 16MHz, the CTC operating mode will allow you to obtain a switching frequency of:

f_OCnA = f_clk_IO / (2 * N * [1 + OCRnA) = 16e6 / (2 * 1 * [1 + 1]) = 4MHz

The Fast PWM mode will let you toggle the pin at:

f_OCnxPWM = f_clk_IO / (N * [1 + TOP]) = 16e6 / (1 * [1 + 1]) = 8MHz

So I still think you want Fast PWM mode. Specifically Mode 3 with OCR0A = OCR0B = 0x80 for 50% duty cycle. And set COM0A bits to 0x3 and COM0B bits to 0x2 to make the two waveforms on OC0A and OC0B inversions of one another.

Update #2 More the Mega328 Try this Arduino code:

#define tick 9
#define tock 10

void setup(){

  pinMode(tick, OUTPUT);  
  pinMode(tock, OUTPUT); 

  // Setup Waveform Generation Mode 15
  // OC1A Compare Output Mode = inverting mode
  // OC1B Compare Output Mode = non-inverting mode
  // Timer Prescaler = 1
  // TOP = OCR1A = 1

  //COM1A[1:0] = 0b11, COM1B[1:0] = 0b10, WGM1[1:0] = 0b11
  TCCR1A = _BV(COM1A1) | _BV(COM1A0) | _BV(COM1B1) | _BV(WGM11) | _BV(WGM10);

  //WGM1[3:2] = 0b11, CS1[2:0] = 0b001
  TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);

  OCR1A = 0x0001;
  OCR1B = 0x0001;
}

void loop(){

}
vicatcu
  • 22,499
  • 13
  • 79
  • 155
  • Let me chew on this a bit and see if it works. Thankyou. – ExcitingProjects Nov 26 '12 at 18:39
  • After re-reading your answer to try it out today, I see a couple of invalid assumptions: I specified 20 MHz clock (and now I have switched to 16 MHz), not *"(8MHz it sounds like for you)"*. Also I specified that I do not need PWM pulse width variation, so not sure where you surmised *"If you want to vary the duty cycle, and it sounds like you do"*. – ExcitingProjects Nov 29 '12 at 11:07
  • @ExcitingProjects I was keying off your statement "On ATTiny85 PCB I have a 8 MHz crystal and that is also working reliably." and my answer is in reference to the ATtiny85. I'll try and update my answre in response do your updated question. – vicatcu Nov 29 '12 at 19:50
  • @vicateu Thank you. I have updated the question, seeing as the invert mode seems to have no effect in CTC mode unless I am missing some step. – ExcitingProjects Nov 29 '12 at 20:29
  • @ExcitingProjects from the ATmega328 datasheet: "For non-PWM modes the COM0x1:0 bits control whether the output should be set, cleared, or toggled at a compare match" – vicatcu Nov 30 '12 at 17:22
  • @vicatcu Question: Have you tried this out? I just did, changing things to Timer1 as per OP's requirement, and it isn't working on my scope - both signals go high simultaneously no matter what. What might be wrong? – Anindo Ghosh Dec 04 '12 at 05:05
  • @AnindoGhosh no I haven't personally tried it, but I just posted some Arduino code to try that I'm pretty confident should work – vicatcu Dec 04 '12 at 16:52
  • @vicatcu Odd... It isn't working, and for the life of me I can't figure out what's up with it: Now the scope just has one pin high and the other low, not even the identical clocks we had earlier. Strange. – Anindo Ghosh Dec 04 '12 at 17:30
  • @AnindoGhosh try making OCR1A = OCR1B = 0x8000 for fun? – vicatcu Dec 04 '12 at 17:57
  • @vicatcu Same. One high, one low, no clock. – Anindo Ghosh Dec 04 '12 at 18:25
  • hm... why wouldn't it be ticking.... I'm puzzled – vicatcu Dec 04 '12 at 21:14
  • @vicatcu Sorry, not working. – ExcitingProjects Dec 05 '12 at 08:49
2

ATtinyX5 family has PLL inside, use it big boy.

I use internal PLL to power CPU clock too and have 16Mhz without XTAL. This is precious since you have just 5 pins. (I don't count reset pin). Also one PLL'ed PWM (OCR1B) runs at XTAL pins with it's optional complimentary output. You just need to adjust fuses for 16Mhz Xtalless ATtiny... Or just let CPU run in 8Mhz but run PWM with 64Mhz clock without changing fuses..

You can have up to 64 Mhz clock PWM (but 1 bit resolution). Or 125Khz @ 8 bit resolution. You can reduce PWM resolution & increase speed via decreasing OCR1C register.

For 1 Mhz you need to set OCR1C to 63. For 2 Mhz you need to set OCR1C to 31. For 4 Mhz you need to set OCR1C to 15. ...

Just enable PLL with this code:

PLLCSR |= (1 << PLLE);           //Start PLL
while( !(PLLCSR & (1<<PLOCK)) ); //Wait for PLL lock
//PLLCSR |= (1<<LSM );           //Low Speed PLL that clocks 32Mhz, not 64Mhz
PLLCSR |= (1 << PCKE);           //Enable PLL

Now you have 64 Mhz clock on "OCR1B0/OCR1A0" PWMs.

Also, you can adjust OCR1[A/B]0 & XOCR1[A/B]0 for mirrored output.

if(0){ //Synch mode
     //OCR1A & XOCR1A enable for Synch operation but not allow odd PWM values!
     TCCR1 |= (1 << PWM1A) | (0 << COM1A1) | (1 << COM1A0); 
     //Also ATtinyX5 has "Dead Time Generator", use it ;)
     DTPS1 = 3;   //8x Prescaler for dead time generator (maximum)
     DT1A = 0xff; //Clk dead on both channels (maximum)
     }
   else
     TCCR1 |= (1 << PWM1A) | (1 << COM1A1) | (0 << COM1A0);  //ONLY OCR1A enabled

You need to know, Dead Time Generator will eat PWM outout if you set OCR1A=1. You need higher values than dead time.

Regards,

Erdem

E.U.A.
  • 51
  • 2