在上节视频里说ARMCPU有两种状态
ARM State 每条指令会占据4byte
Thumb State 每条指令占据2byte
我们说过Thumb指令集并不重要,本节演示把一个程序使用Thumb指令集来编译它
使用上一章节的重定位代码,打开Makefile和Start.S
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
对于使用Thumb指令集
all:
arm-linux-gcc -mthumb -c -o led.o led.c//只需要在arm-linux-gcc加上 mthumb命令即可
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
改进
all: led.o uart.o init.o main.o start.o //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 $@ $< //对于所有的.c文件使用规则就可以使用thumb指令集编译 $@表示目标 $<表示第一个依赖
%.o : %.S
arm-linux-gcc -c -o $@ $<
```
对start.S需要修改代码
原重定位章节Start.S文件
```c
.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
使用thumb指令集的Start.S文件
.text
.global _start
.code 32 //表示后续的指令使用ARM指令集
_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指令集
thumb_func: //需要得到这个标号的地址
/*下面就是使用thumb指令来执行程序*/
bl sdram_init
//bl sdram_init2 /* 用到有初始值的数组, 不是位置无关码 */
/* 重定位text, rodata, data段整个程序 */
bl copy2sdram
/* 清除BSS段 */
bl clean_bss
//bl main /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */
ldr r0, =main /* 绝对跳转, 跳到SDRAM ,先把main的地址赋值给R0 */
mov pc, r0 /*让后再移动到PC*/
halt:
b halt
上传代码编译测试
出现错误,如下
init.o(.text+0x6c):In function ‘sdram_init2’;
undefined reference to ‘memcpy’
发现是init,o里sdram_init2使用的了memcpy函数
查看init.c
#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
/*下面函数使用了memcpy函数,显然是编译器的操作,使用了memcpy把数组里的值从代码段拷贝到了arr局部变量里
是否可以禁用掉memcpy*/
void sdram_init2(void)
{
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++;
}
}
文章说没有什么方法禁用memecpy但是可以修改这些变量
比如说将其修改为静态变量,这些数据就会放在数据段中,最终重定位时会把数据类拷贝到对应的arr地址里面
void sdram_init2(void)
{
const static unsigned int arr[] = { //加上const 和static
0x22000000, //BWSCON
0x00000700, //BANKCON0
0x00000700, //BANKCON1
0x00000700, //BANKCON2
0x00000700, //BANKCON3
0x00000700, //BANKCON4
0x00000700, //BANKCON5
上一篇:S3c2440ARM异常与中断体系详解8---定时器中断程序示例
下一篇:S3c2440ARM异常与中断体系详解7---按键中断程序示例完善
推荐阅读最新更新时间:2024-11-08 11:35
推荐帖子
- 路由信息协议(RIP)
- 一、背景 路由信息协议(RIP)是以跳数作为metric的距离向量协议。RIP广泛用于全球因特网的路由,是一种内部网关协议(interiorgatewayprotocol),即在自治系统内部执行路由功能。外部网关路由协议(exteriorgatewayprotocol),如边缘网关协议(BGP),在不同的自治系统间进行路由。RIP的前身是Xerox协议GWINFO,后来的版本routed(发音为/rutdi/)封装在1982年伯克利标准发布Unix(即BSD中)。RIP本身发
- clj2004000 RF/无线
- 这是什么问题啊
- 单片机是tm4c123g我下的tivaware里面的例程报了这样的错是哪里出问题了这是什么问题啊重复定义解决了加一个#includeutils/uartstdio.c就好了
- xiaojianren210 微控制器 MCU
- MSP430 内置温度传感器的精度
- 产品说明书中提供了带有相应容差范围的额定00C电压与温度系数。额定00C电压规定为986mV,其最大误差为+/-5%。因此,温度传感器的00C电压在最恶劣的环境下,每个器件可能会相差几乎+/-50mV。这大约等于+/-14C。请注意,这种差异主要与各个器件有关,因此,只要对单个器件进行适当校准,即可通过满分辨率的ADC12获得非常准确的绝对温度。MSP430内置温度传感器的精度
- vicer 微控制器 MCU
- 手把手教你玩转RVSTAR—实时时钟RTC篇
- 实时时钟(Real-TimeClock,RTC)常用于制作时钟日历。RTC电路分属于两个电源域:备份域和VDD电源域。RTC的核心计数部分在备份域中,可在VDD断电VBAT供电时保持RTC的计数,当系统复位或者从待机模式唤醒时,RTC的设置和时间也都保持不变。本期内容将通过一个显示当前时间的例程带领大家初步了解GD32VF103的RTC外设的使用方法。系统环境Windows10-64bit软件平台NucleiStudioIDE202102版或Platf
- 火辣西米秀 国产芯片交流
- 如何设置管脚间距
- 我画PCB时,一个芯片管脚间距太小了,变绿了应该怎么修改?谢谢!如何设置管脚间距修改designrules或者把DRC的这个颜色告错取消掉板子还没画好之前肯定很多告错,把这边可以先关闭,见下图也可以修改设计规格,否则如果封装跟规格不匹配,板子画好后DRC也过不了多谢各位 这是正解,修改引脚规则,不过你这为什么用mm单位用mil多好 刚工作时就习惯了先把单位改为mm,最小格设置为0.1mm信号的飞线也可以先隐藏掉,否则画板子
- chenbingjy PCB设计
- Altium Designer学习笔记
- 最近时间学习PCB画板技巧总结分享给大家AltiumDesigner学习笔记自己总结的?看了写的好还不错啊谢谢不错,很好的分享。。。。。。。。。。。。。。。。。。。。。。。。看看,借鉴借鉴thanks,厉害可以当做初学者学习书啊不错谢谢正在看tks,楼主
- DavidLee1986 PCB设计
设计资源 培训 开发板 精华推荐
- ISM330DLC适配器板,标准DIL24插座
- 具有电源排序功能的 LTC3589HUJ-1 8 输出稳压器的典型应用电路
- 用于增加软启动的 LT3089IFE 线性稳压器的典型应用电路
- 适用于 SOP-8(裸焊盘)封装的 RT7274、2A、18V、700kHz ACOTTM 同步降压转换器的典型应用
- LT1118CS8 具有数字控制功能的 2.1V 至 6.5V 可变稳压器的典型应用电路
- 开源锂电池管理板,充电5V2A,放电5V/1.52A 或者 12V/0.76A
- #第五届立创电子设计大赛#线缆护套材料热稳定自动测试装置
- DC1975A,使用 LTC2270 高速、16 位、20 MSPS 双模数转换器的演示板
- SC4212 极低输入/极低压差 1Amp 稳压器的典型应用
- DC1989B-B,基于 LTM4676AEY 双路 13A 或单路 26A 稳压器的演示板,具有数字电源系统管理 3× LTM4676A @ 75A