【问题标题】:Register address - change bit value of the second bit (bit index = 1) to 1寄存器地址 - 将第二位(位索引 = 1)的位值更改为 1
【发布时间】:2016-05-15 15:09:03
【问题描述】:

我有以下寄存器地址:0x18040028。由于我对这些东西很陌生,我应该如何访问该寄存器地址,更改一位然后将其写回(所有其他条目应保持不变)?
我需要编写程序,还是可以从终端编写程序?

我在 linux (openwrt) 上这样做

谢谢

【问题讨论】:

    标签: linux bit-manipulation bit cpu-registers openwrt


    【解决方案1】:

    选项 1

    在许多 linux 版本中,您可以使用 sysfs 直接访问 GPIO 引脚。特别是在 openwrt 上,它几乎总是暴露在外。

    在openwrt设备的终端上,查看这个文件夹是否存在:

    ls -Al /sys/class/gpio
    

    如果存在,您通常需要导出您要访问的特定 GPIO 引脚。我看了http://www.black-swift.ru/files/AR9331.pdf 并无法弄清楚。问题是我认为该寄存器上的特定引脚不会以这种方式暴露 - 至少我找不到它。我必须在那个系统上挖掘 GPIO 控制器才能有机会弄清楚。

    您要启用的 UART 引脚暴露 - GPIO9 (RX) 和 GPIO10 (TX)。所以也许这些信息无论如何都会有所帮助。

    下面的选项 2 几乎可以保证有效;在我写完这部分之后,我发现了这一点。

    根据您的内核版本,您可以直接使用该 GPIO #,也可以添加偏移量。 试试:

    cat /sys/class/gpio/gpiochip*/base | head -n1
    

    如果它返回一个数字,那就是偏移量。以您的 GPIO #,添加该偏移量(以 200 为例)并将其用作您的 GPIO #。

    使用您的 GPIO 编号(无论有无偏移),输入以下内容(仅使用 210 作为示例;200 偏移,GPIO10)

    echo "210" > /sys/class/gpio/export
    

    然后 GPIO 引脚将暴露在此目录中,再次以 210 为例,/sys/class/gpio210/ 导出后至少会创建两个文件,/sys/class/gpio240/value/sys/class/gpio240/direction
    您可以使用 cat 与它们进行交互以读取它们,例如cat /sys/class/gpio240/value 并使用 echo 修改它:echo 1 > /sys/class/gpio240/value

    在我放在底部的链接中有更多关于通过 sysfs 访问 gpio 的信息。

    如果您找到正确的 GPIO #,这将很容易工作,但如果没有(或者即使您找到了),请使用:

    选项 2

    有人已经完成了所有的工作。有关于如何与该寄存器接口以禁用/启用 UART 的说明。它需要将一个名为 io 的包添加到您的 openwrt 安装中,并且它们提供了一个切换位值的脚本。如果您只想回显,您可以修改它,始终将其设置为某个值等。它是用 bash 编写的。

    您可以添加脚本的内容或从 /etc/rc.local 调用脚本本身,它会在每次启动时运行;解决这个问题。

    既然你已经知道你有AR9331,你可以剪掉很多脚本,例如:

        #!/bin/bash -
    
        # Bitwise operations: & = And, | = Or, ^ = xOr, << = Left Shift
    
        func_addr="0x18040028"
        func_value=0x`io -4 $func_addr | cut -f3 -d' 
        case_bit="1<<1"
    
        # This is where you would make a change if you wanted to 
        # just set it to 1 every time. 
    
        # To always set it to a '1', change from xor ^ to or |; like this
        #    io -4 $func_addr $(printf "0x%8.8x" $(($func_value | $case_bit)))
    
        # to always be 0 change the operator to and &, and use a mask
        # with just bit 1 set to 0
        mask32_b1="0xFFFFFFFD"
        # io -4 $func_addr $(printf "0x%8.8x" $(($func_value $ $mask32_b1)))
        # we using Bitwise xOr operation to switching bit# state (0 or 1)
        io -4 $func_addr $(printf "0x%8.8x" $(($func_value ^ $case_bit)))
    
        # read bit# state and depending on the state - print some info
        if [ $(($func_value & $case_bit)) = $(($case_bit)) ]; then
            echo "Hardware UART is turned OFF"
            # You can use this line for automatic configuring GPIOs via sysfs
            # or you can load other modules that use these GPIOs
        else
            echo "Hardware UART is turned ON"
        fi
    

    它可能是单衬里(相当丑陋的):

    io -4  "0x18040028" $(printf "0x%8.8x" $(("0x"$((io -4   "0x18040028" | cut -f3 -d )) ^ "0x2")))
    

    Toggle uart_en on AR9331

    我无法对此进行任何测试,因此我可能在任何地方都犯了错误,但是如果您按照该指南进行修改,并将我放入的始终设置为 1(目前已注释掉),那么你应该很好。确保您只保留一个选项来修改该寄存器。

    来源/更多信息:
    OpenWrt Wiki
    Working with GPIOs
    Kernel.org

    【讨论】:

    • 感谢您的意见。第二个选项做到了。虽然我的显示器仍然有问题,但当我将它连接到 GPIO10/UART_TX 时,我会听到奇怪的声音和字符。我以为是因为默认情况下没有打开UART,但是当我执行脚本时它说UART关闭时似乎是bcz。我将不得不更多地寻找问题。再次感谢您对此的帮助
    • 除了显而易见的(切换该寄存器中的那个位)之外,我根本不清楚您打算将其他 2 个 gpio 引脚用于什么等。除非那是一个错误类型,否则听起来就像您将 16550 uart TX 线连接到显示器一样——除非它是大约 1960 年的哑终端显示器,否则根本没有任何意义。您可能应该提出一个新问题,其中包含您要详细实现的最终目标,我相信您会得到帮助。至少听起来很有趣。
    • “1960 哑终端显示”是什么意思?我有一个串行液晶显示器,我的问题是/是当我将它连接到 Black Swift 上的 TX 并启动它时,我会从显示器中得到随机字符和声音(显示器也有扬声器)。所以我想也许那个引脚上没有启用UART。但现在我尝试在显示屏上写字,令我惊讶的是,它确实有效。我也可以清除它,所有这些随机字符都消失了。现在的问题是这些随机声音一个字符总是在开始时出现(并且在我清除显示之前不要去)
    • 其实那基本上是个哑终端。 linfo.org/dumb_terminal.html。这不是侮辱;只是一种较旧的方法,并且是我所拥有的信息中唯一想到的。我猜对了
    【解决方案2】:

    快速而肮脏的方法是尝试将内存区域映射到 /dev/mem 之外。看到这两个问题:

    Accessing hardware registers in Linux userspace

    Accessing physical address from user space

    但是,我不建议您对生产系统执行此操作。更清洁的是编写内核驱动程序。一种选择是编写一个使用 ioremap 和 ioread/iowrite 操作的常规内核模块,并通过 sysfs 公开寄存器。

    Using IO Memory

    Sysfs Documentation

    在我看来,另一个特别巧妙的选择是通过你的板支持文件中的 platform_device 系统公开这些寄存器。

    Platform Devices

    基本上你需要读取值,然后做:

    readvalue |= 1&lt;&lt;1;

    然后将值写回寄存器。

    【讨论】:

    • 这看起来很复杂。只是为了解释一下,在我的情况下,我需要在我的微控制器上启用一个引脚,并且在手册中它说我必须通过 SoC 内部寄存器来做到这一点。但是,当我检查您发送的链接时,对于我所拥有的这种微不足道的需求(启用 pin)似乎相当复杂。我想我需要更多的时间来解决这个问题
    • @rimes 好吧,如果它只是一个寄存器是一回事,您可以尝试使用前几个链接到 mmap /dev/mem。
    • @rimes 是否需要始终打开引脚,从启动时开始?如果是这种情况,我会在你的 uboot 源代码的 gpio_config 文件中打开它。同样,这些建议最适合生产,因为它们可以很好地扩展并为最终用户提供通用界面。 platform_device 方法确实有很多样板代码,但它非常好,因为它允许您通过 sysfs 公开您需要的所有内容,并为所有 sysfs 条目定义适当的权限。
    • 是的,它应该始终处于开启状态。实际上引脚是打开的,我需要改变它的功能(所以我可以使用串行通信)。该引脚是多路复用 GPIO 引脚,也用作 TX_UART 接口(我连接设备的地方)。所以我需要打开那个 TX_UART 接口(因为现在它被用作普通的 GPIO)。这里black-swift.ru/files/AR9331.pdf 在第 6.4.11 节中我发现我需要设置第 1 位,(UART_EN)所以我启用了我需要的接口
    • 在这种情况下,我会在您的 Uboot 源代码中更改此功能。你能刷新你的uboot吗?
    猜你喜欢
    • 2017-12-19
    • 1970-01-01
    • 2019-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-21
    • 2019-01-11
    相关资源
    最近更新 更多