打印
[应用方案]

新唐 cortex - m0 FMC的使用

[复制链接]
453|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主

在有联网需求的嵌入式项目中经常有场景需要本地能够保存一些掉电不丢失的消息,比如区分冷热启动或者保存离线数据等等。
在需要保存数据的量比较小的时候为了节约成本,可以不用外部FLASH或EEPROM,使用主控的内部空间。

下面介绍周星星在新唐单片机开发之旅中的景点FM
C。

————————————————版权声明:本文为CSDN博主「Leanthink」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/Leanthink/article/details/89309253

使用特权

评论回复
沙发
gaonaiweng|  楼主 | 2022-12-25 13:44 | 只看该作者
基础操作
打开FMC驱动的头文件,找到我需要的四个基础函数:
1、使能函数;
2、读函数;
3、写函数;
4、擦除函数。
然后我先封装了一个任意地址写任意数量数据再验证。
嗯,失败了。
应该是封装的函数有问题吧。
这里提醒某些小伙伴一句千万不要像阿星一样驱动函数都没验证OK,先把应用代码敲完了。
有这个习惯的小伙伴可能认为反正驱动函数有问题后面再调,开发顺序正反都一样,况且官方的库函数怎么可能有问题呢。但是领导看见你搞了半天没有进度,他可是会着急的哦。
封装的函数验证失败后,我用库文件的3个元函数重新验证。伪代码如下:
fmc_open();
fmc_write(addr,data);
if(data == fmc_read(addr))
printf(“ok !\r\n”);
else
printf(“err !\r\n”);
打印结果是err。

使用特权

评论回复
板凳
gaonaiweng|  楼主 | 2022-12-25 13:45 | 只看该作者
使能,写,读。
这个流程有问题吗?
我找到官方的例程,下载进去,验证OK。
我把自己的代码放到例程的初始化后面,验证OK。
有问题,初始化的问题!
可是例程初始化跟FMC相关的只有一个使能,而使能我也用了。
难道这个IC有自己的想法。
就在阿星胡思乱想的时候,公司的老司机指点了一句。
有没有去除写保护呢?

使用特权

评论回复
地板
gaonaiweng|  楼主 | 2022-12-25 13:46 | 只看该作者
这个时候我再看例程的初始化。

使用特权

评论回复
5
gaonaiweng|  楼主 | 2022-12-25 13:47 | 只看该作者
我找到了问题的关键:
在写操作之前没有去除写保护。

使用特权

评论回复
6
gaonaiweng|  楼主 | 2022-12-25 13:49 | 只看该作者
任意数量写函数代码
水泥砖没问题了我们再来砌墙。
下面贴出我封装函数的代码。

void fmc_wr(uint32_t start_addr,uint32_t num_to_wr,void *pbuf)
{
uint32_t *buf = pbuf;
uint32_t w_start_addr = start_addr;
uint32_t page_offset = start_addr&0x1ff;
uint32_t page_start = start_addr - page_offset;
uint32_t page_end = page_start + FMC_FLASH_PAGE_SIZE;
uint32_t w_end_addr = 0;
uint32_t page_remain =FMC_PAGE_WORDS - (page_offset>>2);
uint32_t buf_loop = 0,adr_loop = 0;
if(page_remain > num_to_wr)
page_remain = num_to_wr;
w_end_addr = w_start_addr + (page_remain<<2);
SYS_UnlockReg();
while(1)
{
if(VerifyData( w_start_addr, w_end_addr, 0xffffffff))
{
buf_loop = 0;
for(adr_loop = 0; adr_loop < page_offset; adr_loop += 4)
{
fmc_page_buf[buf_loop++] = FMC_Read(page_start+adr_loop);
}
for(adr_loop = w_start_addr; adr_loop < w_end_addr; adr_loop+=4)
{
fmc_page_buf[buf_loop++] = *buf;
buf++;
}
for(adr_loop = w_end_addr; adr_loop < page_end; adr_loop+=4)
{
fmc_page_buf[buf_loop++] = FMC_Read(adr_loop);
}
FMC_Erase(page_start);
fmc_wr_nochk(page_start,page_end,fmc_page_buf);
}
else
{
fmc_wr_nochk(w_start_addr,w_end_addr,buf);
buf += page_remain;
}
if(num_to_wr == page_remain)
break;
page_start += FMC_FLASH_PAGE_SIZE;
page_end += FMC_FLASH_PAGE_SIZE;
w_start_addr += (page_remain<<2);
page_offset = 0;
num_to_wr -= page_remain;
if(FMC_PAGE_WORDS >= num_to_wr)
page_remain = num_to_wr;
else
page_remain = FMC_PAGE_WORDS;
w_end_addr = w_start_addr + (page_remain<<2);
}

使用特权

评论回复
7
gaonaiweng|  楼主 | 2022-12-25 14:07 | 只看该作者
在测试这个函数的时候阿星又犯了一个低级错误。
现象是做可靠性测试时,每过一段时间验证会失败一次,而且一旦失败,程序就在下图函数中死掉了。

使用特权

评论回复
8
gaonaiweng|  楼主 | 2022-12-25 14:08 | 只看该作者

使用特权

评论回复
9
gaonaiweng|  楼主 | 2022-12-25 14:09 | 只看该作者
来发现测试函数中有个变量表示验证数组的元素位置,而这个变量在定时中断里有赋值的地方。结果出现了越界错误。
最后还有一点值得小伙伴在涉及FLASH开发中考虑,就是FLASH的擦写次数。一般FLASH的擦写次数在1万~10万次左右。如果可以的话尽量在低电或重启等情况在写入FLASH减少FLASH的擦写次数。

使用特权

评论回复
10
nongshengjiang| | 2022-12-25 15:11 | 只看该作者
新的资料做得不到位,一大堆废话,主次不分。有关联的寄存器有时候根本不提。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

69

主题

697

帖子

3

粉丝