REGISTER USER GUIDE
REVISION HISTORY¶
| Revision No. | Description |
Date |
|---|---|---|
| 1.0 | 04/26/2024 | |
| 1.1 | 04/17/2025 |
1. OVERVIEW¶
Registers are key programmable units inside the chip, responsible for controlling the behavior, status monitoring and system-level functional coordination of hardware modules. This article mainly describes the address conversion of registers, the use of register-related tools, and the description of commonly used software APIs.
2. KEYWORD DESCRIPTION¶
-
riu (Rigster Interface Unit)
Abbreviation of register control unit
3. FUNCTION DESCRIPTION¶
3.1. Register Address Composition¶
-
Base address: The base address of the CPU bus corresponding to the register. For ARM CPU, base address is equal to 0x1F000000. For RISC-V CPU, base address is equal to 0x02000000.
-
Bank address: The registers of a certain type of functional peripherals (such as SPI, I2C) or IP will be divided into an area, which is called a bank, and the corresponding address is the bank address.
-
Offset address: The addressing of a specific register in a bank is called an offset address.

Figure 1-1: Register-1
3.2. 8-bit Mode and 16-bit Mode¶
For offset address, there are 8-bit mode and 16-bit mode. The offset address range of 8-bit mode is 0x00 ~ 0xFF. The offset address range of 16-bit mode is 0x00 ~ 0x7F. The offset address of 8-bit mode and 16-bit mode is 2 times. For example, the offset address of 8-bit mode is 0x34, and the corresponding offset address of 16-bit mode is 0x1A.
Why are there two modes? In fact, it is to make it easier to operate registers. The 16-bit mode is generally used to directly operate 16-bit registers, while the 8-bit mode is used to operate the upper 8 bits (odd addresses in 8-bit mode) or lower 8 bits (even addresses in 8-bit mode) of 16-bit registers.
The figure below intuitively shows the difference between the ARM CPU bus register address and the register 8-bit mode and 16-bit mode.

