bsp_flash.c 13 KB

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