本帖最后由 39035605 于 2019-8-24 21:58 编辑
最近看到有人反馈潘多拉开发板例程:FLASH模拟EEPROM实验的底层驱动存在问题,仔细看了一下驱动代码,这里首先说明一下,确实是存在问题的!!! 例程里面的函数:void STMFLASH_Write(u32 WriteAddr, uint64_t *pBuffer, u32 NumToWrite)
这一行代码:STMFLASH_Read(secpos * STM_SECTOR_SIZE, (u32*)STMFLASH_BUF, STM_SECTOR_SIZE / 4); //读出该页全部数据
STMFLASH_Read函数的输入地址是存在问题的,应该还需要加上STM32 FLASH的基地址,代码应该为:
STMFLASH_Read(secpos * STM_SECTOR_SIZE+STM32_FLASH_BASE, (u32*)STMFLASH_BUF, STM_SECTOR_SIZE / 4); //读出该页全部数据
那么问题就来了:
感到奇怪的是,为什么这里的地址错误,程序的功能却没有任何问题(STMFLASH_Read函数读出来数据一模一样),代码可以正常运行。没有任何错误。
也就是说:
STMFLASH_Read(secpos * STM_SECTOR_SIZE, (u32*)STMFLASH_BUF, STM_SECTOR_SIZE / 4); 与STMFLASH_Read(secpos * STM_SECTOR_SIZE+STM32_FLASH_BASE, (u32*)STMFLASH_BUF, STM_SECTOR_SIZE / 4);
读出的数据是一致的,没有任何区别!!!!相当于从地址0x0读数据与从地址0x08000000(STM32_FLASH_BASE)读数据没有没有任何区别
这个现象我也通过J-LINK的J-FLASH工具和ST-LINK的STM32 ST-LINK Utility工具进行验证,答案是一致的:
从地址0x0读数据与从地址0x08000000(STM32_FLASH_BASE)读数据没有没有任何区别
刚开始我怀疑过有可能是J-FLASH和STM32 ST-LINK Utility这些工具进行过处理,软件会自动处理0x0地址数据,自动加上一个STM32的基地址(0x08000000),甚至还使用了逻辑分析仪分析SWD协议(这个由于数据太多被放弃了)
终于通过查找相关文档资料找到了:(这里以STM32F103为例进行说明)
参考资料:1.《Cortex-M3权威指南》2.《STM32数据手册》
在《Cortex-M3权威指南》中找到这些说明:
从上图中我们可以看到,CM3复位后,是直接从地址0x0开始运行的,然后再从0x00000004处取出复位向量。 而我们的STM32一般代码存放位置是0x08000000,接着看。。。。
在《STM32数据手册》中的Memory mapping小节可以看到下图所示内容,
从图中可以看到,0x00000000 - 0x08000000 之间的128M是预留出来的,这个区域的名字叫:Aliased to Flash or system memory depending on BOOT pins,翻译成中文意思为:这里为可选区域,具体是“FLASH”区域还是“System memory”区域,是取决于 BOOT引脚的。
这里我们知道STM32是可以通过BOOT引脚来选择启动方式的,一般有三种:1.从FLASH启动,2.从system memory启动,3.从内部SRAM启动,这就和这里说明的Memory mapping对上了。
结论:
1.当从FLASH启动时:0x00000000 - 0x08000000 区域为FLASH,也就是FLASH既可以从0x00000000操作,也可以从从0x08000000 操作
2.当从sytem memory启动时:0x00000000 - 0x08000000 区域为sytem memory,也就是sytem memory既可以从0x00000000操作,也可以从从0x1FFFF000 操作
3.当从SRAM启动时,SRAM只能通过0x20000000进行操作。
这里我们也可以实际通过正点原子的战舰V3开发板测试一下,随便下载一个例程源码,然后使用ST-LINK Utility工具进行验证:
1.当BOOT0为0时,从FLASH启动
从地址0x0读数据:
从地址0x08000000读数据:
从地址0x1FFFF000读数据:
2.当BOOT0为1 BOOT1为0时,从system memory启动
从地址0x0读数据:
从地址0x08000000读数据:
从地址0x1FFFF000读数据:
2.当BOOT0为1 BOOT1为1时,从SRAM启动
从地址0x0读数据:
从地址0x20000000读数据:
感兴趣的小伙伴可以试一下写操作是否能从地址0开始写入。。。 ,不知道是否可行
|