ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2021-07-22 09:03:32  阅读:259  来源: 互联网

标签:树莓 mov ldr BASE 串口 x0 4B REG define


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

标签:树莓,mov,ldr,BASE,串口,x0,4B,REG,define
来源: https://blog.csdn.net/dai_xiangjun/article/details/118990467

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有