Guest User

Arduino ISP with boot-time selectable slow SPI support

a guest
Apr 22nd, 2012
1,484
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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. }
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×