uboot,s5pv210 , lowlevel_init.s 分析

ops/2025/1/22 12:24:35/

这是 三星的外围设备,在Board 目录下。

文件是 :board/samsung/goni/lowlevel_init.S

首先是这段代码。

   14 _TEXT_BASE:13     .word   CONFIG_SYS_TEXT_BASE1211     .globl lowlevel_init

这里的  CONFIG_SYS_TEXT_BASE  这是 在 文件

board/samsung/goni/config.mk 中。

34  CONFIG_SYS_TEXT_BASE = 0x34800000

疑问: 但是这里 为什么 将这个地址放在 .word 里面呢?

继续往下分析。

   16 lowlevel_init:15     mov r11, lr1413     /* r5 has always zero */12     mov r5, #01110     ldr r7, =S5PC100_GPIO_BASE9     ldr r8, =S5PC100_GPIO_BASE8     /* Read CPU ID */7     ldr r2, =S5PC110_PRO_ID6     ldr r0, [r2]5     mov r1, #0x000100004     and r0, r0, r13     cmp r0, r52     beq 100f1     ldr r8, =S5PC110_GPIO_BASE

这里 定义了一个 标号。 lowlevel_init

mov r11, lr  这句 将 lr 保存在了 r11 中,这里的目的是 在跳转函数的时候,能够跳转回来。

但是问题是。

疑问:最开始 这个 lr保存的是什么值呢?

mov r5, #0  这句 就是 让 r5 总是 保存0 值。

这两绝 保存了两个地址,没什么可以分析的。

   10     ldr r7, =S5PC100_GPIO_BASE
    9     ldr r8, =S5PC100_GPIO_BASE

ldr r2, =S5PC110_PRO_ID  这句在设置 id 寄存器的值。

我们来看看是什么值。

文件是:arch/arm/include/asm/arch-s5pc1xx/cpu.h

#define S5PC110_PRO_ID      0xE0000000

查看一下数据手册。

可以看到 如果读取这个寄存器的话,最终读取到的就是 0x43110020

这几句 实际上就是 读取了 第16位 , 就是1

   12     ldr r0, [r2]11     mov r1, #0x0001000010     and r0, r0, r1

然后跟 0 比较 , 如果 相等的话,就跳转到 100f , 很明显是不相等的,所以继续往下执行。

    9     cmp r0, r58     beq 100f

     ldr r8, =S5PC110_GPIO_BASE   这一句又保存了一个 寄存器的地址。

这两句 将r7 r8 相比较一下, 很明显是不相等的,所以继续执行。

   25     cmp r7, r824     beq skip_check_didle            @ Support C110 only


 

接下来分析这段代码。

   22     ldr r0, =S5PC110_RST_STAT21     ldr r1, [r0]20     and r1, r1, #0x000D0000

 这里的  S5PC110_RST_STAT

在文件  arch/arm/include/asm/arch-s5pc1xx/power.h 中。

#define S5PC110_RST_STAT        0xE010A000

看一下数据手册。

我们是开机复位。

属于 第0 位。

and r1, r1, #0x000D0000 这句是在得到第16--19 位。

也就是判断是不是 从sleep 模式 reset的。

很明显不是的。

继续往下分析。

    1     cmp r1, #(0x1 << 19)            @ DEEPIDLE_WAKEUP2     beq didle_wakeup3     cmp r7, r8

这句是让 r1 与 0x8 0000比较。

很明显是不同的。

所以执行。

cmp r7, r8      这句中,很明显也是不同的。

所以继续往下执行。

    5 skip_check_didle:6     addeq   r0, r8, #0x280              @ S5PC100_GPIO_J47     addne   r0, r8, #0x2C0              @ S5PC110_GPIO_J48     ldr r1, [r0, #0x0]              @ GPIO_CON_OFFSET9     bic r1, r1, #(0xf << 4)         @ 1 * 4-bit10     orr r1, r1, #(0x1 << 4)11     str r1, [r0, #0x0]              @ GPIO_CON_OFFSET1213     ldr r1, [r0, #0x4]              @ GPIO_DAT_OFFSET14     bic r1, r1, #(1 << 1)15     str r1, [r0, #0x4]              @ GPIO_DAT_OFFSET

addne   r0, r8, #0x2C0  会执行这一句。

然后我感觉后面就是 操作gpio 了。

r8 是 0xe020 0000

所以现在 r0 就是 ,0xe020 02c0

数据手册上显示。

所以它操作的就是 gpj4con

这几句就是在设置 gpj4con0 为输出。这是一个 pin脚。

    8     ldr r1, [r0, #0x0]              @ GPIO_CON_OFFSET9     bic r1, r1, #(0xf << 4)         @ 1 * 4-bit10     orr r1, r1, #(0x1 << 4)11     str r1, [r0, #0x0]              @ GPIO_CON_OFFSET

这几句就是在设置输出的数据。

   13     ldr r1, [r0, #0x4]              @ GPIO_DAT_OFFSET14     bic r1, r1, #(1 << 1)15     str r1, [r0, #0x4]              @ GPIO_DAT_OFFSET

将 第一位 输出为0

数据手册就是这里。

来看看原理图吧。,

就是这个脚,直接到了底板上。

这个脚可能在 goni 上有特别的用处。

然后是 继续往下分析代码

   11     /*10      * Initialize Async Register Setting for EVT19      * Because we are setting EVT1 as the default value of EVT0,8      * setting EVT0 as well does not make things worse.7      * Thus, for the simplicity, we set for EVT0, too6      *5      * The "Async Registers" are:4      *  0xE0F0_00003      *  0xE1F0_00002      *  0xF180_00001      *  0xF190_000099       *  0xF1A0_00001      *  0xF1B0_00002      *  0xF1C0_00003      *  0xF1D0_00004      *  0xF1E0_00005      *  0xF1F0_00006      *  0xFAF0_00007      */9     ldr     r0, =0xe0f000008     ldr     r1, [r0]7     bic     r1, r1, #0x16     str     r1, [r0]54     ldr     r0, =0xe1f000003     ldr     r1, [r0]2     bic     r1, r1, #0x11     str     r1, [r0]1161     ldr     r0, =0xf18000002     ldr     r1, [r0]3     bic     r1, r1, #0x14     str     r1, [r0]56     ldr     r0, =0xf19000007     ldr     r1, [r0]8     bic     r1, r1, #0x19     str     r1, [r0]1011     ldr     r0, =0xf1a0000012     ldr     r1, [r0]13     bic     r1, r1, #0x114     str     r1, [r0]1516     ldr     r0, =0xf1b0000017     ldr     r1, [r0]18     bic     r1, r1, #0x119     str     r1, [r0]2021     ldr     r0, =0xf1c0000022     ldr     r1, [r0]23     bic     r1, r1, #0x124     str     r1, [r0]2526     ldr     r0, =0xf1d0000027     ldr     r1, [r0]28     bic     r1, r1, #0x129     str     r1, [r0]3031     ldr     r0, =0xf1e0000032     ldr     r1, [r0]33     bic     r1, r1, #0x134     str     r1, [r0]3536     ldr     r0, =0xf1f0000037     ldr     r1, [r0]38     bic     r1, r1, #0x139     str     r1, [r0]4041     ldr     r0, =0xfaf0000042     ldr     r1, [r0]43     bic     r1, r1, #0x144     str     r1, [r0]

我不是很明白 这里的 时钟同步的意思。

看一下 数据手册。

看一下解释。但依然是不是很懂。

先放过去。这段代码 不分析了。

这一段的内容 ,在 4412 的数据手册中是找不到的

继续往下分析。

   23     /*24      * Diable ABB block to reduce sleep current at low temperature25      * Note that it's hidden register setup don't modify it26      */27     ldr r0, =0xE010C30028     ldr r1, =0x0080000029     str r1, [r0]

看解释 像是在减少电流的。

这几个寄存器是 隐藏的。 只有 oem 厂商知道,所以不分析。

然后继续往下分析。

   14 100:13     /* IO retension release */12     ldreq   r0, =S5PC100_OTHERS         @ 0xE010820011     ldrne   r0, =S5PC110_OTHERS         @ 0xE010E00010     ldr r1, [r0]9     ldreq   r2, =(1 << 31)              @ IO_RET_REL8     ldrne   r2, =((1 << 31) | (1 << 30) | (1 << 29) | (1 << 28))7     orr r1, r1, r26     /* Do not release retention here for S5PC110 */5     streq   r1, [r0]4

ldrne   r0, =S5PC110_OTHERS  会运行这段代码。

我们可以看下 数据手册。

就是这个寄存器,但是没有看懂。

到最后 它只有。

streq   r1, [r0]

而没有

strneq r1 [r0]

所以最后根本就没有起到作用。

不看了。

继续往下分析。

这是在关闭看门狗

    3     /* Disable Watchdog */2     ldreq   r0, =S5PC100_WATCHDOG_BASE      @ 0xEA2000001     ldrne   r0, =S5PC110_WATCHDOG_BASE      @ 0xE2700000184     str r5, [r0]

看一下数据手册。

r5 一直存放的是0 , 所以 将这个寄存器清零了。

第0 位是 关闭 看门狗的 复位功能

第1 位 是保留位。

第2位 是 关闭看门狗的中断位

第3位 ,第4位 是 对始终进行16 分频。

第5位 是关闭 看门狗的 定时功能。

第6位,第7 位是保留位。

第8 到 15位, 是再次进行预分频,这里 为0 。

继续往下分析。

这里是在设置 sram

    2     /* setting SRAM */3     ldreq   r0, =S5PC100_SROMC_BASE4     ldrne   r0, =S5PC110_SROMC_BASE5     ldr r1, =0x96     str r1, [r0]7

我们没有用到 sram 。

看一下数据手册吧。

主要是看它的 第0位, 与第3位。

第0位 设置了 16 位数据线。

第3位, 设置了nWBE  这个不懂。

继续往下分析。

   24     /* S5PC100 has 3 groups of interrupt sources */23     ldreq   r0, =S5PC100_VIC0_BASE          @ 0xE400000022     ldrne   r0, =S5PC110_VIC0_BASE          @ 0xF200000021     add r1, r0, #0x0010000020     add r2, r0, #0x002000001918     /* Disable all interrupts (VIC0, VIC1 and VIC2) */17     mvn r3, #0x016     str r3, [r0, #0x14]             @ INTENCLEAR15     str r3, [r1, #0x14]             @ INTENCLEAR14     str r3, [r2, #0x14]             @ INTENCLEAR1312     /* Set all interrupts as IRQ */11     str r5, [r0, #0xc]              @ INTSELECT10     str r5, [r1, #0xc]              @ INTSELECT9     str r5, [r2, #0xc]              @ INTSELECT87     /* Pending Interrupt Clear */6     str r5, [r0, #0xf00]            @ INTADDRESS5     str r5, [r1, #0xf00]            @ INTADDRESS4     str r5, [r2, #0xf00]            @ INTADDRESS

这一段是跟中断相关的。

中断这里不是很理解。

简单看一下, 这里的 中断的几种状态。

这里比较难理解的是 这个 active and pending .

这是他的解释。

总结: 就是 在 cpu 处理这个中断的时候,又来了中断,这时候他的状态就是 active and pending 的状态了。

继续往分析。

这几句应该是在设置 寄存器的基地址。

   22     ldrne   r0, =S5PC110_VIC0_BASE          @ 0xF200000021     add r1, r0, #0x0010000020     add r2, r0, #0x00200000

看一下 数据手册。

这个寄存器的内容就是 将中断 变成 inactive 了。

其实他的注释已经说了。

这几句就是在设置 fiq

   12     /* Set all interrupts as IRQ */11     str r5, [r0, #0xc]              @ INTSELECT10     str r5, [r1, #0xc]              @ INTSELECT9     str r5, [r2, #0xc]              @ INTSELECT

数据手册中是这么写的。

这是设置 irq 的。

这几句代码 ,是设置 pending 的 , 将pending clear .

    7     /* Pending Interrupt Clear */6     str r5, [r0, #0xf00]            @ INTADDRESS5     str r5, [r1, #0xf00]            @ INTADDRESS4     str r5, [r2, #0xf00]            @ INTADDRESS

这个应该是 clear pending 的。

疑问: 他为什么要这么做呢? 有什么流程吗?

我觉得这里我有必要 ,重新复习一下  彭老师的 4412 的裸机这里。

中断输入异常的一种。

中断的处理流程,这个图非常的重要。

总结一下:

1 中断发生之后, 硬件会自动完成4步, 保存cpsr----->设置cpsr ---->设置LR----->pc跳转到 异常向量表

2 然后 在异常函数中, 会  修改LR的值---->保存现场寄存器---->跳转到 harndleirq ----->回复现场寄存器---->PC=LR ,

注意: 这个 异常函数是 厂商自己写的, 这个handleirq 函数 是我们自己写的,这是一个回调函数。

中断组成部分: 模块+中断控制器+cpu

中断源 , 4412 是 GIC , 单片机 是VIC。s5pv210 就是 Vic

看一下数据手册。

可以看到 有几条路线 到 cpu

1  首先是   中断源 ----->gic ---->cpu

2  然后是  中断源 -----> int _combiner---->gic ----->cpu

3 这个 core_sfr 就是 控制 int_combiner + gic 的寄存器 所使用的。

然后看一下 关于中断源的表述。

总结一下:

1      SGI : oftware Generated Interrupts (SGIs[15:0], ID[15:0])  , 这是软中断, 中断号,与 SGI编号是一致的。这个不是很理解。

2    PPI : rivate Peripheral Interrupts (PPIs[15:0], ID[31:16]) , 这是私有中断,中断号与PPI的编号已经不一致了,这是 一个 CPU核 独有的中断。

3  SPI : hared Peripheral Interrupts (SPIs[127:0], ID[159:32])  这是 外联部连接的中断, 每个 cpu 核心 都可以处理的, 比如 gpio 产生的中断。

思考,

我知道 gic 是通过 中断号 来区分 不同的中断类型的。但是,这些中断号是怎么产生的呢? 比如 uart 的中断, 是不是 只能由 内部的 某个线 来产生,而不能够由 gpio 来产生,也就是说 有的 中断号的路线 是定死的。可以这么理解吗?

还有就是关于 挂起的状态, 这个标志位 ,是在gic 的控制器中,还是在 cpu 核中呢?

然后是关于 gic 的 了解。

gic 的框图。

gic 的功能。

1 使能或者是禁止中断。

2 设置中断是分配到 fiq 还是分配到 irq .

3 设置 分配到哪个 核心上。

4 设置 电平 是边沿触发, 还是电平出发, 这里的出发方式与 外设的 出发方式是不一样的,这里主要指的是 , gic 与cpu 的 触发方式。

 gic 的内部的结构。

分发器的作用。

1 中断源的使能。 中断源是通过 interrupt id 来进行区分的。

2 设置触发方式。

3 优先级排序。

4 设置分发到哪个cpu 上。

然后是 cpu interface 的功能。

1  也可以 使能或者禁止 中断源。

2 应答中断, 这应该也是与 分发器的交互。

3 通知中断处理完毕,这也是与 分发器的交互。

4 设定优先级的掩码

5 设定 中断的抢占策略。

6 多个中断到来时, 选择一个 优先级 最高的中断,并通知cpu

然后就是 中断的状态的 维护。

这块 我不看,前面已经说过了。

然后是举个例子。

比如我要使用一个 按键的中断,

步骤是。

框图:

流程大致如下:

1 首先是 设置 gpio , 的 触发方式, 设置中断的掩码,就是 中断是否打开。

2 然后就是 设置分发器对中断 源 是否打开。

3 然后是 打开分发器, 到cpu interface 的通路。

4 然后是选择 分发到哪个 cpui interface 。

5 然后是 到了cpu interface , 设置中断的优先级的掩码。

6 然后是 打开 cpu interface 到 cpu 的通路。

然后 cpu 相应完了中断之后,还要清楚相应的中断,

框图如下;

1 首先是清除了 gpio 的中断。

2 然后是 清除 分发器的中断标志。

3 然后是清除 cpu interface 的中断标志。

具体的 gic 的寄存器我就不去看了。

我觉得了解到这里就可以了。

然后就是 关于串口的分析了。

同步通讯  spi  , 同步的话,是有时钟线的, 然后 只能在板子上。

异步通讯  uart ,  异步是没有时钟线的, 但是传输距离长。

然后是 波特率与比特率

其实 就是 说 比特率 就是一秒传了多少个bit .

而波特率 需要 比特率 除以10 。

波特率与通信距离的关系。

这个表格没有找到, 不找了。

各个位数的解析。

232 的 接口定义。

疑问:为什么 sp3232 外围的 电阻,电容 要接在外面,而不是 做到里面。

因为, 芯片 容易做的是 晶体管,难做的是大电阻,大电容。

然后是 数据手册中的框图。

有buffer 队列的含义 就是 这部分电路 可以自己发送数据了, cpu 可以干别的事情, 而在单片机的时候,是 没发送一个字节, 就要中断一次。

然是关于  rts cts 的流控。

数据手册的框图。

就是, rts ----cts 是一对。

然后是 uart 的时钟的选择框图。

然后是 数据手册中的 uart 的寄存器,

大概是 15个寄存器,用到的就几个。

然后就是开始分析代码了。

就是这一句了。

    1     /* for UART */2     bl  uart_asm_init3

这就是所有的代码了。

   53 /*52  * uart_asm_init: Initialize UART's pins51  */50 uart_asm_init:49     /* set GPIO to enable UART0-UART4 */48     mov r0, r847     ldr r1, =0x2222222246     str r1, [r0, #0x0]          @ S5PC100_GPIO_A0_OFFSET45     ldr r1, =0x0000222244     str r1, [r0, #0x20]         @ S5PC100_GPIO_A1_OFFSET4342     /* Check S5PC100 */41     cmp r7, r840     bne 110f3938     /* UART_SEL GPK0[5] at S5PC100 */37     add r0, r8, #0x2A0          @ S5PC100_GPIO_K0_OFFSET36     ldr r1, [r0, #0x0]          @ S5PC1XX_GPIO_CON_OFFSET35     bic r1, r1, #(0xf << 20)        @ 20 = 5 * 4-bit34     orr r1, r1, #(0x1 << 20)        @ Output33     str r1, [r0, #0x0]          @ S5PC1XX_GPIO_CON_OFFSET3231     ldr r1, [r0, #0x8]          @ S5PC1XX_GPIO_PULL_OFFSET30     bic r1, r1, #(0x3 << 10)        @ 10 = 5 * 2-bit29     orr r1, r1, #(0x2 << 10)        @ Pull-up enabled28     str r1, [r0, #0x8]          @ S5PC1XX_GPIO_PULL_OFFSET2726     ldr r1, [r0, #0x4]          @ S5PC1XX_GPIO_DAT_OFFSET25     orr r1, r1, #(1 << 5)       @ 5 = 5 * 1-bit24     str r1, [r0, #0x4]          @ S5PC1XX_GPIO_DAT_OFFSET2322     b   200f21 110:20     /*19      * Note that the following address18      * 0xE020'0360 is reserved address at S5PC10017      */16     /* UART_SEL MP0_5[7] at S5PC110 */15     add r0, r8, #0x360          @ S5PC110_GPIO_MP0_5_OFFSET14     ldr r1, [r0, #0x0]          @ S5PC1XX_GPIO_CON_OFFSET13     bic r1, r1, #(0xf << 28)        @ 28 = 7 * 4-bit12     orr r1, r1, #(0x1 << 28)        @ Output11     str r1, [r0, #0x0]          @ S5PC1XX_GPIO_CON_OFFSET109     ldr r1, [r0, #0x8]          @ S5PC1XX_GPIO_PULL_OFFSET8     bic r1, r1, #(0x3 << 14)        @ 14 = 7 * 2-bit7     orr r1, r1, #(0x2 << 14)        @ Pull-up enabled6     str r1, [r0, #0x8]          @ S5PC1XX_GPIO_PULL_OFFSET54     ldr r1, [r0, #0x4]          @ S5PC1XX_GPIO_DAT_OFFSET3     orr r1, r1, #(1 << 7)       @ 7 = 7 * 1-bit2     str r1, [r0, #0x4]          @ S5PC1XX_GPIO_DAT_OFFSET1 200:467     mov pc, lr

这一段很明显是  在设置 gpio 的。

   48     mov r0, r847     ldr r1, =0x2222222246     str r1, [r0, #0x0]          @ S5PC100_GPIO_A0_OFFSET45     ldr r1, =0x0000222244     str r1, [r0, #0x20]         @ S5PC100_GPIO_A1_OFFSET

这几个引脚其实 就我是没有使用到的。

   38     /* UART_SEL GPK0[5] at S5PC100 */37     add r0, r8, #0x2A0          @ S5PC100_GPIO_K0_OFFSET36     ldr r1, [r0, #0x0]          @ S5PC1XX_GPIO_CON_OFFSET35     bic r1, r1, #(0xf << 20)        @ 20 = 5 * 4-bit34     orr r1, r1, #(0x1 << 20)        @ Output33     str r1, [r0, #0x0]          @ S5PC1XX_GPIO_CON_OFFSET

看一下数据手册。

就是这个。

在看一下原理图。

就是这些。

但是 实际上, 这个开发板 , 内存用的是 port1 口。

port0 口作为的是 DM9000 网卡, 或者是 sd 卡。

所以 这个 MP0 都可以不用设置。

这几句是在设置 上下拉, 以及 输出电平。

    8     ldr r1, [r0, #0x8]          @ S5PC1XX_GPIO_PULL_OFFSET9     bic r1, r1, #(0x3 << 14)        @ 14 = 7 * 2-bit10     orr r1, r1, #(0x2 << 14)        @ Pull-up enabled11     str r1, [r0, #0x8]          @ S5PC1XX_GPIO_PULL_OFFSET1213     ldr r1, [r0, #0x4]          @ S5PC1XX_GPIO_DAT_OFFSET14     orr r1, r1, #(1 << 7)       @ 7 = 7 * 1-bit15     str r1, [r0, #0x4]          @ S5PC1XX_GPIO_DAT_OFFSET

由于 在 下载 的 uboot 的源码中,没有 关于串口的设置, 所以 他自己 设置了串口。

这块还是 挺厉害的。

接下来看一下 他写的代码

ldr r0, =0xe2900000        @ulcon
ldr r1,=3
str r1,[r0]ldr r1,=ox385               @ucon
str r1,[r0,#0x4]ldr r1,=1                    @ufcon
str r1,[r0,#0x8]ldr r1,=0                    @umcon
str r1,[r0,#0xc]ldr r1,=0x34       @ubrdiv0 =34                
str r1,[r0,#0x28]ldr r1,=0xDFDD       @udivslot = DFDD
str r1,[r0,#0x2c]ldr r0,=0xe2900028     @ u
ldr r1,=0x55
str r1,[r0]ldr r1,=0x01            @ a
str r1,[r0]ldr r1,=0x72             @ r
str r1,[r0]ldr r1,=0x74             @t
str r1,[r0]ldr r1,=0xA             @ \r
str r1,[r0]ldr r1,=0xD             @ \n
str r1,[r0]

这里需要注意的是 对于 uart 时钟的选择。

这里主要涉及到的是时钟的计算。

就是这些。

我们知道 ,pclk 是 66M, bps 是 115200 ,

这里的 div_val 是一个概念, 不是寄存器, 指的是, 你从66M 分频的值。这是你的目的。

ubrdivn  与 udivslotn 有点像粗调与 细调  的 意思。

然后就是 关于fifo 的触发方式的 解释。

关于触发方式在 ucon 中进行设置的。

如图:

这里的 pulse 指的是边沿触发。

level 指的是 高点电平触发。

看看  它对于 fifo 的解释。

对于发送来说: 如果 fifo 中字节的数量 少于了你设置的这个阈值了,那么就触发一个中断。

对于接受来说: 如果fifo 中的字节的数量, 大于你设置的一个数值了,就会触发一个中断。

那么这个 阈值 怎么设置呢。

在ufcon 中。

如图:

还有就是, uart0 ,uart1 , uart2 ,的fifo 的大小是不同的。

好像uart0 是最大的, 200多。

然后就是关于 一个连接的问题:

虽然 他 写了 关于 Lowlevel_init.s 的 串口的内容。

但是根本不会执行。

因为 , lowlevle 文件,是在 最后才连接的。

所以16K 里面不包含这个这个文件,

所以解决的方法也是, 将lowlevel 放到start.o 的后面。

他之所以 能这么做,是因为这个文件也没有什么依赖,如果依赖的多了可能就不能这么做了。

疑问: 但是 这里他改的是 makefile 文件。不知道能不能改 lds 文件。

他改的是这里。

然后就是 继续往下分析。

开始分析 怎么样使用 uart 显示内存中读到的数据

逻辑是这样的。

我需要将  0x23144asdf  -----> 字符串  0x xxxxx

首先需要先 输出 字符 0x

然后需要将接收到的, 0x xxxx , 先左移动,28 位,

然后与10 比较 如果小于10 就加上 字符0  的 数值。

如果是大于10 的话,就加上 字符 a 的数值。

然后 在向左移动 24 位, 在循环一次,以此类推。

代码如下:

display hex:ldr r1,=0xe29000020     @txldr r2,=0x30str r2,[r1]               @ '0'ldr r2,=0x78str r2,[r1]               @ 'x'ldr r3,=28                 @向左移动的位数display loop_cnt:ldr r2,r0,r3and r2,r2,#0xfcmp r2,#10addmi r2,r2,#30            @是否大于10 addpi r2,r2,#37str r2,[r1]                @写入 txsub r3,r3,#24                @向左的移动位数递减cmp r3,0bpl display loop_cnt          @如果大于等于0 就在循环一次。ldr r2,=0xAstr r2,[r1]                    @'\r'ldr r2,=0xDstr r2,[r1]                    @'\n'mov pc,lr

那么如何使用 这个汇编函数呢?

这样。

ldr r0,=0x123456
bl display_hex

那么如何去读取内存中的地址的值呢?

就读取这个内存地址。

如下:

ldr r0,=0xe2900020
bl display hexdisplay hex:ldr r0,[r0]            @就多了这一步。ldr r1,=0xe29000020     @txldr r2,=0x30str r2,[r1]               @ '0'ldr r2,=0x78str r2,[r1]               @ 'x'ldr r3,=28                 @向左移动的位数display loop_cnt:ldr r2,r0,r3and r2,r2,#0xfcmp r2,#10addmi r2,r2,#30            @是否大于10 addpi r2,r2,#37str r2,[r1]                @写入 txsub r3,r3,#24                @向左的移动位数递减cmp r3,0bpl display loop_cnt          @如果大于等于0 就在循环一次。ldr r2,=0xAstr r2,[r1]                    @'\r'ldr r2,=0xDstr r2,[r1]                    @'\n'mov pc,lr

到此为止 ,uart 就分析完了。

基本对uart 已经了解的差不多了。


http://www.ppmy.cn/ops/152186.html

相关文章

app版本控制java后端接口版本管理

java api version 版本控制 java接口版本管理 1 自定义 AppVersionHandleMapping 自定义AppVersionHandleMapping实现RequestMappingHandlerMapping里面的方法 public class AppVersionHandleMapping extends RequestMappingHandlerMapping {Overrideprotected RequestCondit…

R语言的图形用户界面

R语言的图形用户界面简介 随着数据科学和统计分析的快速发展&#xff0c;R语言作为一种强大的统计分析工具&#xff0c;受到了越来越多研究人员和数据科学家的青睐。R语言不仅具有强大的计算能力&#xff0c;还拥有丰富的图形绘制功能&#xff0c;为数据可视化提供了便利。为了…

mapbox js本地化部署

移除mapbox-gl.js的token检测&#xff0c;使用本地sprite和glyphs&#xff0c;并支持相对路径而不是网络地址url 版本 vue3&#xff08;v3.5.13&#xff09; vite&#xff08;v6.0.1&#xff09;mapbox-gl.js&#xff08;v3.9.3&#xff09; 参考 https://github.com/HuHongYon…

2025年1月21日刷题记录

1.leetcode1768题目 链接&#xff1a;1768. 交替合并字符串 - 力扣&#xff08;LeetCode&#xff09; 代码&#xff1a; class Solution { public:string mergeAlternately(string word1, string word2) {string word3;int a word1.size(), b word2.size();int i 0, j 0…

Visual Studio2019调试DLL

1、编写好DLL代码之后&#xff0c;对DLL项目的属性进行设置&#xff0c;选择待注入的DLL&#xff0c;如下图所示 2、生成DLL文件 3、将DLL设置为启动项目之后&#xff0c;按F5启动调试。弹出选择注入的exe的界面之后&#xff0c;使用代码注入器注入步骤2中生成的dll&#xff…

从零搭建一套远程手机的桌面操控和文件传输的小工具

从零搭建一套远程手机的桌面操控和文件传输的小工具 --ADB连接专题 一、前言 前面的篇章中&#xff0c;我们确定了通过基于TCP连接的ADB控制远程手机的操作思路。本篇中我们将进行实际的ADB桥接的具体链路搭建工作&#xff0c;从原理和实际部署和操作层面上&#xff0c;从零…

算法-键盘行

力扣题目&#xff1a;500. 键盘行 - 力扣&#xff08;LeetCode&#xff09; 给你一个字符串数组 words &#xff0c;只返回可以使用在 美式键盘 同一行的字母打印出来的单词。键盘如下图所示。 请注意&#xff0c;字符串 不区分大小写&#xff0c;相同字母的大小写形式都被视…

【Unity】使用Canvas Group改变UI的透明度

目录 一、前言二、Canvas Group三、结合DOTween达到画面淡进的效果 一、前言 在平时开发中&#xff0c;可以通过控制材质、Color改变UI透明度&#xff0c;除此之外还可以CanvasGroup组件来控制透明度。 二、Canvas Group 官方文档链接&#x1f449;&#x1f449; 点击进入 …