123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502 |
- //flash 1.0V
- /*********************************************************************
- * INCLUDES
- */
- #include "bsp_flash.h"
- static void fstorageCallbackFunc(nrf_fstorage_evt_t *pFstorageEvent);
- static uint32_t getflashEndAddress(void);
- static void waitForFlashReady(nrf_fstorage_t const *pFstorageHandle);
- /*********************************************************************
- * LOCAL VARIABLES
- */
-
- static uint32_t flash_PageBuff[PAGE_INT_SIZE]; //页缓冲区
- NRF_FSTORAGE_DEF(nrf_fstorage_t s_fstorageHandle) =
- {
- /* Set a handler for fstorage events. */
- .evt_handler = fstorageCallbackFunc,
- /* These below are the boundaries of the flash space assigned to this instance of fstorage.
- * You must set these manually, even at runtime, before nrf_fstorage_init() is called.
- * The function nrf5_flash_end_addr_get() can be used to retrieve the last address on the
- * last page of flash available to write data. */
- .start_addr = START_FSTORAGE_ADDR,
- .end_addr = END_FSTORAGE_ADDR,
- };
- /*********************************************************************
- * LOCAL FUNCTIONS
- */
- /**
- @brief Fstorage读写内存操作
- @param flashAddr -[in] 闪存地址
- @param readWriteFlag -[in] 读写操作标志
- @param pData -[in&out] 指向需要操作的数据
- @param dataLen -[in] 数据长度
- @return 错误代码
- */
- static uint32_t Fstorage_FlashRW(uint32_t flashAddr, uint8_t readWriteFlag, uint32_t *pData, uint32_t dataLen)
- {
- ret_code_t errCode;
-
- if(flashAddr%4 != 0 || flashAddr == 0)return FLASH_ERROR_ADDRALIGN;
- if((flashAddr + dataLen) > END_FSTORAGE_ADDR){
- return FLASH_ERROR_ADDROVERBOUNDS; //是否越界
- }
-
- if(readWriteFlag == FSTORAGE_READ) // 读取数据
- {
- errCode = nrf_fstorage_read(&s_fstorageHandle, flashAddr, pData, dataLen);
- APP_ERROR_CHECK(errCode);
- }
- else // 写入数据
- {
- if(dataLen %4 != 0 || dataLen == 0)return FLASH_ERROR_DATAALIGN;
- if( FLASH_ZONEADDR_CHECK(flashAddr) )return FLASH_ERROR_ZONEADDR;
-
- errCode = nrf_fstorage_erase(&s_fstorageHandle, flashAddr, 1, NULL); // 只能写入位值1,不能写入位值0,所以先擦后写
- errCode = nrf_fstorage_write(&s_fstorageHandle, flashAddr, pData, dataLen, NULL);
- APP_ERROR_CHECK(errCode);
-
- waitForFlashReady(&s_fstorageHandle); // 等待写完
- }
-
- return FLASH_OP_SUCCESS;
- }
- /**
- @brief Fstorage写内存操作,调用前FLASH预先已擦除
- @param flashAddr -[in] 闪存地址
- @param pData -[in&out] 指向需要操作的数据
- @param dataLen -[in] 数据长度
- @param is_check - [in] 是否检测数据存不存在
- @return 0:写入成功 1:4字节不对齐 2:已有数据存在 3:访问越界
- */
- static uint32_t Fstorage_FlashOnlyWrite(uint32_t flashAddr, uint32_t *pData, uint32_t dataLen, bool is_check)
- {
- ret_code_t errCode;
- uint32_t check,i,len;
-
- if(flashAddr%4 != 0 || flashAddr == 0)return FLASH_ERROR_ADDRALIGN;
- if(dataLen %4 != 0 || dataLen == 0)return FLASH_ERROR_DATAALIGN;
- if((flashAddr + dataLen) > END_FSTORAGE_ADDR){
- return FLASH_ERROR_ADDROVERBOUNDS;
- }
-
- if(is_check)
- {
- len = dataLen / 4;
- for(i=0;i<len;i++)
- {
- memcpy(&check, (uint32_t*)flashAddr + i, 4);
- if(check != 0xFFFFFFFF)return FLASH_ERROR_DATAEXIST;
- }
- }
- errCode = nrf_fstorage_write(&s_fstorageHandle, flashAddr, pData, dataLen, NULL);
- APP_ERROR_CHECK(errCode);
-
- waitForFlashReady(&s_fstorageHandle); // 等待写完
-
- return FLASH_OP_SUCCESS;
- }
- /**
- @brief Fstorage擦除一整页
- @param 要擦除的页的首地址
- @return 错误代码
- */
- static uint32_t Fstorage_FlashOnlyErasePage(uint32_t zone_addr)
- {
-
- ret_code_t errCode;
-
- if(zone_addr%4 != 0 || zone_addr == 0)return FLASH_ERROR_ADDRALIGN;
- if( FLASH_ZONEADDR_CHECK(zone_addr) )return FLASH_ERROR_ZONEADDR;
-
- errCode = nrf_fstorage_erase(&s_fstorageHandle, zone_addr, 1, NULL); // 只能写入位值1,不能写入位值0,所以先擦后写
- APP_ERROR_CHECK(errCode);
-
- waitForFlashReady(&s_fstorageHandle);
-
- return FLASH_OP_SUCCESS;
- }
- /*********************************************************************
- * LOCAL FUNCTIONS
- */
- /**
- @brief Fstorage事件回调函数
- @param pFstorageEvent -[in] Fstorage事件
- @return 无
- */
- static void fstorageCallbackFunc(nrf_fstorage_evt_t *pFstorageEvent)
- {
- if(pFstorageEvent->result != NRF_SUCCESS)
- {
- SEGGER_RTT_printf(0,"--> Event received: ERROR while executing an fstorage operation.\n");
- return ;
- }
- switch(pFstorageEvent->id)
- {
- case NRF_FSTORAGE_EVT_WRITE_RESULT:
- //SEGGER_RTT_printf(0,"--> Event received: wrote %d bytes at address 0x%x.\n", pFstorageEvent->len, pFstorageEvent->addr);
- break;
- case NRF_FSTORAGE_EVT_ERASE_RESULT:
- //SEGGER_RTT_printf(0,"--> Event received: erased %d page from address 0x%x.\n", pFstorageEvent->len, pFstorageEvent->addr);
- break;
- default:
- break;
- }
- }
- /**
- @brief 检索Flash上可用于写入数据的地址
- @param 无
- @return 无
- */
- static uint32_t getflashEndAddress(void)
- {
- uint32_t const bootloaderAddr = NRF_UICR->NRFFW[0];
- uint32_t const pageSz = NRF_FICR->CODEPAGESIZE;
- uint32_t const codeSz = NRF_FICR->CODESIZE;
- return (bootloaderAddr != 0xFFFFFFFF ? bootloaderAddr : (codeSz * pageSz));
- }
- /**
- @brief 等待写入完成
- @param pFstorageHandle -[in] Fstorage句柄
- @return 无
- */
- static void waitForFlashReady(nrf_fstorage_t const *pFstorageHandle)
- {
- while(nrf_fstorage_is_busy(pFstorageHandle)) // While fstorage is busy, sleep and wait for an event.
- {
- nrf_pwr_mgmt_run();
- }
- }
- /**
- @brief 从flash中连续读取N个4字节数据
- @param addr-[in] 读取的首地址
- @param pData -[in&out] 指向需要操作的数据
- @param dataLen -[in] 数据长度
- @return 错误代码
- */
- static uint32_t Read_N_4Byte_flash(uint32_t addr , uint32_t *pData, uint32_t dataLen)
- {
- return Fstorage_FlashRW(addr, FSTORAGE_READ, pData, dataLen);
- }
- /**
- @brief 获取页号所在的首地址
- @param PageNum-[in] 需要查找的页号
- @param PageAddr-[in/out] 返回的页号首地址
- @return 错误代码
- */
- static uint32_t GetPageAddr(uint16_t PageNum, uint32_t *PageAddr)
- {
- if(PageNum >= FLASH_PAGE_NUM)return FLASH_ERROR_PAGENUM;
-
- *PageAddr = FLASH_ZONE_ADDR_1 + PageNum * FLASH_PAGE_SIZE;
-
- return FLASH_OP_SUCCESS;
- }
- /**
- @brief 获取页号所在的尾地址(该页号下一页的首地址)
- @param PageNum-[in] 需要查找的页号
- @param PageAddr-[in/out] 返回的页号首地址
- @return 错误代码
- */
- static uint32_t GetPageEndAddr(uint16_t PageNum, uint32_t *PageAddr)
- {
- if(PageNum >= FLASH_PAGE_NUM)return FLASH_ERROR_PAGENUM;
-
- *PageAddr = FLASH_ZONE_ADDR_1 + (PageNum+1) * FLASH_PAGE_SIZE;
-
- return FLASH_OP_SUCCESS;
- }
- /**
- @brief 获取地址距离所在页的偏移量
- @param addr-[in] 需要查找的flash地址
- @param _offset-[in/out] 返回的偏移量
- @return 错误代码
- */
- static uint32_t GetDistanceFromPage(uint32_t addr, uint32_t *_offset)
- {
-
- if(addr %4 != 0 || addr == 0)return FLASH_ERROR_ADDRALIGN;
- if(addr > END_FSTORAGE_ADDR || addr < START_FSTORAGE_ADDR){
- return FLASH_ERROR_ADDROVERBOUNDS; //是否越界
- }
-
- //获取偏移量
- *_offset = ((addr - START_FSTORAGE_ADDR)%FLASH_PAGE_SIZE)/4;
-
- return FLASH_OP_SUCCESS;
- }
- /**
- @brief 判断是否需要擦除
- @param start_addr-[in] flash首地址
- @param len -[in] 长度
- @param is_erase-[in/out] 1:需要擦除,0:不需要擦除
- @return 错误代码
- */
- static uint32_t __NeedErase(uint32_t start_addr , uint32_t len , uint8_t *is_erase)
- {
- uint32_t err_code;
- uint32_t i = 0, data;
-
- if((start_addr + len) > END_FSTORAGE_ADDR)return FLASH_ERROR_ADDROVERBOUNDS;
- if(start_addr%4 != 0 || start_addr == 0)return FLASH_ERROR_ADDRALIGN;
- if(len %4 != 0 || len == 0)return FLASH_ERROR_DATAALIGN;
- len /=4;
- for(;i<len;i++)
- {
- err_code = Fstorage_FlashRW(start_addr, FSTORAGE_READ, &data, 4);
- if(err_code != FLASH_OP_SUCCESS)return err_code;
-
- if(data != 0xFFFFFFFF)break;
- start_addr += 4;
- }
-
- *is_erase = (i==len)?0:1;
-
- return FLASH_OP_SUCCESS;
- }
- /****************************************************接口****************************************************/
- /**
- @brief Fstorage读写内存初始化
- @param 无
- @return 无
- */
- void Fstorage_FlashInit(void)
- {
- ret_code_t errCode;
- nrf_fstorage_api_t *pFstorageApi;
- pFstorageApi = &nrf_fstorage_sd;
-
- errCode = nrf_fstorage_init(&s_fstorageHandle, pFstorageApi, NULL); // Flash处理的开始地址和结束地址初始化
- APP_ERROR_CHECK(errCode);
-
- (void)getflashEndAddress(); // 获取地址,判断为可写地址大小
- }
- /**
- @brief 从flash中连续读取N个字节数据
- @param addr-[in] 读取的首地址
- @param pData -[in&out] 指向需要操作的数据
- @param dataLen -[in] 数据长度
- @return 错误代码
- */
- uint32_t Read_N_Byte_flash(uint32_t addr , uint32_t *pData, uint32_t dataLen)
- {
- if(addr > END_FSTORAGE_ADDR || addr < START_FSTORAGE_ADDR){
- return FLASH_ERROR_ADDROVERBOUNDS; //是否越界
- }
-
- memcpy(pData, (uint32_t*)addr, dataLen);
-
- return FLASH_OP_SUCCESS;
- }
- /**
- @brief 获取flash地址所在的页号
- @param addr-[in] 需要查找的flash地址
- @param page_num-[in/out] 返回的页号
- @return 错误代码
- */
- uint32_t GetPageNum(uint32_t addr, uint16_t *PageNum)
- {
- uint16_t page_num = 0;
-
- if(addr > END_FSTORAGE_ADDR || addr < START_FSTORAGE_ADDR){
- return FLASH_ERROR_ADDROVERBOUNDS; //是否越界
- }
-
- // if(addr %4 != 0 || addr == 0)return FLASH_ERROR_ADDRALIGN;
-
- page_num = (addr - START_FSTORAGE_ADDR)/FLASH_PAGE_SIZE;
- if(page_num >= FLASH_PAGE_NUM)return FLASH_ERROR_PAGENUM;
-
- *PageNum = page_num;
-
- return FLASH_OP_SUCCESS;
- }
- /**
- @brief 擦除1页
- @param PageNum-[in] 页号
- @return 错误代码
- */
- uint32_t Erase_OnePage(uint16_t PageNum)
- {
- uint32_t PageAddr;
- uint32_t err_code;
-
- err_code = GetPageAddr(PageNum, &PageAddr);
- if(err_code != FLASH_OP_SUCCESS)return err_code;
-
- return Fstorage_FlashOnlyErasePage(PageAddr);
- }
- /**
- @brief 写N个字到flash中
- @param addr-[in] 写入的flash首地址
- @param pdata-[in] 需要写入的数据
- @param len-[in] 数据长度
- @return 错误代码
- */
- uint32_t Write_N_4Byte_flash(uint32_t addr , uint32_t *pdata, uint32_t len)
- {
- uint8_t is_erase;
- uint16_t start_page = 0; //起始页号
- uint32_t page_size = 0; //需要操作页的大小
- uint32_t _offset = 0; //页操作页码的起始地址
- uint32_t page_offset = 0; //页偏移
- uint32_t data_offset = 0; //数据偏移
- uint32_t remain_size = 0; //本次操作页可以使用的剩余大小
- uint32_t base_addr = 0; //本次操作页的基地址
- uint32_t surplus = 0;
- uint32_t err_code;
-
- //是否越界
- if((addr + len) > END_FSTORAGE_ADDR){
- return FLASH_ERROR_ADDROVERBOUNDS;
- }
- //获取起始页号
- err_code = GetPageNum(addr, &start_page);
- if(err_code != FLASH_OP_SUCCESS)return err_code;
- //获取偏移量
- err_code = GetDistanceFromPage(addr,&_offset);
- if(err_code != FLASH_OP_SUCCESS)return err_code;
- //计算需要写入的页数
- if(((PAGE_INT_SIZE - _offset)*4) >= len)
- {
- page_size = 1;
- surplus = 0;
- }
- else
- {
- page_size = 1;
- surplus = len - ((PAGE_INT_SIZE - _offset)*4);
- page_size += ((surplus/FLASH_PAGE_SIZE) + (surplus%FLASH_PAGE_SIZE>0?1:0));
- }
- //写入
- surplus = len;
- for(page_offset = 0; page_offset < page_size; page_offset++)
- {
-
- //获取页首地址
- err_code = GetPageAddr(start_page + page_offset, &base_addr);
- if(err_code != FLASH_OP_SUCCESS)return err_code;
-
- if(page_offset == 0)
- {
- remain_size = (PAGE_INT_SIZE - _offset)*4<surplus ? (PAGE_INT_SIZE - _offset)*4:surplus;
- surplus = len - remain_size;
- }
- else
- {
- _offset = 0;
- remain_size = surplus > FLASH_PAGE_SIZE ? FLASH_PAGE_SIZE : surplus;
- surplus = surplus - remain_size;
- }
-
- //判断是否要擦除
- err_code = __NeedErase(base_addr + _offset*4 , remain_size, &is_erase);
- if(err_code != FLASH_OP_SUCCESS)return err_code;
-
-
- //先擦除后写
- if(is_erase)
- {
- //读取
- err_code = Read_N_4Byte_flash(base_addr , flash_PageBuff, FLASH_PAGE_SIZE);
- if(err_code != FLASH_OP_SUCCESS)return err_code;
- //修改
- memcpy(&flash_PageBuff[_offset], pdata + data_offset, remain_size);
- //写回
- err_code = Fstorage_FlashRW(base_addr, FSTORAGE_WRITE, flash_PageBuff, FLASH_PAGE_SIZE);
- if(err_code != FLASH_OP_SUCCESS)return err_code;
- }
- else
- {
- err_code = Fstorage_FlashOnlyWrite(base_addr + _offset*4, pdata + data_offset, remain_size, false); //直接写
- if(err_code != FLASH_OP_SUCCESS)return err_code;
- }
- data_offset += remain_size/4;
-
- }
-
- return FLASH_OP_SUCCESS;
-
- }
- /**
- @brief 只写N个字到flash中,调用前FLASH预先已擦除
- @param addr-[in] 写入的flash首地址
- @param pdata-[in] 需要写入的数据
- @param len-[in] 数据长度
- @return 错误代码
- */
- uint32_t Only_Write_N_4Byte_flash(uint32_t addr , uint32_t *pdata, uint32_t len, bool is_check)
- {
- return Fstorage_FlashOnlyWrite(addr, pdata, len, is_check);
- }
- /**
- @brief 查找一页中可写的空间(0xFF)
- @param PageNum-[in] 输入的页号
- @param start_addr-[in/out] 返回的空闲空间的起始地址
- @param len-[in/out] 返回的空间的长度
- @return 错误代码
- */
- uint32_t Find_FreeSpace_In_Page(uint16_t PageNum, uint32_t *start_addr, uint32_t *len)
- {
- uint32_t PageEndAddr, RetrieveAddr, i;
- uint32_t flash_data;
-
- if(PageNum >= FLASH_PAGE_NUM)return FLASH_ERROR_PAGENUM;
-
- //获取该页的结尾地址
- GetPageEndAddr(PageNum, &PageEndAddr);
-
- //从页尾开始检索空闲空间
- RetrieveAddr = PageEndAddr;
- for(i = 0;i<PAGE_INT_SIZE;i++)
- {
- RetrieveAddr -= 4;
- Read_N_4Byte_flash(RetrieveAddr , &flash_data, 4);
-
- if(flash_data != 0xFFFFFFFF)break;
-
- }
- *start_addr = PageEndAddr - i *4;
- *len = i*4;
-
- return FLASH_OP_SUCCESS;
- }
- /****************************************************END OF FILE****************************************************/
|