debug中遇到的問題:
1,寫入數據,讀出來不對
2,看之前被人寫的代碼發現,讀flash直接用的標准C庫函數:memcpy,但是,寫用的專門的flash寫接口。所以,我這里兩個疑問:
A,寫flash的時候,為什么沒有用memcpy,可不可以用?
B,用const 修飾的全局變量是存儲在ROM空間的(也就是內置flash上),沒有用const修飾的全局變量 和 局部變量是存儲在RAM空間上的。
比如 有個全局const 變量 A,全局變量 B,那么,memcpy(B,A)為什么就能正確執行,他們兩個都在不同的地址空間中?
flash相關的知識點:
1,從datasheet中 Memroy章節 圖:Memory Layout(如下) 中可以看到,Flash分為很多page,每個page又分為8個block。每個page的大小為4KBytes。
代碼實現:
#include "stdint.h" #define FLASH_PAGE_SIZE 4096 #define FLASH_BASE_ADDRESS 0x6D000 #define FLASH_SIZE ( FLASH_PAGE_SIZE<<1) enum { WSYS_FLASH_OK = 0, WSYS_FLASH_INVALID_ADDRESS, WSYS_FLASH_INVALID_LENGTH }; /******************************************************************* * Function Nume: flash_read_data * Descriptions : read data from flash * In Para : address: address to access(address must be word-aligned), length: length to be read(4 integer multiple) * In-Out Para : none * Out Para : data: data buffer to be read * Return Value : FLASH_SUCCESS: success, FLASH_ERROR_INVALID_ADDRESS: address error *******************************************************************/ uint8_t flash_write_data(uint32_t address, uint8_t *data, uint16_t length); /******************************************************************* * Function Nume: flash_read_data * Descriptions : read data from flash * In Para : address: address to access(align=2), length: length to be read(4 integer multiple) * In-Out Para : none * Out Para : data: data buffer to be read * Return Value : FLASH_SUCCESS: success, FLASH_ERROR_INVALID_ADDRESS: address error *******************************************************************/ uint8_t flash_read_data(uint32_t address, uint32_t *data, uint16_t length); /******************************************************************* * Function Nume: flash_erase_data * Descriptions : erase flash data * In Para : address: address to access(align=2), length: length to be erased(4 integer multiple) * In-Out Para : none * Out Para : none * Return Value : FLASH_SUCCESS: success, FLASH_ERROR_INVALID_ADDRESS: address error *******************************************************************/ uint8_t flash_erase_data(uint32_t address, uint16_t length);
static void fstorage_evt_handler(nrf_fstorage_evt_t * p_evt); static uint32_t sg_flash_buffer[FLASH_PAGE_SIZE/4] = {0}; NRF_FSTORAGE_DEF(nrf_fstorage_t fstorage) = { /* Set a handler for fstorage events. */ .evt_handler = fstorage_evt_handler, /* 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 = FLASH_BASE_ADDRESS, .end_addr = (FLASH_BASE_ADDRESS + FLASH_SIZE), }; static void fstorage_evt_handler(nrf_fstorage_evt_t * p_evt) { if (p_evt->result != NRF_SUCCESS) { WLOG_I("--> Event received: ERROR while executing an fstorage operation.\r\n"); return; } switch (p_evt->id) { case NRF_FSTORAGE_EVT_WRITE_RESULT: { WLOG_I("--> Event received: write %d bytes at address 0x%x.\r\n", p_evt->len, p_evt->addr); } break; case NRF_FSTORAGE_EVT_ERASE_RESULT: { WLOG_I("--> Event received: erased %d page from address 0x%x.\r\n", p_evt->len, p_evt->addr); } break; default: break; } } static void wait_for_flash_ready(void) { /* While fstorage is busy, sleep and wait for an event. */ while (nrf_fstorage_is_busy(&fstorage)) { ; } } static void flash_read(uint32_t dest_addr, uint32_t src_addr, uint16_t length) { memcpy((uint32_t*)dest_addr, (uint32_t*)src_addr, length); //nrf_fstorage_read(&fstorage, (uint32_t)src, (void *)dest, (length / 4)); } /******************************************************************* * Function Nume: flash_write_check * Descriptions : it is need write or not * In Para : m_flash_handle: pointer of the pstorage, data: data to be writed, length: length of the data, offset: offset in flash * In-Out Para : none * Out Para : none * Return Value : 1: need write, 0: do not need write *******************************************************************/ static uint8_t flash_write_check(uint32_t address, const uint8_t *data, uint16_t length) { uint32_t data_read = 0; const uint32_t *p_src_data = (const uint32_t *)data; length = length / 4; for (uint16_t i=0; i<length; i++) { flash_read((uint32_t)&data_read, address + i*4 , 4); //if (memcmp(&data_read, &p_src_data[i], 4) != 0) if (data_read != p_src_data[i]) { return 1; } } WLOG_I("flash_write_check no need write\r\n"); return 0; } /******************************************************************* * Function Nume: flash_erase_check * Descriptions : it is need erase or not * In Para : m_flash_handle: pointer of the pstorage, length: length of the data, offset: offset in flash * In-Out Para : none * Out Para : none * Return Value : 1: need erase, 0: do not need erase *******************************************************************/ static uint8_t flash_erase_check(uint32_t dest_addr, uint16_t length) { uint32_t data_read = 0; uint32_t data_default = 0xFFFFFFFF; length = length / 4; for (uint16_t i=0; i<length; i++) { flash_read((uint32_t)&data_read, dest_addr + i*4 , 4); //if (memcmp(&data_read, &data_default, 4) != 0) if (data_default != data_read) { return 1; } } WLOG_I("flash_erase_check no need erse\r\n"); return 0; } static void flash_erase_one_page(uint32_t dest_addr, uint16_t length) { uint32_t result = 0; uint16_t offset = 0 ; uint16_t remain = 0; uint32_t page_start = dest_addr / FLASH_PAGE_SIZE * FLASH_PAGE_SIZE; memcpy(sg_flash_buffer, (uint32_t *)page_start, FLASH_PAGE_SIZE); if(1!= flash_erase_check(dest_addr, dest_addr)) { return; } result = nrf_fstorage_erase(&fstorage, page_start, 1, NULL); wait_for_flash_ready(); WLOG_I("FE==%d\r\n",result); offset = dest_addr - page_start; //Write back the data not need and can not be erased if (offset != 0) { nrf_fstorage_write(&fstorage, page_start, sg_flash_buffer, offset, NULL); wait_for_flash_ready(); } //Write back the data not need and can not be erased remain = FLASH_PAGE_SIZE - offset - length; if (remain != 0) { nrf_fstorage_write(&fstorage, (dest_addr + length), (uint32_t *)&sg_flash_buffer[(offset+length)/4], remain, NULL); wait_for_flash_ready(); } } static void flash_write(uint32_t address, uint8_t *src, uint16_t length) { uint32_t result = 0; if(1 != flash_write_check(address, src, length)) { return; } flash_erase_one_page(address, length); result = nrf_fstorage_write(&fstorage, address, (void const *)src,length/4*4, NULL); wait_for_flash_ready(); WLOG_I("FW==%d,length==%d\r\n",result,length); } static uint8_t valid_check(uint32_t address, uint16_t length) { if(address< FLASH_BASE_ADDRESS) { WLOG_E("flash_write_data invalid flash address\r\n"); return WSYS_FLASH_INVALID_ADDRESS; } if((address - FLASH_BASE_ADDRESS + length) > FLASH_SIZE) { WLOG_E("flash_write_data invalid length\r\n"); return WSYS_FLASH_INVALID_LENGTH; } return WSYS_FLASH_OK; } /******************************************************************* * Function Nume: flash_read_data * Descriptions : read data from flash * In Para : address: address to access(address must be word-aligned), length: length to be read(4 integer multiple) * In-Out Para : none * Out Para : data: data buffer to be read * Return Value : FLASH_SUCCESS: success, FLASH_ERROR_INVALID_ADDRESS: address error *******************************************************************/ uint8_t flash_write_data(uint32_t address, uint8_t *data, uint16_t length) { uint16_t length_temp = 0; uint16_t offset = address - FLASH_BASE_ADDRESS; uint8_t result = 0; result = valid_check(address,length); if(WSYS_FLASH_OK != result) return result; if ((offset + length) <= FLASH_PAGE_SIZE)//single page { flash_write(address, data, length); }else { //Multiple page length_temp = FLASH_PAGE_SIZE - offset; flash_write(address, data, length_temp); address += length_temp; data += length_temp; length_temp = length - length_temp; flash_write(address, data, length_temp); } return WSYS_FLASH_OK; } /******************************************************************* * Function Nume: flash_erase_data * Descriptions : erase flash data * In Para : address: address to access(align=2), length: length to be erased(4 integer multiple) * In-Out Para : none * Out Para : none * Return Value : FLASH_SUCCESS: success, FLASH_ERROR_INVALID_ADDRESS: address error *******************************************************************/ uint8_t flash_erase_data(uint32_t address, uint16_t length) { uint16_t length_temp = 0; uint16_t offset = address - FLASH_BASE_ADDRESS; uint8_t result = 0; result = valid_check(address,length); if(WSYS_FLASH_OK != result) return result; if ((offset + length) <= FLASH_PAGE_SIZE)//single page { flash_erase_one_page(address, length); }else { //Multiple page length_temp = FLASH_PAGE_SIZE - offset; flash_erase_one_page(address, length_temp); address += length_temp; length_temp = length - length_temp; while(length_temp > FLASH_PAGE_SIZE) { flash_erase_one_page(address, FLASH_PAGE_SIZE); length_temp -= FLASH_PAGE_SIZE; address += FLASH_PAGE_SIZE; } if(length_temp > 0) { flash_erase_one_page(address, length_temp); } } return WSYS_FLASH_OK; } /******************************************************************* * Function Nume: flash_read_data * Descriptions : read data from flash * In Para : address: address to access(align=2), length: length to be read(4 integer multiple) * In-Out Para : none * Out Para : data: data buffer to be read * Return Value : FLASH_SUCCESS: success, FLASH_ERROR_INVALID_ADDRESS: address error *******************************************************************/ uint8_t flash_read_data(uint32_t address, uint32_t *data, uint16_t length) { flash_read((uint32_t)data, address, length); return WSYS_FLASH_OK; } #if 1 #define add_len 4 void flash_test(void) { WLOG_I("flash_test\r\n"); //uint8_t *data_write = {"123456789ABCDEF0"}; uint8_t *data_write = {"123456789ABCDEF03333"}; #if 1 flash_write_data(FLASH_BASE_ADDRESS, data_write, 16+add_len); nrf_delay_ms(3000); #endif uint8_t data_read[17+add_len] = {0}; flash_read_data(FLASH_BASE_ADDRESS, (uint32_t*)data_read, 16+add_len); WLOG_I("FR: %s\r\n", data_read); //flash_erase_data(FLASH_BASE_ADDRESS,16+add_len); //flash_read_data(FLASH_BASE_ADDRESS, (uint32_t*)data_read, 16+add_len); //WLOG_I("FR_EEEE: %s\r\n", data_read); } #endif /******************************************************************* * Function Nume: flash_init * Descriptions : init internal flash * In Para : none * In-Out Para : none * Out Para : none * Return Value : state *******************************************************************/ Status_Type flash_init(void) { nrf_fstorage_api_t * p_fs_api; p_fs_api = &nrf_fstorage_sd; nrf_fstorage_init(&fstorage,p_fs_api,NULL); return STATUS_SUCCESS; } const struct file_operations flash_fops = { .module = FLASH_MODULE, .init = flash_init, };
sdk_config.h 中需要修改:#define NRF_FSTORAGE_ENABLED 1
問題解答:
問題2A:
Flash有一些特性,1,對flash的讀操作是沒有次數限制的,但是,對flash的擦除和寫操作是有次數限制的,這個和具體的芯片相關。如下是原文:
The Flash can be read an unlimited number of times by the CPU, but it has restrictions on the number of
times it can be written and erased and also on how it can be written.
2,寫入的時候只能寫入32bit字長的數據到字對齊的flash地址上,而且,flash的每個bit位上只能寫入0,不能寫1。要寫入1的話,只能通過擦除的方式,原文如下:
The NVMC is only able to write '0' to bits in the Flash that are erased, that is, set to '1'. It cannot write back a
bit to '1'.
3,flash擦除的時候 只能一個page一個page的擦除