打印
[STM32F0]

内部FLASH问题

[复制链接]
1492|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tgwfcc|  楼主 | 2016-3-5 18:11 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
问题是这样的:
       FLASH的读写操作是Copy的青风F030上边的代码。
/****************************************************************************
*        读取指定地址的半字(16位数据)
*        faddr:读地址(此地址必须为2的倍数!!)
*        返回值:对应数据.
****************************************************************************/
uint16_t STMFLASH_ReadHalfWord(uint32_t faddr)
{
        return *(uint16_t*)faddr;
}

/****************************************************************************
*        不检查的写入
*        WriteAddr:起始地址
*        pBuffer:数据指针
*        NumToWrite:半字(16位)数  
****************************************************************************/
void STMFLASH_Write_NoCheck(uint32_t WriteAddr,uint16_t *pBuffer,uint16_t NumToWrite)   
{                                           
        uint16_t i;
        for(i=0;i<NumToWrite;i++)
        {
                FLASH_ProgramHalfWord(WriteAddr,pBuffer[i]);
            WriteAddr += 2;//地址增加2.
        }  
}

/****************************************************************************
*        从指定地址开始读出指定长度的数据
*        ReadAddr:起始地址
*        pBuffer:数据指针
*        NumToWrite:半字(16位)数
***************************************************************************/
void STMFLASH_Read(uint32_t ReadAddr,uint16_t *pBuffer,uint16_t NumToRead)          
{
        uint16_t i;
        for(i=0;i<NumToRead;i++)
        {
                pBuffer[i] = STMFLASH_ReadHalfWord(ReadAddr);//读取2个字节.
                ReadAddr += 2;//偏移2个字节.       
        }
}

/****************************************************************************
*        从指定地址开始写入指定长度的数据
*        WriteAddr:起始地址(此地址必须为2的倍数!!)
*        pBuffer:数据指针
*        NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
****************************************************************************/
void STMFLASH_Write(uint32_t WriteAddr,uint16_t *pBuffer,uint16_t NumToWrite)       
{
        uint32_t secpos;                   //FLASH 页数
        uint16_t secoff;                   //页内偏移地址(16位字计算)
        uint16_t secremain;         //页内剩余地址(16位字计算)          
        uint16_t i;   
        uint32_t offaddr;                //去掉0X08000000后的地址
        if(WriteAddr<STM32_FLASH_BASE || (WriteAddr>=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))
                return;//非法地址

        FLASH_Unlock();                                         //解锁
        offaddr = WriteAddr - STM32_FLASH_BASE;         //实际偏移地址.
        secpos = offaddr/STM_SECTOR_SIZE;                 //FLASH 页数        0~63 for STM32F030C8
        secoff = (offaddr%STM_SECTOR_SIZE)/2;         //在页内的偏移(2个字节为基本单位.)
        secremain = STM_SECTOR_SIZE/2 - secoff;         //页剩余空间大小         
        if(NumToWrite <= secremain)
                secremain = NumToWrite;//不大于该扇区范围
        while(1)
        {       
                STMFLASH_Read(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整个页的内容
                for(i=0;i<secremain;i++)//校验数据
                {
                        if(STMFLASH_BUF[secoff+i] != 0XFFFF)
                                break;//需要擦除                  
                }
                if(i < secremain)//需要擦除
                {
                        FLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除这一页
                        for(i=0;i<secremain;i++)//复制
                        {
                                STMFLASH_BUF[i+secoff] = pBuffer[i];          
                        }
                        STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//写入整个页  
                }
                else
                        STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//写已经擦除了的,直接写入扇区剩余区间.                                  

                if(NumToWrite == secremain)
                        break;//写入结束了
                else//写入未结束
                {
                        secpos ++;                                //页地址增1
                        secoff=0;                                //偏移位置为0         
                        pBuffer += secremain;         //指针偏移
                        WriteAddr += secremain;        //写地址偏移          
                        NumToWrite -= secremain;        //字节(16位)数递减
                        if(NumToWrite > (STM_SECTOR_SIZE/2))
                                secremain = STM_SECTOR_SIZE/2;//下一页还是写不完
                        else
                                secremain = NumToWrite;//下一页可以写完了
                }         
        };       
        FLASH_Lock();//上锁
}
       在一个alrt.c文件中定义了一个uint8_t的变量learnFlag,uint8_t learnFlag = NoLearn;这个变量是保存到FLASH地址0x0800F8B0的。
       在main.c中,从FLASH中读出该变量的值,STMFLASH_Read(0x0800F8B0,(uint16_t *)&learnFlag, 1);
       这地方,有3中情况:
        1)当在alrt.c文件中定义变量learnFlag为uint8_t时,程序执行到FLASH的STMFLASH_Read操作时,会进入到HardFault_Handler。出现错误。
        2)当在main.c中定义变量learnFlag为uint8_t时,程序可以正常执行。FLASH读操作正常。
        3)当在alrt.c文件中定义变量learnFlag为uint16_t时,程序可以正常执行。FLASH读操作正常。
