Chris Styles
/
m3pi_AVRprogrammer
AVR910.cpp
- Committer:
- chris
- Date:
- 2010-11-01
- Revision:
- 0:20fc0ecfb510
File content as of revision 0:20fc0ecfb510:
//****************************************************************************/ // 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; }