stm32sprog.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. #include <limits.h>
  2. #include <stdbool.h>
  3. #include <stdint.h>
  4. #include "tinystdio.h"
  5. #include <string.h>
  6. #include "stm32f4xx_usart.h"
  7. #include "stm32f4xx_crc.h"
  8. #include "stm32sprog.h"
  9. #include "serial.h"
  10. #include "systick.h"
  11. #include "common_config.h"
  12. #undef DBG
  13. #define DBG if(0)
  14. static int cmdIndex(uint8_t cmd);
  15. static bool cmdSupported(Command cmd);
  16. static bool stmRecvAck(void);
  17. static bool stmSendByte(uint8_t byte);
  18. static bool stmSendAddr(uint32_t addr);
  19. static bool stmSendBlock(const uint8_t *buffer, size_t size);
  20. static void printProgressBar(int percent);
  21. static bool stmReadBlock(uint32_t addr, uint8_t *buff, size_t size);
  22. static bool stmRun();
  23. static SerialDev *dev = NULL;
  24. static DeviceParameters devParams;
  25. static uint32_t flash_start = 0;
  26. void usleep(uint32_t us) {
  27. if (us < 1000) us = 1000;
  28. Delay_ms(us / 1000);
  29. }
  30. int stm32sprog_test(void) {
  31. bool ok = false;
  32. stmRebootForFlash();
  33. /* Connect */
  34. ok = stmConnect();
  35. if(!ok) {
  36. printf("STM32 not detected.\n");
  37. return 1;
  38. } else printf("STM32 connected\n");
  39. /* Get params */
  40. ok = stmGetDevParams();
  41. if(!ok) {
  42. printf("Device not supported.\n");
  43. return 2;
  44. }
  45. int major = devParams.bootloaderVer >> 4;
  46. int minor = devParams.bootloaderVer & 0x0F;
  47. printf("Bootloader version %d.%d detected.\n", major, minor);
  48. /* Erase */
  49. printf("Erasing.. ");
  50. ok = stmEraseFlash();
  51. if(ok) printf("OK\n");
  52. else {
  53. printf("Erase error!\n");
  54. return 3;
  55. }
  56. /* Write */
  57. uint8_t buff[MAX_BLOCK_SIZE];
  58. memset(buff, 0xAA, MAX_BLOCK_SIZE);
  59. uint32_t addr = devParams.flashBeginAddr;
  60. printf("Start addr: 0x%X\n", (unsigned int)devParams.flashBeginAddr);
  61. printf("End addr: x%X\n", (unsigned int)devParams.flashEndAddr);
  62. ok = stmWriteBlock(addr, buff, MAX_BLOCK_SIZE);
  63. usleep(devParams.writeDelay);
  64. printf("Writing.. ");
  65. if (ok) printf("Written %d bytes\r\n", MAX_BLOCK_SIZE);
  66. else printf("Write error!\r\n");
  67. printf("Comparing.. ");
  68. uint8_t refbuff[MAX_BLOCK_SIZE];
  69. memset(refbuff, 0xBB, MAX_BLOCK_SIZE);
  70. ok = false;
  71. ok = stmReadBlock(addr, refbuff, MAX_BLOCK_SIZE);
  72. if(ok) ok = (memcmp(buff, refbuff, MAX_BLOCK_SIZE) == 0);
  73. else printf("Read error!\r\n");
  74. if (ok) printf("OK\r\n");
  75. else printf("Compare error!\r\n");
  76. printf("Erasing.. ");
  77. if (stmEraseFlash()) printf("OK\r\n");
  78. else printf("Erase error!\r\n");
  79. if (ok) printf("Test OK\r\n");
  80. else printf("Test failed!\n");
  81. return 0;
  82. }
  83. bool stmConnect(void) {
  84. uint8_t data = 0x7F;
  85. int retries = 0;
  86. do {
  87. usleep(10000);
  88. if(++retries > MAX_CONNECT_RETRIES) return false;
  89. (void)serialWrite(dev, &data, 1);
  90. } while(!stmRecvAck());
  91. return true;
  92. }
  93. static int cmdIndex(uint8_t cmd) {
  94. int idx = -1;
  95. switch(cmd) {
  96. case CMD_GET_VERSION: idx++;
  97. case CMD_GET_READ_STATUS: idx++;
  98. case CMD_GET_ID: idx++;
  99. case CMD_READ_MEM: idx++;
  100. case CMD_GO: idx++;
  101. case CMD_WRITE_MEM: idx++;
  102. case CMD_ERASE: idx++;
  103. case CMD_EXTENDED_ERASE: idx++;
  104. case CMD_WRITE_PROTECT: idx++;
  105. case CMD_WRITE_UNPROTECT: idx++;
  106. case CMD_READ_PROTECT: idx++;
  107. case CMD_READ_UNPROTECT: idx++;
  108. default: break;
  109. }
  110. //assert(idx < NUM_COMMANDS_KNOWN);
  111. return idx;
  112. }
  113. static bool cmdSupported(Command cmd) {
  114. int idx = cmdIndex(cmd);
  115. //assert(idx >= 0);
  116. return devParams.commands[idx];
  117. }
  118. static bool stmRecvAck(void) {
  119. uint8_t data = 0;
  120. if(!serialRead(dev, &data, 1)) return false;
  121. return data == ACK;
  122. }
  123. static bool stmSendByte(uint8_t byte) {
  124. uint8_t buffer[] = { byte, ~byte };
  125. if(!serialWrite(dev, buffer, sizeof(buffer))) return false;
  126. return stmRecvAck();
  127. }
  128. static bool stmSendAddr(uint32_t addr) {
  129. //assert(addr % 4 == 0);
  130. uint8_t buffer[5] = { 0 };
  131. int i;
  132. for(i = 0; i < 4; ++i) {
  133. buffer[i] = (uint8_t)(addr >> ((3 - i) * CHAR_BIT));
  134. buffer[4] ^= buffer[i];
  135. }
  136. if(!serialWrite(dev, buffer, sizeof(buffer))) return false;
  137. return stmRecvAck();
  138. }
  139. static bool stmSendBlock(const uint8_t *buffer, size_t size) {
  140. //assert(size > 0 && size <= MAX_BLOCK_SIZE);
  141. size_t padding = (4 - (size % 4)) % 4;
  142. uint8_t n = size + padding - 1;
  143. uint8_t checksum = n;
  144. size_t i;
  145. for(i = 0; i < size; ++i) checksum ^= buffer[i];
  146. if(!serialWrite(dev, &n, 1)) return false;
  147. if(!serialWrite(dev, buffer, size)) return false;
  148. for(i = 0; i < padding; ++i) {
  149. uint8_t data = 0xFF;
  150. checksum ^= data;
  151. if(!serialWrite(dev, &data, 1)) return false;
  152. }
  153. if(!serialWrite(dev, &checksum, 1)) return false;
  154. return stmRecvAck();
  155. }
  156. bool stmGetDevParams(void) {
  157. uint8_t data = 0;
  158. int i;
  159. if (flash_start) devParams.flashBeginAddr = flash_start;
  160. else devParams.flashBeginAddr = 0x08000000;
  161. devParams.flashEndAddr = 0x08008000;
  162. devParams.flashPagesPerSector = 4;
  163. devParams.flashPageSize = 1024;
  164. devParams.eraseDelay = 40000;
  165. devParams.writeDelay = 80000;
  166. if(!stmSendByte(CMD_GET_VERSION)) return false;
  167. if(!serialRead(dev, &data, 1)) return false;
  168. if(!serialRead(dev, &devParams.bootloaderVer, 1)) return false;
  169. for(i = 0; i < NUM_COMMANDS_KNOWN; ++i) devParams.commands[i] = false;
  170. for(i = data; i > 0; --i) {
  171. if(!serialRead(dev, &data, 1)) return false;
  172. int idx = cmdIndex(data);
  173. if(idx >= 0) devParams.commands[idx] = true;
  174. }
  175. if(!stmRecvAck()) return false;
  176. if(!cmdSupported(CMD_GET_ID)) {
  177. printf("Target device does not support GET_ID command.\n");
  178. return false;
  179. }
  180. if(!stmSendByte(CMD_GET_ID)) return false;
  181. if(!serialRead(dev, &data, 1)) return false;
  182. if(data != 1) return false;
  183. uint16_t id = 0;
  184. for(i = data; i >= 0; --i) {
  185. if(!serialRead(dev, &data, 1)) return false;
  186. if(i < 2) {
  187. id |= data << (i * CHAR_BIT);
  188. }
  189. }
  190. if(!stmRecvAck()) return false;
  191. switch(id) {
  192. case ID_LOW_DENSITY:
  193. devParams.flashEndAddr = 0x08008000;
  194. break;
  195. case ID_MED_DENSITY:
  196. devParams.flashEndAddr = 0x08020000;
  197. break;
  198. case ID_HI_DENSITY:
  199. devParams.flashEndAddr = 0x08080000;
  200. devParams.flashPagesPerSector = 2;
  201. devParams.flashPageSize = 2048;
  202. break;
  203. case ID_CONNECTIVITY:
  204. devParams.flashEndAddr = 0x08040000;
  205. devParams.flashPagesPerSector = 2;
  206. devParams.flashPageSize = 2048;
  207. break;
  208. case ID_VALUE:
  209. devParams.flashEndAddr = 0x08020000;
  210. break;
  211. case ID_HI_DENSITY_VALUE:
  212. devParams.flashEndAddr = 0x08080000;
  213. devParams.flashPagesPerSector = 2;
  214. devParams.flashPageSize = 2048;
  215. break;
  216. case ID_XL_DENSITY:
  217. devParams.flashEndAddr = 0x08100000;
  218. devParams.flashPagesPerSector = 2;
  219. devParams.flashPageSize = 2048;
  220. break;
  221. case ID_MED_DENSITY_ULTRA_LOW_POWER:
  222. devParams.flashEndAddr = 0x08060000;
  223. devParams.flashPagesPerSector = 16;
  224. devParams.flashPageSize = 256;
  225. break;
  226. case ID_HI_DENSITY_ULTRA_LOW_POWER:
  227. devParams.flashEndAddr = 0x08020000;
  228. devParams.flashPagesPerSector = 16;
  229. devParams.flashPageSize = 256;
  230. break;
  231. default:
  232. printf("Device id %d\n not supported", id);
  233. return false;
  234. }
  235. return true;
  236. }
  237. bool stmEraseFlash(void) {
  238. if(cmdSupported(CMD_ERASE)) {
  239. if(!stmSendByte(CMD_ERASE)) return false;
  240. if(!stmSendByte(0xFF)) return false;
  241. } else if(cmdSupported(CMD_EXTENDED_ERASE)) {
  242. /* CMD_EXTENDED_ERASE not tested */
  243. printf("CMD_EXTENDED_ERASE supported\r\n");
  244. int c;
  245. do {
  246. c = 'y';
  247. if(c == 'n' || c == 'N' || c == '\n') {
  248. printf("\n");
  249. return false;
  250. }
  251. } while(c != 'y' && c != 'Y');
  252. printf("\n");
  253. if(!stmSendByte(CMD_EXTENDED_ERASE)) return false;
  254. uint8_t data[] = { 0xFF, 0xFF, 0x00 };
  255. if(!serialWrite(dev, data, sizeof(data))) return false;
  256. if(!stmRecvAck()) return false;
  257. } else {
  258. printf("Target device does not support known erase commands.\n");
  259. return false;
  260. }
  261. /*
  262. int i;
  263. int delay = 60000;
  264. printf("Erasing:\n");
  265. for(i = 1; i <= 100; ++i) {
  266. usleep(delay);
  267. printProgressBar(i);
  268. }
  269. printf("\n");
  270. */
  271. return true;
  272. }
  273. /* Erase only FW flash pages, keep settings page */
  274. bool stmEraseFW(void) {
  275. if(cmdSupported(CMD_ERASE)) {
  276. if(!stmSendByte(CMD_ERASE)) return false;
  277. /* n + 1 pages would be erased */
  278. uint8_t n = DB_CPU_SETTINGS_PAGE - 1;
  279. if(!serialWrite(dev, &n, 1)) return false;
  280. uint8_t checksum = n;
  281. for (uint8_t i = 0; i <= n; i++) {
  282. if(!serialWrite(dev, &i, 1)) return false;
  283. checksum ^= i;
  284. }
  285. if(!serialWrite(dev, &checksum, 1)) return false;
  286. if(!stmRecvAck()) return false;
  287. }
  288. else {
  289. printf("Target device does not support known erase commands.\n");
  290. return false;
  291. }
  292. return true;
  293. }
  294. bool stmWriteBlock(uint32_t addr, const uint8_t *buff, size_t size) {
  295. if(!stmSendByte(CMD_WRITE_MEM)) return false;
  296. if(!stmSendAddr(addr)) return false;
  297. if(!stmSendBlock(buff, size)) return false;
  298. return true;
  299. }
  300. static bool stmReadBlock(uint32_t addr, uint8_t *buff, size_t size) {
  301. if(!stmSendByte(CMD_READ_MEM)) return false;
  302. if(!stmSendAddr(addr)) return false;
  303. if(!stmSendByte(size - 1)) return false;
  304. return serialRead(dev, buff, size);
  305. }
  306. void stmRebootForFlash(void) {
  307. IO_SetDbBoot0();
  308. IO_ClearDbReset();
  309. usleep(60000);
  310. IO_SetDbReset();
  311. usleep(60000);
  312. IO_ClearDbBoot0();
  313. }
  314. void stmReboot(void) {
  315. IO_ClearDbBoot0();
  316. IO_ClearDbReset();
  317. usleep(60000);
  318. IO_SetDbReset();
  319. }
  320. uint32_t stmCalcFlashCrc(void (* periodic_handler)(uint8_t)) {
  321. bool ok = false;
  322. uint8_t buf[4];
  323. uint32_t crc = 0;
  324. uint8_t block[MAX_BLOCK_SIZE];
  325. uint32_t last_block_size, n = 0;
  326. volatile uint32_t* ptr;
  327. static uint32_t last_progress = 0;
  328. CRC_ResetDR();
  329. #if 0
  330. /* Read by 4 bytes blocks. Slow method */
  331. for(uint32_t* ptr = (uint32_t*)DB_CPU_FLASH_FIRST_PAGE_ADDRESS; ptr != (uint32_t*)DB_CPU_FLASH_CRC_ADDRESS; ptr++) {
  332. ok = stmReadBlock((uint32_t)ptr, buf, 4);
  333. if(ok) {
  334. crc = CRC_CalcCRC(*(uint32_t *)buf);
  335. DBG printf("Verify block %u\r\n", n++);
  336. }
  337. else printf("Device read error!\r\n");
  338. }
  339. #endif
  340. /* Read by MAX_BLOCK_SIZE bytes blocks. Fast method */
  341. for (ptr = (uint32_t*)DB_CPU_FLASH_FIRST_PAGE_ADDRESS; ptr < (uint32_t*)DB_CPU_FLASH_CRC_ADDRESS - MAX_BLOCK_SIZE / 4; ptr += MAX_BLOCK_SIZE/4) {
  342. ok = stmReadBlock((uint32_t)ptr, block, MAX_BLOCK_SIZE);
  343. if (ok) {
  344. crc = CRC_CalcBlockCRC((uint32_t *)block, MAX_BLOCK_SIZE / 4);
  345. DBG printf("Verify block %u\r\n", n++);
  346. if (periodic_handler != NULL) {
  347. uint32_t progress = ((uint32_t)ptr - DB_CPU_FLASH_FIRST_PAGE_ADDRESS) * 100 /
  348. (DB_CPU_FLASH_CRC_ADDRESS - MAX_BLOCK_SIZE / 4 - DB_CPU_FLASH_FIRST_PAGE_ADDRESS);
  349. if (progress > last_progress) {
  350. last_progress = progress;
  351. periodic_handler(progress);
  352. }
  353. }
  354. }
  355. else printf("Device read error!\r\n");
  356. }
  357. last_block_size = ((uint32_t*)DB_CPU_FLASH_CRC_ADDRESS - ptr) * 4;
  358. ok = stmReadBlock((uint32_t)ptr, block, last_block_size);
  359. if(ok) {
  360. crc = CRC_CalcBlockCRC((uint32_t *)block, last_block_size / 4);
  361. DBG printf("Verify block %u\r\n", n++);
  362. if (periodic_handler != NULL) {
  363. periodic_handler(100);
  364. }
  365. }
  366. else printf("Device read error!\r\n");
  367. return crc;
  368. }
  369. uint32_t stmReadFlashCrc(void) {
  370. bool ok = false;
  371. uint8_t buf[4];
  372. uint32_t crc = 0x0;
  373. ok = stmReadBlock(DB_CPU_FLASH_CRC_ADDRESS, buf, 4);
  374. if(ok) {
  375. crc = *(uint32_t *)buf;
  376. }
  377. else printf("Read error!\r\n");
  378. printf("Written CRC: 0x%X\r\n", (unsigned int)crc);
  379. return crc;
  380. }
  381. void stmProg( uint32_t* addr, uint8_t * ptr, uint32_t len)
  382. {
  383. uint32_t count, remain = 0, i = 0;
  384. static uint32_t n = 0;
  385. bool ok = false;
  386. /* Reset blocks count */
  387. if (*addr == DB_CPU_FLASH_FIRST_PAGE_ADDRESS) n = 0;
  388. /* write received bytes into flash */
  389. count = len / MAX_BLOCK_SIZE;
  390. /* check if remaining bytes */
  391. remain = len % MAX_BLOCK_SIZE;
  392. for (i = 0; i < count; i++) {
  393. ok = stmWriteBlock(*addr, ptr + (i * MAX_BLOCK_SIZE ), MAX_BLOCK_SIZE);
  394. usleep(8000);
  395. if (ok) {
  396. DBG printf("Block %u (0x%X) %ub\r\n", (unsigned int)n++, *addr, MAX_BLOCK_SIZE);
  397. }
  398. else {
  399. printf("Device write error!\r\n");
  400. return;
  401. }
  402. *addr += MAX_BLOCK_SIZE;
  403. }
  404. if (remain > 0)
  405. {
  406. ok = stmWriteBlock(*addr, ptr + (i * MAX_BLOCK_SIZE ), remain);
  407. if (ok) {
  408. DBG printf("Block %u (0x%X) %ub\r\n", (unsigned int)n++, *addr, (unsigned int)remain);
  409. }
  410. else {
  411. printf("Device write error!\r\n");
  412. return;
  413. }
  414. *addr += remain;
  415. }
  416. }
  417. static bool stmRun() {
  418. if(!stmSendByte(CMD_GO)) return false;
  419. return stmSendAddr(devParams.flashBeginAddr);
  420. }
  421. static void printProgressBar(int percent) {
  422. int num = percent * 70 / 100;
  423. int i = 0;
  424. printf("\r%3d%%[", percent);
  425. for(i = 0; i < 70; ++i) {
  426. printf(i < num ? "=" : " ");
  427. }
  428. printf("]");
  429. }