RT1064之Flash例程
Ps:本例程主要作用是,展示如何使用FLASH储存数据的概念
主板为:逐飞RT1064 + 母板
一,NAND flash 控制原理(基于RT1052)
NAND flash 作用类似于电脑的固态硬盘,主要用于存储数据。相同容量 NAND flash要比 Nor flash 便宜很多, NAND flash 只能按页读、写,所以在 NAND flash 中不能执行代码。 NAND flash 一般容量较大,用于存储大量的数据。
二,FLASH宏定义介绍
1)FLAHS扇区
//定义flash最后一个扇区,避免与程序冲突
//存储参数最好从最后一个扇区开始使用
#define EXAMPLE_FLASH_SECTOR (FLASH_SECTOR_NUM-1)
2)FLASH所在扇区页编号
//定义所在扇区的页编号
#define EXAMPLE_FLASH_SECTOR_PAGE (0)
3)存储参数的个数
#define FLASH_SAVE_NUM 4
//宏定义需要存储参数的个数 一个页最多为256字节,一个参数需要占4个字节,因此最多这里为256/4=64
4)读与写的数据
uint8 write_data1;
uint16 write_data2;
uint32 write_data3;
float write_data4;
uint8 read_data1;
uint16 read_data2;
uint32 read_data3;
float read_data4;
uint8 read_data11;
uint16 read_data22;
uint32 read_data33;
float read_data44;
//存储数据数组
uint32 write_buf[FLASH_SAVE_NUM];
uint32 read_buf[FLASH_SAVE_NUM];
三,关于flash的相关函数
1)flash_init()
//-------------------------------------------------------------------------------------------------------------------
// @brief flash初始化
// @param void
// @return 返回1有表示失败 返回0表示成功
// @since v1.0
// Sample usage:
//-------------------------------------------------------------------------------------------------------------------
uint8 flash_init(void)
2)flash_check()
//-------------------------------------------------------------------------------------------------------------------
// @brief 校验FLASH是否有数据
// @param sector_num 需要写入的扇区编号 参数范围0-1023
// @param page_num 当前扇区页的编号 参数范围0-255
// @return 返回1有数据,返回0没有数据,如果需要对有数据的区域写入新的数据则应该对所在扇区进行擦除操作
// @since v1.0
// Sample usage: flash_check(500,0);//校验500号扇区,第0页是否有数据
//-------------------------------------------------------------------------------------------------------------------
uint8 flash_check(uint32 sector_num, uint32 page_num)
3)flash_erase_sector()
/-------------------------------------------------------------------------------------------------------------------
// @brief 擦除扇区
// @param sector_num 需要写入的扇区编号 参数范围0-1023
// @return 返回1有表示失败 返回0表示成功
// @since v1.0
// Sample usage: flash_erase_sector(500);
//-------------------------------------------------------------------------------------------------------------------
uint8 flash_erase_sector(uint32 sector_num)
4)flash_page_program()
/-------------------------------------------------------------------------------------------------------------------
// @brief 编程一页
// @param sector_num 需要写入的扇区编号 参数范围0-1023
// @param page_num 需要写入的页编号 参数范围0-255
// @param buf 需要写入的数据地址 传入的数组类型必须为uint32
// @param len 需要写入的数据长度 参数范围1-64
// @return 返回1有表示失败 返回0表示成功
// @since v1.0
// Sample usage:
//-------------------------------------------------------------------------------------------------------------------
uint8 flash_page_program(uint32 sector_num, uint32 page_num, const uint32 *buf, uint8 len)
5)flash_read_page()
//-------------------------------------------------------------------------------------------------------------------
// @brief 编程一页
// @param sector_num 需要读取的扇区编号 参数范围0-1023
// @param page_num 需要读取的页编号 参数范围0-255
// @param buf 需要读取的数据地址 传入的数组类型必须为uint32
// @param len 需要读取的数据长度 参数范围1-64
// @return 返回1有表示失败 返回0表示成功
// @since v1.0
// Sample usage:
//-------------------------------------------------------------------------------------------------------------------
void flash_read_page(uint32 sector_num, uint32 page_num, uint32 *buf, uint8 len)
四,关于数据的写入与读取
1.关于数据的写入
//设置需要写入的数据
write_data1 = 66;
write_data2 = 6666;
write_data3 = 666666;
write_data4 = 6666.66;
if(flash_check(EXAMPLE_FLASH_SECTOR,EXAMPLE_FLASH_SECTOR_PAGE))//校验当前 扇区所在页是否有数据,如果有数据则擦除整个扇区
{
status = flash_erase_sector(EXAMPLE_FLASH_SECTOR);//擦除扇区,如果扇区已经有数据则必须擦除扇区之后才能再次写入新的数据
if(status) while(1);//擦除失败
}
write_buf[0] = write_data1;
write_buf[1] = write_data2;
write_buf[2] = write_data3;
//存储浮点时,首先取变量地址然后以uint32 *来访问变量获取数据。
//write_buf[3] = *(uint32 *)&write_data4;
//不能使用此类格式write_buf[3] = (uint32)write_data4;这样会导致强制转换为整型,导致小数部分丢失
//也可以使用库提供的宏定义 读取float类型的二进制数据
write_buf[3] = float_conversion_uint32(write_data4); //
status = flash_page_program(EXAMPLE_FLASH_SECTOR, EXAMPLE_FLASH_SECTOR_PAGE, write_buf, FLASH_SAVE_NUM);
if(status) while(1);//写入失败
2.关于数据的读取
//读取数据有两个方式
//第一种方式为全部读取出来放在数组里,然后自行分配
flash_read_page(EXAMPLE_FLASH_SECTOR, EXAMPLE_FLASH_SECTOR_PAGE, read_buf, FLASH_SAVE_NUM);
//分别读取对应数据
read_data1 = read_buf[0];
read_data2 = read_buf[1];
read_data3 = read_buf[2];
read_data4 = uint32_conversion_float(read_buf[3]); //读取浮点数时,应该使用宏函数将uint32类型转换为float
//第二种方式,与以前的flash读取方式比较接近
DCACHE_CleanInvalidateByRange(FLASH_BASE_ADDR + EXAMPLE_FLASH_SECTOR * FLASH_SECTOR_SIZE, FLASH_SAVE_NUM*4);//读取flash前,最好先清空缓存
read_data11 = flash_read(EXAMPLE_FLASH_SECTOR,EXAMPLE_FLASH_SECTOR_PAGE*FLASH_PAGE_SIZE+0,uint8);
read_data22 = flash_read(EXAMPLE_FLASH_SECTOR,EXAMPLE_FLASH_SECTOR_PAGE*FLASH_PAGE_SIZE+1,uint16);
read_data33 = flash_read(EXAMPLE_FLASH_SECTOR,EXAMPLE_FLASH_SECTOR_PAGE*FLASH_PAGE_SIZE+2,uint32);
read_data44 = flash_read(EXAMPLE_FLASH_SECTOR,EXAMPLE_FLASH_SECTOR_PAGE*FLASH_PAGE_SIZE+3,float);
五,整体主函数代码
int main(void)
{
DisableGlobalIRQ();
board_init(); //务必保留,本函数用于初始化MPU 时钟 调试串口
flash_init(); //初始化flash
//设置需要写入的数据
write_data1 = 66;
write_data2 = 6666;
write_data3 = 666666;
write_data4 = 6666.66;
if(flash_check(EXAMPLE_FLASH_SECTOR,EXAMPLE_FLASH_SECTOR_PAGE))//校验当前 扇区所在页是否有数据,如果有数据则擦除整个扇区
{
status = flash_erase_sector(EXAMPLE_FLASH_SECTOR);//擦除扇区,如果扇区已经有数据则必须擦除扇区之后才能再次写入新的数据
if(status) while(1);//擦除失败
}
write_buf[0] = write_data1;
write_buf[1] = write_data2;
write_buf[2] = write_data3;
//存储浮点时,首先取变量地址然后以uint32 *来访问变量获取数据。
//write_buf[3] = *(uint32 *)&write_data4;
//不能使用此类格式write_buf[3] = (uint32)write_data4;这样会导致强制转换为整型,导致小数部分丢失
//也可以使用库提供的宏定义 读取float类型的二进制数据
write_buf[3] = float_conversion_uint32(write_data4); //
status = flash_page_program(EXAMPLE_FLASH_SECTOR, EXAMPLE_FLASH_SECTOR_PAGE, write_buf, FLASH_SAVE_NUM);
if(status) while(1);//写入失败
//读取数据有两个方式
//第一种方式为全部读取出来放在数组里,然后自行分配
flash_read_page(EXAMPLE_FLASH_SECTOR, EXAMPLE_FLASH_SECTOR_PAGE, read_buf, FLASH_SAVE_NUM);
//分别读取对应数据
read_data1 = read_buf[0];
read_data2 = read_buf[1];
read_data3 = read_buf[2];
read_data4 = uint32_conversion_float(read_buf[3]); //读取浮点数时,应该使用宏函数将uint32类型转换为float
//第二种方式,与以前的flash读取方式比较接近
DCACHE_CleanInvalidateByRange(FLASH_BASE_ADDR + EXAMPLE_FLASH_SECTOR * FLASH_SECTOR_SIZE, FLASH_SAVE_NUM*4);//读取flash前,最好先清空缓存
read_data11 = flash_read(EXAMPLE_FLASH_SECTOR,EXAMPLE_FLASH_SECTOR_PAGE*FLASH_PAGE_SIZE+0,uint8);
read_data22 = flash_read(EXAMPLE_FLASH_SECTOR,EXAMPLE_FLASH_SECTOR_PAGE*FLASH_PAGE_SIZE+1,uint16);
read_data33 = flash_read(EXAMPLE_FLASH_SECTOR,EXAMPLE_FLASH_SECTOR_PAGE*FLASH_PAGE_SIZE+2,uint32);
read_data44 = flash_read(EXAMPLE_FLASH_SECTOR,EXAMPLE_FLASH_SECTOR_PAGE*FLASH_PAGE_SIZE+3,float);
EnableGlobalIRQ(0);
//通过在线调试直接查看 read_data1 - read_data3 和 read_data11 - read_data33 变量的内容即可
//观察写入的数据与读出的数据是否一致
while(1)
{
}
}