Hands On AVR

From SGMK-SSAM-WIKI
Jump to: navigation, search

Overview

This wiki page is dedicated to AVR development with focus on the ATtiny13 and ATtiny85 (has more memory... naaaiiice)

Links

wanna use the arduino programming language? check this

Memory

The ATtiny13 has two main memories:

Program memory is 1K Bytes. It's organized as 512x16 Bits, because all AVR instructions are 16 or 32 bits wide.

Tiny13-progmem.jpg

Data memory is 64 bytes of SRAM (internal memory) + 64 I/O Registers + 32 general purpose registers.

Tiny13-datamem.jpg

Furthermore there's electrically erasable programmable read-only memory (EEPROM) of 64 Bytes. Single bytes can be read and written.

I/O Ports

Individual I/O ports can be set as input or output. Each output can deliver 40mA.

The ATtiny13 has 6 I/O pins named: PB0, PB1, PB2, PB3, PB4 and PB5. Generally AVR ports are named Pxn, x is the letter of the port, n is the pin number.

All pins of PORTB of the attiny13 can be configured with only three registers:

  • Data Register - PORTB - write values to port PBx / set internal pull-up of PBx
  • Data Direction Register – DDRB - set PBx as input (0) or output (1).
  • Port Input Pins – PINB - read values at port PBx

Notes:

  • If PORTxn is written logic one when the pin is configured as an input pin, the pull-up resistor is activated.
  • The pin numbers don't correspond to the acutal hardware pin numbers, for example PB0 is located at hardware pin 5.
  • All ports have also alternate functions (ADC, PWM, ..).


ArduinoISP

ArduinoISP Steckplatine.png ArduinoISP Aufbau.jpg

Arduino can be used as an In-system programming (ISP) interface for the ATtiny and ATmega microcontrollers.

