AVR910 In-System Programming

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers AVR910.cpp Source File

AVR910.cpp

00001 //****************************************************************************/
00002 // Description:
00003 //
00004 //  Program AVR chips with the AVR910 ISP (in-system programming) protocol,
00005 //  using an mbed.
00006 //
00007 // AVR Application Note:
00008 //
00009 //  http://www.atmel.com/dyn/resources/prod_documents/doc0943.pdf
00010 //****************************************************************************/
00011 
00012 //****************************************************************************/
00013 // Includes
00014 //****************************************************************************/
00015 #include "AVR910.h"
00016 
00017 Serial debug(USBTX, USBRX);
00018 
00019 AVR910::AVR910(PinName mosi, PinName miso, PinName sclk, PinName nReset) {
00020 
00021     spi_    = new SPI(mosi, miso, sclk);
00022     spi_->frequency(32000);
00023     spi_->format(8, 1);
00024     nReset_ = new DigitalOut(nReset);
00025 
00026 }
00027 
00028 int AVR910::program(FILE* binary) {
00029 
00030     int response = 0;
00031 
00032     debug.printf("mbed AVR910 Programmer starting\n");
00033 
00034     //Enter serial programming mode by pulling reset line low.
00035     *nReset_ = 0;
00036 
00037     //Wait 20ms before issuing first command.
00038     wait_ms(20);
00039 
00040     //Issue a programming enable command.
00041     response = enableProgramming();
00042 
00043     if (response < 0) {
00044         debug.printf("Enable programming command not successful\n");
00045     } else {
00046         debug.printf("Enable programming command successful\n");
00047     }
00048 
00049     //Read vendor code, part family and part number.
00050     response = readVendorCode();
00051 
00052     if (response == ATMEL_VENDOR_CODE) {
00053         debug.printf("Microcontroller is an Atmel [0x%02x]\n", response);
00054     } else if (response == DEVICE_LOCKED) {
00055         debug.printf("Device is locked\n");
00056     } else {
00057         debug.printf("Microcontroller is not an Atmel\n");
00058     }
00059 
00060     response = readPartFamilyAndFlashSize();
00061 
00062     if (response == 0xFF) {
00063         debug.printf("Device code erased or target missing\n");
00064     } else if (response == 0x01) {
00065         debug.printf("Device locked\n");
00066     } else {
00067         debug.printf("Part family and flash size code is: 0x%02x\n", response);
00068     }
00069 
00070     response = readPartNumber();
00071 
00072     if (response == 0xFF) {
00073         debug.printf("Device code erased or target missing\n");
00074     } else if (response == 0x02) {
00075         debug.printf("Device locked\n");
00076     } else {
00077         debug.printf("Part number code is: 0x%02x\n", response);
00078     }
00079 
00080     //Clear memory contents.
00081     chipErase();
00082 
00083     char pageOffset = 0;
00084     int  pageNumber = 0;
00085     int  c          = 0;
00086     int  highLow    = 0;
00087 
00088     while ((c = getc(binary)) != EOF) {
00089 
00090         //Page is fully loaded, time to write it to flash.
00091         if (pageOffset == (PAGE_SIZE)) {
00092             writeFlashMemoryPage(pageNumber);
00093             debug.printf("Page %i written\n", pageNumber);
00094             pageNumber++;
00095             pageOffset = 0;
00096         }
00097 
00098         //Write low byte.
00099         if (highLow == 0) {
00100             loadMemoryPage(WRITE_LOW_BYTE, pageOffset, c);
00101             highLow = 1;
00102         }
00103         //Write high byte.
00104         else {
00105             loadMemoryPage(WRITE_HIGH_BYTE, pageOffset, c);
00106             highLow = 0;
00107             pageOffset++;
00108         }
00109 
00110     }
00111 
00112     //We might have partially filled up a page.
00113     writeFlashMemoryPage(pageNumber);
00114 
00115     int success = -1;
00116     success = checkMemory(pageNumber, binary);
00117 
00118     //Leave serial programming mode by pulling reset line high.
00119     *nReset_ = 1;
00120     
00121     return success;
00122 
00123 }
00124 
00125 void AVR910::setFrequency(int frequency){
00126 
00127     spi_->frequency(frequency);
00128 
00129 }
00130 
00131 int AVR910::enableProgramming(void) {
00132 
00133     int response = 0;
00134     int error    = 0;
00135 
00136     //Programming Enable Command: 0xAC, 0x53, 0x00, 0x00
00137     //Byte two echo'd back in byte three.
00138     spi_->write(0xAC);
00139 
00140     spi_->write(0x53);
00141 
00142     response = spi_->write(0x00);
00143 
00144     if (response == 0x53) {
00145         error =  0;
00146     } else {
00147         error = -1;
00148     }
00149 
00150     spi_->write(0x00);
00151 
00152     return error;
00153 
00154 }
00155 
00156 void AVR910::poll(void) {
00157 
00158     int response = 0;
00159 
00160     do {
00161         spi_->write(0xF0);
00162         spi_->write(0x00);
00163         spi_->write(0x00);
00164         response = spi_->write(0x00);
00165     } while ((response & 0x01) != 0);
00166 
00167 }
00168 
00169 int AVR910::readVendorCode(void) {
00170 
00171     int response = 0;
00172 
00173     //Issue read signature byte command.
00174     //Address 0x00 is vendor code.
00175     spi_->write(0x30);
00176     spi_->write(0x00);
00177     spi_->write(0x00);
00178     response = spi_->write(0x00);
00179 
00180     return response;
00181 
00182 }
00183 
00184 int AVR910::readPartFamilyAndFlashSize(void) {
00185 
00186     int response = 0;
00187 
00188     //Issue read signature byte command.
00189     //Address 0x01 is part family and flash size code.
00190     spi_->write(0x30);
00191     spi_->write(0x00);
00192     spi_->write(0x01);
00193     response = spi_->write(0x00);
00194 
00195     return response;
00196 
00197 }
00198 
00199 int AVR910::readPartNumber(void) {
00200 
00201     int response = 0;
00202 
00203     //Issue read signature byte command.
00204     //Address 0x02 is part number code.
00205     spi_->write(0x30);
00206     spi_->write(0x00);
00207     spi_->write(0x02);
00208     response = spi_->write(0x00);
00209 
00210     return response;
00211 
00212 }
00213 
00214 void AVR910::chipErase(void) {
00215 
00216     //Issue chip erase command.
00217     spi_->write(0xAC);
00218     spi_->write(0x80);
00219     spi_->write(0x00);
00220     spi_->write(0x00);
00221 
00222     poll();
00223 
00224     //Temporarily release reset line.
00225     *nReset_ = 1;
00226     *nReset_ = 0;
00227 
00228 }
00229 
00230 void AVR910::loadMemoryPage(int highLow, char address, char data) {
00231 
00232     spi_->write(highLow);
00233     spi_->write(0x00);
00234     spi_->write(address & 0x3F);
00235     spi_->write(data);
00236 
00237     poll();
00238 
00239 }
00240 
00241 void AVR910::writeFlashMemoryPage(char pageNumber) {
00242 
00243     spi_->write(0x4C);
00244     spi_->write((pageNumber >> 2) & 0x3F);
00245     spi_->write((pageNumber & 0x03) << 6);
00246     spi_->write(0x00);
00247 
00248     poll();
00249 
00250 }
00251 
00252 char AVR910::readProgramMemory(int highLow, char pageNumber, char pageOffset) {
00253 
00254     int response = 0;
00255 
00256     spi_->write(highLow);
00257     spi_->write((pageNumber >> 2) & 0x3F);
00258     spi_->write(((pageNumber & 0x03) << 6) | (pageOffset & 0x3F));
00259     response = spi_->write(0x00);
00260 
00261     poll();
00262 
00263     return response;
00264 
00265 }
00266 
00267 int AVR910::checkMemory(int numPages, FILE* binary){
00268 
00269     int success  = 0;
00270     int response = 0;
00271     char c       = 0;
00272 
00273     //Go back to the beginning of the binary file.
00274     fseek(binary, 0, SEEK_SET);
00275 
00276     for(int i = 0; i < numPages; i++){
00277         for (int j = 0; j < PAGE_SIZE; j++) {
00278             c = getc(binary);
00279             //Read program memory low byte.
00280             response = readProgramMemory(READ_LOW_BYTE, i, j);
00281             //debug.printf("Low byte: 0x%02x\n", response);
00282             if( c != response ){
00283                 debug.printf("page %i low byte %i: 0x%02x\n", i, j, response);
00284                 debug.printf("correct byte is 0x%02x\n", c);
00285                 success = -1;
00286             }
00287 
00288             c = getc(binary);
00289             //Read program memory high byte.
00290             response = readProgramMemory(READ_HIGH_BYTE, i, j);
00291             //debug.printf("High byte: 0x%02x\n", response);
00292             if( c != response ){
00293                 debug.printf("page %i high byte %i: 0x%02x\n", i, j, response);
00294                 debug.printf("correct byte is 0x%02x\n", c);
00295                 success = -1;
00296             }
00297         }
00298     }
00299     
00300     return success;
00301 
00302 }