Studio 6.2 Simulator CLKPR setting error

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

Hi All, Using 6.2 on a tiny13, I am using the watchdog timer to flash an LED. The timer0 is used to switch outputs between the red/green/blue LEDs for intermediate colours. On startup I slow the clock using CLKPR so I can show the individual RGB LEDs are working then change to a higher rate to mix the colours when needed. So I have two #defines, a function and two calls to it:

#define CLKDIV32 ((1 << CLKPS2) | (1 << CLKPS0))
#define CLKDIV8 ((1 << CLKPS1) | (1 << CLKPS0))
...
void set_CLKPR (unsigned char);
...
// in main code
set_CLKPR (CLKDIV32);
sei();
...
set_CLKPR(CLKDIV8);
sei();
...
// function
void set_CLKPR (unsigned char speed)
{
    cli();
    CLKPR = (1 << CLKPCE);
    CLKPR = speed;
}

In the simulator CLKPR does not display the set value. Examples:

speed      Sim

0001        0010

0010        0001

0011        0000

0100        0111

1000        1011

1100        1111

1110        1101

 

Looking at the processor stop watch the frequency is 1 MHz and the timer running at clk/1024 always takes .0262 seconds to overflow no matter which value of CLKPR is set, so sim CLKPR always clk/1.

By the way, really annoying to have to go into the Task Manager and kill atbackend.exe every time I run a simulation, otherwise the debugger always starts from where it left off or just gets stuck.

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

Take a look at the .lss file in the project's output folder.

This file lists the assembler code intermixed with the c statements.

This way you can verify that the four cycle rule is met for changing CLKPR.

 

BTW, if you are using Atmel Studio, which version and what is the optimization level?

 

 

Last Edited: Wed. Mar 1, 2017 - 08:27 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Which C compiler? If it's avr-gcc then one of the library headers already has an optimised asm() macro for setting CLKPR that guarantees the 4 cycle requirement.

 

EDIT: documentation in the manual here:

http://www.nongnu.org/avr-libc/u...

Last Edited: Wed. Mar 1, 2017 - 10:21 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avr-gcc -O1. I also tried -O3 and -Os. From the .lss file:

My C code gives:
OPS_Light.elf:     file format elf32-avr
...
00000124 <set_CLKPR>:
}


