历史上的今天
返回首页

历史上的今天

今天是:2024年10月12日(星期六)

正在发生

2021年10月12日 | S3C2440裸机------异常与中断__Thumb指令集程序示例

2021-10-12 来源:eefocus

我们以之前的代码重定位程序为例简单看一下thumb指令集。


1.C代码修改为Thumb指令集格式

对于C程序,如果我们想把他们编译成Thumb指令集的话,只需要修改makefile,加上-mthumb选项即可,先看一下之前的makefile。


all:

arm-linux-gcc -c -o led.o led.c

arm-linux-gcc -c -o uart.o uart.c

arm-linux-gcc -c -o init.o init.c

arm-linux-gcc -c -o main.o main.c

arm-linux-gcc -c -o start.o start.S

#arm-linux-ld -Ttext 0 -Tdata 0x30000000  start.o led.o uart.o init.o main.o -o sdram.elf

arm-linux-ld -T sdram.lds start.o led.o uart.o init.o main.o -o sdram.elf

arm-linux-objcopy -O binary -S sdram.elf sdram.bin

arm-linux-objdump -D sdram.elf > sdram.dis

clean:

rm *.bin *.o *.elf *.dis

修改后的makefile如下:


all: led.o uart.o init.o main.o start.o

#arm-linux-ld -Ttext 0 -Tdata 0x30000000  start.o led.o uart.o init.o main.o -o sdram.elf

arm-linux-ld -T sdram.lds start.o led.o uart.o init.o main.o -o sdram.elf

arm-linux-objcopy -O binary -S sdram.elf sdram.bin

arm-linux-objdump -D sdram.elf > sdram.dis

clean:

rm *.bin *.o *.elf *.dis

%.o : %.c

arm-linux-gcc -mthumb -c -o $@ $<

 

%.o : %.S

arm-linux-gcc -c -o $@ $<

2.汇编代码修改为Thumb指令集

对于汇编文件,我们需要修改代码切换为Thumb指令集。


我们先看一下之前的start.S


 

.text

.global _start

 

_start:

 

/* 关闭看门狗 */

ldr r0, =0x53000000

ldr r1, =0

str r1, [r0]

 

/* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */

/* LOCKTIME(0x4C000000) = 0xFFFFFFFF */

ldr r0, =0x4C000000

ldr r1, =0xFFFFFFFF

str r1, [r0]

 

/* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8  */

ldr r0, =0x4C000014

ldr r1, =0x5

str r1, [r0]

 

/* 设置CPU工作于异步模式 */

mrc p15,0,r0,c1,c0,0

orr r0,r0,#0xc0000000   //R1_nF:OR:R1_iA

mcr p15,0,r0,c1,c0,0

 

/* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0) 

*  m = MDIV+8 = 92+8=100

*  p = PDIV+2 = 1+2 = 3

*  s = SDIV = 1

*  FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M

*/

ldr r0, =0x4C000004

ldr r1, =(92<<12)|(1<<4)|(1<<0)

str r1, [r0]

 

/* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定

* 然后CPU工作于新的频率FCLK

*/

 

/* 设置内存: sp 栈 */

/* 分辨是nor/nand启动

* 写0到0地址, 再读出来

* 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动

* 否则就是nor启动

*/

mov r1, #0

ldr r0, [r1] /* 读出原来的值备份 */

str r1, [r1] /* 0->[0] */ 

ldr r2, [r1] /* r2=[0] */

cmp r1, r2   /* r1==r2? 如果相等表示是NAND启动 */

ldr sp, =0x40000000+4096 /* 先假设是nor启动 */

moveq sp, #4096  /* nand启动 */

streq r0, [r1]   /* 恢复原来的值 */

 

bl sdram_init

//bl sdram_init2 /* 用到有初始值的数组, 不是位置无关码 */

 

/* 重定位text, rodata, data段整个程序 */

bl copy2sdram

 

/* 清除BSS段 */

bl clean_bss

 

//bl main  /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */

ldr pc, =main  /* 绝对跳转, 跳到SDRAM */

 

halt:

b halt

然后进行修改,我们首先在_start:前面增加 .code 32 表示后续的指令使用arm指令集,然后由于我们的C函数是使用Thumb指令集,因为我们在bl sdram_init前面加上.code 16,然后我们在.code 16的前面还要加上一个切换指令,表示我们从arm指令切换到thumb指令,我们使用bx指令进行切换,bx命令后面的值如果它的最低位是1的话,它会跳转到thumb指令。修改后的start.S如下:


 

.text

.global _start

.code 32

_start:

 

/* 关闭看门狗 */

ldr r0, =0x53000000

ldr r1, =0

str r1, [r0]

 

/* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */

/* LOCKTIME(0x4C000000) = 0xFFFFFFFF */

