2009年2月28日 星期六

Arduino Bootloader Copier

If you need more than one Arduino, you can build this cheaper Arduino by copying the bootloader into the Atmega8 using the following circuit.




Photo shows the Arduino Bootloader copier. I am using a Duemilanove.

In Arduino version 0011 IDE, select BOARD = Arduino Diecimila. Upload the script to the Duemilanove.



The script is as follows:
/* ARDUINO BOOT-CLONER
* -------------------
*
* Comments
*
* The ATmega8 fuse bytes and bootloader are copied
* from the chip on the Arduino, to a new blank ATmega8.
*
* / See app note DOC0943.pdf "AVR910: In-System Programming"
* / See app note DOC2486.pdf "ATmega8 Documentation" - The chapter on Memory Programming, p.237/240
* / iHex flash file format information "http://www.scienceprog.com/shelling-the-intel-8-bit-hex-file-format/"
* / PROGMEM and pgmspace.h usage information:
* "http://www.scienceprog.com/simple-routine-how-to-store-data-in-microcontroller-flash-and-read-from-it-using-winavr/"
*
* Notes:
* Contrary to what I originally thought, the bootloader resides at the end of flash memory.
*
* The program was too big, so some of the extra functions are commented out to save memory.
*
* This program hasn't been optimized for speed, but it's still pretty quick. Some of the delays are unnecessary.
*
* Your bootloader flash probably can't be read; the default lock bits prevent that. (0xCF ~ bit 6)
* This boot-cloner writes different lock bits to the new ATmega8; so the boot flash section *could* be read
* when run from the new chip. (0xEF)
* With the bootloader flash unlocked, you could remove the bootloader[] table and save a bunch of memory.
*
* (copyright notice) 2007 by Amplificar
*/

// need this header for PROGMEM and the command pgm_read_byte()
// which reads bytes from flash program memory.
// you can view the header's contents, which are in arduino->tools->avr->avr->include->avr->pgmspace.h
#include

// CONSTANT DECLARATION

// target microcontroller constants
#define FLASH_MAX 8192
// the flash size
#define PAGE_WORDS 32
// the number of words per page
#define BOOT_PAGE 112
// the starting page number, where the bootloader lurks (8192/2/32=128, 1024/2/32=16, 128-16=112)

