main.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. /*****************************************************************************
  2. * XMODEM BOOTLOADER FOR ARM USING CODE SOURCERY
  3. *****************************************************************************/
  4. #include "board.h" /* Board Support Package */
  5. #include "AT91SAM7S.h"
  6. #include "lib_AT91SAM7S.h"
  7. //{{{ Definition
  8. #define RAMFUNC __attribute__ ((long_call, section (".ramfunc")))
  9. #define AT91C_MC_FSR_MVM ((unsigned int) 0xFF << 8) // (MC) Status Register GPNVMx: General-purpose NVM Bit Status
  10. #define AT91C_MC_FSR_LOCK ((unsigned int) 0xFFFF << 16) // (MC) Status Register LOCKSx: Lock Region x Lock Status
  11. #define ERASE_VALUE 0xFFFFFFFF
  12. typedef void (*funct)(void);
  13. #define UART_RXBUFSIZE 1500
  14. // X/YMODEM header def
  15. #define CRC_TABLE_SIZE (256)
  16. #define CRC16_POLYNOMIAL (0x1021)
  17. #define PACKET_HEADER (3) /* start, block, block-complement */
  18. #define PACKET_TRAILER_CRC (2) /* CRC bytes */
  19. #define PACKET_OVERHEAD_CRC (PACKET_HEADER + PACKET_TRAILER_CRC)
  20. #define PACKET_SIZE (128)
  21. #define PACKET_1K_SIZE (1024)
  22. // X/YMODEM header byte
  23. #define SOH (0x01) /* start of 128-byte data packet */
  24. #define STX (0x02) /* start of 1024-byte data packet */
  25. #define EOT (0x04) /* end of transmission */
  26. #define ACK (0x06) /* receive OK */
  27. #define NAK (0x15) /* receiver error; retry */
  28. #define CAN (0x18) /* two of these in succession aborts transfer */
  29. #define CRC (0x43) /* use in place of first NAK for CRC mode */
  30. #define GRC (0x47) /* use in place of first NAK for -g *///}}}
  31. //{{{ poll_UART
  32. static unsigned char uart_rxbuf[UART_RXBUFSIZE];
  33. static unsigned short rx_index=0,tx_index=0;
  34. __attribute__ ((section (".text.fastcode"))) void poll_UART(void) {
  35. if(((AT91PS_USART)BOOTLOADER_UART_BASE)->US_CSR & AT91C_US_RXRDY) {
  36. uart_rxbuf[tx_index++] = ((AT91PS_USART)BOOTLOADER_UART_BASE)->US_RHR & 0x1FF;
  37. if(tx_index==UART_RXBUFSIZE) tx_index=0;
  38. }
  39. }
  40. //}}}
  41. //{{{ getc_UART
  42. unsigned char getc_UART() {
  43. unsigned char c;
  44. while(rx_index==tx_index) poll_UART();
  45. c = uart_rxbuf[rx_index++];
  46. if(rx_index==UART_RXBUFSIZE) rx_index=0;
  47. return c;
  48. }
  49. //}}}
  50. //{{{ kbhit_UART
  51. int kbhit_UART() {
  52. poll_UART();
  53. return (rx_index!=tx_index);
  54. }
  55. //}}}
  56. //{{{ putc_UART
  57. void putc_UART(unsigned char c) {
  58. while (!AT91F_US_TxReady((AT91PS_USART)BOOTLOADER_UART_BASE));
  59. AT91F_US_PutChar((AT91PS_USART)BOOTLOADER_UART_BASE, c);
  60. }
  61. //}}}
  62. //{{{ puts_UART
  63. void puts_UART(const char *c) {
  64. while((*c)!=0) { putc_UART(*c); c++; }
  65. }
  66. //}}}
  67. //{{{ AT91F_Flash_Ready
  68. //----------------------------------------------------------------------------
  69. // \fn AT91F_Flash_Ready
  70. // \brief Wait the flash ready
  71. //----------------------------------------------------------------------------
  72. __attribute__ ((section (".text.fastcode"))) int AT91F_Flash_Ready (void) {
  73. unsigned int status = 0;
  74. // Wait the end of command
  75. while ((status & AT91C_MC_FRDY) != AT91C_MC_FRDY) {
  76. status = AT91C_BASE_MC->MC_FSR;
  77. poll_UART();
  78. }
  79. return status;
  80. }
  81. //}}}
  82. //{{{ AT91F_Flash_Write
  83. //----------------------------------------------------------------------------
  84. // \fn AT91F_Flash_Write
  85. // \brief Write in one Flash page located in AT91C_IFLASH, size in 32 bits
  86. // \input Flash_Address: start at 0x0010 0000 size: in byte
  87. //----------------------------------------------------------------------------
  88. __attribute__ ((section (".text.fastcode"))) int AT91F_Flash_Write(unsigned int page,unsigned int *buff) {
  89. if(page>=AT91C_IFLASH_NB_OF_PAGES) return false;
  90. // set the Flash controller base address
  91. AT91PS_MC ptMC = AT91C_BASE_MC;
  92. unsigned int i, status;
  93. unsigned int * Flash;
  94. // init flash pointer
  95. Flash = (unsigned int *)AT91C_IFLASH + (page * AT91C_IFLASH_PAGE_SIZE);
  96. // copy the new value
  97. for (i=0; i<AT91C_IFLASH_PAGE_SIZE; i+=4, Flash++, buff++) { *Flash=*buff; poll_UART(); }
  98. // Write the write page command
  99. ptMC->MC_FCR = AT91C_MC_CORRECT_KEY | AT91C_MC_FCMD_START_PROG | (AT91C_MC_PAGEN & (page <<8)) ;
  100. // Wait the end of command
  101. status = AT91F_Flash_Ready();
  102. // Check the result
  103. if ( (status & ( AT91C_MC_PROGE | AT91C_MC_LOCKE ))!=0) return false;
  104. return true;
  105. }
  106. //}}}
  107. //{{{ crc16_init
  108. static unsigned short crc16_table[CRC_TABLE_SIZE * sizeof(unsigned short)];
  109. /* Generate the table of constants used in executing the CRC32 algorithm: */
  110. void crc16_init(void) {
  111. int i, j;
  112. unsigned short crc;
  113. for(i = 0; i < CRC_TABLE_SIZE; ++i) {
  114. crc = i << 8;
  115. for(j = 8; j > 0; --j) {
  116. if(crc & 0x8000)
  117. crc = (crc << 1) ^ CRC16_POLYNOMIAL;
  118. else
  119. crc <<= 1;
  120. }
  121. crc16_table[i] = crc;
  122. }
  123. }
  124. //}}}
  125. //{{{ crc_16_buf
  126. /* Perform a CRC16 computation over `buf'. This method was derived from
  127. * an algorithm (C) 1986 by Gary S. Brown, and was checked against an
  128. * implementation (C) 2000 by Compaq Computer Corporation, authored by
  129. * George France.
  130. */
  131. unsigned short crc16_buf(unsigned char *buf, unsigned int length) {
  132. unsigned short crc = 0;
  133. while(length-- > 0) crc = crc16_table[(crc >> 8) & 0xff] ^ (crc << 8) ^ *buf++;
  134. return crc;
  135. }
  136. //}}}
  137. //{{{ wait - delay loop
  138. //--------------------------------------------------------------------------------------
  139. // Function Name : wait
  140. // Object : Software waiting loop
  141. // Input Parameters : none. Waiting time is defined by the global variable LedSpeed.
  142. // Output Parameters : none
  143. //--------------------------------------------------------------------------------------
  144. void wait(unsigned long time) {
  145. unsigned int waiting_time;
  146. for(waiting_time = 0; waiting_time < time; waiting_time++) if (kbhit_UART()) return;
  147. }
  148. //}}}
  149. //{{{ error
  150. void error(unsigned char code) {
  151. while(1) {
  152. putc_UART(CAN);
  153. switch(code) {
  154. case 0: puts_UART("Error writing last page\r\n"); break;
  155. case 1: puts_UART("CAN received\r\n"); break;
  156. case 2: puts_UART("Error writting flash page\r\n"); break;
  157. }
  158. while(kbhit_UART()) getc_UART();
  159. wait(500000*3);
  160. }
  161. }
  162. //}}}
  163. //{{{ main
  164. static unsigned char xmodem_buf[PACKET_1K_SIZE+PACKET_OVERHEAD_CRC];
  165. static unsigned int page_buffer[AT91C_IFLASH_PAGE_SIZE/4];
  166. int main (void) {
  167. int i,p;
  168. unsigned char c=0,ymodem;
  169. unsigned int page_index,page;
  170. int index,pkt_count,waitloop; // Buffer pointer
  171. unsigned char xmodem_pktid; // Next packet ID to receive (begin with 1)
  172. AT91PS_PMC pPMC;
  173. /* BOARD INIT (SWITCH CLOCK TO 48 MHZ) */
  174. //{{{ Start main clock oscillator at 18.432 MHz
  175. /* Enable the Main Oscillator:
  176. * set OSCOUNT to 6, which gives Start up time = 8 * 6 / SCK = 1.4ms
  177. * (SCK = 32768Hz)
  178. */
  179. pPMC = AT91C_BASE_PMC;
  180. pPMC->PMC_MOR = ((6 << 8) & AT91C_CKGR_OSCOUNT) | AT91C_CKGR_MOSCEN;
  181. while ((pPMC->PMC_SR & AT91C_PMC_MOSCS) == 0); /* Wait the startup time */
  182. //}}}
  183. //{{{ Select 1 wait state for flash
  184. /* Set flash wait sate FWS and FMCN at 72(1.5uS) for 48Mhz operation */
  185. AT91C_BASE_MC->MC_FMR = (72 << 16) | AT91C_MC_FWS_1FWS;
  186. //}}}
  187. //{{{ Configure PLL for 48Mhz operation
  188. /* Set the PLL and Divider:
  189. * - div by 5 Fin = 3,6864 =(18,432 / 5)
  190. * - Mul 25+1: Fout = 95,8464 =(3,6864 *26)
  191. * for 96 MHz the error is 0.16%
  192. * Field out NOT USED = 0
  193. * PLLCOUNT pll startup time estimate at : 0.844 ms
  194. * PLLCOUNT 28 = 0.000844 /(1/32768)
  195. */
  196. pPMC->PMC_PLLR = ((AT91C_CKGR_DIV & 0x05)
  197. | (AT91C_CKGR_PLLCOUNT & (28 << 8))
  198. | (AT91C_CKGR_MUL & (25 << 16)));
  199. while ((pPMC->PMC_SR & AT91C_PMC_LOCK) == 0);
  200. /* Wait the startup time */
  201. while ((pPMC->PMC_SR & AT91C_PMC_MCKRDY) == 0);
  202. //}}}
  203. //{{{ Switch ARM core clock and master clock to PLL
  204. /* Select Master Clock and CPU Clock select the PLL clock / 2 */
  205. pPMC->PMC_MCKR = AT91C_PMC_PRES_CLK_2; while ((pPMC->PMC_SR & AT91C_PMC_MCKRDY) == 0);
  206. pPMC->PMC_MCKR |= AT91C_PMC_CSS_PLL_CLK; while ((pPMC->PMC_SR & AT91C_PMC_MCKRDY) == 0);
  207. //}}}
  208. /* INITIALIZE SERIAL PORT */
  209. //{{{ Configure UART
  210. #if BOOTLOADER_UART == 0
  211. AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC,((unsigned int) 1 << AT91C_ID_US0));
  212. AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, ((unsigned int) AT91C_PA5_RXD0)|((unsigned int) AT91C_PA6_TXD0), 0);
  213. #endif
  214. #if BOOTLOADER_UART == 1
  215. AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC,((unsigned int) 1 << AT91C_ID_US1));
  216. AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA,((unsigned int) AT91C_PA22_TXD1)|((unsigned int) AT91C_PA21_RXD1),0);
  217. #endif
  218. #if BOOTLOADER_UART == 2
  219. AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA,((unsigned int) AT91C_PA9_DRXD)|((unsigned int) AT91C_PA10_DTXD), 0);
  220. #endif
  221. // Configure UART
  222. //-------------------
  223. AT91F_US_Configure (
  224. (AT91PS_USART) BOOTLOADER_UART_BASE, // UART base address
  225. BOARD_MCK,
  226. AT91C_US_ASYNC_MODE , // Mode Register to be programmed
  227. BOOTLOADER_BAUDRATE, // Baudrate to be programmed
  228. 0); // Timeguard to be programmed
  229. // Enable Transmitter & receiver
  230. //-----------------------------------
  231. ((AT91PS_USART)BOOTLOADER_UART_BASE)->US_CR = AT91C_US_RXEN | AT91C_US_TXEN;
  232. //}}}
  233. /* Check for bootloader key */
  234. wait(200000);
  235. puts_UART("\r\nXLoader 7.0");
  236. wait(500000*3);
  237. if (kbhit_UART()) c = getc_UART();
  238. if(c != '\r') {
  239. puts_UART(" - run");
  240. goto StartCode;
  241. } else {
  242. puts_UART(" - x/ymodem 1k/CRC\r\n");
  243. }
  244. /* Init xmodem variable */
  245. index = 0;
  246. xmodem_pktid = 1;
  247. pkt_count = 0; // Only use is to detect ymodem header packet ID=0
  248. ymodem = 0; // Set to 1 if detect YMODEM transfer
  249. page = (CODE_START-(unsigned int)AT91C_IFLASH) / AT91C_IFLASH_PAGE_SIZE;
  250. page_index = 0;
  251. crc16_init();
  252. /* HANDSHACKING FOR XMODEM CRC/1K OR YMODEM */
  253. while(1) {
  254. // Search for SOH or STX start flag
  255. if (kbhit_UART()) {
  256. c = getc_UART();
  257. if(c==SOH || c==STX) break;
  258. }
  259. // Send CRC
  260. putc_UART(CRC);
  261. // Wait loop
  262. wait(240000*3);
  263. AT91F_WDTRestart(AT91C_BASE_WDTC);
  264. }
  265. /* STORE FIRST PACKET TYPE */
  266. xmodem_buf[index++] = c;
  267. /* MAIN LOOP X/YMODEM PROTOCOL */
  268. while(1) {
  269. /* GET CARACTER FROM SERIAL PORT */
  270. AT91F_WDTRestart(AT91C_BASE_WDTC);
  271. waitloop=0;
  272. while(kbhit_UART()==0) {
  273. waitloop++;
  274. if(waitloop==500000) { waitloop=0; putc_UART(NAK); } // Timeout
  275. }
  276. c = getc_UART();
  277. /* FIRST CARACTER: CHECK PACKET TYPE */
  278. if(index==0) {
  279. if(c==EOT) { // End of transfer
  280. /* DO NOT FLUSH FLASH BUFFER ON 2ND YMODEM SEQUENCE */
  281. if(ymodem<2 && page_index!=0) {
  282. if(AT91F_Flash_Write(page, page_buffer)==0) error(0);
  283. }
  284. if(ymodem) {
  285. if(ymodem==1) {
  286. putc_UART(NAK); // 1st YMODEM end sequence
  287. ymodem++;
  288. } else {
  289. putc_UART(ACK); // 2nd YMODEM end sequence (reset receiver for next batch)
  290. putc_UART(CRC);
  291. xmodem_pktid = 1;
  292. pkt_count = 0;
  293. }
  294. } else {
  295. putc_UART(ACK); // XMODEM end sequence
  296. break;
  297. }
  298. }
  299. if(c==CAN) error(1); // Cancel send
  300. if(c==SOH || c==STX) xmodem_buf[index++] = c; // Start new data packet
  301. /* RECEIVE PACKET, CHECK FOR END OF BLOCK */
  302. } else {
  303. xmodem_buf[index++] = c;
  304. if((xmodem_buf[0]==SOH && index==(PACKET_SIZE+PACKET_OVERHEAD_CRC)) ||
  305. (xmodem_buf[0]==STX && index==(PACKET_1K_SIZE+PACKET_OVERHEAD_CRC)) ) {
  306. // Detect YMODEM transfer, end batch if filename is NULL
  307. if(xmodem_buf[1]==0 && pkt_count==0) {
  308. ymodem=1;
  309. index=0;
  310. putc_UART(ACK);
  311. if(xmodem_buf[3]!=0) {
  312. putc_UART(CRC); // Start new YMODEM transfer
  313. continue;
  314. } else {
  315. break; // Pathname is NULL, end batch transfer
  316. }
  317. }
  318. pkt_count++;
  319. // Verify CRC and packet ID
  320. if(xmodem_buf[1]!=xmodem_pktid) { putc_UART(NAK); continue; }
  321. if(crc16_buf(xmodem_buf + PACKET_HEADER, (xmodem_buf[0]==SOH?PACKET_SIZE:PACKET_1K_SIZE) + PACKET_TRAILER_CRC) != 0) { putc_UART(NAK); continue; }
  322. // ack packet before write to FLASH (UART buffer fill when wait for flash)
  323. putc_UART(ACK);
  324. // Transfer packet in flash page buffer
  325. p = 3;
  326. i=(xmodem_buf[0]==SOH?PACKET_SIZE:PACKET_1K_SIZE);
  327. while(i--) {
  328. poll_UART();
  329. ((unsigned char*)page_buffer)[page_index++] = xmodem_buf[p++];
  330. // Write flash if page is full
  331. if(page_index==AT91C_IFLASH_PAGE_SIZE) {
  332. if(AT91F_Flash_Write(page,page_buffer)==0) error(2);
  333. page_index=0;
  334. page++;
  335. }
  336. }
  337. xmodem_pktid++;
  338. index=0;
  339. }
  340. }
  341. }
  342. puts_UART("complete\r\n ");
  343. StartCode:
  344. AT91F_PMC_DisablePeriphClock (AT91C_BASE_PMC, 0xFFFFFFFF ); // All peripheral clocks de-activated.
  345. AT91F_PMC_CfgMCKReg (AT91C_BASE_PMC,AT91C_PMC_CSS_SLOW_CLK | AT91C_PMC_PRES_CLK); // Slow Clock
  346. while(!(AT91F_PMC_GetStatus(AT91C_BASE_PMC) & AT91C_PMC_MCKRDY));
  347. AT91F_CKGR_CfgPLLReg(AT91C_BASE_CKGR,0); // Shutdown PLL
  348. AT91F_CKGR_DisableMainOscillator(AT91C_BASE_CKGR); // Disable Main Oscillator
  349. ((funct)(CODE_START-(unsigned int)AT91C_IFLASH))();
  350. return 0;
  351. }
  352. //}}}