ldr r0, =0x4C000000

ldr r1, =0xFFFFFFFF

str r1, [r0]

 

/* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8  */

ldr r0, =0x4C000014

ldr r1, =0x5

str r1, [r0]

 

/* 设置CPU工作于异步模式 */

mrc p15,0,r0,c1,c0,0

orr r0,r0,#0xc0000000   //R1_nF:OR:R1_iA

mcr p15,0,r0,c1,c0,0

 

/* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0) 

*  m = MDIV+8 = 92+8=100

*  p = PDIV+2 = 1+2 = 3

*  s = SDIV = 1

*  FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M

*/

ldr r0, =0x4C000004

ldr r1, =(92<<12)|(1<<4)|(1<<0)

str r1, [r0]

 

/* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定

* 然后CPU工作于新的频率FCLK

*/

 

/* 设置内存: sp 栈 */

/* 分辨是nor/nand启动

* 写0到0地址, 再读出来

* 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动

* 否则就是nor启动

*/

mov r1, #0

ldr r0, [r1] /* 读出原来的值备份 */

str r1, [r1] /* 0->[0] */ 

ldr r2, [r1] /* r2=[0] */

cmp r1, r2   /* r1==r2? 如果相等表示是NAND启动 */

ldr sp, =0x40000000+4096 /* 先假设是nor启动 */

moveq sp, #4096  /* nand启动 */

streq r0, [r1]   /* 恢复原来的值 */

 

/* 怎么从ARM State切换到Thumb State? */

adr r0, thumb_func

add r0, r0, #1  /* bit0=1时, bx就会切换CPU State到thumb state */

bx r0

.code 16

thumb_func:

bl sdram_init

//bl sdram_init2 /* 用到有初始值的数组, 不是位置无关码 */

 

/* 重定位text, rodata, data段整个程序 */

bl copy2sdram

 

/* 清除BSS段 */

bl clean_bss

 

//bl main  /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */

ldr r0, =main  /* 绝对跳转, 跳到SDRAM */

mov pc, r0

 

halt:

b halt

3.bug

3.1 bug1

在start.S中,我们直接用ldr pc, =main编译会出错,这是因为对于Thumb指令集不能直接向PC直接赋值,我们先把main的值赋给某个寄存器,然后再把这个寄存器的值赋值给PC,


3.2 bug2

在init.c中的sdram_init2函数中提示undefined reference to memcpy,但是我们发现我们再这个函数里面并没有用到memcpy,这是因为arr数组的值是保存到代码里面的,为了构造这个数组,编译器偷偷的使用memcpy从代码段中拷贝到局部变量arr中,我们通过把arr修改为const static类型,这样static变量就会放到数据段里面,然后重定位时就会把数据段的值拷贝到arr所对应的地址中去,遮掩过就不会用到memcpy了。


 

#include "s3c2440_soc.h"

 

void sdram_init(void)

{

BWSCON = 0x22000000;

 

BANKCON6 = 0x18001;

BANKCON7 = 0x18001;

 

REFRESH  = 0x8404f5;

 

BANKSIZE = 0xb1;

 

MRSRB6   = 0x20;

MRSRB7   = 0x20;

}

 

#if 0

 

 

/**************************************************************************   

* 设置控制SDRAM的13个寄存器

* 使用位置无关代码

**************************************************************************/   

void memsetup(void)

{

unsigned long *p = (unsigned long *)MEM_CTL_BASE;

p[0] = 0x22111110; //BWSCON

p[1] = 0x00000700; //BANKCON0

p[2] = 0x00000700; //BANKCON1

p[3] = 0x00000700; //BANKCON2

p[4] = 0x00000700; //BANKCON3

p[5] = 0x00000700; //BANKCON4

p[6] = 0x00000700; //BANKCON5

p[7] = 0x00018005; //BANKCON6

p[8] = 0x00018005; //BANKCON7

p[9] = 0x008e07a3; //REFRESH,HCLK=12MHz:0x008e07a3,HCLK=100MHz:0x008e04f4

p[10] = 0x000000b2; //BANKSIZE

p[11] = 0x00000030; //MRSRB6

p[12] = 0x00000030; //MRSRB7

}

 

 

#endif

 

void sdram_init2(void)

{

const static unsigned int arr[] = {

0x22000000, //BWSCON

0x00000700, //BANKCON0

0x00000700, //BANKCON1

0x00000700, //BANKCON2

0x00000700, //BANKCON3

0x00000700, //BANKCON4

0x00000700, //BANKCON5

0x18001, //BANKCON6

0x18001, //BANKCON7

0x8404f5, //REFRESH,HCLK=12MHz:0x008e07a3,HCLK=100MHz:0x008e04f4

0xb1, //BANKSIZE

0x20, //MRSRB6

0x20, //MRSRB7

 

};

volatile unsigned int * p = (volatile unsigned int *)0x48000000;

int i;

 

for (i = 0; i < 13; i++)

{

*p = arr[i];

p++;

}

}

 

 

