调试数据存储到nandflash的那些事儿(五):对nandflash的寻址说明

作为用户,操作nandflash大部分操作无非就是 读、写、格式化。其中读写都一定得需要目标地址。如何根据需求,设定寻址方法就显得不可缺少了。

比如说,需求是nandflash存储一年的分钟数据。请问如何存2019年8月21日00:00的分钟数据?一包分钟数据64字节

/*********************************************************************************************************
nandflsh共有1024块,1块=64页,1页=2048bytes

实时数据:
	存储一包64字节,一页可存 2048/64 = 32包;
	一共有 366*24*60 = 527040包 则共需要 527040/32 = 16470页;
	一共需要 16470/64     ~ 258 块
										
0	                                                                           1024块			
=========================================================================================
0		          258		
{	   实时数据	   }{	       实时数据	       }{	   实时数据	  }

*****************************************************************************************/
//nandflash的块数
#define NAND_BLOCKS				1024
//nandflash一块中的页数
#define NAND_PAGES_PER_BLOCK			64
//nandflash一页中的字节数
#define NAND_BYTES_PER_PAGE			2048
//一年的分钟数
#define MINUTES_PER_YEAR			(366*24*60)
//一个实时数据包大小
#define RT_PACKAGE_SIZE				64
//一页中可以存多少实时数据包
#define RT_PACKAGES_PER_PAGE			(NAND_BYTES_PER_PAGE/RT_PACKAGE_SIZE)
//一年数据所需要的页数
#define RT_PAGES_USED_ONE_YEAR			(MINUTES_PER_YEAR/RT_PACKAGES_PER_PAGE)
//实时数据初始页
#define RT_INITIAL_OFFSET         		0	

步骤:

1.我需要知道我一包64字节,如果存一年的数据,nandflash够不够。

366(一年最大天数)*24(小时)*60(分钟)= 527040 

总共需要527040*64(包大小)= 33730560字节

而nandflash一共128MB = 128*1024*1024 = 134217728字节

不仅够存,还能存134217728 / 33730560 ≈ 3.98年

当然上面的方法是很极限的存储方式,需要依次存满每一页,也就是说第一页存不完,往第二页接着存,这导致存储时很麻烦,甚至一包还会跨块。不是不可行,而是没必要使用如此紧凑,增加了底层的难度。

如果不让一包跨页,底层实现会更简单。

那么一页最多能存 2048%64 = 32包

一年最大需要存527040包,所以需要527040 /32 = 16470页

一共需要16470/64 = 258块。满足nandflash的存储条件。

2.分配空间的同时其实也想好了寻址方式。

从第1块开始存,每一页存32包分钟数据,一共能存258块。

回到开头提到的问题,如何存2019年8月21日00:00的分钟数据?

思路是根据时间计算分钟数,根据分钟数计算该存到nandflash的第几个字节。

这个时间是全年,所以从1月1日00:00到 8月21日00:00 一共是31+28+31+30+31+30+31+21 = 233天。也就是233*24*60 = 335520(分钟数)。

一页最多能存32包,所以一共需要335520/32 = 10485页 335520%32 = 0。所以这说明了这个时间是要存在第10485页的0页内偏移位置。

所以在nandflash中的位置是第10485*2048+0 = 21473280(字节)

3.将想法转换成函数

一共需要两个函数,一个是根据时间计算分钟数,所以入口参数是时间,返回分钟数

第二个是根据分钟数计算nandflash地址,入口参数为分钟数,返回地址

//月份天数
#define JAN_DAYS              31
#define FEB_DAYS              28
#define MAR_DAYS              31
#define APR_DAYS              30
#define MAY_DAYS              31
#define JUN_DAYS              30
#define JUL_DAYS              31
#define AUG_DAYS              31
#define SEP_DAYS              30
#define OCT_DAYS              31
#define NOV_DAYS              30
#define DEC_DAYS              31
#define LEAP_YEAR             1

