寄存器使用参考
REVISION HISTORY¶
Revision No. | Description |
Date |
---|---|---|
1.0 | 04/26/2024 | |
1.1 | 04/17/2025 |
1. 概述¶
寄存器是芯片内部的关键可编程单元,负责控制硬件模块的行为、状态监测和系统级功能协调。本文主要描述寄存器的地址转换、寄存器相关工具的使用以及常用的软件API说明。
2. 关键字说明¶
-
riu (Rigster Interface Unit)
寄存器控制单元的缩写
3. 功能描述¶
3.1. 寄存器地址组成¶
-
base address:寄存器对应CPU总线的基地址。对ARM CPU来说,base address等于0x1F000000。对RISC-V CPU来说,base address等于0x02000000。
-
bank address:某一类功能外设(例如SPI,I2C)或者IP的寄存器会被划分到一个区域,这个区域被称为bank,对应的地址为bank address。
-
offset address:具体寄存器在bank内的寻址称为offset address。
3.2. 8bit模式和16bit模式¶
对于offset address来说,有8bit模式和16bit模式。8bit模式offset地址范围为0x00 ~ 0xFF。16bit模式offset地址范围为0x00 ~ 0x7F。8bit与16bit模式的offset address是2倍关系。例如:8bit模式的offset地址为0x34,对应的16bit模式的offset地址为0x1A。
为何会存在两种模式?其实是为了更方便操作寄存器,16bit模式一般用来直接操作16bit的寄存器,而8bit模式则用来操作16bit寄存器的高8位(8bit模式奇数地址)或者低8位(8bit模式偶数地址)。
下图比较直观地展示ARM CPU总线寄存器地址以及寄存器8bit模式和16bit模式的差异。
3.3. x32 bank¶
对于大部分的寄存器bank来说,每个offset的有效位是16bit。然而有一些特殊的寄存器bank,它们的offset有效位是32bit,这些寄存器bank被称作x32 bank。对x32 bank的寄存器进行读写操作,要使用特定的命令和工具,下面会再介绍。
3.4. 寄存器表解析¶
下面以TIMER0的寄存器表为例来说明如何查看寄存器表格。
Bank=0x30:表示TIMER0寄存器的bank address=0x30。
Index 0x10:表示TIMER0寄存器16bit模式的offset address=0x10。
Index 0x003021:表示TIMER0寄存器8bit模式的offset address=0x21。
Table 1: TIMER0 Register (Bank = 30)
Index (Absolute) | Mnemonic | Bit | Description | |
---|---|---|---|---|
10h (003020h) | REG003020 | 7:0 | Default : 0x00 | Access : R/W |
- | 7:2 | Reserved. | ||
TIMER_TRIG | 1 | set: Enable timer counting one time (from 0 to max, then stop). clear: By reset itself OR set reg_timer_en. |
||
TIMER_EN | 0 | set: Enable timer counting rolled (from 0 to max, then rolled). clear: By reset itself OR set reg_timer_trig. |
||
10h (003021h) | REG003021 | 7:0 | Default : 0x00 | Access : R/W |
- | 7:1 | Reserved. | ||
TIMER_INT_EN | 0 | set: Enable interrupt. clear: By reset itself. |
||
11h (003022h) | REG003022 | 7:0 | Default : 0x00 | Access : RO/WO |
- | 7:1 | Reserved. | ||
TIMER_HIT_CLEAR_SW | 0 | Clear TIMER_HIT. | ||
TIMER_HIT | 0 | assert: When counter enabled and matches
reg_timer_max. deassert: By write TIMER_HIT_CLEAR_SW OR set reg_timer_en, reg_timer_once, reg_timer_max. |
||
11h (003023h) | REG003023 | 7:0 | Default : 0x00 | Access : R/W |
- | 7:0 | Reserved. |
3.5. 寄存器地址计算¶
下面介绍一下已知寄存器的bank和offset,如何计算它的CPU物理地址(这个地址是软件编程会直接使用到的地址)。
-
8bit模式公式
cpu phy addr = base addr + bank addr x 0x200 + offset addr x 2 - (offset & 1)
示例:
已知bank address=0x30, offset address = 0x2 ARM cpu phy addr = 0x1F000000 + 0x30 x 0x200 + 0x2 x 2 - (0x2 & 1) = 0x1F006004 RISC-V cpu phy addr = 0x02000000 + 0x30 x 0x200 + 0x2 x 2 - (0x2 & 1) = 0x02006004
-
16bit模式公式
cpu phy addr = base addr + bank addr x 0x200 + offset addr x 4
示例:
已知bank address=0x30, offset address = 0x1 ARM cpu phy addr = 0x1F000000 + 0x30 x 0x200 + 0x1 x 4 = 0x1F006004 RISC-V cpu phy addr = 0x02000000 + 0x30 x 0x200 + 0x1 x 4 = 0x02006004
-
x32 bank公式
cpu phy addr = base addr + x32 bank addr x 0x200 + offset addr x 4
示例:
已知x32 bank address=0x1821, offset address = 0xC ARM cpu phy addr = 0x1F000000 + 0x1821 x 0x200 + 0xC x 4 = 0x1F304230 RISC-V cpu phy addr = 0x02000000 + 0x1821 x 0x200 + 0xc x 4 = 0x02304230
4. 命令行工具¶
4.1. 命令使用说明¶
U-Boot、Linux和FreeRTOS都支持寄存器读命令(riu_r)和写命令(riu_w),并且使用方法都一样。U-Boot和FreeRTOS可以直接在命令行执行riu_r和riu_w命令,Linux则是通过执行riu_r和riu_w应用程序来对寄存器进行读写操作。执行riu_r和riu_w命令时,offset address是16bit模式。
此外,在U-Boot和Linux上可以使用x32读命令(riux32_r)和x32写命令(riux32_w)来对x32 bank寄存器进行读写操作。U-Boot可以直接在命令行执行riux32_r和riux32_w命令,Linux则是通过执行riux32_r和riux32_w应用程序来对x32 bank寄存器进行读写操作。执行riux32_r和riux32_w命令时,offset address是32bit模式。
4.1.1. riu_r¶
如果直接使用riu_r [bank address]
命令,会读取整个bank的寄存器值。
示例:读取bank address=0x103c的整个bank。
# Linux /customer # riu_r 0x103c BANK:0x103C 00: 0x0400 0x0000 0x0000 0x00C0 0x0000 0x0000 0x0000 0x0000 08: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 10: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 18: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 20: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 28: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 30: 0x0000 0x0000 0x0000 0x0000 0x0000 0x1000 0x0000 0x0000 38: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 40: 0x43C0 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 48: 0x0000 0x8400 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 50: 0x0000 0x0000 0x0000 0x0004 0x0000 0x0000 0x0000 0x0000 58: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 60: 0x0000 0x0000 0x0000 0x0000 0x0001 0x0000 0x0000 0x0000 68: 0x0800 0x0000 0x0000 0x0000 0x0000 0x0000 0x0003 0x0004 70: 0x0000 0x000C 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 78: 0x0000 0x0000 0x0010 0x0000 0x0000 0x0000 0x0000 0xDF3F /customer # # Uboot SigmaStar # riu_r 0x103c BANK:0x103C 00: 0x0C00 0x0000 0x0000 0x00C0 0x0000 0x0000 0x0000 0x0000 08: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 10: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 18: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 20: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 28: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 30: 0x0000 0x0000 0x0000 0x0000 0x0000 0x1000 0x0000 0x0000 38: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 40: 0x43C0 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 48: 0x0000 0x8400 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 50: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 58: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 60: 0x0000 0x0000 0x0000 0x0000 0x0001 0x0000 0x0000 0x0000 68: 0x0800 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 70: 0x0000 0x000C 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 78: 0x0000 0x0000 0x0010 0x0000 0x0000 0x0000 0x0000 0xDF3F SigmaStar # # FreeRTOS SS-RTOS # riu_r 0x103c BANK:0x103C 00: 0x0400 0x0000 0x0000 0x00C0 0x0000 0x0000 0x0000 0x0000 08: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 10: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 18: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 20: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 28: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 30: 0x0000 0x0000 0x0000 0x0000 0x0000 0x1000 0x0000 0x0000 38: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 40: 0x43C0 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 48: 0x0000 0x8400 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 50: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 58: 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 60: 0x0000 0x0000 0x0000 0x0000 0x0001 0x0000 0x0000 0x0000 68: 0x0800 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 70: 0x0000 0x000C 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 78: 0x0000 0x0000 0x0010 0x0000 0x0000 0x0000 0x0000 0xDF3F SS-RTOS #
如果要读取某个offset address的寄存器值,可以通过riu_r [bank address] [offset address]
命令。
示例:读取bank address=0x103c,offset address=0x38的值。
# Linux /customer # riu_r 0x103c 0x38 BANK:0x103C 16bit-offset 0x38 0x0000 /customer # # Uboot SigmaStar # riu_r 0x103c 0x38 BANK:0x103C 16bit-offset 0x38 0x0000 SigmaStar # # FreeRTOS SS-RTOS # riu_r 0x103c 0x38 BANK:0x103C 16bit-offset 0x38 0x0000 SS-RTOS #
4.1.2. riu_w¶
如果要修改某个寄存器的值,可以通过riu_w [bank address] [offset address] [value]
来操作。
示例:把bank address=0x103c,offset address=0x38的值改为0x1。
# Linux /customer # riu_w 0x103c 0x38 0x0001 BANK:0x103C 16bit-offset 0x38 0x0001 /customer # # Uboot SigmaStar # riu_w 0x103c 0x38 0x0001 BANK:0x103C 16bit-offset 0x38 0x0001 SigmaStar # # FreeRTOS SS-RTOS # riu_w 0x103c 0x38 0x0001 BANK:0x103C 16bit-offset 0x38 0x0001 SS-RTOS #
4.1.3. riux32_r¶
如果直接使用riux32_r [bank address]
命令,会读取整个x32 bank的寄存器值。
示例:读取x32 bank address=0x802的整个bank。
# Linux /customer # riux32_r 0x802 BANK:0x0802 00: 0x00000000 0x5F65935E 0x00000000 0x5F657219 0x00000000 0x00000004 0x00000004 0x00000004 08: 0x00000004 0x00000004 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 10: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x0000003C 0x00000000 0x00000000 18: 0x00000000 0x08000000 0x00000000 0x00000001 0x00000000 0x00000000 0x00000001 0x00000000 20: 0x00000001 0x00000003 0x00000000 0x06000000 0x00000000 0x00000001 0x00000000 0x00000000 28: 0x00000000 0x00000000 0x00000001 0x00000000 0x10086000 0x10087FFF 0x00000010 0x00000000 30: 0x00000001 0x00000000 0x00000001 0x00000001 0x90000000 0xA0000FFF 0x00000002 0x00000000 38: 0x00000000 0x00000FFF 0x00000000 0x00000000 0x00000000 0x00000FFF 0x00000000 0x00000000 40: 0x00000000 0x00000FFF 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 48: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000001 0x14A4DD03 50: 0x00000000 0x00000001 0x10000000 0x1FFFFFFF 0x00680000 0x00000001 0x90000000 0x9FFFFFFF 58: 0xF8680000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 60: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 68: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 70: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 78: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 /customer # # Uboot SigmaStar # riux32_r 0x802 BANK:0x0802 00: 0x00000000 0x04E24FA3 0x00000000 0x04E281AF 0x00000000 0x00000004 0x00000004 0x00000004 08: 0x00000004 0x00000004 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 10: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x0000003C 0x00000000 0x00000000 18: 0x00000000 0x08000000 0x00000000 0x00000001 0x00000000 0x00000000 0x00000001 0x00000000 20: 0x00000001 0x00000003 0x00000000 0x06000000 0x00000000 0x00000001 0x00000000 0x00000000 28: 0x00000000 0x00000000 0x00000001 0x00000000 0x10084000 0x10084FFF 0x00000010 0x00000000 30: 0x00000001 0x00000000 0x00000001 0x00000001 0x90000000 0xA0000FFF 0x00000002 0x00000000 38: 0x00000000 0x00000FFF 0x00000000 0x00000000 0x00000000 0x00000FFF 0x00000000 0x00000000 40: 0x00000000 0x00000FFF 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 48: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000001 0x14A4DD03 50: 0x00000000 0x00000001 0x10000000 0x1FFFFFFF 0x00680000 0x00000001 0x90000000 0x9FFFFFFF 58: 0xF8680000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 60: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 68: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 70: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 78: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 SigmaStar #
如果要读取某个offset address的寄存器值,可以通过riux32_r [bank address] [offset address]
命令。
示例:读取x32 bank address=0x802,offset address=0x2的值。
# Linux /customer # riux32_r 0x802 0x02 BANK:0x0802 16bit-offset 0x02 0x00000000 /customer # # Uboot SigmaStar # riux32_r 0x802 0x02 BANK:0x0802 16bit-offset 0x02 0x00000000 SigmaStar #
4.1.4. riux32_w¶
如果要修改某个x32 bank寄存器的值,可以通过riux32_w [bank address] [offset address] [value]
来操作。
示例:把x32 bank address=0x802,offset address=0x2的值改为0x00000000。
# Linux /customer # riux32_w 0x802 0x02 0x00000000 BANK:0x0802 16bit-offset 0x02 0x00000000 /customer # # Uboot SigmaStar # riux32_w 0x802 0x02 0x00000000 BANK:0x0802 16bit-offset 0x02 0x00000000 SigmaStar #
4.2. 命令配置¶
4.2.1. Uboot¶
Uboot下可以通过menuconfig选择开启或关闭riu相关命令,配置项位置如下:
Command line interface ---> SigmaStar common commands ---> [*] riu
将该选项关闭即可关闭riu相关命令,默认情况下为开启状态。
4.2.2. Linux¶
Linux下riu的相关命令是Linux的应用程序,该程序的源码位于:
kernel/drivers/sstar/samples/riu.c
使用以下的命令编译生成riu相关命令:
cd kernel/drivers/sstar/samples export CROSS_COMPILE=xxxxx # 根据自己的平台配置工具链 sh build_riu.sh
编译后会在kernel/drivers/sstar/samples
生成riu_r
、riu_w
、riux32_r
和riux32_w
,将它们复制到文件系统中即可,Alkaid上会默认将riu相关命令放置在/customer
中。
4.2.3. FreeRTOS¶
FreeRTOS下可以通过修改配置文件选择开启或关闭riu相关命令,选择当前使用的配置文件如mak/options_pcupid_riscv_isw.mak
文件中:
# Feature_Name = [SYS] CLI Support "riu_r" command # Description = RIU read command # Option_Selection = TRUE, FALSE CONFIG_CLI_CMD_SUPPORT_RIU_R = TRUE # Feature_Name = [SYS] CLI Support "riu_w" command # Description = RIU write command # Option_Selection = TRUE, FALSE CONFIG_CLI_CMD_SUPPORT_RIU_W = TRUE
将配置项的值改成FALSE
即可关闭命令,默认riu相关命令为开启状态。
5. 在代码中读写寄存器¶
对于U-Boot和FreeRTOS来说,physical address和virtual address是等同的,因此:
register cpu address = register cpu physical address
对于Linux来说,由于开启了MMU,physical address和virtual address在设计上存在一个偏移值,因此:
register cpu address = register cpu physical address + MS_IO_OFFSET *注:MS_IO_OFFSET的定义在./driver/sstar/include/ms_platform.h*
最后,在代码里面访问寄存器的方法为:
-
8bit模式
(*(volatile u8*)(register cpu address))
-
16bit模式
(*(volatile u16*)(register cpu address))
-
x32 bank
(*(volatile u32*)(register cpu address))
5.1. 寄存器操作宏¶
在U-Boot、Linux和FreeRTOS的代码里已经封装了一些操作寄存器的宏,可以直接使用。这些宏都是对上述的register cpu address地址操作的封装。
Macro | Detail |
---|---|
INREG8(x) | [功能] 获取8bit寄存器值 [参数] x: register cpu address [返回] 8bit寄存器值 |
OUTREG8(x, y) | [功能] 修改8bit寄存器值 [参数] x: register cpu address; y: 待写入寄存器的值 [返回] 无 |
SETREG8(x, y) | [功能] 把8bit寄存器某些bit位置1 [参数] x: register cpu address; y: 指定的bit位 [返回] 无 |
CLRREG8(x, y) | [功能] 把8bit寄存器某些bit位清零 [参数] x: register cpu address; y: 指定的bit位 [返回] 无 |
INREGMSK8(x, y) | [功能] 按指定mask获取8bit寄存器某些bit位的值 [参数] x: register cpu address; y: 指定要获取的bit位 [返回] 8bit寄存器某些bit位的值 |
OUTREGMSK8(x, y, z) | [功能] 清零8bit寄存器某些bit位,并重新设置这些bit位的值 [参数] x: register cpu address; y: 待写入到bit位的值; z: 指定的bit位 [返回] 无 |
INREG16(x) | [功能] 获取16bit寄存器值 [参数] x: register cpu address [返回] 16bit寄存器值 |
OUTREG16(x, y) | [功能] 修改16bit寄存器值 [参数] x: register cpu address; y: 待写入寄存器的值 [返回] 无 |
SETREG16(x, y) | [功能] 把16bit寄存器某些bit位置1 [参数] x: register cpu address; y: 指定的bit位 [返回] 无 |
CLRREG16(x, y) | [功能] 把16bit寄存器某些bit位清零 [参数] x: register cpu address; y: 指定的bit位 [返回] 无 |
INREGMSK16(x, y) | [功能] 按指定mask获取16bit寄存器某些bit位的值 [参数] x: register cpu address; y: 指定要获取的bit位 [返回] 16bit寄存器某些bit位的值 |
OUTREGMSK16(x, y, z) | [功能] 清零16bit寄存器某些bit位,并重新设置这些bit位的值 [参数] x: register cpu address; y: 待写入到bit位的值; z: 指定的bit位 [返回] 无 |
INREG32(x) | [功能] 获取32bit寄存器值 [参数] x: register cpu address [返回] 32bit寄存器值 |
OUTREG32(x, y) | [功能] 修改32bit寄存器值 [参数] x: register cpu address; y: 待写入寄存器的值 [返回] 无 |
SETREG32(x, y) | [功能] 把32bit寄存器某些bit位置1 [参数] x: register cpu address; y: 指定的bit位 [返回] 无 |
CLRREG32(x, y) | [功能] 把32bit寄存器某些bit位清零 [参数] x: register cpu address; y: 指定的bit位 [返回] 无 |
INREGMSK32(x, y) | [功能] 按指定mask获取32bit寄存器某些bit位的值 [参数] x: register cpu address; y: 指定要获取的bit位 [返回] 32bit寄存器某些bit位的值 |
OUTREGMSK32(x, y, z) | [功能] 清零32bit寄存器某些bit位,并重新设置这些bit位的值 [参数] x: register cpu address; y: 待写入到bit位的值; z: 指定的bit位 [返回] 无 |
5.2. 在Linux kernel space里读写寄存器¶
以将bank=0x3F offset=0x06的低4位写成0x8为例,Linux内核空间下的操作示例下:
#include <ms_platform.h> void test_riu_rw_mask(void) { OUTREGMSK16(0x1F000000 + (0x3F * 0x200) + (0x06 * 0x4) + MS_IO_OFFSET, 0x8, 0xF); } // 或者分步操作 void test_riu_rw(void) { u16 reg; reg = INREG16(0x1F000000 + (0x3F * 0x200) + (0x06 * 0x4) + MS_IO_OFFSET); reg &= ~(0xF); reg |= 0x8; OUTREG16(0x1F000000 + (0x3F * 0x200) + (0x06 * 0x4) + MS_IO_OFFSET, reg); }
5.3. 在Uboot里读写寄存器¶
同样以将bank=0x3F offset=0x06的低4位写成0x8为例,Uboot下的操作示例下:
#include <ms_platform.h> void test_riu_rw_mask(void) { OUTREGMSK16(0x1F000000 + (0x3F * 0x200) + (0x06 * 0x4), 0x8, 0xF); } // 或者分步操作 void test_riu_rw(void) { u16 reg; reg = INREG16(0x1F000000 + (0x3F * 0x200) + (0x06 * 0x4)); reg &= ~(0xF); reg |= 0x8; OUTREG16(0x1F000000 + (0x3F * 0x200) + (0x06 * 0x4), reg); }
5.4. 在FreeRTOS里读写寄存器¶
同样以将bank=0x3F offset=0x06的低4位写成0x8为例,FreeRTOS下的操作示例下:
#include <ms_platform.h> void test_riu_rw_mask(void) { OUTREGMSK16(0x02000000 + (0x3F * 0x200) + (0x06 * 0x4), 0x8, 0xF); } // 或者分步操作 void test_riu_rw(void) { u16 reg; reg = INREG16(0x02000000 + (0x3F * 0x200) + (0x06 * 0x4)); reg &= ~(0xF); reg |= 0x8; OUTREG16(0x02000000 + (0x3F * 0x200) + (0x06 * 0x4), reg); }
5.5. 在Linux userspace app里读写寄存器¶
如果需要在Linux userspace app里读写寄存器,则要先将寄存器所在的物理地址通过mmap映射成虚拟地址,然后在虚拟地址上进行读写。具体可以参考如下的demo代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <sys/mman.h> #define DBG_INFO printf #define DBG_ERR printf #define BASE_RIU_PA 0x1F000000 #define PMSLEEP_BANK 0x000E00 #define PM_SAR_BANK 0x001400 #define ALBANY1_BANK 0x151500 #define ALBANY2_BANK 0x151600 #define CHIPTOP_BANK 0x101E00 #define PADTOP_BANK 0x103C00 #define PM_PADTOP_BANK 0x003F00 #define UTMI0_BANK 0x142100 #define ETH_BANK 0x003300 #define PM_PADTOP_BANK 0x003F00 #define CHIPTOP_BANK 0x101E00 #define PADTOP_BANK 0x103C00 #define PADGPIO_BANK 0x103E00 #define PM_SAR_BANK 0x001400 #define PMSLEEP_BANK 0x000E00 #define PM_GPIO_BANK 0x000F00 #define PAD_GPIO0 0x06 #define TEST_GPIO 6 #define GET_BANK_ADDR(base,bank,offset) ((base) + ((bank) << 1) + ((offset) << 2)) #define REG_W_WORD(addr,val) {(*(unsigned short *)(addr)) = (unsigned short)(val);} #define REG_W_WORD_MASK(addr,val,mask) {(*(unsigned short *)(addr)) = ((*(unsigned short *)(addr)) & ~(mask)) | ((unsigned short)(val) & (mask));} #define REG_R_WORD(addr) (*(unsigned short *)(addr)) #define REG_R_WORD_MASK(addr,mask) (*(unsigned short *)(addr)) & (mask)) #define BIT8 0x100 #define BANK_TO_ADDR32(b) (b<<9) #define REG_ADDR(riu_base,bank,reg_offset) ((riu_base)+BANK_TO_ADDR32(bank)+(reg_offset*4)) typedef struct { unsigned char *virt_addr; unsigned char *mmap_base; unsigned int mmap_length; }MmapHandle; static unsigned int const page_size_mask = 0xFFF; MmapHandle* devMemMMap(unsigned int phys_addr, unsigned int length) { int fd; unsigned int phys_offset = 0; fd = open("/dev/mem", O_RDWR|O_SYNC); if (fd == -1) { DBG_ERR("open /dev/mem fail\n"); return NULL; } MmapHandle *handle = malloc(sizeof(MmapHandle)); //phys_offset =(phys_addr & (page_size_mask)); //phys_addr &= ~(page_size_mask); handle->mmap_length = length + phys_offset; handle->mmap_base = mmap(NULL, handle->mmap_length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, phys_addr); handle->virt_addr = handle->mmap_base + phys_offset; DBG_INFO("phys_addr: %#x\n", phys_addr); DBG_INFO("virt_addr: %p\n", handle->virt_addr); DBG_INFO("phys_offset: %#x\n", phys_offset); if (handle->mmap_base == MAP_FAILED) { DBG_ERR("mmap fail\n"); close(fd); free(handle); return NULL; } close(fd); return handle; } int devMemUmap(MmapHandle* handle) { int ret = 0; ret = munmap(handle->mmap_base, handle->mmap_length); if(ret != 0) { printf("munmap fail\n"); return ret; } free(handle); return ret; } int main(int argc, char *argv[]) { unsigned short content; int value = 0; /* RIU mapping*/ MmapHandle *riu_base = devMemMMap(BASE_RIU_PA, 0x400000); if (!strcmp(argv[1], "input")) { REG_W_WORD(GET_BANK_ADDR(riu_base->virt_addr, PM_PADTOP_BANK, PAD_GPIO0), 0x7C); content = REG_R_WORD(GET_BANK_ADDR(riu_base->virt_addr, PM_PADTOP_BANK, PAD_GPIO0)); value = (content & 0x0001) ? 1 : 0; printf("gpio[%d] value = %d\n", TEST_GPIO, value); } else if (!strcmp(argv[1], "output")) { if (argc < 3) { devMemUmap(riu_base); return -1; } value = atoi(argv[2]); if (value) { REG_W_WORD(GET_BANK_ADDR(riu_base->virt_addr, PM_PADTOP_BANK, PAD_GPIO0), 0x7B); } else { REG_W_WORD(GET_BANK_ADDR(riu_base->virt_addr, PM_PADTOP_BANK, PAD_GPIO0), 0x78); } } else { printf("unknown commamd\n"); } devMemUmap(riu_base); return 0; }
6. FAQ¶
6.1. riu_w显示的值和输入的值不同¶
riu_w或riux32_w时显示的值和输入的值不同,例如:
SigmaStar # riux32_w 0x802 0x09 0x12345678 BANK:0x0802 16bit-offset 0x09 0x00000000 SigmaStar #
此为正常现象,因为寄存器的某些位是只读位,或者写入之后值会立刻发生改变,导致回读回来时已经和写入的值不同,具体行为取决与每个寄存器的功能。