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.
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 }
Generated on Fri Jul 15 2022 00:16:42 by 1.7.2