st_flash.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. #include "st_sys.h"
  2. #include "st_flash.h"
  3. #include "hardware_delay.h"
  4. typedef struct
  5. {
  6. uint32_t addr;
  7. uint32_t size;
  8. }
  9. st_flash_page_info;
  10. /**
  11. * FLASH页分块表
  12. *
  13. * @author lxz (121319 18:16:08)
  14. */
  15. static const st_flash_page_info page_infos[] = {
  16. { ST_FLASH_SECTOR_0, 24 * 1024},
  17. { ST_FLASH_SECTOR_2, 16 * 1024},
  18. { ST_FLASH_SECTOR_3, 4 * 1024},
  19. { ST_FLASH_SECTOR_5, 212 * 1024 }
  20. };
  21. /**
  22. * flash 操作解锁
  23. *
  24. * @author lxz (2019/5/30/鍛ㄥ洓)
  25. *
  26. * @param void
  27. */
  28. void st_flash_unlock(void) {
  29. if (FLASH->CR & (1 << 7)) {
  30. FLASH->KEYR = FLASH_KEY1;
  31. FLASH->KEYR = FLASH_KEY2;
  32. }
  33. //清除错误标志位
  34. FLASH->SR = FLASH_SR_PGERR |FLASH_SR_WRPRTERR;
  35. }
  36. /**
  37. * flash操作 上锁
  38. *
  39. * @author lxz (2019/5/30/鍛ㄥ洓)
  40. *
  41. * @param void
  42. */
  43. void st_flash_lock(void) {
  44. FLASH->CR |= ((uint32_t)1) << 7; //Bank1,涓婇攣
  45. }
  46. /**
  47. * 获取flash状态
  48. *
  49. * @author LXZ (121819)
  50. *
  51. * @return int
  52. */
  53. int st_flash_error_no(void) {
  54. int res = 0;
  55. res = FLASH->SR;
  56. if (res & (1 << 0)) return 1; //忙
  57. else if (res & (1 << 2)) return 2; //页面错误
  58. else if (res & (1 << 4)) return 3; //写保护
  59. return 0; //没有任何状态/操作完成
  60. }
  61. int flash_last_wait_time = 0;
  62. /**
  63. * 等待操作完成
  64. *
  65. * @author lxz (2019/5/30/鍛ㄥ洓)
  66. *
  67. * @param bankx
  68. * @param time 等待时间
  69. */
  70. int st_flash_wait_done(int time) {
  71. int res = 0;
  72. do {
  73. res = st_flash_error_no();
  74. if (res != 1) break; //非忙,无需等待了,直接退出.
  75. hw_delay_us(1);
  76. time--;
  77. }while (time);
  78. if (time == 0) res = 0xff; //TIMEOUT
  79. flash_last_wait_time = time;
  80. return res;
  81. }
  82. /**
  83. *擦除扇区
  84. *
  85. * @author lxz (2019/5/30/鍛ㄥ洓)
  86. *
  87. * @param sector_no
  88. *
  89. * @return int
  90. */
  91. int st_flash_erase_secotr(uint8_t sector_no) {
  92. int res = 0;
  93. int number = 0;
  94. int blockNumber = page_infos[sector_no].size;
  95. uint32_t addr = page_infos[sector_no].addr;
  96. int page_size = 1024;
  97. //FLASH->ACR &= ~(1 << 4);
  98. res = st_flash_wait_done(20000); //绛夊緟涓婃鎿嶄綔缁撴潫,鏈€澶?s
  99. if (__ST_FLASH_SIZE >= 0x100) {
  100. page_size = 2048;
  101. }
  102. blockNumber /= page_size;
  103. while (res == 0 && number < blockNumber) {
  104. //FLASH->CR&=~(3<<8); //清除PSIZE原来的设置
  105. //FLASH->CR|=2<<8; //设置为32bit宽,确保VCC=2.7~3.6V之间!!
  106. //FLASH->CR&=~(0X1F<<3);//清除原来的设置
  107. //FLASH->CR|=sector_no<<3;//设置要擦除的扇区
  108. FLASH->CR |= 1 << 1; //扇区擦除
  109. FLASH->AR = addr;
  110. FLASH->CR |= 1 << 6; //开始擦除
  111. res = st_flash_wait_done(20000); //等待操作结束,最大2s
  112. if (res != 1) { //非忙
  113. FLASH->CR &= ~(1 << 1); //清除扇区擦除标志.
  114. }
  115. number++;
  116. addr += page_size;
  117. }
  118. //FLASH->ACR |= (1 << 4);
  119. return res;
  120. }
  121. /**
  122. * 往指定地址写入一个字,地址必须保证字对齐
  123. *
  124. * @author lxz (2019/5/30/鍛ㄥ洓)
  125. *
  126. * @param faddr
  127. * @param pdata
  128. *
  129. * @return int
  130. */
  131. int st_flash_write_flash_word(uint32_t faddr, uint32_t pdata) {
  132. u8 res;
  133. res = st_flash_wait_done(0XFF);
  134. if (res == 0) { //OK
  135. FLASH->CR |= 1 << 0;
  136. *(vu16 *)faddr = pdata;
  137. res = st_flash_wait_done(0XFF);
  138. if (res == 0) {
  139. FLASH->CR &= ~(1 << 0);
  140. }
  141. }
  142. res = st_flash_wait_done(0XFF);
  143. faddr += 2;
  144. pdata >>= 16;
  145. if (res == 0) {
  146. FLASH->CR |= 1 << 0;
  147. *(vu16 *)faddr = pdata;
  148. res = st_flash_wait_done(0XFF);
  149. if (res == 0) {
  150. FLASH->CR &= ~(1 << 0);
  151. }
  152. }
  153. return res;
  154. }
  155. int st_flash_write_half_word(uint32_t faddr, uint16_t pdata) {
  156. u8 res;
  157. res = st_flash_wait_done(0XFF);
  158. if (res == 0) { //OK
  159. FLASH->CR |= 1 << 0;
  160. *(vu16 *)faddr = pdata;
  161. res = st_flash_wait_done(0XFF);
  162. if (res == 0) {
  163. FLASH->CR &= ~(1 << 0);
  164. }
  165. }
  166. return res;
  167. }
  168. /**
  169. * 读取指定地址一个32位数据
  170. *
  171. * @author LXZ (121819)
  172. *
  173. * @param faddr
  174. *
  175. * @return uint32_t
  176. */
  177. uint32_t st_flash_read_word(uint32_t faddr) {
  178. return *(vu32 *)faddr;
  179. }
  180. /**
  181. * 閫氳繃鍦板潃鑾峰彇鎵€鍦ㄧ殑鎵囧尯鍙?
  182. *
  183. * @author lxz (2019/5/30/鍛ㄥ洓)
  184. *
  185. * @param addr
  186. *
  187. * @return uint8_t
  188. */
  189. uint8_t st_flash_addr_to_sector_no(uint32_t addr) {
  190. int i = 0;
  191. while ((page_infos[i].addr + page_infos[i].size) <= addr &&
  192. i < (sizeof(page_infos) / sizeof(st_flash_page_info))) { //计算块大小是否已经包含了地址
  193. i++;
  194. }
  195. return i;
  196. }
  197. /**
  198. * 向指定地址写入32位数据
  199. *
  200. * @author LXZ (121819)
  201. *
  202. * @param addr
  203. * @param buffer
  204. * @param length
  205. *
  206. * @return int
  207. */
  208. int st_flash_write(uint32_t addr, uint32_t *buffer, uint32_t length) {
  209. int status = 0;
  210. uint32_t addrx = 0;
  211. uint32_t endaddr = 0;
  212. if (addr < STM32_FLASH_BASE || addr % 4) return 1; //非法地址
  213. st_flash_unlock(); //解锁
  214. //FLASH->ACR &= ~(1 << 10); //FLASH擦除期间,必须禁止数据缓存!!!搞了我两晚上才发现这个问题!
  215. addrx = addr; //写入的起始地址
  216. endaddr = addr + length * 4; //写入的结束地址
  217. if (addrx < 0X1FFF0000) { //只有主存储区,才需要执行擦除操作!!
  218. while (addrx < endaddr) { //扫清一切障碍.(对非FFFFFFFF的地方,先擦除)
  219. if (st_flash_read_word(addrx) != 0XFFFFFFFF) { //有非0XFFFFFFFF的地方,要擦除这个扇区
  220. status = st_flash_erase_secotr(st_flash_addr_to_sector_no(addrx));
  221. if (status) break; //发生错误了
  222. } else addrx += 4;
  223. }
  224. }
  225. if (status == 0) {
  226. uint16_t * dat = (uint16_t *)buffer;
  227. while (addr < endaddr) {
  228. if (st_flash_write_half_word(addr, *dat)) { //写入数据
  229. break; //写入异常
  230. }
  231. //sw_timer_now(&timer);
  232. addr += 2;
  233. dat++;
  234. }
  235. /*
  236. while (addr < endaddr) { //写数据
  237. //sw_timer_now(&timer2);
  238. if (st_flash_write_flash_word(addr, *buffer)) { //写入数据
  239. break; //写入异常
  240. }
  241. //sw_timer_now(&timer);
  242. addr += 4;
  243. buffer++;
  244. }
  245. */
  246. } else {
  247. while (1);
  248. }
  249. //FLASH->ACR |= 1 << 10; //FLASH擦除结束,开启数据fetch
  250. st_flash_lock(); //上锁
  251. return 0;
  252. }
  253. /**
  254. * 读取指定长度的32位数据
  255. *
  256. * @author LXZ (121819)
  257. *
  258. * @param addr
  259. * @param buffer
  260. * @param length
  261. */
  262. void st_flash_read(uint32_t addr, uint32_t *buffer, uint32_t length) {
  263. int i;
  264. for (i = 0; i < length; i++) {
  265. buffer[i] = st_flash_read_word(addr);
  266. addr += 4;
  267. }
  268. }