U2A---指令存放到RAM

本文介绍了单片机程序中的指令和数据存储,重点讨论了如何通过修改链接文件和使用绝对地址复制技术,将代码从FLASH区复制到RAM区。作者还展示了如何使用相对地址实现自动化的代码拷贝和调试过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单片机程序主要包含指令数据两个部分(简化说法,不太准确),

指令(如函数体)存放在FLASH区;

数据(主要是变量)存放在RAM区,同时;

数据也可以存放在FLASH区(可使用const关键字实现);

指令也可以存放在RAM区,而这就是我们今天的主题。

1、绝对地址复制

    首先,修改链接文件

    这里需要设置我们自己的测试section,将我们的测试代码存放到指定位置。

现在来解释一下它的意思,其中(:>iRAM)是指定具体的内存空间,这里是公用RAM的B区,如下图,其中(:ORIGN是指定起始地址,LENGTH是指定长度,这里可不是随便定义的,而是根据芯片手册的地址空间分配来的);

:>.)是指本段的起始地址在满足地址对齐方式的情况下与上一段的结束地址连续;(align(4))是指本段的地址对齐方式为4字节对齐,关于地址对齐,咱们后面再讲;(pad(0x0800))是告诉链接器需要为本段分配0x0800也就是4K个字节的空间;最后,(.test_123)是定义我们的段名,也就是用于存放指令的目标RAM区。

FLASH区也是一样,只不过(.FLS_BUFFER_CODE_RAM)是存放指令的原始FLASH区。

第二,将测试代码分配到指定的代码段。

#pragma ghs section text = ".teat_123"

————代码
----代码

#pragma ghs section text = default

其中,第一句指令的意思是将这一句指令之后的代码全部放到指定的段,也就是我们定义的(.teat_123)段里去;第二句指令是说到此结束,后面的代码任由编译器自己放。

 第三,复制到指定RAM区。

void Flash Test(void)
{
    uint32 srcAddr= 0;
    uint8 size =0
    uint32 desAddr= 0:
    uint8 *pSrcAddr = (uint8 *)srcAddr;               
    uint8*pDesAddr = (uint8 *)desaddr;
    uint8 i;
    uint8 ret;
    uint8(*fp)(void);

    fp = 0;
    for(i =0;i< size; ++i)
    {
        *pDesAddr =*psrcAddr;
        pDesAddr++;
        pSrcAddr++;
    }
    ret = fp();
}

细心的小伙伴已经发现了,函数中复制的源地址和目标地址都还未定义,因为我们讲的的绝对地址复制,所以这个地址需要打开MAP文件来确定。

首先是源地址,其中源起始地址为0x0001c678,大小为0xe,也就是14个字节;

然后是目标地址,其起始地址为0xfef0000,大小为0x2000,跟我们之前定义的完全一样;

故更改之后的测试函数如下图;

void Flash Test(void)
{
    uint32 srcAddr= 0x0001c648;
    uint8 size =0xe;
    uint32 desAddr= axfefo0000:
    uint8 *pSrcAddr = (uint8 *)srcAddr;               
    uint8*pDesAddr = (uint8 *)desaddr;
    uint8 i;
    uint8 ret;
    uint8(*fp)(void);

    fp = 0;
    for(i =0;i< size; ++i)
    {
        *pDesAddr =*psrcAddr;
        pDesAddr++;
        pSrcAddr++;
    }
    ret = fp();
}

现在我们来看下测试函数的执行结果;

我们可以看到,调用函数指针fp之后的执行结果和前面复制的函数Flash_Init()执行结果完全一样,说明我们的操作是成功的。

    再扩展一点,咱们可以看下函数指针fp和函数Flash_Init的汇编内容是不是一样的;

这是Flash_Init()函数的汇编;

这是函数指针fp执行时调用的的汇编;

  可以看到,二者完全一样,其执行结果当然一样。

以上就是本篇关于绝对地址复制的内容,绝对地址复制需要先编译一遍工程,再根据生成的MAP文件修改,这就显得很麻烦,那么能不能做的自动化一点呢,答案当然是可以的,请大家接着往下看;

首先,先修改链接文件

        这里我们需要新增在链接文件中新增3个变量,如下图所示;

首先是定义变量名分别为.heapbase、heap以及FLS_TEST_RAM_START,变量名前面的短横线"_"是告诉链接器这是变量;然后ADDR和ENDADDR是链接器内置函数,分别用于指定段的起始地址和结束地址的计算,其输入参数就是我们需要计算的段名;

然后我们声明变量

extern Const uint32 FLS TEST CODE START[];
extern const uint32 FLS TEST CODE END[];
extern const uint32 FLS TEST RAM START[];

void Flash Test(void)
{
    uint32 srcAddr = (uint32)FLS TEST CODE START;
    uint32endAddr = (uint32)FLS TEST CODE END;
    uint32desAddr = (uint32)ELS TEST RAM START;

    uint8*pSrcAddr = (uint8*)srcaddr;
    uint8*pDesAddr =(uint8*)desaddr;

    uint8 ret;
    uint8(* fp)(void);

    fp =(uint32)FLS IEST RAM START;

    while(psrcAddr <(uint32 *)endAddr)
    {
        *pDesAddr =*psrcAddr;
        pDesAddr++;
        psrcAddr++;
    }
   ret = fp();
   
}

这里需要以数组的方式进行定义,定义成(uint32*)指针的方式会编译报错,有兴趣的童鞋可以研究下原因,这里我们就不探讨了;

完成上面的步骤之后我们可以看下编译生成的MAP文件,

可以看到,这几个变量的地址跟之前的绝对地址完全一样。

最后,看下调试结果。

可以看到,运行结果和汇编内容完全相同。

以上,我们就实现了使用相对地址来实现将代码拷贝到RAM区执行的操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值