Fast PWM mode - Timer 1 HW peripheral

Hello,

I am using Timer 1 in Fast PWM mode ---> i update the special function registers associated with the timer 1 HW peripheral for achieving the above PWM mode function.

But, i am unable to update the upper byte of OCR1A register...namely OCR1AH.

I not able to do this with C programming..

If anyone can provide me a piece of C code that will successfully update the FULL 16bit OCR1A register...

or

i can try a short assembly code snippet within the setup() function as well to update the OCR1A register, but - how do i invoke the assembler to compile the snippet within the bigger c code based setup() function?
will assembly code successfully update the OCR1A register..

Kindly help SOS...SOS...SOS

If you tried something, show us!

And you don't need assembly.

As I look at the datasheet doing
OCR1A = 0x01FF; should just work. But note that the operation isn't atomic aka, turn off interrupts while doing it.

Hi Septillion,

s i know it is atomic. but the compiler is expected to take care of this…

i have also disabled the interrupts.

Here is the code sequence i tried

/* Disable interrupts */
cli();//stop interrupts

unsigned short int temp = 400;

OCR1AH = (unsigned char)(temp >> 8);

OCR1AL = (unsigned char)temp;

unsigned short int readR = (unsigned short int)OCR1AL;

readR |= (((unsigned short int)(OCR1AH)) << 8);

//OCR1A = 384 ; this set of code i tried also doesnt workk

//OCR1AH |= (1 << TOIE1);
//OCR1AL = 0xfa ;

TCNT1 = 0;//initialize counter value to 0

ICR1 = 512 ;
TCCR1A = 0xA2 ;
TCCR1B = 0x19 ;

// enable timer compare interrupt

TIMSK1 |= (1 << TOIE1);

sei();//allow interrupts

You need to put your code inside tags. Failure to do so results in silly faces showing up in the posting, which don’t compile.

The compiler will NOT take care of atomic or not! The compiler knows nothing about the interrupts, only where to place the code for it in order for the micro to call it when there is an interrupt. That's why you need to make globals used in an interrupt volatile. Because as far as the compiler is concerned, interrupt functions are never called, they are outside the program flow the compiler sees. But even then, YOU have to take care of the atomic part :slight_smile:

Oops, sorry… i didnt know about tags… posting first time…

Here is the code now in tags…

cli();//stop interrupts

unsigned  short int temp = 400;

   OCR1AH = (unsigned char)(temp >> 8);

   OCR1AL = (unsigned char)temp;





   unsigned  short int readR = (unsigned  short int)OCR1AL;

   readR |= (((unsigned  short int)(OCR1AH)) << 8);



 //OCR1A = 384 ;   this set of code i tried also doesnt workk

 //OCR1AH |= (1 << TOIE1); 
 //OCR1AL = 0xfa ;


  

 TCNT1  = 0;//initialize counter value to 0






 ICR1 = 512 ;
 TCCR1A = 0xA2 ;
 TCCR1B = 0x19 ;




 // enable timer compare interrupt

    TIMSK1 |= (1 << TOIE1);   

 sei();//allow interrupts

bbenji74:
Hello,

I am using Timer 1 in Fast PWM mode ---> i update the special function registers associated with the timer 1 HW peripheral for achieving the above PWM mode function.

But, i am unable to update the upper byte of OCR1A register...namely OCR1AH.

I not able to do this with C programming..

If anyone can provide me a piece of C code that will successfully update the FULL 16bit OCR1A register...

Simple as

  noInterrupts() ;
  OCR1A = 0x5555 ;
  interrupts();

If outside an ISR. If no ISR is accessing any timer1 16 bit registers, there is no need for the
critical section at all.

Also to clear up the results of testing.

Septillion - The atomic write to OCR1A register has nothing to do with the ISR code - my ISR code never updates the special function registers..by the way

I am able to get the PWM on the pin . I also tested the OCR1A register with multiple values to change the pwm duty cycle...

what i discovered was the Lower byte OCR1AL values get updated and the PWM varies from 0 to 50 %

the OCR1AH value always remains zero and i cannot get PWM duty cycles above 50% to 100 %

so the problem is OCR1AH --- upper byte of OCR1A register never updates...

See section 15.3 of the datasheet (page 115):

15.3
Accessing 16-bit Registers
The TCNT1, OCR1A/B, and ICR1 are 16-bit registers that can be accessed by the AVR CPU via the 8-bit data bus. The 16-bit register must be byte accessed using two read or write operations. Each 16-bit timer has a single 8-bit register for temporary storing of the high byte of the 16-bit access. The same temporary register is shared between all 16-bit registers within each 16-bit timer. Accessing the low byte triggers the 16-bit read or write operation. When the low byte of a 16-bit register is written by the CPU, the high byte stored in the temporary register, and the low byte written are both copied into the 16-bit register in the same clock cycle. When the low byte of a 16-bit register is read by the CPU, the high byte of the 16-bit register is copied into the tempo- rary register in the same clock cycle as the low byte is read.

Not all 16-bit accesses uses the temporary register for the high byte. Reading the OCR1A/B 16- bit registers does not involve using the temporary register.

To do a 16-bit write, the high byte must be written before the low byte. For a 16-bit read, the low byte must be read before the high byte.

The following code examples show how to access the 16-bit Timer Registers assuming that no interrupts updates the temporary register. The same principle can be used directly for accessing the OCR1A/B and ICR1 Registers. Note that when using “C”, the compiler handles the 16-bit access.

bbenji74:
posting first time..

That is NOT an excuse... It IS a good reason to read How to use the forum though.... It also tells you we're not Snippets R Us.

