Timer problems, ATtiny85

418 views
Skip to first unread message

Nick Andrew

unread,
Dec 2, 2010, 8:16:18 PM12/2/10
to simavr
I've just started using simavr and it's very impressive, particularly
the VCD debugging with gtkwave.

A little documentation would be very useful to get new users started.
Even this would have helped me:

- To use simavr, write a C program which functions as a harness
around the MCU + your firmware, and implements any "devices" (such as
buttons, LEDs, sensors or other circuitry) attached to your "chip"
- See the boards in examples/ as a starting point
- You debug by writing a trace file of signal or variable changes
(and how to do it)

Anyway, on to my problem. I'm using an ATtiny85 and timer0 in FastPWM
mode to generate a waveform with a 50% duty cycle. The first half of
the waveform should be logic low, then it should switch to logic high
as a result of a match in comparison to OCR0A.

What I'm seeing is:

- The counter TCNT0 doesn't count by itself. VCD trace shows no
change in that value. If I add a line into the firmware to read it, it
then counts up and shows on the VCD trace.

- The output bit PORTB1 is always low.

I'm tracing it like this:

<pre>
const struct avr_mmcu_vcd_trace_t _mytrace[] _MMCU_ = {
{ AVR_MCU_VCD_SYMBOL("OCR0A"), .what = (void*)&OCR0A, },
{ AVR_MCU_VCD_SYMBOL("OCR0B"), .what = (void*)&OCR0B, },
{ AVR_MCU_VCD_SYMBOL("TCNT0"), .what = (void*)&TCNT0, },
{ AVR_MCU_VCD_SYMBOL("PB0"), .mask = (1 << PORTB0), .what =
(void*)&PORTB, },
{ AVR_MCU_VCD_SYMBOL("PB1"), .mask = (1 << PORTB1), .what =
(void*)&PORTB, },
{ AVR_MCU_VCD_SYMBOL("PB2"), .mask = (1 << PORTB2), .what =
(void*)&PORTB, },
{ AVR_MCU_VCD_SYMBOL("PB3"), .mask = (1 << PORTB3), .what =
(void*)&PORTB, },
{ AVR_MCU_VCD_SYMBOL("PB4"), .mask = (1 << PORTB4), .what =
(void*)&PORTB, },
{ AVR_MCU_VCD_SYMBOL("cycles"), .what =
(void*)&cycle_debug, },
};
</pre>

And initialising timer0 like this:

<pre>
// setup inverted output, logic low first, switch to high on
OCR0B match
unsigned char com_mode = 1<<COM0B1 | 1<<COM0B0;

// FastPCM mode with TCNT0 limited to OCR0A
unsigned char wgma_mode = 1<<WGM01 | 1<<WGM00;
unsigned char wgmb_mode = 1<<WGM02;

// Slow down the rate as much as possible for debugging
unsigned char prescaler = 1<<CS02 | 1<<CS00;

// Stop the timer for programming
GTCCR |= 1<<TSM | 1<<PSR0;

// Set TOP count
OCR0A = 243;

// Set transition count
OCR0B = 122;

// Program the timer0 and interrupt
TCCR0A = com_mode | wgma_mode;
TCCR0B = wgmb_mode | prescaler;
TIMSK |= 1<<OCIE0A;

// Set PORTB1 for output
DDRB |= 1<<DDB1;

// Turn the timer on
GTCCR &= ~( 1<<TSM );
</pre>

M P

unread,
Dec 3, 2010, 5:52:17 AM12/3/10
to sim...@googlegroups.com
There is a bit on misunderstanding here. simavr is made to allow
people to run their code as close to the real thing as possible, and
at a "resonable" speed, but it doesn't try to emulate every bit of
silicon in the avr core. ie a VCD of value that isn't read by the AVR
code is not considered important to the simulation, and therefore not
updated...

It is not a "cheap" calculation, and having to do it for every cycle
would make the simulator slow down to a crawl. Same applies to the PWM
pin itself, it's /never/ toggled because we don't really care as it's
an output... that would involve massive overhead at each cycle for no
reason than having a pretty trace in VCD.

Thats why the value is calculated only when the AVR core reads it,
because that's the whole point. The simavr IRQ system for PWMs allows
you to make external "peripherals" that reacts to a certain PWM
frequency/duty cycles if you like, but not at the pin level...

Michael

Nick Andrew

unread,
Dec 3, 2010, 9:28:23 AM12/3/10
to simavr
That raises some questions.

The reason I use a simulator is because I want a precise reproduction
of my firmware's execution as if it were running on a physical chip.
The simulator should run the firmware just as a physical chip would,
given the same inputs and showing the same outputs. The VCD trace is
not there to look pretty; it is an essential tool to prove the program
is working as expected.

In my firmware's case, I want to see that the timer is counting at the
correct rate, and that its output is the correct waveform and is
glitch-free.

As I understand it, one of the goals of this project is to allow
simulated AVR chips to participate in a larger simulated circuit, and
this would require that output pins be correctly modified at the
appropriate time to allow connected logic to react to changed values.
Is this correct?

