Advertisement
adolf01

AVRPICProg

Apr 26th, 2017
347
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 41.11 KB | None | 0 0
  1. /*
  2. * Copyright (C) 2014-2016 www.pikoder.com (Gregor Schlechtriem)
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. *
  17. *
  18. * Change log:
  19. * 02/09/16:  - billy fixes for Arduino 1.6.7 compline test only. Bump version to 1.5
  20. * 01/30/16:  - added new mode to initiate programming for 16F87 and 16F88
  21. * 05/31/15:  - added support for pic 16f877 according to git_hub
  22. *              check also: https://github.com/alchemycs/ardpicprog/commit/a991b2f0616cfac586a0603570169ce457172987
  23. *            - revised program version to 1.3 (s_Version)
  24. * 03/30/15:  - added PIC16F690
  25. *            - revised program version to 1.2 (s_Version)
  26. * 02/09/14:  - added PIC16F684
  27. *            - revised program version to 1.1 (s_Version)
  28. *
  29. */
  30. #define __PROG_TYPES_COMPAT__
  31. #include <avr/pgmspace.h> // For PROGMEM
  32. // Pin mappings for the PIC programming shield.
  33. #define PIN_MCLR 13 // 0: MCLR is VPP voltage, 1: Reset PIC
  34. #define PIN_ACTIVITY 7 // LED that indicates read/write activity
  35. #define PIN_VDD A5 // Controls the power to the PIC
  36. #define PIN_CLOCK 11 // Clock pin
  37. #define PIN_DATA 12 // Data pin
  38. #define MCLR_RESET HIGH // PIN_MCLR state to reset the PIC
  39. #define MCLR_VPP LOW // PIN_MCLR state to apply 13v to MCLR/VPP pin
  40. // All delays are in microseconds.
  41. #define DELAY_SETTLE 50 // Delay for lines to settle for reset
  42. #define DELAY_TPPDP 5 // Hold time after raising MCLR
  43. #define DELAY_THLD0 5 // Hold time after raising VDD
  44. #define DELAY_TSET1 1 // Data in setup time before lowering clock
  45. #define DELAY_THLD1 1 // Data in hold time after lowering clock
  46. #define DELAY_TDLY2 1 // Delay between commands or data
  47. #define DELAY_TDLY3 1 // Delay until data bit read will be valid
  48. #define DELAY_TPROG 4000 // Time for a program memory write to complete
  49. #define DELAY_TDPROG 6000 // Time for a data memory write to complete
  50. #define DELAY_TERA 6000 // Time for a word erase to complete
  51. #define DELAY_TPROG5 1000 // Time for program write on FLASH5 systems
  52. #define DELAY_TFULLERA 50000 // Time for a full chip erase
  53. #define DELAY_TFULL84 20000 // Intermediate wait for PIC16F84/PIC16F84A
  54. // Commands that may be sent to the device.
  55. #define CMD_LOAD_CONFIG 0x00 // Load (write) to config memory
  56. #define CMD_LOAD_PROGRAM_MEMORY 0x02 // Load to program memory
  57. #define CMD_LOAD_DATA_MEMORY 0x03 // Load to data memory
  58. #define CMD_INCREMENT_ADDRESS 0x06 // Increment the PC
  59. #define CMD_READ_PROGRAM_MEMORY 0x04 // Read from program memory
  60. #define CMD_READ_DATA_MEMORY 0x05 // Read from data memory
  61. #define CMD_BEGIN_PROGRAM 0x08 // Begin programming with erase cycle
  62. #define CMD_BEGIN_PROGRAM_ONLY 0x18 // Begin programming only cycle
  63. #define CMD_END_PROGRAM_ONLY 0x17 // End programming only cycle
  64. #define CMD_BULK_ERASE_PROGRAM 0x09 // Bulk erase program memory
  65. #define CMD_BULK_ERASE_DATA 0x0B // Bulk erase data memory
  66. #define CMD_CHIP_ERASE 0x1F // Erase the entire chip
  67. // States this application may be in.
  68. #define STATE_IDLE 0 // Idle, device is held in the reset state
  69. #define STATE_PROGRAM 1 // Active, reading and writing program memory
  70. #define STATE_CONFIG 2 // Active, reading and writing config memory
  71. int state = STATE_IDLE;
  72. // Flash types. Uses a similar naming system to picprog.
  73. #define EEPROM 0
  74. #define FLASH 1
  75. #define FLASH4 4
  76. #define FLASH5 5
  77. // HPP programming entry modes
  78. #define MCLR_first 0
  79. #define Vdd_first 1
  80.  
  81. unsigned long pc = 0; // Current program counter.
  82. // Flat address ranges for the various memory spaces. Defaults to the values
  83. // for the PIC16F628A. "DEVICE" command updates to the correct values later.
  84. unsigned long programEnd = 0x07FF;
  85. unsigned long configStart = 0x2000;
  86. unsigned long configEnd = 0x2007;
  87. unsigned long dataStart = 0x2100;
  88. unsigned long dataEnd = 0x217F;
  89. unsigned long reservedStart = 0x0800;
  90. unsigned long reservedEnd = 0x07FF;
  91. unsigned int configSave = 0x0000;
  92. byte progFlashType = FLASH4;
  93. byte dataFlashType = EEPROM;
  94. byte hpp_progEntryMode = MCLR_first;
  95.  
  96. // Program version
  97. const char s_Version[] = "1.5";
  98.  
  99. // Device names, forced out into PROGMEM.
  100. const char s_pic12f629[] PROGMEM = "pic12f629";
  101. const char s_pic12f675[] PROGMEM = "pic12f675";
  102. const char s_pic16f630[] PROGMEM = "pic16f630";
  103. const char s_pic16f676[] PROGMEM = "pic16f676";
  104. const char s_pic16f84[] PROGMEM = "pic16f84";
  105. const char s_pic16f84a[] PROGMEM = "pic16f84a";
  106. const char s_pic16f87[] PROGMEM = "pic16f87";
  107. const char s_pic16f88[] PROGMEM = "pic16f88";
  108. const char s_pic16f627[] PROGMEM = "pic16f627";
  109. const char s_pic16f627a[] PROGMEM = "pic16f627a";
  110. const char s_pic16f628[] PROGMEM = "pic16f628";
  111. const char s_pic16f628a[] PROGMEM = "pic16f628a";
  112. const char s_pic16f648a[] PROGMEM = "pic16f648a";
  113. const char s_pic16f684[] PROGMEM = "pic16f684";
  114. const char s_pic16f690[] PROGMEM = "pic16f690";
  115. const char s_pic16f877[] PROGMEM = "pic16f877";
  116. const char s_pic16f882[] PROGMEM = "pic16f882";
  117. const char s_pic16f883[] PROGMEM = "pic16f883";
  118. const char s_pic16f884[] PROGMEM = "pic16f884";
  119. const char s_pic16f886[] PROGMEM = "pic16f886";
  120. const char s_pic16f887[] PROGMEM = "pic16f887";
  121. // List of devices that are currently supported and their properties.
  122. // Note: most of these are based on published information and have not
  123. // been tested by the author. Patches welcome to improve the list.
  124.  
  125. struct deviceInfo {
  126. const char PROGMEM *name; // User-readable name of the device.
  127. int16_t PROGMEM deviceId; // Device ID for the PIC (-1 if no id).
  128. uint32_t PROGMEM programSize; // Size of program memory (words).
  129. uint32_t PROGMEM configStart; // Flat address start of configuration memory.
  130. uint32_t PROGMEM dataStart; // Flat address start of EEPROM data memory.
  131. uint16_t PROGMEM configSize; // Number of configuration words.
  132. uint16_t PROGMEM dataSize; // Size of EEPROM data memory (bytes).
  133. uint16_t PROGMEM reservedWords;// Reserved program words (e.g. for OSCCAL).
  134. uint16_t PROGMEM configSave; // Bits in config word to be saved.
  135. uint8_t PROGMEM progFlashType; // Type of flash for program memory.
  136. uint8_t PROGMEM dataFlashType; // Type of flash for data memory.
  137. uint8_t PROGMEM progEntryMode; // Programm entry mode (MLCR first or Vdd)
  138. };
  139.  
  140. struct deviceInfo const devices[] PROGMEM = {
  141. // http://ww1.microchip.com/downloads/en/DeviceDoc/41191D.pdf
  142. {s_pic12f629, 0x0F80, 1024, 0x2000, 0x2100, 8, 128, 1, 0x3000, FLASH4, EEPROM, MCLR_first},
  143. {s_pic12f675, 0x0FC0, 1024, 0x2000, 0x2100, 8, 128, 1, 0x3000, FLASH4, EEPROM, MCLR_first},
  144. {s_pic16f630, 0x10C0, 1024, 0x2000, 0x2100, 8, 128, 1, 0x3000, FLASH4, EEPROM, MCLR_first},
  145. {s_pic16f676, 0x10E0, 1024, 0x2000, 0x2100, 8, 128, 1, 0x3000, FLASH4, EEPROM, MCLR_first},
  146. // http://ww1.microchip.com/downloads/en/DeviceDoc/30262e.pdf
  147. {s_pic16f84, -1, 1024, 0x2000, 0x2100, 8, 64, 0, 0, FLASH, EEPROM, MCLR_first},
  148. {s_pic16f84a, 0x0560, 1024, 0x2000, 0x2100, 8, 64, 0, 0, FLASH, EEPROM, MCLR_first},
  149. // http://ww1.microchip.com/downloads/en/DeviceDoc/39607c.pdf
  150. {s_pic16f87, 0x0720, 4096, 0x2000, 0x2100, 9, 256, 0, 0, FLASH5, EEPROM, Vdd_first},
  151. {s_pic16f88, 0x0760, 4096, 0x2000, 0x2100, 9, 256, 0, 0, FLASH5, EEPROM, Vdd_first},
  152. // 627/628: http://ww1.microchip.com/downloads/en/DeviceDoc/30034d.pdf
  153. // A series: http://ww1.microchip.com/downloads/en/DeviceDoc/41196g.pdf
  154. {s_pic16f627, 0x07A0, 1024, 0x2000, 0x2100, 8, 128, 0, 0, FLASH, EEPROM, MCLR_first},
  155. {s_pic16f627a, 0x1040, 1024, 0x2000, 0x2100, 8, 128, 0, 0, FLASH4, EEPROM, MCLR_first},
  156. {s_pic16f628, 0x07C0, 2048, 0x2000, 0x2100, 8, 128, 0, 0, FLASH, EEPROM, MCLR_first},
  157. {s_pic16f628a, 0x1060, 2048, 0x2000, 0x2100, 8, 128, 0, 0, FLASH4, EEPROM, MCLR_first},
  158. {s_pic16f648a, 0x1100, 4096, 0x2000, 0x2100, 8, 256, 0, 0, FLASH4, EEPROM, MCLR_first},
  159. // http://ww1.microchip.com/downloads/en/devicedoc/41202C.pdf
  160. {s_pic16f684, 0x1080, 2048, 0x2000, 0x2100, 8, 256, 0, 0, FLASH4, EEPROM, MCLR_first},
  161. // http://ww1.microchip.com/downloads/en/DeviceDoc/41262A.pdf
  162. {s_pic16f690, 0x1400, 4096, 0x2000, 0x2100, 9, 256, 1, 0, FLASH4, EEPROM, MCLR_first},
  163. // http://ww1.microchip.com/downloads/en/DeviceDoc/39025f.pdf
  164. {s_pic16f877, 0x09A0, 8192, 0x2000, 0x2100, 8, 256, 0, 0, FLASH4, EEPROM, MCLR_first},
  165. // http://ww1.microchip.com/downloads/en/DeviceDoc/41287D.pdf  
  166. {s_pic16f882, 0x2000, 2048, 0x2000, 0x2100, 9, 128, 0, 0, FLASH4, EEPROM, MCLR_first},
  167. {s_pic16f883, 0x2020, 4096, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM, MCLR_first},
  168. {s_pic16f884, 0x2040, 4096, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM, MCLR_first},
  169. {s_pic16f886, 0x2060, 8192, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM, MCLR_first},
  170. {s_pic16f887, 0x2080, 8192, 0x2000, 0x2100, 9, 256, 0, 0, FLASH4, EEPROM, MCLR_first},
  171. {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
  172. };
  173. // Buffer for command-line character input and READBIN data packets.
  174. #define BINARY_TRANSFER_MAX 64
  175. #define BUFFER_MAX (BINARY_TRANSFER_MAX + 1)
  176. char buffer[BUFFER_MAX];
  177. int buflen = 0;
  178. unsigned long lastActive = 0;
  179. void setup()
  180. {
  181. // Need a serial link to the host.
  182. Serial.begin(9600);
  183. // Hold the PIC in the powered down/reset state until we are ready for it.
  184. pinMode(PIN_MCLR, OUTPUT);
  185. pinMode(PIN_VDD, OUTPUT);
  186. digitalWrite(PIN_MCLR, MCLR_RESET);
  187. digitalWrite(PIN_VDD, LOW);
  188. // Clock and data are floating until the first PIC command.
  189. pinMode(PIN_CLOCK, INPUT);
  190. pinMode(PIN_DATA, INPUT);
  191. // Turn off the activity LED initially.
  192. pinMode(PIN_ACTIVITY, OUTPUT);
  193. digitalWrite(PIN_ACTIVITY, LOW);
  194. }
  195. void loop()
  196. {
  197. if (Serial.available()) {
  198. // Process serial input for commands from the host.
  199. int ch = Serial.read();
  200. if (ch == 0x0A || ch == 0x0D) {
  201. // End of the current command. Blank lines are ignored.
  202. if (buflen > 0) {
  203. buffer[buflen] = '\0';
  204. buflen = 0;
  205. digitalWrite(PIN_ACTIVITY, HIGH); // Turn on activity LED.
  206. processCommand(buffer);
  207. digitalWrite(PIN_ACTIVITY, LOW); // Turn off activity LED.
  208. }
  209. } else if (ch == 0x08) {
  210. // Backspace over the last character.
  211. if (buflen > 0)
  212. --buflen;
  213. } else if (buflen < (BUFFER_MAX - 1)) {
  214. // Add the character to the buffer after forcing to upper case.
  215. if (ch >= 'a' && ch <= 'z')
  216. buffer[buflen++] = ch - 'a' + 'A';
  217. else
  218. buffer[buflen++] = ch;
  219. }
  220. lastActive = millis();
  221. } else if (state != STATE_IDLE) {
  222. // Power off the programming socket if no activity for 2 seconds.
  223. // Normally the host will issue the "PWROFF" command, but if we are
  224. // operating in interactive mode or the host has crashed, then this
  225. // timeout will ensure that the system eventually enters safe mode.
  226. if ((millis() - lastActive) >= 2000)
  227. exitProgramMode();
  228. }
  229. }
  230. void printHex1(unsigned int value)
  231. {
  232. if (value >= 10)
  233. Serial.print((char)('A' + value - 10));
  234. else
  235. Serial.print((char)('0' + value));
  236. }
  237. void printHex4(unsigned int word)
  238. {
  239. printHex1((word >> 12) & 0x0F);
  240. printHex1((word >> 8) & 0x0F);
  241. printHex1((word >> 4) & 0x0F);
  242. printHex1(word & 0x0F);
  243. }
  244. void printHex8(unsigned long word)
  245. {
  246. unsigned int upper = (unsigned int)(word >> 16);
  247. if (upper)
  248. printHex4(upper);
  249. printHex4((unsigned int)word);
  250. }
  251. void printProgString(const char PROGMEM *str)
  252. {
  253. for (;;) {
  254. char ch = (char)(pgm_read_byte(str));
  255. if (ch == '\0')
  256. break;
  257. Serial.print(ch);
  258. ++str;
  259. }
  260. }
  261. // PROGRAM_PIC_VERSION command.
  262. void cmdVersion(const char *args)
  263. {
  264. Serial.print("ProgramPIC ");
  265. Serial.println(s_Version);
  266. }
  267. // Initialize device properties from the "devices" list and
  268. // print them to the serial port. Note: "dev" is in PROGMEM.
  269. void initDevice(const struct deviceInfo *dev)
  270. {
  271. // Update the global device details.
  272. programEnd = pgm_read_dword(&(dev->programSize)) - 1;
  273. configStart = pgm_read_dword(&(dev->configStart));
  274. configEnd = configStart + pgm_read_word(&(dev->configSize)) - 1;
  275. dataStart = pgm_read_dword(&(dev->dataStart));
  276. dataEnd = dataStart + pgm_read_word(&(dev->dataSize)) - 1;
  277. reservedStart = programEnd - pgm_read_word(&(dev->reservedWords)) + 1;
  278. reservedEnd = programEnd;
  279. configSave = pgm_read_word(&(dev->configSave));
  280. progFlashType = pgm_read_byte(&(dev->progFlashType));
  281. dataFlashType = pgm_read_byte(&(dev->dataFlashType));
  282. hpp_progEntryMode = pgm_read_byte(&(dev->progEntryMode));
  283. // Print the extra device information.
  284. Serial.print("DeviceName: ");
  285. printProgString((const char PROGMEM *)(pgm_read_word(&(dev->name))));
  286. Serial.println();
  287. Serial.print("ProgramRange: 0000-");
  288. printHex8(programEnd);
  289. Serial.println();
  290. Serial.print("ConfigRange: ");
  291. printHex8(configStart);
  292. Serial.print('-');
  293. printHex8(configEnd);
  294. Serial.println();
  295. if (configSave != 0) {
  296. Serial.print("ConfigSave: ");
  297. printHex4(configSave);
  298. Serial.println();
  299. }
  300. Serial.print("DataRange: ");
  301. printHex8(dataStart);
  302. Serial.print('-');
  303. printHex8(dataEnd);
  304. Serial.println();
  305. if (reservedStart <= reservedEnd) {
  306. Serial.print("ReservedRange: ");
  307. printHex8(reservedStart);
  308. Serial.print('-');
  309. printHex8(reservedEnd);
  310. Serial.println();
  311. }
  312. }
  313. // Offsets of interesting config locations that contain device information.
  314. #define DEV_USERID0 0
  315. #define DEV_USERID1 1
  316. #define DEV_USERID2 2
  317. #define DEV_USERID3 3
  318. #define DEV_ID 6
  319. #define DEV_CONFIG_WORD 7
  320. // DEVICE command.
  321. void cmdDevice(const char *args) {
  322.   // Make sure the device is reset before we start.
  323.   exitProgramMode();
  324.   // Read identifiers and configuration words from config memory.
  325.   unsigned int userid0 = readConfigWord(DEV_USERID0);
  326.   unsigned int userid1 = readConfigWord(DEV_USERID1);
  327.   unsigned int userid2 = readConfigWord(DEV_USERID2);
  328.   unsigned int userid3 = readConfigWord(DEV_USERID3);
  329.   unsigned int deviceId = readConfigWord(DEV_ID);
  330.   unsigned int configWord = readConfigWord(DEV_CONFIG_WORD);
  331.   // If the device ID is all-zeroes or all-ones, then it could mean
  332.   // one of the following:
  333.   //
  334.   // 1. There is no PIC in the programming socket.
  335.   // 2. The VPP programming voltage is not available.
  336.   // 3. Code protection is enabled and the PIC is unreadable.
  337.   // 4. The PIC uses the Vdd first timing to enter into programming mode
  338.   // 5. The PIC is an older model with no device identifier.
  339.   //
  340.   // We will explore case 4 first and then take a look at case 4.
  341.   //
  342.   // For evaluating case 5 we look for any word in configuration
  343.   // memory or the first 16 words of program memory that is non-zero.
  344.   // If we find a non-zero word, we assume that we have a PIC but we
  345.   // cannot detect what type it is.
  346.  
  347.   if (deviceId == 0 || deviceId == 0x3FFF) {
  348.     exitProgramMode();  // return from config state to reset...
  349.     hpp_progEntryMode = Vdd_first; // swith order, might be another type
  350.     userid0 = readConfigWord(DEV_USERID0);
  351.     userid1 = readConfigWord(DEV_USERID1);
  352.     userid2 = readConfigWord(DEV_USERID2);
  353.     userid3 = readConfigWord(DEV_USERID3);
  354.     deviceId = readConfigWord(DEV_ID);
  355.     configWord = readConfigWord(DEV_CONFIG_WORD);
  356.        
  357.     if (deviceId == 0 || deviceId == 0x3FFF) {
  358.         // now we explore case 5...
  359.         hpp_progEntryMode = MCLR_first; // swith order, might be another type
  360.         unsigned int word = userid0 | userid1 | userid2 | userid3 | configWord;
  361.         unsigned int addr = 0;
  362.         while (!word && addr < 16) {
  363.           word |= readWord(addr);
  364.           ++addr;
  365.         }
  366.         if (!word) {
  367.           Serial.println("ERROR");
  368.           exitProgramMode();
  369.           return;
  370.         }
  371.         deviceId = 0;
  372.       }
  373.   }
  374.   Serial.println("OK");
  375.   Serial.print("DeviceID: ");
  376.   printHex4(deviceId);
  377.   Serial.println();
  378.   // Find the device in the built-in list if we have details for it.
  379.   int index = 0;
  380.   for (;;) {
  381.     const char PROGMEM *name = (const char PROGMEM *)
  382.     (pgm_read_word(&(devices[index].name)));
  383.     if (!name) {
  384.       index = -1;
  385.       break;
  386.     }
  387.     int id = pgm_read_word(&(devices[index].deviceId));
  388.     if (id == (deviceId & 0xFFE0))  break;  
  389.     ++index;
  390.   }
  391.   if (index >= 0) {
  392.     initDevice(&(devices[index]));
  393.   } else {
  394.     // Reset the global parameters to their defaults. A separate
  395.     // "SETDEVICE" command will be needed to set the correct values.
  396.     programEnd = 0x07FF;
  397.     configStart = 0x2000;
  398.     configEnd = 0x2007;
  399.     dataStart = 0x2100;
  400.     dataEnd = 0x217F;
  401.     reservedStart = 0x0800;
  402.     reservedEnd = 0x07FF;
  403.     configSave = 0x0000;
  404.     progFlashType = FLASH4;
  405.     dataFlashType = EEPROM;
  406.   }
  407.   Serial.print("ConfigWord: ");
  408.   printHex4(configWord);
  409.   Serial.println();
  410.   Serial.println(".");
  411.   // Don't need programming mode once the details have been read.
  412.   exitProgramMode();
  413. }
  414.  
  415. // DEVICES command.
  416. void cmdDevices(const char *args)
  417. {
  418. Serial.println("OK");
  419. int index = 0;
  420. for (;;) {
  421. const char PROGMEM *name = (const char PROGMEM *)
  422. (pgm_read_word(&(devices[index].name)));
  423. if (!name)
  424. break;
  425. if (index > 0) {
  426. Serial.print(',');
  427. if ((index % 6) == 0)
  428. Serial.println();
  429. else
  430. Serial.print(' ');
  431. }
  432. printProgString(name);
  433. int id = (int)(pgm_read_word(&(devices[index].deviceId)));
  434. if (id != -1)
  435. Serial.print('*');
  436. ++index;
  437. }
  438. Serial.println();
  439. Serial.println(".");
  440. }
  441.  
  442.  
  443. // SETDEVICE command.
  444. void cmdSetDevice(const char *args) {
  445. // Extract the name of the device from the command arguments.
  446.   int len = 0;
  447.   for (;;) {
  448.     char ch = args[len];
  449.     if (ch == '\0' || ch == ' ' || ch == '\t')  break;
  450.     ++len;
  451.   }
  452.   // Look for the name in the devices list.
  453.   int index = 0;
  454.   for (;;) {
  455.     const char PROGMEM *name = (const char PROGMEM *)(pgm_read_word(&(devices[index].name)));
  456.     if (!name) break;
  457.     if (matchString(name, args, len)) {
  458.       Serial.println("OK");
  459.       initDevice(&(devices[index]));
  460.       Serial.println(".");
  461.       exitProgramMode(); // Force a reset upon the next command.
  462.       return;
  463.     }
  464.     ++index;
  465.   }
  466.   Serial.println("ERROR");
  467. }
  468.  
  469.  
  470. int parseHex(const char *args, unsigned long *value)
  471. {
  472. int size = 0;
  473. *value = 0;
  474. for (;;) {
  475. char ch = *args;
  476. if (ch >= '0' && ch <= '9')
  477. *value = (*value << 4) | (ch - '0');
  478. else if (ch >= 'A' && ch <= 'F')
  479. *value = (*value << 4) | (ch - 'A' + 10);
  480. else if (ch >= 'a' && ch <= 'f')
  481. *value = (*value << 4) | (ch - 'a' + 10);
  482. else
  483. break;
  484. ++size;
  485. ++args;
  486. }
  487. if (*args != '\0' && *args != '-' && *args != ' ' && *args != '\t')
  488. return 0;
  489. return size;
  490. }
  491. // Parse a range of addresses of the form START or START-END.
  492. bool parseRange(const char *args, unsigned long *start, unsigned long *end)
  493. {
  494. int size = parseHex(args, start);
  495. if (!size)
  496. return false;
  497. args += size;
  498. while (*args == ' ' || *args == '\t')
  499. ++args;
  500. if (*args != '-') {
  501. *end = *start;
  502. return true;
  503. }
  504. ++args;
  505. while (*args == ' ' || *args == '\t')
  506. ++args;
  507. if (!parseHex(args, end))
  508. return false;
  509. return *end >= *start;
  510. }
  511. bool parseCheckedRange(const char *args, unsigned long *start, unsigned long *end)
  512. {
  513. // Parse the basic values and make sure that start <= end.
  514. if (!parseRange(args, start, end))
  515. return false;
  516. // Check that both start and end are within the same memory area
  517. // and within the bounds of that memory area.
  518. if (*start <= programEnd) {
  519. if (*end > programEnd)
  520. return false;
  521. } else if (*start >= configStart && *start <= configEnd) {
  522. if (*end < configStart || *end > configEnd)
  523. return false;
  524. } else if (*start >= dataStart && *start <= dataEnd) {
  525. if (*end < dataStart || *end > dataEnd)
  526. return false;
  527. } else {
  528. return false;
  529. }
  530. return true;
  531. }
  532. // READ command.
  533. void cmdRead(const char *args)
  534. {
  535. unsigned long start;
  536. unsigned long end;
  537. if (!parseCheckedRange(args, &start, &end)) {
  538. Serial.println("ERROR");
  539. return;
  540. }
  541. Serial.println("OK");
  542. int count = 0;
  543. bool activity = true;
  544. while (start <= end) {
  545. unsigned int word = readWord(start);
  546. if (count > 0) {
  547. if ((count % 8) == 0)
  548. Serial.println();
  549. else
  550. Serial.print(' ');
  551. }
  552. printHex4(word);
  553. ++start;
  554. ++count;
  555. if ((count % 32) == 0) {
  556. // Toggle the activity LED to make it blink during long reads.
  557. activity = !activity;
  558. if (activity)
  559. digitalWrite(PIN_ACTIVITY, HIGH);
  560. else
  561. digitalWrite(PIN_ACTIVITY, LOW);
  562. }
  563. }
  564. Serial.println();
  565. Serial.println(".");
  566. }
  567. // READBIN command.
  568. void cmdReadBinary(const char *args)
  569. {
  570. unsigned long start;
  571. unsigned long end;
  572. if (!parseCheckedRange(args, &start, &end)) {
  573. Serial.println("ERROR");
  574. return;
  575. }
  576. Serial.println("OK");
  577. int count = 0;
  578. bool activity = true;
  579. size_t offset = 0;
  580. while (start <= end) {
  581. unsigned int word = readWord(start);
  582. buffer[++offset] = (char)word;
  583. buffer[++offset] = (char)(word >> 8);
  584. if (offset >= BINARY_TRANSFER_MAX) {
  585. // Buffer is full - flush it to the host.
  586. buffer[0] = (char)offset;
  587. Serial.write((const uint8_t *)buffer, offset + 1);
  588. offset = 0;
  589. }
  590. ++start;
  591. ++count;
  592. if ((count % 64) == 0) {
  593. // Toggle the activity LED to make it blink during long reads.
  594. activity = !activity;
  595. if (activity)
  596. digitalWrite(PIN_ACTIVITY, HIGH);
  597. else
  598. digitalWrite(PIN_ACTIVITY, LOW);
  599. }
  600. }
  601. if (offset > 0) {
  602. // Flush the final packet before the terminator.
  603. buffer[0] = (char)offset;
  604. Serial.write((const uint8_t *)buffer, offset + 1);
  605. }
  606. // Write the terminator (a zero-length packet).
  607. Serial.write((uint8_t)0x00);
  608. }
  609. const char s_force[] PROGMEM = "FORCE";
  610. // WRITE command.
  611. void cmdWrite(const char *args)
  612. {
  613. unsigned long addr;
  614. unsigned long limit;
  615. unsigned long value;
  616. int size;
  617. // Was the "FORCE" option given?
  618. int len = 0;
  619. while (args[len] != '\0' && args[len] != ' ' && args[len] != '\t')
  620. ++len;
  621. bool force = matchString(s_force, args, len);
  622. if (force) {
  623. args += len;
  624. while (*args == ' ' || *args == '\t')
  625. ++args;
  626. }
  627. size = parseHex(args, &addr);
  628. if (!size) {
  629. Serial.println("ERROR");
  630. return;
  631. }
  632. args += size;
  633. if (addr <= programEnd) {
  634. limit = programEnd;
  635. } else if (addr >= configStart && addr <= configEnd) {
  636. limit = configEnd;
  637. } else if (addr >= dataStart && addr <= dataEnd) {
  638. limit = dataEnd;
  639. } else {
  640. // Address is not within one of the valid ranges.
  641. Serial.println("ERROR");
  642. return;
  643. }
  644. int count = 0;
  645. for (;;) {
  646. while (*args == ' ' || *args == '\t')
  647. ++args;
  648. if (*args == '\0')
  649. break;
  650. if (*args == '-') {
  651. Serial.println("ERROR");
  652. return;
  653. }
  654. size = parseHex(args, &value);
  655. if (!size) {
  656. Serial.println("ERROR");
  657. return;
  658. }
  659. args += size;
  660. if (addr > limit) {
  661. // We've reached the limit of this memory area, so fail.
  662. Serial.println("ERROR");
  663. return;
  664. }
  665. if (!force) {
  666. if (!writeWord(addr, (unsigned int)value)) {
  667. // The actual write to the device failed.
  668. Serial.println("ERROR");
  669. return;
  670. }
  671. } else {
  672. if (!writeWordForced(addr, (unsigned int)value)) {
  673. // The actual write to the device failed.
  674. Serial.println("ERROR");
  675. return;
  676. }
  677. }
  678. ++addr;
  679. ++count;
  680. }
  681. if (!count) {
  682. // Missing word argument.
  683. Serial.println("ERROR");
  684. } else {
  685. Serial.println("OK");
  686. }
  687. }
  688. // Blocking serial read for use by WRITEBIN.
  689. int readBlocking()
  690. {
  691. while (!Serial.available())
  692. ; // Do nothing.
  693. return Serial.read();
  694. }
  695. // WRITEBIN command.
  696. void cmdWriteBinary(const char *args)
  697. {
  698. unsigned long addr;
  699. unsigned long limit;
  700. int size;
  701. // Was the "FORCE" option given?
  702. int len = 0;
  703. while (args[len] != '\0' && args[len] != ' ' && args[len] != '\t')
  704. ++len;
  705. bool force = matchString(s_force, args, len);
  706. if (force) {
  707. args += len;
  708. while (*args == ' ' || *args == '\t')
  709. ++args;
  710. }
  711. size = parseHex(args, &addr);
  712. if (!size) {
  713. Serial.println("ERROR");
  714. return;
  715. }
  716. args += size;
  717. if (addr <= programEnd) {
  718. limit = programEnd;
  719. } else if (addr >= configStart && addr <= configEnd) {
  720. limit = configEnd;
  721. } else if (addr >= dataStart && addr <= dataEnd) {
  722. limit = dataEnd;
  723. } else {
  724. // Address is not within one of the valid ranges.
  725. Serial.println("ERROR");
  726. return;
  727. }
  728. Serial.println("OK");
  729. int count = 0;
  730. bool activity = true;
  731. for (;;) {
  732. // Read in the next binary packet.
  733. int len = readBlocking();
  734. while (len == 0x0A && count == 0) {
  735. // Skip 0x0A bytes before the first packet as they are
  736. // probably part of a CRLF pair rather than a packet length.
  737. len = readBlocking();
  738. }
  739. // Stop if we have a zero packet length - end of upload.
  740. if (!len)
  741. break;
  742. // Read the contents of the packet from the serial input stream.
  743. int offset = 0;
  744. while (offset < len) {
  745. if (offset < BINARY_TRANSFER_MAX) {
  746. buffer[offset++] = (char)readBlocking();
  747. } else {
  748. readBlocking(); // Packet is too big - discard extra bytes.
  749. ++offset;
  750. }
  751. }
  752. // Write the words to memory.
  753. for (int posn = 0; posn < (len - 1); posn += 2) {
  754. if (addr > limit) {
  755. // We've reached the limit of this memory area, so fail.
  756. Serial.println("ERROR");
  757. return;
  758. }
  759. unsigned int value =
  760. (((unsigned int)buffer[posn]) & 0xFF) |
  761. ((((unsigned int)buffer[posn + 1]) & 0xFF) << 8);
  762. if (!force) {
  763. if (!writeWord(addr, (unsigned int)value)) {
  764. // The actual write to the device failed.
  765. Serial.println("ERROR");
  766. return;
  767. }
  768. } else {
  769. if (!writeWordForced(addr, (unsigned int)value)) {
  770. // The actual write to the device failed.
  771. Serial.println("ERROR");
  772. return;
  773. }
  774. }
  775. ++addr;
  776. ++count;
  777. if ((count % 24) == 0) {
  778. // Toggle the activity LED to make it blink during long writes.
  779. activity = !activity;
  780. if (activity)
  781. digitalWrite(PIN_ACTIVITY, HIGH);
  782. else
  783. digitalWrite(PIN_ACTIVITY, LOW);
  784. }
  785. }
  786. // All words in this packet have been written successfully.
  787. Serial.println("OK");
  788. }
  789. Serial.println("OK");
  790. }
  791. const char s_noPreserve[] PROGMEM = "NOPRESERVE";
  792. // ERASE command.
  793. void cmdErase(const char *args)
  794. {
  795. // Was the "NOPRESERVE" option given?
  796. int len = 0;
  797. while (args[len] != '\0' && args[len] != ' ' && args[len] != '\t')
  798. ++len;
  799. bool preserve = !matchString(s_noPreserve, args, len);
  800. // Preserve reserved words if necessary.
  801. unsigned int *reserved = 0;
  802. unsigned int configWord = 0x3FFF;
  803. if (preserve && reservedStart <= reservedEnd) {
  804. size_t size = ((size_t)(reservedEnd - reservedStart + 1))
  805. * sizeof(unsigned int);
  806. reserved = (unsigned int *)malloc(size);
  807. if (reserved) {
  808. unsigned long addr = reservedStart;
  809. int offset = 0;
  810. while (addr <= reservedEnd) {
  811. reserved[offset] = readWord(addr);
  812. ++addr;
  813. ++offset;
  814. }
  815. } else {
  816. // If we cannot preserve the reserved words, then abort now.
  817. Serial.println("ERROR");
  818. return;
  819. }
  820. }
  821. if (configSave != 0 && preserve) {
  822. // Some of the bits in the configuration word must also be saved.
  823. configWord &= ~configSave;
  824. configWord |= readWord(configStart + DEV_CONFIG_WORD) & configSave;
  825. }
  826. // Perform the memory type specific erase sequence.
  827. switch (progFlashType) {
  828. case FLASH4:
  829. setErasePC();
  830. sendSimpleCommand(CMD_BULK_ERASE_PROGRAM);
  831. delayMicroseconds(DELAY_TERA);
  832. sendSimpleCommand(CMD_BULK_ERASE_DATA);
  833. break;
  834. case FLASH5:
  835. setErasePC();
  836. sendSimpleCommand(CMD_CHIP_ERASE);
  837. break;
  838. default:
  839. // Details for disabling code protection and erasing all memory
  840. // for PIC16F84/PIC16F84A comes from this doc, section 4.1:
  841. // http://ww1.microchip.com/downloads/en/DeviceDoc/30262e.pdf
  842. setErasePC();
  843. for (int count = 0; count < 7; ++count)
  844. sendSimpleCommand(CMD_INCREMENT_ADDRESS); // Advance to 0x2007
  845. sendSimpleCommand(0x01); // Command 1
  846. sendSimpleCommand(0x07); // Command 7
  847. sendSimpleCommand(CMD_BEGIN_PROGRAM);
  848. delayMicroseconds(DELAY_TFULL84);
  849. sendSimpleCommand(0x01); // Command 1
  850. sendSimpleCommand(0x07); // Command 7
  851. // Some FLASH devices need the data memory to be erased separately.
  852. sendWriteCommand(CMD_LOAD_DATA_MEMORY, 0x3FFF);
  853. sendSimpleCommand(CMD_BULK_ERASE_DATA);
  854. sendSimpleCommand(CMD_BEGIN_PROGRAM);
  855. break;
  856. }
  857. // Wait until the chip is fully erased.
  858. delayMicroseconds(DELAY_TFULLERA);
  859. // Force the device to reset after it has been erased.
  860. exitProgramMode();
  861. enterProgramMode();
  862. // Write the reserved words back to program memory.
  863. if (reserved) {
  864. unsigned long addr = reservedStart;
  865. int offset = 0;
  866. bool ok = true;
  867. while (addr <= reservedEnd) {
  868. if (!writeWord(addr, reserved[offset]))
  869. ok = false;
  870. ++addr;
  871. ++offset;
  872. }
  873. free(reserved);
  874. if (!ok) {
  875. // Reserved words did not read back correctly.
  876. Serial.println("ERROR");
  877. return;
  878. }
  879. }
  880. // Forcibly write 0x3FFF over the configuration words as erase
  881. // sometimes won't reset the words (e.g. PIC16F628A). If the
  882. // write fails, then leave the words as-is - don't report the failure.
  883. for (unsigned long configAddr = configStart + DEV_CONFIG_WORD;
  884. configAddr <= configEnd; ++configAddr)
  885. writeWordForced(configAddr, configWord);
  886. // Done.
  887. Serial.println("OK");
  888. }
  889. // PWROFF command.
  890. void cmdPowerOff(const char *args)
  891. {
  892. exitProgramMode();
  893. Serial.println("OK");
  894. }
  895. // List of all commands that are understood by the programmer.
  896. typedef void (*commandFunc)(const char *args);
  897. typedef struct
  898. {
  899. const char PROGMEM *name;
  900. commandFunc func;
  901. const char PROGMEM *desc;
  902. const char PROGMEM *args;
  903. } command_t;
  904. const char s_cmdRead[] PROGMEM = "READ";
  905. const char s_cmdReadDesc[] PROGMEM =
  906. "Reads program and data words from device memory (text)";
  907. const char s_cmdReadArgs[] PROGMEM = "STARTADDR[-ENDADDR]";
  908. const char s_cmdReadBinary[] PROGMEM = "READBIN";
  909. const char s_cmdReadBinaryDesc[] PROGMEM =
  910. "Reads program and data words from device memory (binary)";
  911. const char s_cmdWrite[] PROGMEM = "WRITE";
  912. const char s_cmdWriteDesc[] PROGMEM =
  913. "Writes program and data words to device memory (text)";
  914. const char s_cmdWriteArgs[] PROGMEM = "STARTADDR WORD [WORD ...]";
  915. const char s_cmdWriteBinary[] PROGMEM = "WRITEBIN";
  916. const char s_cmdWriteBinaryDesc[] PROGMEM =
  917. "Writes program and data words to device memory (binary)";
  918. const char s_cmdWriteBinaryArgs[] PROGMEM = "STARTADDR";
  919. const char s_cmdErase[] PROGMEM = "ERASE";
  920. const char s_cmdEraseDesc[] PROGMEM =
  921. "Erases the contents of program, configuration, and data memory";
  922. const char s_cmdDevice[] PROGMEM = "DEVICE";
  923. const char s_cmdDeviceDesc[] PROGMEM =
  924. "Probes the device and returns information about it";
  925. const char s_cmdDevices[] PROGMEM = "DEVICES";
  926. const char s_cmdDevicesDesc[] PROGMEM =
  927. "Returns a list of all supported device types";
  928. const char s_cmdSetDevice[] PROGMEM = "SETDEVICE";
  929. const char s_cmdSetDeviceDesc[] PROGMEM =
  930. "Sets a specific device type manually";
  931. const char s_cmdSetDeviceArgs[] PROGMEM = "DEVTYPE";
  932. const char s_cmdPowerOff[] PROGMEM = "PWROFF";
  933. const char s_cmdPowerOffDesc[] PROGMEM =
  934. "Powers off the device in the programming socket";
  935. const char s_cmdVersion[] PROGMEM = "PROGRAM_PIC_VERSION";
  936. const char s_cmdVersionDesc[] PROGMEM =
  937. "Prints the version of ProgramPIC";
  938. const char s_cmdHelp[] PROGMEM = "HELP";
  939. const char s_cmdHelpDesc[] PROGMEM =
  940. "Prints this help message";
  941. const command_t commands[] PROGMEM = {
  942. {s_cmdRead, cmdRead, s_cmdReadDesc, s_cmdReadArgs},
  943. {s_cmdReadBinary, cmdReadBinary, s_cmdReadBinaryDesc, s_cmdReadArgs},
  944. {s_cmdWrite, cmdWrite, s_cmdWriteDesc, s_cmdWriteArgs},
  945. {s_cmdWriteBinary, cmdWriteBinary, s_cmdWriteBinaryDesc, s_cmdWriteBinaryArgs},
  946. {s_cmdErase, cmdErase, s_cmdEraseDesc, 0},
  947. {s_cmdDevice, cmdDevice, s_cmdDeviceDesc, 0},
  948. {s_cmdDevices, cmdDevices, s_cmdDevicesDesc, 0},
  949. {s_cmdSetDevice, cmdSetDevice, s_cmdSetDeviceDesc, s_cmdSetDeviceArgs},
  950. {s_cmdPowerOff, cmdPowerOff, s_cmdPowerOffDesc, 0},
  951. {s_cmdVersion, cmdVersion, s_cmdVersionDesc, 0},
  952. {s_cmdHelp, cmdHelp, s_cmdHelpDesc, 0},
  953. {0, 0}
  954. };
  955. // "HELP" command.
  956. void cmdHelp(const char *args)
  957. {
  958. Serial.println("OK");
  959. int index = 0;
  960. for (;;) {
  961. const char PROGMEM *name = (const char PROGMEM *)
  962. (pgm_read_word(&(commands[index].name)));
  963. if (!name)
  964. break;
  965. const char PROGMEM *desc = (const char PROGMEM *)
  966. (pgm_read_word(&(commands[index].desc)));
  967. const char PROGMEM *args = (const char PROGMEM *)
  968. (pgm_read_word(&(commands[index].args)));
  969. printProgString(name);
  970. if (args) {
  971. Serial.print(' ');
  972. printProgString(args);
  973. }
  974. Serial.println();
  975. Serial.print(" ");
  976. printProgString(desc);
  977. Serial.println();
  978. ++index;
  979. }
  980. Serial.println(".");
  981. }
  982. // Match a data-space string where the name comes from PROGMEM.
  983. bool matchString(const char PROGMEM *name, const char *str, int len)
  984. {
  985. for (;;) {
  986. char ch1 = (char)(pgm_read_byte(name));
  987. if (ch1 == '\0')
  988. return len == 0;
  989. else if (len == 0)
  990. break;
  991. if (ch1 >= 'a' && ch1 <= 'z')
  992. ch1 = ch1 - 'a' + 'A';
  993. char ch2 = *str;
  994. if (ch2 >= 'a' && ch2 <= 'z')
  995. ch2 = ch2 - 'a' + 'A';
  996. if (ch1 != ch2)
  997. break;
  998. ++name;
  999. ++str;
  1000. --len;
  1001. }
  1002. return false;
  1003. }
  1004. // Process commands from the host.
  1005. void processCommand(const char *buf)
  1006. {
  1007. // Skip white space at the start of the command.
  1008. while (*buf == ' ' || *buf == '\t')
  1009. ++buf;
  1010. if (*buf == '\0')
  1011. return; // Ignore blank lines.
  1012. // Extract the command portion of the line.
  1013. const char *cmd = buf;
  1014. int len = 0;
  1015. for (;;) {
  1016. char ch = *buf;
  1017. if (ch == '\0' || ch == ' ' || ch == '\t')
  1018. break;
  1019. ++buf;
  1020. ++len;
  1021. }
  1022. // Skip white space after the command name and before the arguments.
  1023. while (*buf == ' ' || *buf == '\t')
  1024. ++buf;
  1025. // Find the command and execute it.
  1026. int index = 0;
  1027. for (;;) {
  1028. const char PROGMEM *name = (const char PROGMEM *)
  1029. (pgm_read_word(&(commands[index].name)));
  1030. if (!name)
  1031. break;
  1032. if (matchString(name, cmd, len)) {
  1033. commandFunc func =
  1034. (commandFunc)(pgm_read_word(&(commands[index].func)));
  1035. (*func)(buf);
  1036. return;
  1037. }
  1038. ++index;
  1039. }
  1040. // Unknown command.
  1041. Serial.println("NOTSUPPORTED");
  1042. }
  1043.  
  1044. // Enter high voltage programming mode.
  1045. void enterProgramMode() {
  1046.   // Bail out if already in programming mode.
  1047.   if (state != STATE_IDLE) return;
  1048.   // Lower MCLR, VDD, DATA, and CLOCK initially. This will put the
  1049.   // PIC into the powered-off, reset state just in case.
  1050.   digitalWrite(PIN_MCLR, MCLR_RESET);
  1051.   digitalWrite(PIN_VDD, LOW);
  1052.   digitalWrite(PIN_DATA, LOW);
  1053.   digitalWrite(PIN_CLOCK, LOW);
  1054.   // Wait for the lines to settle.
  1055.   delayMicroseconds(DELAY_SETTLE);
  1056.   // Switch DATA and CLOCK into outputs.
  1057.   pinMode(PIN_DATA, OUTPUT);
  1058.   pinMode(PIN_CLOCK, OUTPUT);
  1059.   if (hpp_progEntryMode == MCLR_first) {
  1060.     // Raise MCLR, then VDD.
  1061.     digitalWrite(PIN_MCLR, MCLR_VPP);
  1062.     delayMicroseconds(DELAY_TPPDP);
  1063.     digitalWrite(PIN_VDD, HIGH);
  1064.     delayMicroseconds(DELAY_THLD0);
  1065.   } else {
  1066.     digitalWrite(PIN_VDD, HIGH);
  1067.     delayMicroseconds(DELAY_THLD0);
  1068.     digitalWrite(PIN_MCLR, MCLR_VPP);
  1069.     delayMicroseconds(DELAY_TPPDP);
  1070.   }      
  1071.   // Now in program mode, starting at the first word of program memory.
  1072.   state = STATE_PROGRAM;
  1073.   pc = 0;
  1074. }
  1075.  
  1076. // Exit programming mode and reset the device.
  1077. void exitProgramMode()
  1078. {
  1079. // Nothing to do if already out of programming mode.
  1080. if (state == STATE_IDLE)
  1081. return;
  1082. // Lower MCLR, VDD, DATA, and CLOCK.
  1083. digitalWrite(PIN_MCLR, MCLR_RESET);
  1084. digitalWrite(PIN_VDD, LOW);
  1085. digitalWrite(PIN_DATA, LOW);
  1086. digitalWrite(PIN_CLOCK, LOW);
  1087. // Float the DATA and CLOCK pins.
  1088. pinMode(PIN_DATA, INPUT);
  1089. pinMode(PIN_CLOCK, INPUT);
  1090. // Now in the idle state with the PIC powered off.
  1091. state = STATE_IDLE;
  1092. pc = 0;
  1093. }
  1094. // Send a command to the PIC.
  1095. void sendCommand(byte cmd)
  1096. {
  1097. for (byte bit = 0; bit < 6; ++bit) {
  1098. digitalWrite(PIN_CLOCK, HIGH);
  1099. if (cmd & 1)
  1100. digitalWrite(PIN_DATA, HIGH);
  1101. else
  1102. digitalWrite(PIN_DATA, LOW);
  1103. delayMicroseconds(DELAY_TSET1);
  1104. digitalWrite(PIN_CLOCK, LOW);
  1105. delayMicroseconds(DELAY_THLD1);
  1106. cmd >>= 1;
  1107. }
  1108. }
  1109. // Send a command to the PIC that has no arguments.
  1110. void sendSimpleCommand(byte cmd)
  1111. {
  1112. sendCommand(cmd);
  1113. delayMicroseconds(DELAY_TDLY2);
  1114. }
  1115. // Send a command to the PIC that writes a data argument.
  1116. void sendWriteCommand(byte cmd, unsigned int data)
  1117. {
  1118. sendCommand(cmd);
  1119. delayMicroseconds(DELAY_TDLY2);
  1120. for (byte bit = 0; bit < 16; ++bit) {
  1121. digitalWrite(PIN_CLOCK, HIGH);
  1122. if (data & 1)
  1123. digitalWrite(PIN_DATA, HIGH);
  1124. else
  1125. digitalWrite(PIN_DATA, LOW);
  1126. delayMicroseconds(DELAY_TSET1);
  1127. digitalWrite(PIN_CLOCK, LOW);
  1128. delayMicroseconds(DELAY_THLD1);
  1129. data >>= 1;
  1130. }
  1131. delayMicroseconds(DELAY_TDLY2);
  1132. }
  1133. // Send a command to the PIC that reads back a data value.
  1134. unsigned int sendReadCommand(byte cmd)
  1135. {
  1136. unsigned int data = 0;
  1137. sendCommand(cmd);
  1138. digitalWrite(PIN_DATA, LOW);
  1139. pinMode(PIN_DATA, INPUT);
  1140. delayMicroseconds(DELAY_TDLY2);
  1141. for (byte bit = 0; bit < 16; ++bit) {
  1142. data >>= 1;
  1143. digitalWrite(PIN_CLOCK, HIGH);
  1144. delayMicroseconds(DELAY_TDLY3);
  1145. if (digitalRead(PIN_DATA))
  1146. data |= 0x8000;
  1147. digitalWrite(PIN_CLOCK, LOW);
  1148. delayMicroseconds(DELAY_THLD1);
  1149. }
  1150. pinMode(PIN_DATA, OUTPUT);
  1151. delayMicroseconds(DELAY_TDLY2);
  1152. return data;
  1153. }
  1154. // Set the program counter to a specific "flat" address.
  1155. void setPC(unsigned long addr)
  1156. {
  1157. if (addr >= dataStart && addr <= dataEnd) {
  1158. // Data memory.
  1159. addr -= dataStart;
  1160. if (state != STATE_PROGRAM || addr < pc) {
  1161. // Device is off, currently looking at configuration memory,
  1162. // or the address is further back. Reset the device.
  1163. exitProgramMode();
  1164. enterProgramMode();
  1165. }
  1166. } else if (addr >= configStart && addr <= configEnd) {
  1167. // Configuration memory.
  1168. addr -= configStart;
  1169. if (state == STATE_IDLE) {
  1170. // Enter programming mode and switch to config memory.
  1171. enterProgramMode();
  1172. sendWriteCommand(CMD_LOAD_CONFIG, 0);
  1173. state = STATE_CONFIG;
  1174. } else if (state == STATE_PROGRAM) {
  1175. // Switch from program memory to config memory.
  1176. sendWriteCommand(CMD_LOAD_CONFIG, 0);
  1177. state = STATE_CONFIG;
  1178. pc = 0;
  1179. } else if (addr < pc) {
  1180. // Need to go backwards in config memory, so reset the device.
  1181. exitProgramMode();
  1182. enterProgramMode();
  1183. sendWriteCommand(CMD_LOAD_CONFIG, 0);
  1184. state = STATE_CONFIG;
  1185. }
  1186. } else {
  1187. // Program memory.
  1188. if (state != STATE_PROGRAM || addr < pc) {
  1189. // Device is off, currently looking at configuration memory,
  1190. // or the address is further back. Reset the device.
  1191. exitProgramMode();
  1192. enterProgramMode();
  1193. }
  1194. }
  1195. while (pc < addr) {
  1196. sendSimpleCommand(CMD_INCREMENT_ADDRESS);
  1197. ++pc;
  1198. }
  1199. }
  1200. // Sets the PC for "erase mode", which is activated by loading the
  1201. // data value 0x3FFF into location 0 of configuration memory.
  1202. void setErasePC()
  1203. {
  1204. // Forcibly reset the device so we know what state it is in.
  1205. exitProgramMode();
  1206. enterProgramMode();
  1207. // Load 0x3FFF for the configuration.
  1208. sendWriteCommand(CMD_LOAD_CONFIG, 0x3FFF);
  1209. state = STATE_CONFIG;
  1210. }
  1211. // Read a word from memory (program, config, or data depending upon addr).
  1212. // The start and stop bits will be stripped from the raw value from the PIC.
  1213. unsigned int readWord(unsigned long addr)
  1214. {
  1215. setPC(addr);
  1216. if (addr >= dataStart && addr <= dataEnd)
  1217. return (sendReadCommand(CMD_READ_DATA_MEMORY) >> 1) & 0x00FF;
  1218. else
  1219. return (sendReadCommand(CMD_READ_PROGRAM_MEMORY) >> 1) & 0x3FFF;
  1220. }
  1221.  
  1222. // Read a word from config memory using relative, non-flat, addressing.
  1223. // Used by the "DEVICE" command to fetch information about devices whose
  1224. // flat address ranges are presently unknown.
  1225. unsigned int readConfigWord(unsigned long addr)
  1226. {
  1227. if (state == STATE_IDLE) {
  1228. // Enter programming mode and switch to config memory.
  1229. enterProgramMode();
  1230. sendWriteCommand(CMD_LOAD_CONFIG, 0);
  1231. state = STATE_CONFIG;
  1232. } else if (state == STATE_PROGRAM) {
  1233. // Switch from program memory to config memory.
  1234. sendWriteCommand(CMD_LOAD_CONFIG, 0);
  1235. state = STATE_CONFIG;
  1236. pc = 0;
  1237. } else if (addr < pc) {
  1238. // Need to go backwards in config memory, so reset the device.
  1239. exitProgramMode();
  1240. enterProgramMode();
  1241. sendWriteCommand(CMD_LOAD_CONFIG, 0);
  1242. state = STATE_CONFIG;
  1243. }
  1244. while (pc < addr) {
  1245. sendSimpleCommand(CMD_INCREMENT_ADDRESS);
  1246. ++pc;
  1247. }
  1248. return (sendReadCommand(CMD_READ_PROGRAM_MEMORY) >> 1) & 0x3FFF;
  1249. }
  1250.  
  1251. // Begin a programming cycle, depending upon the type of flash being written.
  1252. void beginProgramCycle(unsigned long addr, bool isData)
  1253. {
  1254. switch (isData ? dataFlashType : progFlashType) {
  1255. case FLASH:
  1256. case EEPROM:
  1257. sendSimpleCommand(CMD_BEGIN_PROGRAM);
  1258. delayMicroseconds(DELAY_TDPROG + DELAY_TERA);
  1259. break;
  1260. case FLASH4:
  1261. sendSimpleCommand(CMD_BEGIN_PROGRAM);
  1262. delayMicroseconds(DELAY_TPROG);
  1263. break;
  1264. case FLASH5:
  1265. sendSimpleCommand(CMD_BEGIN_PROGRAM_ONLY);
  1266. delayMicroseconds(DELAY_TPROG5);
  1267. sendSimpleCommand(CMD_END_PROGRAM_ONLY);
  1268. break;
  1269. }
  1270. }
  1271. // Write a word to memory (program, config, or data depending upon addr).
  1272. // Returns true if the write succeeded, false if read-back failed to match.
  1273. bool writeWord(unsigned long addr, unsigned int word)
  1274. {
  1275. unsigned int readBack;
  1276. setPC(addr);
  1277. if (addr >= dataStart && addr <= dataEnd) {
  1278. word &= 0x00FF;
  1279. sendWriteCommand(CMD_LOAD_DATA_MEMORY, word << 1);
  1280. beginProgramCycle(addr, true);
  1281. readBack = sendReadCommand(CMD_READ_DATA_MEMORY);
  1282. readBack = (readBack >> 1) & 0x00FF;
  1283. } else if (!configSave || addr != (configStart + DEV_CONFIG_WORD)) {
  1284. word &= 0x3FFF;
  1285. sendWriteCommand(CMD_LOAD_PROGRAM_MEMORY, word << 1);
  1286. beginProgramCycle(addr, false);
  1287. readBack = sendReadCommand(CMD_READ_PROGRAM_MEMORY);
  1288. readBack = (readBack >> 1) & 0x3FFF;
  1289. } else {
  1290. // The configuration word has calibration bits within it that
  1291. // must be preserved when we write to it. Read the current value
  1292. // and preserve the necessary bits.
  1293. readBack = (sendReadCommand(CMD_READ_PROGRAM_MEMORY) >> 1) & 0x3FFF;
  1294. word = (readBack & configSave) | (word & 0x3FFF & ~configSave);
  1295. sendWriteCommand(CMD_LOAD_PROGRAM_MEMORY, word << 1);
  1296. beginProgramCycle(addr, false);
  1297. readBack = sendReadCommand(CMD_READ_PROGRAM_MEMORY);
  1298. readBack = (readBack >> 1) & 0x3FFF;
  1299. }
  1300. return readBack == word;
  1301. }
  1302. // Force a word to be written even if it normally would protect config bits.
  1303. bool writeWordForced(unsigned long addr, unsigned int word)
  1304. {
  1305. unsigned int readBack;
  1306. setPC(addr);
  1307. if (addr >= dataStart && addr <= dataEnd) {
  1308. word &= 0x00FF;
  1309. sendWriteCommand(CMD_LOAD_DATA_MEMORY, word << 1);
  1310. beginProgramCycle(addr, true);
  1311. readBack = sendReadCommand(CMD_READ_DATA_MEMORY);
  1312. readBack = (readBack >> 1) & 0x00FF;
  1313. } else {
  1314. word &= 0x3FFF;
  1315. sendWriteCommand(CMD_LOAD_PROGRAM_MEMORY, word << 1);
  1316. beginProgramCycle(addr, false);
  1317. readBack = sendReadCommand(CMD_READ_PROGRAM_MEMORY);
  1318. readBack = (readBack >> 1) & 0x3FFF;
  1319. }
  1320. return readBack == word;
  1321. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement