A fork of mAVRISP by Aaron Berk. This version does not use a local file system to hold the AVR program. Instead it uses a serial connection to a PC and a python script to send the AVR program to the mbed.

Dependencies:   mbed

Fork of mAVRISP by Aaron Berk

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers AVR910_Serial.cpp Source File

AVR910_Serial.cpp

00001 /**
00002  * @author Aaron Berk, Jeroen Voogd
00003  *
00004  * @section LICENSE
00005  *
00006  * Copyright (c) 2010 Aaron Berk
00007  * Copyright (c) 2015 Jeroen Voogd
00008  *
00009  * Permission is hereby granted, free of charge, to any person obtaining a copy
00010  * of this software and associated documentation files (the "Software"), to deal
00011  * in the Software without restriction, including without limitation the rights
00012  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00013  * copies of the Software, and to permit persons to whom the Software is
00014  * furnished to do so, subject to the following conditions:
00015  *
00016  * The above copyright notice and this permission notice shall be included in
00017  * all copies or substantial portions of the Software.
00018  *
00019  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00020  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00021  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00022  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00023  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00024  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00025  * THE SOFTWARE.
00026  *
00027  * @section DESCRIPTION
00028  *
00029  * Program AVR chips with the AVR910 ISP (in-system programming) protocol,
00030  * using an mbed. The version of Aaron Berk used a local file system, this version
00031  * useses a python script to feed the data via a serial connection.
00032  *
00033  * AVR910 Application Note:
00034  *
00035  * http://www.atmel.com/dyn/resources/prod_documents/doc0943.pdf
00036  */
00037 
00038 /**
00039  * Includes
00040  */
00041 #include "AVR910_Serial.h"
00042 
00043 Serial debug(USBTX, USBRX);
00044 
00045 AVR910::AVR910(PinName mosi,
00046                PinName miso,
00047                PinName sclk,
00048                PinName nReset) : spi_(mosi, miso, sclk), nReset_(nReset)
00049 {
00050 
00051     //Slow frequency as default to ensure no errors from
00052     //trying to run it too fast. Increase as appropriate.
00053     spi_.frequency(32000);
00054     spi_.format(8, 0);
00055 
00056     int response = 0;
00057 
00058     //Enter serial programming mode by pulling reset line low.
00059     nReset_ = 0;
00060 
00061     //Wait 20ms before issuing first command.
00062     wait_ms(20);
00063 
00064     //Issue a programming enable command.
00065     response = enableProgramming();
00066 
00067     //TODO: introduce a timeout.
00068     while (response < 0) {
00069 
00070         //Give nReset a positive pulse.
00071         nReset_ = 1;
00072         wait_ms(20);
00073         nReset_ = 0;
00074         wait_ms(20);
00075 
00076         //Issue another programming enable.
00077         response = enableProgramming();
00078     }
00079 }
00080 
00081 
00082 int AVR910::programData(char* myData, int dataSize, int pageSize, int numPages)
00083 {
00084 
00085     //Clear memory contents.
00086     chipErase();
00087 
00088     char pageOffset = 0;
00089     int  pageNumber = 0;
00090     int  c          = 0;
00091     int  highLow    = 0;
00092 
00093     //In this version we're always dealing with paged memory.
00094 
00095     for (int i=0; i<dataSize; i++) {
00096         c = myData[i];
00097         //Page is fully loaded, time to write it to flash.
00098         if (pageOffset == (pageSize)) {
00099             writeFlashMemoryPage(pageNumber);
00100 
00101             pageNumber++;
00102             if (pageNumber > numPages) {
00103                 break;
00104             }
00105             pageOffset = 0;
00106         }
00107 
00108         //Write low byte.
00109         if (highLow == 0) {
00110             loadMemoryPage(WRITE_LOW_BYTE, pageOffset, c);
00111             highLow = 1;
00112         }
00113         //Write high byte.
00114         else {
00115             loadMemoryPage(WRITE_HIGH_BYTE, pageOffset, c);
00116             highLow = 0;
00117             pageOffset++;
00118         }
00119 
00120     }
00121 
00122     //We might have partially filled up a page.
00123     writeFlashMemoryPage(pageNumber);
00124 
00125     int success = -1;
00126     success = checkMemoryData(pageNumber, myData, dataSize);
00127 
00128     //Leave serial programming mode by pulling reset line high.
00129     nReset_ = 1;
00130 
00131     return success;
00132 
00133 }
00134 void AVR910::setFrequency(int frequency)
00135 {
00136 
00137     spi_.frequency(frequency);
00138 
00139 }
00140 
00141 int AVR910::enableProgramming(void)
00142 {
00143 
00144     int response = 0;
00145     int error    = 0;
00146 
00147     //Programming Enable Command: 0xAC, 0x53, 0x00, 0x00
00148     //Byte two echo'd back in byte three.
00149     spi_.write(0xAC);
00150 
00151     spi_.write(0x53);
00152 
00153     response = spi_.write(0x00);
00154 
00155     if (response == 0x53) {
00156         error =  0;
00157     } else {
00158         error = -1;
00159     }
00160 
00161     response = spi_.write(0x00);
00162     
00163     return error;
00164 
00165 }
00166 
00167 void AVR910::poll(void)
00168 {
00169 
00170     int response = 0;
00171 
00172     do {
00173         spi_.write(0xF0);
00174         spi_.write(0x00);
00175         spi_.write(0x00);
00176         response = spi_.write(0x00);
00177     } while ((response & 0x01) != 0);
00178 
00179 }
00180 
00181 int AVR910::readVendorCode(void)
00182 {
00183 
00184     int response = 0;
00185 
00186     //Issue read signature byte command.
00187     //Address 0x00 is vendor code.
00188     spi_.write(0x30);
00189     spi_.write(0x00);
00190     spi_.write(0x00);
00191     response = spi_.write(0x00);
00192    
00193     return response;
00194 
00195 }
00196 
00197 int AVR910::readPartFamilyAndFlashSize(void)
00198 {
00199 
00200     int response = 0;
00201 
00202     //Issue read signature byte command.
00203     //Address 0x01 is part family and flash size code.
00204     spi_.write(0x30);
00205     spi_.write(0x00);
00206     spi_.write(0x01);
00207     response = spi_.write(0x00);
00208 
00209     return response;
00210 
00211 }
00212 
00213 int AVR910::readPartNumber(void)
00214 {
00215 
00216     int response = 0;
00217 
00218     //Issue read signature byte command.
00219     //Address 0x02 is part number code.
00220     spi_.write(0x30);
00221     spi_.write(0x00);
00222     spi_.write(0x02);
00223     response = spi_.write(0x00);
00224 
00225     return response;
00226 
00227 }
00228 
00229 void AVR910::chipErase(void)
00230 {
00231 
00232     //Issue chip erase command.
00233     spi_.write(0xAC);
00234     spi_.write(0x80);
00235     spi_.write(0x00);
00236     spi_.write(0x00);
00237 
00238     poll();
00239 
00240     //Temporarily release reset line.
00241     nReset_ = 1;
00242     nReset_ = 0;
00243 
00244 }
00245 
00246 void AVR910::loadMemoryPage(int highLow, char address, char data)
00247 {
00248 
00249     spi_.write(highLow);
00250     spi_.write(0x00);
00251     spi_.write(address & 0x3F);
00252     spi_.write(data);
00253 
00254     poll();
00255 
00256 }
00257 
00258 void AVR910::writeFlashMemoryByte(int highLow, int address, char data)
00259 {
00260 
00261     spi_.write(highLow);
00262     spi_.write(address & 0xFF00 >> 8);
00263     spi_.write(address & 0x00FF);
00264     spi_.write(data);
00265 
00266 }
00267 
00268 void AVR910::writeFlashMemoryPage(char pageNumber)
00269 {
00270 
00271     spi_.write(0x4C);
00272     spi_.write((pageNumber >> 2) & 0x3F);
00273     spi_.write((pageNumber & 0x03) << 6);
00274     spi_.write(0x00);
00275 
00276     poll();
00277 
00278 }
00279 
00280 char AVR910::readProgramMemory(int highLow, char pageNumber, char pageOffset)
00281 {
00282 
00283     int response = 0;
00284 
00285     spi_.write(highLow);
00286     spi_.write((pageNumber >> 2) & 0x3F);
00287     spi_.write(((pageNumber & 0x03) << 6) | (pageOffset & 0x3F));
00288     response = spi_.write(0x00);
00289 
00290     poll();
00291 
00292     return response;
00293 
00294 }
00295 
00296 
00297 int AVR910::checkMemoryData(int numPages, char* myData, int dataSize)
00298 {
00299     
00300     int success  = 0;
00301     int response = 0;
00302     char c       = 0;
00303 
00304     // start at the beginning of the original data
00305     int dpoint=0;
00306     
00307     for (int i = 0; i <= numPages; i++) {
00308         for (int j = 0; j < PAGE_SIZE; j++) {
00309 
00310             c = myData[dpoint];
00311             //Read program memory low byte.
00312             response = readProgramMemory(READ_LOW_BYTE, i, j);
00313             if ( c != response ) {
00314                 success = -1;
00315             }
00316             
00317             // next data item to check, break if all data has been checked
00318             dpoint++;
00319             if (dpoint==dataSize) break;
00320             c = myData[dpoint];
00321             
00322             //Read program memory high byte.
00323             response = readProgramMemory(READ_HIGH_BYTE, i, j);
00324             if ( c != response ) {
00325                 success = -1;
00326             }
00327             
00328             // next data item to check, break if all data has been checked
00329             dpoint++;
00330             if (dpoint==dataSize) break;
00331         }
00332     }
00333 
00334     return success;
00335 
00336 }