bsp_flash.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. //flash 1.0V
  2. /*********************************************************************
  3. * INCLUDES
  4. */
  5. #include "bsp_flash.h"
  6. static void fstorageCallbackFunc(nrf_fstorage_evt_t *pFstorageEvent);
  7. static uint32_t getflashEndAddress(void);
  8. static void waitForFlashReady(nrf_fstorage_t const *pFstorageHandle);
  9. /*********************************************************************
  10. * LOCAL VARIABLES
  11. */
  12. static uint32_t flash_PageBuff[PAGE_INT_SIZE]; //页缓冲区
  13. NRF_FSTORAGE_DEF(nrf_fstorage_t s_fstorageHandle) =
  14. {
  15. /* Set a handler for fstorage events. */
  16. .evt_handler = fstorageCallbackFunc,
  17. /* These below are the boundaries of the flash space assigned to this instance of fstorage.
  18. * You must set these manually, even at runtime, before nrf_fstorage_init() is called.
  19. * The function nrf5_flash_end_addr_get() can be used to retrieve the last address on the
  20. * last page of flash available to write data. */
  21. .start_addr = START_FSTORAGE_ADDR,
  22. .end_addr = END_FSTORAGE_ADDR,
  23. };
  24. /*********************************************************************
  25. * LOCAL FUNCTIONS
  26. */
  27. /**
  28. @brief Fstorage读写内存操作
  29. @param flashAddr -[in] 闪存地址
  30. @param readWriteFlag -[in] 读写操作标志
  31. @param pData -[in&out] 指向需要操作的数据
  32. @param dataLen -[in] 数据长度
  33. @return 错误代码
  34. */
  35. static uint32_t Fstorage_FlashRW(uint32_t flashAddr, uint8_t readWriteFlag, uint32_t *pData, uint32_t dataLen)
  36. {
  37. ret_code_t errCode;
  38. if(flashAddr%4 != 0 || flashAddr == 0)return FLASH_ERROR_ADDRALIGN;
  39. if((flashAddr + dataLen) > END_FSTORAGE_ADDR){
  40. return FLASH_ERROR_ADDROVERBOUNDS; //是否越界
  41. }
  42. if(readWriteFlag == FSTORAGE_READ) // 读取数据
  43. {
  44. errCode = nrf_fstorage_read(&s_fstorageHandle, flashAddr, pData, dataLen);
  45. APP_ERROR_CHECK(errCode);
  46. }
  47. else // 写入数据
  48. {
  49. if(dataLen %4 != 0 || dataLen == 0)return FLASH_ERROR_DATAALIGN;
  50. if( FLASH_ZONEADDR_CHECK(flashAddr) )return FLASH_ERROR_ZONEADDR;
  51. errCode = nrf_fstorage_erase(&s_fstorageHandle, flashAddr, 1, NULL); // 只能写入位值1,不能写入位值0,所以先擦后写
  52. errCode = nrf_fstorage_write(&s_fstorageHandle, flashAddr, pData, dataLen, NULL);
  53. APP_ERROR_CHECK(errCode);
  54. waitForFlashReady(&s_fstorageHandle); // 等待写完
  55. }
  56. return FLASH_OP_SUCCESS;
  57. }
  58. /**
  59. @brief Fstorage写内存操作,调用前FLASH预先已擦除
  60. @param flashAddr -[in] 闪存地址
  61. @param pData -[in&out] 指向需要操作的数据
  62. @param dataLen -[in] 数据长度
  63. @param is_check - [in] 是否检测数据存不存在
  64. @return 0:写入成功 1:4字节不对齐 2:已有数据存在 3:访问越界
  65. */
  66. static uint32_t Fstorage_FlashOnlyWrite(uint32_t flashAddr, uint32_t *pData, uint32_t dataLen, bool is_check)
  67. {
  68. ret_code_t errCode;
  69. uint32_t check,i,len;
  70. if(flashAddr%4 != 0 || flashAddr == 0)return FLASH_ERROR_ADDRALIGN;
  71. if(dataLen %4 != 0 || dataLen == 0)return FLASH_ERROR_DATAALIGN;
  72. if((flashAddr + dataLen) > END_FSTORAGE_ADDR){
  73. return FLASH_ERROR_ADDROVERBOUNDS;
  74. }
  75. if(is_check)
  76. {
  77. len = dataLen / 4;
  78. for(i=0;i<len;i++)
  79. {
  80. memcpy(&check, (uint32_t*)flashAddr + i, 4);
  81. if(check != 0xFFFFFFFF)return FLASH_ERROR_DATAEXIST;
  82. }
  83. }
  84. errCode = nrf_fstorage_write(&s_fstorageHandle, flashAddr, pData, dataLen, NULL);
  85. APP_ERROR_CHECK(errCode);
  86. waitForFlashReady(&s_fstorageHandle); // 等待写完
  87. return FLASH_OP_SUCCESS;
  88. }
  89. /**
  90. @brief Fstorage擦除一整页
  91. @param 要擦除的页的首地址
  92. @return 错误代码
  93. */
  94. static uint32_t Fstorage_FlashOnlyErasePage(uint32_t zone_addr)
  95. {
  96. ret_code_t errCode;
  97. if(zone_addr%4 != 0 || zone_addr == 0)return FLASH_ERROR_ADDRALIGN;
  98. if( FLASH_ZONEADDR_CHECK(zone_addr) )return FLASH_ERROR_ZONEADDR;
  99. errCode = nrf_fstorage_erase(&s_fstorageHandle, zone_addr, 1, NULL); // 只能写入位值1,不能写入位值0,所以先擦后写
  100. APP_ERROR_CHECK(errCode);
  101. waitForFlashReady(&s_fstorageHandle);
  102. return FLASH_OP_SUCCESS;
  103. }
  104. /*********************************************************************
  105. * LOCAL FUNCTIONS
  106. */
  107. /**
  108. @brief Fstorage事件回调函数
  109. @param pFstorageEvent -[in] Fstorage事件
  110. @return 无
  111. */
  112. static void fstorageCallbackFunc(nrf_fstorage_evt_t *pFstorageEvent)
  113. {
  114. if(pFstorageEvent->result != NRF_SUCCESS)
  115. {
  116. SEGGER_RTT_printf(0,"--> Event received: ERROR while executing an fstorage operation.\n");
  117. return ;
  118. }
  119. switch(pFstorageEvent->id)
  120. {
  121. case NRF_FSTORAGE_EVT_WRITE_RESULT:
  122. //SEGGER_RTT_printf(0,"--> Event received: wrote %d bytes at address 0x%x.\n", pFstorageEvent->len, pFstorageEvent->addr);
  123. break;
  124. case NRF_FSTORAGE_EVT_ERASE_RESULT:
  125. //SEGGER_RTT_printf(0,"--> Event received: erased %d page from address 0x%x.\n", pFstorageEvent->len, pFstorageEvent->addr);
  126. break;
  127. default:
  128. break;
  129. }
  130. }
  131. /**
  132. @brief 检索Flash上可用于写入数据的地址
  133. @param 无
  134. @return 无
  135. */
  136. static uint32_t getflashEndAddress(void)
  137. {
  138. uint32_t const bootloaderAddr = NRF_UICR->NRFFW[0];
  139. uint32_t const pageSz = NRF_FICR->CODEPAGESIZE;
  140. uint32_t const codeSz = NRF_FICR->CODESIZE;
  141. return (bootloaderAddr != 0xFFFFFFFF ? bootloaderAddr : (codeSz * pageSz));
  142. }
  143. /**
  144. @brief 等待写入完成
  145. @param pFstorageHandle -[in] Fstorage句柄
  146. @return 无
  147. */
  148. static void waitForFlashReady(nrf_fstorage_t const *pFstorageHandle)
  149. {
  150. while(nrf_fstorage_is_busy(pFstorageHandle)) // While fstorage is busy, sleep and wait for an event.
  151. {
  152. nrf_pwr_mgmt_run();
  153. }
  154. }
  155. /**
  156. @brief 从flash中连续读取N个4字节数据
  157. @param addr-[in] 读取的首地址
  158. @param pData -[in&out] 指向需要操作的数据
  159. @param dataLen -[in] 数据长度
  160. @return 错误代码
  161. */
  162. static uint32_t Read_N_4Byte_flash(uint32_t addr , uint32_t *pData, uint32_t dataLen)
  163. {
  164. return Fstorage_FlashRW(addr, FSTORAGE_READ, pData, dataLen);
  165. }
  166. /**
  167. @brief 获取页号所在的首地址
  168. @param PageNum-[in] 需要查找的页号
  169. @param PageAddr-[in/out] 返回的页号首地址
  170. @return 错误代码
  171. */
  172. static uint32_t GetPageAddr(uint16_t PageNum, uint32_t *PageAddr)
  173. {
  174. if(PageNum >= FLASH_PAGE_NUM)return FLASH_ERROR_PAGENUM;
  175. *PageAddr = FLASH_ZONE_ADDR_1 + PageNum * FLASH_PAGE_SIZE;
  176. return FLASH_OP_SUCCESS;
  177. }
  178. /**
  179. @brief 获取页号所在的尾地址(该页号下一页的首地址)
  180. @param PageNum-[in] 需要查找的页号
  181. @param PageAddr-[in/out] 返回的页号首地址
  182. @return 错误代码
  183. */
  184. static uint32_t GetPageEndAddr(uint16_t PageNum, uint32_t *PageAddr)
  185. {
  186. if(PageNum >= FLASH_PAGE_NUM)return FLASH_ERROR_PAGENUM;
  187. *PageAddr = FLASH_ZONE_ADDR_1 + (PageNum+1) * FLASH_PAGE_SIZE;
  188. return FLASH_OP_SUCCESS;
  189. }
  190. /**
  191. @brief 获取地址距离所在页的偏移量
  192. @param addr-[in] 需要查找的flash地址
  193. @param _offset-[in/out] 返回的偏移量
  194. @return 错误代码
  195. */
  196. static uint32_t GetDistanceFromPage(uint32_t addr, uint32_t *_offset)
  197. {
  198. if(addr %4 != 0 || addr == 0)return FLASH_ERROR_ADDRALIGN;
  199. if(addr > END_FSTORAGE_ADDR || addr < START_FSTORAGE_ADDR){
  200. return FLASH_ERROR_ADDROVERBOUNDS; //是否越界
  201. }
  202. //获取偏移量
  203. *_offset = ((addr - START_FSTORAGE_ADDR)%FLASH_PAGE_SIZE)/4;
  204. return FLASH_OP_SUCCESS;
  205. }
  206. /**
  207. @brief 判断是否需要擦除
  208. @param start_addr-[in] flash首地址
  209. @param len -[in] 长度
  210. @param is_erase-[in/out] 1:需要擦除,0:不需要擦除
  211. @return 错误代码
  212. */
  213. static uint32_t __NeedErase(uint32_t start_addr , uint32_t len , uint8_t *is_erase)
  214. {
  215. uint32_t err_code;
  216. uint32_t i = 0, data;
  217. if((start_addr + len) > END_FSTORAGE_ADDR)return FLASH_ERROR_ADDROVERBOUNDS;
  218. if(start_addr%4 != 0 || start_addr == 0)return FLASH_ERROR_ADDRALIGN;
  219. if(len %4 != 0 || len == 0)return FLASH_ERROR_DATAALIGN;
  220. len /=4;
  221. for(;i<len;i++)
  222. {
  223. err_code = Fstorage_FlashRW(start_addr, FSTORAGE_READ, &data, 4);
  224. if(err_code != FLASH_OP_SUCCESS)return err_code;
  225. if(data != 0xFFFFFFFF)break;
  226. start_addr += 4;
  227. }
  228. *is_erase = (i==len)?0:1;
  229. return FLASH_OP_SUCCESS;
  230. }
  231. /****************************************************接口****************************************************/
  232. /**
  233. @brief Fstorage读写内存初始化
  234. @param 无
  235. @return 无
  236. */
  237. void Fstorage_FlashInit(void)
  238. {
  239. ret_code_t errCode;
  240. nrf_fstorage_api_t *pFstorageApi;
  241. pFstorageApi = &nrf_fstorage_sd;
  242. errCode = nrf_fstorage_init(&s_fstorageHandle, pFstorageApi, NULL); // Flash处理的开始地址和结束地址初始化
  243. APP_ERROR_CHECK(errCode);
  244. (void)getflashEndAddress(); // 获取地址,判断为可写地址大小
  245. }
  246. /**
  247. @brief 从flash中连续读取N个字节数据
  248. @param addr-[in] 读取的首地址
  249. @param pData -[in&out] 指向需要操作的数据
  250. @param dataLen -[in] 数据长度
  251. @return 错误代码
  252. */
  253. uint32_t Read_N_Byte_flash(uint32_t addr , uint32_t *pData, uint32_t dataLen)
  254. {
  255. if(addr > END_FSTORAGE_ADDR || addr < START_FSTORAGE_ADDR){
  256. return FLASH_ERROR_ADDROVERBOUNDS; //是否越界
  257. }
  258. memcpy(pData, (uint32_t*)addr, dataLen);
  259. return FLASH_OP_SUCCESS;
  260. }
  261. /**
  262. @brief 获取flash地址所在的页号
  263. @param addr-[in] 需要查找的flash地址
  264. @param page_num-[in/out] 返回的页号
  265. @return 错误代码
  266. */
  267. uint32_t GetPageNum(uint32_t addr, uint16_t *PageNum)
  268. {
  269. uint16_t page_num = 0;
  270. if(addr > END_FSTORAGE_ADDR || addr < START_FSTORAGE_ADDR){
  271. return FLASH_ERROR_ADDROVERBOUNDS; //是否越界
  272. }
  273. // if(addr %4 != 0 || addr == 0)return FLASH_ERROR_ADDRALIGN;
  274. page_num = (addr - START_FSTORAGE_ADDR)/FLASH_PAGE_SIZE;
  275. if(page_num >= FLASH_PAGE_NUM)return FLASH_ERROR_PAGENUM;
  276. *PageNum = page_num;
  277. return FLASH_OP_SUCCESS;
  278. }
  279. /**
  280. @brief 擦除1页
  281. @param PageNum-[in] 页号
  282. @return 错误代码
  283. */
  284. uint32_t Erase_OnePage(uint16_t PageNum)
  285. {
  286. uint32_t PageAddr;
  287. uint32_t err_code;
  288. err_code = GetPageAddr(PageNum, &PageAddr);
  289. if(err_code != FLASH_OP_SUCCESS)return err_code;
  290. return Fstorage_FlashOnlyErasePage(PageAddr);
  291. }
  292. /**
  293. @brief 写N个字到flash中
  294. @param addr-[in] 写入的flash首地址
  295. @param pdata-[in] 需要写入的数据
  296. @param len-[in] 数据长度
  297. @return 错误代码
  298. */
  299. uint32_t Write_N_4Byte_flash(uint32_t addr , uint32_t *pdata, uint32_t len)
  300. {
  301. uint8_t is_erase;
  302. uint16_t start_page = 0; //起始页号
  303. uint32_t page_size = 0; //需要操作页的大小
  304. uint32_t _offset = 0; //页操作页码的起始地址
  305. uint32_t page_offset = 0; //页偏移
  306. uint32_t data_offset = 0; //数据偏移
  307. uint32_t remain_size = 0; //本次操作页可以使用的剩余大小
  308. uint32_t base_addr = 0; //本次操作页的基地址
  309. uint32_t surplus = 0;
  310. uint32_t err_code;
  311. //是否越界
  312. if((addr + len) > END_FSTORAGE_ADDR){
  313. return FLASH_ERROR_ADDROVERBOUNDS;
  314. }
  315. //获取起始页号
  316. err_code = GetPageNum(addr, &start_page);
  317. if(err_code != FLASH_OP_SUCCESS)return err_code;
  318. //获取偏移量
  319. err_code = GetDistanceFromPage(addr,&_offset);
  320. if(err_code != FLASH_OP_SUCCESS)return err_code;
  321. //计算需要写入的页数
  322. if(((PAGE_INT_SIZE - _offset)*4) >= len)
  323. {
  324. page_size = 1;
  325. surplus = 0;
  326. }
  327. else
  328. {
  329. page_size = 1;
  330. surplus = len - ((PAGE_INT_SIZE - _offset)*4);
  331. page_size += ((surplus/FLASH_PAGE_SIZE) + (surplus%FLASH_PAGE_SIZE>0?1:0));
  332. }
  333. //写入
  334. surplus = len;
  335. for(page_offset = 0; page_offset < page_size; page_offset++)
  336. {
  337. //获取页首地址
  338. err_code = GetPageAddr(start_page + page_offset, &base_addr);
  339. if(err_code != FLASH_OP_SUCCESS)return err_code;
  340. if(page_offset == 0)
  341. {
  342. remain_size = (PAGE_INT_SIZE - _offset)*4<surplus ? (PAGE_INT_SIZE - _offset)*4:surplus;
  343. surplus = len - remain_size;
  344. }
  345. else
  346. {
  347. _offset = 0;
  348. remain_size = surplus > FLASH_PAGE_SIZE ? FLASH_PAGE_SIZE : surplus;
  349. surplus = surplus - remain_size;
  350. }
  351. //判断是否要擦除
  352. err_code = __NeedErase(base_addr + _offset*4 , remain_size, &is_erase);
  353. if(err_code != FLASH_OP_SUCCESS)return err_code;
  354. //先擦除后写
  355. if(is_erase)
  356. {
  357. //读取
  358. err_code = Read_N_4Byte_flash(base_addr , flash_PageBuff, FLASH_PAGE_SIZE);
  359. if(err_code != FLASH_OP_SUCCESS)return err_code;
  360. //修改
  361. memcpy(&flash_PageBuff[_offset], pdata + data_offset, remain_size);
  362. //写回
  363. err_code = Fstorage_FlashRW(base_addr, FSTORAGE_WRITE, flash_PageBuff, FLASH_PAGE_SIZE);
  364. if(err_code != FLASH_OP_SUCCESS)return err_code;
  365. }
  366. else
  367. {
  368. err_code = Fstorage_FlashOnlyWrite(base_addr + _offset*4, pdata + data_offset, remain_size, false); //直接写
  369. if(err_code != FLASH_OP_SUCCESS)return err_code;
  370. }
  371. data_offset += remain_size/4;
  372. }
  373. return FLASH_OP_SUCCESS;
  374. }
  375. /**
  376. @brief 只写N个字到flash中,调用前FLASH预先已擦除
  377. @param addr-[in] 写入的flash首地址
  378. @param pdata-[in] 需要写入的数据
  379. @param len-[in] 数据长度
  380. @return 错误代码
  381. */
  382. uint32_t Only_Write_N_4Byte_flash(uint32_t addr , uint32_t *pdata, uint32_t len, bool is_check)
  383. {
  384. return Fstorage_FlashOnlyWrite(addr, pdata, len, is_check);
  385. }
  386. /**
  387. @brief 查找一页中可写的空间(0xFF)
  388. @param PageNum-[in] 输入的页号
  389. @param start_addr-[in/out] 返回的空闲空间的起始地址
  390. @param len-[in/out] 返回的空间的长度
  391. @return 错误代码
  392. */
  393. uint32_t Find_FreeSpace_In_Page(uint16_t PageNum, uint32_t *start_addr, uint32_t *len)
  394. {
  395. uint32_t PageEndAddr, RetrieveAddr, i;
  396. uint32_t flash_data;
  397. if(PageNum >= FLASH_PAGE_NUM)return FLASH_ERROR_PAGENUM;
  398. //获取该页的结尾地址
  399. GetPageEndAddr(PageNum, &PageEndAddr);
  400. //从页尾开始检索空闲空间
  401. RetrieveAddr = PageEndAddr;
  402. for(i = 0;i<PAGE_INT_SIZE;i++)
  403. {
  404. RetrieveAddr -= 4;
  405. Read_N_4Byte_flash(RetrieveAddr , &flash_data, 4);
  406. if(flash_data != 0xFFFFFFFF)break;
  407. }
  408. *start_addr = PageEndAddr - i *4;
  409. *len = i*4;
  410. return FLASH_OP_SUCCESS;
  411. }
  412. /****************************************************END OF FILE****************************************************/