// the bootloader data; distributed with arduino ide 0005
// this is the extracted data from the ihex file
// PROGMEM forces this data to be kept in the flash - and not get loaded into ram (that'd be bad)
// this table has to be read back using "byte=pgm_read_byte(&bootloader[index]);"
#define BOOT_MAX 1019
const unsigned char bootloader[] PROGMEM= {
0x12,0xC0,0x2B,0xC0,0x2A,0xC0,0x29,0xC0,0x28,0xC0,0x27,0xC0,0x26,0xC0,0x25,0xC0,
0x24,0xC0,0x23,0xC0,0x22,0xC0,0x21,0xC0,0x20,0xC0,0x1F,0xC0,0x1E,0xC0,0x1D,0xC0,
0x1C,0xC0,0x1B,0xC0,0x1A,0xC0,0x11,0x24,0x1F,0xBE,0xCF,0xE5,0xD4,0xE0,0xDE,0xBF,
0xCD,0xBF,0x10,0xE0,0xA0,0xE6,0xB0,0xE0,0xE6,0xEF,0xFF,0xE1,0x02,0xC0,0x05,0x90,
0x0D,0x92,0xA2,0x36,0xB1,0x07,0xD9,0xF7,0x11,0xE0,0xA2,0xE6,0xB0,0xE0,0x01,0xC0,
0x1D,0x92,0xAA,0x36,0xB1,0x07,0xE1,0xF7,0x4B,0xC0,0xD2,0xCF,0xEF,0x92,0xFF,0x92,
0x0F,0x93,0x1F,0x93,0xEE,0x24,0xFF,0x24,0x87,0x01,0x5F,0x99,0x15,0xC0,0x08,0x94,
0xE1,0x1C,0xF1,0x1C,0x01,0x1D,0x11,0x1D,0x81,0xE0,0xE8,0x16,0x82,0xE1,0xF8,0x06,
0x8A,0xE7,0x08,0x07,0x80,0xE0,0x18,0x07,0x28,0xF0,0xE0,0x91,0x62,0x00,0xF0,0x91,
0x63,0x00,0x09,0x95,0x5F,0x9B,0xEB,0xCF,0x8C,0xB1,0x99,0x27,0x87,0xFD,0x90,0x95,
0x1F,0x91,0x0F,0x91,0xFF,0x90,0xEF,0x90,0x08,0x95,0x5D,0x9B,0xFE,0xCF,0x8C,0xB9,
0x08,0x95,0xD4,0xDF,0x80,0x32,0x21,0xF4,0x84,0xE1,0xF7,0xDF,0x80,0xE1,0xF5,0xDF,
0x08,0x95,0x08,0x95,0xCF,0x93,0xC8,0x2F,0xC9,0xDF,0x80,0x32,0x31,0xF4,0x84,0xE1,
0xEC,0xDF,0x8C,0x2F,0xEA,0xDF,0x80,0xE1,0xE8,0xDF,0xCF,0x91,0x08,0x95,0xCF,0x93,
0x88,0x23,0x21,0xF0,0xC8,0x2F,0xBA,0xDF,0xC1,0x50,0xE9,0xF7,0xCF,0x91,0x08,0x95,
0xCF,0xE5,0xD4,0xE0,0xDE,0xBF,0xCD,0xBF,0x00,0x00,0x10,0xBC,0x83,0xE3,0x89,0xB9,
0x88,0xE1,0x8A,0xB9,0x86,0xE8,0x80,0xBD,0xBD,0x9A,0x10,0x92,0x68,0x01,0x30,0xE2,
0x2F,0xE0,0x88,0xB3,0x83,0x27,0x88,0xBB,0x80,0xE0,0x90,0xE0,0x01,0x97,0xF1,0xF7,
0x21,0x50,0x27,0xFF,0xF6,0xCF,0x20,0xE1,0x20,0x93,0x68,0x01,0x97,0xDF,0x80,0x33,
0x09,0xF4,0x44,0xC0,0x81,0x33,0xA1,0xF4,0x91,0xDF,0xC8,0x2F,0x80,0x32,0xB1,0xF7,
0x84,0xE1,0xB3,0xDF,0x81,0xE4,0xB1,0xDF,0x86,0xE5,0xAF,0xDF,0x82,0xE5,0xAD,0xDF,
0x8C,0x2F,0xAB,0xDF,0x89,0xE4,0xA9,0xDF,0x83,0xE5,0xA7,0xDF,0x80,0xE5,0x2E,0xC1,
0x80,0x34,0x29,0xF4,0x7B,0xDF,0x86,0x38,0x48,0xF1,0x78,0xDF,0x27,0xC0,0x81,0x34,
0x71,0xF4,0x74,0xDF,0x80,0x38,0x11,0xF4,0x82,0xE0,0x28,0xC1,0x81,0x38,0x11,0xF4,
0x81,0xE0,0x24,0xC1,0x82,0x38,0x09,0xF0,0x20,0xC1,0x82,0xE1,0x1F,0xC1,0x82,0x34,
0x11,0xF4,0x84,0xE1,0x03,0xC0,0x85,0x34,0x19,0xF4,0x85,0xE0,0xA0,0xDF,0x0E,0xC0,
0x80,0x35,0x61,0xF0,0x81,0x35,0x51,0xF0,0x82,0x35,0x41,0xF0,0x85,0x35,0x41,0xF4,
0x55,0xDF,0x80,0x93,0x64,0x00,0x52,0xDF,0x80,0x93,0x65,0x00,0x7A,0xDF,0xB6,0xCF,
0x86,0x35,0x19,0xF4,0x84,0xE0,0x8B,0xDF,0x00,0xC1,0x84,0x36,0x09,0xF0,0x9D,0xC0,
0x45,0xDF,0x80,0x93,0x67,0x01,0x42,0xDF,0x80,0x93,0x66,0x01,0x80,0x91,0x69,0x01,
0x8E,0x7F,0x80,0x93,0x69,0x01,0x3A,0xDF,0x85,0x34,0x29,0xF4,0x80,0x91,0x69,0x01,
0x81,0x60,0x80,0x93,0x69,0x01,0xC0,0xE0,0xD0,0xE0,0x80,0x91,0x66,0x01,0x90,0x91,
0x67,0x01,0xC8,0x17,0xD9,0x07,0x70,0xF4,0x06,0xE6,0x10,0xE0,0x27,0xDF,0xF8,0x01,
0x81,0x93,0x8F,0x01,0x21,0x96,0x80,0x91,0x66,0x01,0x90,0x91,0x67,0x01,0xC8,0x17,
0xD9,0x07,0xA0,0xF3,0x1B,0xDF,0x80,0x32,0x09,0xF0,0x80,0xCF,0x80,0x91,0x69,0x01,
0x80,0xFF,0x26,0xC0,0xC0,0xE0,0xD0,0xE0,0x80,0x91,0x66,0x01,0x90,0x91,0x67,0x01,
0xC8,0x17,0xD9,0x07,0x08,0xF0,0x5F,0xC0,0x06,0xE6,0x10,0xE0,0xF8,0x01,0x61,0x91,
0x8F,0x01,0x80,0x91,0x64,0x00,0x90,0x91,0x65,0x00,0xC2,0xD0,0x80,0x91,0x64,0x00,
0x90,0x91,0x65,0x00,0x01,0x96,0x90,0x93,0x65,0x00,0x80,0x93,0x64,0x00,0x21,0x96,
0x80,0x91,0x66,0x01,0x90,0x91,0x67,0x01,0xC8,0x17,0xD9,0x07,0x38,0xF3,0x43,0xC0,
0xF8,0x94,0xE1,0x99,0xFE,0xCF,0x11,0x27,0xE0,0x91,0x64,0x00,0xF0,0x91,0x65,0x00,
0xEE,0x0F,0xFF,0x1F,0xC6,0xE6,0xD0,0xE0,0x80,0x91,0x66,0x01,0x90,0x91,0x67,0x01,
0x80,0xFF,0x01,0xC0,0x01,0x96,0x10,0x30,0x51,0xF4,0x22,0xD0,0x03,0xE0,0x00,0x93,
0x57,0x00,0xE8,0x95,0x1D,0xD0,0x01,0xE1,0x00,0x93,0x57,0x00,0xE8,0x95,0x09,0x90,
0x19,0x90,0x16,0xD0,0x01,0xE0,0x00,0x93,0x57,0x00,0xE8,0x95,0x13,0x95,0x10,0x32,
0x58,0xF0,0x11,0x27,0x0D,0xD0,0x05,0xE0,0x00,0x93,0x57,0x00,0xE8,0x95,0x08,0xD0,
0x01,0xE1,0x00,0x93,0x57,0x00,0xE8,0x95,0x32,0x96,0x02,0x97,0x39,0xF0,0xDB,0xCF,
0x00,0x91,0x57,0x00,0x01,0x70,0x01,0x30,0xD9,0xF3,0x08,0x95,0x10,0x30,0x11,0xF0,
0x02,0x96,0xE7,0xCF,0x11,0x24,0x84,0xE1,0x59,0xC0,0x84,0x37,0x09,0xF0,0x49,0xC0,
0xA5,0xDE,0x80,0x93,0x67,0x01,0xA2,0xDE,0x80,0x93,0x66,0x01,0x9F,0xDE,0x90,0x91,
0x69,0x01,0x85,0x34,0x21,0xF4,0x91,0x60,0x90,0x93,0x69,0x01,0x0D,0xC0,0x9E,0x7F,
0x90,0x93,0x69,0x01,0x80,0x91,0x64,0x00,0x90,0x91,0x65,0x00,0x88,0x0F,0x99,0x1F,
0x90,0x93,0x65,0x00,0x80,0x93,0x64,0x00,0x89,0xDE,0x80,0x32,0x09,0xF0,0xEE,0xCE,
0x84,0xE1,0xAB,0xDE,0xC0,0xE0,0xD0,0xE0,0x80,0x91,0x66,0x01,0x90,0x91,0x67,0x01,
0xC8,0x17,0xD9,0x07,0x60,0xF5,0x80,0x91,0x69,0x01,0x80,0xFF,0x06,0xC0,0x80,0x91,
0x64,0x00,0x90,0x91,0x65,0x00,0x2C,0xD0,0x08,0xC0,0x86,0x95,0x80,0xFD,0x06,0xC0,
0xE0,0x91,0x64,0x00,0xF0,0x91,0x65,0x00,0x84,0x91,0x8F,0xDE,0x80,0x91,0x64,0x00,
0x90,0x91,0x65,0x00,0x01,0x96,0x90,0x93,0x65,0x00,0x80,0x93,0x64,0x00,0x21,0x96,
0xDB,0xCF,0x85,0x37,0x79,0xF4,0x5A,0xDE,0x80,0x32,0x09,0xF0,0xBF,0xCE,0x84,0xE1,
0x7C,0xDE,0x8E,0xE1,0x7A,0xDE,0x83,0xE9,0x78,0xDE,0x87,0xE0,0x76,0xDE,0x80,0xE1,
0x74,0xDE,0xB4,0xCE,0x86,0x37,0x09,0xF0,0xB1,0xCE,0x80,0xE0,0x7B,0xDE,0xAE,0xCE,
0xE1,0x99,0xFE,0xCF,0x9F,0xBB,0x8E,0xBB,0xE0,0x9A,0x99,0x27,0x8D,0xB3,0x08,0x95,
0xE1,0x99,0xFE,0xCF,0x9F,0xBB,0x8E,0xBB,0x6D,0xBB,0x0F,0xB6,0xF8,0x94,0xE2,0x9A,
0xE1,0x9A,0x0F,0xBE,0x08,0x95,
0x80,0x00,
0x00,0x00,0x1C,0x00
};

