main.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. Author: Vinod S
  3. http://blog.vinu.co.in
  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. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #include <avr/io.h>
  16. #define F_CPU 16000000
  17. #include <util/delay.h>
  18. #include "uart.h"
  19. #include "i2c.h"
  20. #include "boot.h"
  21. #include <inttypes.h>
  22. #include <avr/pgmspace.h>
  23. #include "stk500.h"
  24. #include "pin_defs.h"
  25. /////////////////////// definitions /////////////////////////////////////////////////////
  26. #define FUNC_READ 1
  27. #define FUNC_WRITE 1
  28. #define ER 0b10100001
  29. #define EW 0b10100000
  30. #define OPTIBOOT_MAJVER 6
  31. #define OPTIBOOT_MINVER 2
  32. #define LED_START_FLASHES 0
  33. #define GETLENGTH(len) (void) getch() /* skip high byte */; len = getch()
  34. #define save_vect_num (SPM_RDY_vect_num)
  35. #define appstart_vec (save_vect_num*2)
  36. #define WATCHDOG_1S (_BV(WDP2) | _BV(WDP1) | _BV(WDE))
  37. #define WATCHDOG_OFF (0)
  38. #define WATCHDOG_16MS (_BV(WDE))
  39. ////////////////////// global variables ////////////////////////////////////////////////
  40. volatile uint16_t dd = 0;
  41. typedef uint8_t pagelen_t;
  42. uint8_t buff[200];
  43. ///////////////////// function prototypes //////////////////////////////////////////////
  44. static inline void writebuffer(int8_t memtype, uint8_t * mybuff,
  45. uint16_t address, pagelen_t len);
  46. static inline void read_mem(uint8_t memtype, uint16_t address,
  47. pagelen_t length);
  48. void watchdogReset();
  49. void verifySpace();
  50. void watchdogConfig(uint8_t x);
  51. void getNch(uint8_t count);
  52. //////////////////// JUMP to main application function ////////////////////////////////
  53. void app_start(void)
  54. {
  55. watchdogConfig(WATCHDOG_OFF);
  56. __asm__ __volatile__("clr r30\n" "clr r31\n" "ijmp");
  57. }
  58. ///////////////// main function ////////////////////////////////////////////////////////
  59. int main()
  60. {
  61. uint8_t ch;
  62. uint16_t address = 0;
  63. pagelen_t length;
  64. ch = MCUSR;
  65. MCUSR = 0;
  66. watchdogConfig(WATCHDOG_OFF);
  67. if (ch & (_BV(WDRF) | _BV(BORF) | _BV(PORF)))
  68. app_start();
  69. PORTB &= ~(1 << PB5);
  70. DDRB |= 1 << PB5;
  71. //PIN 10 of arduino as ZERO
  72. PORTC &= ~(1 << PC0); //A0
  73. //enable pin10 as output
  74. DDRC |= 1 << PC0; //A0
  75. //PULL UP pin 11 of arduino
  76. PORTC |= 1 << PC1; //A1
  77. //enable pin11 as input.
  78. DDRC &= ~(1 << PC1); //A1
  79. _delay_ms(10);
  80. //check if 10 and 11 is shorted while MCU is reset.
  81. //LED ON
  82. PORTB |= 1 << PB5;
  83. if ((PINC & (1 << PC1)) == 0) { //A1
  84. uint8_t buff2[128];
  85. uint8_t buff1[128];
  86. _delay_ms(1000);
  87. PORTB &= ~(1 << PB5);
  88. if ((PINC & (1 << PC1)) == 0) { //A1
  89. app_start();
  90. }
  91. i2c_init();
  92. watchdogConfig(WATCHDOG_OFF);
  93. uint16_t addr = 0;
  94. for (int i = 0; i < 224; i++) {
  95. while (i2c_start(EW)) ;
  96. i2c_write(addr >> 8);
  97. i2c_write(addr);
  98. i2c_start(ER);
  99. //read one page from i2c eeprom
  100. //read one page from internal flash
  101. for (int j = 0; j < 128; j++) {
  102. buff2[j] = i2c_read_ack();
  103. buff1[j] = pgm_read_byte_near(addr + j);
  104. }
  105. i2c_stop();
  106. i2c_start(EW);
  107. i2c_write(addr >> 8);
  108. i2c_write(addr);
  109. //write the page read from internal flash to i2c eeprom. (Swap write)
  110. for (int j = 0; j < 128; j++) {
  111. i2c_write(buff1[j]);
  112. }
  113. i2c_stop();
  114. //write the page read from external eeprom to internal flash.
  115. writebuffer(0, buff2, addr, 128);
  116. _delay_ms(2);
  117. //increment page address. Here both flash and eeprom are of same page size.
  118. addr += 128;
  119. //toggle LED
  120. PORTB ^= 1 << PB5;
  121. }
  122. // wait while dualboot enable pin is LOW
  123. while ((PINC & (1 << PC1)) == 0) ; //PB3
  124. //forcefull watchdog reset for app start.
  125. watchdogConfig(WATCHDOG_16MS);
  126. while (1) ;
  127. }
  128. uart_init();
  129. watchdogConfig(WATCHDOG_1S);
  130. watchdogReset();
  131. for (;;) {
  132. /* get character from UART */
  133. ch = getch();
  134. if (ch == STK_GET_PARAMETER) {
  135. unsigned char which = getch();
  136. verifySpace();
  137. /*
  138. * Send optiboot version as "SW version"
  139. * Note that the references to memory are optimized away.
  140. */
  141. if (which == STK_SW_MINOR) {
  142. putch((256 * 6 + 2) & 0xFF);
  143. } else if (which == STK_SW_MAJOR) {
  144. putch((256 * 6 + 2) >> 8);
  145. } else {
  146. /*
  147. * GET PARAMETER returns a generic 0x03 reply for
  148. * other parameters - enough to keep Avrdude happy
  149. */
  150. putch(0x03);
  151. }
  152. } else if (ch == STK_SET_DEVICE) {
  153. // SET DEVICE is ignored
  154. getNch(20);
  155. } else if (ch == STK_SET_DEVICE_EXT) {
  156. // SET DEVICE EXT is ignored
  157. getNch(5);
  158. } else if (ch == STK_LOAD_ADDRESS) {
  159. // LOAD ADDRESS
  160. uint16_t newAddress;
  161. newAddress = getch();
  162. newAddress = (newAddress & 0xff) | (getch() << 8);
  163. newAddress += newAddress; // Convert from word address to byte address
  164. address = newAddress;
  165. verifySpace();
  166. } else if (ch == STK_UNIVERSAL) {
  167. // UNIVERSAL command is ignored
  168. getNch(4);
  169. putch(0x00);
  170. }
  171. /* Write memory, length is big endian and is in bytes */
  172. else if (ch == STK_PROG_PAGE) {
  173. // PROGRAM PAGE - we support flash programming only, not EEPROM
  174. uint8_t desttype;
  175. uint8_t *bufPtr;
  176. pagelen_t savelength;
  177. GETLENGTH(length);
  178. savelength = length;
  179. desttype = getch();
  180. // read a page worth of contents
  181. bufPtr = buff;
  182. do
  183. *bufPtr++ = getch();
  184. while (--length);
  185. // Read command terminator, start reply
  186. verifySpace();
  187. writebuffer(desttype, buff, address, savelength);
  188. }
  189. /* Read memory block mode, length is big endian. */
  190. else if (ch == STK_READ_PAGE) {
  191. uint8_t desttype;
  192. GETLENGTH(length);
  193. desttype = getch();
  194. verifySpace();
  195. read_mem(desttype, address, length);
  196. }
  197. /* Get device signature bytes */
  198. else if (ch == STK_READ_SIGN) {
  199. // READ SIGN - return what Avrdude wants to hear
  200. verifySpace();
  201. putch(SIGNATURE_0);
  202. putch(SIGNATURE_1);
  203. putch(SIGNATURE_2);
  204. }
  205. else if (ch == STK_LEAVE_PROGMODE) { /* 'Q' */
  206. // Adaboot no-wait mod
  207. watchdogConfig(WATCHDOG_1S);
  208. verifySpace();
  209. } else {
  210. // This covers the response to commands like STK_ENTER_PROGMODE
  211. verifySpace();
  212. }
  213. putch(STK_OK);
  214. }
  215. }
  216. /*
  217. * void writebuffer(memtype, buffer, address, length)
  218. */
  219. static inline void writebuffer(int8_t memtype, uint8_t * mybuff,
  220. uint16_t address, pagelen_t len)
  221. {
  222. // Copy buffer into programming buffer
  223. uint8_t *bufPtr = mybuff;
  224. uint16_t addrPtr = (uint16_t) (void *)address;
  225. watchdogReset();
  226. /*
  227. * Start the page erase and wait for it to finish. There
  228. * used to be code to do this while receiving the data over
  229. * the serial link, but the performance improvement was slight,
  230. * and we needed the space back.
  231. */
  232. __boot_page_erase_short((uint16_t) (void *)address);
  233. boot_spm_busy_wait();
  234. /*
  235. * Copy data from the buffer into the flash write buffer.
  236. */
  237. do {
  238. uint16_t a;
  239. a = *bufPtr++;
  240. a |= (*bufPtr++) << 8;
  241. __boot_page_fill_short((uint16_t) (void *)addrPtr, a);
  242. addrPtr += 2;
  243. } while (len -= 2);
  244. /*
  245. * Actually Write the buffer to flash (and wait for it to finish.)
  246. */
  247. __boot_page_write_short((uint16_t) (void *)address);
  248. boot_spm_busy_wait();
  249. __boot_rww_enable_alternate();
  250. }
  251. static inline void read_mem(uint8_t memtype, uint16_t address, pagelen_t length)
  252. {
  253. uint8_t cc;
  254. //watchdogReset();
  255. // read a Flash byte and increment the address
  256. do {
  257. __asm__("lpm %0,Z+\n": "=r"(cc), "=z"(address):"1"(address));
  258. putch(cc);
  259. } while (--length);
  260. }
  261. void verifySpace()
  262. {
  263. if (getch() != CRC_EOP) {
  264. watchdogConfig(WATCHDOG_1S); // shorten WD timeout
  265. while (1) // and busy-loop so that WD causes
  266. ; // a reset and app start.
  267. }
  268. putch(STK_INSYNC);
  269. }
  270. void getNch(uint8_t count)
  271. {
  272. do
  273. getch();
  274. while (--count);
  275. verifySpace();
  276. }
  277. void watchdogConfig(uint8_t x)
  278. {
  279. WDTCSR = _BV(WDCE) | _BV(WDE);
  280. WDTCSR = x;
  281. }
  282. // Watchdog functions. These are only safe with interrupts turned off.
  283. void watchdogReset()
  284. {
  285. __asm__ __volatile__("wdr\n");
  286. }