I don't understand the simavr IRQ system. How does it work? I'm
basing my "harness" code on board_ledramp which simulates an array of
LEDs connected to the pins. If one of those pins is driven by a PWM
timer, I expect to see the corresponding LED flashing. After all, not
only LEDs may connect to the pins, it could be logic gates or another
CPU, etc ...

I understand that you want to minimise the cost of simulation, and one
way to do that is to calculate the value of TCNT0 at the time it is
read. However I think the simulator can do more than that, without
having to recalculate things every cycle. I think there is a mechanism
to schedule something to happen in advance? A running timer has
predictable behaviour: the simulator could calculate _when_ the pin
value will change in the future, and schedule an event to make the
change at the correct future time. This calculation needs to be done
only when the timer is (re)-programmed, or when the compare bytes
match, to setup for the next match. I'm only referring to timers
driven by the prescaled system clock of course; any timer clocked by
T0 will have to be simulated step by step.

Even without pre-calculation, I'm not sure how the overhead of
incrementing a timer counter will be excessive. Assuming the timer is
clocked by the prescaled system clock, the value will increase by 1
every 'N' clock cycles. Testing 2 or 3 comparison registers needs to
be done only when the timer counter changes or the register values
change. Toggling the output pin needs to be done only when the
comparison matches. If toggling the output pin is the most resource-
consuming action the emulator can do, it is also the least frequent.

M P

unread,
Dec 3, 2010, 12:23:26 PM12/3/10
to sim...@googlegroups.com
In my particular case, I have no interest in making a simulator for
Atmel's piece of silicon that toggle output pins for PWM -- why would
I want to ever debug THAT? I really don't see the point in doing so at
all. What I want to know "externally" in my "peripheral" is the duty
cycle and frequency -- that is provided by the IRQs (which are one way
communication channels).. Having to make a piece of code that
re-calculate that from a "non pin" toggling endlessly is entirely
pointless. At that rare, I'd have to "toggle pins" for SPI, UART and
all that too, which is really silly.

I know that FPGA simulators allow you to do that, but it's because in
their case you /actualy/ make the silicon that does the PWM and so on,
and there is no interest nor possibility to run the simulation at
nowhere near real time speed. In /my/ case, I want to be able to write
an AVR firmware on my laptop that responds and drive "peripherals"
that I have re-coded as their "logical" level, not pin levels.

So in the case of the LedRamp example, the PWM would be passed as an
integer representing frequency and duty cycle, and the "peripheral"
would change the display brightness to simulate the real hardware,
without "blinking". Check the Timer example, it does just that...

Michael

dcl...@gmail.com

unread,
Dec 3, 2010, 6:52:33 PM12/3/10
to sim...@googlegroups.com

Just to clarify what simavr does and does not do: Is it possible to
directly simulate input pin changes? I want to run test case
simulations, ideally without having to modify the original code.

M P

unread,
Dec 3, 2010, 7:34:24 PM12/3/10
to sim...@googlegroups.com
yes, normal PIN & PORT changes are simulated completely. these are
linked each to avr_irq_t that simulates the core, triggers interrupts
and so on.
So check the "Timer" example, it is pretty complete in dealing with
PORT/PIN/PWM etc

Whats the previous discussion is about is where the simulator should
go down to simulating some of the AVR /external/ interfaces.

Michael

Nick Andrew

unread,
Dec 3, 2010, 9:30:56 PM12/3/10
to simavr
How does the IRQ mechanism work?

M P

unread,
Dec 4, 2010, 6:35:04 AM12/4/10
to sim...@googlegroups.com
On Sat, Dec 4, 2010 at 2:30 AM, Nick Andrew <elro...@gmail.com> wrote:
> How does the IRQ mechanism work?

It's a pretty simple construct really. Each peripherals (and quite a
few other things) have use an "IRQ" to signal to whomever is
interested that something has changed... It is really just a
mono-directional signal, with one source and one or more destinations.
A destination can be either a C callback, or another IRQ in which case
the "signal" is passed on.

Each simavr IO module as a set of IRQs that are specific to that
peripheral, and "output" values of interests from that peripheral. It
can also have "input" IRQs that can be used to feed it information...

For example, if you look at the ADC module (sim/avr_adc.h), it has :
+ ADC0-7 as Input IRQs, these are used by a peripherals to pre-load
the "ADC" pre-multiplexer, so your "peripheral" can set the ADC0 to a
specific voltage for example...
+ TEMP for setting the temperature, if the AVR has that
+ OUT_TRIGGER is "signaled" when the AVR core starts a "conversion",
it allows your peripheral to calculate a value and send back a ADC0-7
to fill the pre-mux
+ IN_TRIGGER can be used by the peripheral to signal the AVR to start
a conversion automaticaly, the the regular AVR ADC can be triggered by
the timer etc.

these "IRQs" are used all over the place, every peripheral use them
and it is their standard way of communicating with "external" code...

Michael

Reply all
Reply to author
Forward
0 new messages