And after some testing, OCR1A only acts 16-bit if TCCR1x set to a 16-bit mode. And guess what. that's the part not posted...

As for the atomic, your code may not, other code may. And you may in the future. Aka, it's safety first thing. Only wanted to make clear the compiler does NOT take that into account for you.

Thanks All for ur valuable suggestions. let us continue...the dialogue

Septillion, Scroll down thru the code. my code has lot of empty lines in between to keep the reading easy..

The TCCR1X register updates are performed and the value is there...of course in my first post the absence of code tags wud have obscured it... now with the code tags it is there...

do any of u have tried timer 1 in 16 bit mode and the fast PWM works...for above 50% duty cycle.

does it work under that condition? i mean the OCR1A register gets updated with full 16 bit value? if so pls share that code...

if not, can any of u kindly use my piece of code on ur Arduino kits that have the Atmega328p Controller and check if the code works in the Fast PWM mode, i mean even with the simple OCR1A = value; statement

the registers settings in my code shud get the PWM out on the D9 pin of the micro. comment out the TIMSK1 register code line as the ISR is not needed for the pure PWM testing...

u will surely get upto 50% PWM , but if OCR1A is fully updated then u shud be able to obtain above 50% duty cycle as well....

all - in my code, u can also find the commented out code that does the simple OCR1A = decimal value statement.

i also tried that and it still doesnt work. (some of u suggested that).

strange thing the lower byte gets updated but not the upper.

John wasser- i have read the datasheet note...as well and the caution. But what is that piece of code that will work for updating the OCR1A register?

bbenji74:
Septillion, Scroll down thru the code. my code has lot of empty lines in between to keep the reading easy..

You mean to absolutely mess up ANY readability... You're a person who starts every sentence on a new page, arn't you? :wink: Or better, leave blank pages in between...

Because of that an the messed up indentation I indeed missed it.

BUT, I have you the answer :wink: The timer has to be set up for >8-bit BEFORE you can access OCR1A as 16-bit :wink: Now you try the other way around...

Super Good Septillion, let me try that soon....

Thanks again...i think this must be problem in my code...

Or better, leave blank pages in between...

With the comment "This page intentionally left blank".

Just for reference...

The code reference from the datasheet for the ATmega328/P - Atmel 42735 8 bit AVR Microcontroller
Page 152:
"

16-bit Access
The following code examples show how to access the 16-bit Timer Registers assuming that no interrupts
updates the temporary register. The same principle can be used directly for accessing the OCR1A/B and
ICR1 Registers. Note that when using C, the compiler handles the 16-bit access.
Assembly Code Example
(1)

   ...
; Set TCNT1 to 0x01FF
ldi    r17,0x01
ldi    r16,0xFF
out    TCNT1H,r17
out    TCNT1L,r16
; Read TCNT1 into r17:r16
in    r16,TCNT1L
in    r17,TCNT1H
   ...

The assembly code example returns the TCNT1 value in the r17:r16 register pair.

C Code Example
(1)

unsigned int i;
   ...
/* Set TCNT1 to 0x01FF */
TCNT1 = 0x1FF;
/* Read TCNT1 into i */
i = TCNT1;
   ...

Note:

  1. The example code assumes that the part specific header file is included. For I/O Registers located
    in extended I/O map, “IN”, “OUT”, “SBIS”, “SBIC”, “CBI”, and “SBI” instructions must be replaced
    with instructions that allow access to extended I/O. Typically “LDS” and “STS” combined with
    “SBRS”, “SBRC”, “SBR”, and “CBR”.
    Atomic Read
    It is important to notice that accessing 16-bit registers are atomic operations. If an interrupt occurs
    between the two instructions accessing the 16-bit register, and the interrupt code updates the temporary
    register by accessing the same or any other of the 16-bit Timer Registers, then the result of the access
    outside the interrupt will be corrupted. Therefore, when both the main code and the interrupt code update
    the temporary register, the main code must disable the interrupts during the 16-bit access.
    The following code examples show how to perform an atomic read of the TCNT1 Register contents. The
    OCR1A/B or ICR1 Registers can be ready by using the same principle.
    "

@darrob echo echo echo echo.....

septillion:
@darrob echo echo echo echo.....

Yeah I know, but I heard this heartfelt cry

bbenji74:
John wasser- i have read the datasheet note...as well and the caution. But what is that piece of code that will work for updating the OCR1A register?

and I had to provide :wink:

Small example to show what I mean:

void setup() {
  Serial.begin(115200);
  Serial.println("OCR1A test");

  Serial.println("8-bit mode");
  OCR1A = 384;
  printOCR1A();

  //change to 16-bit fast PWM  
  TCCR1A = (1 << WGM10) | (1 << WGM11); 
  TCCR1B = (1 << WGM12) | (1 << WGM13)| (1 << CS10);

  Serial.println("16-bit mode");
  OCR1A = 384;
  printOCR1A();
  Serial.println();
}

void loop() {
  // put your main code here, to run repeatedly:

}
void printOCR1A(){
  Serial.print("OCR1A\t");
  Serial.println(OCR1A);
  Serial.print("OCR1AH\t");
  Serial.println(OCR1AH);
  Serial.print("OCR1AL\t");
  Serial.println(OCR1AL);
  Serial.println();
}

Output:

OCR1A test
8-bit mode
OCR1A 128
OCR1AH 0
OCR1AL 128

16-bit mode
OCR1A 384
OCR1AH 1
OCR1AL 128

All, thanks for the piece of codes posted.

as per Septillion hint,

I just moved the OCR1A register update code in my piece of code, as the last update of the timer 1 special function registers, before the enable interrupt command and Bingo it worked....

Thanks again...Septillion!! and the others too.