Pastebin launched a little side project called HostCabi.net, check it out ;-)Don't like ads? PRO users don't see any ads ;-)
Guest

Arduino ISP with boot-time selectable slow SPI support

By: a guest on Apr 22nd, 2012  |  syntax: C++  |  size: 13.40 KB  |  hits: 310  |  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. #define LED_HB 6
  42. #define LED_ERR 8
  43. #define LED_PMODE 5
  44. #define LED_COMMON 7
  45.  
  46. #define MODE_BUTTON 9
  47.  
  48. // These set the correct timing delays for programming a target with clk < 500KHz.
  49. // Be sure to specify the lowest clock frequency of any target you plan to burn.
  50. // The rule is the programing clock (on SCK) must be less than 1/4 the clock
  51. // speed of the target (or 1/6 for speeds above 12MHz).  For example, if using
  52. // the 128KHz RC oscillator, with a prescaler of 8, the target's clock frequency
  53. // would be 16KHz, and the maximum programming clock would be 4KHz, or a clock
  54. // period of 250uS.  The algorithm uses a quarter of the clock period for sync
  55. // purposes, so QUARTER_PERIOD would be set to 63uS.  Be aware that internal RC
  56. // oscillators can be off by as much as 10%, so you might have to force a slower
  57. // clock speed.
  58. #define MINIMUM_TARGET_CLOCK_SPEED 128000
  59. #define SCK_FREQUENCY (MINIMUM_TARGET_CLOCK_SPEED/4)
  60. #define QUARTER_PERIOD ((1000000/SCK_FREQUENCY/4)+1)
  61.  
  62. #define HWVER 2
  63. #define SWMAJ 1
  64. #define SWMIN 18
  65.  
  66. // As per http://arduino.cc/en/Tutorial/ArduinoISP
  67. #if ARDUINO >= 100
  68.   #define HB_DELAY 20
  69. #else
  70.   #define HB_DELAY 40
  71. #endif
  72.  
  73. #define RESET SS
  74.  
  75. // STK Definitions
  76. #define STK_OK 0x10
  77. #define STK_FAILED 0x11
  78. #define STK_UNKNOWN 0x12
  79. #define STK_INSYNC 0x14
  80. #define STK_NOSYNC 0x15
  81. #define CRC_EOP 0x20 //ok it is a space...
  82.  
  83. #define PTIME 30
  84.  
  85. uint8_t hbval=128;
  86. int8_t hbdelta;
  87.  
  88. // this provides a heartbeat on pin 9, so you can tell the software is running.
  89. void heartbeat() {
  90.   if ((hbval > 192) || (hbval < 32))
  91.     hbdelta = -hbdelta;
  92.   hbval += hbdelta;
  93.   analogWrite(LED_HB, hbval);
  94.   delay(HB_DELAY);
  95. }
  96.  
  97. void pulse(int pin, int times) {
  98.   do {
  99.     digitalWrite(pin, HIGH);
  100.     delay(PTIME);
  101.     digitalWrite(pin, LOW);
  102.     delay(PTIME);
  103.   } while (times--);
  104. }
  105.  
  106. void (*spi_init)();
  107. uint8_t (*spi_send)(uint8_t);
  108.  
  109. void setup() {
  110.   Serial.begin(19200);
  111.   pinMode(MODE_BUTTON, INPUT);
  112.   digitalWrite(MODE_BUTTON, HIGH);
  113.   pinMode(LED_PMODE, OUTPUT);
  114.   pinMode(LED_ERR, OUTPUT);
  115.   pinMode(LED_HB, OUTPUT);
  116.   pinMode(LED_COMMON, OUTPUT);
  117.   digitalWrite(LED_COMMON, LOW);
  118.   pulse(LED_PMODE, 2);
  119.   pulse(LED_ERR, 2);
  120.   pulse(LED_HB, 2);
  121.   pinMode(MODE_BUTTON, INPUT);
  122.   digitalWrite(MODE_BUTTON, HIGH);
  123.   if (digitalRead(MODE_BUTTON)){
  124.     spi_init = hw_spi_init;
  125.     spi_send = hw_spi_send;
  126.     hbdelta = 12;
  127.   }
  128.   else {
  129.     spi_init = sw_spi_init;
  130.     spi_send = sw_spi_send;
  131.     hbdelta = 6;
  132.   }
  133. }
  134.  
  135. int error=0;
  136. int pmode=0;
  137. // address for reading and writing, set by 'U' command
  138. int here;
  139. uint8_t buff[256]; // global block storage
  140.  
  141. #define beget16(addr) (*addr * 256 + *(addr+1) )
  142.  
  143. typedef struct param {
  144.   uint8_t devicecode;
  145.   uint8_t revision;
  146.   uint8_t progtype;
  147.   uint8_t parmode;
  148.   uint8_t polling;
  149.   uint8_t selftimed;
  150.   uint8_t lockbytes;
  151.   uint8_t fusebytes;
  152.   int flashpoll;
  153.   int eeprompoll;
  154.   int pagesize;
  155.   int eepromsize;
  156.   int flashsize;
  157. }
  158. parameter;
  159.  
  160. parameter param;
  161.  
  162. void loop(void) {
  163.   // is pmode active?
  164.   if (pmode) digitalWrite(LED_PMODE, HIGH);
  165.   else digitalWrite(LED_PMODE, LOW);
  166.   // is there an error?
  167.   if (error) digitalWrite(LED_ERR, HIGH);
  168.   else digitalWrite(LED_ERR, LOW);
  169.  
  170.   // light the heartbeat LED
  171.   heartbeat();
  172.   if (Serial.available()) {
  173.     avrisp();
  174.   }
  175. }
  176.  
  177. uint8_t getch() {
  178.   while(!Serial.available());
  179.   return Serial.read();
  180. }
  181. void readbytes(int n) {
  182.   for (int x = 0; x < n; x++) {
  183.     buff[x] = Serial.read();
  184.   }
  185. }
  186.  
  187. void hw_spi_init() {
  188.   uint8_t x;
  189.   SPCR = 0x53;
  190.   x=SPSR;
  191.   x=SPDR;
  192. }
  193.  
  194. void sw_spi_init() {
  195. }
  196.  
  197. void spi_wait() {
  198.   do {
  199.   } while (!(SPSR & (1 << SPIF)));
  200. }
  201.  
  202. uint8_t hw_spi_send(uint8_t b) {
  203.   uint8_t reply;
  204.   SPDR=b;
  205.   spi_wait();
  206.   reply = SPDR;
  207.   return reply;
  208. }
  209.  
  210. #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])
  211. uint8_t sw_spi_send(uint8_t b) {
  212.   unsigned static char msk[] = { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 };
  213.   uint8_t reply;
  214.   char bits[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  215.   for(uint8_t _bit = 0;_bit < 8;_bit++){
  216.     digitalWrite(MOSI, !!(b & msk[_bit]));
  217.     delayMicroseconds(QUARTER_PERIOD);
  218.     digitalWrite(SCK, HIGH);
  219.     delayMicroseconds(QUARTER_PERIOD);
  220.     bits[_bit] = digitalRead(MISO);
  221.     delayMicroseconds(QUARTER_PERIOD);
  222.     digitalWrite(SCK, LOW);
  223.     delayMicroseconds(QUARTER_PERIOD);
  224.   }
  225.   reply = PCK();
  226.   return reply;
  227. }
  228.  
  229. uint8_t spi_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
  230.   uint8_t n;
  231.   spi_send(a);
  232.   n=spi_send(b);
  233.   //if (n != a) error = -1;
  234.   n=spi_send(c);
  235.   return spi_send(d);
  236. }
  237.  
  238. void empty_reply() {
  239.   if (CRC_EOP == getch()) {
  240.     Serial.print((char)STK_INSYNC);
  241.     Serial.print((char)STK_OK);
  242.   }
  243.   else {
  244.     Serial.print((char)STK_NOSYNC);
  245.   }
  246. }
  247.  
  248. void breply(uint8_t b) {
  249.   if (CRC_EOP == getch()) {
  250.     Serial.print((char)STK_INSYNC);
  251.     Serial.print((char)b);
  252.     Serial.print((char)STK_OK);
  253.   }
  254.   else {
  255.     Serial.print((char)STK_NOSYNC);
  256.   }
  257. }
  258.  
  259. void get_version(uint8_t c) {
  260.   switch(c) {
  261.   case 0x80:
  262.     breply(HWVER);
  263.     break;
  264.   case 0x81:
  265.     breply(SWMAJ);
  266.     break;
  267.   case 0x82:
  268.     breply(SWMIN);
  269.     break;
  270.   case 0x93:
  271.     breply('S'); // serial programmer
  272.     break;
  273.   default:
  274.     breply(0);
  275.   }
  276. }
  277.  
  278. void set_parameters() {
  279.   // call this after reading paramter packet into buff[]
  280.   param.devicecode = buff[0];
  281.   param.revision = buff[1];
  282.   param.progtype = buff[2];
  283.   param.parmode = buff[3];
  284.   param.polling = buff[4];
  285.   param.selftimed = buff[5];
  286.   param.lockbytes = buff[6];
  287.   param.fusebytes = buff[7];
  288.   param.flashpoll = buff[8];
  289.   // ignore buff[9] (= buff[8])
  290.   //getch(); // discard second value
  291.  
  292.   // WARNING: not sure about the byte order of the following
  293.   // following are 16 bits (big endian)
  294.   param.eeprompoll = beget16(&buff[10]);
  295.   param.pagesize = beget16(&buff[12]);
  296.   param.eepromsize = beget16(&buff[14]);
  297.  
  298.   // 32 bits flashsize (big endian)
  299.   param.flashsize = buff[16] * 0x01000000
  300.     + buff[17] * 0x00010000
  301.     + buff[18] * 0x00000100
  302.     + buff[19];
  303.  
  304. }
  305.  
  306. void start_pmode() {
  307.   spi_init();
  308.   // following delays may not work on all targets...
  309.   pinMode(RESET, OUTPUT);
  310.   digitalWrite(RESET, HIGH);
  311.   pinMode(SCK, OUTPUT);
  312.   digitalWrite(SCK, LOW);
  313.   delay(50);
  314.   digitalWrite(RESET, LOW);
  315.   delay(50);
  316.   pinMode(MISO, INPUT);
  317.   pinMode(MOSI, OUTPUT);
  318.   spi_transaction(0xAC, 0x53, 0x00, 0x00);
  319.   pmode = 1;
  320. }
  321.  
  322. void end_pmode() {
  323.   pinMode(MISO, INPUT);
  324.   pinMode(MOSI, INPUT);
  325.   pinMode(SCK, INPUT);
  326.   pinMode(RESET, INPUT);
  327.   pmode = 0;
  328. }
  329.  
  330. void universal() {
  331.   int w;
  332.   uint8_t ch;
  333.  
  334.   for (w = 0; w < 4; w++) {
  335.     buff[w] = getch();
  336.   }
  337.   ch = spi_transaction(buff[0], buff[1], buff[2], buff[3]);
  338.   breply(ch);
  339. }
  340.  
  341. void flash(uint8_t hilo, int addr, uint8_t data) {
  342.   spi_transaction(0x40+8*hilo,
  343.   addr>>8 & 0xFF,
  344.   addr & 0xFF,
  345.   data);
  346. }
  347. void commit(int addr) {
  348.   spi_transaction(0x4C, (addr >> 8) & 0xFF, addr & 0xFF, 0);
  349. }
  350.  
  351. //#define _current_page(x) (here & 0xFFFFE0)
  352. int current_page(int addr) {
  353.   if (param.pagesize == 32) return here & 0xFFFFFFF0;
  354.   if (param.pagesize == 64) return here & 0xFFFFFFE0;
  355.   if (param.pagesize == 128) return here & 0xFFFFFFC0;
  356.   if (param.pagesize == 256) return here & 0xFFFFFF80;
  357.   return here;
  358. }
  359. uint8_t write_flash(int length) {
  360.   if (param.pagesize < 1) return STK_FAILED;
  361.   //if (param.pagesize != 64) return STK_FAILED;
  362.   int page = current_page(here);
  363.   int x = 0;
  364.   while (x < length) {
  365.     if (page != current_page(here)) {
  366.       commit(page);
  367.       page = current_page(here);
  368.     }
  369.     flash(LOW, here, buff[x++]);
  370.     flash(HIGH, here, buff[x++]);
  371.     here++;
  372.   }
  373.  
  374.   commit(page);
  375.  
  376.   return STK_OK;
  377. }
  378.  
  379. uint8_t write_eeprom(int length) {
  380.   // here is a word address, so we use here*2
  381.   // this writes byte-by-byte,
  382.   // page writing may be faster (4 bytes at a time)
  383.   for (int x = 0; x < length; x++) {
  384.     spi_transaction(0xC0, 0x00, here*2+x, buff[x]);
  385.     delay(45);
  386.   }
  387.   return STK_OK;
  388. }
  389.  
  390. void program_page() {
  391.   char result = (char) STK_FAILED;
  392.   int length = 256 * getch() + getch();
  393.   if (length > 256) {
  394.     Serial.print((char) STK_FAILED);
  395.     return;
  396.   }
  397.   char memtype = getch();
  398.   for (int x = 0; x < length; x++) {
  399.     buff[x] = getch();
  400.   }
  401.   if (CRC_EOP == getch()) {
  402.     Serial.print((char) STK_INSYNC);
  403.     if (memtype == 'F') result = (char)write_flash(length);
  404.     if (memtype == 'E') result = (char)write_eeprom(length);
  405.     Serial.print(result);
  406.   }
  407.   else {
  408.     Serial.print((char) STK_NOSYNC);
  409.   }
  410. }
  411. uint8_t flash_read(uint8_t hilo, int addr) {
  412.   return spi_transaction(0x20 + hilo * 8,
  413.   (addr >> 8) & 0xFF,
  414.   addr & 0xFF,
  415.   0);
  416. }
  417.  
  418. char flash_read_page(int length) {
  419.   for (int x = 0; x < length; x+=2) {
  420.     uint8_t low = flash_read(LOW, here);
  421.     Serial.print((char) low);
  422.     uint8_t high = flash_read(HIGH, here);
  423.     Serial.print((char) high);
  424.     here++;
  425.   }
  426.   return STK_OK;
  427. }
  428.  
  429. char eeprom_read_page(int length) {
  430.   // here again we have a word address
  431.   for (int x = 0; x < length; x++) {
  432.     uint8_t ee = spi_transaction(0xA0, 0x00, here*2+x, 0xFF);
  433.     Serial.print((char) ee);
  434.   }
  435.   return STK_OK;
  436. }
  437.  
  438. void read_page() {
  439.   char result = (char)STK_FAILED;
  440.   int length = 256 * getch() + getch();
  441.   char memtype = getch();
  442.   if (CRC_EOP != getch()) {
  443.     Serial.print((char) STK_NOSYNC);
  444.     return;
  445.   }
  446.   Serial.print((char) STK_INSYNC);
  447.   if (memtype == 'F') result = flash_read_page(length);
  448.   if (memtype == 'E') result = eeprom_read_page(length);
  449.   Serial.print(result);
  450.   return;
  451. }
  452.  
  453. void read_signature() {
  454.   if (CRC_EOP != getch()) {
  455.     Serial.print((char) STK_NOSYNC);
  456.     return;
  457.   }
  458.   Serial.print((char) STK_INSYNC);
  459.   uint8_t high = spi_transaction(0x30, 0x00, 0x00, 0x00);
  460.   Serial.print((char) high);
  461.   uint8_t middle = spi_transaction(0x30, 0x00, 0x01, 0x00);
  462.   Serial.print((char) middle);
  463.   uint8_t low = spi_transaction(0x30, 0x00, 0x02, 0x00);
  464.   Serial.print((char) low);
  465.   Serial.print((char) STK_OK);
  466. }
  467. //////////////////////////////////////////
  468. //////////////////////////////////////////
  469.  
  470.  
  471. ////////////////////////////////////
  472. ////////////////////////////////////
  473. int avrisp() {
  474.   uint8_t data, low, high;
  475.   uint8_t ch = getch();
  476.   switch (ch) {
  477.   case '0': // signon
  478.     empty_reply();
  479.     break;
  480.   case '1':
  481.     if (getch() == CRC_EOP) {
  482.       Serial.print((char) STK_INSYNC);
  483.       Serial.print("AVR ISP");
  484.       Serial.print((char) STK_OK);
  485.     }
  486.     break;
  487.   case 'A':
  488.     get_version(getch());
  489.     break;
  490.   case 'B':
  491.     readbytes(20);
  492.     set_parameters();
  493.     empty_reply();
  494.     break;
  495.   case 'E': // extended parameters - ignore for now
  496.     readbytes(5);
  497.     empty_reply();
  498.     break;
  499.  
  500.   case 'P':
  501.     start_pmode();
  502.     empty_reply();
  503.     break;
  504.   case 'U':
  505.     here = getch() + 256 * getch();
  506.     empty_reply();
  507.     break;
  508.  
  509.   case 0x60: //STK_PROG_FLASH
  510.     low = getch();
  511.     high = getch();
  512.     empty_reply();
  513.     break;
  514.   case 0x61: //STK_PROG_DATA
  515.     data = getch();
  516.     empty_reply();
  517.     break;
  518.  
  519.   case 0x64: //STK_PROG_PAGE
  520.     program_page();
  521.     break;
  522.  
  523.   case 0x74: //STK_READ_PAGE
  524.     read_page();
  525.     break;
  526.  
  527.   case 'V':
  528.     universal();
  529.     break;
  530.   case 'Q':
  531.     error=0;
  532.     end_pmode();
  533.     empty_reply();
  534.     break;
  535.  
  536.   case 0x75: //STK_READ_SIGN
  537.     read_signature();
  538.     break;
  539.  
  540.     // expecting a command, not CRC_EOP
  541.     // this is how we can get back in sync
  542.   case CRC_EOP:
  543.     Serial.print((char) STK_NOSYNC);
  544.     break;
  545.  
  546.     // anything else we will return STK_UNKNOWN
  547.   default:
  548.     if (CRC_EOP == getch())
  549.       Serial.print((char)STK_UNKNOWN);
  550.     else
  551.       Serial.print((char)STK_NOSYNC);
  552.   }
  553. }