Pastebin launched a little side project called VERYVIRAL.com, check it out ;-) Want more features on Pastebin? Sign Up, it's FREE!
Guest

Arduino ISP boot-selectable, serial-config slow SPI support

By: a guest on Apr 23rd, 2012  |  syntax: C++  |  size: 17.08 KB  |  views: 1,045  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. // this sketch turns the Arduino into a AVRISP
  2. // using the following pins:
  3. // 10: target reset
  4. // 11: MOSI
  5. // 12: MISO
  6. // 13: SCK
  7.  
  8. // Put an LED (with resistor) on the following pins:
  9. // 6: Heartbeat - shows the programmer is running
  10. // 8: Error - Lights up if something goes wrong (use red if that makes sense)
  11. // 5: Programming - In communication with the slave
  12. // 7: Configured for output at LOW
  13. // The above arrangement makes it easy to attach a common-cathode RGB LED directly
  14. // into the arduino pin header.
  15. //
  16. // April 2012 by Joey Morin
  17. // - Integrated code from http://pastebin.com/Aw5BD0zy probably authored by
  18. // smeezekitty, referenced in http://arduino.cc/forum/index.php?topic=89918.0
  19. // to include support for slow software SPI.  This allows for programming of
  20. // targets with clk < 500KHz, which is the lower limit for hardware SPI on a
  21. // 16MHz Arduino (SPI clock of 125KHz).
  22. // - Minor code cleanup.
  23. // - Mode selection is made on powerup or reset.  Switch or short the
  24. // MODE_BUTTON pin to GND to enable slow software SPI mode.  Current mode is
  25. // indicated by a fast or slow heartbeat.
  26. //
  27. // October 2009 by David A. Mellis
  28. // - Added support for the read signature command
  29. //
  30. // February 2009 by Randall Bohn
  31. // - Added support for writing to EEPROM (what took so long?)
  32. // Windows users should consider WinAVR's avrdude instead of the
  33. // avrdude included with Arduino software.
  34. //
  35. // January 2008 by Randall Bohn
  36. // - Thanks to Amplificar for helping me with the STK500 protocol
  37. // - The AVRISP/STK500 (mk I) protocol is used in the arduino bootloader
  38. // - The SPI functions herein were developed for the AVR910_ARD programmer
  39. // - More information at http://code.google.com/p/mega-isp
  40.  
  41. // These set the correct timing delays for programming a target with clk < 500KHz.
  42. // Be sure to specify the lowest clock frequency of any target you plan to burn.
  43. // The rule is the programing clock (on SCK) must be less than 1/4 the clock
  44. // speed of the target (or 1/6 for speeds above 12MHz).  For example, if using
  45. // the 128KHz RC oscillator, with a prescaler of 8, the target's clock frequency
  46. // would be 16KHz, and the maximum programming clock would be 4KHz, or a clock
  47. // period of 250uS.  The algorithm uses a quarter of the clock period for sync
  48. // purposes, so quarter_period would be set to 63uS.  Be aware that internal RC
  49. // oscillators can be off by as much as 10%, so you might have to force a slower
  50. // clock speed.
  51. #define DEFAULT_MINIMUM_TARGET_CLOCK_SPEED 128000
  52. #define DEFAULT_SCK_FREQUENCY (DEFAULT_MINIMUM_TARGET_CLOCK_SPEED/4)
  53. #define DEFAULT_QUARTER_PERIOD ((1000000/DEFAULT_SCK_FREQUENCY/4)+1)
  54.  
  55. #define MINIMUM_SCK_FREQUENCY 50
  56. #define QUARTER_PERIOD_EEPROM_ADDRESS 0
  57.  
  58. #define HWVER 2
  59. #define SWMAJ 1
  60. #define SWMIN 18
  61.  
  62. #define LED_HB 6
  63. #define LED_ERR 8
  64. #define LED_PMODE 5
  65. #define LED_COMMON 7
  66.  
  67. #define MODE_BUTTON 9
  68.  
  69. #define MAX_COMMAND_LENGTH 64
  70.  
  71. // As per http://arduino.cc/en/Tutorial/ArduinoISP
  72. #if ARDUINO >= 100
  73. #define HB_DELAY 20
  74. #else
  75. #define HB_DELAY 40
  76. #endif
  77.  
  78. #include <EEPROM.h>
  79.  
  80. #define RESET SS
  81.  
  82. // STK Definitions
  83. #define STK_OK 0x10
  84. #define STK_FAILED 0x11
  85. #define STK_UNKNOWN 0x12
  86. #define STK_INSYNC 0x14
  87. #define STK_NOSYNC 0x15
  88. #define CRC_EOP 0x20 //ok it is a space...
  89.  
  90. #define PTIME 30
  91.  
  92. #define HW_SPI_MODE 1
  93. #define SW_SPI_MODE 0
  94.  
  95. uint8_t spi_mode;
  96.  
  97. // safe EEPROM write (only writes if value changed)
  98. void safe_EEPROM_write(int address, byte value) {
  99.   if (value != EEPROM.read(address)) {
  100.     EEPROM.write(address, value);
  101.   }
  102. }
  103.  
  104. // save a 16 bit value to eeprom
  105. void save_quarter_period_to_eeprom(unsigned int value) {
  106.  
  107.  safe_EEPROM_write(QUARTER_PERIOD_EEPROM_ADDRESS, (uint8_t)(value & 0x00FF));
  108.  safe_EEPROM_write(QUARTER_PERIOD_EEPROM_ADDRESS+1, (uint8_t)((value & 0xFF00) >> 8));
  109.  
  110. }
  111.  
  112. unsigned int load_quarter_period_from_eeprom() {
  113.   unsigned int value;
  114.  
  115.   value = EEPROM.read(QUARTER_PERIOD_EEPROM_ADDRESS) + (EEPROM.read(QUARTER_PERIOD_EEPROM_ADDRESS+1) << 8);
  116.   if ((value == 0) || (value > 1000000/MINIMUM_SCK_FREQUENCY/4))
  117.     value = DEFAULT_QUARTER_PERIOD;
  118.  
  119.   return value;
  120. }
  121.  
  122. // configure programming speed
  123. unsigned int quarter_period = load_quarter_period_from_eeprom();
  124.  
  125. // set programming clock from a terminal
  126. void change_sck() {
  127.  
  128.   char command[MAX_COMMAND_LENGTH];
  129.   uint8_t command_length = 0;
  130.   int key;
  131.   uint32_t sck_frequency;
  132.  
  133.   Serial.print("Current software SPI quarter-period delay: ");
  134.   Serial.print(quarter_period);
  135.   Serial.print(" microseconds,\n\r");
  136.   Serial.print("Resulting in a programming speed of ");
  137.   Serial.print(1000000/quarter_period/4);
  138.   Serial.print(" Hz.\n\r");
  139.   Serial.print("Enter a new programming clock speed (SCK) in HZ for software SPI.\n\r");
  140.   Serial.print("(NOTE THAT THIS SHOULD BE LESS THAN 1/4 OF TARGET'S CLOCK SPEED):\n\r");
  141.  
  142.   while(true) {
  143.     heartbeat();
  144.     key = Serial.read();
  145.     if (key != -1) {
  146.       Serial.write(key);
  147.       if (key == '\r') {
  148.         Serial.println();
  149.         command[command_length] = 0;
  150.         sck_frequency = atoi(command);
  151.         if (sck_frequency < 50) {
  152.           Serial.print("\n\rERROR: MINIMUM FREQUENCY IS 50 HZ, TRY AGAIN.\n\r");
  153.         }
  154.         else {
  155.           quarter_period = (1000000/sck_frequency/4)+1;
  156.           Serial.print("Setting software SPI quarter-period delay to ");
  157.           Serial.print(quarter_period);
  158.           Serial.print(" microseconds,\n\r");
  159.           Serial.print("Resulting in a programming speed of ");
  160.           Serial.print(1000000/quarter_period/4);
  161.           Serial.print(" Hz.\n\r");
  162.           save_quarter_period_to_eeprom(quarter_period);
  163.           Serial.print("Saved to EEPROM.\n\r");
  164.           return;
  165.         }
  166.       }
  167.       else if ((key == 8) || (key == 127)) {
  168.         if (command_length) {
  169.           command[command_length] = 0;
  170.           command[--command_length] = ' ';
  171.           Serial.print("\r");
  172.           Serial.write(command);
  173.           command[command_length] = 0;
  174.           Serial.print("\r");
  175.           Serial.write(command);
  176.         }
  177.       }
  178.       else {
  179.         command[command_length++] = key;
  180.       }
  181.       if (command_length >= MAX_COMMAND_LENGTH-1) {
  182.         Serial.print("\n\rERROR: COMMAND LINE TOO LONG, START OVER.\n\r");
  183.         command_length = 0;
  184.       }
  185.     }
  186.   }
  187. }
  188.  
  189. uint8_t hbval=12;
  190. int8_t hbdelta;
  191.  
  192. // this provides a heartbeat on pin 9, so you can tell the software is running.
  193. void heartbeat() {
  194.   if ((hbval > 24) || (hbval < 2))
  195.     hbdelta = -hbdelta;
  196.   hbval += hbdelta;
  197.   analogWrite(LED_HB, hbval);
  198.   delay(HB_DELAY);
  199. }
  200.  
  201. void pulse(int pin, int times) {
  202.   do {
  203.     digitalWrite(pin, HIGH);
  204.     delay(PTIME);
  205.     digitalWrite(pin, LOW);
  206.     delay(PTIME);
  207.   }
  208.   while (times--);
  209. }
  210.  
  211. void (*spi_init)();
  212. uint8_t (*spi_send)(uint8_t);
  213.  
  214. void setup() {
  215.   Serial.begin(19200);
  216.   pinMode(MODE_BUTTON, INPUT);
  217.   digitalWrite(MODE_BUTTON, HIGH);
  218.   pinMode(LED_PMODE, OUTPUT);
  219.   pinMode(LED_ERR, OUTPUT);
  220.   pinMode(LED_HB, OUTPUT);
  221.   pinMode(LED_COMMON, OUTPUT);
  222.   digitalWrite(LED_COMMON, LOW);
  223.   pulse(LED_PMODE, 2);
  224.   pulse(LED_ERR, 2);
  225.   pulse(LED_HB, 2);
  226.   pinMode(MODE_BUTTON, INPUT);
  227.   digitalWrite(MODE_BUTTON, HIGH);
  228.   if (digitalRead(MODE_BUTTON)){
  229.     spi_mode = HW_SPI_MODE;
  230.     spi_init = hw_spi_init;
  231.     spi_send = hw_spi_send;
  232.     hbdelta = 2;
  233.   }
  234.   else {
  235.     spi_mode = SW_SPI_MODE;
  236.     spi_init = sw_spi_init;
  237.     spi_send = sw_spi_send;
  238.     hbdelta = 1;
  239.   }
  240. }
  241.  
  242. int error=0;
  243. int pmode=0;
  244. // address for reading and writing, set by 'U' command
  245. int here;
  246. uint8_t buff[256]; // global block storage
  247.  
  248. #define beget16(addr) (*addr * 256 + *(addr+1) )
  249.  
  250. typedef struct param {
  251.   uint8_t devicecode;
  252.   uint8_t revision;
  253.   uint8_t progtype;
  254.   uint8_t parmode;
  255.   uint8_t polling;
  256.   uint8_t selftimed;
  257.   uint8_t lockbytes;
  258.   uint8_t fusebytes;
  259.   int flashpoll;
  260.   int eeprompoll;
  261.   int pagesize;
  262.   int eepromsize;
  263.   int flashsize;
  264. }
  265. parameter;
  266.  
  267. parameter param;
  268.  
  269. #define LED_PWM_DUTY 10
  270. void loop(void) {
  271.   static uint8_t pwm;
  272.   // is pmode active?
  273.   if (pmode) analogWrite(LED_PMODE, (pwm++)%((LED_PWM_DUTY<<1))<<2);
  274.   else digitalWrite(LED_PMODE, LOW);
  275.   // is there an error?
  276.   if (error) digitalWrite(LED_ERR, !((pwm++)%LED_PWM_DUTY));
  277.   else digitalWrite(LED_ERR, LOW);
  278.  
  279.   // light the heartbeat LED
  280.   heartbeat();
  281.   if (Serial.available()) {
  282.     avrisp();
  283.   }
  284. }
  285.  
  286. uint8_t getch() {
  287.   while(!Serial.available());
  288.   return Serial.read();
  289. }
  290. void readbytes(int n) {
  291.   for (int x = 0; x < n; x++) {
  292.     buff[x] = Serial.read();
  293.   }
  294. }
  295.  
  296. void hw_spi_init() {
  297.   uint8_t x;
  298.   SPCR = 0x53;
  299.   x=SPSR;
  300.   x=SPDR;
  301. }
  302.  
  303. void sw_spi_init() {
  304. }
  305.  
  306. void spi_wait() {
  307.   do {
  308.   }
  309.   while (!(SPSR & (1 << SPIF)));
  310. }
  311.  
  312. uint8_t hw_spi_send(uint8_t b) {
  313.   uint8_t reply;
  314.   SPDR=b;
  315.   spi_wait();
  316.   reply = SPDR;
  317.   return reply;
  318. }
  319.  
  320. #define PCK() (bits[0] << 7 | bits[1] << 6 | bits[2] << 5 | bits[3] << 4 | bits[4] << 3 | bits[5] << 2 | bits[6] << 1 | bits[7])
  321.  
  322. uint8_t sw_spi_send(uint8_t b) {
  323.   unsigned static char msk[] = {
  324.     0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1   };
  325.   uint8_t reply;
  326.   char bits[8] = {
  327.     0, 0, 0, 0, 0, 0, 0, 0   };
  328.   for(uint8_t _bit = 0;_bit < 8;_bit++){
  329.     digitalWrite(MOSI, !!(b & msk[_bit]));
  330.     delayMicroseconds(quarter_period);
  331.     digitalWrite(SCK, HIGH);
  332.     delayMicroseconds(quarter_period);
  333.     bits[_bit] = digitalRead(MISO);
  334.     delayMicroseconds(quarter_period);
  335.     digitalWrite(SCK, LOW);
  336.     delayMicroseconds(quarter_period);
  337.   }
  338.   reply = PCK();
  339.   return reply;
  340. }
  341.  
  342. uint8_t spi_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
  343.   uint8_t n;
  344.   spi_send(a);
  345.   n=spi_send(b);
  346.   //if (n != a) error = -1;
  347.   n=spi_send(c);
  348.   return spi_send(d);
  349. }
  350.  
  351. void empty_reply() {
  352.   if (CRC_EOP == getch()) {
  353.     Serial.print((char)STK_INSYNC);
  354.     Serial.print((char)STK_OK);
  355.   }
  356.   else {
  357.     Serial.print((char)STK_NOSYNC);
  358.   }
  359. }
  360.  
  361. void breply(uint8_t b) {
  362.   if (CRC_EOP == getch()) {
  363.     Serial.print((char)STK_INSYNC);
  364.     Serial.print((char)b);
  365.     Serial.print((char)STK_OK);
  366.   }
  367.   else {
  368.     Serial.print((char)STK_NOSYNC);
  369.   }
  370. }
  371.  
  372. void get_version(uint8_t c) {
  373.   switch(c) {
  374.   case 0x80:
  375.     breply(HWVER);
  376.     break;
  377.   case 0x81:
  378.     breply(SWMAJ);
  379.     break;
  380.   case 0x82:
  381.     breply(SWMIN);
  382.     break;
  383.   case 0x93:
  384.     breply('S'); // serial programmer
  385.     break;
  386.   default:
  387.     breply(0);
  388.   }
  389. }
  390.  
  391. void set_parameters() {
  392.   // call this after reading paramter packet into buff[]
  393.   param.devicecode = buff[0];
  394.   param.revision = buff[1];
  395.   param.progtype = buff[2];
  396.   param.parmode = buff[3];
  397.   param.polling = buff[4];
  398.   param.selftimed = buff[5];
  399.   param.lockbytes = buff[6];
  400.   param.fusebytes = buff[7];
  401.   param.flashpoll = buff[8];
  402.   // ignore buff[9] (= buff[8])
  403.   //getch(); // discard second value
  404.  
  405.   // WARNING: not sure about the byte order of the following
  406.   // following are 16 bits (big endian)
  407.   param.eeprompoll = beget16(&buff[10]);
  408.   param.pagesize = beget16(&buff[12]);
  409.   param.eepromsize = beget16(&buff[14]);
  410.  
  411.   // 32 bits flashsize (big endian)
  412.   param.flashsize = buff[16] * 0x01000000
  413.     + buff[17] * 0x00010000
  414.     + buff[18] * 0x00000100
  415.     + buff[19];
  416.  
  417. }
  418.  
  419. void start_pmode() {
  420.   spi_init();
  421.   // following delays may not work on all targets...
  422.   pinMode(RESET, OUTPUT);
  423.   digitalWrite(RESET, HIGH);
  424.   pinMode(SCK, OUTPUT);
  425.   digitalWrite(SCK, LOW);
  426.   delay(50);
  427.   digitalWrite(RESET, LOW);
  428.   delay(50);
  429.   pinMode(MISO, INPUT);
  430.   pinMode(MOSI, OUTPUT);
  431.   spi_transaction(0xAC, 0x53, 0x00, 0x00);
  432.   pmode = 1;
  433. }
  434.  
  435. void end_pmode() {
  436.   pinMode(MISO, INPUT);
  437.   pinMode(MOSI, INPUT);
  438.   pinMode(SCK, INPUT);
  439.   pinMode(RESET, INPUT);
  440.   pmode = 0;
  441. }
  442.  
  443. void universal() {
  444.   int w;
  445.   uint8_t ch;
  446.  
  447.   for (w = 0; w < 4; w++) {
  448.     buff[w] = getch();
  449.   }
  450.   ch = spi_transaction(buff[0], buff[1], buff[2], buff[3]);
  451.   breply(ch);
  452. }
  453.  
  454. void flash(uint8_t hilo, int addr, uint8_t data) {
  455.   spi_transaction(0x40+8*hilo,
  456.   addr>>8 & 0xFF,
  457.   addr & 0xFF,
  458.   data);
  459. }
  460. void commit(int addr) {
  461.   spi_transaction(0x4C, (addr >> 8) & 0xFF, addr & 0xFF, 0);
  462. }
  463.  
  464. //#define _current_page(x) (here & 0xFFFFE0)
  465. int current_page(int addr) {
  466.   if (param.pagesize == 32) return here & 0xFFFFFFF0;
  467.   if (param.pagesize == 64) return here & 0xFFFFFFE0;
  468.   if (param.pagesize == 128) return here & 0xFFFFFFC0;
  469.   if (param.pagesize == 256) return here & 0xFFFFFF80;
  470.   return here;
  471. }
  472. uint8_t write_flash(int length) {
  473.   if (param.pagesize < 1) return STK_FAILED;
  474.   //if (param.pagesize != 64) return STK_FAILED;
  475.   int page = current_page(here);
  476.   int x = 0;
  477.   while (x < length) {
  478.     if (page != current_page(here)) {
  479.       commit(page);
  480.       page = current_page(here);
  481.     }
  482.     flash(LOW, here, buff[x++]);
  483.     flash(HIGH, here, buff[x++]);
  484.     here++;
  485.   }
  486.  
  487.   commit(page);
  488.  
  489.   return STK_OK;
  490. }
  491.  
  492. uint8_t write_eeprom(int length) {
  493.   // here is a word address, so we use here*2
  494.   // this writes byte-by-byte,
  495.   // page writing may be faster (4 bytes at a time)
  496.   for (int x = 0; x < length; x++) {
  497.     spi_transaction(0xC0, 0x00, here*2+x, buff[x]);
  498.     delay(45);
  499.   }
  500.   return STK_OK;
  501. }
  502.  
  503. void program_page() {
  504.   char result = (char) STK_FAILED;
  505.   int length = 256 * getch() + getch();
  506.   if (length > 256) {
  507.     Serial.print((char) STK_FAILED);
  508.     return;
  509.   }
  510.   char memtype = getch();
  511.   for (int x = 0; x < length; x++) {
  512.     buff[x] = getch();
  513.   }
  514.   if (CRC_EOP == getch()) {
  515.     Serial.print((char) STK_INSYNC);
  516.     if (memtype == 'F') result = (char)write_flash(length);
  517.     if (memtype == 'E') result = (char)write_eeprom(length);
  518.     Serial.print(result);
  519.   }
  520.   else {
  521.     Serial.print((char) STK_NOSYNC);
  522.   }
  523. }
  524. uint8_t flash_read(uint8_t hilo, int addr) {
  525.   return spi_transaction(0x20 + hilo * 8,
  526.   (addr >> 8) & 0xFF,
  527.   addr & 0xFF,
  528.   0);
  529. }
  530.  
  531. char flash_read_page(int length) {
  532.   for (int x = 0; x < length; x+=2) {
  533.     uint8_t low = flash_read(LOW, here);
  534.     Serial.print((char) low);
  535.     uint8_t high = flash_read(HIGH, here);
  536.     Serial.print((char) high);
  537.     here++;
  538.   }
  539.   return STK_OK;
  540. }
  541.  
  542. char eeprom_read_page(int length) {
  543.   // here again we have a word address
  544.   for (int x = 0; x < length; x++) {
  545.     uint8_t ee = spi_transaction(0xA0, 0x00, here*2+x, 0xFF);
  546.     Serial.print((char) ee);
  547.   }
  548.   return STK_OK;
  549. }
  550.  
  551. void read_page() {
  552.   char result = (char)STK_FAILED;
  553.   int length = 256 * getch() + getch();
  554.   char memtype = getch();
  555.   if (CRC_EOP != getch()) {
  556.     Serial.print((char) STK_NOSYNC);
  557.     return;
  558.   }
  559.   Serial.print((char) STK_INSYNC);
  560.   if (memtype == 'F') result = flash_read_page(length);
  561.   if (memtype == 'E') result = eeprom_read_page(length);
  562.   Serial.print(result);
  563.   return;
  564. }
  565.  
  566. void read_signature() {
  567.   if (CRC_EOP != getch()) {
  568.     Serial.print((char) STK_NOSYNC);
  569.     return;
  570.   }
  571.   Serial.print((char) STK_INSYNC);
  572.   uint8_t high = spi_transaction(0x30, 0x00, 0x00, 0x00);
  573.   Serial.print((char) high);
  574.   uint8_t middle = spi_transaction(0x30, 0x00, 0x01, 0x00);
  575.   Serial.print((char) middle);
  576.   uint8_t low = spi_transaction(0x30, 0x00, 0x02, 0x00);
  577.   Serial.print((char) low);
  578.   Serial.print((char) STK_OK);
  579. }
  580. //////////////////////////////////////////
  581. //////////////////////////////////////////
  582.  
  583.  
  584. ////////////////////////////////////
  585. ////////////////////////////////////
  586. int avrisp() {
  587.   uint8_t data, low, high;
  588.   uint8_t ch = getch();
  589.   uint8_t static cr = 0;
  590.  
  591.   // support for changing SCK speed via serial interface
  592.   // issuing carriage return 5 times in a row enters SCK change mode
  593.   if (spi_mode == SW_SPI_MODE) {
  594.     if (ch == '\r') {
  595.       cr++;
  596.       if (cr >= 5) {
  597.         cr = 0;
  598.         change_sck();
  599.       }
  600.       return 0;
  601.     }
  602.     else {
  603.       cr = 0;
  604.     }
  605.   }
  606.  
  607.   switch (ch) {
  608.   case '0': // signon
  609.     empty_reply();
  610.     break;
  611.   case '1':
  612.     if (getch() == CRC_EOP) {
  613.       Serial.print((char) STK_INSYNC);
  614.       Serial.print("AVR ISP");
  615.       Serial.print((char) STK_OK);
  616.     }
  617.     break;
  618.   case 'A':
  619.     get_version(getch());
  620.     break;
  621.   case 'B':
  622.     readbytes(20);
  623.     set_parameters();
  624.     empty_reply();
  625.     break;
  626.   case 'E': // extended parameters - ignore for now
  627.     readbytes(5);
  628.     empty_reply();
  629.     break;
  630.  
  631.   case 'P':
  632.     start_pmode();
  633.     empty_reply();
  634.     break;
  635.   case 'U':
  636.     here = getch() + 256 * getch();
  637.     empty_reply();
  638.     break;
  639.  
  640.   case 0x60: //STK_PROG_FLASH
  641.     low = getch();
  642.     high = getch();
  643.     empty_reply();
  644.     break;
  645.   case 0x61: //STK_PROG_DATA
  646.     data = getch();
  647.     empty_reply();
  648.     break;
  649.  
  650.   case 0x64: //STK_PROG_PAGE
  651.     program_page();
  652.     break;
  653.  
  654.   case 0x74: //STK_READ_PAGE
  655.     read_page();
  656.     break;
  657.  
  658.   case 'V':
  659.     universal();
  660.     break;
  661.   case 'Q':
  662.     error=0;
  663.     end_pmode();
  664.     empty_reply();
  665.     break;
  666.  
  667.   case 0x75: //STK_READ_SIGN
  668.     read_signature();
  669.     break;
  670.  
  671.     // expecting a command, not CRC_EOP
  672.     // this is how we can get back in sync
  673.   case CRC_EOP:
  674.     Serial.print((char) STK_NOSYNC);
  675.     break;
  676.  
  677.     // anything else we will return STK_UNKNOWN
  678.   default:
  679.     if (CRC_EOP == getch())
  680.       Serial.print((char)STK_UNKNOWN);
  681.     else
  682.       Serial.print((char)STK_NOSYNC);
  683.   }
  684. }