#define JAN_OFFSET       0
#define FEB_OFFSET       (JAN_OFFSET + JAN_DAYS)
#define MAR_OFFSET       (FEB_OFFSET + FEB_DAYS)
#define APR_OFFSET       (MAR_OFFSET + MAR_DAYS)
#define MAY_OFFSET       (APR_OFFSET + APR_DAYS)
#define JUN_OFFSET       (MAY_OFFSET + MAY_DAYS)
#define JUL_OFFSET       (JUN_OFFSET + JUN_DAYS)
#define AUG_OFFSET       (JUL_OFFSET + JUL_DAYS)
#define SEP_OFFSET       (AUG_OFFSET + AUG_DAYS)
#define OCT_OFFSET       (SEP_OFFSET + SEP_DAYS)
#define NOV_OFFSET       (OCT_OFFSET + OCT_DAYS)
#define DEC_OFFSET       (NOV_OFFSET + NOV_DAYS)

/*
*********************************************************************************************************
*                                          Compute_CurrentMinutes
*
* Description : 由时间计算分钟数
* Arguments   : time:时间结构体指针
*
* Returns     : 分钟数
*********************************************************************************************************
*/
uint32_t Compute_CurrentMinutes(HexTime_Typedef* time)
{
	uint8_t  leap_year = 0;
	uint16_t days      = 0;

	if((time->year % 4) == 0)
	{
		leap_year = 1;
	}

	switch(time->month)
	{
		case JAN :
			days = JAN_OFFSET + (time->day );
			break;
		case FEB :
			days = FEB_OFFSET + (time->day );
			break;
		case MAR :
			days = MAR_OFFSET + (time->day ) + leap_year;
			break;
		case APR :
			days = APR_OFFSET + (time->day ) + leap_year;
			break;
		case MAY :
			days = MAY_OFFSET + (time->day ) + leap_year;
			break;
		case JUN :
			days = JUN_OFFSET + (time->day ) + leap_year;
			break;
		case JUL :
			days = JUL_OFFSET + (time->day ) + leap_year;
			break;
		case AUG :
			days = AUG_OFFSET + (time->day ) + leap_year;
			break;
		case SEP :
			days = SEP_OFFSET + (time->day ) + leap_year;
			break;
		case OCT :
			days = OCT_OFFSET + (time->day ) + leap_year;
			break;
		case NOV :
			days = NOV_OFFSET + (time->day ) + leap_year;
			break;
		case DEC :
			days = DEC_OFFSET + (time->day ) + leap_year;
			break;
		default: break;
	}

	return (((days-1) * 1440) + (time->hour*60) + time->minute);
}
//nandflash的块数
#define NAND_BLOCKS				1024
//nandflash一块中的页数
#define NAND_PAGES_PER_BLOCK			64
//nandflash一页中的字节数
#define NAND_BYTES_PER_PAGE			2048
//一年的分钟数
#define MINUTES_PER_YEAR			(366*24*60)
//一个实时数据包大小
#define RT_PACKAGE_SIZE				64
//一页中可以存多少实时数据包
#define RT_PACKAGES_PER_PAGE			(NAND_BYTES_PER_PAGE/RT_PACKAGE_SIZE)
//一年数据所需要的页数
#define RT_PAGES_USED_ONE_YEAR			(MINUTES_PER_YEAR/RT_PACKAGES_PER_PAGE)
//实时数据初始页
#define RT_INITIAL_OFFSET         		0		

/*
*********************************************************************************************************									  
*
* Description : 整数分钟数计算存储地址
* Arguments   : minute :当前分钟数
* Returns     : 存储器地址(字节)
* Note	      :
*********************************************************************************************************
*/
uint32_t Air_CalculateAddr(HexTime_Typedef* tTime)
{
	uint32_t	PageNum;         //第几页
	uint32_t	Inner_Offset;    //页内偏移
	uint32_t	_cMinute = Compute_CurrentMinutes(tTime);

	//算所需数据所在页数 = 第几页 + nand初始页号
	PageNum 	= _cMinute / RT_PACKAGES_PER_PAGE + RT_INITIAL_OFFSET;
			
	Inner_Offset	= (_cMinute % RT_PACKAGES_PER_PAGE) * RT_PACKAGE_SIZE;

	return (PageNum * 2048 + Inner_Offset);
}

 


地址找的对,包内数据的排放顺序又是已知的,存入和读出应该就不难了。

发布了26 篇原创文章 · 获赞 0 · 访问量 3001

猜你喜欢

转载自blog.csdn.net/nianzhu2937/article/details/99977266
今日推荐