// PINS
#define SCK 13
// serial clock to target avr
#define MISO 12
// input from target avr
#define MOSI 11
// output to target avr
#define RESET 10
// reset pin of the target avr

#define START_BTN 9
// active low - starts burning the bootloader to the new chip
#define IDLE_LED 8
#define RUN_LED 7
#define ERR_LED 6

// on the target avr, wire these other pins:
// GND: pins 22 (GND), 8 (GND)
// +VCC: pin 7 (VCC)
// XTAL1 & XTAL2

#define CKEDGE LOW
// SCK transmits the bit from MOSI on the rising edge of the clock pulse
// CKEDGE should be LOW, which means SCK pulses "...LOW->HIGH->LOW..."

// ISP Command Words (use the functions defined further below)
#define PE 0xAC53
#define ER 0xAC80
#define RD_PL 0x2000
#define RD_PH 0x2800
#define LD_PL 0x4000
#define LD_PH 0x4800
#define WR_P 0x4C00
#define RD_E 0xA000
#define WR_E 0xC000
#define RD_L 0x5800
#define WR_L 0xACE0
#define RD_S 0x3000
#define WR_F 0xACA0
#define WR_FH 0xACA8
#define RD_F 0x5000
#define RD_FH 0x5808
#define RD_C 0x3800