请教这个是怎么回事?特别是第一种和第二种情况?
沙发
quray1985| | 2016-3-5 19:48 | 只看该作者
你用的flash的地址是不是太靠前了啊

使用特权

评论回复
板凳
mmuuss586| | 2016-3-6 14:53 | 只看该作者
改下FLASH数据存放地址看下;

使用特权

评论回复
地板
zchong| | 2016-3-6 18:10 | 只看该作者
注意你的STMFLASH_Read函数的参数中存在一个强制类型转换,变量learnFlag的类型是uint8_t,其地址就有可能不是按uint16_t对齐的,这才是问题所在
你可以观察一下当出错的时候learnFlag这个变量的地址

使用特权

评论回复
5
tgwfcc|  楼主 | 2016-3-7 15:12 | 只看该作者
zchong 发表于 2016-3-6 18:10
注意你的STMFLASH_Read函数的参数中存在一个强制类型转换,变量learnFlag的类型是uint8_t,其地址就有可能 ...

这是在alrt.c里定义变量时的learnFlag地址。

这是在main.c中定义变量的地址。
这两种定义位置不同,变量地址也不同,这对FLASH的读操作会有什么影响呢?FLASH读数据的话,是读到开始地址的,这个开始地址难道还有什么限制?
        在main中我定义了两个指针,
        uint8_t *tmp8;
        uint16_t *tmp16;
        tmp8 = &learnFlag;
        tmp16 = (uint16_t *)&learnFlag;
        然后分别查看tmp8和tmp16,

我的理解是tmp8里存的是learnFlag的地址,为什么不是呢?

使用特权

评论回复
6
tgwfcc|  楼主 | 2016-3-7 15:21 | 只看该作者
mmuuss586 发表于 2016-3-6 14:53
改下FLASH数据存放地址看下;

换地址也不行

使用特权

评论回复
7
zchong| | 2016-3-7 16:57 | 只看该作者
本帖最后由 zchong 于 2016-3-7 16:59 编辑

哥哥,是字节对齐,原因是强制类型转换
learnFlag你定义成8bit的时候,意味着它的地址可能是奇数,一旦是奇数,(uint16_t *)&learnFlag这个东西是啥?
就你这个具体问题来说,你向奇数地址读写一个16bit的数,会不会出问题?一定出问题
但是其它条件下这个结论就不一定成立。

使用特权

评论回复
8
tgwfcc|  楼主 | 2016-3-7 19:35 | 只看该作者
zchong 发表于 2016-3-7 16:57
哥哥,是字节对齐,原因是强制类型转换
learnFlag你定义成8bit的时候,意味着它的地址可能是奇数,一旦是奇 ...

哦,明白了,我在研究研究,按你说的,我在其他.c文件中定义了该变量,分配的地址是偶数时,FLASH读成功了。O(∩_∩)O谢谢!
对了,ARM对齐有没有什么文档说明啊?找来看一下。

使用特权

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

本版积分规则

34

主题

260

帖子

4

粉丝