AVR

Powering on my STK 500

You can use any polarity, but if you can, please use a negative center connector 10-15V DC.

Background from STK500 Manual:

An external 10 - 15V DC power supply is required. The input circuit is a full bridge rectifier, and the STK500 automatically handles both positive or negative center connectors. If a positive center connector is used, it can be impossible to turn the STK500 off since the power switch disconnects the GND terminal. In this case, GND can be supplied through the RS-232 cable shield if connected or through alternative GND connections.

Getting on and connecting the STK500

$ dmesg 
pl2303 converter now attached to ttyUSB0

Which Socket to use?

STK500 Jumper Settings

Clock Settings

AVRDUDE commands

List supported MCUs:

avrdude  -c stk500v2 -p ?

Read lfuse:

avrdude -c stk500v2 -p m16 -P /dev/ttyUSB0 -U lfuse:r:lfuse.hex:b

Read hfuse:

avrdude -c stk500v2 -p m16 -P /dev/ttyUSB0 -U hfuse:r:hfuse.hex:b

Set lfuse:

avrdude -c stk500v2 -p m16 -P /dev/ttyUSB0 -U lfuse:w:0b11110000:m

ATMEGA16L Fuses

Read the datasheet, and search for "Fuse Low Byte" and "Fuse High Byte". For my configuration, for an external clock, 0000 needs to be written to CKSEL3...CKSEL0

ATMEGA8 Fuses

STK500 is having a resonator on it's own, so AVR has to be configured to use an external clock source. For this, the external clock options needs to be selected, and that is the same as in the case of ATMEGA16L.

Trying out V-USB

This is using an ATTINY2313 chip. First I want to see if I can get the lfuse to read.

Read lfuse:

$ avrdude -c stk500v2 -p t2313 -P /dev/ttyUSB0 -U lfuse:r:lfuse.hex:b
$ cat lfuse.hex
0b1100100

Read hfuse:

avrdude -c stk500v2 -p t2313 -P /dev/ttyUSB0 -U hfuse:r:hfuse.hex:b
$ cat hfuse.hex
0b11011111

This more or less matches the datasheet. I say more or less, as one section suggests that the default value for CKSEL3..1 is 001 whereas the document also mentions:

The device is shipped with CKSEL = 0100, SUT = 10, and CKDIV8 programmed.

Clock configuration

For an xtal configuration, I need CKSEL3..1 to be 111 for crystal above 8 Mhz. CKSEL0 fuse together with SUT1..0 determines startup.

Also looking at examples with V-USB:

$(AVRDUDE) -U hfuse:w:0xdb:m -U lfuse:w:0xef:m

Meaning hfuse to be on 0b11011011 and lfuse to be on 0b11101111

ATTINY2313 HFUSE

What changes in VUSB configuration is that Brown-Out detection voltage is put to 2.7V

ATTINY2313 LFUSE

This means that we will not use a prescaler and CKSEL3..1 will be 111 meaning external Xtal above 8 MHz. CKSEL0 becomes 1 which togther with SUT0 being 0 and SUT1 being 1 means Crystal Oscillator, fast rising power configuration.

Let's program those bytes:

avrdude -c stk500v2 -p t2313 -P /dev/ttyUSB0 -U hfuse:w:0xdb:m -U lfuse:w:0xef:m

And now let's try to blink it. This is blink.c

#define F_CPU 12000000
#define LED_DELAY 200
#include <avr/io.h>
#include <util/delay.h>

int main(void) {
    DDRB = 0xff;

    for(;;) {
        _delay_ms(LED_DELAY);
        PORTB = 0b00001000;
        _delay_ms(LED_DELAY);
        PORTB = 0b00000100;
        _delay_ms(LED_DELAY);
        PORTB = 0b00000010;
        _delay_ms(LED_DELAY);
        PORTB = 0b00000001;
        _delay_ms(LED_DELAY);
        PORTB = 0b00000010;
        _delay_ms(LED_DELAY);
        PORTB = 0b00000100;
    }
}

And this is my Makefile:

:::make
MMCU=attiny2313
AVRDUDE_DEVICE=t2313

CC=avr-gcc
OBJCOPY=avr-objcopy
CMPNAME=blink

STKPORT=/dev/ttyUSB0

CFLAGS=-g -mmcu=$(MMCU) -v

$(CMPNAME).hex : $(CMPNAME).out
        $(OBJCOPY) -j .text -O ihex $(CMPNAME).out $@

$(CMPNAME).out : $(CMPNAME).o
        $(CC) $(CFLAGS) -o $@ -Wl,-Map,$(CMPNAME).map $<

$(CMPNAME).o : $(CMPNAME).c
        $(CC) $(CFLAGS) -Os -c $<

$(CMPNAME).s: $(CMPNAME).c
        $(CC) -S $(CFLAGS) -o $<

program: $(CMPNAME).hex
        avrdude -p $(AVRDUDE_DEVICE) -c stk500v2 -P $(STKPORT) -U flash:w:$(CMPNAME).hex:i