void set_CLKPR (unsigned char speed)
{
	cli();
 124:	f8 94       	cli
	CLKPR = (1 << CLKPCE);
 126:	90 e8       	ldi	r25, 0x80	; 128
 128:	96 bd       	out	0x26, r25	; 38
	CLKPR = speed;
 12a:	86 bd       	out	0x26, r24	; 38
 12c:	08 95       	ret

0000012e <main>:
int main(void)
{
...
	set_CLKPR (CLKDIV32);
 138:	85 e0       	ldi	r24, 0x05	; 5
 13a:	f4 df       	rcall	.-24     	; 0x124 <set_CLKPR>
	sei();
...

	set_CLKPR (CLKDIV8);
 19e:	83 e0       	ldi	r24, 0x03	; 3
 1a0:	c1 df       	rcall	.-126    	; 0x124 <set_CLKPR>

asm clock_prescale_set gives:

static __inline__ void clock_prescale_set(clock_div_t) __attribute__((__always_inline__));

void clock_prescale_set(clock_div_t __x)
{
    uint8_t __tmp = _BV(CLKPCE);
    __asm__ __volatile__ (
 12e:	95 e0       	ldi	r25, 0x05	; 5
 130:	80 e8       	ldi	r24, 0x80	; 128
 132:	0f b6       	in	r0, 0x3f	; 63
 134:	f8 94       	cli
 136:	86 bd       	out	0x26, r24	; 38
 138:	96 bd       	out	0x26, r25	; 38
 13a:	0f be       	out	0x3f, r0	; 63
	clock_prescale_set (clock_div_32);
...
	clock_prescale_set (clock_div_8);

I changed my set_CLKPR function to the asm macro and got the same result in the simulator:

speed     sim

0101     0110

0011     0000

The timer overflow still takes 0.262 seconds which means clk/1.

 

Mr. Clawson, how did you find the correct asm header file? I was looking through the header files but had no luck. Is there a search tool for this? Thanks.

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

Look in  <avr/power.h>.

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

In my EDIT: I already gave a link to:

 

http://www.nongnu.org/avr-libc/u...

 

At the top of the page it says:

 

 

Was the hint there that this was documenting <avr/power.h> too subtle?

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

Please could you attach a buildable project. 

 

Yes,  it would be nice if CLKPR altered the Simulator execution time calculations.   I don't think that it does.

 

But I am too idle to create a project for myself to check.   However,   I would  test your  project in AS7.

 

David.

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

Mr. Clawson, I think you misread my post. In the listing from the .lss file it clearly says:

static __inline__ void clock_prescale_set(clock_div_t) __attribute__((__always_inline__));

and then I posted:

"I changed my set_CLKPR function to the asm macro and got the same result in the simulator:"

Yes, I did find the assembly macro, inserted it into my code and tried again with the same results, the CLKPR does not change correctly and always runs at clk/1.

My question was how did you know where to look? Is there a macro listing somewhere? After looking through numerous header files (previous to my original post) and not finding anything I wrote the function in C as given in the datasheet. Thanks.

David - I will post the project a little later, it is on a non-networked machine.

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

Maybe you missed the point I was making. To use clock_prescale_set() you use <avr/power.h>. If you open that header file in your editor you find:

void clock_prescale_set(clock_div_t __x)
{
    uint8_t __tmp = _BV(CLKPCE);
    __asm__ __volatile__ (
        "in __tmp_reg__,__SREG__" "\n\t"
        "cli" "\n\t"
        "sts %1, %0" "\n\t"
        "sts %1, %2" "\n\t"
        "out __SREG__, __tmp_reg__"
        : /* no outputs */
        : "d" (__tmp),
          "M" (_SFR_MEM_ADDR(CLKPR)),
          "d" (__x)
        : "r0");
}

(or some variant of that). That code will be inserted at the point of invocation. As it is __asm__() it will simply be inserted "as is" into the opcodes of the .s file that is passed to the assembler.

 

So the "macro listing" is the macro definition in <avr/power.h> - hence my suggest to use and, if necessary, examine that file.

 

So if I use:

#include <avr/io.h>
#include <avr/power.h>

int main(void) {	
	clock_prescale_set(clock_div_64);
	while(1);
}

and compile it with:

C:\SysGCC\avr\bin>avr-gcc -mmcu=atmega328p -Os -save-temps avr.c -o avr.elf

C:\SysGCC\avr\bin>

then in the .s file I find...

        ldi r18,lo8(6)
        ldi r19,0
        ldi r24,lo8(-128)
/* #APP */
 ;  1454 "c:\sysgcc\avr\avr\include\avr\power.h" 1
        in __tmp_reg__,__SREG__
        cli
        sts 97, r24
        sts 97, r18
        out __SREG__, __tmp_reg__

and if I build with -g and the objdump with -S I get:

00000080 <main>:
from 1 to 129. Thus, one does not need to use \c clock_div_t type as argument.
*/
void clock_prescale_set(clock_div_t __x)
{
    uint8_t __tmp = _BV(CLKPCE);
    __asm__ __volatile__ (
  80:   26 e0           ldi     r18, 0x06       ; 6
  82:   30 e0           ldi     r19, 0x00       ; 0
  84:   80 e8           ldi     r24, 0x80       ; 128
  86:   0f b6           in      r0, 0x3f        ; 63
  88:   f8 94           cli
  8a:   80 93 61 00     sts     0x0061, r24
  8e:   20 93 61 00     sts     0x0061, r18
  92:   0f be           out     0x3f, r0        ; 63

which is just another view of the same thing.

 

The pointless loading of r19 with 0 suggests the code is sub-optimal in fact. I guess it's a consequence of the input __x being clock_div_t type which is presumably 16 bits wide. (it's a typedef'd enum in fact).

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

Yes, I did include <avr/power.h> in my new code per your original hint which is why it shows up in the .lss file. Still,

the question that I was asking is how did you know to look in <avr/power.h> for the macro? Is there a listing of all macros somewhere?

 

David - Attached is the project file and code. Tiny13, simulator, avr-GCC -O1

The watchdog asm macro is in-line only because I originally wrote the C version from the datasheet and was comparing the two in the simulator.

Attachment(s): 

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

magno_grail wrote:
Still, the question that I was asking is how did you know to look in for the macro? Is there a listing of all macros somewhere?
I just read the entire manual at:

http://www.nongnu.org/avr-libc/u...

 

from time to time when there is a new major release. (last major was 2.0.0 in fact). I just know all that is available at:

 

http://www.nongnu.org/avr-libc/u...

 

(not sure how else you would know how to use the compiler if you didn't keep abreast of the functionality it offers - which is generally documented in those location).

 

<avr/power.h> and what it offers is simply one of the many entries under "modules". If you haven't done so already I'd take at least a cursory look at what's offered in all the headers there. (though the K&R standard headers should not be TOO surprising apart from the inclusion of non-standard extras such as itoa() etc.

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

I just read the entire manual

WOW so not just a fast typer....wink

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

@magno_grail,

 

I built your project in AS7.   The Simulation works but there are some "features":

 

1.  The Frequency always says 8MHz.

2.  CLKPR is not displayed properly.

3.  Cycle counts are correct.   Time calculation is relative to Frequency.

 

e.g.  you set the Watchdog to 250ms.  And clock to F_CPU/8.   This is 262k cycles.   Calculated as 32ms.

 

Obviously the Watchdog is still firing at 250ms.   But with 1MHz clock Frequency,  only 262k cycles have elapsed.

 

If the Simulator was really clever,   it would display the effective Frequency and calculate the effective elapsed time.

Hey-ho.   I bet that more people would whinge at that.

 

The CLKPR display is a genuine display bug.   I guess that someone will fix it one day.    Meanwhile,  just live with it.

 

David.