![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Code to program an AVR microcontroller over SPI using the mBed's first SPI port. The AVR must support ICSP. Alter max page size from 64 to the matching page size for your microcontroller. Alter the clock to the minimum clock speed for your microcontroller. Has only been tested with ATMega88.
Diff: main.cpp
- Revision:
- 0:52ce2a69824f
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Mon Jun 21 14:43:29 2010 +0000 @@ -0,0 +1,261 @@ +// Code to implement ICSP of an AVR using the ISP on the mBed pins 5,6,7 +// and 8 as RESET + +//NOTES: -load hex file onto the mBed as a file named "avr" +// -Change TARGET_CLK to a suiteable value for your particular avr (it gets divided by 2 for ATMega88) +// -Change the max page size to suite the microcontroller (change the 64 only) + +#include "mbed.h" +#define LSB(I) ((I) & 0xFF) +#define MSB(I) (((I) & 0xF00) >> 8) + +#define TARGET_CLK 1000000L +#define MAX_PAGE_SIZE (64 >> 1) //divide max page size by 2 to get number of words per page + +SPI spi(p5, p6, p7); // mosi, miso, sclk/ +DigitalOut reset(p8); //RESET + +Serial pc(USBTX, USBRX); // tx, rx + +LocalFileSystem local("local"); + + +int enable_prog_mode() //function to enable prog mode +{ + int failed = 0; + + while(failed < 5) //loop to try to enable programming mode 5 times + { + spi.write(0xAC); + spi.write(0x53); + int prog_en_check = spi.write(0x00); + if(prog_en_check == 0x53) { //if data read on 3rd byte load is 0x53 + spi.write(0x00); //programming mode was enabled...good job! + pc.printf("\nProgramming mode enabled...\n"); + return 0; + } + else{ + pc.printf("Programming mode failed!\n"); + pc.printf("%d\n",prog_en_check); + failed++; + reset = 1; //pulse reset and try again + reset = 0; + pc.printf("Trying again...\n"); + wait(0.5); + } + } + return -1; //Bummer... +} + +//A function to poll BSY to prevent loading a new instruction prematurely +void still_programming() +{ + int check = 1; + while(check == 1) + { + spi.write(0xF0); + spi.write(0x00); + spi.write(0x00); + check = spi.write(0x00); //read data byte out + } +} + +//A function to send the chip erase command +void chip_erase() +{ + pc.printf("Chip erase initiated...\n"); + spi.write(0xAC); + spi.write(0x80); + spi.write(0x00); + spi.write(0x00); + still_programming(); + pc.printf("Chip erase completed!\n"); + reset = 1; + wait(0.020); + reset = 0; + wait(0.020); + enable_prog_mode(); +} + + +void write_prog_page(uint16_t addr) +{ + //write program memory page + spi.write(0x4C); + spi.write(MSB(addr)); + spi.write(LSB(addr)); + spi.write(0x00); + still_programming(); //make sure the operation worked + // pc.printf("Wrote a flash page.\n"); +} + + +//function to load and write program memory +//args: addr is the 12 bit address of the memory location +// low_data and high_data are the values to write to that location +void load_prog_page(uint16_t addr, uint8_t low_data, uint8_t high_data)//int addr_MSB, +{ + //load program memory low byte (little endian) + spi.write(0x40); + spi.write(0x00); + spi.write(LSB(addr)); + spi.write(low_data); + + //load program memory high byte + spi.write(0x48); + spi.write(0x00); + spi.write(LSB(addr)); + spi.write(high_data); + //pc.printf(" Wrote: %x %x to LSB address: %x\n", high_data, low_data, LSB(addr)); + + // write page if 32 words have now been written + if(addr % MAX_PAGE_SIZE == (MAX_PAGE_SIZE-1)) + write_prog_page(addr); +} + +void write_lock_bits(uint8_t bits) +{ + bits = bits & 0xFF; + spi.write(0xAC); + spi.write(0xE0); + spi.write(0x00); + spi.write(bits); + still_programming(); + pc.printf("Wrote lock bits...\n"); +} + +void write_fuse_bits(uint8_t bits) +{ + bits = bits & 0xFF; + spi.write(0xAC); + spi.write(0xA0); + spi.write(0x00); + spi.write(bits); + still_programming(); + pc.printf("Wrote fuse bits...\n"); +} + +void write_fuse_bits_high(uint8_t bits) +{ + bits = bits & 0xFF; + spi.write(0xAC); + spi.write(0xA8); + spi.write(0x00); + spi.write(bits); + still_programming(); + pc.printf("Wrote fuse bits high...\n"); +} + +void write_extended_fuse_bits(uint8_t bits) +{ + bits = bits & 0xFF; + spi.write(0xAC); + spi.write(0xA4); + spi.write(0x00); + spi.write(bits); + still_programming(); + pc.printf("Wrote extended fuse bits...\n"); +} + +uint8_t read_byte(FILE *file) +{ + char ascii_char[2]; + fread(&ascii_char, 1, 2, file); + return (((ascii_char[0] < 65) ? (ascii_char[0]-48) : (ascii_char[0]-55)) << 4) + | ((ascii_char[1] < 65) ? (ascii_char[1]-48) : (ascii_char[1]-55)); +} + +void read_prog_flash(uint8_t addr_MSB, uint8_t addr_LSB) +{ + spi.write(0x28); + spi.write(addr_MSB); + spi.write(addr_LSB); + pc.printf("At address LSB %x: MSB: %x - %x ",addr_LSB,addr_MSB,spi.write(0x00)); + spi.write(0x20); + spi.write(addr_MSB); + spi.write(addr_LSB); + pc.printf("%x\n",spi.write(0x00)); +} + +int main() { + reset = 1; + // Setup the spi for 8 bit data,writing data on the rising SCK edge, + // and reading data on the falling SCK edge as according to AVR specs + // with a 1MHz clock rate + pc.printf("\nPress any button to program the AVR.\n"); + char c = pc.getc(); + + spi.format(8,1); //SPI format: write data on rising edge, read on falling + //w/ a base clock value of zero + spi.frequency(TARGET_CLK >> 2); + //wait(0.5); + pc.printf("SPI interface started...\n"); + + // Select the device by seting chip select low + reset = 0; + wait(0.02); + + if(enable_prog_mode() != 0) //Enable programming mode and check for errors + return -1; + spi.write(0x30); + spi.write(0x00); + spi.write(0x00); + pc.printf("SIGNATURE BYTE: %x\n",spi.write(0x00)); + chip_erase(); + + write_lock_bits(0xFF); //1111 1111 + write_fuse_bits(0x62); //1110 0010 + write_fuse_bits_high(0xDF); //1101 1111 + write_extended_fuse_bits(0xF9); //1111 1001 + + //Opening a file on local FS as in example code + pc.printf("Opening File...\n"); + int flag = 0; + FILE *hex_file; + hex_file = fopen("/local/avr","r"); + if(hex_file !=NULL) + { + uint16_t address = 0; + char temp; + temp = fgetc(hex_file); + while(flag == 0) + { + if(temp == ':') + { + uint8_t length = read_byte(hex_file); + if(length == 0){ + flag = 1; + printf("EOF line reached.\n"); + } + else{ + fseek(hex_file, 6, SEEK_CUR); //2 if reading address + + for(uint8_t i=0;i<length;i+=2){ + uint8_t low_data = read_byte(hex_file); + uint8_t high_data = read_byte(hex_file); + + //load data bytes here + load_prog_page(address, low_data, high_data); + + address++; + } + while((temp = fgetc(hex_file)) != ':'); + //pc.printf("\n"); + } + } + else flag =1; + } + pc.printf("WRITE THE PAGE!\n");//write page here + write_prog_page(address); + fclose(hex_file); + } + else { + pc.printf("Failed to open the file...check the name.\n"); + } + pc.printf("Successfully programmed!(hopefully...)\n"); + + // Deselect the device + reset = 1; + wait(0.02); + return 0; +} \ No newline at end of file