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.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 // Code to implement ICSP of an AVR using the ISP on the mBed pins 5,6,7 
00002 // and 8 as RESET
00003 
00004 //NOTES:    -load hex file onto the mBed as a file named "avr"
00005 //          -Change TARGET_CLK to a suiteable value for your particular avr (it gets divided by 2 for ATMega88)
00006 //          -Change the max page size to suite the microcontroller (change the 64 only)
00007 
00008 #include "mbed.h"
00009 #define LSB(I) ((I) & 0xFF)
00010 #define MSB(I) (((I) & 0xF00) >> 8)
00011 
00012 #define TARGET_CLK 1000000L
00013 #define MAX_PAGE_SIZE (64 >> 1) //divide max page size by 2 to get number of words per page                                    
00014                                                    
00015 SPI spi(p5, p6, p7); // mosi, miso, sclk/
00016 DigitalOut reset(p8);   //RESET
00017 
00018 Serial pc(USBTX, USBRX); // tx, rx
00019 
00020 LocalFileSystem local("local");
00021 
00022 
00023 int enable_prog_mode() //function to enable prog mode
00024 {
00025     int failed = 0;
00026     
00027     while(failed < 5) //loop to try to enable programming mode 5 times
00028     {
00029         spi.write(0xAC);
00030         spi.write(0x53);
00031         int prog_en_check = spi.write(0x00);
00032         if(prog_en_check == 0x53) { //if data read on 3rd byte load is 0x53
00033             spi.write(0x00);        //programming mode was enabled...good job!
00034             pc.printf("\nProgramming mode enabled...\n");
00035             return 0;
00036         }      
00037         else{
00038             pc.printf("Programming mode failed!\n");
00039             pc.printf("%d\n",prog_en_check); 
00040             failed++;
00041             reset = 1; //pulse reset and try again
00042             reset = 0;
00043             pc.printf("Trying again...\n");
00044             wait(0.5);
00045         }
00046      }
00047     return -1; //Bummer...
00048 }
00049 
00050 //A function to poll BSY to prevent loading a new instruction prematurely
00051 void still_programming() 
00052 {
00053     int check = 1;
00054     while(check == 1)
00055     {
00056         spi.write(0xF0);
00057         spi.write(0x00);
00058         spi.write(0x00);
00059         check = spi.write(0x00); //read data byte out
00060     }
00061 }
00062 
00063 //A function to send the chip erase command
00064 void chip_erase() 
00065 {
00066         pc.printf("Chip erase initiated...\n");
00067         spi.write(0xAC);
00068         spi.write(0x80);
00069         spi.write(0x00);
00070         spi.write(0x00);
00071         still_programming();
00072         pc.printf("Chip erase completed!\n");
00073         reset = 1;
00074         wait(0.020);
00075         reset = 0;
00076         wait(0.020);
00077         enable_prog_mode();
00078 }
00079 
00080 
00081 void write_prog_page(uint16_t addr)
00082 {
00083     //write program memory page
00084     spi.write(0x4C);
00085     spi.write(MSB(addr));
00086     spi.write(LSB(addr));
00087     spi.write(0x00);
00088     still_programming(); //make sure the operation worked
00089    // pc.printf("Wrote a flash page.\n"); 
00090 }
00091 
00092 
00093 //function to load and write program memory
00094 //args: addr is the 12 bit address of the memory location
00095 //      low_data and high_data are the values to write to that location
00096 void load_prog_page(uint16_t addr, uint8_t low_data, uint8_t high_data)//int addr_MSB, 
00097 {
00098     //load program memory low byte (little endian)
00099     spi.write(0x40);
00100     spi.write(0x00);
00101     spi.write(LSB(addr));
00102     spi.write(low_data);
00103     
00104     //load program memory high byte
00105     spi.write(0x48);
00106     spi.write(0x00);
00107     spi.write(LSB(addr));
00108     spi.write(high_data);
00109     //pc.printf(" Wrote: %x %x to LSB address: %x\n", high_data, low_data, LSB(addr));
00110    
00111     // write page if 32 words have now been written
00112     if(addr % MAX_PAGE_SIZE == (MAX_PAGE_SIZE-1))
00113         write_prog_page(addr);
00114 }
00115 
00116 void write_lock_bits(uint8_t bits)
00117 {
00118     bits = bits & 0xFF;
00119     spi.write(0xAC);
00120     spi.write(0xE0);
00121     spi.write(0x00);
00122     spi.write(bits);
00123     still_programming();
00124     pc.printf("Wrote lock bits...\n");
00125 }
00126 
00127 void write_fuse_bits(uint8_t bits)
00128 {
00129     bits = bits & 0xFF;
00130     spi.write(0xAC);
00131     spi.write(0xA0);
00132     spi.write(0x00);
00133     spi.write(bits);
00134     still_programming();
00135     pc.printf("Wrote fuse bits...\n");
00136 }
00137 
00138 void write_fuse_bits_high(uint8_t bits)
00139 {
00140     bits = bits & 0xFF;
00141     spi.write(0xAC);
00142     spi.write(0xA8);
00143     spi.write(0x00);
00144     spi.write(bits);
00145     still_programming();
00146     pc.printf("Wrote fuse bits high...\n");
00147 }
00148 
00149 void write_extended_fuse_bits(uint8_t bits)
00150 {
00151     bits = bits & 0xFF;
00152     spi.write(0xAC);
00153     spi.write(0xA4);
00154     spi.write(0x00);
00155     spi.write(bits);
00156     still_programming();
00157     pc.printf("Wrote extended fuse bits...\n");
00158 }
00159 
00160 uint8_t read_byte(FILE *file)
00161 {
00162     char ascii_char[2];
00163     fread(&ascii_char, 1, 2, file);
00164     return   (((ascii_char[0] < 65) ? (ascii_char[0]-48) : (ascii_char[0]-55)) << 4)
00165             | ((ascii_char[1] < 65) ? (ascii_char[1]-48) : (ascii_char[1]-55));
00166 }
00167 
00168 void read_prog_flash(uint8_t addr_MSB, uint8_t addr_LSB)
00169 {
00170     spi.write(0x28);
00171     spi.write(addr_MSB);
00172     spi.write(addr_LSB);
00173     pc.printf("At address LSB %x: MSB: %x - %x ",addr_LSB,addr_MSB,spi.write(0x00));
00174     spi.write(0x20);
00175     spi.write(addr_MSB);
00176     spi.write(addr_LSB);
00177     pc.printf("%x\n",spi.write(0x00));      
00178 }
00179 
00180 int main() {
00181     reset = 1;
00182     // Setup the spi for 8 bit data,writing data on the rising SCK edge,
00183     // and reading data on the falling SCK edge as according to AVR specs
00184     // with a 1MHz clock rate
00185     pc.printf("\nPress any button to program the AVR.\n");
00186     char c = pc.getc();
00187     
00188     spi.format(8,1);        //SPI format: write data on rising edge, read on falling
00189                             //w/ a base clock value of zero
00190     spi.frequency(TARGET_CLK >> 2);
00191     //wait(0.5);
00192     pc.printf("SPI interface started...\n");
00193     
00194     // Select the device by seting chip select low
00195     reset = 0;
00196     wait(0.02); 
00197 
00198     if(enable_prog_mode() != 0)  //Enable programming mode and check for errors
00199         return -1;
00200     spi.write(0x30);
00201     spi.write(0x00);
00202     spi.write(0x00);
00203     pc.printf("SIGNATURE BYTE: %x\n",spi.write(0x00));
00204     chip_erase();
00205     
00206     write_lock_bits(0xFF);                  //1111 1111
00207     write_fuse_bits(0x62);                  //1110 0010
00208     write_fuse_bits_high(0xDF);             //1101 1111
00209     write_extended_fuse_bits(0xF9);         //1111 1001
00210     
00211     //Opening a file on local FS as in example code
00212     pc.printf("Opening File...\n"); 
00213     int flag = 0;
00214     FILE *hex_file;
00215     hex_file = fopen("/local/avr","r");
00216     if(hex_file !=NULL)
00217     {    
00218         uint16_t address = 0;
00219         char temp;
00220         temp = fgetc(hex_file);
00221         while(flag == 0)
00222         {
00223             if(temp == ':')
00224             {
00225                 uint8_t length = read_byte(hex_file);
00226                 if(length == 0){
00227                     flag = 1;
00228                     printf("EOF line reached.\n");
00229                 }
00230                 else{
00231                     fseek(hex_file, 6, SEEK_CUR); //2 if reading address
00232                     
00233                     for(uint8_t i=0;i<length;i+=2){
00234                         uint8_t low_data = read_byte(hex_file);
00235                         uint8_t high_data = read_byte(hex_file);
00236                        
00237                         //load data bytes here
00238                         load_prog_page(address, low_data, high_data);
00239                         
00240                         address++;
00241                     }
00242                     while((temp = fgetc(hex_file)) != ':');
00243                     //pc.printf("\n");             
00244                 }
00245             }
00246             else flag =1;
00247         }
00248         pc.printf("WRITE THE PAGE!\n");//write page here
00249         write_prog_page(address);
00250         fclose(hex_file);
00251     }
00252     else {
00253         pc.printf("Failed to open the file...check the name.\n");          
00254     }
00255     pc.printf("Successfully programmed!(hopefully...)\n");    
00256     
00257     // Deselect the device
00258     reset = 1;
00259     wait(0.02);
00260     return 0;    
00261 }