Session 1; Simple AVR Program
The following example should work with any ATtiny or ATmega device having at
least two GPIO ports (PORTA
and PORTB
). It should be
run with the I/O view active, and set up to show the PORTA
and
PORTB
modules.
PORTA
as output and
PORTB
as input, and then loops, reading whatever is present on
PINB
, increments it by one, and outputs it at
PORTA
.
reset: rjmp start start: ldi r16, 0xff out DDRA, r16 // PORTA => output clr r0 out DDRB, r0 // input <= PORTB loop: in r0, PINB // Requires stimuli for any action inc r0 out PORTA, r0 rjmp loopWithout stimuli, this program will read 0 from
PINB
, and output 1 to
PORTA
, forever.// Example stimuli file, feeds any output on PINA back to PINB.
#10
$repeat 10
PINB = *PINA
#10
$break
$endrep
PINB
will now be driven by the output from PORTA
every
10th cycle, and the effect will be directly visible in the I/O view. Thanks to the
$break
directive inside the loop, the program can will stop every
10 cycles without any breakpoint in the program.Session 2; Simple AVR Logging
TIMER0
and then enters a
loop constantly adding 1 to the value in PIND
and assigning the result
to PORTD
.
#include <avr/io.h> int main(void) { DDRD = 0xFF; TCCR0B = (1<<CS00); while(1) { PORTD = PIND + 1; } }
PORTD
and PIND
. After 20 cycles
it changes to logging PIND
and TCNT0
, and after
another 20 cycles it continues to only log PIND
for 60 cycles.
$log PORTD
$log PIND
$startlog mega328p_log_output.stim
#20
$unlog PORTD
$log TCNT0
#20
$unlog TCNT0
#60
$stoplog
$break
mega328p_log_output.stim
with the following
content:#6
PORTD = 0x01
#1
PIND = 0x01
#4
PORTD = 0x02
#1
PIND = 0x02
#4
PORTD = 0x03
#1
PIND = 0x03
#3
TCNT0 = 0x10
TCNT0 = 0x11
#1
TCNT0 = 0x12
#1
PIND = 0x04
TCNT0 = 0x13
#1
TCNT0 = 0x14
#1
TCNT0 = 0x15
#1
TCNT0 = 0x16
#1
TCNT0 = 0x17
#1
PIND = 0x05
TCNT0 = 0x18
#1
...
Session 3; Logging PWM ouput
TIMER0
in fast PWM mode.
The output of the PWM signal on PD6 is controlled by PB0. '1' on PB0 enables PWM output,
'0' on PB0 disables it.
#include <avr/io.h> int main(void) { DDRB = 0x00; DDRD = 0xFF; PORTD = 0x00; OCR0A = 0x20; TCCR0A = (1<<COM0A0 | 1<<WGM01 | 1<<WGM00); TCCR0B |= (1<<CS00); while(1) { if(PINB & 0x01) TCCR0B |= (1<<WGM02); else TCCR0B &= ~(1<<WGM02); } }
PINB
and PIND
. After 20 cycles it
also starts to log TCNT0
. 5 cycles later it applies a '1' to PB0 to
start the PWM output, and another 5 cycles later it turns off logging of TCNT0. For the
next 200 cycles the PWM output on PD6 will be logged before it is turned off by setting
PB0 to '0'. Then it continues for another 200 cycles before it breaks.
$log PINB
$log PIND
$startlog mega328p_log_output.stim
#20
// Log TIMER0 counter
$log TCNT0
#5
// Set pin PB0 to '1', Start PWM output
PINB |= 0x01
#5
// Stop logging TIMER0 counter
$unlog TCNT0
#200
// Set pin PB0 to '0', Stop PWM output
PINB &= 0xFE
#200
$stoplog
$break
mega328p_log_output.stim
with the following
content:#20 TCNT0 = 0x09 TCNT0 = 0x0a #1 TCNT0 = 0x0b #1 TCNT0 = 0x0c #1 TCNT0 = 0x0d #1 TCNT0 = 0x0e #1 TCNT0 = 0x0f #1 PINB = 0x01 TCNT0 = 0x10 #1 TCNT0 = 0x11 #1 TCNT0 = 0x12 #1 TCNT0 = 0x13 #15 PIND = 0x40 #33 PIND = 0x00 #33 PIND = 0x40 #33 PIND = 0x00 #33 PIND = 0x40 #33 PIND = 0x00 #22 PINB = 0x00 #11 PIND = 0x40 #1 PIND = 0x00