// Arduino lock bits (default 0xCF ~ prevented reading the boot sector with LPM)
#define LockBits 0xEF
// 11101111 = SPM is not allowed to write to the boot loader section (prevents bootloader corruption)
// Your mega8 running this program probably has bit 6 is programmed. That lock bit makes the bootloader unreadable... (doh!)
// When you use this program to burn new bootloaders, those chips WILL be able to use LPM in the boot flash section.
// You could reduce this program's size by 1K, if LPM can read the boot flash. (there'd be no need for the bootloader table above)

// Arduino fuse bits
#define FuseLow 0xDF
// default 11011111 = 0xDF, bits 1-4 (rightmost) are CKSEL clock select, bits 5-6 are SUT1 & SUT0 start up time delay
// bits 7-8 are BOD brown out detect, which is disabled

#define FuseHigh 0xCA
// default 11001010 = 0xCA, bit 1 select reset vector (on), bits 2-3 boot size (1K), bit 4 EESAVE eeprom preserved through chip erase (off)
// bit 5 CKOPT clock options (on), bit 6 SPIEN SPI enabled (on), bit 7 WDT watchdog timer (off), bit 8 RSTDISBL reset disable (off)

// MACRO DECLARATION

#define PULSE_SCK(level) { digitalWrite((SCK),(level)); digitalWrite((SCK),!(level)); }
// slow pulse, max 60KHz

#define GetWordHigh(a) ( ((a) & 0xFF00) >> 8 )
#define GetWordLow(a) ( ((a) & 0x00FF) )
// these macros are used by the function declarations below

