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