Programació dels microcontroladors AVR: avr-gcc

De Wikijoan
Dreceres ràpides: navegació, cerca

Contingut

Referències

A Brief Tutorial on Programming the AVR without Arduino

Programming the AVR microcontroller with GCC, libc 1.0.4

AVR Microcontrollers in Linux HOWTO

Segueixo el primer manual.

Quick explanation per entendre la programació dels xips:

Tutorial

$ sudo apt-get install gcc-avr
$ sudo apt-get install avr-libc
$ sudo apt-get install avrdude

Lesson 1: A blinking LED

IMG 20150602 133122805.jpg

NOTA: en la foto s'ha utilitzat el port D.

NOTA. També he seguit aquet tutorial, que ha funcionat, i que per fer el delay el codi és una mica diferent:

NOTA: també s'ha fet proves de fer pampallugues a un LED a: Atmel_ISP_MCU_programmer_ATmega._Programador_AVR_USBasp#Blink_LED

El meu xip és el Atmega168 de 28 pins:

1    PC6 - PCINT14, Reset [RESET]
2    PD0 - PCINT16, RXD [PIN0]
3    PD1 - PCINT17, TXD [PIN1]
4    PD2 - PCINT18, INT0 [PIN2]
5    PD3 - PCINT19, INT1, OC2B [PIN3]
6    PD4 - PCINT20, XCK, T0 [PIN4]
7    VCC
8    GND
9    PB6 - PCINT6, XTAL1, TOSC1
10    PB7 - PCINT7, XTAL2, TOSC2
11    PD5 - PCINT21, OC0B, T1 [PIN5/PWM]
12    PD6 - PCINT22, OC0A, AIN0 [PIN6/PWM]
13    PD7 - PCINT23, AIN1 [PIN7]
14    PB0 - PCINT0, CLKO, ICP1 [PIN8]
15    PB1 - PCINT1, OC1A [PIN9/PWM]
16    PB2 - PCINT2, OC1B, SS [PIN10/PWM]
17    PB3 - PCINT3, OC2A, MOSI [PIN11/PWM]
18    PB4 - PCINT4, MISO [PIN12]
19    PB5 - PCINT5, SCK [PIN13] LED
20    AVCC
21    AREF
22    GND
23    PC0 - PCINT8, ADC0 [ANALOG0]
24    PC1 - PCINT9, ADC1 [ANALOG1]
25    PC2 - PCINT10, ADC2 [ANALOG2]
26    PC3 - PCINT11, ADC3 [ANALOG3]
27    PC4 - PCINT12, ADC4, SDA [ANALOG4]
28    PC5 - PCINT13, ADC5, SCL [ANALOG5]

lesson1.c:

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

/*
 * Assumptions:
 * 	- LED connected to PORTB
 * 	- F_CPU is defined to be your cpu speed (preprocessor define)
 */

int main (void)
{
	/* set PORTB for output*/
	DDRB = 0xFF;

	while (1) {
		/* set PORTB high */
		PORTB = 0xFF;
		_delay_ms(500);

		/* set PORTB low */
		PORTB = 0x00;
		_delay_ms(500);
	}
	return 0;
}

NOTA: DDRB significa Data Direction Register for port B

Ja puc compilar el codi:

$ avr-gcc -g -mmcu=atmega168 -c lesson1.c -Wa,-alh,-L -o lesson1.o > lesson1.asm
In file included from lesson1.c:11:0:
/usr/lib/gcc/avr/4.5.3/../../../avr/include/util/delay.h:90:3: warning: #warning "F_CPU not defined for <util/delay.h>"
/usr/lib/gcc/avr/4.5.3/../../../avr/include/util/delay.h:95:3: warning: #warning "Compiler optimizations disabled; functions from <util/delay.h> won't work as designed"

Es generen els fitxers de sortida, però amb warnings.

És lògic que doni el primer warning: protesta perquè no sap a quina freqüència treballarà el uC, i per tant no sap calcular el delay. Falta ficar dalt de tot, abans dels include:

#ifndef F_CPU
   #define F_CPU 8000000UL     
#endif

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

(comprovar quin és el valor correcte per al Atmega168). Veure una discussió a:

El segon warning es soluciona ficant l'opció -Os:

