Resulta que compré un puñado de ATmega328, pensando que podría usarlos sin ningún problema para mis futuros proyectos con arduino, como por ejemplo, realizar circuitos compactos (no modulares) y poder usar el microcontrolador ya programado... o programandolo como si fuese un arduino externo.
Instrucciones para construir el programador
Preparé el programador externo usando un cristal de cuarzo de 16 Mhz, montandolo en una placa de topos.
Entonces cargué el software de programación en mi arduino ( File > Examples > ArduinoISP ), y al volcar el BootLoader me dice que el código de identificación no es correcto. ( y solo era el principio ... )
Buscando, encontré que la opción mas usada es modificar el archivo de configuración del compilador (<arduino>/hardware/tools/avrdude.conf) para decirle que un ATmega328P(0x1e 0x95 0x0F) tiene el código de identificación correpondiente al ATmega328(0x1e 0x95 0x14)
De todas formas, esto resulta un engorro, ya que al tener que grabar código en arduino, tenemos el mismo problema, pero al revés, y tenemos que dejar el archivo como estaba.
Después de unos cuantos cambios, decidí que esto no podía seguir así. Así que decidí duplicar la información del ATmega328:
La configuración original la renombré como:
#------------------------------------------------------------
# ATmega328P
#------------------------------------------------------------
part
id = "m328p";
desc = "ATMEGA328P";
has_debugwire = yes;
flash_instr = 0xB6, 0x01, 0x11;
eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00,
0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF,
0x99, 0xF9, 0xBB, 0xAF;
stk500_devcode = 0x86;
# avr910_devcode = 0x;
signature = 0x1e 0x95 0x0F;
pagel = 0xd7;
bs2 = 0xc2;
chip_erase_delay = 9000;
pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1",
"x x x x x x x x x x x x x x x x";
chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x",
"x x x x x x x x x x x x x x x x";
timeout = 200;
stabdelay = 100;
cmdexedelay = 25;
synchloops = 32;
bytedelay = 0;
pollindex = 3;
pollvalue = 0x53;
predelay = 1;
postdelay = 1;
pollmethod = 1;
pp_controlstack =
0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
hventerstabdelay = 100;
progmodedelay = 0;
latchcycles = 5;
togglevtg = 1;
poweroffdelay = 15;
resetdelayms = 1;
resetdelayus = 0;
hvleavestabdelay = 15;
resetdelay = 15;
chiperasepulsewidth = 0;
chiperasepolltimeout = 10;
programfusepulsewidth = 0;
programfusepolltimeout = 5;
programlockpulsewidth = 0;
programlockpolltimeout = 5;
memory "eeprom"
paged = no;
page_size = 4;
size = 1024;
min_write_delay = 3600;
max_write_delay = 3600;
readback_p1 = 0xff;
readback_p2 = 0xff;
read = " 1 0 1 0 0 0 0 0",
" 0 0 0 x x x a9 a8",
" a7 a6 a5 a4 a3 a2 a1 a0",
" o o o o o o o o";
write = " 1 1 0 0 0 0 0 0",
" 0 0 0 x x x a9 a8",
" a7 a6 a5 a4 a3 a2 a1 a0",
" i i i i i i i i";
loadpage_lo = " 1 1 0 0 0 0 0 1",
" 0 0 0 0 0 0 0 0",
" 0 0 0 0 0 0 a1 a0",
" i i i i i i i i";
writepage = " 1 1 0 0 0 0 1 0",
" 0 0 x x x x a9 a8",
" a7 a6 a5 a4 a3 a2 0 0",
" x x x x x x x x";
mode = 0x41;
delay = 20;
blocksize = 4;
readsize = 256;
;
memory "flash"
paged = yes;
size = 32768;
page_size = 128;
num_pages = 256;
min_write_delay = 4500;
max_write_delay = 4500;
readback_p1 = 0xff;
readback_p2 = 0xff;
read_lo = " 0 0 1 0 0 0 0 0",
" 0 0 a13 a12 a11 a10 a9 a8",
" a7 a6 a5 a4 a3 a2 a1 a0",
" o o o o o o o o";
read_hi = " 0 0 1 0 1 0 0 0",
" 0 0 a13 a12 a11 a10 a9 a8",
" a7 a6 a5 a4 a3 a2 a1 a0",
" o o o o o o o o";
loadpage_lo = " 0 1 0 0 0 0 0 0",
" 0 0 0 x x x x x",
" x x a5 a4 a3 a2 a1 a0",
" i i i i i i i i";
loadpage_hi = " 0 1 0 0 1 0 0 0",
" 0 0 0 x x x x x",
" x x a5 a4 a3 a2 a1 a0",
" i i i i i i i i";
writepage = " 0 1 0 0 1 1 0 0",
" 0 0 a13 a12 a11 a10 a9 a8",
" a7 a6 x x x x x x",
" x x x x x x x x";
mode = 0x41;
delay = 6;
blocksize = 128;
readsize = 256;
;
memory "lfuse"
size = 1;
min_write_delay = 4500;
max_write_delay = 4500;
read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0",
"x x x x x x x x o o o o o o o o";
write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0",
"x x x x x x x x i i i i i i i i";
;
memory "hfuse"
size = 1;
min_write_delay = 4500;
max_write_delay = 4500;
read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0",
"x x x x x x x x o o o o o o o o";
write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0",
"x x x x x x x x i i i i i i i i";
;
memory "efuse"
size = 1;
min_write_delay = 4500;
max_write_delay = 4500;
read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0",
"x x x x x x x x x x x x x o o o";
write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0",
"x x x x x x x x x x x x x i i i";
;
memory "lock"
size = 1;
min_write_delay = 4500;
max_write_delay = 4500;
read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0",
"x x x x x x x x x x o o o o o o";
write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x",
"x x x x x x x x 1 1 i i i i i i";
;
memory "calibration"
size = 1;
read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x",
"0 0 0 0 0 0 0 0 o o o o o o o o";
;
memory "signature"
size = 3;
read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x",
"x x x x x x a1 a0 o o o o o o o o";
;
;
y la copiada, la dejé como:
#------------------------------------------------------------
# ATmega328
#------------------------------------------------------------
part
id = "m328";
desc = "ATMEGA328";
has_debugwire = yes;
flash_instr = 0xB6, 0x01, 0x11;
eeprom_instr = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00,
0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF,
0x99, 0xF9, 0xBB, 0xAF;
stk500_devcode = 0x86;
# avr910_devcode = 0x;
signature = 0x1e 0x95 0x14;
pagel = 0xd7;
bs2 = 0xc2;
chip_erase_delay = 9000;
pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1",
"x x x x x x x x x x x x x x x x";
chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x",
"x x x x x x x x x x x x x x x x";
timeout = 200;
stabdelay = 100;
cmdexedelay = 25;
synchloops = 32;
bytedelay = 0;
pollindex = 3;
pollvalue = 0x53;
predelay = 1;
postdelay = 1;
pollmethod = 1;
pp_controlstack =
0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
hventerstabdelay = 100;
progmodedelay = 0;
latchcycles = 5;
togglevtg = 1;
poweroffdelay = 15;
resetdelayms = 1;
resetdelayus = 0;
hvleavestabdelay = 15;
resetdelay = 15;
chiperasepulsewidth = 0;
chiperasepolltimeout = 10;
programfusepulsewidth = 0;
programfusepolltimeout = 5;
programlockpulsewidth = 0;
programlockpolltimeout = 5;
memory "eeprom"
paged = no;
page_size = 4;
size = 1024;
min_write_delay = 3600;
max_write_delay = 3600;
readback_p1 = 0xff;
readback_p2 = 0xff;
read = " 1 0 1 0 0 0 0 0",
" 0 0 0 x x x a9 a8",
" a7 a6 a5 a4 a3 a2 a1 a0",
" o o o o o o o o";
write = " 1 1 0 0 0 0 0 0",
" 0 0 0 x x x a9 a8",
" a7 a6 a5 a4 a3 a2 a1 a0",
" i i i i i i i i";
loadpage_lo = " 1 1 0 0 0 0 0 1",
" 0 0 0 0 0 0 0 0",
" 0 0 0 0 0 0 a1 a0",
" i i i i i i i i";
writepage = " 1 1 0 0 0 0 1 0",
" 0 0 x x x x a9 a8",
" a7 a6 a5 a4 a3 a2 0 0",
" x x x x x x x x";
mode = 0x41;
delay = 20;
blocksize = 4;
readsize = 256;
;
memory "flash"
paged = yes;
size = 32768;
page_size = 128;
num_pages = 256;
min_write_delay = 4500;
max_write_delay = 4500;
readback_p1 = 0xff;
readback_p2 = 0xff;
read_lo = " 0 0 1 0 0 0 0 0",
" 0 0 a13 a12 a11 a10 a9 a8",
" a7 a6 a5 a4 a3 a2 a1 a0",
" o o o o o o o o";
read_hi = " 0 0 1 0 1 0 0 0",
" 0 0 a13 a12 a11 a10 a9 a8",
" a7 a6 a5 a4 a3 a2 a1 a0",
" o o o o o o o o";
loadpage_lo = " 0 1 0 0 0 0 0 0",
" 0 0 0 x x x x x",
" x x a5 a4 a3 a2 a1 a0",
" i i i i i i i i";
loadpage_hi = " 0 1 0 0 1 0 0 0",
" 0 0 0 x x x x x",
" x x a5 a4 a3 a2 a1 a0",
" i i i i i i i i";
writepage = " 0 1 0 0 1 1 0 0",
" 0 0 a13 a12 a11 a10 a9 a8",
" a7 a6 x x x x x x",
" x x x x x x x x";
mode = 0x41;
delay = 6;
blocksize = 128;
readsize = 256;
;
memory "lfuse"
size = 1;
min_write_delay = 4500;
max_write_delay = 4500;
read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0",
"x x x x x x x x o o o o o o o o";
write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0",
"x x x x x x x x i i i i i i i i";
;
memory "hfuse"
size = 1;
min_write_delay = 4500;
max_write_delay = 4500;
read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0",
"x x x x x x x x o o o o o o o o";
write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0",
"x x x x x x x x i i i i i i i i";
;
memory "efuse"
size = 1;
min_write_delay = 4500;
max_write_delay = 4500;
read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0",
"x x x x x x x x x x x x x o o o";
write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0",
"x x x x x x x x x x x x x i i i";
;
memory "lock"
size = 1;
min_write_delay = 4500;
max_write_delay = 4500;
read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0",
"x x x x x x x x x x o o o o o o";
write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x",
"x x x x x x x x 1 1 i i i i i i";
;
memory "calibration"
size = 1;
read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x",
"0 0 0 0 0 0 0 0 o o o o o o o o";
;
memory "signature"
size = 3;
read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x",
"x x x x x x a1 a0 o o o o o o o o";
;
;
y entonces encontré la referencia que buscaba en <arduino>/hardware/tools/boards.txt :
Copiando la sección correspondiente, y cambiando las identificaciones, tenemos:
##############################################################
atmega328.name=Arduino Duemilanove w/ ATmega328
atmega328.upload.protocol=arduino
atmega328.upload.maximum_size=30720
atmega328.upload.speed=57600
atmega328.bootloader.low_fuses=0xFF
atmega328.bootloader.high_fuses=0xDA
atmega328.bootloader.extended_fuses=0x05
atmega328.bootloader.path=atmega
atmega328.bootloader.file=ATmegaBOOT_168_atmega328.hex
atmega328.bootloader.unlock_bits=0x3F
atmega328.bootloader.lock_bits=0x0F
atmega328.build.mcu=atmega328
atmega328.build.f_cpu=16000000L
atmega328.build.core=arduino
atmega328.build.variant=standard
##############################################################
atmega328p.name=Arduino Duemilanove w/ ATmega328P
atmega328p.upload.protocol=arduino
atmega328p.upload.maximum_size=30720
atmega328p.upload.speed=57600
atmega328p.bootloader.low_fuses=0xFF
atmega328p.bootloader.high_fuses=0xDA
atmega328p.bootloader.extended_fuses=0x05
atmega328p.bootloader.path=atmega
atmega328p.bootloader.file=ATmegaBOOT_168_atmega328.hex
atmega328p.bootloader.unlock_bits=0x3F
atmega328p.bootloader.lock_bits=0x0F
atmega328p.build.mcu=atmega328p
atmega328p.build.f_cpu=16000000L
atmega328p.build.core=arduino
atmega328p.build.variant=standard
Ahora, en la selección de placas arduino, tenemos el Duemilanove ATmega328P (nombre cambiado, opciones originales) y el Duemilanove ATmega328 (Que es el nuevo, y el que tenemos que seleccionar como destino para grabar el BootLoader en los nuevos integrados).
y con esto creía que sería suficiente, y por suerte así fué:
Para compilar el código seleccionando el ATmega328, tengo errores de id no soportado, y necesitaría tocar mas cosas, pero resulta que el ATmega328 con el BootLoader cargado en la placa de arduino se identifica como si fuese un ATmega328P, por lo que respecta al compilador, así que lo dejé estar.
Lo que ya no me pareció tan normal, es que de cada 10 veces que intentaba grabar el BootLoader, 9 veces recibía un error de sincronismo.
Y ya no digo nada cuando intenté grabar un ATmega328 poniendo en la placa base de arduino otro igual ya programado, misión : imposible.
Entonces volví a la carga, empezé a revisar el código del programador, y lo que no me gustó es que pusiesen un delay() en la función heartbeat()
void heartbeat() {
if (hbval > 192) hbdelta = -hbdelta;
if (hbval < 32) hbdelta = -hbdelta;
hbval += hbdelta;
analogWrite(LED_HB, hbval);
delay(40);
}
No tenía ni tengo intención de reescribir el código, pero algo había que hacer.
Tras varias pruebas, funciona perfectamente así :
void heartbeat() {
if (hbval > 192) hbdelta = -hbdelta;
if (hbval < 32) hbdelta = -hbdelta;
hbval += hbdelta;
analogWrite(LED_HB, hbval);
delay(30);
}
Pues por hoy, es suficiente, buena suerte y a disfrutar el código y el hardware.