这里简单记录一个单片机log日志方案:
该日志是记录在外部SPI的flash的,该方案任存在使用的bug,但是做日志的循环记录是足够了。
(1)这里需要了解的SPI flash 使用次数为10W次,该日志目标是错误日志。
(2)日志信息循环擦写的,但是索引不是,这个地方可以自己优化一下。
// 文件索引块结构(24字节)
typedef struct _file_block {
//用来记录扇区信息,先扇区定位
uint32_t file_block_base; // 起始扇区编号 相当于基地址
uint32_t file_block_start; // 起始扇区编号 循环记录的头
uint32_t file_block_end; // 结束扇区编号 循环记录的尾
uint32_t file_block_size; // 扇区数量 可用扇区的数量
uint32_t file_block_used_size; // 扇区占用数量 已经使用的扇区数量
//每个扇区进行数据包定位
uint32_t file_pack_end; // 存储的结束
uint32_t file_pack_size; // 存储区的字节数字
uint32_t first_init_flag; // 做初始化符号
} FileBlock;
#ifndef _FILESYS_H_
#define _FILESYS_H_
#include "main.h"
#define LOG_flash_message_addr (2 * 1024 * 1024)
#define LOG_flash_addr_end (5 * 1024 * 1024)
#define LOG_flash_addr_start (LOG_flash_message_addr+(4*1024))
#define LOG_flash_size ( (LOG_flash_addr_end - LOG_flash_message_addr ) - (4*1024) )
#define FLASH_MIN_SIZE 4096
#define LOGG_MIN_SIZE 64
// 文件索引块结构(24字节)
typedef struct _file_block {
uint32_t file_block_base; // 起始扇区编号
uint32_t file_block_start; // 起始扇区编号
uint32_t file_block_end; // 结束扇区编号
uint32_t file_block_size; // 扇区数量
uint32_t file_block_used_size; // 扇区占用数量
// 4096/64 =64 个空间存放字符串
uint32_t file_pack_end; // 存储的结束
uint32_t file_pack_size; // 存储区的字节数字
uint32_t first_init_flag;
} FileBlock;
void init_flash_log(void);
void read_file_log( void );
void clear_file_log( void );
void write_file_log(char* string);
int Flash_LOG_printf( const char *cmd_expr, ...);
#endif
#include "flash_log.h"
#include "log.h"
#include "usr_cfg.h"
uint8_t flash_log_temp[4096]={0};//flash 数据的暂存区
FileBlock file_block;
uint8_t file_log_is_on=0;
void read_index_message(void)
{
flash_read_page(LOG_flash_message_addr,flash_log_temp,4096);//读索引地址
memcpy((uint8_t *) &file_block,flash_log_temp,sizeof(file_block));
if(file_block.first_init_flag !=0x12345678)
{
file_block.file_block_base=LOG_flash_addr_start/4096; //(起始的偏移编号)
file_block.file_block_start=0; //存放消息循环队列的首
file_block.file_block_end=0; //存放消息循环队列的尾
file_block.file_block_size=(LOG_flash_size)/FLASH_MIN_SIZE; //存放消息循环队列包含的块个数
file_block.file_block_used_size=0;//存放消息循环队列使用块的个数
file_block.file_pack_end=0; //每个块尾部可写的位置 //尾部指向下一个可以写的地方
file_block.file_pack_size=FLASH_MIN_SIZE /LOGG_MIN_SIZE;//4096/64=64条
file_block.first_init_flag=0x12345678;
memcpy(flash_log_temp,(uint8_t *) &file_block,sizeof(file_block));
flash_write_page(LOG_flash_message_addr,flash_log_temp,sizeof(file_block));
flash_read_page(LOG_flash_message_addr,flash_log_temp,4096);
}
}
//获取block 如果满了就删除 delet_num 个扇区
//带回扇区编号
int get_malloc_block(void)
{
int delet_block=0;
if(file_block.file_block_used_size >= ( file_block.file_block_size ) )//接近满时候 删除起始的扇区
{
//删除报文首地址所在的扇区,注意报文的开始一定是扇区的首地址,但是报文的尾随便。
delet_block = ( file_block.file_block_base ) +(file_block.file_block_start);
flash_EraseSector(delet_block);
file_block.file_block_start= (file_block.file_block_start+1)%file_block.file_block_size;
file_block.file_block_used_size--;
}
return 0;
}
void open_log_function(void)
{
if(file_log_is_on==0)
{
read_index_message();//加载配置
}
}
void close_log_function(void)
{
file_log_is_on=0;
}
//读取所有log
void read_file_log( void )
{
#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
int i,j=0;
int read_block=0;
COLOR_RED_INFO(">>>> read log <<<<\r\n");
for(i=0;i<=file_block.file_block_used_size;i++)
{
read_block = ( file_block.file_block_base) + ( (file_block.file_block_start+i)%file_block.file_block_size );
flash_read_page(read_block*4096,flash_log_temp,4096);
for(j=0;j<FLASH_MIN_SIZE;j++)
{
if( __is_print(flash_log_temp[j]) )
{
printf("%c", flash_log_temp[j] );
}
if(flash_log_temp[j] ==0x0D ) printf("\r");
if(flash_log_temp[j] ==0x0A ) printf("\n");
}
}
COLOR_RED_INFO(">>>>*************<<<<\r\n");
}
//擦除所有log
void clear_file_log( void )
{
int i=0;
COLOR_RED_INFO(">>>> earse log <<<<\r\n");
for(i=0;i<= (LOG_flash_size/4096);i++)
{
flash_EraseSector((LOG_flash_addr_start/4096)+i);
progress_printf_bar( (i*100)/(LOG_flash_size/4096) );
}
printf("\r\n");
flash_EraseSector(LOG_flash_message_addr/4096);
file_block.file_block_base=LOG_flash_addr_start/4096; //(起始的偏移编号)
//block 编码 0-1790
file_block.file_block_start=0;
file_block.file_block_end=0;
file_block.file_block_size=(LOG_flash_size)/FLASH_MIN_SIZE;
file_block.file_block_used_size=0;
file_block.file_pack_end=0;
file_block.file_pack_size=FLASH_MIN_SIZE /LOGG_MIN_SIZE;
file_block.first_init_flag=0x12345678;
memset( flash_log_temp,0,sizeof(flash_log_temp));
memcpy(flash_log_temp,(uint8_t *) &file_block,sizeof(file_block));
flash_write_page(LOG_flash_message_addr,flash_log_temp,sizeof(file_block));
IWDT_Clr();
COLOR_RED_INFO(">>>>*************<<<<\r\n");
}
//写字符串到log空间 最大64个字符
void write_file_log(char* string)
{
uint32_t addr = get_malloc_block();//获取
// uint32_t offset = file_block.file_pack_end;
uint32_t read_block=0;
//读flash
COLOR_RED_INFO(">>>> write log <<<<\r\n");
read_block =( file_block.file_block_base + file_block.file_block_end );
//printf("new_addr: 0x%x\r\n",read_block);
flash_read_page(read_block*4096,flash_log_temp,4096);
memcpy(&flash_log_temp[file_block.file_pack_end*LOGG_MIN_SIZE],string,strlen(string));
//回写flash
flash_write_page(read_block*4096,flash_log_temp,4096);
file_block.file_pack_end+=1;
if(file_block.file_pack_end>=file_block.file_pack_size)
{
file_block.file_pack_end=0;
file_block.file_block_end=(file_block.file_block_end+1)%file_block.file_block_size;//寻找下一个扇区
file_block.file_block_used_size++;
}
//写回控制块
memset( flash_log_temp,0,sizeof(flash_log_temp));
memcpy( flash_log_temp,(uint8_t *) &file_block,sizeof(file_block)/sizeof(uint8_t));
flash_write_page(LOG_flash_message_addr,flash_log_temp,sizeof(file_block)/sizeof(uint8_t));
printf("%s",string);
COLOR_RED_INFO(">>>>*************<<<<\r\n");
}
//写字符串到log空间 最大64个字符
void printf_flash_log(char* string)
{
uint32_t addr = get_malloc_block();//获取
// uint32_t offset = file_block.file_pack_end;
uint32_t read_block=0;
//读flash
read_block =( file_block.file_block_base + file_block.file_block_end );
//printf("new_addr: 0x%x\r\n",read_block);
flash_read_page(read_block*4096,flash_log_temp,4096);
memcpy(&flash_log_temp[file_block.file_pack_end*LOGG_MIN_SIZE],string,strlen(string));
//回写flash
flash_write_page(read_block*4096,flash_log_temp,4096);
file_block.file_pack_end+=1;
if(file_block.file_pack_end>=file_block.file_pack_size)
{
file_block.file_pack_end=0;
file_block.file_block_end=(file_block.file_block_end+1)%file_block.file_block_size;//寻找下一个扇区
file_block.file_block_used_size++;
}
//写回控制块
memset( flash_log_temp,0,sizeof(flash_log_temp));
memcpy( flash_log_temp,(uint8_t *) &file_block,sizeof(file_block)/sizeof(uint8_t));
flash_write_page(LOG_flash_message_addr,flash_log_temp,sizeof(file_block)/sizeof(uint8_t));
printf("%s",string);
}