Hands On AVR: Difference between revisions

From SGMK-SSAM-WIKI
Jump to navigation Jump to search
Line 149: Line 149:


=Code Examples by dusjagr=
=Code Examples by dusjagr=
== Heartbeat PWM out ==
<syntaxhighlight lang="c">
/*
Heartbeat - Hello World
PWM LED at OC0A (PB0) - Pin 5
*/ 
#define F_CPU 9600000UL    // Define software reference clock for delay duration 1 MHz
#include <avr/io.h>
#include <util/delay.h>
#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) | (1 << PWM1);    // OC0A on PB0 & P01
  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 >


== Analog in & PWM out ==
== Analog in & PWM out ==

Revision as of 10:28, 21 February 2012

Overview

This wiki page is dedicated to AVR development with focus on the ATtiny13.

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.

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

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

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:

/*
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)

*/

#define F_CPU 9600000	// Define software reference clock for delay duration

#include <avr/io.h>
#include <util/delay.h>

#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;
}
  • 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:

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

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.

AVR

more on AVR soon.

Code Examples by dusjagr

Heartbeat PWM out

/* 
Heartbeat - Hello World
PWM LED at OC0A (PB0) - Pin 5
*/  
 
#define F_CPU 9600000UL     // Define software reference clock for delay duration 1 MHz

#include <avr/io.h> 
#include <util/delay.h> 

#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) | (1 << PWM1);    // OC0A on PB0 & P01
   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);
    }

  } 
}


Analog in & PWM out

/* 
Analog sensor input at ADC3 (PB3) - Pin 2
PWM LED at OC0A (PB0) - Pin 5
Digital FAN at (PB4) - Pin 3
*/  
 
#define F_CPU 9600000UL     // Define software reference clock for delay duration 1 MHz

#include <avr/io.h> 
#include <util/delay.h> 

#define FAN PB4
#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);
       }
  } 
}