打印
[N32G430]

读写内部FLASH

[复制链接]
375|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
qiufengsd|  楼主 | 2024-7-22 02:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

本文介绍N32G030K8L7(以下简称N32)的内部flash读写操作。

在N32的芯片手册可以看到,N32的数据字节是以小端格式储存的,即数据低位存储在地址低位,数据高位则存放在地址高位,位权匹配。

下面是N32的flash规格

本文是介绍flash的读写操作,所以重点放在主存储区。可以看到主存储区容量大小为64K,平均分为128个页,每个页就是0.5KB,用于用户程序的存放和运行。也就是是说我们写的程序是存储在flash的主存储区的。

对主存储器和信息块的写入由内嵌的闪存编程/擦除控制器管理。

闪存存储器有两种保护方式防止非法的访问(读、写、擦除):

  • 页写入保护(WRP)
  • 读出保护(RDP)

在执行闪存写操作时,任何对闪存的读操作都会锁住总线,在写操作完成后读操作才能正确地进行;

即在进行写或擦除操作时,不能进行代码或数据的读取操作。进行闪存编程操作时(写或擦除),必须打开内部的 RC 振荡器(HSI)。

注: 在低功耗模式下,所有闪存存储器的操作都被中止。

flash的规格就介绍完了,接下来开始flash的读写操作,先查阅一下芯片手册对读写操作的介绍:

通过芯片手册我们可以得知,flash在进行读操作前需要先进行flash的擦除(擦除的最小块为一个页,即0.5KB),而再擦除前还需要先进行flash模块的解锁。还有一个很关键的点为,

flash的写操作仅支持32位操作,即在进行写操作时,是一次性写入32位数据的,那么在进行写操作的时候需注意地址偏移。即写操作的大致流程为:

  • flash模块的解锁(写入特定的键值序列到FLASH_KEY寄存器中,即可解锁flash模块);
  • 对要写入数据的页进行擦除(擦除为1);
  • 写入数据到已经擦除的页;

我们来看下芯片手册中官方给出的具体的擦除(页擦除)写入操作流程:

擦除和写入的第一步,在上边都有提到,应该先检查此时是否在进行闪存的读取操作,通过FLASH_STS.BUSY位来进行判断。即该位为0时才能进行闪存操作。

在进行主存储区写入数据操作时,需注意一些细节。

  • 每次编程写入32位(即1个字)的数据,写入其他位数的数据,将产生总线错误,触发HardFault_Handler硬件错误中断;
  • 在进行任何读写闪存操作时,都会使CPU暂停,直至本次闪存操作结束,即在一次闪存操作没有结束前不能进行下一次闪存操作;

清楚了的flash的读写流程,下面我们看一下官方给的例程源码:

#include "main.h"#include <stdio.h>#define FLASH_PAGE_SIZE        ((uint16_t)0x200)        //512个字节#define FLASH_WRITE_START_ADDR ((uint32_t)0x08008000)#define FLASH_WRITE_END_ADDR   ((uint32_t)0x08010000)int main(void){    uint32_t Counter_Num = 0;    uint32_t Erase_Data  = 0xCDEF89AB;        /* Unlocks the FLASH Program Erase Controller */    FLASH_Unlock();    /* Erase */    if (FLASH_COMPL != FLASH_EraseOnePage(FLASH_WRITE_START_ADDR))    {        //FLASH擦除错误处理    }        /* Program */    for (Counter_Num = 0; Counter_Num < FLASH_PAGE_SIZE; Counter_Num += 4)    {        if (FLASH_COMPL != FLASH_ProgramWord(FLASH_WRITE_START_ADDR + Counter_Num, Erase_Data))        {            //写入操作错误处理        }    }        /* Locks the FLASH Program Erase Controller */    FLASH_Lock();    /* Check */    for (Counter_Num = 0; Counter_Num < FLASH_PAGE_SIZE; Counter_Num += 4)    {        if (Erase_Data != (*(__IO uint32_t*)(FLASH_WRITE_START_ADDR + Counter_Num)))        {            //检查错误处理        }    }        while (1)    {    }}   

上面是官方给予的例程源码,我在此基础上删掉了一些与flash操作无关的操作。

可以看到,官方在进行写操作时,也是按照流程来的:

  • 进行flash模块的解锁,通过调用flash解锁函数,FLASH_Unlock();
  • 在需要写入的页进行页擦除,通过调用页擦除函数,FLASH_EraseOnePage(uint32_t Page_Address),参数为需擦除页的起始地址;
  • 在已经擦除的页进行写操作,通过调用字编程函数,FLASH_ProgramWord(uint32_t Address, uint32_t Data),第一个参数为要写入的起始地址,第二个参数为要写入的数据(注意为32位);
  • 对写入的数据进行检查,将写入的数据读出再与源数据进行对比,读取flash数据可以使用下面的形式
Data = (*(__IO uint32_t*)(DataAddr));        //将DataAddr所指向的内存地址中的值作为一个32位无符号整数(uint32_t)类型返回。

想要得到正确的数据,在flash的写入和读取时,地址要相匹配。N32的FLASH读写操作到此就讲解完了,讲的有些啰嗦了。

另外提一点作者在flash读写操作中出现的问题:

将数组通过指针进行数据传递的问题。

比如有一个数组,uint32_t data[4]; data表示的就是该数组首元素的地址,所以该数组首元素的可以用 *data 来表示,而第二个元素可以用 *(data + 1)的形式来表示,这样,*data 和 *(data + 1)的地址之间是有一个字长的偏移量的。

而普通或者说一般的地址数据传递是这样:

例如有一个指针,void *pdata = 0x08008000;*pdata 表示就是地址 0x08008000 中存储的数据,而 *(pdata + 1)就是就是地址 0x08008001 存储的数据,*pdata 和 *(pdata + 1)的地址之间的偏移量就是一个节字。


使用特权

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

本版积分规则

20

主题

3149

帖子

0

粉丝