fuses:
        avrdude -p $(AVRDUDE_DEVICE) -c stk500v2 -P $(STKPORT) -U hfuse:w:0xdb:m -U lfuse:w:0xef:m

clean:
        rm -f *.o *.out *.map *.hex

.PHONY: clean program fuses

Making a timer out of ATMEGA8-16U

Goal is to creata timer that measures 10 minutes using the internal oscillator and nothing more.

Linux setup

STK500 Setup

Hardware Setup

Software

Read lfuse and hfuse (I had to re-connect xtal for these)

avrdude -c stk500v2 -P /dev/ttyUSB0 -p m8 -U lfuse:r:lfuse-origin.hex:b
avrdude -c stk500v2 -P /dev/ttyUSB0 -p m8 -U hfuse:r:hfuse-origin.hex:b

Fuses were: - lfuse: 0b11100000 - hfuse: 0b11011001

Write fuses so chip will use internal oscillator. From datasheet, in order to have internal RC oscillator used I need CKSEL3..0 set as: 0100 - 0001

For the 1MHz option CKSEL3..0 needs to be 0001

HFUSE explanation (highest bit first) - RSTDISBL- 1 - PC6 is reset pin - WDTON - 1 - WDT enabled by WDTCR - SPIEN - 0 - Serial programming enabled - CKOPT - 1 - Oscillator options - EESAVE - 1 - EEPROM not preserved through chip erase - BOOTSZ1 - 0 - Boot size related - BOOTSZ0 - 0 - Boot size related - BOOTRST - 1 - Boot reset vector

HFUSE can stay as it is

LFUSE explanation (highest bit first) - BODLEVEL - 1 - Brown out related - BODEN - 1 - Brown out related - SUT1 - 1 - start-up time related - SUT0 - 0 - start-up time related - CKSEL3 - 0 - OK - CKSEL2 - 0 - OK - CKSEL1 - 0 - OK - CKSEL0 - 0 - Shall be changed to 1

New values then: - lfuse 0b11100001 - 0xe1 - hfuse 0b11011001 - 0xd9

avrdude -c stk500v2 -p m8 -P /dev/ttyUSB0 -U hfuse:w:0xd9:m -U lfuse:w:0xe1:m

Now xtal jumper removed from STK500, and I can read fuses again.

And now let's try to blink it via PORTC. This is blink.c

#define F_CPU 1000000
#define LED_DELAY 200
#include <avr/io.h>
#include <util/delay.h>

int main(void) {
    DDRC = 0xff;

    for(;;) {
        _delay_ms(LED_DELAY);
        PORTC = 0b00001000;
        _delay_ms(LED_DELAY);
        PORTC = 0b00000100;
        _delay_ms(LED_DELAY);
        PORTC = 0b00000010;
        _delay_ms(LED_DELAY);
        PORTC = 0b00000001;
        _delay_ms(LED_DELAY);
        PORTC = 0b00000010;
        _delay_ms(LED_DELAY);
        PORTC = 0b00000100;
    }
}

And this is my Makefile:

:::make
MMCU=atmega8
AVRDUDE_DEVICE=m8

CC=avr-gcc
OBJCOPY=avr-objcopy
CMPNAME=blink
PROGRAMMER=stk500v2

STKPORT=/dev/ttyUSB0

CFLAGS=-g -mmcu=$(MMCU) -v

$(CMPNAME).hex : $(CMPNAME).out
        $(OBJCOPY) -j .text -O ihex $(CMPNAME).out $@

$(CMPNAME).out : $(CMPNAME).o
        $(CC) $(CFLAGS) -o $@ -Wl,-Map,$(CMPNAME).map $<

$(CMPNAME).o : $(CMPNAME).c
        $(CC) $(CFLAGS) -Os -c $<

$(CMPNAME).s: $(CMPNAME).c
        $(CC) -S $(CFLAGS) -o $<

program: $(CMPNAME).hex
        avrdude -p $(AVRDUDE_DEVICE) -c $(PROGRAMMER) -P $(STKPORT) -U flash:w:$(CMPNAME).hex:i

fuses:
        avrdude -p $(AVRDUDE_DEVICE) -c $(PROGRAMMER) -P $(STKPORT) -U hfuse:w:0xd9:m -U lfuse:w:0xe1:m

clean:
        rm -f *.o *.out *.map *.hex

.PHONY: clean program fuses

Interrupt Handling of TIMER0 overflow

#define F_CPU 1000000
#include <avr/io.h>
#include <avr/interrupt.h>

volatile int port_value;

ISR(TIMER0_OVF_vect)
{
    if(port_value==0) {
        port_value=1;
    } else {
        port_value=0;
    }
}