Continuo amb la compilació:

$ avr-gcc -g -mmcu=atmega168 -Wl,-Map,lesson1.map -o lesson1.elf lesson1.o
$ avr-objdump -h -S lesson1.elf > lesson1.lst
$ avr-objcopy -j .text -j .data -O ihex lesson1.elf lesson1.hex
$ avr-size lesson1.elf

S'ha generat el ftixer hex, que ja puc gravar al xip amb el programador que tinc:

$ cat lesson1.hex
:100000000C9434000C9449000C9449000C94490061
:100010000C9449000C9449000C9449000C9449003C
:100020000C9449000C9449000C9449000C9449002C
$ sudo avrdude -b19200 -P usb -c usbasp -p m168 -U flash:w:lesson1.hex

Jugant amb els fuses. Càlcul correcte de la freqüència

Resumint, per compilar el meu codi les comandes són:

avr-gcc -g -mmcu=atmega168 -Os -c lesson1.c -Wa,-alh,-L -o lesson1.o > lesson1.asm
avr-gcc -g -mmcu=atmega168 -Wl,-Map,lesson1.map -o lesson1.elf lesson1.o
avr-objdump -h -S lesson1.elf > lesson1.lst
avr-objcopy -j .text -j .data -O ihex lesson1.elf lesson1.hex
avr-size lesson1.elf

sudo avrdude -p m168 -P usb -c usbasp -Uflash:w:lesson1.hex -B 1

use intern i que divideixi per 8

-U lfuse:w:0x62:m -U hfuse:w:0xdf:m
$ sudo avrdude -p m168 -P usb -c usbasp -U lfuse:w:0x62:m -U hfuse:w:0xdf:m
RC Osc 8MHz
Divide clock by 8 internally; [CKDIV8=0]

per tant el resultat és 1 MHz

#ifndef F_CPU
   #define F_CPU 1000000UL     
#endif 

va bé, 1 blink cada segon

Fuse intern i que divideixi per 8

#ifndef F_CPU
   #define F_CPU 8000000UL     
#endif 

va molt lent, el led intermitent. 10 blinks, 78 segons. Ara la freq ha de quedar dividit per 8: 1 blink cada 8 segons. Amb 70 segons són 78*1/8 = 9,75 blinks

Fuse intern i que no divideixi per 8

-U lfuse:w:0xe2:m -U hfuse:w:0xdf:m
$ sudo avrdude -p m168 -P usb -c usbasp -U lfuse:w:0xe2:m -U hfuse:w:0xdf:m

RC Osc 8MHz
NOT Divide clock by 8 internally; [CKDIV8=0]

per tant treballa a 8MHz, i en el programa li dic que el uC està treballant a 8MHz:

#ifndef F_CPU
   #define F_CPU 8000000UL     
#endif 

I ara el resultat és correcte, torno a trobar que el blink és cada segon

Cristall extern de 16MHz

Fins ara he fet proves amb l'oscil.lador intern. Ara faré proves amb un cristall extern de 16MHz

Llegeixo a http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=71917&view=previous:

You will want CKOPT programmed for 16mhz. 

Però per al Atmega168 aquesta opció no hi és.

sense tenir en compte el fuse extended, queda:

-U lfuse:w:0x62:m -U hfuse:w:0xdf:m

Per a cristalls d'alta freqüència (com ara 16MHz) és convenient retrassar el start-up time.

$ sudo avrdude -p m168 -P usb -c usbasp -U lfuse:w:0x62:m -U hfuse:w:0xdf:m
#ifndef F_CPU
   #define F_CPU 2000000UL   (fico 2000000 en comptes de 16000000 perquè hi ha el divide per 8)
#endif 

40 blinks, 80 segons. Per tant, és un blink cada 2 segons, la meitat de freqüència de lo esperat. Això és lògic, perquè l'opció del fuse és 8MHz (no hi ha opció 16Mhz). Com que jo li poso un cristall de 16MHz treballa el doble de ràpid, i per tant en el #define jo li he de dir que vagi la meitat de lent:

#ifndef F_CPU
   #define F_CPU 1000000UL
#endif 

