zwmasdf 发表于 2018-1-10 09:30:11

分享STM32如何运行存储在SPI FLASH中的代码

本帖最后由 zwmasdf 于 2018-8-31 07:58 编辑

大家都知道STM32的代码是保存在内部FLASH中,执行也在内部FLASH中。那有没有设想一下,代码保存在外部SPI FLASH,执行在内部RAM?
了解过UBOOT的童鞋应该知道,刚才的那种设想在UBOOT上体现的淋漓尽致,那么STM32应该也可以实现。
在阅读本文之前,建议先阅读我的几片帖子
1. 如何将代码烧录到外部FLASH
2.如何在RAM中执行代码
然后对执行域和加载域有深入了解,如不了解则百度

有了以上2片文章和执行域与加载域的阅读基础,接下来可以开干了
我使用的是STM32F103RCT6,板载SPI FLASH,并且PA4(CS),PA5(SCK),PA6(MISO),PA7(MOSI)连到W25Q32FV上,PA2接到LED上
使用STMCubeMX新建工程,定义SPI4根线、配置SPI相关参数、定义LED端口,生成工程,然后加入SPI FLASH的驱动
修改总工程属性Option for File Target,勾选并定义ROM1:0xC0000000, 0x100,由于测试代码较小,这里只分配256个字节
IRAM字段由于要放一部分用来执行代码,则将原先长度0xC000缩小为0x8000
如图:
然后新建test.c文件,该文件用于保存在SPI FLASH、执行在RAM的代码
修改test.c文件属性Option for File Target,如图

然后编辑test.c,加入翻转LED灯代码:
#include "main.h"
#include "stm32f1xx_hal.h"

void led_test(void)
{
    while(1)
    {
      HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
      HAL_Delay(1000);
    }
}编译没问题后,重新修改总工程属性Option for File Target,切换到Link选项,取消勾选Use Memory Layout from Target Dialog,并点击Edit编辑sct文件
如图
sct编辑内容如下:
LR_IROM1 0x08000000 0x00020000{    ; load region size_region
ER_IROM1 0x08000000 0x00020000{; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
}
RW_IRAM1 0x20000000 0x00008000{; RW data
   .ANY (+RW +ZI)
}
}

LR_ROM1 0xC0000000 0x00000100{
ER_ROM1 0x20008000 0x00000100{; load address = execution address
    test.o (+RO)
   .ANY (+RO)
}
}


然后编辑main.c
添加以下代码//由于代码存在外部的SPI FLASH,因此代码搬移工作必须手动完成,即加载域到执行域的拷贝工作必须自己完成
W25QXX_Read((uint8_t*)0x20008000,0x0, 100);//注释该语句将进入HardFault_Handler
led_test();

重新完全编译
然后烧录选项添加SPI FLASH的烧录算法,见之前的帖子
烧录后上电,点灯间隔1秒闪烁成功,大功告成!

eric2013 发表于 2018-1-10 11:14:32

非常感谢楼主分享,置酷

zwmasdf 发表于 2018-1-10 13:23:30

eric2013 发表于 2018-1-10 11:14
非常感谢楼主分享,置酷
这种方法还是具有实战意义的,可以把有些能证明正版的代码加密后放在外部Flash,这样,别人解密的成本就很高。
不过目前只能用MDK配合烧录算法下载
好像Jlink的JFlash目前还没找到如何加载外部FLASH的烧录算法,如果可以的话量产问题也解决了
此外还可以用JLINK做外部FLASH的编程器,完全可以取代V9的JFlashSPI直接用SPI连到FLASH上烧录的方式
希望后续有人能攻克

leiyitan 发表于 2018-1-21 22:18:30

这个ST自己就有例程的,只是没有实际意义。

zwmasdf 发表于 2018-1-26 08:33:57

leiyitan 发表于 2018-1-21 22:18
这个ST自己就有例程的,只是没有实际意义。

有意义啊,假如把STM32判断唯一ID的判断代码放到SPI FLASH中,并对代码进行加密,那就会增加破解者的难度

hqgboy 发表于 2018-1-27 08:41:53

谢谢分享。,

yklstudent 发表于 2018-3-23 09:54:06

楼主牛逼的不要不要的

caicaptain2 发表于 2018-3-26 14:03:50

由于stm32系列的内部RAM都小于flash,感觉这种折腾意义不大啊。。。

ruboss 发表于 2018-4-9 00:30:58

楼主,我测试的有点问题,数据在外部flash没问题,代码在外部flash单片机就无法启动,不只是不是启动文件中__main函数有对代码进行加载导致无法启动?

zwmasdf 发表于 2018-4-10 10:49:02

ruboss 发表于 2018-4-9 00:30
楼主,我测试的有点问题,数据在外部flash没问题,代码在外部flash单片机就无法启动,不只是不是启动文件中 ...

你外部ram的代码有没有单独用一个c文件存放,必须隔离开来的

xy201207 发表于 2018-4-11 15:03:26

弱弱的问下大多数MCU RAM本来就小,为什么还要把代码加载到RAM中运行?

596142041 发表于 2018-4-26 19:41:56

准备尝试一下看看

csgtli 发表于 2018-5-1 23:24:33

放在外部FLASH有什么好处

悠悠三千载 发表于 2018-5-10 17:54:37

66666666666666

廷润 发表于 2018-5-21 14:15:23

顶帖支持。

MaxChen 发表于 2018-8-30 16:42:55

楼主方便交流下吗

ghslfgkkl88 发表于 2018-8-30 21:17:53

为何回帖全是“仅作者可见”

diancity 发表于 2021-2-28 11:45:37

厉害,这样就能弥补片内flash太小的缺点。把不同的函数写入spi flash,使用时加载不同的函数实现不同的功能,类似APP应用程序一样。如果把公共驱动写入片内,其他功能代码都放入spi flash。实现一个可以安装APP的功能就太强了。

h_007 发表于 2021-3-1 00:06:07

假设IRAM为4K bytes,外部程序的大小如果大于4k bytes,就要设计载入算法(跟PC差不多了),太复杂了。
“操作系统教程”好像有个经典算法:如何设置只有2根铁轨让火车跑起来。大致的意思是,确保每根铁轨都比火车长,将后面的铁轨拆下来铺在火车的前面(非常快速),一直循环,火车就一直往前开。

lin814329685 发表于 2021-8-14 20:55:57

为什么我按照你的方法在407单片机上试了下,数据我核对了是正确的,只能下载不能运行,一运行,执行完SystemInit函数就进硬件错误中断了

armUser112233 发表于 2022-9-18 23:36:17

不错不错,我这个周末也在搞这个,现在遇到了一点问题,下载后无法调用在外部flash的函数,看到你的分享我又有点思路了.

嵌入式丨小白 发表于 2023-9-21 16:07:54

楼主能发一下工程文件吗
页: [1]
查看完整版本: 分享STM32如何运行存储在SPI FLASH中的代码