int main(void) {
    // SETTING PORTC DIRECTION AS OUTPUT
    DDRC = 0xff;

    // INITIALIZING DISPLAY VALUE
    port_value = 0;

    // SETTING TIMER0 SOURCE TO CLKIO/1024
    TCCR0|=(1<<CS02)|(1<<CS00);
    TCCR0&=~(1<<CS01);

    // ENABLE TIMER0 INTERRUPT
    TIMSK|=(1<<TOIE0);

    // ENABLE GLOBAL INTERRUPT
    sei();

    for(;;) {
        PORTC=port_value;
    }
}

Real Time Clock with Timer 2

STK500 Setup

When XTAL1 jumper is not mounted, the internal clock system is disconnected. This allows external clock signals or crystals to be used as tar- get clock source for the AVR.

When the XTAL1 jumper is not mounted, an external clock source or crystal can be con- nected to the PORTE header.

Fuse Setup

Fuses shall remain the same - still using an internal 1MHz clock, see above

Register Setup

Example Code

This code fragment will display the counter's value on the STK500 LEDs. Note: I was looking at /usr/avr/include/avr/iom8.h for finding register names.

:::c
#define F_CPU 1000000
#include <avr/io.h>

volatile int port_value;


int main(void) {
    // SETTING PORTC DIRECTION AS OUTPUT
    DDRC = 0xff;
    // SHOW WHERE WE ARE
    PORTC = 0x01;

    // TIMER2 SETTINGS
    //   1.) DISABLE INTERRUPTS
    //       - DISABLE OUTPUT COMPARE MATCH INTERRUPT
    TIMSK &= ~(1<<OCIE2);
    //       - DISABLE OVERFLOW INTERRUPT
    TIMSK &= ~(1<<TOIE2);

    //   2.) SELECT ASYNC OPERATION
    ASSR|=(1<<AS2);

    //   3.) INITIALIZE VALUES
    //       - COUNTER VALUE
    TCNT2 = 0;
    //       - COMPARE MATCH VALUE
    OCR2 = 0xff;
    //       - CONFIGURE TIMER2 FOR 1024 PRESCALE
    TCCR2 |= (1<<WGM21)|(1<<CS22)|(1<<CS21)|(1<<CS20);

    //   4.) WAIT FOR ASYNC OPERATION TO FINISH
    //       - Wait for TCN2UB, OCR2UB, and TCR2UB
    PORTC = 0x02;  
    while((ASSR & (1<<TCN2UB))) {;};
    PORTC = 0x03;
    while((ASSR & (1<<OCR2UB))) {;};
    PORTC = 0x04;
    while((ASSR & (1<<TCR2UB))) {;};

    //   5.) CLEAR INTERRUPT FLAGS
    TIFR &= ~((1<<OCF2)|(1<<TOV2));
    // ENABLE INTERRUPTS

    for(;;) {
        PORTC=TCNT2;
    }
}

Example 1sec blink

:::c
#define F_CPU 1000000
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

volatile int one_sec_flag;

#define LED_DELAY 50

ISR(TIMER2_COMP_vect)
{
    one_sec_flag = 1;
}

int main(void) {
    // SETTING GLOBAL VALUE
    one_sec_flag = 0;

    // SETTING PORTC DIRECTION AS OUTPUT
    DDRC = 0xff;

    // DURING INIT SETTING PORT TO ALL 0 TO LIGHT ALL THE LEDS
    PORTC = 0x0;

    // TIMER2 SETTINGS
    //   1.) DISABLE INTERRUPTS
    //       - DISABLE OUTPUT COMPARE MATCH INTERRUPT
    TIMSK &= ~(1<<OCIE2);
    //       - DISABLE OVERFLOW INTERRUPT
    TIMSK &= ~(1<<TOIE2);

    //   2.) SELECT ASYNC OPERATION
    ASSR|=(1<<AS2);

    //   3.) INITIALIZE VALUES
    //       - COUNTER VALUE
    TCNT2 = 0;
    //       - COMPARE MATCH VALUE
    OCR2 = 31;
    //       - CONFIGURE TIMER2 FOR 1024 PRESCALE
    TCCR2 |= (1<<WGM21)|(1<<CS22)|(1<<CS21)|(1<<CS20);

    //   4.) WAIT FOR ASYNC OPERATION TO FINISH
    //       - Wait for TCN2UB, OCR2UB, and TCR2UB  
    while((ASSR & (1<<TCN2UB))) {;};
    while((ASSR & (1<<OCR2UB))) {;};
    while((ASSR & (1<<TCR2UB))) {;};

    //   5.) CLEAR INTERRUPT FLAGS
    TIFR &= ~((1<<OCF2)|(1<<TOV2));

    //   6.) ENABLE INTERRUPTS
    //       - Output compare match interrupt enable
    TIMSK |= (1<<OCIE2);
    sei();

    for(;;) {
        if(one_sec_flag == 1) {
            PORTC = ~(1<<0);
            _delay_ms(LED_DELAY);
            PORTC = ~(0);
            one_sec_flag = 0;
        }

    }
}