Aaron Berk
/
mAVRISP
Program an AVR microcontroller using mbed.
AVR910.cpp
- Committer:
- aberk
- Date:
- 2010-08-31
- Revision:
- 0:3066745764a5
- Child:
- 1:276f6df4be7a
File content as of revision 0:3066745764a5:
/** * @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; }