Paso 6: Añadir Arduino, Chips y código!
Ahora puede programar Arduino Bootloaders desde dentro del IDE y también las fichas AVR con AVRDUDE, pero voy a explicar cómo hacer todo eso en un producto menos orientado Instructable.
Este bosquejo convierte el Arduino en un AVRISP
usando los siguientes pines:
10: reset del esclavo
11: MOSI
12: MISO
13: SCKPoner un LED (con resistencia) en los siguientes pines:
7: error: se ilumina si algo sale mal (uso rojo si tiene sentido)
8: programación - en comunicación con el esclavo
6: latido del corazón - muestra que se está ejecutando el programador (eliminado, ver notas a continuación)
Opcional - Piezo altavoz en el pin A3
//
Octubre de 2009 por David A. Mellis
-Añadido soporte para el comando de lectura de la firma
//
De febrero de 2009 por Randall Bohn
-Añadido soporte para escritura a EEPROM (lo que tomó tanto tiempo?)
Los usuarios de Windows deben considerar avrdude de WinAVR en vez de la
AVRDUDE incluido con el software de Arduino.
//
De enero de 2008 por Randall Bohn
-Gracias a Amplificar por ayudarme con el protocolo STK500
-El AVRISP/STK500 (mk I) protocolo se utiliza en el bootloader de arduino
-Las funciones SPI aquí fueron desarrolladas para el programador de AVR910_ARD
-Más información en http://code.google.com/p/mega-isp
//
De marzo de 2012 - William Phelps
modificar para trabajar con Arduino IDE 1.0 que tiene un puerto serie más corto recibe el almacenador intermediario
getEOP() ahora recibe solicitud completa antes de avrisp() para procesarlo
Serial.Print((Char) xxx) cambiado a Serial.write(xxx)
uint8_t cambiada a byte
añadido soporte para altavoz piezoeléctrico
movido el LED Pmode A0
quitar "heartbeat" en el pin 6, añadido un pitido corto de ERROR LED en su lugar
¿Por qué es que PROG_FLASH y PROG_DATA no hacen nada???
Probado con el IDE de Arduino 22 y 1.0
IDE 22-5148 bytes
IDE 1.0-5524 bytes!Enero de 2014 - Ben gris
Poner el latido conducido detrás y cambiado un poco alrededor del pins para los LEDs.VELOCIDAD LENTA CHIP ERASE Y QUEMA EL FUSIBLE
//
Activar LOW_SPEED para que pueda borrar las fichas que de lo contrario, no
para que correr con un reloj demasiado lento para el programador.
//
Esto me permitió recuperar varios ATMega328 que ningún cargador de arranque y la
primera instrucción fue ajustar el reloj a la velocidad más lenta. Generalmente esto
tipo de recuperación requiere de alto voltaje de programación, pero este truco hará
muy bien.
//
Cómo proceder:
// 1. Active LOW_SPEED y cargarlo al programador.
// 2. Borrar y quemar los fusibles en la uC de destino. Ejemplo para ATMega328:
Arduino-1.0.1/Hardware/Tools/AVRDUDE-Carduino-1.0.1/hardware/tools/avrdude.conf-patmega328p-cstk500v1 -P /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A900cf1Q-if00-port0-b19200 -e - Ulock: w: 0x3F: m - Uefuse: w: 0 x 05: m - Uhfuse: w: 0xDA: m - Ulfuse: w: 0xF7: m
// 3. Comentario de LOW_SPEED y carga hacia el programador.
// 4. Programa de la uC de objetivo como de costumbre. Ejemplo:
Arduino-1.0.1/Hardware/Tools/AVRDUDE-Carduino-1.0.1/hardware/tools/avrdude.conf-patmega328p-cstk500v1 -P /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A900cf1Q-if00-port0-b19200-Uflash:w:firmware.hex:i
//
Nota 1: EXTRA_SPI_DELAY fue agregado para hacerle frenar SPI más. Puedes
Juega con el valor si no te funciona con el valor por defecto.
Nota 2: LOW_SPEED a lijar sólo a borrar el chip y quemar los fusibles! Se
fracasará si intenta programar el uC objetivo así!
#define LOW_SPEED
#ifdef LOW_SPEED
#define EXTRA_SPI_DELAY 125
#else
#define EXTRA_SPI_DELAY 0
#endif
#include "pins_arduino.h" / / define SS, MOSI, MISO SCK
#define RESET SS
#define LED_ERR 7
#define LED_PMODE 8
#define LED_HB 6
#define PIEZO A3
#define HWVER 2
#define SWMAJ 1
#define SWMIN 18
Definiciones de STK
byte const STK_OK = 0 x 10;
byte const STK_FAILED = 0x11;
byte const STK_UNKNOWN = 0x12;
byte const STK_INSYNC = 0x14;
byte const STK_NOSYNC = 0x15;
byte const CRC_EOP = 0 x 20; OK es un espacio...
byte const STK_GET_SYNC = 0 x 30;
byte const STK_GET_SIGNON = 0x31;
byte const STK_GET_PARM = 0 x 41;
byte const STK_SET_PARM = 0x42;
byte const STK_SET_PARM_EXT = 0x45;
byte const STK_PMODE_START = 0 x 50;
byte const STK_PMODE_END = 0x51;
byte const STK_SET_ADDR = 0x55;
byte const STK_UNIVERSAL = 0x56;
byte const STK_PROG_FLASH = 0x60;
byte const STK_PROG_DATA = 0x61;
byte const STK_PROG_PAGE = 0x64;
byte const STK_READ_PAGE = 0x74;
byte const STK_READ_SIGN = 0 x 75;
//// TONES ==========================================
Comenzar por definir la relación entre
Nota, período y frecuencia.
#define c 3830 / / 261 Hz
#define d 3400 / / 294 Hz
#define e 3038 / / Hz 329
#define f 2864 / / 349 Hz
#define g 2550 / / 392 Hz
#define a 2272 / / 440 Hz
#define b 2028 / / 493 Hz
#define C 1912 / / 523 Hz
pulso vacío (pin int, int veces);
error de int = 0;
pmode int = 0;
Dirección para la lectura y la escritura, por comando STK_SET_ADDR
int _addr;
byte _buffer [256]; buffer del puerto serie
pBuffer int = 0; puntero de búfer
iBuffer int = 0; Índice de amortiguamiento
buff de Byte [256]; búfer temporal
Boolean EOP_SEEN = false;
void setup() {}
Serial.Begin(19200);
pinMode (PIEZO, salida);
BEEP(1700, 40);
EOP_SEEN = false;
iBuffer = pBuffer = 0;
pinMode (LED_PMODE, salida);
pulso (LED_PMODE, 2);
pinMode (LED_ERR, salida);
pulso (LED_ERR, 2);
pinMode (LED_HB, salida);
pulso (LED_HB, 2);
pinMode (9, salida);
configuración de alta frecuencia PWM en el pin 9 (temporizador 1)
ciclo de trabajo 50% -> 8 MHz
OCR1A = 0;
ICR1 = 1;
OC1A salida PWM rápida
TCCR1A = _BV(WGM11) | _BV(COM1A1);
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); sin prescaler de reloj
}
#define beget16(addr) (* addr * 256 + *(addr+1))
typedef struct param {}
devicecode de bytes;
revisión de bytes;
progtype de bytes;
parmode de bytes;
byte de la interrogación;
selftimed de bytes;
lockbytes bytes;
fusebytes de bytes;
int flashpoll;
int eeprompoll;
int pagesize;
int eepromsize;
int FlashTamaño;
}
parámetro;
parámetro param;
Esto proporciona un latido en el pin 6, por lo que puede decir que el software se está ejecutando.
hbval bytes = 128;
int8_t hbdelta = 4;
void heartbeat() {}
Si (hbval > 192) hbdelta = - hbdelta;
Si hbdelta (hbval < 32) = - hbdelta;
Si hbdelta (hbval > 250) = - hbdelta;
Si hbdelta (hbval < 10) = - hbdelta;
hbval += hbdelta;
analogWrite (LED_HB, hbval);
Delay(20);
}
void getEOP() {}
minL int = 0;
byte avrch = 0;
bl byte = 0;
mientras (!. EOP_SEEN) {}
mientras que (Serial.available() > 0) {}
ch byte = Serial.read();
_buffer [iBuffer] = ch;
iBuffer = (++ iBuffer) % 256; incremento y abrigo
Si (iBuffer == 1) avrch = ch; guardar del comando
Si ((avrch == STK_PROG_PAGE) & & (iBuffer == 3)) {}
minL = 256 * _buffer [1] [2] de _buffer + 4;
}
Si ((iBuffer>minL) & & (ch == CRC_EOP)) {}
EOP_SEEN = true;
}
}
if (!. EOP_SEEN) {}
Heartbeat(); el LED de latido de luz
Si (bl == 100) {}
Pulse(LED_ERR,1,10); parpadea el LED rojo
// bl = 0;
// }
BL ++;
Delay(10);
}
}
}
serialEvent no utilizada sketch sería compatible con versiones anteriores del IDE
void serialEvent() {}
minL int = 0;
byte avrch = 0;
mientras que (Serial.available() > 0)
// {
ch byte = Serial.read();
_buffer [iBuffer] = ch;
iBuffer = (++ iBuffer) % 256; incremento y abrigo
Si (iBuffer == 1) avrch = ch; guardar del comando
Si ((avrch == STK_PROG_PAGE) & & (iBuffer == 3)) {}
minL = 256 * _buffer [1] [2] de _buffer + 4;
// }
Si ((iBuffer>minL) & & (ch == CRC_EOP)) {}
EOP_SEEN = true;
// }
// }
//}
void loop(void) {}
¿pmode está activa?
Si (pmode) digitalWrite (LED_PMODE, alto);
Else digitalWrite (LED_PMODE, bajo);
digitalWrite (LED_PMODE, bajo);
¿hay un error?
Si (error) digitalWrite (LED_ERR, alto);
Else digitalWrite (LED_ERR, bajo);
getEOP();
¿nosotros hemos recibido una solicitud completa? (termina con CRC_EOP)
Si (EOP_SEEN) {}
digitalWrite (LED_PMODE, alto);
EOP_SEEN = false;
avrisp();
iBuffer = pBuffer = 0; reiniciar el buffer
}
}
{} de getch() bytes
Si (pBuffer == iBuffer) {/ / spin hasta datos disponibles???
pulso (LED_ERR, 1);
BEEP(1700, 20);
error ++;
volver -1;
}
ch byte = _buffer [pBuffer]; obtener siguiente char
pBuffer = (++ pBuffer) % 256; incremento y abrigo
volver ch;
}
void readbytes (int n) {}
para (int x = 0; x < n; x ++) {}
Buff [x] = getch();
}
}
#define PTIME 20
pulso vacío (pin int, int veces, ptime int) {}
{}
digitalWrite (pin, HIGH);
Delay(ptime);
digitalWrite (pin, LOW);
Delay(ptime);
veces--;
}
mientras que (veces > 0);
}
{} void pulso (pin int, int veces)
pulso (pin, veces, 50);
}
void spi_init() {}
byte x;
SPCR = 0X53;
#ifdef LOW_SPEED
SPCR = SPCR| B00000011;
#endif
x = SPSR;
x = SPDR;
}
void spi_wait() {}
{}
}
mientras (! () SPSR & (1 << SPIF)));
}
byte spi_send (byte b) {}
respuesta de bytes;
#ifdef LOW_SPEED
CLI();
CLKPR = B10000000;
CLKPR = B00000011;
SEI();
#endif
SPDR = b;
spi_wait();
respuesta = SPDR;
#ifdef LOW_SPEED
CLI();
CLKPR = B10000000;
CLKPR = B00000000;
SEI();
#endif
volver a contestar;
}
spi_transaction de bytes (byte a byte b, c de byte, byte d) {}
byte n;
spi_send(a);
n=spi_send(b);
Si (n! = un) error = -1;
n=spi_send(c);
volver spi_send(d);
}
void replyOK() {}
Si (EOP_SEEN == true) {}
Si (CRC_EOP == getch()) {/ EOP debe tener los siguiente char
Serial.Write(STK_INSYNC);
Serial.Write(STK_OK);
}
Else {}
pulso (LED_ERR, 2);
Serial.Write(STK_NOSYNC);
error ++;
}
}
void breply (byte b) {}
Si (CRC_EOP == getch()) {/ EOP debe tener los siguiente char
Serial.Write(STK_INSYNC);
Serial.Write(b);
Serial.Write(STK_OK);
}
Else {}
Serial.Write(STK_NOSYNC);
error ++;
}
}
void get_parameter (byte c) {}
{Switch(c)}
caso 0 x 80:
breply(HWVER);
rotura;
caso 0x81:
breply(SWMAJ);
rotura;
caso 0x82:
breply(SWMIN);
rotura;
caso 0x93:
breply('S'); Programador serial
rotura;
por defecto:
breply(0);
}
}
void set_parameters() {}
llamar a esto después de leer el paquete de parámetro en [buff]
param.devicecode = buff [0];
param.revision = buff [1];
param.progtype = buff [2];
param.parmode = buff [3];
param.polling = buff [4];
param.selftimed = buff [5];
param.lockbytes = buff [6];
param.fusebytes = buff [7];
param.flashpoll = buff [8];
ignorar buff [9] (= buff[8])
getch(); Deseche el segundo valor
ADVERTENCIA: no está seguro sobre el orden de bytes de los siguientes
los siguientes son 16 pedacitos (endian grande)
param.eeprompoll = beget16 (& buff[10]);
param.PageSize = beget16 (& buff[12]);
param.eepromsize = beget16 (& buff[14]);
32 bits FlashTamaño (endian grande)
param.flashsize = buff [16] * 0x01000000
+ buff [17] * 0x00010000
+ buff [18] * 0x00000100
+ buff [19];
}
void start_pmode() {}
spi_init();
Tras retrasos pueden no funcionar en todos los destinos...
pinMode (RESET, salida);
digitalWrite (RESET, alto);
pinMode (SCK, salida);
digitalWrite (SCK, LOW);
Delay(50+EXTRA_SPI_DELAY);
digitalWrite (RESET, LOW);
Delay(50+EXTRA_SPI_DELAY);
pinMode (MISO, entrada);
pinMode (MOSI, salida);
spi_transaction (0xAC, 0x53, 0 x 00, 0 x 00);
PMODE = 1;
}
void end_pmode() {}
pinMode (MISO, entrada);
pinMode (MOSI, entrada);
pinMode (SCK, entrada);
pinMode (RESET, entrada);
PMODE = 0;
}
void universal() {}
int w;
ch de bytes;
para (w = 0; w < 4; w ++) {}
Buff [w] = getch();
// }
readbytes(4);
CH = spi_transaction (buff [0] [1] a buff, buff [2], buff[3]);
breply(CH);
}
{} void flash (hilo de byte, int addr, datos byte)
spi_transaction (0 x 40 + 8 * hilo, addr >> 8 & 0xFF, addr & 0xFF, datos);
}
{} void commit (int addr)
spi_transaction (0x4C, (addr >> 8) & 0xFF, addr & 0xFF, 0);
}
#define _current_page(x) (aquí & 0xFFFFE0)
int current_page (int addr) {}
Si (param.pagesize == 32) volver addr & 0xFFFFFFF0;
Si (param.pagesize == 64) volver addr & 0xFFFFFFE0;
Si (param.pagesize == 128) volver addr & 0xFFFFFFC0;
Si (param.pagesize == 256) volver addr & 0xFFFFFF80;
volver addr;
}
byte write_flash (int longitud) {}
Si (param.pagesize < 1) {}
volver STK_FAILED;
}
Si (param.pagesize! = 64) vuelta STK_FAILED;
Página de int = current_page(_addr);
int x = 0;
mientras que (x < longitud) {}
Si (página! = {current_page(_addr))}
Commit(Page);
Página = current_page(_addr);
}
Flash (bajo, _addr, buff[x++]);
Flash (alta, _addr, buff[x++]);
_addr ++;
}
Commit(Page);
volver STK_OK;
}
byte write_eeprom (int longitud) {}
Aquí es una dirección de palabra, así que usamos aquí * 2
Esto escribe byte por byte,
escritura de página puede ser más rápido (4 bytes a la vez)
para (int x = 0; x < longitud; x ++) {}
spi_transaction (0xC0, 0 x 00, _addr * 2 + x, buff[x]);
Delay(45);
}
volver STK_OK;
}
void program_page() {}
resultado de bytes = STK_FAILED;
int longitud = 256 * getch() + getch();
Si (longitud > 256) {}
Serial.Write(STK_FAILED);
error ++;
retorno;
}
char memtype = (char)getch();
para (int x = 0; x < longitud; x ++) {}
Buff [x] = getch();
// }
readbytes(length);
Si (CRC_EOP == {} getch())
Serial.Write(STK_INSYNC);
interruptor (memtype) {}
caso 'E':
resultado = (byte)write_eeprom(length);
rotura;
caso 'F':
resultado = (byte)write_flash(length);
rotura;
}
Serial.Write(Result);
Si (resultado! = STK_OK) {}
error ++;
}
}
Else {}
Serial.Write(STK_NOSYNC);
error ++;
}
}
byte flash_read (hilo de byte, int addr) {}
volver spi_transaction (0 x 20 + hilo * 8,
(addr >> 8) & 0xFF,
addr y 0xFF,
0);
}
char flash_read_page(int length) {}
para (int x = 0; x < longitud; x+= 2) {}
byte bajo = flash_read (bajo, _addr);
Serial.Write (bajo);
byte alto = flash_read (altas, _addr);
Serial.Write (alto);
_addr ++;
}
volver STK_OK;
}
char eeprom_read_page(int length) {}
aquí otra vez tenemos una dirección de palabra
para (int x = 0; x < longitud; x ++) {}
ee de byte = spi_transaction (0xA0, 0 x 00, _addr * 2 + x, 0xFF);
Serial.Write (ee);
}
volver STK_OK;
}
void read_page() {}
resultado de byte = (byte) STK_FAILED;
int longitud = 256 * getch() + getch();
char memtype = getch();
Si (CRC_EOP! = getch()) {}
Serial.Write(STK_NOSYNC);
retorno;
}
Serial.Write(STK_INSYNC);
Si (memtype == 'F') resultado = flash_read_page(length);
Si (memtype == 'E') resultado = eeprom_read_page(length);
Serial.Write(Result);
retorno;
}
void read_signature() {}
Si (CRC_EOP! = getch()) {}
Serial.Write(STK_NOSYNC);
error ++;
retorno;
}
Serial.Write(STK_INSYNC);
byte alto = spi_transaction (0 x 30, 0 x 00, 0 x 00, 0 x 00);
Serial.Write(High);
medio byte = spi_transaction (0 x 30, 0 x 00, 0 x 01, 0 x 00);
Serial.Write(Middle);
byte bajo = spi_transaction (0 x 30, 0 x 00, 0 x 02, 0 x 00);
Serial.Write(Low);
Serial.Write(STK_OK);
}
//////////////////////////////////////////
//////////////////////////////////////////
////////////////////////////////////
////////////////////////////////////
int avrisp() {}
los datos de byte, bajo, alto;
byte avrch = getch();
interruptor (avrch) {}
caso STK_GET_SYNC: / / obtener en sincronía
replyOK();
rotura;
caso STK_GET_SIGNON: / / obtener la muestra
Si (getch() == CRC_EOP) {}
Serial.Write(STK_INSYNC);
Serial.Write ("AVR ISP");
Serial.Write(STK_OK);
}
rotura;
caso STK_GET_PARM: / / 0 x 41
get_parameter(getch());
rotura;
caso STK_SET_PARM: / / 0x42
readbytes(20);
set_parameters();
replyOK();
rotura;
caso STK_SET_PARM_EXT: / / extendido parámetros - ignorar por ahora
readbytes(5);
replyOK();
rotura;
caso STK_PMODE_START: / / 0 x 50
BEEP(2272, 20);
start_pmode();
replyOK();
rotura;
caso STK_PMODE_END: //0x51
BEEP(1912, 50);
error = 0;
end_pmode();
replyOK();
rotura;
caso STK_SET_ADDR: / / 0x55
_addr = getch() + 256 * getch();
replyOK();
rotura;
caso STK_UNIVERSAL: //UNIVERSAL 0x56
universal();
rotura;
caso STK_PROG_FLASH: //STK_PROG_FLASH???
bajo = getch();
alta = getch();
replyOK();
rotura;
caso STK_PROG_DATA: //STK_PROG_DATA???
datos = getch();
replyOK();
rotura;
caso STK_PROG_PAGE: //STK_PROG_PAGE
BEEP(1912, 20);
program_page();
rotura;
caso STK_READ_PAGE: //STK_READ_PAGE
read_page();
rotura;
caso STK_READ_SIGN: //STK_READ_SIGN
read_signature();
rotura;
esperando un comando, no CRC_EOP
Esto es cómo podemos conseguir detrás en la sinc.
caso CRC_EOP:
Serial.Write(STK_NOSYNC);
rotura;
nada más vamos a volver STK_UNKNOWN
por defecto:
Si (CRC_EOP == getch())
Serial.Write(STK_UNKNOWN);
otra cosa
Serial.Write(STK_NOSYNC);
}
}
un pitido sin usar PWM
{} void beep (int tono, larga duración)
tiempo transcurrido = 0;
mientras que (transcurrido < (duración * 10000)) {}
digitalWrite (PIEZO, alto);
delayMicroseconds(tone / 2);
digitalWrite (PIEZO, LOW);
delayMicroseconds(tone / 2);
Hacer un seguimiento de cuánto tiempo hemos pulsado
transcurrido += tono;
// }
//}