Chinaunix首页 | 论坛 | 博客
  • 博客访问: 128534
  • 博文数量: 38
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 191
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-16 11:31
个人简介

嵌入式新人

文章分类

全部博文(38)

文章存档

2016年(38)

我的朋友

分类: 嵌入式

2016-05-24 12:58:25

        汇编语言可以直接对硬件进行操作,因此他是很高效的,所以启动代码使用汇编语言进行编写,然后讲程序交给C语言进行后续的操作,这就涉及到C语言运行环境的设置(主要是设置栈和汇编语言对C函数的调用。
1 栈的设置
         C语言运行时需要栈(C语言的局部变量都是通过栈来实现的),因此我们需要在C语言运行前,使用汇编语言给后续的C代码设置合理合法的栈地址,否则C代码中定义的局部变量就会落空,整个程序就会死掉。
注:用C语言编写单片机程序(如51单片机)或应用程序时,通常并不会“明文”设置栈,但C代码依然可以运行,原因是:单片机硬件初始化时会默认提供一个可用的栈;应用程序中我们编写的C代码其实并不是全部代码,编译器(gcc)会在链接时自动添加一个头代码,这个头代码就会引导并设置C语言需要的栈。
         ARM的7中工作模式和37个寄存器的2.3节说明每种工作模式下都有自己的独立的堆栈指针(SP)寄存器(r13),这样设计的目的是: 如果各种工作模式共用同一个SP寄存器,意味着整个程序(操作系统内核程序、用户应用程序)都用同一个栈的,应用程序一旦出错(譬如栈溢出),就连累操作系统的栈也损坏,整个操作系统就会崩溃,这样的操作系统设计是脆弱的,不合理的。因此解决方案就是各种工作模式使用不同的栈,操作系统内核使用自己的栈,每个应用程序也使用自己独立的栈,各不关联,一个损坏不会连累其他人。
        我们希望设置SVC模式下的SP寄存器,而ARM复位启动后默认进入SVC模式,因此我们直接设置SP寄存器即可。结合iROM_application_note中的memory map,可知SVC栈应该设置为0xD0037D80(S5PV210s使用满减栈,因此地址为0xD0037D80),代码如下

点击(此处)折叠或打开

  1. #define SVC_STACK 0xd0037d80

  2.  ldr sp, =SVC_STACK
  3.   
  4.  //完整程序见 start.S

 
    
2 C语言函数的调用

    汇编语言使用bl指令来调用C语言函数,如调用led_blink函数的代码为

点击(此处)折叠或打开

  1. bl led_blink // led_blink是C语言实现的一个函数

汇编语言设置栈和调用C语言函数的代码展示
    在5.rar 中,包括start.S、led.c、Makefile、mkv210_image.c和write2sd(这里没有用处,仅前4个文件有用),

下面通过阅读start.S和led.c的代码,可以看到栈的设置、汇编语言使用bl指令来调用C语言函数和C语言调用函数的具体指令和过程

点击(此处)折叠或打开

  1. /*
  2.  * 文件名:    start.S    
  3.  * 作者:    朱老师,我稍作修改
  4.  * 描述:    演示汇编开关icache
  5.  */

  6. #define WTCON        0xE2700000
  7. #define SVC_STACK    0xd0037d80

  8. .global _start                    // 把_start链接属性改为外部,这样其他文件就可以看见_start了
  9. _start:
  10.     // 第1步:关看门狗(向WTCON的bit5写入0即可)
  11.     ldr r0, =WTCON
  12.     ldr r1, =0x0 //朱老师的写法
  13.     ldr r1, =0x00008001 //我的写法,目的不破坏WTCON中其他位的默认值
  14.     str r1, [r0]
  15.     
  16.     // 第2步:设置SVC栈
  17.     ldr sp, =SVC_STACK
  18.     
  19.     // 第3步:开/关icache
  20.     mrc p15,0,r0,c1,c0,0; // 读CP15的c1到r0中
  21.     //bic r0, r0, #(1<<12) // bit12 置0 关闭iCache
  22.     orr r0, r0, #(1<<12) // bit12 置1 启用iCache
  23.     mcr p15,0,r0,c1,c0,0; // 写r0到CP15的c1中

  24.     // 调用C函数led_blink
  25.     bl led_blink                    // led_blink是C语言实现的一个函数
  26.     
  27.     // 汇编死循环不能少
  28.     b .


点击(此处)折叠或打开

  1. /*
  2.  * 文件名:    led.c    
  3.  * 作者:    朱老师,我稍作修改
  4.  * 描述:    演示汇编开关icache
  5.  */

  6. #define GPJ0CON        0xE0200240
  7. #define GPJ0DAT        0xE0200244

  8. #define rGPJ0CON    *((volatile unsigned int *)GPJ0CON)
  9. #define rGPJ0DAT    *((volatile unsigned int *)GPJ0DAT)

  10. void delay(void);

  11. // 该函数实现led闪烁效果
  12. void led_blink(void)
  13. {
  14.     // led初始化,把GPJ0CON中设置为输出模式
  15.     //volatile unsigned int *p = (unsigned int *)GPJ0CON;
  16.     //volatile unsigned int *p1 = (unsigned int *)GPJ0DAT;
  17.     rGPJ0CON = 0x11111111;
  18.     
  19.     while (1)
  20.     {
  21.         // led亮
  22.         rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5));
  23.         // 延时
  24.         delay();
  25.         // led灭
  26.         rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));
  27.         // 延时
  28.         delay();
  29.     }
  30. }


  31. void delay(void)
  32. {
  33.     volatile unsigned int i = 900000;        // volatile 让编译器不要优化,这样才能真正的减
  34.     while (i--);                            // 才能消耗时间,实现delay
  35. }



阅读(2062) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~