
AVRisp tested on ATMega88A inspired by various implementations around: - AVR_SPI_Programmer_v2 ( BO Qiang ) - mAVRISP (Aaron Berk) - TestAVRISP(Chester Hamilton)
AVRisp implementation for mBED
AVRISP/AVRISP.cpp@1:4b883042df7d, 2015-04-28 (annotated)
- Committer:
- Ellips
- Date:
- Tue Apr 28 11:01:19 2015 +0000
- Revision:
- 1:4b883042df7d
- Parent:
- 0:29abe3c0b902
AVRisp , v0.1
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Ellips | 0:29abe3c0b902 | 1 | #include "AVRISP.h" |
Ellips | 0:29abe3c0b902 | 2 | |
Ellips | 0:29abe3c0b902 | 3 | // constructor |
Ellips | 0:29abe3c0b902 | 4 | AVRISP::AVRISP(PinName mosi, PinName miso, PinName sclk, PinName reset, uint32_t targetClk, uint16_t pageSize, PRGCB pCB ) |
Ellips | 0:29abe3c0b902 | 5 | : spiPort(mosi, miso, sclk ) |
Ellips | 0:29abe3c0b902 | 6 | , resetPin(reset) |
Ellips | 0:29abe3c0b902 | 7 | , mPageSize(pageSize) |
Ellips | 0:29abe3c0b902 | 8 | , progressCB(pCB) |
Ellips | 0:29abe3c0b902 | 9 | { |
Ellips | 0:29abe3c0b902 | 10 | spiPort.frequency(targetClk>>2);//1/4 th of the clock frequency of the unit |
Ellips | 0:29abe3c0b902 | 11 | spiPort.format(8,0); |
Ellips | 0:29abe3c0b902 | 12 | } |
Ellips | 0:29abe3c0b902 | 13 | |
Ellips | 0:29abe3c0b902 | 14 | AVRISP::~AVRISP() |
Ellips | 0:29abe3c0b902 | 15 | { |
Ellips | 0:29abe3c0b902 | 16 | } |
Ellips | 0:29abe3c0b902 | 17 | |
Ellips | 0:29abe3c0b902 | 18 | //A function to poll BSY to prevent loading a new instruction prematurely |
Ellips | 0:29abe3c0b902 | 19 | void AVRISP::StillProgramming() |
Ellips | 0:29abe3c0b902 | 20 | { |
Ellips | 0:29abe3c0b902 | 21 | uint8_t check = 1; |
Ellips | 0:29abe3c0b902 | 22 | while(check & 0x1){//check LSB only |
Ellips | 0:29abe3c0b902 | 23 | spiPort.write(0xF0); |
Ellips | 0:29abe3c0b902 | 24 | spiPort.write(0x00); |
Ellips | 0:29abe3c0b902 | 25 | spiPort.write(0x00); |
Ellips | 0:29abe3c0b902 | 26 | check = spiPort.write(0x00); //read data byte out |
Ellips | 0:29abe3c0b902 | 27 | } |
Ellips | 0:29abe3c0b902 | 28 | } |
Ellips | 0:29abe3c0b902 | 29 | |
Ellips | 0:29abe3c0b902 | 30 | // enable programming mode |
Ellips | 0:29abe3c0b902 | 31 | bool AVRISP::EnableProgrammingMode() |
Ellips | 0:29abe3c0b902 | 32 | { |
Ellips | 0:29abe3c0b902 | 33 | int failed = 0; |
Ellips | 0:29abe3c0b902 | 34 | |
Ellips | 0:29abe3c0b902 | 35 | resetPin = 1; |
Ellips | 0:29abe3c0b902 | 36 | wait(0.02); |
Ellips | 0:29abe3c0b902 | 37 | resetPin = 0; |
Ellips | 0:29abe3c0b902 | 38 | wait(0.02); |
Ellips | 0:29abe3c0b902 | 39 | |
Ellips | 0:29abe3c0b902 | 40 | while(failed < 5) //loop to try to enable programming mode 5 times |
Ellips | 0:29abe3c0b902 | 41 | { |
Ellips | 0:29abe3c0b902 | 42 | spiPort.write(0xAC); |
Ellips | 0:29abe3c0b902 | 43 | spiPort.write(0x53); |
Ellips | 0:29abe3c0b902 | 44 | int echoBack= spiPort.write(0x00); |
Ellips | 0:29abe3c0b902 | 45 | if(echoBack == 0x53) |
Ellips | 0:29abe3c0b902 | 46 | { //if data read on 3rd byte load is 0x53 |
Ellips | 0:29abe3c0b902 | 47 | spiPort.write(0x00); //programming mode was enabled...good job! |
Ellips | 0:29abe3c0b902 | 48 | return true; |
Ellips | 0:29abe3c0b902 | 49 | } |
Ellips | 0:29abe3c0b902 | 50 | else |
Ellips | 0:29abe3c0b902 | 51 | { |
Ellips | 0:29abe3c0b902 | 52 | failed++; |
Ellips | 0:29abe3c0b902 | 53 | resetPin = 1; //pulse reset and try again |
Ellips | 0:29abe3c0b902 | 54 | resetPin = 0; |
Ellips | 0:29abe3c0b902 | 55 | wait(0.5); |
Ellips | 0:29abe3c0b902 | 56 | } |
Ellips | 0:29abe3c0b902 | 57 | } |
Ellips | 0:29abe3c0b902 | 58 | return false; //Bummer... |
Ellips | 0:29abe3c0b902 | 59 | } |
Ellips | 0:29abe3c0b902 | 60 | |
Ellips | 0:29abe3c0b902 | 61 | void AVRISP::LeaveProgrammingMode() |
Ellips | 0:29abe3c0b902 | 62 | { |
Ellips | 0:29abe3c0b902 | 63 | resetPin = 1; |
Ellips | 0:29abe3c0b902 | 64 | wait(0.02); |
Ellips | 0:29abe3c0b902 | 65 | } |
Ellips | 0:29abe3c0b902 | 66 | |
Ellips | 0:29abe3c0b902 | 67 | // read chip signature byte |
Ellips | 0:29abe3c0b902 | 68 | uint8_t AVRISP::ReadChipSignatureByte(SignatureByte Nr) |
Ellips | 0:29abe3c0b902 | 69 | { |
Ellips | 0:29abe3c0b902 | 70 | spiPort.write(0x30); |
Ellips | 0:29abe3c0b902 | 71 | spiPort.write(0x00); |
Ellips | 0:29abe3c0b902 | 72 | spiPort.write(Nr); |
Ellips | 0:29abe3c0b902 | 73 | return spiPort.write(0x00); |
Ellips | 0:29abe3c0b902 | 74 | } |
Ellips | 0:29abe3c0b902 | 75 | |
Ellips | 0:29abe3c0b902 | 76 | // erase chip |
Ellips | 0:29abe3c0b902 | 77 | void AVRISP::ChipErase() |
Ellips | 0:29abe3c0b902 | 78 | { |
Ellips | 0:29abe3c0b902 | 79 | spiPort.write(0xAC); |
Ellips | 0:29abe3c0b902 | 80 | spiPort.write(0x80); |
Ellips | 0:29abe3c0b902 | 81 | spiPort.write(0x00); |
Ellips | 0:29abe3c0b902 | 82 | spiPort.write(0x00); |
Ellips | 0:29abe3c0b902 | 83 | StillProgramming(); |
Ellips | 0:29abe3c0b902 | 84 | resetPin = 1; |
Ellips | 0:29abe3c0b902 | 85 | wait(0.02); |
Ellips | 0:29abe3c0b902 | 86 | resetPin = 0; |
Ellips | 0:29abe3c0b902 | 87 | wait(0.02); |
Ellips | 0:29abe3c0b902 | 88 | EnableProgrammingMode(); |
Ellips | 0:29abe3c0b902 | 89 | } |
Ellips | 0:29abe3c0b902 | 90 | |
Ellips | 0:29abe3c0b902 | 91 | // write fuse byte |
Ellips | 0:29abe3c0b902 | 92 | void AVRISP::WriteFuse(FuseType Typ, uint8_t fuse) |
Ellips | 0:29abe3c0b902 | 93 | { |
Ellips | 0:29abe3c0b902 | 94 | spiPort.write(0xAC); |
Ellips | 0:29abe3c0b902 | 95 | switch ( Typ ){ |
Ellips | 0:29abe3c0b902 | 96 | case eFTLo: |
Ellips | 0:29abe3c0b902 | 97 | spiPort.write(0xA0); break; |
Ellips | 0:29abe3c0b902 | 98 | case eFTHi: |
Ellips | 0:29abe3c0b902 | 99 | spiPort.write(0xA8); break; |
Ellips | 0:29abe3c0b902 | 100 | case eFTEx: |
Ellips | 0:29abe3c0b902 | 101 | spiPort.write(0xA4); break; |
Ellips | 0:29abe3c0b902 | 102 | case eFTLock: |
Ellips | 0:29abe3c0b902 | 103 | spiPort.write(0xE0); break; |
Ellips | 0:29abe3c0b902 | 104 | default: |
Ellips | 0:29abe3c0b902 | 105 | spiPort.write(0x00); break; |
Ellips | 0:29abe3c0b902 | 106 | }; |
Ellips | 0:29abe3c0b902 | 107 | spiPort.write(0x00); |
Ellips | 0:29abe3c0b902 | 108 | spiPort.write(fuse&0xff); |
Ellips | 0:29abe3c0b902 | 109 | StillProgramming(); |
Ellips | 0:29abe3c0b902 | 110 | } |
Ellips | 0:29abe3c0b902 | 111 | |
Ellips | 0:29abe3c0b902 | 112 | // read fuse byte |
Ellips | 0:29abe3c0b902 | 113 | uint8_t AVRISP::ReadFuse(FuseType Typ) |
Ellips | 0:29abe3c0b902 | 114 | { |
Ellips | 0:29abe3c0b902 | 115 | switch (Typ){ |
Ellips | 0:29abe3c0b902 | 116 | case eFTLo: |
Ellips | 0:29abe3c0b902 | 117 | spiPort.write(0x50); |
Ellips | 0:29abe3c0b902 | 118 | spiPort.write(0x00); |
Ellips | 0:29abe3c0b902 | 119 | break; |
Ellips | 0:29abe3c0b902 | 120 | case eFTHi: |
Ellips | 0:29abe3c0b902 | 121 | spiPort.write(0x58); |
Ellips | 0:29abe3c0b902 | 122 | spiPort.write(0x08); |
Ellips | 0:29abe3c0b902 | 123 | break; |
Ellips | 0:29abe3c0b902 | 124 | case eFTEx: |
Ellips | 0:29abe3c0b902 | 125 | spiPort.write(0x50); |
Ellips | 0:29abe3c0b902 | 126 | spiPort.write(0x08); |
Ellips | 0:29abe3c0b902 | 127 | break; |
Ellips | 0:29abe3c0b902 | 128 | case eFTLock: |
Ellips | 0:29abe3c0b902 | 129 | spiPort.write(0x58); |
Ellips | 0:29abe3c0b902 | 130 | spiPort.write(0x00); |
Ellips | 0:29abe3c0b902 | 131 | break; |
Ellips | 0:29abe3c0b902 | 132 | default: |
Ellips | 0:29abe3c0b902 | 133 | spiPort.write(0x00); |
Ellips | 0:29abe3c0b902 | 134 | spiPort.write(0x00); |
Ellips | 0:29abe3c0b902 | 135 | break; |
Ellips | 0:29abe3c0b902 | 136 | } |
Ellips | 0:29abe3c0b902 | 137 | spiPort.write(0x00); |
Ellips | 0:29abe3c0b902 | 138 | return spiPort.write(0x00); |
Ellips | 0:29abe3c0b902 | 139 | } |
Ellips | 0:29abe3c0b902 | 140 | #define LSB(I) ((I) & 0xFF) |
Ellips | 0:29abe3c0b902 | 141 | #define MSB(I) (((I) & 0xF00) >> 8) |
Ellips | 0:29abe3c0b902 | 142 | // write program page |
Ellips | 0:29abe3c0b902 | 143 | void AVRISP::WriteProgramPage(uint16_t addr) |
Ellips | 0:29abe3c0b902 | 144 | { |
Ellips | 0:29abe3c0b902 | 145 | //write program memory page |
Ellips | 0:29abe3c0b902 | 146 | spiPort.write(0x4C); |
Ellips | 0:29abe3c0b902 | 147 | spiPort.write(MSB(addr)); |
Ellips | 0:29abe3c0b902 | 148 | spiPort.write(LSB(addr)); |
Ellips | 0:29abe3c0b902 | 149 | spiPort.write(0x00); |
Ellips | 0:29abe3c0b902 | 150 | |
Ellips | 0:29abe3c0b902 | 151 | StillProgramming(); //make sure the operation worked |
Ellips | 0:29abe3c0b902 | 152 | } |
Ellips | 0:29abe3c0b902 | 153 | |
Ellips | 0:29abe3c0b902 | 154 | |
Ellips | 0:29abe3c0b902 | 155 | //function to load and write program memory |
Ellips | 0:29abe3c0b902 | 156 | //args: addr is the 12 bit address of the memory location |
Ellips | 0:29abe3c0b902 | 157 | // low_data and high_data are the values to write to that location |
Ellips | 0:29abe3c0b902 | 158 | void AVRISP::LoadProgramPage(uint16_t addr,uint8_t lowData,uint8_t highData)//int addr_MSB, |
Ellips | 0:29abe3c0b902 | 159 | { |
Ellips | 0:29abe3c0b902 | 160 | //load program memory low byte (little endian) |
Ellips | 0:29abe3c0b902 | 161 | spiPort.write(0x40); |
Ellips | 0:29abe3c0b902 | 162 | spiPort.write(0x00); |
Ellips | 0:29abe3c0b902 | 163 | spiPort.write(LSB(addr)); |
Ellips | 0:29abe3c0b902 | 164 | spiPort.write(lowData); |
Ellips | 0:29abe3c0b902 | 165 | |
Ellips | 0:29abe3c0b902 | 166 | //load program memory high byte |
Ellips | 0:29abe3c0b902 | 167 | spiPort.write(0x48); |
Ellips | 0:29abe3c0b902 | 168 | spiPort.write(0x00); |
Ellips | 0:29abe3c0b902 | 169 | spiPort.write(LSB(addr)); |
Ellips | 0:29abe3c0b902 | 170 | spiPort.write(highData); |
Ellips | 0:29abe3c0b902 | 171 | } |
Ellips | 0:29abe3c0b902 | 172 | |
Ellips | 0:29abe3c0b902 | 173 | inline uint8_t AVRISP::ReadByte(FILE *file) |
Ellips | 0:29abe3c0b902 | 174 | { |
Ellips | 0:29abe3c0b902 | 175 | char ascii_char[2]; |
Ellips | 0:29abe3c0b902 | 176 | fread(&ascii_char, 1, 2, file); |
Ellips | 0:29abe3c0b902 | 177 | return (((ascii_char[0] < 65) ? (ascii_char[0]-48) : (ascii_char[0]-55)) << 4) |
Ellips | 0:29abe3c0b902 | 178 | | ((ascii_char[1] < 65) ? (ascii_char[1]-48) : (ascii_char[1]-55)); |
Ellips | 0:29abe3c0b902 | 179 | } |
Ellips | 0:29abe3c0b902 | 180 | |
Ellips | 0:29abe3c0b902 | 181 | uint8_t AVRISP::ReadProgramFlash(uint16_t addr, bool highByte) |
Ellips | 0:29abe3c0b902 | 182 | { |
Ellips | 0:29abe3c0b902 | 183 | spiPort.write(highByte ? 0x28: 0x20 ); |
Ellips | 0:29abe3c0b902 | 184 | spiPort.write(MSB(addr)); |
Ellips | 0:29abe3c0b902 | 185 | spiPort.write(LSB(addr)); |
Ellips | 0:29abe3c0b902 | 186 | return spiPort.write(0x00); |
Ellips | 0:29abe3c0b902 | 187 | } |
Ellips | 0:29abe3c0b902 | 188 | #define AT_BOUNDARY(addr,size) ((addr % size) == (size -1)) |
Ellips | 0:29abe3c0b902 | 189 | // program flash |
Ellips | 0:29abe3c0b902 | 190 | |
Ellips | 0:29abe3c0b902 | 191 | //TODO: Implement address gaps in the hex file format |
Ellips | 0:29abe3c0b902 | 192 | bool AVRISP::ProgramFlash(FILE *hexFile) |
Ellips | 0:29abe3c0b902 | 193 | { |
Ellips | 0:29abe3c0b902 | 194 | int flag = 0; |
Ellips | 0:29abe3c0b902 | 195 | if(hexFile != NULL) |
Ellips | 0:29abe3c0b902 | 196 | { |
Ellips | 0:29abe3c0b902 | 197 | uint16_t address = 0; |
Ellips | 0:29abe3c0b902 | 198 | char temp; |
Ellips | 0:29abe3c0b902 | 199 | temp = fgetc(hexFile); |
Ellips | 0:29abe3c0b902 | 200 | while(flag == 0) |
Ellips | 0:29abe3c0b902 | 201 | { |
Ellips | 0:29abe3c0b902 | 202 | if(temp == ':') |
Ellips | 0:29abe3c0b902 | 203 | { |
Ellips | 0:29abe3c0b902 | 204 | uint8_t length = ReadByte(hexFile); |
Ellips | 0:29abe3c0b902 | 205 | if(length == 0) |
Ellips | 0:29abe3c0b902 | 206 | { |
Ellips | 0:29abe3c0b902 | 207 | flag = 1; |
Ellips | 0:29abe3c0b902 | 208 | } |
Ellips | 0:29abe3c0b902 | 209 | else |
Ellips | 0:29abe3c0b902 | 210 | { |
Ellips | 0:29abe3c0b902 | 211 | fseek(hexFile,6,SEEK_CUR); //2 if reading address |
Ellips | 0:29abe3c0b902 | 212 | |
Ellips | 0:29abe3c0b902 | 213 | for(uint8_t i=0;i<length;i+=2) |
Ellips | 0:29abe3c0b902 | 214 | { |
Ellips | 0:29abe3c0b902 | 215 | uint8_t lowData = ReadByte(hexFile); |
Ellips | 0:29abe3c0b902 | 216 | uint8_t highData = ReadByte(hexFile); |
Ellips | 0:29abe3c0b902 | 217 | |
Ellips | 0:29abe3c0b902 | 218 | //load data bytes here |
Ellips | 0:29abe3c0b902 | 219 | LoadProgramPage(address,lowData,highData); |
Ellips | 0:29abe3c0b902 | 220 | |
Ellips | 0:29abe3c0b902 | 221 | if (AT_BOUNDARY(address, mPageSize)) // write page if 32 words have now been written |
Ellips | 0:29abe3c0b902 | 222 | { |
Ellips | 0:29abe3c0b902 | 223 | WriteProgramPage(address); |
Ellips | 0:29abe3c0b902 | 224 | if( progressCB ) (*progressCB)(); //activity callback |
Ellips | 0:29abe3c0b902 | 225 | } |
Ellips | 0:29abe3c0b902 | 226 | |
Ellips | 0:29abe3c0b902 | 227 | address++; |
Ellips | 0:29abe3c0b902 | 228 | } |
Ellips | 0:29abe3c0b902 | 229 | while((temp = fgetc(hexFile)) != ':'); |
Ellips | 0:29abe3c0b902 | 230 | } |
Ellips | 0:29abe3c0b902 | 231 | } |
Ellips | 0:29abe3c0b902 | 232 | else flag = 1; |
Ellips | 0:29abe3c0b902 | 233 | } |
Ellips | 0:29abe3c0b902 | 234 | WriteProgramPage(address);//write the last part |
Ellips | 0:29abe3c0b902 | 235 | } |
Ellips | 0:29abe3c0b902 | 236 | else |
Ellips | 0:29abe3c0b902 | 237 | { |
Ellips | 0:29abe3c0b902 | 238 | return false; |
Ellips | 0:29abe3c0b902 | 239 | } |
Ellips | 0:29abe3c0b902 | 240 | return true; |
Ellips | 0:29abe3c0b902 | 241 | } |
Ellips | 0:29abe3c0b902 | 242 | |
Ellips | 0:29abe3c0b902 | 243 | //TODO: Implement address gaps in the hex file format |
Ellips | 0:29abe3c0b902 | 244 | bool AVRISP::VerifyFlash(FILE* hexFile) |
Ellips | 0:29abe3c0b902 | 245 | { |
Ellips | 0:29abe3c0b902 | 246 | int flag = 0; |
Ellips | 0:29abe3c0b902 | 247 | bool Error = false; |
Ellips | 0:29abe3c0b902 | 248 | if(hexFile != NULL) |
Ellips | 0:29abe3c0b902 | 249 | { |
Ellips | 0:29abe3c0b902 | 250 | uint16_t address = 0; |
Ellips | 0:29abe3c0b902 | 251 | char temp; |
Ellips | 0:29abe3c0b902 | 252 | temp = fgetc(hexFile); |
Ellips | 0:29abe3c0b902 | 253 | while(flag == 0) |
Ellips | 0:29abe3c0b902 | 254 | { |
Ellips | 0:29abe3c0b902 | 255 | if(temp == ':') |
Ellips | 0:29abe3c0b902 | 256 | { |
Ellips | 0:29abe3c0b902 | 257 | uint8_t length = ReadByte(hexFile); |
Ellips | 0:29abe3c0b902 | 258 | if(length == 0) |
Ellips | 0:29abe3c0b902 | 259 | { |
Ellips | 0:29abe3c0b902 | 260 | flag = 1; |
Ellips | 0:29abe3c0b902 | 261 | } |
Ellips | 0:29abe3c0b902 | 262 | else |
Ellips | 0:29abe3c0b902 | 263 | { |
Ellips | 0:29abe3c0b902 | 264 | fseek(hexFile,6,SEEK_CUR); //2 if reading address |
Ellips | 0:29abe3c0b902 | 265 | |
Ellips | 0:29abe3c0b902 | 266 | for(uint8_t i=0;i<length;i+=2) |
Ellips | 0:29abe3c0b902 | 267 | { |
Ellips | 0:29abe3c0b902 | 268 | uint8_t lowData = ReadByte(hexFile); |
Ellips | 0:29abe3c0b902 | 269 | uint8_t highData = ReadByte(hexFile); |
Ellips | 0:29abe3c0b902 | 270 | uint8_t lowDataF = ReadProgramFlash(address, false); |
Ellips | 0:29abe3c0b902 | 271 | uint8_t highDataF = ReadProgramFlash(address, true); |
Ellips | 0:29abe3c0b902 | 272 | |
Ellips | 0:29abe3c0b902 | 273 | if( lowData != lowDataF || highData != highDataF ) |
Ellips | 0:29abe3c0b902 | 274 | { |
Ellips | 0:29abe3c0b902 | 275 | printf( "\n@%04x src %02x,%02x != %02x,%02x\n", address, lowData, highData, lowDataF,highDataF); |
Ellips | 0:29abe3c0b902 | 276 | Error = true; |
Ellips | 0:29abe3c0b902 | 277 | } |
Ellips | 0:29abe3c0b902 | 278 | |
Ellips | 0:29abe3c0b902 | 279 | if (AT_BOUNDARY(address, mPageSize)) |
Ellips | 0:29abe3c0b902 | 280 | { |
Ellips | 0:29abe3c0b902 | 281 | if( progressCB ) (*progressCB)(); //activity callback |
Ellips | 0:29abe3c0b902 | 282 | } |
Ellips | 0:29abe3c0b902 | 283 | address++; |
Ellips | 0:29abe3c0b902 | 284 | } |
Ellips | 0:29abe3c0b902 | 285 | while((temp = fgetc(hexFile)) != ':'); |
Ellips | 0:29abe3c0b902 | 286 | } |
Ellips | 0:29abe3c0b902 | 287 | } |
Ellips | 0:29abe3c0b902 | 288 | else flag = 1; |
Ellips | 0:29abe3c0b902 | 289 | } |
Ellips | 0:29abe3c0b902 | 290 | if(Error) |
Ellips | 0:29abe3c0b902 | 291 | return false; |
Ellips | 0:29abe3c0b902 | 292 | } |
Ellips | 0:29abe3c0b902 | 293 | else |
Ellips | 0:29abe3c0b902 | 294 | { |
Ellips | 0:29abe3c0b902 | 295 | return false; |
Ellips | 0:29abe3c0b902 | 296 | } |
Ellips | 0:29abe3c0b902 | 297 | |
Ellips | 0:29abe3c0b902 | 298 | return true; |
Ellips | 0:29abe3c0b902 | 299 | } |