Program an AVR microcontroller using mbed.

Dependencies:   mbed

Revision:
0:3066745764a5
Child:
1:276f6df4be7a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AVR910.cpp	Tue Aug 31 14:09:53 2010 +0000
@@ -0,0 +1,311 @@
+/**
+ * @author Aaron Berk
+ *
+ * @section LICENSE
+ *
+ * Copyright (c) 2010 Aaron Berk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @section DESCRIPTION
+ *
+ * Program AVR chips with the AVR910 ISP (in-system programming) protocol,
+ * using an mbed.
+ *
+ * AVR910 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_(mosi, miso, sclk), nReset_(nReset) {
+
+    //Slow frequency as default to ensure no errors from
+    //trying to run it too fast. Increase as appropriate.
+    spi_.frequency(32000);
+    spi_.format(8, 0);
+
+    int response = 0;
+
+    //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();
+    
+    //Simple debugging to see if we get trapped
+    //in an infinite loop.
+    DigitalOut working(LED1);
+    working = 1;
+
+    //TODO: introduce a timeout.
+    while (response < 0) {
+
+        //Give nReset a positive pulse.
+        nReset_ = 1;
+        wait_ms(20);
+        nReset_ = 0;
+        wait_ms(20);
+
+        //Issue another programming enable.
+        response = enableProgramming();
+
+    }
+    
+    working = 0;
+
+}
+
+int AVR910::program(FILE* binary) {
+
+    //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);
+
+            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;
+
+}