int sdram_test(void)

{

volatile unsigned char *p = (volatile unsigned char *)0x30000000;

int i;

 

// write sdram

for (i = 0; i < 1000; i++)

p[i] = 0x55;

 

// read sdram

for (i = 0; i < 1000; i++)

if (p[i] != 0x55)

return -1;

 

return 0;

}

 

void copy2sdram(void)

{

/* 要从lds文件中获得 __code_start, __bss_start

* 然后从0地址把数据复制到__code_start

*/

 

extern int __code_start, __bss_start;

 

volatile unsigned int *dest = (volatile unsigned int *)&__code_start;

volatile unsigned int *end = (volatile unsigned int *)&__bss_start;

volatile unsigned int *src = (volatile unsigned int *)0;

 

while (dest < end)

{

*dest++ = *src++;

}

}

 

 

void clean_bss(void)

{

/* 要从lds文件中获得 __bss_start, _end

*/

extern int _end, __bss_start;

 

volatile unsigned int *start = (volatile unsigned int *)&__bss_start;

volatile unsigned int *end = (volatile unsigned int *)&_end;

 

 

while (start <= end)

{

*start++ = 0;

}

}

推荐阅读

史海拾趣

GTM公司的发展小趣事

关于电源反馈控制电路,网友们可能会提出多种问题,这些问题涵盖了其工作原理、设计、应用、故障排查及优化等方面。以下是一些常见问题及其简要回答:

  1. 问题:什么是电源反馈控制电路,它的主要作用是什么?
    回答:电源反馈控制电路是一种通过监测电源输出电压或电流,并将其与设定值进行比较,然后调整电源输出以维持设定值的电路。它的主要作用是确保电源输出的稳定性和准确性,无论负载如何变化,都能保持输出电压或电流在预定范围内。

  2. 问题:电源反馈控制电路有哪些常见的拓扑结构?
    回答:常见的电源反馈控制电路拓扑包括电压模式控制(Voltage Mode Control, VMC)和电流模式控制(Current Mode Control, CMC)。电压模式控制主要关注输出电压的稳定性,而电流模式控制则在电压控制的基础上增加了对输出电流的直接控制,以提高瞬态响应和稳定性。

  3. 问题:如何设计有效的电源反馈控制电路?
    回答:设计有效的电源反馈控制电路需要考虑多个因素,包括选择合适的反馈元件(如电阻、电容、电感)、放大器类型(运算放大器、比较器等)、补偿网络设计(以改善稳定性和响应速度)、以及选择合适的控制策略(如PID控制)。此外,还需要进行仿真和实验验证,以确保设计的电路能够满足性能指标。

  4. 问题:电源反馈控制电路中遇到稳定性问题时应该如何解决?
    回答:遇到稳定性问题时,首先需要检查反馈回路中的元件是否匹配良好,特别是补偿网络的设计是否合理。可以通过调整补偿网络的参数(如增加相位裕度)来改善稳定性。此外,检查控制策略是否适合当前的应用场景,必要时可以更换控制策略或调整控制参数。

  5. 问题:电源反馈控制电路中的噪声问题如何解决?
    回答:噪声问题通常来源于电源本身、外部环境或电路内部元件。解决噪声问题的方法包括使用低噪声的电源元件、增加滤波电路(如LC滤波器)、优化PCB布局以减少电磁干扰、以及采用差分放大器等噪声抑制技术。

  6. 问题:电源反馈控制电路在哪些领域有广泛应用?
    回答:电源反馈控制电路在电子设备的各个领域都有广泛应用,包括但不限于计算机电源、通信设备、工业控制、汽车电子、医疗设备、LED照明等。这些领域对电源的稳定性和效率要求很高,因此电源反馈控制电路成为不可或缺的一部分。

Elcos AG公司的发展小趣事

随着公司规模的扩大和业务的增长,Elcos AG面临着供应链管理的挑战。为了降低成本、提高效率和保证产品质量,公司决定对供应链进行优化。通过引入先进的供应链管理软件、加强与供应商的合作和建立严格的质量控制体系等措施,Elcos AG成功实现了供应链的优化和升级。这不仅提高了公司的运营效率和市场竞争力,还为客户提供了更加稳定可靠的产品和服务。

Embedded Artists公司的发展小趣事

随着嵌入式技术的不断发展,Embedded Artists公司不断投入研发,推出了一系列创新产品。其中,一款基于恩智浦处理器的嵌入式开发板因其高性能、低功耗和易用性,受到了市场的热烈欢迎。这款产品不仅为公司带来了可观的收入,还提高了公司在行业中的知名度。

