S3c2440ARM异常与中断体系详解3---Thumb指令集程序示例

发布者:WiseSage123最新更新时间:2021-10-14 来源: eefocus关键字:S3c2440  ARM异常  中断体系  Thumb指令集 手机看文章 扫描二维码
随时随地手机看文章

在上节视频里说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

[1] [2]
关键字:S3c2440  ARM异常  中断体系  Thumb指令集 引用地址:S3c2440ARM异常与中断体系详解3---Thumb指令集程序示例

上一篇:S3c2440ARM异常与中断体系详解8---定时器中断程序示例
下一篇:S3c2440ARM异常与中断体系详解7---按键中断程序示例完善

推荐阅读最新更新时间:2024-11-08 11:35

s3c2440裸机之中断向量的写法(一)
直接使用跳转指令(B) b reset b undefined_instruction b software_interrupt b prefetch_abort b data_abort b not_used b irq b fiq /* ... */ 反汇编后是这个样子的(链接时的起始地址为0x33f80000): 33f80000 .text : 33f80000: ea000006 b 33f80020 reset 33f80004: ea000006 b 33f80024 undefined_instruction 33f80008: ea000006 b 33f80028 software_interrupt 3
[单片机]
S3C2440裸机------NandFlash编程_时序及初始化
1.NandFlash初始化 Nandflash初始化主要包括时序图的设置和Nandflash控制器的使能,我们首先看一下S3C2440芯片手册里面的时序图。 上图中的HCLK我们已经设置成了100M。那么时钟周期是1/100M=10ns 然后下图是NandFlash芯片手册里面的时序图。 我们将S2C2440里面NandFlash控制器的时序图和NandFlash时序图结合起来看。 左图中的TACLS表示当我们的CLE/ALE发出之后,再过多长时间再发出WE信号,就是右图中的tcls-twp,而我们从右下图可以看到,tcls的最小值是12,twp的最小值也是12,就表明tcls-twp可以为零,也就表明CLE
[单片机]
<font color='red'>S3C2440</font>裸机------NandFlash编程_时序及初始化
基于S3C2440处理器SPI移植全过程
环境 硬件:S3C2440(ARM920T) 嵌入式操作系统:Linux2.6.24内核 文件系统:Yaffs2文件系统 服务器:SuSe10.0 Linux服务器 第一步:内核配置 需要在内核中选择以上几个选项: 很多网友发邮件说Linux2.6.24内核在SPI选项上未发现有Samsung S3C2440 series SPI 或 Samsung S3C24XX series SPI 和User mode SPI device driver support这两个选项。 其实在Linux2.6.24内核里已经兼容了对SPI的操作。只是在Linux2.6.24/drivers/spi/Kconfig中未能选中此选项
[单片机]
基于<font color='red'>S3C2440</font>处理器SPI移植全过程
s3c2440的FCLK、HCLK、PCLK
1、系统工作时钟频率 在对系统时钟进行提速之前,让我们先来了解下S3C2440上的工作时钟频率,FCLK,HCLK,PCLK,其中FCLK主要为ARM920T内核提供工作频率,如图2-44所示: 图2-44 ARM920T内核结构 HCLK主要为S3C2440 AHB总线(Advanced High performance Bus)上挂接硬件提供工作频率,AHB总线主要挂接有内存,NAND,LCD控制器等硬件,如图2-45所示: 图2-45 S3C2440 AHB总线上挂接硬件 PCLK主要为APB总线提供工作频率,由图2-46所示,APB总线主要挂接UART串口,Watchdog等硬件控制器。
[单片机]
<font color='red'>s3c2440</font>的FCLK、HCLK、PCLK
S3C2440学习之存储控制器
1、概述 数据位宽:BANK0:16/32位 其它BANK:8/16/32位 BANK0-BANK5可接ROM、SRAM BANK6-BANK7可接ROM、SRAM、SDRAM BANK0-6的起始地址是固定的,BANK7的起始地址是可调整的 BANK6-7的寻址范围可通过编程调整 所有存储器BANK的访问周期可编程 总线访问周期可通过插入外部wait来延长 支持SDRAM的自刷新和掉电模式 2、功能描述 (1)、BANK0的总线宽度由引脚OM1和OM2的电平信号决定。 (2)、BANK与ROM或SRAM连接时,由芯片的数据输出位宽决定将第几根地址线与芯片的第0根地址线连接,此处 主要是保证字节对齐 (3)、BANK6-
[单片机]
基于S3C2440和DM9000移植LWIP
终于开始我的第一篇笔记了。这回要做的事情,是以太网的移植。 使用mini2440已经有一段时间了。诸如裸机的LED,键盘开关等等等等也都试验过了,uCOS,WinCE也是浅尝了一下。如今想到了以太网。 由于mini2440的板上集成了一个DM9000的网卡,并且在CE系统里面成功的使用以太网与PC连接了。于是自然而然的想,能不能在uCOS下也实现以太网接口呢? 一上来什么都不懂,于是找一些资料,在这里要谢谢焦海波老师所著的嵌入式网络系统设计一书,移植过程中很多资料都来源于这本书。其次是mikenoodle的单片机驱动DM9000网卡一文,里面详细地讲述如何在2440裸机下驱动DM9000网卡。 首先明确我们需要做的事情是什么?为了
[单片机]
S3C2440 测试程序(四) 外部中断实验
TQ2440板上将4个按键K1~K4分别接在4个外部中断口上: K1 ---- EINT1(GPF1) K2 ---- EINT4(GPF4) K3 ---- EINT2(GPF2) K4 ---- EINT0(GPF0) K5 ---- EINT5(GPF5)外接单片机的I/O口 主程序里初始化:KeyPort_Init(); 之后while(1) ; void KeyPort_Init(void) { rGPFCON = rGPFCON & ~((3 0)|(3 2)|(3 4)|(3 8)|(3 10))\ |((2 0)|(2 2)|(2 4)|(2 8)|(2 10)); //将GPF
[单片机]
S3C2440移植linux3.4.2内核之支持YAFFS文件系统
获取yaffs2源码并给内核打补丁 首先获取yaffs2源码(参考git命令使用详解) cd /work/nfs_root git clone git@github.com:lifeyx/yaffs2.git //若下载出现error:403,可以试试vi /etc/resolv.conf,将nameserver地址改为: 114.114.114.114 将yaffs2源码来配置到内核里(使内核支持yaffs2) vi /work/nfs_root/yaffs2/README-linux 参考上图: /*给内核打补丁*/ cd /work/nfs_root/yaffs2/ ./patch-ker.sh c m /w
[单片机]

推荐帖子

路由信息协议(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设计
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved