Dependencies:   mbed

Revision:
0:20fc0ecfb510
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AVR910.cpp	Mon Nov 01 17:11:45 2010 +0000
@@ -0,0 +1,302 @@
+//****************************************************************************/
+// Description:
+//
+//  Program AVR chips with the AVR910 ISP (in-system programming) protocol,
+//  using an mbed.
+//
+// AVR Application Note:
+//
+//  http://www.atmel.com/dyn/resources/prod_documents/doc0943.pdf
+//****************************************************************************/
+
+//****************************************************************************/
+// Includes
+//****************************************************************************/
+#include "AVR910.h"
+
+Serial debug(USBTX, USBRX);
+
+AVR910::AVR910(PinName mosi, PinName miso, PinName sclk, PinName nReset) {
+
+    spi_    = new SPI(mosi, miso, sclk);
+    spi_->frequency(32000);
+    spi_->format(8, 1);
+    nReset_ = new DigitalOut(nReset);
+
+}
+
+int AVR910::program(FILE* binary) {
+
+    int response = 0;
+
+    debug.printf("mbed AVR910 Programmer starting\n");
+
+    //Enter serial programming mode by pulling reset line low.
+    *nReset_ = 0;
+
+    //Wait 20ms before issuing first command.
+    wait_ms(20);
+
+    //Issue a programming enable command.
+    response = enableProgramming();
+
+    if (response < 0) {
+        debug.printf("Enable programming command not successful\n");
+    } else {
+        debug.printf("Enable programming command successful\n");
+    }
+
+    //Read vendor code, part family and part number.
+    response = readVendorCode();
+
+    if (response == ATMEL_VENDOR_CODE) {
+        debug.printf("Microcontroller is an Atmel [0x%02x]\n", response);
+    } else if (response == DEVICE_LOCKED) {
+        debug.printf("Device is locked\n");
+    } else {
+        debug.printf("Microcontroller is not an Atmel\n");
+    }
+
+    response = readPartFamilyAndFlashSize();
+
+    if (response == 0xFF) {
+        debug.printf("Device code erased or target missing\n");
+    } else if (response == 0x01) {
+        debug.printf("Device locked\n");
+    } else {
+        debug.printf("Part family and flash size code is: 0x%02x\n", response);
+    }
+
+    response = readPartNumber();
+
+    if (response == 0xFF) {
+        debug.printf("Device code erased or target missing\n");
+    } else if (response == 0x02) {
+        debug.printf("Device locked\n");
+    } else {
+        debug.printf("Part number code is: 0x%02x\n", response);
+    }
+
+    //Clear memory contents.
+    chipErase();
+
+    char pageOffset = 0;
+    int  pageNumber = 0;
+    int  c          = 0;
+    int  highLow    = 0;
+
+    while ((c = getc(binary)) != EOF) {
+
+        //Page is fully loaded, time to write it to flash.
+        if (pageOffset == (PAGE_SIZE)) {
+            writeFlashMemoryPage(pageNumber);
+            debug.printf("Page %i written\n", pageNumber);
+            pageNumber++;
+            pageOffset = 0;
+        }
+
+        //Write low byte.
+        if (highLow == 0) {
+            loadMemoryPage(WRITE_LOW_BYTE, pageOffset, c);
+            highLow = 1;
+        }
+        //Write high byte.
+        else {
+            loadMemoryPage(WRITE_HIGH_BYTE, pageOffset, c);
+            highLow = 0;
+            pageOffset++;
+        }
+
+    }
+
+    //We might have partially filled up a page.
+    writeFlashMemoryPage(pageNumber);
+
+    int success = -1;
+    success = checkMemory(pageNumber, binary);
+
+    //Leave serial programming mode by pulling reset line high.
+    *nReset_ = 1;
+    
+    return success;
+
+}
+
+void AVR910::setFrequency(int frequency){
+
+    spi_->frequency(frequency);
+
+}
+
+int AVR910::enableProgramming(void) {
+
+    int response = 0;
+    int error    = 0;
+
+    //Programming Enable Command: 0xAC, 0x53, 0x00, 0x00
+    //Byte two echo'd back in byte three.
+    spi_->write(0xAC);
+
+    spi_->write(0x53);
+
+    response = spi_->write(0x00);
+
+    if (response == 0x53) {
+        error =  0;
+    } else {
+        error = -1;
+    }
+
+    spi_->write(0x00);
+
+    return error;
+
+}
+
+void AVR910::poll(void) {
+
+    int response = 0;
+
+    do {
+        spi_->write(0xF0);
+        spi_->write(0x00);
+        spi_->write(0x00);
+        response = spi_->write(0x00);
+    } while ((response & 0x01) != 0);
+
+}
+
+int AVR910::readVendorCode(void) {
+
+    int response = 0;
+
+    //Issue read signature byte command.
+    //Address 0x00 is vendor code.
+    spi_->write(0x30);
+    spi_->write(0x00);
+    spi_->write(0x00);
+    response = spi_->write(0x00);
+
+    return response;
+
+}
+
+int AVR910::readPartFamilyAndFlashSize(void) {
+
+    int response = 0;
+
+    //Issue read signature byte command.
+    //Address 0x01 is part family and flash size code.
+    spi_->write(0x30);
+    spi_->write(0x00);
+    spi_->write(0x01);
+    response = spi_->write(0x00);
+
+    return response;
+
+}
+
+int AVR910::readPartNumber(void) {
+
+    int response = 0;
+
+    //Issue read signature byte command.
+    //Address 0x02 is part number code.
+    spi_->write(0x30);
+    spi_->write(0x00);
+    spi_->write(0x02);
+    response = spi_->write(0x00);
+
+    return response;
+
+}
+
+void AVR910::chipErase(void) {
+
+    //Issue chip erase command.
+    spi_->write(0xAC);
+    spi_->write(0x80);
+    spi_->write(0x00);
+    spi_->write(0x00);
+
+    poll();
+
+    //Temporarily release reset line.
+    *nReset_ = 1;
+    *nReset_ = 0;
+
+}
+
+void AVR910::loadMemoryPage(int highLow, char address, char data) {
+
+    spi_->write(highLow);
+    spi_->write(0x00);
+    spi_->write(address & 0x3F);
+    spi_->write(data);
+
+    poll();
+
+}
+
+void AVR910::writeFlashMemoryPage(char pageNumber) {
+
+    spi_->write(0x4C);
+    spi_->write((pageNumber >> 2) & 0x3F);
+    spi_->write((pageNumber & 0x03) << 6);
+    spi_->write(0x00);
+
+    poll();
+
+}
+
+char AVR910::readProgramMemory(int highLow, char pageNumber, char pageOffset) {
+
+    int response = 0;
+
+    spi_->write(highLow);
+    spi_->write((pageNumber >> 2) & 0x3F);
+    spi_->write(((pageNumber & 0x03) << 6) | (pageOffset & 0x3F));
+    response = spi_->write(0x00);
+
+    poll();
+
+    return response;
+
+}
+
+int AVR910::checkMemory(int numPages, FILE* binary){
+
+    int success  = 0;
+    int response = 0;
+    char c       = 0;
+
+    //Go back to the beginning of the binary file.
+    fseek(binary, 0, SEEK_SET);
+
+    for(int i = 0; i < numPages; i++){
+        for (int j = 0; j < PAGE_SIZE; j++) {
+            c = getc(binary);
+            //Read program memory low byte.
+            response = readProgramMemory(READ_LOW_BYTE, i, j);
+            //debug.printf("Low byte: 0x%02x\n", response);
+            if( c != response ){
+                debug.printf("page %i low byte %i: 0x%02x\n", i, j, response);
+                debug.printf("correct byte is 0x%02x\n", c);
+                success = -1;
+            }
+
+            c = getc(binary);
+            //Read program memory high byte.
+            response = readProgramMemory(READ_HIGH_BYTE, i, j);
+            //debug.printf("High byte: 0x%02x\n", response);
+            if( c != response ){
+                debug.printf("page %i high byte %i: 0x%02x\n", i, j, response);
+                debug.printf("correct byte is 0x%02x\n", c);
+                success = -1;
+            }
+        }
+    }
+    
+    return success;
+
+}