FCT electronic公司的发展小趣事

在环保和可持续发展成为全球共识的背景下,FCT electronic公司积极响应这一趋势,致力于推动绿色环保和可持续发展。公司采用了环保材料和工艺,减少了对环境的污染;同时,FCT electronic公司还加强了废物回收和资源利用方面的工作,实现了资源的循环利用和节约。这些努力不仅使FCT electronic公司在环保方面取得了显著成绩,也为公司的可持续发展奠定了坚实基础。

Antiference公司的发展小趣事

近年来,随着物联网、5G等技术的快速发展,电子行业面临着巨大的变革。Antiference公司敏锐地捕捉到这一趋势,及时调整战略方向,将研发重点转向物联网设备的电磁兼容性研究。通过不断创新和优化产品,Antiference成功抓住了物联网发展的机遇,实现了业务的快速增长。

Exclara Inc公司的发展小趣事

随着LED技术的不断发展和市场需求的不断变化,Exclara看到了新的市场机遇。公司凭借在LED领域的技术积累和市场经验,成功进军了智能家居、智能照明等新兴市场。在这些新兴市场中,公司凭借其独特的技术优势和创新能力,迅速获得了市场份额和客户的认可。面对新的市场挑战和机遇,Exclara将继续保持创新精神和技术实力,为电子行业的发展贡献更多的力量。

请注意,以上故事框架仅供参考,具体内容和细节需要根据实际情况进行补充和完善。

问答坊 | AI 解惑

PROTEL常用元件封装

电阻:RES1,RES2,RES3,RES4;封装属性为axial系列   无极性电容:cap;封装属性为RAD-0.1到rad-0.4   电解电容:electroi;封装属性为rb.2/.4到rb.5/1.0   电位器:pot1,pot2;封装属性为vr-1到vr-5  &nbs ...…

查看全部问答>

新手入门,请大虾指点!

我想在半个时钟周期输出num,用如下语句 always@(posedge clk or posedge clk_re)      num…

查看全部问答>

求教各位大虾 DIY钳形表 小电流信号放大

求教各位大虾 DIY钳形表 小电流信号放大   我现在正在DIY一个钳形电流表 目标参数是测量mA至十安级电流 传感器是买的钳形表表头 前期测试了表头的工作曲线 在温湿度允许范围内 表头的线性度比较好   让我郁闷的是  变比 ...…

查看全部问答>

很好的Android论坛

需要的兄弟可以看一下 http://www.eoeandroid.com/?fromuid=9379 偷偷说一句:我不是来做广告的,呵呵…

查看全部问答>

减了BSP几个驱动编译出错,特来请教。

我在我得2440 的BSP减了 camera,SDHC,wavedev 三个驱动, 采用的是在 dirs 中把 camera,sdhc,wavedev删除,然后对BSP Rebuild, Error: Could not find file \'C:\\WINCE600\\OSDesigns\\OSDesign1\\OSDesign1\\RelDir\\smdk2440a_ARMV4I_Debug\\o ...…

查看全部问答>

菜鸟求助:一份正常的BSP我的电脑编译出来的系统无法正常运行?

OMAP3530 + WinCE6 R3 由于项目开始时是基于一个较早版本的BSP,现在打算更新到TI的最新BSP. 更新才刚刚开始一点,就被卡住了.先把屏的参数拷过来,屏可以正常显示,发现触摸屏没用,然后就拷过来触摸屏的一些参数,发现还是没用. 然后就开始分析了: ...…

查看全部问答>

【求助】退出低功耗

我用的是149,初始化后让其进入低功耗状态,我用一个端口实现外部中断,可不可以在中断执行完成后,让其退出低功耗,并继续往下执行主程序。(因为主程序比较复杂,无发都写到中断程序中执行) 谢谢!…

查看全部问答>

无线充电系统设计原理与实作讲析

引言   无线充电技术经过了数年的推广与演进后,到如今终于开始受到人们的关注。无线充电是指具有电池的装置透过无线感应的方式取得电力而进行充电,正是因为其方便性,才得以让消费者愿意支付额外的费用购买无线充电相关产品;如此一来,大批厂 ...…

查看全部问答>

宏定义怎样才能人为选择呢?

我想这样编程序:有2段程序,分别叫“程序1”、“程序0”。里面均包括多个函数。 我希望在这种情况下,执行程序1,另种情况下执行程序2。 我是这样做的: 一、程序开头写上: uint8_t x; #define cons x 二、程序中有赋值语句: 在按下某键 ...…

查看全部问答>

麻烦管理员请注意:我不参加SensorTag大赛了,别给我寄了

麻烦管理员请注意:我不想参加SensorTag有奖赛了,别给我寄了 不好弄 转玩别的了 别给我寄SensorTag了 ,别浪费。…

查看全部问答>