Here are step-by-step instructions on how to program an attiny13 with an LED blinking program:

  • On the Arduino, the ArduinoISP code must be running. Open the Arduino IDE -> examples -> ArduinoISP and flash it (File->Upload).
  • Build the circuit as shown above. Pins are documented in the source code. Use a 470Ω resistor between PB4 (that's pin 3 on the attiny13) and the LED.
  • Install AVR toolchain: Windows, Mac, Linux users: install avr-gcc, avr-gcc-c++ and avr-libc

the code: <syntaxhighlight lang="c"> /* hello, LED!

attiny13 Pins:

1: RESET (Arduino 10) 2: NC (not connected) 3: R (470Ω) to LED to GND 4: GND (Arduino Gnd) 5: MOSI (Arduino 11) 6: MISO (Arduino 12) 7: SCK (Arduino 13) 8: VCC (Arduino 5V)

  • /
  1. define F_CPU 9600000 // Define software reference clock for delay duration
  1. include <avr/io.h>
  2. include <util/delay.h>
  1. define LED PB4 // Define led output on PB4

int main() { DDRB |= (1 << LED); // Set direction to output for LED

for (;;) { // forever PORTB ^= (1 << LED); // toggle pin _delay_ms(1000); } return 0; } </syntaxhighlight >

  • download and run File:Led.zip and extract it somewhere. open the cmd/shell and run the command make all. this will generate the file "lex.hex"
  • upload it manually using avrdude (which is part of the WinAVR software), change correct com port and baudrate:

avrdude -P COM1 -b 19200 -c avrisp -p attiny13 -U flash:w:led.hex:i

linux: use /dev/ttyUSB.. instead of COM1.

  • now the LED should be blinking, but too slow.

We have to change the fuse bits.

  • Windows: avrdude -P COM*** -b 19200 -c avrisp -p t13 -U lfuse:w:0x7a:m -U hfuse:w:0xff:m (***select appropriate usb device, can be COM1, COM2, etc. and baudrate -b ...)
  • Linux: avrdude -P /dev/ttyUSB*** -c avrisp -p t13 -U lfuse:w:0x7a:m -U hfuse:w:0xff:m (***select appropriate usb device)
  • enjoy the blinking LED (1 second on, 1 second off)!

ISP Programming

AVR can be programmed using the In-System-Programming interface ISP. Different programmers are available: AVR pocket programmer, USBtinyISP, official Atmel programmers.

Breadboard setup:

Attiny13-ISP-breakout.png 6pinAVRproghead.jpg

Solder a breakout cable. You could also connect the lines from the programmer directly to the tiny pins. If you're too lazy, buy the sparkfun Programming Adapter.

LED Example:

  • setup the circuit as shown in the image above. See also #ArduinoISP.
  • download File:Led.zip and extract the files (Makefile and led.c) to a new folder on the system.
  • Open the Makefile in a texteditor and check the following (IMPORTANT):
    • TARGET: i called the source file "led.c", thus in the makefile the TARGET has to be named "led" (without extension).
    • AVRDUDE_PROGRAMMER: here "usbtiny" must be set, because we're using AVR Pocket programmer. make your appropriate choice, if you use another programmer. (see note below).
    • AVRDUDE_PORT: set the correct comport. windows: COM1, COM2, etc. Linux: /dev/ttyUSB...

Note: other programmers can be defined, if you are for example using the "AVR Pocket programmer", AVRDUDE_PROGRAMMER must be set to "usbtiny", for "AVRISP mkII", set it to 'stk500'. all programmers can be listed with the command avrdude -c ?

  • make sure the Makefile is in the same folder as the source file is in.
  • run these commands from the cmd (windows) or shell (linux):
    • to check, if we are using the correct compiler: avr-gcc --version (this should give you something like "avr-gcc (WinAVR 20100110) 4.3.3")
    • make hex file: make all
    • download hex file to AVR: make program
    • at this stage the LED should already blink, but too slow, because the fuse bits are not set correctly yet.

We have to change the fuse bits.

  • Windows: avrdude -P COM*** -c usbtiny -p t13 -U lfuse:w:0x7a:m -U hfuse:w:0xff:m (***select appropriate usb device, can be COM1, COM2, etc.)
  • Linux: avrdude -P /dev/ttyUSB*** -c usbtiny -p t13 -U lfuse:w:0x7a:m -U hfuse:w:0xff:m (***select appropriate usb device)
  • enjoy the blinking LED!

High Voltage Fuse Resetter

IMAG0467.jpg

If the fusebits are messed up, the AVR can be factory resetted. This can be done with "high-voltage serial programming". Here is a excellent project to reset attiny13/25/45/85 chips: hvsp fuse resetter

tips:

  • The schema on the website seems to have bugs, i fixed them, check my copy File:Hvsp-fuse-resetter-schema.pdf.
  • The 7x4 LED module can be found on ebay. If the display doesn't work, you probably have to comment out "#define _REVERSE" in the code, this switches common anode/common cathode of the display.

Links

Tutorials

fusecalc - make sure u dont burn the wrong fuses :-)

AVR Programmers

AVR Pocket Programmer Windows Driver: [1]

LadyAda USBtinyISP Windows Driver: [2]

SGMK tiny

SGMKtinyuoino v03.jpg

easy to use on breadboards with onboard connected ISP port

Pin Layout

Tinyuino5 labels.png

Mask

More Code Examples

Heartbeat PWM out

<syntaxhighlight lang="c"> /* Heartbeat - Hello World PWM LED at OC0A (PB0) - Pin 5

  • /
  1. define F_CPU 9600000UL // Define software reference clock for delay duration 1 MHz
  1. include <avr/io.h>
  2. include <util/delay.h>
  1. define PWM0 PB0

int i; int delay;

void pwm_init() { //PWM Init

  TCCR0A |= (1 << COM0A1) | (1 << COM0A0);    // COM0A1 - COM0A0 (Set OC0A on Compare Match, clear OC0A at TOP) 
  TCCR0A |= (1 << WGM01) | (1 << WGM00);   // WGM01 - WGM00 (set fast PWM) 
  OCR0A   = 0;                                // initialize Output Compare Register A to 0 
  //TCCR0B |= (1 << CS00);                      // Start timer at Fcpu / 1
  TCCR0B |= (1 << CS01);                    // Start timer at Fcpu / 8
  //TCCR0B |= (1 << CS02) | (1 << CS00);      // Start timer at Fcpu / 1024

}

int main(void) {

//Initialization:

  DDRB |= (1 << PWM0);    // OC0A on PB0
  pwm_init();

//Actual Program:

  while (1) {            // loop forever 
    
   for (i=0; i<=255; i++) { 
    
    OCR0A = (i); 
    _delay_us (200);
   }
   for (i=254; i>=0; i--) { 
    
    OCR0A = (i); 
    _delay_us (200);
   }
 } 

} </syntaxhighlight >

2 x better Analog-in 10-bit & 2 x PWM out & threshold value

<syntaxhighlight lang="c"> /* Analog sensor input at ADC3 (PB3) - Pin 2 Analog sensor input at ADC1 (PB2) - Pin 7 PWM LED at OC0A (PB0) - Pin 5 PWM LED at OC0A (PB1) - Pin 6 Digital FAN at (PB4) - Pin 3

  • /
  1. define F_CPU 9600000UL // Define software reference clock for delay duration 1 MHz
  1. include <avr/io.h>
  2. include <util/delay.h>
  1. define ADC3 PB3
  2. define ADC1 PB7
  3. define FAN PB4
  4. define PWM0 PB0
  5. define PWM1 PB1

unsigned int read_adc(unsigned char channel);

int i; unsigned int sensorValue; //16bit unsigned int temperatureValue; //16bit unsigned int outputVoltage;

void adc_init() { //ADC init

  ADMUX =  0b00000011; //ADC3 (default),right,VCc
  //ADMUX =  0b00100011; //ADC3 (default),ADLAR left,VCc
  ADCSRA = 0b10000010; //prescaled by 4

}

void pwm_init() { //PWM Init

  TCCR0A |= (1 << COM0A1) | (1 << COM0A0);    // COM0A1 - COM0A0 (Set OC0A on Compare Match, clear OC0A at TOP) 
  TCCR0A |= (1 << COM0B1) | (1 << COM0B0);    // COM0B1 - COM0B0 (Set OC0B on Compare Match, clear OC0B at TOP) 
  TCCR0A |= (1 << WGM01) | (1 << WGM00);   // WGM01 - WGM00 (set fast PWM) 
  OCR0A   = 0;                                // initialize Output Compare Register A to 0 
  OCR0B   = 0;                                // initialize Output Compare Register B to 0 
  //TCCR0B |= (1 << CS00);                      // Start timer at Fcpu / 1
  TCCR0B |= (1 << CS01);                    // Start timer at Fcpu / 8
  //TCCR0B |= (1 << CS02) | (1 << CS00);      // Start timer at Fcpu / 1024

}

int main(void) {

//Initialization:

  DDRB &= ~(1 << ADC3);  // Set direction of (PB3) to input for ADC3
  DDRB |= (1 << FAN);    // Set direction of (PB4) to output for FAN
  DDRB |= (1 << PWM0) | (1 << PWM1);    // OC0A on PB0 & P01
  adc_init(); 
  pwm_init();

//Actual Program:

  while (1) {            // loop forever 
    
    sensorValue = read_adc(3);  
    
    OCR0A = (255-(sensorValue>>2)); 
    OCR0B = ((sensorValue>>2));  
    
    temperatureValue = read_adc(1);
    // map it to the range 0 to 5000 mV:
    //outputVoltage = ((sensorValue*50) / 255);  
  
    // Calculate Temperature, 10mV/°C -50°C for TMP36, check data sheet
    //temperatureValue = (2 + (outputVoltage*10));
    
    if (temperatureValue >= sensorValue) {
      PORTB = (1 << FAN);
      } 
    else {
      PORTB = (0 << FAN);
      }
 } 

}


unsigned int read_adc(unsigned char channel) {

unsigned char k; unsigned int adcvalue=0; ADMUX = ADMUX&(0b11111100); //clear channel select bits ADMUX |= channel;

//neglect first reading after changing channel ADCSRA |= 1<<ADSC; while(ADCSRA&(1<<ADSC));//Wait adcvalue=ADCL + (ADCH<<8); adcvalue=0;//neglectreading for(k=0;k<=7;k++) { ADCSRA |= 1<<ADSC; while(ADCSRA&(1<<ADSC));//Wait adcvalue += (ADCL + (ADCH<<8));

               _delay_ms (2);

} return (adcvalue>>3); //divide by 8

} </syntaxhighlight >

Analog in & PWM out

<syntaxhighlight lang="c"> /* Analog sensor input at ADC3 (PB3) - Pin 2 PWM LED at OC0A (PB0) - Pin 5 Digital FAN at (PB4) - Pin 3

  • /
  1. define F_CPU 9600000UL // Define software reference clock for delay duration 1 MHz
  1. include <avr/io.h>
  2. include <util/delay.h>
  1. define FAN PB4
  2. define PWM PB0

int i ; int TEMP;

void adc_init() { //ADC Init.

  ADCSRA |= (1<<ADEN) | (1<<ADPS1) | (1<<ADPS2) | (1<<ADATE);   //Turn on ADC, with prescaler 64 
  ADCSRB= 0x00;   //Free running mode 
  ADMUX= 0x23;   //VCC Reference, Left Adjust, Channel: PB3 (ADC3) 
  DIDR0= 0x04;   //Disable Digital Input on PB3 
  ADCSRA |= (1 << ADSC); //start adc conversion

}

void pwm_init() { //PWM Init

  DDRB |= (1 << PWM);                       // OC0A on PB0 
  TCCR0A |= ((1 << COM0A1) | (1 << COM0A0)  // COM0A1 - COM0A0 (Set OC0A on Compare Match, clear OC0A at TOP) 
      | (1 << WGM01)    | (1 << WGM00)); // WGM01 - WGM00 (set fast PWM) 
  OCR0A   = 0;                              // initialize Output Compare Register A to 0 
  TCCR0B |= (1 << CS01);                    // Start timer at Fcpu / 256 

}

int main(void) {

//Initialization:

  adc_init(); 
  pwm_init();
  DDRB |= (1 << FAN);    // Set direction of (PB4) to output for FAN

//Actual Program:

  while (1) {            // loop forever 
        
    OCR0A = (255-(ADCH)); 
    TEMP = (2 + (2*ADCH));
    if (TEMP >= 28) {
      PORTB = (1 << FAN);
      } 
    else {
      PORTB = (0 << FAN);
      }
 } 

}

</syntaxhighlight >