0%

关于arm程序的一些理解1

2018年1月25日 下午9:37

先整体理解:

我觉得对arm编程就类似于一份这样的工作:

  1. 一个大的工厂,现在这个工厂已经实现了机器化生产,所有的机器就像我们电影中看到了一样它有一个总控,这个总控的操作形式就是一堆的开关、按键。当一个新的工人去这个工厂打工,他最终的目的是要学会如何操作那个总控,但是在这之前,他的绝大部分时间并不是去学习对应的开关是干什么的,因为即使有师傅告诉他这个开关是干啥的,他不一定能听懂这位师傅说的是什么,因为你对后面的这一大片的机器,以及各个机器之间的运作方式并不清楚,当让他做一个事情的时候,他必须分析出如何做到老板的要求。也就是说,其实这个人在开始阶段大部分时间的学习都放在了学习背后这些机器的原理上了
  2. 同样,在arm中我觉得写起程序的样子也是先找到对应的位置(地址),然后再判断这里是开或关或输入一个值(寄存器),我们学习arm的难点是取了解2440芯片的说明手册,以及芯片底盘原理图,这就是去了解整套机器本身的已经定死的运行原理,并不随你的操作不同而改变的内容,才是最最关键重要的内容

具体上来说有一些套路:

  1. 操作寄存器方式固定

    1. 就一步:赋值
    2. 连地址都给你封装到.h文件中了
    3. 简单的要死
  2. 清零,置位方法固定

    1. 一个原则:只操作我们需要改变的位,其他位我们不影响
    2. 结论:他俩并不是互逆的运算,而是各有各的功能,不被替代
    3. &一定用于清零 用1保护剩余位,清零位=0
    4. |一定用于置位 用0保护剩余位, 置位位=1
    5. 口诀:或的符号“|”,置位不就是1吗,其他的位置根据相反的关系记忆
      1
      2
      GPFCON &= ~((3<<8) | (3<<10) | (3<<12));#清零
      GPFCON |= ((1<<8) | (1<<10) | (1<<12));#置位
    6. &还有截取的能力
      1
      2
      tmp = ~val;
      tmp &= 7;
  3. 使用arm指令固定

    1. 在arm汇编中,指令会三个就行ldr str ldr(伪指令)
    2. 其他的cmp这些用的很少

两个问题:

C语言方便在哪里了?

  1. C语言有{},可以缩进写条件、循环,更加直观
  2. 不用记复杂指令,c会变量+条件+循环+函数+置位就可写各种程序

哪些是C语言无法方便的?

  1. 不管你使用哪种语言,查芯片手册是一定要做的,躲不了
  2. C语言带来的舒服可以理解成:他追求一种视觉上的舒服,分门别类的明显区分开来,一目了然,尤其针对代码比较多的项目,翻到哪页,我一看函数名就知道要干啥,我在接的看看条件和循环结构就知道他这个功能实现的大致步骤是个啥,这是汇编远远比不上的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "s3c2440_soc.h"

void delay(volatile int d)
{
while (d--);
}

int main(void)
{
int val = 0; /* val: 0b000, 0b111 */
int tmp;

/* 设置GPFCON让GPF4/5/6配置为输出引脚 */
GPFCON &= ~((3<<8) | (3<<10) | (3<<12));
GPFCON |= ((1<<8) | (1<<10) | (1<<12));

/* 循环点亮 */
while (1)
{
tmp = ~val;
tmp &= 7;
GPFDAT &= ~(7<<4);
GPFDAT |= (tmp<<4);
delay(100000);
val++;
if (val == 8)
val =0;
}

return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
.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 main

halt:
b halt

注:这是第9课的代码