Efectivament, ara sí que fa pampellugues cada segon. Però fixem-nos que el resultat que he ficat (1000000UL) és el mateix que si tingués un cristall de 8MHz. I això confirma la idea de què quan selecciono cristall extern de 8MHz en realitat vol dir de 8Mhz o més.

Interface USB-joystick: usb_game12-1.0

el projecte està disponible per a Atmega8. Si jo vull programar amb el Atmega168 i 16MHz, quins canvis s'hauran de fer? El projecte està realitzat a:

on ha funcionat correctament amb la configuració Atmel8/12MHz i Atmel168/16MHz.

$ make
avr-gcc -Wall -Os -Iusbdrv -I. -mmcu=atmega8 -DF_CPU=12000000L  -c usbdrv/usbdrv.c -o usbdrv/usbdrv.o
avr-gcc -Wall -Os -Iusbdrv -I. -mmcu=atmega8 -DF_CPU=12000000L  -x assembler-with-cpp -c usbdrv/usbdrvasm.S -o usbdrv/usbdrvasm.o
avr-gcc -Wall -Os -Iusbdrv -I. -mmcu=atmega8 -DF_CPU=12000000L  -c usbdrv/oddebug.c -o usbdrv/oddebug.o
avr-gcc -Wall -Os -Iusbdrv -I. -mmcu=atmega8 -DF_CPU=12000000L  -c main.c -o main.o
avr-gcc -Wall -Os -Iusbdrv -I. -mmcu=atmega8 -DF_CPU=12000000L  -c twelve.c -o twelve.o
avr-gcc -Wall -Os -Iusbdrv -I. -mmcu=atmega8 -DF_CPU=12000000L  -c devdesc.c -o devdesc.o
avr-gcc -Wall -Os -Iusbdrv -I. -mmcu=atmega8 -DF_CPU=12000000L  -o main.bin usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o twelve.o devdesc.o -Wl,-Map=main.map
rm -f main.hex main.eep.hex
avr-objcopy -j .text -j .data -O ihex main.bin main.hex
./checksize main.bin
ROM: 2560 bytes (data=58)
RAM: 134 bytes

Compila sense problemes per a atmega8, i es genera el fitxer .hex, que és el que interessa per cremar el xip amb avrdude.

Si canvio les comandes atmega8 per atmega168, falla la 4a comanda:

$ avr-gcc -Wall -Os -Iusbdrv -I. -mmcu=atmega168 -DF_CPU=12000000L  -c main.c -o main.o
main.c: In function ‘hardwareInit’:
main.c:123:2: error: ‘TCCR0’ undeclared (first use in this function)
main.c:123:2: note: each undeclared identifier is reported only once for each function it appears in
main.c:125:2: error: ‘TCCR2’ undeclared (first use in this function)

Important llegir: swithcing from atmeg8 to atmega168

means the code was written for an AVR that has a register called "TCCR0" and your one does not.
Note that the OP's register name is TCCRO, with a capital O letter rather than a zero, which is invalid on every AVR model. 

The registers are defined through proper use of <avr/io.h>. If they are not defined, then you are doing something wrong. You need to specify the AVR you are using in the project settings.

Es soluciona fent els següents canvis en els noms dels registres en el fitxer main.c:

TCCR0 to TCCR0B
TCCR2 to TCCR2B
TIFR to TIFR0 
OCR2 to OCR0A
OCF2 to OCF0A

I ara ja puc compilar per al atmega168. N'hi ha prou en editar el fitxer Makefile i canviar atmega8 per atmega168.

En el fitxer Makefile també he de canviar aquesta línia per dir quin és el meu AVR i quin és el meu programador:

flash_usb:
        sudo avrdude -p m168 -P usb -c usbasp -Uflash:w:$(HEXFILE) -B 1.0 

I ja puc gravar el nou hex file:

$ make flash_usb
sudo avrdude -p m168 -P usb -c usbasp -Uflash:w:main.hex -B 1.0

avrdude: set SCK frequency to 750000 Hz
avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: AVR device initialized and ready to accept instructions

Reading | ####
...

creat per Joan Quintana Compte, febrer 2014

Eines de l'usuari
Espais de noms
Variants
Accions
Navegació
IES Jaume Balmes
Màquines recreatives
CNC
Informàtica musical
joanillo.org Planet
Eines