嵌入式设备一般都处理一些数据,大多都是通过flash分块来管理。
如下示例写入一些调试数据到flash
dump.c
#include <stdlib.h> #include <string.h> #include "drivers/spi_flash.h" #define DEBUG_DATA_START 705 #define DEBUG_DATA_NB_BLOCKS 255 #define DEBUG_DATA_ITEM_COUNT (255*255) typedef struct { uint32_t id; uint32_t time; uint16_t battery_level; uint16_t battery_vbat; uint16_t boot_target; uint16_t wakelock_lock; }debug_data_item_t; static uint32_t spi_flash_get_debug_item_id(void) { struct td_device *spi_flash_handler =(struct td_device *)&pf_sba_device_flash_spi0; unsigned int retlen; uint32_t item_cnt; uint32_t spi_addr = DEBUG_DATA_START * SERIAL_FLASH_BLOCK_SIZE; spi_flash_read(spi_flash_handler,spi_addr,1,&retlen,&item_cnt); if(item_cnt==0xffffffff) return 0; else return item_cnt; } static void spi_flash_write_debug_item(uint32_t itemOffset,uint8_t itemCount,void *data) { struct td_device *spi_flash_handler =(struct td_device *)&pf_sba_device_flash_spi0; unsigned int retlen; DRIVER_API_RC ret = spi_flash_sector_erase(spi_flash_handler, DEBUG_DATA_START, 1); uint32_t spi_addr = DEBUG_DATA_START * SERIAL_FLASH_BLOCK_SIZE; uint32_t item_offset_v = itemOffset+itemCount; ret = spi_flash_write(spi_flash_handler, spi_addr, 1,&retlen, &item_offset_v); spi_addr += SERIAL_FLASH_BLOCK_SIZE * 1 + itemOffset*sizeof(debug_data_item_t); ret = spi_flash_write(spi_flash_handler, spi_addr , sizeof(debug_data_item_t)*itemCount/4,&retlen,data); } static void spi_flash_read_debug_item(uint32_t itemOffset,uint8_t itemCount, debug_data_item_t *data_read) { struct td_device *spi_flash_handler =(struct td_device *)&pf_sba_device_flash_spi0; unsigned int retlen; uint32_t* data_tmp; data_tmp = balloc((itemCount) * sizeof(debug_data_item_t), NULL); uint32_t spi_addr = DEBUG_DATA_START * SERIAL_FLASH_BLOCK_SIZE; spi_addr += SERIAL_FLASH_BLOCK_SIZE * 1 + (itemOffset*sizeof(debug_data_item_t)); spi_flash_read(spi_flash_handler, spi_addr ,sizeof(debug_data_item_t)*itemCount/4,&retlen,data_tmp); uint8_t i=0; uint8_t j=0; while(i < 4*itemCount) { data_read[j].id =data_tmp[i]; data_read[j].time =data_tmp[i+1]; data_read[j].battery_level =(uint16_t)data_tmp[i+2]; data_read[j].battery_vbat =(uint16_t)(data_tmp[i+2]>>16); data_read[j].boot_target =(uint16_t)data_tmp[i+3]; data_read[j].wakelock_lock =(uint16_t)(data_tmp[i+3]>>16); i=i+4; j++; } bfree(data_tmp); } extern uint16_t battery_level; extern uint16_t battery_vbat; extern enum get_boot_target(); extern uint16_t wakeup_lock(); void debug_data_write() { debug_data_item_t data; uint32_t id_offset = spi_flash_get_debug_item_id(); if(id_offset >= DEBUG_DATA_ITEM_COUNT) return; data.id=id_offset; data.time=utc_time_read(); data.battery_level=battery_level; data.battery_vbat= battery_vbat; data.boot_target = (uint16_t)get_boot_target(); data.wakelock_lock = wakeup_lock(); spi_flash_write_debug_item(data.id,1,&data); } void debug_data_read(uint32_t itemOffset,uint8_t itemCount, debug_data_item_t *data_read) { if(itemOffset >= DEBUG_DATA_ITEM_COUNT) return; spi_flash_read_debug_item(itemOffset,itemCount, data_read); } void debug_data_erase(void) { struct td_device *spi_flash_handler =(struct td_device *)&pf_sba_device_flash_spi0; spi_flash_sector_erase(spi_flash_handler, DEBUG_DATA_START, DEBUG_DATA_NB_BLOCKS); } void debug_data_erase_item(uint32_t item_cnt) { struct td_device *spi_flash_handler =(struct td_device *)&pf_sba_device_flash_spi0; spi_flash_sector_erase(spi_flash_handler,DEBUG_DATA_START, (item_cnt*sizeof(debug_data_item_t) / SERIAL_FLASH_BLOCK_SIZE)+2); } int main(void) { time_60s_cnt++; if(time_60s_cnt % 12 == 0) debug_data_write(); return 0; }
通过app来导出flash中的数据
dump_app.c
void shoes_debug_upload(uint8_t* buf, uint16_t len) { uint16_t block_cnt = 0, remain_cnt = 0, i = 0; block_cnt = len / BLE_UART_MAX_CHAR_LEN; remain_cnt = len % BLE_UART_MAX_CHAR_LEN; for (i = 0; i < block_cnt; i++) { bt_gatt_notify(NULL,shoes_debug_value, buf + i * BLE_UART_MAX_CHAR_LEN,BLE_UART_MAX_CHAR_LEN,NULL); //local_task_sleep_ms(10); } if (remain_cnt > 0) { bt_gatt_notify(NULL,shoes_debug_value, buf + block_cnt*BLE_UART_MAX_CHAR_LEN, remain_cnt,NULL); } } ssize_t on_debug_data_write(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, uint16_t len, uint16_t offset) { if (len!=2) return 0; if(!data_is_synchronizing){ debug_data_write(); data_is_synchronizing = true; } uint8_t para[2]; memcpy(para,buf,2); uint16_t block_index =( (uint16_t)(para[1]) | (uint16_t)(para[0]) << 8); uint8_t item_valid; uint16_t block_total; uint32_t item_id = spi_flash_get_debug_item_id(); if( item_id%ITEM_NUM_ONE_BLOCK == 0) block_total=(uint16_t)((item_id)/ITEM_NUM_ONE_BLOCK); else block_total=(uint16_t)((item_id)/ITEM_NUM_ONE_BLOCK+1); pr_info(LOG_MODULE_MAIN, "item_id:%d block_index:%d block_total:%d", item_id,block_index, block_total); if(block_index >= block_total) { shoes_debug_upload((uint8_t*)buf,len); data_is_synchronizing = false; return 0; } if((item_id % ITEM_NUM_ONE_BLOCK) && (block_index == block_total-1)) item_valid = (item_id) % ITEM_NUM_ONE_BLOCK; else item_valid = ITEM_NUM_ONE_BLOCK; pr_info(LOG_MODULE_MAIN, "item_valid:%d", item_valid); debug_data_item_t debug_sport_data[ITEM_NUM_ONE_BLOCK]; debug_data_read(block_index*ITEM_NUM_ONE_BLOCK,item_valid,debug_sport_data); for(int j=0;j<item_valid;j++) pr_info(LOG_MODULE_MAIN, "time:0x%x,battery_l:0x%x,battery_v:0x%x,boot_target:0x%x,wakelock:0x%x",debug_sport_data[j].time,debug_sport_data[j].battery_level,debug_sport_data[j].battery_vbat,debug_sport_data[j].boot_target,debug_sport_data[j].wakelock_lock); uint8_t send_app_data_info[5+ITEM_NUM_ONE_BLOCK*13] = { (uint8_t)(block_index >> 8), (uint8_t)block_index, (uint8_t)(block_total >> 8), (uint8_t)block_total, item_valid*13, //len }; uint16_t i = 0; for(i=0;i<item_valid;i++) { send_app_data_info[5+i*13]=(uint8_t)(debug_sport_data[i].time); send_app_data_info[6+i*13]=(uint8_t)(debug_sport_data[i].time >> 24); send_app_data_info[7+i*13]=(uint8_t)(debug_sport_data[i].time >> 16); send_app_data_info[8+i*13]=(uint8_t)(debug_sport_data[i].time >> 8); send_app_data_info[9+i*13]=(uint8_t)debug_sport_data[i].time; send_app_data_info[10+i*13]=(uint8_t)(debug_sport_data[i].battery_level >> 8); send_app_data_info[11+i*13]=(uint8_t)debug_sport_data[i].battery_level; send_app_data_info[12+i*13]=(uint8_t)(debug_sport_data[i].battery_vbat >> 8); send_app_data_info[13+i*13]=(uint8_t)debug_sport_data[i].battery_vbat; send_app_data_info[14+i*13]=(uint8_t)(debug_sport_data[i].boot_target >> 8); send_app_data_info[15+i*13]=(uint8_t)debug_sport_data[i].boot_target; send_app_data_info[16+i*13]=(uint8_t)(debug_sport_data[i].wakelock_lock >> 8); send_app_data_info[17+i*13]=(uint8_t)debug_sport_data[i].wakelock_lock; } if(block_index == block_total-1){ debug_data_erase_item(item_id); data_is_synchronizing = false; } shoes_debug_upload(send_app_data_info,send_app_data_info[4]+5); return len; }
以上数据存储与导出都是按字(4字节)来处理的,如果按字节呢,要转换一下数据长度
uint8_t spi_flash_data_read(uint8_t * buf, int len,uint32_t add){ uint32_t retlen = 0, real_len, *data_buf; DRIVER_API_RC ret; struct td_device *spi_flash_handler = (struct td_device *)&pf_sba_device_flash_spi0; if(buf == NULL || len <= 0){ return -1; } real_len = (len + 3) / 4; data_buf = (uint32_t *)malloc(real_len * sizeof(uint32_t)); if(NULL == data_buf) { return -1; } ret = spi_flash_read(spi_flash_handler, add, real_len, &retlen, data_buf); if(DRV_RC_OK != ret || real_len != retlen) { free(data_buf); return -1; } memcpy(buf, (uint8_t *)data_buf, len); free(data_buf); return 0; } uint8_t spi_flash_data_write(uint8_t* buf, int len,uint32_t add){ uint32_t retlen = 0, real_len, *data_buf; DRIVER_API_RC ret; struct td_device *spi_flash_handler = (struct td_device *)&pf_sba_device_flash_spi0; if(buf == NULL || len <= 0){ return -1; } real_len = (len + 3) / 4; data_buf = (uint32_t *)malloc(real_len * sizeof(uint32_t)); if(NULL == data_buf) { return -1; } else { memcpy((uint8_t *)data_buf, buf, len); } ret = spi_flash_block_erase(spi_flash_handler, UER_ID_OFFSET, 1); ret = spi_flash_write(spi_flash_handler, add, real_len, &retlen, data_buf); if(DRV_RC_OK != ret || real_len != retlen) { free(data_buf); return -1; } free(data_buf); return 0; }
以上都是些调试代码,没有成体系比较零散,对于flash数据块的管理,在固件设计中非常重要,后面遇上再整理。