25 de Abril, 2015

Cuidado con los "fuses"

Los fuses (¿fusibles?) son 3 bytes de memoria permanente que determinan ciertas partes del comportamiento del microcontrolador.

Esta semana he estado trabajando con los ATtiny84, que es un microcontrolador de la subfamilia tiny de AVR. Es un MCU más pequeńo que el que viene con el Arduino Uno, y tiene algunas diferencias en cuanto a funcionalidad (ya hablaré de eso en otro momento).

Estos microcontroladores vienen de casa configurados para usar un oscilador RC interno a 8 MHz, pero tienen activado el flag CKDIV8 que divide por 8 la velocidad del oscilador, con lo que el MCU funciona a solo 1 MHz.

Como para mi proyecto quiero usar los 8 MHz (que además es una frecuencia soportada para 3v que puedes conseguir con dos pilas AAA), tengo que cambiar los fuses para desactivar ese flag.

Estoy usando un programador muy barato llamado USBasp que utiliza el interfaz SPI del microcontrolador sin la necesidad de un bootloader (como usa el Arduino), y nos deja disponible así toda la memoria para nuestro programa.

USBasp está soportado por avrdude, así que es bastante fácil reprogramar el MCU.

En primer lugar hay que usar la opción -B de avrdude a un valor de al menos 10 porque sino no será capaz de compunicarse con el MCU a 1 MHz.

Podemos confirmar que los fuses están como esperamos con:

avrdude -c usbasp -p attiny84 -P usb -v -B 10

Y cambiamos el low fuse para desactivar CKDIV8:

avrdude -c usbasp -p attiny84 -P usb -v -B 10 -U lfuse:w:0xe2:m

Muy fácil. A partir de ahora ya no es necesario usar la opción -B porque el MCU funcionará a 8 MHz.

La documentación del microcontrolador explica los fuses en detalle, pero hay que ir con mucho ojo porque podemos inutilizar el MCU (sin la ayuda del microcontrolador, USBasp es incapaz de programarlo).

Por ejemplo yo me equivoqué probando un cristal externo, confundiendo reloj externo con cristal externo; y no es lo mismo. De hecho no tengo un reloj externo y básicamente inutilicé el MCU porque no arrancaba sin el reloj :(.

Bueno, realmente no ;). Teniendo un Arduino a mano se puede generar una señal de reloj, lo que me permitió recuperar el microcontrolador y configurar los fuses correctamente.

Este es mi código de rescate:

// Generate a clock pulse with Aduino (digital port 5)
#define F_CPU	16000000

#include <avr/io.h>
#include <avr/interrupt.h>

int
main()
{
    cli();

    DDRD |= _BV(DDD5);

    TCCR0A = _BV(WGM00) | _BV(WGM01) | _BV(COM0B1);
    TCCR0B = _BV(CS00);
    TCNT0 = 0;
    TIFR0 = 0;
    OCR0B = 127;

    sei();

    while(1);
}

Ese código genera una señal de reloj en el pin 5 como la que espera el ATtiny84 configurado para usar un reloj externo, así que por esta vez... he podido salvar la situación fácilmente ;).

Anotación por Juan J. Martínez, clasificada en: avr.

Los comentarios están cerrados: los comentarios se cierran automáticamente una vez pasados 30 días. Si quieres comentar algo acerca de la anotación, puedes hacerlo por e-mail.

Algunas anotaciones relacionadas: