树莓派4B 汇编实现串口打印

GPIO寄存器

在BCM2711中,共有58个GPIO管脚,被分成了3个banks,Bank0包含的GPIO从0到27,bank1包含的GPIO从28-45,bank2包含的GPIO从46到57。其中GPIO寄存器有GPFSELn、GPSETn、GPCLRn等,下面具体描述这些寄存器的作用:

  • 寄存器GPFSEL0-GPFSEL5 表示功能寄存器,指定管脚为输入、输出等,每3位决定一个管脚:

    • 000 = GPIO Pin 9 is an input     

    • 001 = GPIO Pin 9 is an output

    • 100 = GPIO Pin 9 takes alternate function 0

    • 101 = GPIO Pin 9 takes alternate function 1

    • 110 = GPIO Pin 9 takes alternate function 2

    • 111 = GPIO Pin 9 takes alternate function 3

    • 011 = GPIO Pin 9 takes alternate function 4

    • 010 = GPIO Pin 9 takes alternate function 5

其中:(寄存器---地址--描述)

对于树莓派4B有两种地址模式:Full 35-bit Address Map和Legacy master address

 The peripheral addresses specified in this document are legacy master addresses. Software

accessing peripherals using the DMA engines must use 32-bit legacy master addresses. The Main

peripherals are available from 0x7C00_0000 to 0x7FFF_FFFF. Behind the scenes, the VideoCore

transparently translates these addresses to the 35-bit 0x4_7nnn_nnnn addresses.

So a peripheral described in this document as being at legacy address 0x7Enn_nnnn is available in the

35-bit address space at 0x4_7Enn_nnnn, and visible to the ARM at 0x0_FEnn_nnnn if Low Peripheral

mode is enabled.

寄存器

地址

描述

GPFSEL0

0xEF200000

决定GPIO0-GPIO9的管脚功能

GPFSEL1

0xEF200004

决定GPIO10-GPIO19的管脚功能

GPFSEL2

0xEF200008

决定GPIO20-GPIO29的管脚功能

GPFSEL3

0xEF20000C

决定GPIO30-GPIO39的管脚功能

GPFSEL4

0xEF200010

决定GPIO40-GPIO49的管脚功能

GPFSEL3

0xEF200014

决定GPIO50-GPIO57的管脚功能

  • 寄存器GPSET0-GPSET1 ,设置为1,每一位决定一个管脚

    • 0 = NO effect

    • 1 = Set GPIO pin n

汇编实现串口打印:

  • 确定外设设备的基地址

定义所需的寄存器:

#define BASE_ADDR 0xFE000000
#define _GPFSEL1 0x200004
#define GPFSEL1 (BASE_ADDR+_GPFSEL1)

#define U_BASE (BASE_ADDR+0x00201000)
#define U_CR_REG (U_BASE+0x30)
#define U_IBRD_REG   (U_BASE+0x24)
#define U_FBRD_REG   (U_BASE+0x28)
#define U_LCRH_REG   (U_BASE+0x2C)
#define U_IMSC_REG   (U_BASE+0x38)
#define U_FR_REG     (U_BASE+0x18)
#define U_DATA_REG   (U_BASE)

  • 确定串口的GPIO

GPIO14和GPIO15

从上图可以看出,我们应该将GPFSEL1的[14:12]和[17:15]设置为b100

    ldr x1, =GPFSEL1
    ldr w3, [x1]
    mov w4, 4
    //设置GPFSEL[12:14] 为b100
    bfi w3, w4, 12, 3
    //设置GPFSEL[15:17] 为b100
    bfi w3, w4, 15, 3
    str w3, [x1]
  • 关闭串口

    ldr x0, =U_CR_REG
    str wzr, [x0]

 

  • 设置波特率

设置波特率需要设置IBRD_REG和FBRD_REG

计算公式:

BAUDDIV = (FUARTCLK/(16 * Baud rate))

其中FUARTCLK是在config.txt定义,值为48*10^6 

BAUDDIV = 48*16^6 / (16*115200) = 26.0416666667

integer part = 26

fractional part = (int)((0.0416666667 *64) + 0.5) = 3

generated baud rate divisor = 26 + (3 / 64) = 26.046875

generated baud rate = (48 * 10^6) / (16 * 26.046875) = 115177

error = |(115177 - 115200) / 115200 * 100| = 0.02%

 ldr x0, =U_IBRD_REG
    mov w1, 26
    str w1, [x0]

    ldr x0, =U_FBRD_REG
    mov w1, 3
    str w1, [x0]
  • 使能 FIFOs和 8 bits 帧

           

 /* enable FIFOs and 8 bits frames */
    ldr x0, =U_LCRH_REG
    mov w2, #0x70
    str w2, [x0]

  • 屏蔽串口的中断

   ldr x0, =U_IMSC_REG
    str wzr, [x0]
  • 使能串口(接收和发送)

   /* enable UART, receive and transmit */
    ldr x1, =U_CR_REG
    mov w2, #0x301 //1 | (1<<8) | (1<<9)
    str w2, [x1]

初始化代码如下:

.align 2
.global _init_pl_uart
_init_pl_uart:

    ldr x1, =GPFSEL1
    ldr w0, [x1]
    mov w4, 4
    //设置GPFSEL[12:14] 为b100
    bfi w3, w4, 12, 3
    //设置GPFSEL[15:17] 为b100
    bfi w3, w4, 15, 3
    str w3, [x1]
    /* delay */
    mov x0, #150
1:
    sub x0, x0, #1
    cmp x0, #0
    bne 1b
    isb
    //disable uart
    ldr x0, =U_CR_REG
    str wzr, [x0]

    /*
     * baud divisor = UARTCLK / (16 * baud_rate)
    = 48 * 10^6 / (16 * 115200) = 26.0416666667
    integer part = 26
    fractional part = (int) ((0.0416666667 * 64) + 0.5) = 3
    generated baud rate divisor = 26 + (3 / 64) = 26.046875
    generated baud rate = (48 * 10^6) / (16 * 26.046875) = 115177
    error = |(115177 - 115200) / 115200 * 100| = 0.02%
    */
    ldr x0, =U_IBRD_REG
    mov w1, #26
    str w1, [x0]

    ldr x0, =U_FBRD_REG
    mov w1, #3
    str w1, [x0]

    /* enable FIFOs and 8 bits frames */
    ldr x0, =U_LCRH_REG
    mov w2, #0x70
    str w2, [x0]

    /* mask interupts */
    ldr x0, =U_IMSC_REG
    str wzr, [x0]

    /* enable UART, receive and transmit */
    ldr x1, =U_CR_REG
    mov w2, #0x301 //1 | (1<<8) | (1<<9)
    str w2, [x1]
    isb
    ret
  • 实现打印一个字符

判断uart flag寄存器能否传输

然后向UART Data寄存器写入数据

.global put_char_uart
put_char_uart:
    mov x7, x30
    ldr x1, =U_FR_REG
1:
    ldr w2, [x1]
    and w2, w2, #0x20
    cmp w2, #0x0
    b.ne 1b

    ldr x1, =U_DATA_REG
    str w0, [x1]

    mov x30, x7
    ret

打印字符串:

.global put_string_uart
put_string_uart:
    mov x4, x0
    //save lr
    mov x6, x30
1:
    ldrb w0, [x4]
    bl put_char_uart
    add x4, x4, 1
    cmp w0, #0
    b.ne 1b
    //restore lr
    mov x30, x6
    ret

打印EL等级:

.section  .rodata
.align 3
.globl el_string1
el_string1:
    .string "Booting at EL"

.section .text
.global print_el
print_el:
    mov x10, x30
    /*
       print EL
     */
    adrp x0, el_string1
    add x0, x0, :lo12:el_string1
    bl put_string_uart

    mrs x5, CurrentEL
    /* get the currentEL value */
    lsr x2, x5, #2
    mov x0, #48
    add x0, x0, x2
    bl put_char_uart
    /* print the new line tab */
    mov x0, #10
    bl put_char_uart

    mov x30, x10
    ret

所有的代码如下:

#define BASE_ADDR 0xFE000000
#define _GPFSEL1 0x200004
#define GPFSEL1 (BASE_ADDR+_GPFSEL1)

#define U_BASE (BASE_ADDR+0x00201000)
#define U_CR_REG (U_BASE+0x30)
#define U_IBRD_REG   (U_BASE+0x24)
#define U_FBRD_REG   (U_BASE+0x28)
#define U_LCRH_REG   (U_BASE+0x2C)
#define U_IMSC_REG   (U_BASE+0x38)
#define U_FR_REG     (U_BASE+0x18)
#define U_DATA_REG   (U_BASE)

.section  .rodata
.align 3
.globl el_string1
el_string1:
    .string "Booting at EL"

.section .text
.align 2
.global put_char_uart
put_char_uart:
    mov x7, x30
    ldr x1, =U_FR_REG
1:
    ldr w2, [x1]
    and w2, w2, #0x20
    cmp w2, #0x0
    b.ne 1b

    ldr x1, =U_DATA_REG
    str w0, [x1]

    mov x30, x7
    ret

.global put_string_uart
put_string_uart:
    mov x4, x0
    //save lr
    mov x6, x30
1:
    ldrb w0, [x4]
    bl put_char_uart
    add x4, x4, 1
    cmp w0, #0
    b.ne 1b
    //restore lr
    mov x30, x6
    ret

.global _init_pl_uart
_init_pl_uart:

    ldr x1, =GPFSEL1
    ldr w0, [x1]
    mov w4, 4
    //设置GPFSEL[12:14] 为b100
    bfi w3, w4, 12, 3
    //设置GPFSEL[15:17] 为b100
    bfi w3, w4, 15, 3
    str w3, [x1]

    /* delay */
    mov x0, #150
1:
    sub x0, x0, #1
    cmp x0, #0
    bne 1b
    isb

    //disable uart
    ldr x0, =U_CR_REG
    str wzr, [x0]

    /*
     * baud divisor = UARTCLK / (16 * baud_rate)
    = 48 * 10^6 / (16 * 115200) = 26.0416666667
    integer part = 26
    fractional part = (int) ((0.0416666667 * 64) + 0.5) = 3
    generated baud rate divisor = 26 + (3 / 64) = 26.046875
    generated baud rate = (48 * 10^6) / (16 * 26.046875) = 115177
    error = |(115177 - 115200) / 115200 * 100| = 0.02%
    */
    ldr x0, =U_IBRD_REG
    mov w1, #26
    str w1, [x0]

    ldr x0, =U_FBRD_REG
    mov w1, #3
    str w1, [x0]

    /* enable FIFOs and 8 bits frames */
    ldr x0, =U_LCRH_REG
    mov w2, #0x70
    str w2, [x0]

    /* mask interupts */
    ldr x0, =U_IMSC_REG
    str wzr, [x0]

    /* enable UART, receive and transmit */
    ldr x1, =U_CR_REG
    mov w2, #0x301 //1 | (1<<8) | (1<<9)
    str w2, [x1]
    isb
    ret

.global print_el
print_el:
    mov x10, x30
    /*
       print EL
     */
    adrp x0, el_string1
    add x0, x0, :lo12:el_string1
    bl put_string_uart

    mrs x5, CurrentEL
    /* get the currentEL value */
    lsr x2, x5, #2
    mov x0, #48
    add x0, x0, x2
    bl put_char_uart
    /* print the new line tab */
    mov x0, #10
    bl put_char_uart

    mov x30, x10
    ret

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

byd yes

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值