// FUNCTION DECLARATION

// sends 4 bytes out with SCK, MOSI (output) and gets the return value of the last byte from MISO (input)
unsigned char Send_ISP(unsigned char v0, unsigned char v1, unsigned char v2, unsigned char v3);

#define CMD_Program_Enable() (Send_ISP(GetWordHigh(PE),GetWordLow(PE),0x22,0x22))
// Programming Enable: enable serial programming after reset goes low

#define CMD_Erase_Flash() (Send_ISP(GetWordHigh(ER),GetWordLow(ER),0x22,0x22))
// Chip Erase: chip erase eeprom and flash

#define CMD_Read_Flash_Low(addr) (Send_ISP(GetWordHigh(RD_PL), (GetWordLow(RD_PL) | (((addr) & 0xF00) >> 8)), ((addr) & 0xFF), 0))
// Read Program Memory - Low Byte: reads and returns low data from 12 bit word address (divide byte address by 2 for word address)

#define CMD_Read_Flash_High(addr) (Send_ISP(GetWordHigh(RD_PH), (GetWordLow(RD_PH) | (((addr) & 0xF00) >> 8)), ((addr) & 0xFF), 0))
// Read Program Memory - High Byte: reads and returns high data from 12 bit word address

#define CMD_Load_Page_Low(addr,data) (Send_ISP(GetWordHigh(LD_PL),GetWordLow(LD_PL), (addr), (data)))
// Load Program Memory Page - Low Byte: loads a low byte to the selected memory page, at word address "page" (page is 4 bits)
// data low byte must be loaded before data high byte; the flash data is entered by pages, then that whole page is written
// pages are 32 words (64 bytes)

#define CMD_Load_Page_High(addr,data) (Send_ISP(GetWordHigh(LD_PH),GetWordLow(LD_PH), (addr), (data)))
// Load Program Memory Page - High Byte: loads a high byte to program memory page at word address "page" (page is 4 bits)
// data low byte must be loaded before data high byte; the flash data is entered by pages, then that whole page is written
// pages are 32 words (64 bytes)

//#define CMD_Write_Page(addr) (Send_ISP(GetWordHigh(WR_P),(GetWordLow(WR_P) | (((addr) & 0xF0) >> 4)), (((addr) & 0x0F) <<>> 4, ((addr)*2) << 2="3584)" result =" 0;" result="CMD_Program_Enable()" result="CMD_Program_Enable()" result="CMD_Program_Enable()" page =" BOOT_PAGE" index =" 0" result =" 0;" i =" 0x80">0 ; i /= 2 ) {
digitalWrite(MOSI,(v0 & i));
PULSE_SCK(CKEDGE);
//result = ((result << i =" 0x80">0 ; i /= 2 ) { // second byte - MISO echos first byte
digitalWrite(MOSI,(v1 & i));
PULSE_SCK(CKEDGE);
result = ((result << i =" 0x80">0 ; i /= 2 ) { // third byte - MISO echos second byte
digitalWrite(MOSI,(v2 & i));
PULSE_SCK(CKEDGE);
result = ((result << i =" 0x80">0 ; i /= 2 ) { // fourth byte - MISO returns some value (depends on command)
digitalWrite(MOSI,(v3 & i));
PULSE_SCK(CKEDGE);
result = ((result << x =" 0" value =" 0;" index =" 0" index =" 0" page =" 0" index =" 0">> 8);
}
CMD_Write_Page(page);
delay(20);
}
}*/


Insert your Atmega8 into the Arduino Bootloader copier. Switch on the circuit and the green LED will be ON. Press the switch. The yellow LED will be ON for a few seconds and the bootloader was loaded into the Atmega8.

The following diagram shows the 'cheaper version of the Arduino'. You can remove the ISP connector if you don't need this.






You can upload your program to your Atmega8 in the
Arduino Diecimila. Remove the Atmega8 from the Diecimila board and insert it into the 'cheaper version of Arduino'.

That mean you can use Arduino IDE to program your Atmega8 and put the Atmega8 into the 'cheaper version of Arduino'. ENJOY !

Check : - http://www.arduino.cc/playground/BootCloner/BootCloner



沒有留言:

張貼留言