Прошить PIC ардуиной
- Войдите на сайт для отправки комментариев
Пт, 26/01/2018 - 00:41
нужно прошить 8-ми лапый Dip PIC 12F675 .Нашел вот здесь инфу, что можно пик прошить ардуиной . Там автор выложил скетч для ардуино, схему подключения и программу для прошивки пика ардуиной. Далее там люди благодарят автора, что у них получилось, значит скетч должен быть рабочий, но у меня почему то не компилируется (файл скетча выложен с расширением *.pde ). Компилятор много чего ругает, мне не понятно. Может кто подскажет, если не сложно.
0001 | /* |
0002 | * Copyright (C) 2012 Southern Storm Software, Pty Ltd. |
0003 | * |
0004 | * This program is free software: you can redistribute it and/or modify |
0005 | * it under the terms of the GNU General Public License as published by |
0006 | * the Free Software Foundation, either version 3 of the License, or |
0007 | * (at your option) any later version. |
0008 | * |
0009 | * This program is distributed in the hope that it will be useful, |
0010 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
0011 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
0012 | * GNU General Public License for more details. |
0013 | * |
0014 | * You should have received a copy of the GNU General Public License |
0015 | * along with this program. If not, see <<a href="http://www.gnu.org/licenses/" rel="nofollow">http://www.gnu.org/licenses/</a>>. |
0016 | */ |
0017 |
0018 | #define __PROG_TYPES_COMPAT__ |
0019 | #include <avr/pgmspace.h> // For PROGMEM |
0020 |
0021 | // Pin mappings for the PIC programming shield. |
0022 | #define PIN_MCLR A1 // 0: MCLR is VPP voltage, 1: Reset PIC |
0023 | #define PIN_ACTIVITY A5 // LED that indicates read/write activity |
0024 | #define PIN_VDD 2 // Controls the power to the PIC |
0025 | #define PIN_CLOCK 4 // Clock pin |
0026 | #define PIN_DATA 7 // Data pin |
0027 |
0028 | #define MCLR_RESET HIGH // PIN_MCLR state to reset the PIC |
0029 | #define MCLR_VPP LOW // PIN_MCLR state to apply 13v to MCLR/VPP pin |
0030 |
0031 | // All delays are in microseconds. |
0032 | #define DELAY_SETTLE 50 // Delay for lines to settle for reset |
0033 | #define DELAY_TPPDP 5 // Hold time after raising MCLR |
0034 | #define DELAY_THLD0 5 // Hold time after raising VDD |
0035 | #define DELAY_TSET1 1 // Data in setup time before lowering clock |
0036 | #define DELAY_THLD1 1 // Data in hold time after lowering clock |
0037 | #define DELAY_TDLY2 1 // Delay between commands or data |
0038 | #define DELAY_TDLY3 1 // Delay until data bit read will be valid |
0039 | #define DELAY_TPROG 4000 // Time for a program memory write to complete |
0040 | #define DELAY_TDPROG 6000 // Time for a data memory write to complete |
0041 | #define DELAY_TERA 6000 // Time for a word erase to complete |
0042 | #define DELAY_TPROG5 1000 // Time for program write on FLASH5 systems |
0043 | #define DELAY_TFULLERA 50000 // Time for a full chip erase |
0044 | #define DELAY_TFULL84 20000 // Intermediate wait for PIC16F84/PIC16F84A |
0045 |
0046 | // Commands that may be sent to the device. |
0047 | #define CMD_LOAD_CONFIG 0x00 // Load (write) to config memory |
0048 | #define CMD_LOAD_PROGRAM_MEMORY 0x02 // Load to program memory |
0049 | #define CMD_LOAD_DATA_MEMORY 0x03 // Load to data memory |
0050 | #define CMD_INCREMENT_ADDRESS 0x06 // Increment the PC |
0051 | #define CMD_READ_PROGRAM_MEMORY 0x04 // Read from program memory |
0052 | #define CMD_READ_DATA_MEMORY 0x05 // Read from data memory |
0053 | #define CMD_BEGIN_PROGRAM 0x08 // Begin programming with erase cycle |
0054 | #define CMD_BEGIN_PROGRAM_ONLY 0x18 // Begin programming only cycle |
0055 | #define CMD_END_PROGRAM_ONLY 0x17 // End programming only cycle |
0056 | #define CMD_BULK_ERASE_PROGRAM 0x09 // Bulk erase program memory |
0057 | #define CMD_BULK_ERASE_DATA 0x0B // Bulk erase data memory |
0058 | #define CMD_CHIP_ERASE 0x1F // Erase the entire chip |
0059 |
0060 | // States this application may be in. |
0061 | #define STATE_IDLE 0 // Idle, device is held in the reset state |
0062 | #define STATE_PROGRAM 1 // Active, reading and writing program memory |
0063 | #define STATE_CONFIG 2 // Active, reading and writing config memory |
0064 | int state = STATE_IDLE; |
0065 |
0066 | // Flash types. Uses a similar naming system to picprog. |
0067 | #define EEPROM 0 |
0068 | #define FLASH 1 |
0069 | #define FLASH4 4 |
0070 | #define FLASH5 5 |
0071 |
0072 | unsigned long pc = 0; // Current program counter. |
0073 |
0074 | // Flat address ranges for the various memory spaces. Defaults to the values |
0075 | // for the PIC16F628A. "DEVICE" command updates to the correct values later. |
0076 | unsigned long programEnd = 0x07FF; |
0077 | unsigned long configStart = 0x2000; |
0078 | unsigned long configEnd = 0x2007; |
0079 | unsigned long dataStart = 0x2100; |
0080 | unsigned long dataEnd = 0x217F; |
0081 | unsigned long reservedStart = 0x0800; |
0082 | unsigned long reservedEnd = 0x07FF; |
0083 | unsigned int configSave = 0x0000; |
0084 | byte progFlashType = FLASH4; |
0085 | byte dataFlashType = EEPROM; |
0086 |
0087 | // Device names, forced out into PROGMEM. |
0088 | const char s_pic12f629[] PROGMEM = "pic12f629" ; |
0089 | const char s_pic12f675[] PROGMEM = "pic12f675" ; |
0090 | const char s_pic16f630[] PROGMEM = "pic16f630" ; |
0091 | const char s_pic16f676[] PROGMEM = "pic16f676" ; |
0092 | const char s_pic16f84[] PROGMEM = "pic16f84" ; |
0093 | const char s_pic16f84a[] PROGMEM = "pic16f84a" ; |
0094 | const char s_pic16f87[] PROGMEM = "pic16f87" ; |
0095 | const char s_pic16f88[] PROGMEM = "pic16f88" ; |
0096 | const char s_pic16f627[] PROGMEM = "pic16f627" ; |
0097 | const char s_pic16f627a[] PROGMEM = "pic16f627a" ; |
0098 | const char s_pic16f628[] PROGMEM = "pic16f628" ; |
0099 | const char s_pic16f628a[] PROGMEM = "pic16f628a" ; |
0100 | const char s_pic16f648a[] PROGMEM = "pic16f648a" ; |
0101 | const char s_pic16f882[] PROGMEM = "pic16f882" ; |
0102 | const char s_pic16f883[] PROGMEM = "pic16f883" ; |
0103 | const char s_pic16f884[] PROGMEM = "pic16f884" ; |
0104 | const char s_pic16f886[] PROGMEM = "pic16f886" ; |
0105 | const char s_pic16f887[] PROGMEM = "pic16f887" ; |
0106 |
0107 | // List of devices that are currently supported and their properties. |
0108 | // Note: most of these are based on published information and have not |
0109 | // been tested by the author. Patches welcome to improve the list. |
0110 | struct deviceInfo |
0111 | { |
0112 | const prog_char *name; // User-readable name of the device. |
0113 | prog_int16_t deviceId; // Device ID for the PIC (-1 if no id). |
0114 | prog_uint32_t programSize; // Size of program memory (words). |
0115 | prog_uint32_t configStart; // Flat address start of configuration memory. |
0116 | prog_uint32_t dataStart; // Flat address start of EEPROM data memory. |
0117 | prog_uint16_t configSize; // Number of configuration words. |
0118 | prog_uint16_t dataSize; // Size of EEPROM data memory (bytes). |
0119 | prog_uint16_t reservedWords; // Reserved program words (e.g. for OSCCAL). |
0120 | prog_uint16_t configSave; // Bits in config word to be saved. |
0121 | prog_uint8_t progFlashType; // Type of flash for program memory. |
0122 | prog_uint8_t dataFlashType; // Type of flash for data memory. |
0123 |
0124 | }; |
0125 | struct deviceInfo const devices[] PROGMEM = { |
0127 | {s_pic12f629, 0x0F80, 1024, 0x2000, 0x2100, 8, 128, 1, 0x3000, FLASH4, EEPROM}, |
0128 | {s_pic12f675, 0x0FC0, 1024, 0x2000, 0x2100, 8, 128, 1, 0x3000, FLASH4, EEPROM}, |
0129 | {s_pic16f630, 0x10C0, 1024, 0x2000, 0x2100, 8, 128, 1, 0x3000, FLASH4, EEPROM}, |
0130 | {s_pic16f676, 0x10E0, 1024, 0x2000, 0x2100, 8, 128, 1, 0x3000, FLASH4, EEPROM}, |
0131 |
0133 | {s_pic16f84, -1, 1024, 0x2000, 0x2100, 8, 64, 0, 0, FLASH, EEPROM}, |
0134 | {s_pic16f84a, 0x0560, 1024, 0x2000, 0x2100, 8, 64, 0, 0, FLASH, EEPROM}, |
0135 |
0137 | {s_pic16f87, 0x0720, 4096, 0x2000, 0x2100, 9, 256, 0, 0, FLASH5, EEPROM}, |
0138 | {s_pic16f88, 0x0760, 4096, 0x2000, 0x2100, 9, 256, 0, 0, FLASH5, EEPROM}, |
0139 |
0140 | // 627/628: <a href="http://ww1.microchip.com/downloads/en/DeviceDoc/30034d.pdf" title="http://ww1.microchip.com/downloads/en/DeviceDoc/30034d.pdf" rel="nofollow">http://ww1.microchip.com/downloads/en/DeviceDoc/30034d.pdf</a> |
0141 | // A series: <a href="http://ww1.microchip.com/downloads/en/DeviceDoc/41196g.pdf" title="http://ww1.microchip.com/downloads/en/DeviceDoc/41196g.pdf" rel="nofollow">http://ww1.microchip.com/downloads/en/DeviceDoc/41196g.pdf</a> |
0142 | {s_pic16f627, 0x07A0, 1024, 0x2000, 0x2100, 8, 128, 0, 0, FLASH, EEPROM}, |
0143 | {s_pic16f627a, 0x1040, 1024, 0x2000, 0x2100, 8, 128, 0, 0, FLASH4, EEPROM}, |
0144 | {s_pic16f628, 0x07C0, 2048, 0x2000, 0x2100, 8, 128, 0, 0, FLASH, EEPROM}, |
0145 | {s_pic16f628a, 0x1060, 2048, 0x2000, 0x2100, 8, 128, 0, 0, FLASH4, EEPROM}, |
0146 | {s_pic16f648a, 0x1100, 4096, 0x2000, 0x2100, 8, 256, 0, 0, FLASH4, EEPROM}, |
0147 |
0149 | {s_pic16f882, 0x2000, 2048, 0x2000, 0x2100, 9, 128, 0, 0, FLASH4, EEPROM}, |
0150 | {s_pic16f883, 0x2020, 4096, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM}, |
0151 | {s_pic16f884, 0x2040, 4096, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM}, |
0152 | {s_pic16f886, 0x2060, 8192, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM}, |
0153 | {s_pic16f887, 0x2080, 8192, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM}, |
0154 |
0155 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} |
0156 | }; |
0157 |
0158 | // Buffer for command-line character input and READBIN data packets. |
0159 | #define BINARY_TRANSFER_MAX 64 |
0160 | #define BUFFER_MAX (BINARY_TRANSFER_MAX + 1) |
0161 | char buffer[BUFFER_MAX]; |
0162 | int buflen = 0; |
0163 |
0164 | unsigned long lastActive = 0; |
0165 |
0166 | void setup () |
0167 | { |
0168 | // Need a serial link to the host. |
0169 | Serial .begin(9600); |
0170 |
0171 | // Hold the PIC in the powered down/reset state until we are ready for it. |
0172 | pinMode(PIN_MCLR, OUTPUT); |
0173 | pinMode(PIN_VDD, OUTPUT); |
0174 | digitalWrite(PIN_MCLR, MCLR_RESET); |
0175 | digitalWrite(PIN_VDD, LOW); |
0176 |
0177 | // Clock and data are floating until the first PIC command. |
0178 | pinMode(PIN_CLOCK, INPUT); |
0179 | pinMode(PIN_DATA, INPUT); |
0180 |
0181 | // Turn off the activity LED initially. |
0182 | pinMode(PIN_ACTIVITY, OUTPUT); |
0183 | digitalWrite(PIN_ACTIVITY, LOW); |
0184 | } |
0185 |
0186 | void loop () |
0187 | { |
0188 | if ( Serial .available()) { |
0189 | // Process serial input for commands from the host. |
0190 | int ch = Serial .read(); |
0191 | if (ch == 0x0A || ch == 0x0D) { |
0192 | // End of the current command. Blank lines are ignored. |
0193 | if (buflen > 0) { |
0194 | buffer[buflen] = '\0' ; |
0195 | buflen = 0; |
0196 | digitalWrite(PIN_ACTIVITY, HIGH); // Turn on activity LED. |
0197 | processCommand(buffer); |
0198 | digitalWrite(PIN_ACTIVITY, LOW); // Turn off activity LED. |
0199 | } |
0200 | } else if (ch == 0x08) { |
0201 | // Backspace over the last character. |
0202 | if (buflen > 0) |
0203 | --buflen; |
0204 | } else if (buflen < (BUFFER_MAX - 1)) { |
0205 | // Add the character to the buffer after forcing to upper case. |
0206 | if (ch >= 'a' && ch <= 'z' ) |
0207 | buffer[buflen++] = ch - 'a' + 'A' ; |
0208 | else |
0209 | buffer[buflen++] = ch; |
0210 | } |
0211 | lastActive = millis(); |
0212 | } else if (state != STATE_IDLE) { |
0213 | // Power off the programming socket if no activity for 2 seconds. |
0214 | // Normally the host will issue the "PWROFF" command, but if we are |
0215 | // operating in interactive mode or the host has crashed, then this |
0216 | // timeout will ensure that the system eventually enters safe mode. |
0217 | if ((millis() - lastActive) >= 2000) |
0218 | exitProgramMode(); |
0219 | } |
0220 | } |
0221 |
0222 | void printHex1(unsigned int value) |
0223 | { |
0224 | if (value >= 10) |
0225 | Serial .print(( char )( 'A' + value - 10)); |
0226 | else |
0227 | Serial .print(( char )( '0' + value)); |
0228 | } |
0229 |
0230 | void printHex4(unsigned int word) |
0231 | { |
0232 | printHex1((word >> 12) & 0x0F); |
0233 | printHex1((word >> 8) & 0x0F); |
0234 | printHex1((word >> 4) & 0x0F); |
0235 | printHex1(word & 0x0F); |
0236 | } |
0237 |
0238 | void printHex8(unsigned long word) |
0239 | { |
0240 | unsigned int upper = (unsigned int )(word >> 16); |
0241 | if (upper) |
0242 | printHex4(upper); |
0243 | printHex4((unsigned int )word); |
0244 | } |
0245 |
0246 | void printProgString( const prog_char *str) |
0247 | { |
0248 | for (;;) { |
0249 | char ch = ( char )(pgm_read_byte(str)); |
0250 | if (ch == '\0' ) |
0251 | break ; |
0252 | Serial .print(ch); |
0253 | ++str; |
0254 | } |
0255 | } |
0256 |
0257 | // PROGRAM_PIC_VERSION command. |
0258 | void cmdVersion( const char *args) |
0259 | { |
0260 | Serial .println( "ProgramPIC 1.0" ); |
0261 | } |
0262 |
0263 | // Initialize device properties from the "devices" list and |
0264 | // print them to the serial port. Note: "dev" is in PROGMEM. |
0265 | void initDevice( const struct deviceInfo *dev) |
0266 | { |
0267 | // Update the global device details. |
0268 | programEnd = pgm_read_dword(&(dev->programSize)) - 1; |
0269 | configStart = pgm_read_dword(&(dev->configStart)); |
0270 | configEnd = configStart + pgm_read_word(&(dev->configSize)) - 1; |
0271 | dataStart = pgm_read_dword(&(dev->dataStart)); |
0272 | dataEnd = dataStart + pgm_read_word(&(dev->dataSize)) - 1; |
0273 | reservedStart = programEnd - pgm_read_word(&(dev->reservedWords)) + 1; |
0274 | reservedEnd = programEnd; |
0275 | configSave = pgm_read_word(&(dev->configSave)); |
0276 | progFlashType = pgm_read_byte(&(dev->progFlashType)); |
0277 | dataFlashType = pgm_read_byte(&(dev->dataFlashType)); |
0278 |
0279 | // Print the extra device information. |
0280 | Serial .print( "DeviceName: " ); |
0281 | printProgString(( const prog_char *)(pgm_read_word(&(dev->name)))); |
0282 | Serial .println(); |
0283 | Serial .print( "ProgramRange: 0000-" ); |
0284 | printHex8(programEnd); |
0285 | Serial .println(); |
0286 | Serial .print( "ConfigRange: " ); |
0287 | printHex8(configStart); |
0288 | Serial .print( '-' ); |
0289 | printHex8(configEnd); |
0290 | Serial .println(); |
0291 | if (configSave != 0) { |
0292 | Serial .print( "ConfigSave: " ); |
0293 | printHex4(configSave); |
0294 | Serial .println(); |
0295 | } |
0296 | Serial .print( "DataRange: " ); |
0297 | printHex8(dataStart); |
0298 | Serial .print( '-' ); |
0299 | printHex8(dataEnd); |
0300 | Serial .println(); |
0301 | if (reservedStart <= reservedEnd) { |
0302 | Serial .print( "ReservedRange: " ); |
0303 | printHex8(reservedStart); |
0304 | Serial .print( '-' ); |
0305 | printHex8(reservedEnd); |
0306 | Serial .println(); |
0307 | } |
0308 | } |
0309 |
0310 | // Offsets of interesting config locations that contain device information. |
0311 | #define DEV_USERID0 0 |
0312 | #define DEV_USERID1 1 |
0313 | #define DEV_USERID2 2 |
0314 | #define DEV_USERID3 3 |
0315 | #define DEV_ID 6 |
0316 | #define DEV_CONFIG_WORD 7 |
0317 |
0318 | // DEVICE command. |
0319 | void cmdDevice( const char *args) |
0320 | { |
0321 | // Make sure the device is reset before we start. |
0322 | exitProgramMode(); |
0323 |
0324 | // Read identifiers and configuration words from config memory. |
0325 | unsigned int userid0 = readConfigWord(DEV_USERID0); |
0326 | unsigned int userid1 = readConfigWord(DEV_USERID1); |
0327 | unsigned int userid2 = readConfigWord(DEV_USERID2); |
0328 | unsigned int userid3 = readConfigWord(DEV_USERID3); |
0329 | unsigned int deviceId = readConfigWord(DEV_ID); |
0330 | unsigned int configWord = readConfigWord(DEV_CONFIG_WORD); |
0331 |
0332 | // If the device ID is all-zeroes or all-ones, then it could mean |
0333 | // one of the following: |
0334 | // |
0335 | // 1. There is no PIC in the programming socket. |
0336 | // 2. The VPP programming voltage is not available. |
0337 | // 3. Code protection is enabled and the PIC is unreadable. |
0338 | // 4. The PIC is an older model with no device identifier. |
0339 | // |
0340 | // Case 4 is the interesting one. We look for any word in configuration |
0341 | // memory or the first 16 words of program memory that is non-zero. |
0342 | // If we find a non-zero word, we assume that we have a PIC but we |
0343 | // cannot detect what type it is. |
0344 | if (deviceId == 0 || deviceId == 0x3FFF) { |
0345 | unsigned int word = userid0 | userid1 | userid2 | userid3 | configWord; |
0346 | unsigned int addr = 0; |
0347 | while (!word && addr < 16) { |
0348 | word |= readWord(addr); |
0349 | ++addr; |
0350 | } |
0351 | if (!word) { |
0352 | Serial .println( "ERROR" ); |
0353 | exitProgramMode(); |
0354 | return ; |
0355 | } |
0356 | deviceId = 0; |
0357 | } |
0358 |
0359 | Serial .println( "OK" ); |
0360 |
0361 | Serial .print( "DeviceID: " ); |
0362 | printHex4(deviceId); |
0363 | Serial .println(); |
0364 |
0365 | // Find the device in the built-in list if we have details for it. |
0366 | int index = 0; |
0367 | for (;;) { |
0368 | const prog_char *name = ( const prog_char *) |
0369 | (pgm_read_word(&(devices[index].name))); |
0370 | if (!name) { |
0371 | index = -1; |
0372 | break ; |
0373 | } |
0374 | int id = pgm_read_word(&(devices[index].deviceId)); |
0375 | if (id == (deviceId & 0xFFE0)) |
0376 | break ; |
0377 | ++index; |
0378 | } |
0379 | if (index >= 0) { |
0380 | initDevice(&(devices[index])); |
0381 | } else { |
0382 | // Reset the global parameters to their defaults. A separate |
0383 | // "SETDEVICE" command will be needed to set the correct values. |
0384 | programEnd = 0x07FF; |
0385 | configStart = 0x2000; |
0386 | configEnd = 0x2007; |
0387 | dataStart = 0x2100; |
0388 | dataEnd = 0x217F; |
0389 | reservedStart = 0x0800; |
0390 | reservedEnd = 0x07FF; |
0391 | configSave = 0x0000; |
0392 | progFlashType = FLASH4; |
0393 | dataFlashType = EEPROM; |
0394 | } |
0395 |
0396 | Serial .print( "ConfigWord: " ); |
0397 | printHex4(configWord); |
0398 | Serial .println(); |
0399 |
0400 | Serial .println( "." ); |
0401 |
0402 | // Don't need programming mode once the details have been read. |
0403 | exitProgramMode(); |
0404 | } |
0405 |
0406 | // DEVICES command. |
0407 | void cmdDevices( const char *args) |
0408 | { |
0409 | Serial .println( "OK" ); |
0410 | int index = 0; |
0411 | for (;;) { |
0412 | const prog_char *name = ( const prog_char *) |
0413 | (pgm_read_word(&(devices[index].name))); |
0414 | if (!name) |
0415 | break ; |
0416 | if (index > 0) { |
0417 | Serial .print( ',' ); |
0418 | if ((index % 6) == 0) |
0419 | Serial .println(); |
0420 | else |
0421 | Serial .print( ' ' ); |
0422 | } |
0423 | printProgString(name); |
0424 | int id = ( int )(pgm_read_word(&(devices[index].deviceId))); |
0425 | if (id != -1) |
0426 | Serial .print( '*' ); |
0427 | ++index; |
0428 | } |
0429 | Serial .println(); |
0430 | Serial .println( "." ); |
0431 | } |
0432 |
0433 | // SETDEVICE command. |
0434 | void cmdSetDevice( const char *args) |
0435 | { |
0436 | // Extract the name of the device from the command arguments. |
0437 | int len = 0; |
0438 | for (;;) { |
0439 | char ch = args[len]; |
0440 | if (ch == '\0' || ch == ' ' || ch == '\t' ) |
0441 | break ; |
0442 | ++len; |
0443 | } |
0444 |
0445 | // Look for the name in the devices list. |
0446 | int index = 0; |
0447 | for (;;) { |
0448 | const prog_char *name = ( const prog_char *) |
0449 | (pgm_read_word(&(devices[index].name))); |
0450 | if (!name) |
0451 | break ; |
0452 | if (matchString(name, args, len)) { |
0453 | Serial .println( "OK" ); |
0454 | initDevice(&(devices[index])); |
0455 | Serial .println( "." ); |
0456 | exitProgramMode(); // Force a reset upon the next command. |
0457 | return ; |
0458 | } |
0459 | ++index; |
0460 | } |
0461 | Serial .println( "ERROR" ); |
0462 | } |
0463 |
0464 | int parseHex( const char *args, unsigned long *value) |
0465 | { |
0466 | int size = 0; |
0467 | *value = 0; |
0468 | for (;;) { |
0469 | char ch = *args; |
0470 | if (ch >= '0' && ch <= '9' ) |
0471 | *value = (*value << 4) | (ch - '0' ); |
0472 | else if (ch >= 'A' && ch <= 'F' ) |
0473 | *value = (*value << 4) | (ch - 'A' + 10); |
0474 | else if (ch >= 'a' && ch <= 'f' ) |
0475 | *value = (*value << 4) | (ch - 'a' + 10); |
0476 | else |
0477 | break ; |
0478 | ++size; |
0479 | ++args; |
0480 | } |
0481 | if (*args != '\0' && *args != '-' && *args != ' ' && *args != '\t' ) |
0482 | return 0; |
0483 | return size; |
0484 | } |
0485 |
0486 | // Parse a range of addresses of the form START or START-END. |
0487 | bool parseRange( const char *args, unsigned long *start, unsigned long *end) |
0488 | { |
0489 | int size = parseHex(args, start); |
0490 | if (!size) |
0491 | return false ; |
0492 | args += size; |
0493 | while (*args == ' ' || *args == '\t' ) |
0494 | ++args; |
0495 | if (*args != '-' ) { |
0496 | *end = *start; |
0497 | return true ; |
0498 | } |
0499 | ++args; |
0500 | while (*args == ' ' || *args == '\t' ) |
0501 | ++args; |
0502 | if (!parseHex(args, end)) |
0503 | return false ; |
0504 | return *end >= *start; |
0505 | } |
0506 |
0507 | bool parseCheckedRange( const char *args, unsigned long *start, unsigned long *end) |
0508 | { |
0509 | // Parse the basic values and make sure that start <= end. |
0510 | if (!parseRange(args, start, end)) |
0511 | return false ; |
0512 |
0513 | // Check that both start and end are within the same memory area |
0514 | // and within the bounds of that memory area. |
0515 | if (*start <= programEnd) { |
0516 | if (*end > programEnd) |
0517 | return false ; |
0518 | } else if (*start >= configStart && *start <= configEnd) { |
0519 | if (*end < configStart || *end > configEnd) |
0520 | return false ; |
0521 | } else if (*start >= dataStart && *start <= dataEnd) { |
0522 | if (*end < dataStart || *end > dataEnd) |
0523 | return false ; |
0524 | } else { |
0525 | return false ; |
0526 | } |
0527 | return true ; |
0528 | } |
0529 |
0530 | // READ command. |
0531 | void cmdRead( const char *args) |
0532 | { |
0533 | unsigned long start; |
0534 | unsigned long end; |
0535 | if (!parseCheckedRange(args, &start, &end)) { |
0536 | Serial .println( "ERROR" ); |
0537 | return ; |
0538 | } |
0539 | Serial .println( "OK" ); |
0540 | int count = 0; |
0541 | bool activity = true ; |
0542 | while (start <= end) { |
0543 | unsigned int word = readWord(start); |
0544 | if (count > 0) { |
0545 | if ((count % 8) == 0) |
0546 | Serial .println(); |
0547 | else |
0548 | Serial .print( ' ' ); |
0549 | } |
0550 | printHex4(word); |
0551 | ++start; |
0552 | ++count; |
0553 | if ((count % 32) == 0) { |
0554 | // Toggle the activity LED to make it blink during long reads. |
0555 | activity = !activity; |
0556 | if (activity) |
0557 | digitalWrite(PIN_ACTIVITY, HIGH); |
0558 | else |
0559 | digitalWrite(PIN_ACTIVITY, LOW); |
0560 | } |
0561 | } |
0562 | Serial .println(); |
0563 | Serial .println( "." ); |
0564 | } |
0565 |
0566 | // READBIN command. |
0567 | void cmdReadBinary( const char *args) |
0568 | { |
0569 | unsigned long start; |
0570 | unsigned long end; |
0571 | if (!parseCheckedRange(args, &start, &end)) { |
0572 | Serial .println( "ERROR" ); |
0573 | return ; |
0574 | } |
0575 | Serial .println( "OK" ); |
0576 | int count = 0; |
0577 | bool activity = true ; |
0578 | size_t offset = 0; |
0579 | while (start <= end) { |
0580 | unsigned int word = readWord(start); |
0581 | buffer[++offset] = ( char )word; |
0582 | buffer[++offset] = ( char )(word >> 8); |
0583 | if (offset >= BINARY_TRANSFER_MAX) { |
0584 | // Buffer is full - flush it to the host. |
0585 | buffer[0] = ( char )offset; |
0586 | Serial .write(( const uint8_t *)buffer, offset + 1); |
0587 | offset = 0; |
0588 | } |
0589 | ++start; |
0590 | ++count; |
0591 | if ((count % 64) == 0) { |
0592 | // Toggle the activity LED to make it blink during long reads. |
0593 | activity = !activity; |
0594 | if (activity) |
0595 | digitalWrite(PIN_ACTIVITY, HIGH); |
0596 | else |
0597 | digitalWrite(PIN_ACTIVITY, LOW); |
0598 | } |
0599 | } |
0600 | if (offset > 0) { |
0601 | // Flush the final packet before the terminator. |
0602 | buffer[0] = ( char )offset; |
0603 | Serial .write(( const uint8_t *)buffer, offset + 1); |
0604 | } |
0605 | // Write the terminator (a zero-length packet). |
0606 | Serial .write((uint8_t)0x00); |
0607 | } |
0608 |
0609 | const char s_force[] PROGMEM = "FORCE" ; |
0610 |
0611 | // WRITE command. |
0612 | void cmdWrite( const char *args) |
0613 | { |
0614 | unsigned long addr; |
0615 | unsigned long limit; |
0616 | unsigned long value; |
0617 | int size; |
0618 |
0619 | // Was the "FORCE" option given? |
0620 | int len = 0; |
0621 | while (args[len] != '\0' && args[len] != ' ' && args[len] != '\t' ) |
0622 | ++len; |
0623 | bool force = matchString(s_force, args, len); |
0624 | if (force) { |
0625 | args += len; |
0626 | while (*args == ' ' || *args == '\t' ) |
0627 | ++args; |
0628 | } |
0629 |
0630 | size = parseHex(args, &addr); |
0631 | if (!size) { |
0632 | Serial .println( "ERROR" ); |
0633 | return ; |
0634 | } |
0635 | args += size; |
0636 | if (addr <= programEnd) { |
0637 | limit = programEnd; |
0638 | } else if (addr >= configStart && addr <= configEnd) { |
0639 | limit = configEnd; |
0640 | } else if (addr >= dataStart && addr <= dataEnd) { |
0641 | limit = dataEnd; |
0642 | } else { |
0643 | // Address is not within one of the valid ranges. |
0644 | Serial .println( "ERROR" ); |
0645 | return ; |
0646 | } |
0647 | int count = 0; |
0648 | for (;;) { |
0649 | while (*args == ' ' || *args == '\t' ) |
0650 | ++args; |
0651 | if (*args == '\0' ) |
0652 | break ; |
0653 | if (*args == '-' ) { |
0654 | Serial .println( "ERROR" ); |
0655 | return ; |
0656 | } |
0657 | size = parseHex(args, &value); |
0658 | if (!size) { |
0659 | Serial .println( "ERROR" ); |
0660 | return ; |
0661 | } |
0662 | args += size; |
0663 | if (addr > limit) { |
0664 | // We've reached the limit of this memory area, so fail. |
0665 | Serial .println( "ERROR" ); |
0666 | return ; |
0667 | } |
0668 | if (!force) { |
0669 | if (!writeWord(addr, (unsigned int )value)) { |
0670 | // The actual write to the device failed. |
0671 | Serial .println( "ERROR" ); |
0672 | return ; |
0673 | } |
0674 | } else { |
0675 | if (!writeWordForced(addr, (unsigned int )value)) { |
0676 | // The actual write to the device failed. |
0677 | Serial .println( "ERROR" ); |
0678 | return ; |
0679 | } |
0680 | } |
0681 | ++addr; |
0682 | ++count; |
0683 | } |
0684 | if (!count) { |
0685 | // Missing word argument. |
0686 | Serial .println( "ERROR" ); |
0687 | } else { |
0688 | Serial .println( "OK" ); |
0689 | } |
0690 | } |
0691 |
0692 | // Blocking serial read for use by WRITEBIN. |
0693 | int readBlocking() |
0694 | { |
0695 | while (! Serial .available()) |
0696 | ; // Do nothing. |
0697 | return Serial .read(); |
0698 | } |
0699 |
0700 | // WRITEBIN command. |
0701 | void cmdWriteBinary( const char *args) |
0702 | { |
0703 | unsigned long addr; |
0704 | unsigned long limit; |
0705 | int size; |
0706 |
0707 | // Was the "FORCE" option given? |
0708 | int len = 0; |
0709 | while (args[len] != '\0' && args[len] != ' ' && args[len] != '\t' ) |
0710 | ++len; |
0711 | bool force = matchString(s_force, args, len); |
0712 | if (force) { |
0713 | args += len; |
0714 | while (*args == ' ' || *args == '\t' ) |
0715 | ++args; |
0716 | } |
0717 |
0718 | size = parseHex(args, &addr); |
0719 | if (!size) { |
0720 | Serial .println( "ERROR" ); |
0721 | return ; |
0722 | } |
0723 | args += size; |
0724 | if (addr <= programEnd) { |
0725 | limit = programEnd; |
0726 | } else if (addr >= configStart && addr <= configEnd) { |
0727 | limit = configEnd; |
0728 | } else if (addr >= dataStart && addr <= dataEnd) { |
0729 | limit = dataEnd; |
0730 | } else { |
0731 | // Address is not within one of the valid ranges. |
0732 | Serial .println( "ERROR" ); |
0733 | return ; |
0734 | } |
0735 | Serial .println( "OK" ); |
0736 | int count = 0; |
0737 | bool activity = true ; |
0738 | for (;;) { |
0739 | // Read in the next binary packet. |
0740 | int len = readBlocking(); |
0741 | while (len == 0x0A && count == 0) { |
0742 | // Skip 0x0A bytes before the first packet as they are |
0743 | // probably part of a CRLF pair rather than a packet length. |
0744 | len = readBlocking(); |
0745 | } |
0746 |
0747 | // Stop if we have a zero packet length - end of upload. |
0748 | if (!len) |
0749 | break ; |
0750 |
0751 | // Read the contents of the packet from the serial input stream. |
0752 | int offset = 0; |
0753 | while (offset < len) { |
0754 | if (offset < BINARY_TRANSFER_MAX) { |
0755 | buffer[offset++] = ( char )readBlocking(); |
0756 | } else { |
0757 | readBlocking(); // Packet is too big - discard extra bytes. |
0758 | ++offset; |
0759 | } |
0760 | } |
0761 |
0762 | // Write the words to memory. |
0763 | for ( int posn = 0; posn < (len - 1); posn += 2) { |
0764 | if (addr > limit) { |
0765 | // We've reached the limit of this memory area, so fail. |
0766 | Serial .println( "ERROR" ); |
0767 | return ; |
0768 | } |
0769 | unsigned int value = |
0770 | (((unsigned int )buffer[posn]) & 0xFF) | |
0771 | ((((unsigned int )buffer[posn + 1]) & 0xFF) << 8); |
0772 | if (!force) { |
0773 | if (!writeWord(addr, (unsigned int )value)) { |
0774 | // The actual write to the device failed. |
0775 | Serial .println( "ERROR" ); |
0776 | return ; |
0777 | } |
0778 | } else { |
0779 | if (!writeWordForced(addr, (unsigned int )value)) { |
0780 | // The actual write to the device failed. |
0781 | Serial .println( "ERROR" ); |
0782 | return ; |
0783 | } |
0784 | } |
0785 | ++addr; |
0786 | ++count; |
0787 | if ((count % 24) == 0) { |
0788 | // Toggle the activity LED to make it blink during long writes. |
0789 | activity = !activity; |
0790 | if (activity) |
0791 | digitalWrite(PIN_ACTIVITY, HIGH); |
0792 | else |
0793 | digitalWrite(PIN_ACTIVITY, LOW); |
0794 | } |
0795 | } |
0796 |
0797 | // All words in this packet have been written successfully. |
0798 | Serial .println( "OK" ); |
0799 | } |
0800 | Serial .println( "OK" ); |
0801 | } |
0802 |
0803 | const char s_noPreserve[] PROGMEM = "NOPRESERVE" ; |
0804 |
0805 | // ERASE command. |
0806 | void cmdErase( const char *args) |
0807 | { |
0808 | // Was the "NOPRESERVE" option given? |
0809 | int len = 0; |
0810 | while (args[len] != '\0' && args[len] != ' ' && args[len] != '\t' ) |
0811 | ++len; |
0812 | bool preserve = !matchString(s_noPreserve, args, len); |
0813 |
0814 | // Preserve reserved words if necessary. |
0815 | unsigned int *reserved = 0; |
0816 | unsigned int configWord = 0x3FFF; |
0817 | if (preserve && reservedStart <= reservedEnd) { |
0818 | size_t size = ((size_t)(reservedEnd - reservedStart + 1)) |
0819 | * sizeof (unsigned int ); |
0820 | reserved = (unsigned int *)malloc(size); |
0821 | if (reserved) { |
0822 | unsigned long addr = reservedStart; |
0823 | int offset = 0; |
0824 | while (addr <= reservedEnd) { |
0825 | reserved[offset] = readWord(addr); |
0826 | ++addr; |
0827 | ++offset; |
0828 | } |
0829 | } else { |
0830 | // If we cannot preserve the reserved words, then abort now. |
0831 | Serial .println( "ERROR" ); |
0832 | return ; |
0833 | } |
0834 | } |
0835 | if (configSave != 0 && preserve) { |
0836 | // Some of the bits in the configuration word must also be saved. |
0837 | configWord &= ~configSave; |
0838 | configWord |= readWord(configStart + DEV_CONFIG_WORD) & configSave; |
0839 | } |
0840 |
0841 | // Perform the memory type specific erase sequence. |
0842 | switch (progFlashType) { |
0843 | case FLASH4: |
0844 | setErasePC(); |
0845 | sendSimpleCommand(CMD_BULK_ERASE_PROGRAM); |
0846 | delayMicroseconds(DELAY_TERA); |
0847 | sendSimpleCommand(CMD_BULK_ERASE_DATA); |
0848 | break ; |
0849 | case FLASH5: |
0850 | setErasePC(); |
0851 | sendSimpleCommand(CMD_CHIP_ERASE); |
0852 | break ; |
0853 | default : |
0854 | // Details for disabling code protection and erasing all memory |
0855 | // for PIC16F84/PIC16F84A comes from this doc, section 4.1: |
0857 | setErasePC(); |
0858 | for ( int count = 0; count < 7; ++count) |
0859 | sendSimpleCommand(CMD_INCREMENT_ADDRESS); // Advance to 0x2007 |
0860 | sendSimpleCommand(0x01); // Command 1 |
0861 | sendSimpleCommand(0x07); // Command 7 |
0862 | sendSimpleCommand(CMD_BEGIN_PROGRAM); |
0863 | delayMicroseconds(DELAY_TFULL84); |
0864 | sendSimpleCommand(0x01); // Command 1 |
0865 | sendSimpleCommand(0x07); // Command 7 |
0866 |
0867 | // Some FLASH devices need the data memory to be erased separately. |
0868 | sendWriteCommand(CMD_LOAD_DATA_MEMORY, 0x3FFF); |
0869 | sendSimpleCommand(CMD_BULK_ERASE_DATA); |
0870 | sendSimpleCommand(CMD_BEGIN_PROGRAM); |
0871 | break ; |
0872 | } |
0873 |
0874 | // Wait until the chip is fully erased. |
0875 | delayMicroseconds(DELAY_TFULLERA); |
0876 |
0877 | // Force the device to reset after it has been erased. |
0878 | exitProgramMode(); |
0879 | enterProgramMode(); |
0880 |
0881 | // Write the reserved words back to program memory. |
0882 | if (reserved) { |
0883 | unsigned long addr = reservedStart; |
0884 | int offset = 0; |
0885 | bool ok = true ; |
0886 | while (addr <= reservedEnd) { |
0887 | if (!writeWord(addr, reserved[offset])) |
0888 | ok = false ; |
0889 | ++addr; |
0890 | ++offset; |
0891 | } |
0892 | free(reserved); |
0893 | if (!ok) { |
0894 | // Reserved words did not read back correctly. |
0895 | Serial .println( "ERROR" ); |
0896 | return ; |
0897 | } |
0898 | } |
0899 |
0900 | // Forcibly write 0x3FFF over the configuration words as erase |
0901 | // sometimes won't reset the words (e.g. PIC16F628A). If the |
0902 | // write fails, then leave the words as-is - don't report the failure. |
0903 | for (unsigned long configAddr = configStart + DEV_CONFIG_WORD; |
0904 | configAddr <= configEnd; ++configAddr) |
0905 | writeWordForced(configAddr, configWord); |
0906 |
0907 | // Done. |
0908 | Serial .println( "OK" ); |
0909 | } |
0910 |
0911 | // PWROFF command. |
0912 | void cmdPowerOff( const char *args) |
0913 | { |
0914 | exitProgramMode(); |
0915 | Serial .println( "OK" ); |
0916 | } |
0917 |
0918 | // List of all commands that are understood by the programmer. |
0919 | typedef void (*commandFunc)( const char *args); |
0920 | typedef struct |
0921 | { |
0922 | const prog_char *name; |
0923 | commandFunc func; |
0924 | const prog_char *desc; |
0925 | const prog_char *args; |
0926 | } command_t; |
0927 | const char s_cmdRead[] PROGMEM = "READ" ; |
0928 | const char s_cmdReadDesc[] PROGMEM = |
0929 | "Reads program and data words from device memory (text)" ; |
0930 | const char s_cmdReadArgs[] PROGMEM = "STARTADDR[-ENDADDR]" ; |
0931 | const char s_cmdReadBinary[] PROGMEM = "READBIN" ; |
0932 | const char s_cmdReadBinaryDesc[] PROGMEM = |
0933 | "Reads program and data words from device memory (binary)" ; |
0934 | const char s_cmdWrite[] PROGMEM = "WRITE" ; |
0935 | const char s_cmdWriteDesc[] PROGMEM = |
0936 | "Writes program and data words to device memory (text)" ; |
0937 | const char s_cmdWriteArgs[] PROGMEM = "STARTADDR WORD [WORD ...]" ; |
0938 | const char s_cmdWriteBinary[] PROGMEM = "WRITEBIN" ; |
0939 | const char s_cmdWriteBinaryDesc[] PROGMEM = |
0940 | "Writes program and data words to device memory (binary)" ; |
0941 | const char s_cmdWriteBinaryArgs[] PROGMEM = "STARTADDR" ; |
0942 | const char s_cmdErase[] PROGMEM = "ERASE" ; |
0943 | const char s_cmdEraseDesc[] PROGMEM = |
0944 | "Erases the contents of program, configuration, and data memory" ; |
0945 | const char s_cmdDevice[] PROGMEM = "DEVICE" ; |
0946 | const char s_cmdDeviceDesc[] PROGMEM = |
0947 | "Probes the device and returns information about it" ; |
0948 | const char s_cmdDevices[] PROGMEM = "DEVICES" ; |
0949 | const char s_cmdDevicesDesc[] PROGMEM = |
0950 | "Returns a list of all supported device types" ; |
0951 | const char s_cmdSetDevice[] PROGMEM = "SETDEVICE" ; |
0952 | const char s_cmdSetDeviceDesc[] PROGMEM = |
0953 | "Sets a specific device type manually" ; |
0954 | const char s_cmdSetDeviceArgs[] PROGMEM = "DEVTYPE" ; |
0955 | const char s_cmdPowerOff[] PROGMEM = "PWROFF" ; |
0956 | const char s_cmdPowerOffDesc[] PROGMEM = |
0957 | "Powers off the device in the programming socket" ; |
0958 | const char s_cmdVersion[] PROGMEM = "PROGRAM_PIC_VERSION" ; |
0959 | const char s_cmdVersionDesc[] PROGMEM = |
0960 | "Prints the version of ProgramPIC" ; |
0961 | const char s_cmdHelp[] PROGMEM = "HELP" ; |
0962 | const char s_cmdHelpDesc[] PROGMEM = |
0963 | "Prints this help message" ; |
0964 | const command_t commands[] PROGMEM = { |
0965 | {s_cmdRead, cmdRead, s_cmdReadDesc, s_cmdReadArgs}, |
0966 | {s_cmdReadBinary, cmdReadBinary, s_cmdReadBinaryDesc, s_cmdReadArgs}, |
0967 | {s_cmdWrite, cmdWrite, s_cmdWriteDesc, s_cmdWriteArgs}, |
0968 | {s_cmdWriteBinary, cmdWriteBinary, s_cmdWriteBinaryDesc, s_cmdWriteBinaryArgs}, |
0969 | {s_cmdErase, cmdErase, s_cmdEraseDesc, 0}, |
0970 | {s_cmdDevice, cmdDevice, s_cmdDeviceDesc, 0}, |
0971 | {s_cmdDevices, cmdDevices, s_cmdDevicesDesc, 0}, |
0972 | {s_cmdSetDevice, cmdSetDevice, s_cmdSetDeviceDesc, s_cmdSetDeviceArgs}, |
0973 | {s_cmdPowerOff, cmdPowerOff, s_cmdPowerOffDesc, 0}, |
0974 | {s_cmdVersion, cmdVersion, s_cmdVersionDesc, 0}, |
0975 | {s_cmdHelp, cmdHelp, s_cmdHelpDesc, 0}, |
0976 | {0, 0} |
0977 | }; |
0978 |
0979 | // "HELP" command. |
0980 | void cmdHelp( const char *args) |
0981 | { |
0982 | Serial .println( "OK" ); |
0983 | int index = 0; |
0984 | for (;;) { |
0985 | const prog_char *name = ( const prog_char *) |
0986 | (pgm_read_word(&(commands[index].name))); |
0987 | if (!name) |
0988 | break ; |
0989 | const prog_char *desc = ( const prog_char *) |
0990 | (pgm_read_word(&(commands[index].desc))); |
0991 | const prog_char *args = ( const prog_char *) |
0992 | (pgm_read_word(&(commands[index].args))); |
0993 | printProgString(name); |
0994 | if (args) { |
0995 | Serial .print( ' ' ); |
0996 | printProgString(args); |
0997 | } |
0998 | Serial .println(); |
0999 | Serial .print( " " ); |
1000 | printProgString(desc); |
1001 | Serial .println(); |
1002 | ++index; |
1003 | } |
1004 | Serial .println( "." ); |
1005 | } |
1006 |
1007 | // Match a data-space string where the name comes from PROGMEM. |
1008 | bool matchString( const prog_char *name, const char *str, int len) |
1009 | { |
1010 | for (;;) { |
1011 | char ch1 = ( char )(pgm_read_byte(name)); |
1012 | if (ch1 == '\0' ) |
1013 | return len == 0; |
1014 | else if (len == 0) |
1015 | break ; |
1016 | if (ch1 >= 'a' && ch1 <= 'z' ) |
1017 | ch1 = ch1 - 'a' + 'A' ; |
1018 | char ch2 = *str; |
1019 | if (ch2 >= 'a' && ch2 <= 'z' ) |
1020 | ch2 = ch2 - 'a' + 'A' ; |
1021 | if (ch1 != ch2) |
1022 | break ; |
1023 | ++name; |
1024 | ++str; |
1025 | --len; |
1026 | } |
1027 | return false ; |
1028 | } |
1029 |
1030 | // Process commands from the host. |
1031 | void processCommand( const char *buf) |
1032 | { |
1033 | // Skip white space at the start of the command. |
1034 | while (*buf == ' ' || *buf == '\t' ) |
1035 | ++buf; |
1036 | if (*buf == '\0' ) |
1037 | return ; // Ignore blank lines. |
1038 |
1039 | // Extract the command portion of the line. |
1040 | const char *cmd = buf; |
1041 | int len = 0; |
1042 | for (;;) { |
1043 | char ch = *buf; |
1044 | if (ch == '\0' || ch == ' ' || ch == '\t' ) |
1045 | break ; |
1046 | ++buf; |
1047 | ++len; |
1048 | } |
1049 |
1050 | // Skip white space after the command name and before the arguments. |
1051 | while (*buf == ' ' || *buf == '\t' ) |
1052 | ++buf; |
1053 |
1054 | // Find the command and execute it. |
1055 | int index = 0; |
1056 | for (;;) { |
1057 | const prog_char *name = ( const prog_char *) |
1058 | (pgm_read_word(&(commands[index].name))); |
1059 | if (!name) |
1060 | break ; |
1061 | if (matchString(name, cmd, len)) { |
1062 | commandFunc func = |
1063 | (commandFunc)(pgm_read_word(&(commands[index].func))); |
1064 | (*func)(buf); |
1065 | return ; |
1066 | } |
1067 | ++index; |
1068 | } |
1069 |
1070 | // Unknown command. |
1071 | Serial .println( "NOTSUPPORTED" ); |
1072 | } |
1073 |
1074 | // Enter high voltage programming mode. |
1075 | void enterProgramMode() |
1076 | { |
1077 | // Bail out if already in programming mode. |
1078 | if (state != STATE_IDLE) |
1079 | return ; |
1080 |
1081 | // Lower MCLR, VDD, DATA, and CLOCK initially. This will put the |
1082 | // PIC into the powered-off, reset state just in case. |
1083 | digitalWrite(PIN_MCLR, MCLR_RESET); |
1084 | digitalWrite(PIN_VDD, LOW); |
1085 | digitalWrite(PIN_DATA, LOW); |
1086 | digitalWrite(PIN_CLOCK, LOW); |
1087 |
1088 | // Wait for the lines to settle. |
1089 | delayMicroseconds(DELAY_SETTLE); |
1090 |
1091 | // Switch DATA and CLOCK into outputs. |
1092 | pinMode(PIN_DATA, OUTPUT); |
1093 | pinMode(PIN_CLOCK, OUTPUT); |
1094 |
1095 | // Raise MCLR, then VDD. |
1096 | digitalWrite(PIN_MCLR, MCLR_VPP); |
1097 | delayMicroseconds(DELAY_TPPDP); |
1098 | digitalWrite(PIN_VDD, HIGH); |
1099 | delayMicroseconds(DELAY_THLD0); |
1100 |
1101 | // Now in program mode, starting at the first word of program memory. |
1102 | state = STATE_PROGRAM; |
1103 | pc = 0; |
1104 | } |
1105 |
1106 | // Exit programming mode and reset the device. |
1107 | void exitProgramMode() |
1108 | { |
1109 | // Nothing to do if already out of programming mode. |
1110 | if (state == STATE_IDLE) |
1111 | return ; |
1112 |
1113 | // Lower MCLR, VDD, DATA, and CLOCK. |
1114 | digitalWrite(PIN_MCLR, MCLR_RESET); |
1115 | digitalWrite(PIN_VDD, LOW); |
1116 | digitalWrite(PIN_DATA, LOW); |
1117 | digitalWrite(PIN_CLOCK, LOW); |
1118 |
1119 | // Float the DATA and CLOCK pins. |
1120 | pinMode(PIN_DATA, INPUT); |
1121 | pinMode(PIN_CLOCK, INPUT); |
1122 |
1123 | // Now in the idle state with the PIC powered off. |
1124 | state = STATE_IDLE; |
1125 | pc = 0; |
1126 | } |
1127 |
1128 | // Send a command to the PIC. |
1129 | void sendCommand( byte cmd) |
1130 | { |
1131 | for ( byte bit = 0; bit < 6; ++bit) { |
1132 | digitalWrite(PIN_CLOCK, HIGH); |
1133 | if (cmd & 1) |
1134 | digitalWrite(PIN_DATA, HIGH); |
1135 | else |
1136 | digitalWrite(PIN_DATA, LOW); |
1137 | delayMicroseconds(DELAY_TSET1); |
1138 | digitalWrite(PIN_CLOCK, LOW); |
1139 | delayMicroseconds(DELAY_THLD1); |
1140 | cmd >>= 1; |
1141 | } |
1142 | } |
1143 |
1144 | // Send a command to the PIC that has no arguments. |
1145 | void sendSimpleCommand( byte cmd) |
1146 | { |
1147 | sendCommand(cmd); |
1148 | delayMicroseconds(DELAY_TDLY2); |
1149 | } |
1150 |
1151 | // Send a command to the PIC that writes a data argument. |
1152 | void sendWriteCommand( byte cmd, unsigned int data) |
1153 | { |
1154 | sendCommand(cmd); |
1155 | delayMicroseconds(DELAY_TDLY2); |
1156 | for ( byte bit = 0; bit < 16; ++bit) { |
1157 | digitalWrite(PIN_CLOCK, HIGH); |
1158 | if (data & 1) |
1159 | digitalWrite(PIN_DATA, HIGH); |
1160 | else |
1161 | digitalWrite(PIN_DATA, LOW); |
1162 | delayMicroseconds(DELAY_TSET1); |
1163 | digitalWrite(PIN_CLOCK, LOW); |
1164 | delayMicroseconds(DELAY_THLD1); |
1165 | data >>= 1; |
1166 | } |
1167 | delayMicroseconds(DELAY_TDLY2); |
1168 | } |
1169 |
1170 | // Send a command to the PIC that reads back a data value. |
1171 | unsigned int sendReadCommand( byte cmd) |
1172 | { |
1173 | unsigned int data = 0; |
1174 | sendCommand(cmd); |
1175 | digitalWrite(PIN_DATA, LOW); |
1176 | pinMode(PIN_DATA, INPUT); |
1177 | delayMicroseconds(DELAY_TDLY2); |
1178 | for ( byte bit = 0; bit < 16; ++bit) { |
1179 | data >>= 1; |
1180 | digitalWrite(PIN_CLOCK, HIGH); |
1181 | delayMicroseconds(DELAY_TDLY3); |
1182 | if (digitalRead(PIN_DATA)) |
1183 | data |= 0x8000; |
1184 | digitalWrite(PIN_CLOCK, LOW); |
1185 | delayMicroseconds(DELAY_THLD1); |
1186 | } |
1187 | pinMode(PIN_DATA, OUTPUT); |
1188 | delayMicroseconds(DELAY_TDLY2); |
1189 | return data; |
1190 | } |
1191 |
1192 | // Set the program counter to a specific "flat" address. |
1193 | void setPC(unsigned long addr) |
1194 | { |
1195 | if (addr >= dataStart && addr <= dataEnd) { |
1196 | // Data memory. |
1197 | addr -= dataStart; |
1198 | if (state != STATE_PROGRAM || addr < pc) { |
1199 | // Device is off, currently looking at configuration memory, |
1200 | // or the address is further back. Reset the device. |
1201 | exitProgramMode(); |
1202 | enterProgramMode(); |
1203 | } |
1204 | } else if (addr >= configStart && addr <= configEnd) { |
1205 | // Configuration memory. |
1206 | addr -= configStart; |
1207 | if (state == STATE_IDLE) { |
1208 | // Enter programming mode and switch to config memory. |
1209 | enterProgramMode(); |
1210 | sendWriteCommand(CMD_LOAD_CONFIG, 0); |
1211 | state = STATE_CONFIG; |
1212 | } else if (state == STATE_PROGRAM) { |
1213 | // Switch from program memory to config memory. |
1214 | sendWriteCommand(CMD_LOAD_CONFIG, 0); |
1215 | state = STATE_CONFIG; |
1216 | pc = 0; |
1217 | } else if (addr < pc) { |
1218 | // Need to go backwards in config memory, so reset the device. |
1219 | exitProgramMode(); |
1220 | enterProgramMode(); |
1221 | sendWriteCommand(CMD_LOAD_CONFIG, 0); |
1222 | state = STATE_CONFIG; |
1223 | } |
1224 | } else { |
1225 | // Program memory. |
1226 | if (state != STATE_PROGRAM || addr < pc) { |
1227 | // Device is off, currently looking at configuration memory, |
1228 | // or the address is further back. Reset the device. |
1229 | exitProgramMode(); |
1230 | enterProgramMode(); |
1231 | } |
1232 | } |
1233 | while (pc < addr) { |
1234 | sendSimpleCommand(CMD_INCREMENT_ADDRESS); |
1235 | ++pc; |
1236 | } |
1237 | } |
1238 |
1239 | // Sets the PC for "erase mode", which is activated by loading the |
1240 | // data value 0x3FFF into location 0 of configuration memory. |
1241 | void setErasePC() |
1242 | { |
1243 | // Forcibly reset the device so we know what state it is in. |
1244 | exitProgramMode(); |
1245 | enterProgramMode(); |
1246 |
1247 | // Load 0x3FFF for the configuration. |
1248 | sendWriteCommand(CMD_LOAD_CONFIG, 0x3FFF); |
1249 | state = STATE_CONFIG; |
1250 | } |
1251 |
1252 | // Read a word from memory (program, config, or data depending upon addr). |
1253 | // The start and stop bits will be stripped from the raw value from the PIC. |
1254 | unsigned int readWord(unsigned long addr) |
1255 | { |
1256 | setPC(addr); |
1257 | if (addr >= dataStart && addr <= dataEnd) |
1258 | return (sendReadCommand(CMD_READ_DATA_MEMORY) >> 1) & 0x00FF; |
1259 | else |
1260 | return (sendReadCommand(CMD_READ_PROGRAM_MEMORY) >> 1) & 0x3FFF; |
1261 | } |
1262 |
1263 | // Read a word from config memory using relative, non-flat, addressing. |
1264 | // Used by the "DEVICE" command to fetch information about devices whose |
1265 | // flat address ranges are presently unknown. |
1266 | unsigned int readConfigWord(unsigned long addr) |
1267 | { |
1268 | if (state == STATE_IDLE) { |
1269 | // Enter programming mode and switch to config memory. |
1270 | enterProgramMode(); |
1271 | sendWriteCommand(CMD_LOAD_CONFIG, 0); |
1272 | state = STATE_CONFIG; |
1273 | } else if (state == STATE_PROGRAM) { |
1274 | // Switch from program memory to config memory. |
1275 | sendWriteCommand(CMD_LOAD_CONFIG, 0); |
1276 | state = STATE_CONFIG; |
1277 | pc = 0; |
1278 | } else if (addr < pc) { |
1279 | // Need to go backwards in config memory, so reset the device. |
1280 | exitProgramMode(); |
1281 | enterProgramMode(); |
1282 | sendWriteCommand(CMD_LOAD_CONFIG, 0); |
1283 | state = STATE_CONFIG; |
1284 | } |
1285 | while (pc < addr) { |
1286 | sendSimpleCommand(CMD_INCREMENT_ADDRESS); |
1287 | ++pc; |
1288 | } |
1289 | return (sendReadCommand(CMD_READ_PROGRAM_MEMORY) >> 1) & 0x3FFF; |
1290 | } |
1291 |
1292 | // Begin a programming cycle, depending upon the type of flash being written. |
1293 | void beginProgramCycle(unsigned long addr, bool isData) |
1294 | { |
1295 | switch (isData ? dataFlashType : progFlashType) { |
1296 | case FLASH: |
1297 | case EEPROM: |
1298 | sendSimpleCommand(CMD_BEGIN_PROGRAM); |
1299 | delayMicroseconds(DELAY_TDPROG + DELAY_TERA); |
1300 | break ; |
1301 | case FLASH4: |
1302 | sendSimpleCommand(CMD_BEGIN_PROGRAM); |
1303 | delayMicroseconds(DELAY_TPROG); |
1304 | break ; |
1305 | case FLASH5: |
1306 | sendSimpleCommand(CMD_BEGIN_PROGRAM_ONLY); |
1307 | delayMicroseconds(DELAY_TPROG5); |
1308 | sendSimpleCommand(CMD_END_PROGRAM_ONLY); |
1309 | break ; |
1310 | } |
1311 | } |
1312 |
1313 | // Write a word to memory (program, config, or data depending upon addr). |
1314 | // Returns true if the write succeeded, false if read-back failed to match. |
1315 | bool writeWord(unsigned long addr, unsigned int word) |
1316 | { |
1317 | unsigned int readBack; |
1318 | setPC(addr); |
1319 | if (addr >= dataStart && addr <= dataEnd) { |
1320 | word &= 0x00FF; |
1321 | sendWriteCommand(CMD_LOAD_DATA_MEMORY, word << 1); |
1322 | beginProgramCycle(addr, true ); |
1323 | readBack = sendReadCommand(CMD_READ_DATA_MEMORY); |
1324 | readBack = (readBack >> 1) & 0x00FF; |
1325 | } else if (!configSave || addr != (configStart + DEV_CONFIG_WORD)) { |
1326 | word &= 0x3FFF; |
1327 | sendWriteCommand(CMD_LOAD_PROGRAM_MEMORY, word << 1); |
1328 | beginProgramCycle(addr, false ); |
1329 | readBack = sendReadCommand(CMD_READ_PROGRAM_MEMORY); |
1330 | readBack = (readBack >> 1) & 0x3FFF; |
1331 | } else { |
1332 | // The configuration word has calibration bits within it that |
1333 | // must be preserved when we write to it. Read the current value |
1334 | // and preserve the necessary bits. |
1335 | readBack = (sendReadCommand(CMD_READ_PROGRAM_MEMORY) >> 1) & 0x3FFF; |
1336 | word = (readBack & configSave) | (word & 0x3FFF & ~configSave); |
1337 | sendWriteCommand(CMD_LOAD_PROGRAM_MEMORY, word << 1); |
1338 | beginProgramCycle(addr, false ); |
1339 | readBack = sendReadCommand(CMD_READ_PROGRAM_MEMORY); |
1340 | readBack = (readBack >> 1) & 0x3FFF; |
1341 | } |
1342 | return readBack == word; |
1343 | } |
1344 |
1345 | // Force a word to be written even if it normally would protect config bits. |
1346 | bool writeWordForced(unsigned long addr, unsigned int word) |
1347 | { |
1348 | unsigned int readBack; |
1349 | setPC(addr); |
1350 | if (addr >= dataStart && addr <= dataEnd) { |
1351 | word &= 0x00FF; |
1352 | sendWriteCommand(CMD_LOAD_DATA_MEMORY, word << 1); |
1353 | beginProgramCycle(addr, true ); |
1354 | readBack = sendReadCommand(CMD_READ_DATA_MEMORY); |
1355 | readBack = (readBack >> 1) & 0x00FF; |
1356 | } else { |
1357 | word &= 0x3FFF; |
1358 | sendWriteCommand(CMD_LOAD_PROGRAM_MEMORY, word << 1); |
1359 | beginProgramCycle(addr, false ); |
1360 | readBack = sendReadCommand(CMD_READ_PROGRAM_MEMORY); |
1361 | readBack = (readBack >> 1) & 0x3FFF; |
1362 | } |
1363 | return readBack == word; |
1364 | } |
создал тему, пока качалась версия IDE 1.0.5. На ней скомпилировалось. Если удастся залить hex в пик при помощи дуни, отпишусь
собрал всё по схеме - ВСЁ работает!!! Загрузил блинк
схема
MaksVV - просто интересно - а зачем в наше время нужны ПИКи? - они ж во всем сливают соответствующим АВР-кам
у меня от дядьки осталось вагон пиков)
b707, знаю как минимум одну фишку, которой нет в AVR. -у PICов есть асинхронный счётчик, и он может считать импульсы с частотами сильно выше собственной тактовой. Поэтому всё мало-мальски серьёзные частотометры делают на пиках. Ещё на некоторые популярные пики есть полностью переведённый на русский даташит, мелочь как грится, но приятно)
просто есть готовое устройство к повторению. Я бы с радостью переделал на AVR, но исходник никто не выложил. Я и так полгода собирался его сделать, только пик и останавливал)) Вот щас плату делаю. FTDI учиться паять надо, мелко всё это, однако, для ЛУТ.
это адаптер для диагностики подогревателей Eberspacher.
просто есть готовое устройство к повторению.
ну да, я так и предполагал. Для Пиков можно найти кучу полезных прошивок в инете...
И если что - я не наезжаю на ПИК. спросил именно из любопытства :)
собрал всё по схеме - ВСЁ работает!!! Загрузил блинк
схема
подключаю как написано в скетче, ничего не происходит, помоги пожалуйста, не могу ответ найти второй вечер
что не происходит. программа горит зелёным? сом или connect? внимательнее проверьте схему подключения
13 вольт через транзистор нужно?
я 12 подавал, да, через транзистор. Светодиод не подключал.
схема вроде как такая должна быть.
Спасибо, уже понижайку настроил от ноутбучного блока питания, вечером попробую.
Erase не помогает, куда копать?
вроде прошивка залилась, но в окне одни нули
может где не контачит, нули не должны. Может это erase прошёл
полсе erase там 3FFF
или имя файла не выбрали и он пустоту с нулями залил.
залил блинк, диод не покдлючал, но видно что код залился.
а это уже файл прошивки, который нужно прошить
подал на pic ровно 13 вольт, читал что это может быть защита от чтения, мало верится
Непонятно , дак всё таки получилось или нет?
нет, не работает в устройстве, думаю собирать програматор для COM порта
дак блинк ведь загрузился. Проверьте с реальным диодом. Если будет мигать и всё норм, то прошивка с проектом у вас корявая , наверное. посмотрите её в НЕХ редакторе, какие там байты
Прошу помощи народ, кто шарит в прошивке PIC-ов. Нужно прошить 18F25k50, в списке поддерживаемых микросхем на гитхабе этого контроллера нет. Как я понял принцип программирования пиков по сути идентичен (в основном), может можно добавить поддержку нужного мне чипа?
Точно такая же проблема. Write error to device-Please erase device first, надыбал исходники этой программы на VB. вроде как связано с самим хекс файлом. Решил проблему с этим? Я пробовал нажимать reset на прошивающей ардуино. Но он вроде начинает заливать, но потом останавливается и уходит в бутлуп, но проивка не заливается.
Точно такая же проблема. Write error to device-Please erase device first, надыбал исходники этой программы на VB. вроде как связано с самим хекс файлом. Решил проблему с этим? Я пробовал нажимать reset на прошивающей ардуино. Но он вроде начинает заливать, но потом останавливается и уходит в бутлуп, но проивка не заливается.
это адаптер для диагностики подогревателей Eberspacher.
какая последовательность действий при прошивки? Для чего кнопка reset используется ардуиновская?? нигде не нашел описание у них на сайте для чего она нужна.
на сколько помню не нажимал я ресет на ардуине. Все так шьётся, по клику в проге.
Просто у них на сайте есть два варианта схемы,один вариант без кнопки ресет и двух индикаторных светодиодов дополнительных, а второй вариант с ними. Второй вариант, который у вас для новой версии. Предполагаю, что для новой версии , где уже указаны новые контроллеры,это и нужно. У меня PIC16F877.. Версия скетча 1.8. Для версии 1.0 он вообще не работал В списке скетча он есть, и он определяется, считывается и даже вроде как стирается, но при записи выдает вот эту ошибку сразу "Write error to device - Please erase device first!" . Если же зажать кнопку ресет на некоторое время, то он начинает показывать, что будто бы записывает, НО ОООчень медленно. Отпускаешь кнопку и он вроде опять как продолжает записывать, но через какое-то время просто уходит в бутлуп, а прога не записывается, контроллер чист. Контроллер причем новый.
Прошу помощи народ, кто шарит в прошивке PIC-ов. Нужно прошить 18F25k50, в списке поддерживаемых микросхем на гитхабе этого контроллера нет. Как я понял принцип программирования пиков по сути идентичен (в основном), может можно добавить поддержку нужного мне чипа?
Зайдите в любой сервисный центр, наверняка зашьют, там чипрогами пользуются
А добавлять новые чипы видимо придётся в нескольких местах и не только в прошивке
0001
/*
0002
* Copyright (C) 2012 Southern Storm Software, Pty Ltd.
0003
*
0004
* This program is free software: you can redistribute it and/or modify
0005
* it under the terms of the GNU General Public License as published by
0006
* the Free Software Foundation, either version 3 of the License, or
0007
* (at your option) any later version.
0008
*
0009
* This program is distributed in the hope that it will be useful,
0010
* but WITHOUT ANY WARRANTY; without even the implied warranty of
0011
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0012
* GNU General Public License for more details.
0013
*
0014
* You should have received a copy of the GNU General Public License
0015
* along with this program. If not, see <<a href="http://www.gnu.org/licenses/" rel="nofollow">http://www.gnu.org/licenses/</a>>.
0016
*/
0017
0018
#define __PROG_TYPES_COMPAT__
0019
#include <avr/pgmspace.h> // For PROGMEM
0020
0021
// Pin mappings for the PIC programming shield.
0022
#define PIN_MCLR A1 // 0: MCLR is VPP voltage, 1: Reset PIC
0023
#define PIN_ACTIVITY A5 // LED that indicates read/write activity
0024
#define PIN_VDD 2 // Controls the power to the PIC
0025
#define PIN_CLOCK 4 // Clock pin
0026
#define PIN_DATA 7 // Data pin
0027
0028
#define MCLR_RESET HIGH // PIN_MCLR state to reset the PIC
0029
#define MCLR_VPP LOW // PIN_MCLR state to apply 13v to MCLR/VPP pin
0030
0031
// All delays are in microseconds.
0032
#define DELAY_SETTLE 50 // Delay for lines to settle for reset
0033
#define DELAY_TPPDP 5 // Hold time after raising MCLR
0034
#define DELAY_THLD0 5 // Hold time after raising VDD
0035
#define DELAY_TSET1 1 // Data in setup time before lowering clock
0036
#define DELAY_THLD1 1 // Data in hold time after lowering clock
0037
#define DELAY_TDLY2 1 // Delay between commands or data
0038
#define DELAY_TDLY3 1 // Delay until data bit read will be valid
0039
#define DELAY_TPROG 4000 // Time for a program memory write to complete
0040
#define DELAY_TDPROG 6000 // Time for a data memory write to complete
0041
#define DELAY_TERA 6000 // Time for a word erase to complete
0042
#define DELAY_TPROG5 1000 // Time for program write on FLASH5 systems
0043
#define DELAY_TFULLERA 50000 // Time for a full chip erase
0044
#define DELAY_TFULL84 20000 // Intermediate wait for PIC16F84/PIC16F84A
0045
0046
// Commands that may be sent to the device.
0047
#define CMD_LOAD_CONFIG 0x00 // Load (write) to config memory
0048
#define CMD_LOAD_PROGRAM_MEMORY 0x02 // Load to program memory
0049
#define CMD_LOAD_DATA_MEMORY 0x03 // Load to data memory
0050
#define CMD_INCREMENT_ADDRESS 0x06 // Increment the PC
0051
#define CMD_READ_PROGRAM_MEMORY 0x04 // Read from program memory
0052
#define CMD_READ_DATA_MEMORY 0x05 // Read from data memory
0053
#define CMD_BEGIN_PROGRAM 0x08 // Begin programming with erase cycle
0054
#define CMD_BEGIN_PROGRAM_ONLY 0x18 // Begin programming only cycle
0055
#define CMD_END_PROGRAM_ONLY 0x17 // End programming only cycle
0056
#define CMD_BULK_ERASE_PROGRAM 0x09 // Bulk erase program memory
0057
#define CMD_BULK_ERASE_DATA 0x0B // Bulk erase data memory
0058
#define CMD_CHIP_ERASE 0x1F // Erase the entire chip
0059
0060
// States this application may be in.
0061
#define STATE_IDLE 0 // Idle, device is held in the reset state
0062
#define STATE_PROGRAM 1 // Active, reading and writing program memory
0063
#define STATE_CONFIG 2 // Active, reading and writing config memory
0064
int
state = STATE_IDLE;
0065
0066
// Flash types. Uses a similar naming system to picprog.
0067
#define EEPROM 0
0068
#define FLASH 1
0069
#define FLASH4 4
0070
#define FLASH5 5
0071
0072
unsigned
long
pc = 0;
// Current program counter.
0073
0074
// Flat address ranges for the various memory spaces. Defaults to the values
0075
// for the PIC16F628A. "DEVICE" command updates to the correct values later.
0076
unsigned
long
programEnd = 0x07FF;
0077
unsigned
long
configStart = 0x2000;
0078
unsigned
long
configEnd = 0x2007;
0079
unsigned
long
dataStart = 0x2100;
0080
unsigned
long
dataEnd = 0x217F;
0081
unsigned
long
reservedStart = 0x0800;
0082
unsigned
long
reservedEnd = 0x07FF;
0083
unsigned
int
configSave = 0x0000;
0084
byte
progFlashType = FLASH4;
0085
byte
dataFlashType = EEPROM;
0086
0087
// Device names, forced out into PROGMEM.
0088
const
char
s_pic12f629[] PROGMEM =
"pic12f629"
;
0089
const
char
s_pic12f675[] PROGMEM =
"pic12f675"
;
0090
const
char
s_pic16f630[] PROGMEM =
"pic16f630"
;
0091
const
char
s_pic16f676[] PROGMEM =
"pic16f676"
;
0092
const
char
s_pic16f84[] PROGMEM =
"pic16f84"
;
0093
const
char
s_pic16f84a[] PROGMEM =
"pic16f84a"
;
0094
const
char
s_pic16f87[] PROGMEM =
"pic16f87"
;
0095
const
char
s_pic16f88[] PROGMEM =
"pic16f88"
;
0096
const
char
s_pic16f627[] PROGMEM =
"pic16f627"
;
0097
const
char
s_pic16f627a[] PROGMEM =
"pic16f627a"
;
0098
const
char
s_pic16f628[] PROGMEM =
"pic16f628"
;
0099
const
char
s_pic16f628a[] PROGMEM =
"pic16f628a"
;
0100
const
char
s_pic16f648a[] PROGMEM =
"pic16f648a"
;
0101
const
char
s_pic16f882[] PROGMEM =
"pic16f882"
;
0102
const
char
s_pic16f883[] PROGMEM =
"pic16f883"
;
0103
const
char
s_pic16f884[] PROGMEM =
"pic16f884"
;
0104
const
char
s_pic16f886[] PROGMEM =
"pic16f886"
;
0105
const
char
s_pic16f887[] PROGMEM =
"pic16f887"
;
0106
const
char
s_pic18f25k50[] PROGMEM =
"pic18f25k50"
;
0107
0108
// List of devices that are currently supported and their properties.
0109
// Note: most of these are based on published information and have not
0110
// been tested by the author. Patches welcome to improve the list.
0111
struct
deviceInfo
0112
{
0113
const
prog_char *name;
// User-readable name of the device.
0114
prog_int16_t deviceId;
// Device ID for the PIC (-1 if no id).
0115
prog_uint32_t programSize;
// Size of program memory (words).
0116
prog_uint32_t configStart;
// Flat address start of configuration memory.
0117
prog_uint32_t dataStart;
// Flat address start of EEPROM data memory.
0118
prog_uint16_t configSize;
// Number of configuration words.
0119
prog_uint16_t dataSize;
// Size of EEPROM data memory (bytes).
0120
prog_uint16_t reservedWords;
// Reserved program words (e.g. for OSCCAL).
0121
prog_uint16_t configSave;
// Bits in config word to be saved.
0122
prog_uint8_t progFlashType;
// Type of flash for program memory.
0123
prog_uint8_t dataFlashType;
// Type of flash for data memory.
0124
0125
};
0126
struct
deviceInfo
const
devices[] PROGMEM = {
0127
// <a href="http://ww1.microchip.com/downloads/en/DeviceDoc/41191D.pdf" title="http://ww1.microchip.com/downloads/en/DeviceDoc/41191D.pdf" rel="nofollow">http://ww1.microchip.com/downloads/en/DeviceDoc/41191D.pdf</a>
0128
{s_pic12f629, 0x0F80, 1024, 0x2000, 0x2100, 8, 128, 1, 0x3000, FLASH4, EEPROM},
0129
{s_pic12f675, 0x0FC0, 1024, 0x2000, 0x2100, 8, 128, 1, 0x3000, FLASH4, EEPROM},
0130
{s_pic16f630, 0x10C0, 1024, 0x2000, 0x2100, 8, 128, 1, 0x3000, FLASH4, EEPROM},
0131
{s_pic16f676, 0x10E0, 1024, 0x2000, 0x2100, 8, 128, 1, 0x3000, FLASH4, EEPROM},
0132
0133
// <a href="http://ww1.microchip.com/downloads/en/DeviceDoc/30262e.pdf" title="http://ww1.microchip.com/downloads/en/DeviceDoc/30262e.pdf" rel="nofollow">http://ww1.microchip.com/downloads/en/DeviceDoc/30262e.pdf</a>
0134
{s_pic16f84, -1, 1024, 0x2000, 0x2100, 8, 64, 0, 0, FLASH, EEPROM},
0135
{s_pic16f84a, 0x0560, 1024, 0x2000, 0x2100, 8, 64, 0, 0, FLASH, EEPROM},
0136
0137
// <a href="http://ww1.microchip.com/downloads/en/DeviceDoc/39607c.pdf" title="http://ww1.microchip.com/downloads/en/DeviceDoc/39607c.pdf" rel="nofollow">http://ww1.microchip.com/downloads/en/DeviceDoc/39607c.pdf</a>
0138
{s_pic16f87, 0x0720, 4096, 0x2000, 0x2100, 9, 256, 0, 0, FLASH5, EEPROM},
0139
{s_pic16f88, 0x0760, 4096, 0x2000, 0x2100, 9, 256, 0, 0, FLASH5, EEPROM},
0140
0141
// 627/628: <a href="http://ww1.microchip.com/downloads/en/DeviceDoc/30034d.pdf" title="http://ww1.microchip.com/downloads/en/DeviceDoc/30034d.pdf" rel="nofollow">http://ww1.microchip.com/downloads/en/DeviceDoc/30034d.pdf</a>
0142
// A series: <a href="http://ww1.microchip.com/downloads/en/DeviceDoc/41196g.pdf" title="http://ww1.microchip.com/downloads/en/DeviceDoc/41196g.pdf" rel="nofollow">http://ww1.microchip.com/downloads/en/DeviceDoc/41196g.pdf</a>
0143
{s_pic16f627, 0x07A0, 1024, 0x2000, 0x2100, 8, 128, 0, 0, FLASH, EEPROM},
0144
{s_pic16f627a, 0x1040, 1024, 0x2000, 0x2100, 8, 128, 0, 0, FLASH4, EEPROM},
0145
{s_pic16f628, 0x07C0, 2048, 0x2000, 0x2100, 8, 128, 0, 0, FLASH, EEPROM},
0146
{s_pic16f628a, 0x1060, 2048, 0x2000, 0x2100, 8, 128, 0, 0, FLASH4, EEPROM},
0147
{s_pic16f648a, 0x1100, 4096, 0x2000, 0x2100, 8, 256, 0, 0, FLASH4, EEPROM},
0148
0149
// <a href="http://ww1.microchip.com/downloads/en/DeviceDoc/41287D.pdf" title="http://ww1.microchip.com/downloads/en/DeviceDoc/41287D.pdf" rel="nofollow">http://ww1.microchip.com/downloads/en/DeviceDoc/41287D.pdf</a>
0150
{s_pic16f882, 0x2000, 2048, 0x2000, 0x2100, 9, 128, 0, 0, FLASH4, EEPROM},
0151
{s_pic16f883, 0x2020, 4096, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM},
0152
{s_pic16f884, 0x2040, 4096, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM},
0153
{s_pic16f886, 0x2060, 8192, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM},
0154
{s_pic16f887, 0x2080, 8192, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM},
0155
0156
// new PIC18F25K50 исправить в соответствии с DATASHEET
0157
{s_pic18f25k50, 0x2000, 32768, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM},
0158
0159
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
0160
};
0161
0162
// Buffer for command-line character input and READBIN data packets.
0163
#define BINARY_TRANSFER_MAX 64
0164
#define BUFFER_MAX (BINARY_TRANSFER_MAX + 1)
0165
char
buffer[BUFFER_MAX];
0166
int
buflen = 0;
0167
0168
unsigned
long
lastActive = 0;
0169
0170
void
setup
()
0171
{
0172
// Need a serial link to the host.
0173
Serial
.begin(9600);
0174
0175
// Hold the PIC in the powered down/reset state until we are ready for it.
0176
pinMode(PIN_MCLR, OUTPUT);
0177
pinMode(PIN_VDD, OUTPUT);
0178
digitalWrite(PIN_MCLR, MCLR_RESET);
0179
digitalWrite(PIN_VDD, LOW);
0180
0181
// Clock and data are floating until the first PIC command.
0182
pinMode(PIN_CLOCK, INPUT);
0183
pinMode(PIN_DATA, INPUT);
0184
0185
// Turn off the activity LED initially.
0186
pinMode(PIN_ACTIVITY, OUTPUT);
0187
digitalWrite(PIN_ACTIVITY, LOW);
0188
}
0189
0190
void
loop
()
0191
{
0192
if
(
Serial
.available()) {
0193
// Process serial input for commands from the host.
0194
int
ch =
Serial
.read();
0195
if
(ch == 0x0A || ch == 0x0D) {
0196
// End of the current command. Blank lines are ignored.
0197
if
(buflen > 0) {
0198
buffer[buflen] =
'\0'
;
0199
buflen = 0;
0200
digitalWrite(PIN_ACTIVITY, HIGH);
// Turn on activity LED.
0201
processCommand(buffer);
0202
digitalWrite(PIN_ACTIVITY, LOW);
// Turn off activity LED.
0203
}
0204
}
else
if
(ch == 0x08) {
0205
// Backspace over the last character.
0206
if
(buflen > 0)
0207
--buflen;
0208
}
else
if
(buflen < (BUFFER_MAX - 1)) {
0209
// Add the character to the buffer after forcing to upper case.
0210
if
(ch >=
'a'
&& ch <=
'z'
)
0211
buffer[buflen++] = ch -
'a'
+
'A'
;
0212
else
0213
buffer[buflen++] = ch;
0214
}
0215
lastActive = millis();
0216
}
else
if
(state != STATE_IDLE) {
0217
// Power off the programming socket if no activity for 2 seconds.
0218
// Normally the host will issue the "PWROFF" command, but if we are
0219
// operating in interactive mode or the host has crashed, then this
0220
// timeout will ensure that the system eventually enters safe mode.
0221
if
((millis() - lastActive) >= 2000)
0222
exitProgramMode();
0223
}
0224
}
0225
0226
void
printHex1(unsigned
int
value)
0227
{
0228
if
(value >= 10)
0229
Serial
.print((
char
)(
'A'
+ value - 10));
0230
else
0231
Serial
.print((
char
)(
'0'
+ value));
0232
}
0233
0234
void
printHex4(unsigned
int
word)
0235
{
0236
printHex1((word >> 12) & 0x0F);
0237
printHex1((word >> 8) & 0x0F);
0238
printHex1((word >> 4) & 0x0F);
0239
printHex1(word & 0x0F);
0240
}
0241
0242
void
printHex8(unsigned
long
word)
0243
{
0244
unsigned
int
upper = (unsigned
int
)(word >> 16);
0245
if
(upper)
0246
printHex4(upper);
0247
printHex4((unsigned
int
)word);
0248
}
0249
0250
void
printProgString(
const
prog_char *str)
0251
{
0252
for
(;;) {
0253
char
ch = (
char
)(pgm_read_byte(str));
0254
if
(ch ==
'\0'
)
0255
break
;
0256
Serial
.print(ch);
0257
++str;
0258
}
0259
}
0260
0261
// PROGRAM_PIC_VERSION command.
0262
void
cmdVersion(
const
char
*args)
0263
{
0264
Serial
.println(
"ProgramPIC 1.0"
);
0265
}
0266
0267
// Initialize device properties from the "devices" list and
0268
// print them to the serial port. Note: "dev" is in PROGMEM.
0269
void
initDevice(
const
struct
deviceInfo *dev)
0270
{
0271
// Update the global device details.
0272
programEnd = pgm_read_dword(&(dev->programSize)) - 1;
0273
configStart = pgm_read_dword(&(dev->configStart));
0274
configEnd = configStart + pgm_read_word(&(dev->configSize)) - 1;
0275
dataStart = pgm_read_dword(&(dev->dataStart));
0276
dataEnd = dataStart + pgm_read_word(&(dev->dataSize)) - 1;
0277
reservedStart = programEnd - pgm_read_word(&(dev->reservedWords)) + 1;
0278
reservedEnd = programEnd;
0279
configSave = pgm_read_word(&(dev->configSave));
0280
progFlashType = pgm_read_byte(&(dev->progFlashType));
0281
dataFlashType = pgm_read_byte(&(dev->dataFlashType));
0282
0283
// Print the extra device information.
0284
Serial
.print(
"DeviceName: "
);
0285
printProgString((
const
prog_char *)(pgm_read_word(&(dev->name))));
0286
Serial
.println();
0287
Serial
.print(
"ProgramRange: 0000-"
);
0288
printHex8(programEnd);
0289
Serial
.println();
0290
Serial
.print(
"ConfigRange: "
);
0291
printHex8(configStart);
0292
Serial
.print(
'-'
);
0293
printHex8(configEnd);
0294
Serial
.println();
0295
if
(configSave != 0) {
0296
Serial
.print(
"ConfigSave: "
);
0297
printHex4(configSave);
0298
Serial
.println();
0299
}
0300
Serial
.print(
"DataRange: "
);
0301
printHex8(dataStart);
0302
Serial
.print(
'-'
);
0303
printHex8(dataEnd);
0304
Serial
.println();
0305
if
(reservedStart <= reservedEnd) {
0306
Serial
.print(
"ReservedRange: "
);
0307
printHex8(reservedStart);
0308
Serial
.print(
'-'
);
0309
printHex8(reservedEnd);
0310
Serial
.println();
0311
}
0312
}
0313
0314
// Offsets of interesting config locations that contain device information.
0315
#define DEV_USERID0 0
0316
#define DEV_USERID1 1
0317
#define DEV_USERID2 2
0318
#define DEV_USERID3 3
0319
#define DEV_ID 6
0320
#define DEV_CONFIG_WORD 7
0321
0322
// DEVICE command.
0323
void
cmdDevice(
const
char
*args)
0324
{
0325
// Make sure the device is reset before we start.
0326
exitProgramMode();
0327
0328
// Read identifiers and configuration words from config memory.
0329
unsigned
int
userid0 = readConfigWord(DEV_USERID0);
0330
unsigned
int
userid1 = readConfigWord(DEV_USERID1);
0331
unsigned
int
userid2 = readConfigWord(DEV_USERID2);
0332
unsigned
int
userid3 = readConfigWord(DEV_USERID3);
0333
unsigned
int
deviceId = readConfigWord(DEV_ID);
0334
unsigned
int
configWord = readConfigWord(DEV_CONFIG_WORD);
0335
0336
// If the device ID is all-zeroes or all-ones, then it could mean
0337
// one of the following:
0338
//
0339
// 1. There is no PIC in the programming socket.
0340
// 2. The VPP programming voltage is not available.
0341
// 3. Code protection is enabled and the PIC is unreadable.
0342
// 4. The PIC is an older model with no device identifier.
0343
//
0344
// Case 4 is the interesting one. We look for any word in configuration
0345
// memory or the first 16 words of program memory that is non-zero.
0346
// If we find a non-zero word, we assume that we have a PIC but we
0347
// cannot detect what type it is.
0348
if
(deviceId == 0 || deviceId == 0x3FFF) {
0349
unsigned
int
word = userid0 | userid1 | userid2 | userid3 | configWord;
0350
unsigned
int
addr = 0;
0351
while
(!word && addr < 16) {
0352
word |= readWord(addr);
0353
++addr;
0354
}
0355
if
(!word) {
0356
Serial
.println(
"ERROR"
);
0357
exitProgramMode();
0358
return
;
0359
}
0360
deviceId = 0;
0361
}
0362
0363
Serial
.println(
"OK"
);
0364
0365
Serial
.print(
"DeviceID: "
);
0366
printHex4(deviceId);
0367
Serial
.println();
0368
0369
// Find the device in the built-in list if we have details for it.
0370
int
index = 0;
0371
for
(;;) {
0372
const
prog_char *name = (
const
prog_char *)
0373
(pgm_read_word(&(devices[index].name)));
0374
if
(!name) {
0375
index = -1;
0376
break
;
0377
}
0378
int
id = pgm_read_word(&(devices[index].deviceId));
0379
if
(id == (deviceId & 0xFFE0))
0380
break
;
0381
++index;
0382
}
0383
if
(index >= 0) {
0384
initDevice(&(devices[index]));
0385
}
else
{
0386
// Reset the global parameters to their defaults. A separate
0387
// "SETDEVICE" command will be needed to set the correct values.
0388
programEnd = 0x07FF;
0389
configStart = 0x2000;
0390
configEnd = 0x2007;
0391
dataStart = 0x2100;
0392
dataEnd = 0x217F;
0393
reservedStart = 0x0800;
0394
reservedEnd = 0x07FF;
0395
configSave = 0x0000;
0396
progFlashType = FLASH4;
0397
dataFlashType = EEPROM;
0398
}
0399
0400
Serial
.print(
"ConfigWord: "
);
0401
printHex4(configWord);
0402
Serial
.println();
0403
0404
Serial
.println(
"."
);
0405
0406
// Don't need programming mode once the details have been read.
0407
exitProgramMode();
0408
}
0409
0410
// DEVICES command.
0411
void
cmdDevices(
const
char
*args)
0412
{
0413
Serial
.println(
"OK"
);
0414
int
index = 0;
0415
for
(;;) {
0416
const
prog_char *name = (
const
prog_char *)
0417
(pgm_read_word(&(devices[index].name)));
0418
if
(!name)
0419
break
;
0420
if
(index > 0) {
0421
Serial
.print(
','
);
0422
if
((index % 6) == 0)
0423
Serial
.println();
0424
else
0425
Serial
.print(
' '
);
0426
}
0427
printProgString(name);
0428
int
id = (
int
)(pgm_read_word(&(devices[index].deviceId)));
0429
if
(id != -1)
0430
Serial
.print(
'*'
);
0431
++index;
0432
}
0433
Serial
.println();
0434
Serial
.println(
"."
);
0435
}
0436
0437
// SETDEVICE command.
0438
void
cmdSetDevice(
const
char
*args)
0439
{
0440
// Extract the name of the device from the command arguments.
0441
int
len = 0;
0442
for
(;;) {
0443
char
ch = args[len];
0444
if
(ch ==
'\0'
|| ch ==
' '
|| ch ==
'\t'
)
0445
break
;
0446
++len;
0447
}
0448
0449
// Look for the name in the devices list.
0450
int
index = 0;
0451
for
(;;) {
0452
const
prog_char *name = (
const
prog_char *)
0453
(pgm_read_word(&(devices[index].name)));
0454
if
(!name)
0455
break
;
0456
if
(matchString(name, args, len)) {
0457
Serial
.println(
"OK"
);
0458
initDevice(&(devices[index]));
0459
Serial
.println(
"."
);
0460
exitProgramMode();
// Force a reset upon the next command.
0461
return
;
0462
}
0463
++index;
0464
}
0465
Serial
.println(
"ERROR"
);
0466
}
0467
0468
int
parseHex(
const
char
*args, unsigned
long
*value)
0469
{
0470
int
size = 0;
0471
*value = 0;
0472
for
(;;) {
0473
char
ch = *args;
0474
if
(ch >=
'0'
&& ch <=
'9'
)
0475
*value = (*value << 4) | (ch -
'0'
);
0476
else
if
(ch >=
'A'
&& ch <=
'F'
)
0477
*value = (*value << 4) | (ch -
'A'
+ 10);
0478
else
if
(ch >=
'a'
&& ch <=
'f'
)
0479
*value = (*value << 4) | (ch -
'a'
+ 10);
0480
else
0481
break
;
0482
++size;
0483
++args;
0484
}
0485
if
(*args !=
'\0'
&& *args !=
'-'
&& *args !=
' '
&& *args !=
'\t'
)
0486
return
0;
0487
return
size;
0488
}
0489
0490
// Parse a range of addresses of the form START or START-END.
0491
bool
parseRange(
const
char
*args, unsigned
long
*start, unsigned
long
*end)
0492
{
0493
int
size = parseHex(args, start);
0494
if
(!size)
0495
return
false
;
0496
args += size;
0497
while
(*args ==
' '
|| *args ==
'\t'
)
0498
++args;
0499
if
(*args !=
'-'
) {
0500
*end = *start;
0501
return
true
;
0502
}
0503
++args;
0504
while
(*args ==
' '
|| *args ==
'\t'
)
0505
++args;
0506
if
(!parseHex(args, end))
0507
return
false
;
0508
return
*end >= *start;
0509
}
0510
0511
bool
parseCheckedRange(
const
char
*args, unsigned
long
*start, unsigned
long
*end)
0512
{
0513
// Parse the basic values and make sure that start <= end.
0514
if
(!parseRange(args, start, end))
0515
return
false
;
0516
0517
// Check that both start and end are within the same memory area
0518
// and within the bounds of that memory area.
0519
if
(*start <= programEnd) {
0520
if
(*end > programEnd)
0521
return
false
;
0522
}
else
if
(*start >= configStart && *start <= configEnd) {
0523
if
(*end < configStart || *end > configEnd)
0524
return
false
;
0525
}
else
if
(*start >= dataStart && *start <= dataEnd) {
0526
if
(*end < dataStart || *end > dataEnd)
0527
return
false
;
0528
}
else
{
0529
return
false
;
0530
}
0531
return
true
;
0532
}
0533
0534
// READ command.
0535
void
cmdRead(
const
char
*args)
0536
{
0537
unsigned
long
start;
0538
unsigned
long
end;
0539
if
(!parseCheckedRange(args, &start, &end)) {
0540
Serial
.println(
"ERROR"
);
0541
return
;
0542
}
0543
Serial
.println(
"OK"
);
0544
int
count = 0;
0545
bool
activity =
true
;
0546
while
(start <= end) {
0547
unsigned
int
word = readWord(start);
0548
if
(count > 0) {
0549
if
((count % 8) == 0)
0550
Serial
.println();
0551
else
0552
Serial
.print(
' '
);
0553
}
0554
printHex4(word);
0555
++start;
0556
++count;
0557
if
((count % 32) == 0) {
0558
// Toggle the activity LED to make it blink during long reads.
0559
activity = !activity;
0560
if
(activity)
0561
digitalWrite(PIN_ACTIVITY, HIGH);
0562
else
0563
digitalWrite(PIN_ACTIVITY, LOW);
0564
}
0565
}
0566
Serial
.println();
0567
Serial
.println(
"."
);
0568
}
0569
0570
// READBIN command.
0571
void
cmdReadBinary(
const
char
*args)
0572
{
0573
unsigned
long
start;
0574
unsigned
long
end;
0575
if
(!parseCheckedRange(args, &start, &end)) {
0576
Serial
.println(
"ERROR"
);
0577
return
;
0578
}
0579
Serial
.println(
"OK"
);
0580
int
count = 0;
0581
bool
activity =
true
;
0582
size_t offset = 0;
0583
while
(start <= end) {
0584
unsigned
int
word = readWord(start);
0585
buffer[++offset] = (
char
)word;
0586
buffer[++offset] = (
char
)(word >> 8);
0587
if
(offset >= BINARY_TRANSFER_MAX) {
0588
// Buffer is full - flush it to the host.
0589
buffer[0] = (
char
)offset;
0590
Serial
.write((
const
uint8_t *)buffer, offset + 1);
0591
offset = 0;
0592
}
0593
++start;
0594
++count;
0595
if
((count % 64) == 0) {
0596
// Toggle the activity LED to make it blink during long reads.
0597
activity = !activity;
0598
if
(activity)
0599
digitalWrite(PIN_ACTIVITY, HIGH);
0600
else
0601
digitalWrite(PIN_ACTIVITY, LOW);
0602
}
0603
}
0604
if
(offset > 0) {
0605
// Flush the final packet before the terminator.
0606
buffer[0] = (
char
)offset;
0607
Serial
.write((
const
uint8_t *)buffer, offset + 1);
0608
}
0609
// Write the terminator (a zero-length packet).
0610
Serial
.write((uint8_t)0x00);
0611
}
0612
0613
const
char
s_force[] PROGMEM =
"FORCE"
;
0614
0615
// WRITE command.
0616
void
cmdWrite(
const
char
*args)
0617
{
0618
unsigned
long
addr;
0619
unsigned
long
limit;
0620
unsigned
long
value;
0621
int
size;
0622
0623
// Was the "FORCE" option given?
0624
int
len = 0;
0625
while
(args[len] !=
'\0'
&& args[len] !=
' '
&& args[len] !=
'\t'
)
0626
++len;
0627
bool
force = matchString(s_force, args, len);
0628
if
(force) {
0629
args += len;
0630
while
(*args ==
' '
|| *args ==
'\t'
)
0631
++args;
0632
}
0633
0634
size = parseHex(args, &addr);
0635
if
(!size) {
0636
Serial
.println(
"ERROR"
);
0637
return
;
0638
}
0639
args += size;
0640
if
(addr <= programEnd) {
0641
limit = programEnd;
0642
}
else
if
(addr >= configStart && addr <= configEnd) {
0643
limit = configEnd;
0644
}
else
if
(addr >= dataStart && addr <= dataEnd) {
0645
limit = dataEnd;
0646
}
else
{
0647
// Address is not within one of the valid ranges.
0648
Serial
.println(
"ERROR"
);
0649
return
;
0650
}
0651
int
count = 0;
0652
for
(;;) {
0653
while
(*args ==
' '
|| *args ==
'\t'
)
0654
++args;
0655
if
(*args ==
'\0'
)
0656
break
;
0657
if
(*args ==
'-'
) {
0658
Serial
.println(
"ERROR"
);
0659
return
;
0660
}
0661
size = parseHex(args, &value);
0662
if
(!size) {
0663
Serial
.println(
"ERROR"
);
0664
return
;
0665
}
0666
args += size;
0667
if
(addr > limit) {
0668
// We've reached the limit of this memory area, so fail.
0669
Serial
.println(
"ERROR"
);
0670
return
;
0671
}
0672
if
(!force) {
0673
if
(!writeWord(addr, (unsigned
int
)value)) {
0674
// The actual write to the device failed.
0675
Serial
.println(
"ERROR"
);
0676
return
;
0677
}
0678
}
else
{
0679
if
(!writeWordForced(addr, (unsigned
int
)value)) {
0680
// The actual write to the device failed.
0681
Serial
.println(
"ERROR"
);
0682
return
;
0683
}
0684
}
0685
++addr;
0686
++count;
0687
}
0688
if
(!count) {
0689
// Missing word argument.
0690
Serial
.println(
"ERROR"
);
0691
}
else
{
0692
Serial
.println(
"OK"
);
0693
}
0694
}
0695
0696
// Blocking serial read for use by WRITEBIN.
0697
int
readBlocking()
0698
{
0699
while
(!
Serial
.available())
0700
;
// Do nothing.
0701
return
Serial
.read();
0702
}
0703
0704
// WRITEBIN command.
0705
void
cmdWriteBinary(
const
char
*args)
0706
{
0707
unsigned
long
addr;
0708
unsigned
long
limit;
0709
int
size;
0710
0711
// Was the "FORCE" option given?
0712
int
len = 0;
0713
while
(args[len] !=
'\0'
&& args[len] !=
' '
&& args[len] !=
'\t'
)
0714
++len;
0715
bool
force = matchString(s_force, args, len);
0716
if
(force) {
0717
args += len;
0718
while
(*args ==
' '
|| *args ==
'\t'
)
0719
++args;
0720
}
0721
0722
size = parseHex(args, &addr);
0723
if
(!size) {
0724
Serial
.println(
"ERROR"
);
0725
return
;
0726
}
0727
args += size;
0728
if
(addr <= programEnd) {
0729
limit = programEnd;
0730
}
else
if
(addr >= configStart && addr <= configEnd) {
0731
limit = configEnd;
0732
}
else
if
(addr >= dataStart && addr <= dataEnd) {
0733
limit = dataEnd;
0734
}
else
{
0735
// Address is not within one of the valid ranges.
0736
Serial
.println(
"ERROR"
);
0737
return
;
0738
}
0739
Serial
.println(
"OK"
);
0740
int
count = 0;
0741
bool
activity =
true
;
0742
for
(;;) {
0743
// Read in the next binary packet.
0744
int
len = readBlocking();
0745
while
(len == 0x0A && count == 0) {
0746
// Skip 0x0A bytes before the first packet as they are
0747
// probably part of a CRLF pair rather than a packet length.
0748
len = readBlocking();
0749
}
0750
0751
// Stop if we have a zero packet length - end of upload.
0752
if
(!len)
0753
break
;
0754
0755
// Read the contents of the packet from the serial input stream.
0756
int
offset = 0;
0757
while
(offset < len) {
0758
if
(offset < BINARY_TRANSFER_MAX) {
0759
buffer[offset++] = (
char
)readBlocking();
0760
}
else
{
0761
readBlocking();
// Packet is too big - discard extra bytes.
0762
++offset;
0763
}
0764
}
0765
0766
// Write the words to memory.
0767
for
(
int
posn = 0; posn < (len - 1); posn += 2) {
0768
if
(addr > limit) {
0769
// We've reached the limit of this memory area, so fail.
0770
Serial
.println(
"ERROR"
);
0771
return
;
0772
}
0773
unsigned
int
value =
0774
(((unsigned
int
)buffer[posn]) & 0xFF) |
0775
((((unsigned
int
)buffer[posn + 1]) & 0xFF) << 8);
0776
if
(!force) {
0777
if
(!writeWord(addr, (unsigned
int
)value)) {
0778
// The actual write to the device failed.
0779
Serial
.println(
"ERROR"
);
0780
return
;
0781
}
0782
}
else
{
0783
if
(!writeWordForced(addr, (unsigned
int
)value)) {
0784
// The actual write to the device failed.
0785
Serial
.println(
"ERROR"
);
0786
return
;
0787
}
0788
}
0789
++addr;
0790
++count;
0791
if
((count % 24) == 0) {
0792
// Toggle the activity LED to make it blink during long writes.
0793
activity = !activity;
0794
if
(activity)
0795
digitalWrite(PIN_ACTIVITY, HIGH);
0796
else
0797
digitalWrite(PIN_ACTIVITY, LOW);
0798
}
0799
}
0800
0801
// All words in this packet have been written successfully.
0802
Serial
.println(
"OK"
);
0803
}
0804
Serial
.println(
"OK"
);
0805
}
0806
0807
const
char
s_noPreserve[] PROGMEM =
"NOPRESERVE"
;
0808
0809
// ERASE command.
0810
void
cmdErase(
const
char
*args)
0811
{
0812
// Was the "NOPRESERVE" option given?
0813
int
len = 0;
0814
while
(args[len] !=
'\0'
&& args[len] !=
' '
&& args[len] !=
'\t'
)
0815
++len;
0816
bool
preserve = !matchString(s_noPreserve, args, len);
0817
0818
// Preserve reserved words if necessary.
0819
unsigned
int
*reserved = 0;
0820
unsigned
int
configWord = 0x3FFF;
0821
if
(preserve && reservedStart <= reservedEnd) {
0822
size_t size = ((size_t)(reservedEnd - reservedStart + 1))
0823
*
sizeof
(unsigned
int
);
0824
reserved = (unsigned
int
*)malloc(size);
0825
if
(reserved) {
0826
unsigned
long
addr = reservedStart;
0827
int
offset = 0;
0828
while
(addr <= reservedEnd) {
0829
reserved[offset] = readWord(addr);
0830
++addr;
0831
++offset;
0832
}
0833
}
else
{
0834
// If we cannot preserve the reserved words, then abort now.
0835
Serial
.println(
"ERROR"
);
0836
return
;
0837
}
0838
}
0839
if
(configSave != 0 && preserve) {
0840
// Some of the bits in the configuration word must also be saved.
0841
configWord &= ~configSave;
0842
configWord |= readWord(configStart + DEV_CONFIG_WORD) & configSave;
0843
}
0844
0845
// Perform the memory type specific erase sequence.
0846
switch
(progFlashType) {
0847
case
FLASH4:
0848
setErasePC();
0849
sendSimpleCommand(CMD_BULK_ERASE_PROGRAM);
0850
delayMicroseconds(DELAY_TERA);
0851
sendSimpleCommand(CMD_BULK_ERASE_DATA);
0852
break
;
0853
case
FLASH5:
0854
setErasePC();
0855
sendSimpleCommand(CMD_CHIP_ERASE);
0856
break
;
0857
default
:
0858
// Details for disabling code protection and erasing all memory
0859
// for PIC16F84/PIC16F84A comes from this doc, section 4.1:
0860
// <a href="http://ww1.microchip.com/downloads/en/DeviceDoc/30262e.pdf" title="http://ww1.microchip.com/downloads/en/DeviceDoc/30262e.pdf" rel="nofollow">http://ww1.microchip.com/downloads/en/DeviceDoc/30262e.pdf</a>
0861
setErasePC();
0862
for
(
int
count = 0; count < 7; ++count)
0863
sendSimpleCommand(CMD_INCREMENT_ADDRESS);
// Advance to 0x2007
0864
sendSimpleCommand(0x01);
// Command 1
0865
sendSimpleCommand(0x07);
// Command 7
0866
sendSimpleCommand(CMD_BEGIN_PROGRAM);
0867
delayMicroseconds(DELAY_TFULL84);
0868
sendSimpleCommand(0x01);
// Command 1
0869
sendSimpleCommand(0x07);
// Command 7
0870
0871
// Some FLASH devices need the data memory to be erased separately.
0872
sendWriteCommand(CMD_LOAD_DATA_MEMORY, 0x3FFF);
0873
sendSimpleCommand(CMD_BULK_ERASE_DATA);
0874
sendSimpleCommand(CMD_BEGIN_PROGRAM);
0875
break
;
0876
}
0877
0878
// Wait until the chip is fully erased.
0879
delayMicroseconds(DELAY_TFULLERA);
0880
0881
// Force the device to reset after it has been erased.
0882
exitProgramMode();
0883
enterProgramMode();
0884
0885
// Write the reserved words back to program memory.
0886
if
(reserved) {
0887
unsigned
long
addr = reservedStart;
0888
int
offset = 0;
0889
bool
ok =
true
;
0890
while
(addr <= reservedEnd) {
0891
if
(!writeWord(addr, reserved[offset]))
0892
ok =
false
;
0893
++addr;
0894
++offset;
0895
}
0896
free(reserved);
0897
if
(!ok) {
0898
// Reserved words did not read back correctly.
0899
Serial
.println(
"ERROR"
);
0900
return
;
0901
}
0902
}
0903
0904
// Forcibly write 0x3FFF over the configuration words as erase
0905
// sometimes won't reset the words (e.g. PIC16F628A). If the
0906
// write fails, then leave the words as-is - don't report the failure.
0907
for
(unsigned
long
configAddr = configStart + DEV_CONFIG_WORD;
0908
configAddr <= configEnd; ++configAddr)
0909
writeWordForced(configAddr, configWord);
0910
0911
// Done.
0912
Serial
.println(
"OK"
);
0913
}
0914
0915
// PWROFF command.
0916
void
cmdPowerOff(
const
char
*args)
0917
{
0918
exitProgramMode();
0919
Serial
.println(
"OK"
);
0920
}
0921
0922
// List of all commands that are understood by the programmer.
0923
typedef
void
(*commandFunc)(
const
char
*args);
0924
typedef
struct
0925
{
0926
const
prog_char *name;
0927
commandFunc func;
0928
const
prog_char *desc;
0929
const
prog_char *args;
0930
} command_t;
0931
const
char
s_cmdRead[] PROGMEM =
"READ"
;
0932
const
char
s_cmdReadDesc[] PROGMEM =
0933
"Reads program and data words from device memory (text)"
;
0934
const
char
s_cmdReadArgs[] PROGMEM =
"STARTADDR[-ENDADDR]"
;
0935
const
char
s_cmdReadBinary[] PROGMEM =
"READBIN"
;
0936
const
char
s_cmdReadBinaryDesc[] PROGMEM =
0937
"Reads program and data words from device memory (binary)"
;
0938
const
char
s_cmdWrite[] PROGMEM =
"WRITE"
;
0939
const
char
s_cmdWriteDesc[] PROGMEM =
0940
"Writes program and data words to device memory (text)"
;
0941
const
char
s_cmdWriteArgs[] PROGMEM =
"STARTADDR WORD [WORD ...]"
;
0942
const
char
s_cmdWriteBinary[] PROGMEM =
"WRITEBIN"
;
0943
const
char
s_cmdWriteBinaryDesc[] PROGMEM =
0944
"Writes program and data words to device memory (binary)"
;
0945
const
char
s_cmdWriteBinaryArgs[] PROGMEM =
"STARTADDR"
;
0946
const
char
s_cmdErase[] PROGMEM =
"ERASE"
;
0947
const
char
s_cmdEraseDesc[] PROGMEM =
0948
"Erases the contents of program, configuration, and data memory"
;
0949
const
char
s_cmdDevice[] PROGMEM =
"DEVICE"
;
0950
const
char
s_cmdDeviceDesc[] PROGMEM =
0951
"Probes the device and returns information about it"
;
0952
const
char
s_cmdDevices[] PROGMEM =
"DEVICES"
;
0953
const
char
s_cmdDevicesDesc[] PROGMEM =
0954
"Returns a list of all supported device types"
;
0955
const
char
s_cmdSetDevice[] PROGMEM =
"SETDEVICE"
;
0956
const
char
s_cmdSetDeviceDesc[] PROGMEM =
0957
"Sets a specific device type manually"
;
0958
const
char
s_cmdSetDeviceArgs[] PROGMEM =
"DEVTYPE"
;
0959
const
char
s_cmdPowerOff[] PROGMEM =
"PWROFF"
;
0960
const
char
s_cmdPowerOffDesc[] PROGMEM =
0961
"Powers off the device in the programming socket"
;
0962
const
char
s_cmdVersion[] PROGMEM =
"PROGRAM_PIC_VERSION"
;
0963
const
char
s_cmdVersionDesc[] PROGMEM =
0964
"Prints the version of ProgramPIC"
;
0965
const
char
s_cmdHelp[] PROGMEM =
"HELP"
;
0966
const
char
s_cmdHelpDesc[] PROGMEM =
0967
"Prints this help message"
;
0968
const
command_t commands[] PROGMEM = {
0969
{s_cmdRead, cmdRead, s_cmdReadDesc, s_cmdReadArgs},
0970
{s_cmdReadBinary, cmdReadBinary, s_cmdReadBinaryDesc, s_cmdReadArgs},
0971
{s_cmdWrite, cmdWrite, s_cmdWriteDesc, s_cmdWriteArgs},
0972
{s_cmdWriteBinary, cmdWriteBinary, s_cmdWriteBinaryDesc, s_cmdWriteBinaryArgs},
0973
{s_cmdErase, cmdErase, s_cmdEraseDesc, 0},
0974
{s_cmdDevice, cmdDevice, s_cmdDeviceDesc, 0},
0975
{s_cmdDevices, cmdDevices, s_cmdDevicesDesc, 0},
0976
{s_cmdSetDevice, cmdSetDevice, s_cmdSetDeviceDesc, s_cmdSetDeviceArgs},
0977
{s_cmdPowerOff, cmdPowerOff, s_cmdPowerOffDesc, 0},
0978
{s_cmdVersion, cmdVersion, s_cmdVersionDesc, 0},
0979
{s_cmdHelp, cmdHelp, s_cmdHelpDesc, 0},
0980
{0, 0}
0981
};
0982
0983
// "HELP" command.
0984
void
cmdHelp(
const
char
*args)
0985
{
0986
Serial
.println(
"OK"
);
0987
int
index = 0;
0988
for
(;;) {
0989
const
prog_char *name = (
const
prog_char *)
0990
(pgm_read_word(&(commands[index].name)));
0991
if
(!name)
0992
break
;
0993
const
prog_char *desc = (
const
prog_char *)
0994
(pgm_read_word(&(commands[index].desc)));
0995
const
prog_char *args = (
const
prog_char *)
0996
(pgm_read_word(&(commands[index].args)));
0997
printProgString(name);
0998
if
(args) {
0999
Serial
.print(
' '
);
1000
printProgString(args);
1001
}
1002
Serial
.println();
1003
Serial
.print(
" "
);
1004
printProgString(desc);
1005
Serial
.println();
1006
++index;
1007
}
1008
Serial
.println(
"."
);
1009
}
1010
1011
// Match a data-space string where the name comes from PROGMEM.
1012
bool
matchString(
const
prog_char *name,
const
char
*str,
int
len)
1013
{
1014
for
(;;) {
1015
char
ch1 = (
char
)(pgm_read_byte(name));
1016
if
(ch1 ==
'\0'
)
1017
return
len == 0;
1018
else
if
(len == 0)
1019
break
;
1020
if
(ch1 >=
'a'
&& ch1 <=
'z'
)
1021
ch1 = ch1 -
'a'
+
'A'
;
1022
char
ch2 = *str;
1023
if
(ch2 >=
'a'
&& ch2 <=
'z'
)
1024
ch2 = ch2 -
'a'
+
'A'
;
1025
if
(ch1 != ch2)
1026
break
;
1027
++name;
1028
++str;
1029
--len;
1030
}
1031
return
false
;
1032
}
1033
1034
// Process commands from the host.
1035
void
processCommand(
const
char
*buf)
1036
{
1037
// Skip white space at the start of the command.
1038
while
(*buf ==
' '
|| *buf ==
'\t'
)
1039
++buf;
1040
if
(*buf ==
'\0'
)
1041
return
;
// Ignore blank lines.
1042
1043
// Extract the command portion of the line.
1044
const
char
*cmd = buf;
1045
int
len = 0;
1046
for
(;;) {
1047
char
ch = *buf;
1048
if
(ch ==
'\0'
|| ch ==
' '
|| ch ==
'\t'
)
1049
break
;
1050
++buf;
1051
++len;
1052
}
1053
1054
// Skip white space after the command name and before the arguments.
1055
while
(*buf ==
' '
|| *buf ==
'\t'
)
1056
++buf;
1057
1058
// Find the command and execute it.
1059
int
index = 0;
1060
for
(;;) {
1061
const
prog_char *name = (
const
prog_char *)
1062
(pgm_read_word(&(commands[index].name)));
1063
if
(!name)
1064
break
;
1065
if
(matchString(name, cmd, len)) {
1066
commandFunc func =
1067
(commandFunc)(pgm_read_word(&(commands[index].func)));
1068
(*func)(buf);
1069
return
;
1070
}
1071
++index;
1072
}
1073
1074
// Unknown command.
1075
Serial
.println(
"NOTSUPPORTED"
);
1076
}
1077
1078
// Enter high voltage programming mode.
1079
void
enterProgramMode()
1080
{
1081
// Bail out if already in programming mode.
1082
if
(state != STATE_IDLE)
1083
return
;
1084
1085
// Lower MCLR, VDD, DATA, and CLOCK initially. This will put the
1086
// PIC into the powered-off, reset state just in case.
1087
digitalWrite(PIN_MCLR, MCLR_RESET);
1088
digitalWrite(PIN_VDD, LOW);
1089
digitalWrite(PIN_DATA, LOW);
1090
digitalWrite(PIN_CLOCK, LOW);
1091
1092
// Wait for the lines to settle.
1093
delayMicroseconds(DELAY_SETTLE);
1094
1095
// Switch DATA and CLOCK into outputs.
1096
pinMode(PIN_DATA, OUTPUT);
1097
pinMode(PIN_CLOCK, OUTPUT);
1098
1099
// Raise MCLR, then VDD.
1100
digitalWrite(PIN_MCLR, MCLR_VPP);
1101
delayMicroseconds(DELAY_TPPDP);
1102
digitalWrite(PIN_VDD, HIGH);
1103
delayMicroseconds(DELAY_THLD0);
1104
1105
// Now in program mode, starting at the first word of program memory.
1106
state = STATE_PROGRAM;
1107
pc = 0;
1108
}
1109
1110
// Exit programming mode and reset the device.
1111
void
exitProgramMode()
1112
{
1113
// Nothing to do if already out of programming mode.
1114
if
(state == STATE_IDLE)
1115
return
;
1116
1117
// Lower MCLR, VDD, DATA, and CLOCK.
1118
digitalWrite(PIN_MCLR, MCLR_RESET);
1119
digitalWrite(PIN_VDD, LOW);
1120
digitalWrite(PIN_DATA, LOW);
1121
digitalWrite(PIN_CLOCK, LOW);
1122
1123
// Float the DATA and CLOCK pins.
1124
pinMode(PIN_DATA, INPUT);
1125
pinMode(PIN_CLOCK, INPUT);
1126
1127
// Now in the idle state with the PIC powered off.
1128
state = STATE_IDLE;
1129
pc = 0;
1130
}
1131
1132
// Send a command to the PIC.
1133
void
sendCommand(
byte
cmd)
1134
{
1135
for
(
byte
bit = 0; bit < 6; ++bit) {
1136
digitalWrite(PIN_CLOCK, HIGH);
1137
if
(cmd & 1)
1138
digitalWrite(PIN_DATA, HIGH);
1139
else
1140
digitalWrite(PIN_DATA, LOW);
1141
delayMicroseconds(DELAY_TSET1);
1142
digitalWrite(PIN_CLOCK, LOW);
1143
delayMicroseconds(DELAY_THLD1);
1144
cmd >>= 1;
1145
}
1146
}
1147
1148
// Send a command to the PIC that has no arguments.
1149
void
sendSimpleCommand(
byte
cmd)
1150
{
1151
sendCommand(cmd);
1152
delayMicroseconds(DELAY_TDLY2);
1153
}
1154
1155
// Send a command to the PIC that writes a data argument.
1156
void
sendWriteCommand(
byte
cmd, unsigned
int
data)
1157
{
1158
sendCommand(cmd);
1159
delayMicroseconds(DELAY_TDLY2);
1160
for
(
byte
bit = 0; bit < 16; ++bit) {
1161
digitalWrite(PIN_CLOCK, HIGH);
1162
if
(data & 1)
1163
digitalWrite(PIN_DATA, HIGH);
1164
else
1165
digitalWrite(PIN_DATA, LOW);
1166
delayMicroseconds(DELAY_TSET1);
1167
digitalWrite(PIN_CLOCK, LOW);
1168
delayMicroseconds(DELAY_THLD1);
1169
data >>= 1;
1170
}
1171
delayMicroseconds(DELAY_TDLY2);
1172
}
1173
1174
// Send a command to the PIC that reads back a data value.
1175
unsigned
int
sendReadCommand(
byte
cmd)
1176
{
1177
unsigned
int
data = 0;
1178
sendCommand(cmd);
1179
digitalWrite(PIN_DATA, LOW);
1180
pinMode(PIN_DATA, INPUT);
1181
delayMicroseconds(DELAY_TDLY2);
1182
for
(
byte
bit = 0; bit < 16; ++bit) {
1183
data >>= 1;
1184
digitalWrite(PIN_CLOCK, HIGH);
1185
delayMicroseconds(DELAY_TDLY3);
1186
if
(digitalRead(PIN_DATA))
1187
data |= 0x8000;
1188
digitalWrite(PIN_CLOCK, LOW);
1189
delayMicroseconds(DELAY_THLD1);
1190
}
1191
pinMode(PIN_DATA, OUTPUT);
1192
delayMicroseconds(DELAY_TDLY2);
1193
return
data;
1194
}
1195
1196
// Set the program counter to a specific "flat" address.
1197
void
setPC(unsigned
long
addr)
1198
{
1199
if
(addr >= dataStart && addr <= dataEnd) {
1200
// Data memory.
1201
addr -= dataStart;
1202
if
(state != STATE_PROGRAM || addr < pc) {
1203
// Device is off, currently looking at configuration memory,
1204
// or the address is further back. Reset the device.
1205
exitProgramMode();
1206
enterProgramMode();
1207
}
1208
}
else
if
(addr >= configStart && addr <= configEnd) {
1209
// Configuration memory.
1210
addr -= configStart;
1211
if
(state == STATE_IDLE) {
1212
// Enter programming mode and switch to config memory.
1213
enterProgramMode();
1214
sendWriteCommand(CMD_LOAD_CONFIG, 0);
1215
state = STATE_CONFIG;
1216
}
else
if
(state == STATE_PROGRAM) {
1217
// Switch from program memory to config memory.
1218
sendWriteCommand(CMD_LOAD_CONFIG, 0);
1219
state = STATE_CONFIG;
1220
pc = 0;
1221
}
else
if
(addr < pc) {
1222
// Need to go backwards in config memory, so reset the device.
1223
exitProgramMode();
1224
enterProgramMode();
1225
sendWriteCommand(CMD_LOAD_CONFIG, 0);
1226
state = STATE_CONFIG;
1227
}
1228
}
else
{
1229
// Program memory.
1230
if
(state != STATE_PROGRAM || addr < pc) {
1231
// Device is off, currently looking at configuration memory,
1232
// or the address is further back. Reset the device.
1233
exitProgramMode();
1234
enterProgramMode();
1235
}
1236
}
1237
while
(pc < addr) {
1238
sendSimpleCommand(CMD_INCREMENT_ADDRESS);
1239
++pc;
1240
}
1241
}
1242
1243
// Sets the PC for "erase mode", which is activated by loading the
1244
// data value 0x3FFF into location 0 of configuration memory.
1245
void
setErasePC()
1246
{
1247
// Forcibly reset the device so we know what state it is in.
1248
exitProgramMode();
1249
enterProgramMode();
1250
1251
// Load 0x3FFF for the configuration.
1252
sendWriteCommand(CMD_LOAD_CONFIG, 0x3FFF);
1253
state = STATE_CONFIG;
1254
}
1255
1256
// Read a word from memory (program, config, or data depending upon addr).
1257
// The start and stop bits will be stripped from the raw value from the PIC.
1258
unsigned
int
readWord(unsigned
long
addr)
1259
{
1260
setPC(addr);
1261
if
(addr >= dataStart && addr <= dataEnd)
1262
return
(sendReadCommand(CMD_READ_DATA_MEMORY) >> 1) & 0x00FF;
1263
else
1264
return
(sendReadCommand(CMD_READ_PROGRAM_MEMORY) >> 1) & 0x3FFF;
1265
}
1266
1267
// Read a word from config memory using relative, non-flat, addressing.
1268
// Used by the "DEVICE" command to fetch information about devices whose
1269
// flat address ranges are presently unknown.
1270
unsigned
int
readConfigWord(unsigned
long
addr)
1271
{
1272
if
(state == STATE_IDLE) {
1273
// Enter programming mode and switch to config memory.
1274
enterProgramMode();
1275
sendWriteCommand(CMD_LOAD_CONFIG, 0);
1276
state = STATE_CONFIG;
1277
}
else
if
(state == STATE_PROGRAM) {
1278
// Switch from program memory to config memory.
1279
sendWriteCommand(CMD_LOAD_CONFIG, 0);
1280
state = STATE_CONFIG;
1281
pc = 0;
1282
}
else
if
(addr < pc) {
1283
// Need to go backwards in config memory, so reset the device.
1284
exitProgramMode();
1285
enterProgramMode();
1286
sendWriteCommand(CMD_LOAD_CONFIG, 0);
1287
state = STATE_CONFIG;
1288
}
1289
while
(pc < addr) {
1290
sendSimpleCommand(CMD_INCREMENT_ADDRESS);
1291
++pc;
1292
}
1293
return
(sendReadCommand(CMD_READ_PROGRAM_MEMORY) >> 1) & 0x3FFF;
1294
}
1295
1296
// Begin a programming cycle, depending upon the type of flash being written.
1297
void
beginProgramCycle(unsigned
long
addr,
bool
isData)
1298
{
1299
switch
(isData ? dataFlashType : progFlashType) {
1300
case
FLASH:
1301
case
EEPROM:
1302
sendSimpleCommand(CMD_BEGIN_PROGRAM);
1303
delayMicroseconds(DELAY_TDPROG + DELAY_TERA);
1304
break
;
1305
case
FLASH4:
1306
sendSimpleCommand(CMD_BEGIN_PROGRAM);
1307
delayMicroseconds(DELAY_TPROG);
1308
break
;
1309
case
FLASH5:
1310
sendSimpleCommand(CMD_BEGIN_PROGRAM_ONLY);
1311
delayMicroseconds(DELAY_TPROG5);
1312
sendSimpleCommand(CMD_END_PROGRAM_ONLY);
1313
break
;
1314
}
1315
}
1316
1317
// Write a word to memory (program, config, or data depending upon addr).
1318
// Returns true if the write succeeded, false if read-back failed to match.
1319
bool
writeWord(unsigned
long
addr, unsigned
int
word)
1320
{
1321
unsigned
int
readBack;
1322
setPC(addr);
1323
if
(addr >= dataStart && addr <= dataEnd) {
1324
word &= 0x00FF;
1325
sendWriteCommand(CMD_LOAD_DATA_MEMORY, word << 1);
1326
beginProgramCycle(addr,
true
);
1327
readBack = sendReadCommand(CMD_READ_DATA_MEMORY);
1328
readBack = (readBack >> 1) & 0x00FF;
1329
}
else
if
(!configSave || addr != (configStart + DEV_CONFIG_WORD)) {
1330
word &= 0x3FFF;
1331
sendWriteCommand(CMD_LOAD_PROGRAM_MEMORY, word << 1);
1332
beginProgramCycle(addr,
false
);
1333
readBack = sendReadCommand(CMD_READ_PROGRAM_MEMORY);
1334
readBack = (readBack >> 1) & 0x3FFF;
1335
}
else
{
1336
// The configuration word has calibration bits within it that
1337
// must be preserved when we write to it. Read the current value
1338
// and preserve the necessary bits.
1339
readBack = (sendReadCommand(CMD_READ_PROGRAM_MEMORY) >> 1) & 0x3FFF;
1340
word = (readBack & configSave) | (word & 0x3FFF & ~configSave);
1341
sendWriteCommand(CMD_LOAD_PROGRAM_MEMORY, word << 1);
1342
beginProgramCycle(addr,
false
);
1343
readBack = sendReadCommand(CMD_READ_PROGRAM_MEMORY);
1344
readBack = (readBack >> 1) & 0x3FFF;
1345
}
1346
return
readBack == word;
1347
}
1348
1349
// Force a word to be written even if it normally would protect config bits.
1350
bool
writeWordForced(unsigned
long
addr, unsigned
int
word)
1351
{
1352
unsigned
int
readBack;
1353
setPC(addr);
1354
if
(addr >= dataStart && addr <= dataEnd) {
1355
word &= 0x00FF;
1356
sendWriteCommand(CMD_LOAD_DATA_MEMORY, word << 1);
1357
beginProgramCycle(addr,
true
);
1358
readBack = sendReadCommand(CMD_READ_DATA_MEMORY);
1359
readBack = (readBack >> 1) & 0x00FF;
1360
}
else
{
1361
word &= 0x3FFF;
1362
sendWriteCommand(CMD_LOAD_PROGRAM_MEMORY, word << 1);
1363
beginProgramCycle(addr,
false
);
1364
readBack = sendReadCommand(CMD_READ_PROGRAM_MEMORY);
1365
readBack = (readBack >> 1) & 0x3FFF;
1366
}
1367
return
readBack == word;
1368
}
но и в программе управления
это версия 1.0. на их сайте в гите есть версия 1.8
на сколько помню не нажимал я ресет на ардуине. Все так шьётся, по клику в проге.
пробовал через командную строку слить хекс файл. вышел файл почти весь в нулях размеров 47 кб. ОБратно он заливается, но если произвести изменения в файле (вставить строчки из компилированного кода), то при прошивке выдаётся ошибка. Причем по контрольной сумме всё правильно. Я даже пробовал через последовательное соединение , как у них на сайте. Также отправляются команды на запись нулей по адресам, другие значения записать невозможно. Единственное , что могу считать идентификатор устройства, который соответствует моему контроллеру. Пробовал даже менять формат хекс файла с int32 на int8 через hexmate. пробовал другой компилятор: мплабх, хитек. Подозрения, что считывает ,записывает и стирает он неправильно, учитывая, что он считывает только нулю со всех областей:программной памяти, еепром, конфигурационной памяти. Причем ,если отключить питание от МСЛР, то он также считывает нули, но вот конфигурацию устройства уже не покажет. Либо контроллер паленый либо в коде ошибка или всё-таки он не поддерживает прошивку этого устройства pic16f877, хотя он указан в ардуиновском файле,и автоматически определяется. Код верный в обоих случаях-проверял хекс файл через протеус на том же контроллере.
это версия 1.0. на их сайте в гите есть версия 1.8
а киньте ссылкой пожалуйста
https://codeload.github.com/makerprojects/ProgramPic/zip/master
https://codeload.github.com/makerprojects/ProgramPic/zip/master
Благодарю!
Посмотрел, из изменений добавили пяток чипов и компиляцию в IDE 1.8.7
PIC серии 18 в поддерживаемых нет, увы (((
Если вы хотите прошивать 18 серию, то советую такое решение с низковольтным программированием, но старые контроллеры он уже поддерживать не будет) https://hackaday.io/project/8559-microchip-pic-arduino-based-programmer/
https://sites.google.com/site/thehighspark/arduino-pic18f -есть пример прошивки микроконтроллеров семейства pic18
всё на буржуйском языке, но рисунки хорошие и так понять можно
https://sites.google.com/site/thehighspark/arduino-pic18f -есть пример прошивки микроконтроллеров семейства pic18
Спасибо за интересную статью и ресурс. Хочу попробовать этим методом прошить PIC18F24K22 прям на плате. На плате есть пять контактов для внутрисхемного программирования: 1. PROG (я так понимаю MCLR); 2. 5V (VDD); 3. GND (VSS); 4. PGD; 5. PGC.
В предложенном скетче для Ардуино используется ещё шестой контакт 6. PGM, так как он имеется на PIC18F2420 описанном в примере. А у микроконтроллера PIC18F24K22 такой контакт отсутствует!
Вопрос, как Вы считаете нужно ли вносить изменения в скетч для Ардуино, для того чтобы корректно прошить PIC18F24K22?

Пытался запустить этот программатор. То прочитает чип, то нет. Стирать не получается. Плюнул буду искать готовое изделие...
буду искать готовое изделие...
Найди TL866
Почему у меня при переходе по ссылке на статью автора пишет что отказано в доступе к серверу?
На сегодня ссылка вообще работает?
Или скиньте кто нибудь саму программу для прошивки
Или скиньте кто нибудь саму программу для прошивки
здесь посмотри
Найди TL866
З. Ы. Заранее благодарен
А всякие pinguino и так далее чем не устраивают? Я как бы pic-контроллерами никогда не занимался, но сейчас гугл открыл с запросом «pic arduino ide» и там море всего.