寄存器使用参考


REVISION HISTORY

Revision No.
Description
Date
1.0
  • Initial release
  • 04/26/2024
    1.1
  • 文档格式修改
  • 04/17/2025

    1. 概述

    寄存器是芯片内部的关键可编程单元,负责控制硬件模块的行为、状态监测和系统级功能协调。本文主要描述寄存器的地址转换、寄存器相关工具的使用以及常用的软件API说明。

    2. 关键字说明

    • riu (Rigster Interface Unit)

      寄存器控制单元的缩写

    3. 功能描述

    3.1. 寄存器地址组成

    1. base address:寄存器对应CPU总线的基地址。对ARM CPU来说,base address等于0x1F000000。对RISC-V CPU来说,base address等于0x02000000。

    2. bank address:某一类功能外设(例如SPI,I2C)或者IP的寄存器会被划分到一个区域,这个区域被称为bank,对应的地址为bank address。

    3. 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_rriu_wriux32_rriux32_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 #
    

    此为正常现象,因为寄存器的某些位是只读位,或者写入之后值会立刻发生改变,导致回读回来时已经和写入的值不同,具体行为取决与每个寄存器的功能。