Figure 1-2: Register-2
3.3. x32 Bank¶
For most register banks, the effective bits of each offset are 16 bits. However, there are some special register banks whose effective bits of offset are 32 bits. These register banks are called x32 banks. To read and write registers in the x32 bank, you need to use specific commands and tools, which will be introduced below.
3.4. Register Table Analysis¶
The following uses the TIMER0 register table as an example to explain how to view the register table.
Bank=0x30: indicates that bank address = 0x30 in the TIMER0 register.
Index 0x10: indicates that offset address = 0x10 in 16-bit mode in the TIMER0 register.
Index 0x003021: indicates that offset address = 0x21 in 8-bit mode in the TIMER0 register.
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. Register Address Calculation¶
The following describes how to calculate the CPU physical address of a known register's bank and offset (this address is the address that is directly used in software programming).
-
8-bit mode formula
cpu phy addr = base addr + bank addr x 0x200 + offset addr x 2 - (offset & 1)
Example:
Given 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 -
16-bit mode formula
cpu phy addr = base addr + bank addr x 0x200 + offset addr x 4
Example:
Given 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 formula
cpu phy addr = base addr + x32 bank addr x 0x200 + offset addr x 4
Example:
Given 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. REGISTER TOOL¶
4.1. Introduction¶
U-Boot, Linux and FreeRTOS all support register read commands (riu_r) and write commands (riu_w), and the usage methods are the same. U-Boot and FreeRTOS can directly execute riu_r and riu_w commands in the command line, while Linux executes riu_r and riu_w applications to read and write registers. When executing riu_r and riu_w commands, the offset address is in 16-bit mode.
In addition, x32 read commands (riux32_r) and x32 write commands (riux32_w) can be used on U-Boot and Linux to read and write x32 bank registers. U-Boot can directly execute riux32_r and riux32_w commands in the command line, while Linux executes riux32_r and riux32_w applications to read and write x32 bank registers. When executing riux32_r and riux32_w commands, the offset address is in 32-bit mode.
4.1.1. riu_r¶
If you use the riu_r [bank address] command directly, the register value of the entire bank will be read.
Example: Read the entire bank with bank address = 0x103c.
# 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 #
If you want to read the register value of a certain offset address, you can use the riu_r [bank address] [offset address] command.
Example: Read the value of 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¶
If you want to modify the value of a register, you can use riu_w [bank address] [offset address] [value].
Example: Change the value of bank address = 0x103c, offset address = 0x38 to 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¶
If you use the riux32_r [bank address] command directly, the register value of the entire x32 bank will be read.
Example: Read the entire bank of x32 bank address = 0x802.
# 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 #
If you want to read the register value of a certain offset address, you can use the riux32_r [bank address] [offset address] command.
Example: Read the value of 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¶
If you want to modify the value of a certain x32 bank register, you can use riux32_w [bank address] [offset address] [value] to operate.
Example: Change the value of x32 bank address = 0x802, offset address = 0x2 to 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. COMMAND CONFIGURATION¶
4.2.1. Uboot¶
Under Uboot, you can select the riu-related commands to enable or close riu through menuconfig. The configuration items are as follows:
Command line interface --->
SigmaStar common commands --->
[*] riu
Turn off this option to close the riu-related commands, which are on by default.
4.2.2. Linux¶
The relevant commands of riu under Linux are Linux applications, and the source code of this program is located at:
kernel/drivers/sstar/samples/riu.c
Use the following command to compile and generate riu-related commands:
cd kernel/drivers/sstar/samples export CROSS_COMPILE=xxxxx # Configure toolchain according to your own platform sh build_riu.sh
After compilation, riu_r, riu_w, riux32_r and riux32_w will be generated in kernel/drivers/sstar/samples, and copy them to the file system. On Alkaid, riu-related commands will be placed in /customer by default.
4.2.3. FreeRTOS¶
Under FreeRTOS, you can select the riu-related commands to enable or close riu by modifying the configuration file, and select the currently used configuration file such as mak/options_pumpid_riscv_isw.mak file:
# 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
Change the value of the configuration item to FALSE to close the command, and the default riu-related command is on.
5. READ AND WRITE REGISTERS IN THE CODE¶
For U-Boot and FreeRTOS, physical address and virtual address are equivalent, so:
register cpu address = register cpu physical address
For Linux, since MMU is enabled, there is an offset value between physical address and virtual address by design, so:
register cpu address = register cpu physical address + MS_IO_OFFSET *Note: MS_IO_OFFSET is defined in ./driver/sstar/include/ms_platform.h*
Finally, the method to access registers in the code is:
-
8-bit mode
(*(volatile u8*)(register cpu address))
-
16-bit mode
(*(volatile u16*)(register cpu address))
-
x32 bank
(*(volatile u32*)(register cpu address))
5.1. Register Operation Macro¶
Some register operation macros have been encapsulated in the U-Boot, Linux and FreeRTOS codes and can be used directly. These macros are encapsulations of the above register cpu address operations.
| Macro | Detail |
|---|---|
| INREG8(x) | [Function] Get the 8-bit register value [Parameter] x: register cpu address [Return] 8-bit register value |
| OUTREG8(x, y) | [Function] Modify the 8-bit register value [Parameter] x: register cpu address; y: the value to be written to the register [Return] None |
| SETREG8(x, y) | [Function] Set some bits of 8-bit register to 1 [Parameter] x: register cpu address; y: specified bit [Return] None |
| CLRREG8(x, y) | [Function] Set some bits of 8-bit register to 0 [Parameter] x: register cpu address; y: specified bit [Return] None |
| INREGMSK8(x, y) | [Function] Get the value of some bits of the 8-bit register according to the specified mask [Parameter] x: register cpu address; y: the specified bit to be obtained [Return] the value of some bits of 8-bit register |
| OUTREGMSK8(x, y, z) | [Function] Clear some bits of 8-bit register and reset the values of these bits [Parameter] x: register cpu address; y: the value to be written to the bit; z: specified bit [Return] None |
| INREG16(x) | [Function] Get the 16-bit register value [Parameter] x: register cpu address [Return] 16-bit register value |
| OUTREG16(x, y) | [Function] Modify the 16-bit register value [Parameter] x: register cpu address; y: the value to be written to the register [Return] None |
| SETREG16(x, y) | [Function] Set some bits of 16-bit register to 1 [Parameter] x: register cpu address; y: specified bit [Return] None |
| CLRREG16(x, y) | [Function] Set some bits of 16-bit register to 0 [Parameter] x: register cpu address; y: specified bit [Return] None |
| INREGMSK16(x, y) | [Function] Get the value of some bits of the 16-bit register according to the specified mask [Parameter] x: register cpu address; y: the specified bit to be obtained [Return] the value of some bits of 16-bit register |
| OUTREGMSK16(x, y, z) | [Function] Clear some bits of 16-bit register and reset the values of these bits [Parameter] x: register cpu address; y: the value to be written to the bit; z: specified bit [Return] None |
| INREG32(x) | [Function] Get the 32-bit register value [Parameter] x: register cpu address [Return] 32-bit register value |
| OUTREG32(x, y) | [Function] Modify the 32-bit register value [Parameter] x: register cpu address; y: the value to be written to the register [Return] None |
| SETREG32(x, y) | [Function] Set some bits of 32-bit register to 1 [Parameter] x: register cpu address; y: specified bit [Return] None |
| CLRREG32(x, y) | [Function] Set some bits of 32-bit register to 0 [Parameter] x: register cpu address; y: specified bit [Return] None |
| INREGMSK32(x, y) | [Function] Get the value of some bits of the 32-bit register according to the specified mask [Parameter] x: register cpu address; y: the specified bit to be obtained [Return] the value of some bits of 32-bit register |
| OUTREGMSK32(x, y, z) | [Function] Clear some bits of 32-bit register and reset the values of these bits [Parameter] x: register cpu address; y: the value to be written to the bit; z: specified bit [Return] None |
5.2. READ AND WRITE REGISTERS IN LINUX KERNEL SPACE¶
Taking the example of writing the lower 4 bits of bank=0x3F offset=0x06 as 0x8, the operation example in Linux kernel space is as follows:
#include <ms_platform.h>
void test_riu_rw_mask(void)
{
OUTREGMSK16(0x1F000000 + (0x3F * 0x200) + (0x06 * 0x4) + MS_IO_OFFSET, 0x8, 0xF);
}
// Or step by step
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. READ AND WRITE REGISTERS IN UBOOT¶
Also, take the example of writing the lower 4 bits of bank=0x3F offset=0x06 as 0x8, under the operation examples under Uboot:
#include <ms_platform.h>
void test_riu_rw_mask(void)
{
OUTREGMSK16(0x1F000000 + (0x3F * 0x200) + (0x06 * 0x4), 0x8, 0xF);
}
// Or step by step
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. READ AND WRITE REGISTERS IN FREERTOS¶
Also, take the example of writing the lower 4 bits of bank=0x3F offset=0x06 as 0x8, under the operation examples under FreeRTOS:
#include <ms_platform.h>
void test_riu_rw_mask(void)
{
OUTREGMSK16(0x02000000 + (0x3F * 0x200) + (0x06 * 0x4), 0x8, 0xF);
}
// Or step by step
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. READ AND WRITE REGISTERS IN LINUX USERSPACE APP¶
If you need to read and write registers in Linux userspace app, you must first map the physical address of the register to a virtual address through mmap, and then read and write on the virtual address. For details, please refer to the following demo code:
#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. The value displayed by riu_w is different from the input value¶
The displayed value when riu_w or riux32_w is different from the input value, for example:
SigmaStar # riux32_w 0x802 0x09 0x12345678 BANK:0x0802 16bit-offset 0x09 0x00000000 SigmaStar #
This is a normal phenomenon because some bits in the register are read-only bits, or the value will change immediately after writing, resulting in the value that is already written when reading back is different from the value written. The specific behavior depends on the function of each register.