寄存器地址 - 将第二位(位索引 = 1)的位值更改为 1

Register address - change bit value of the second bit (bit index = 1) to 1

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

我正在 linux (openwrt)

谢谢

快速而肮脏的方法是尝试将内存区域 mmap 出 /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<<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

如果它 returns 是一个数字,那就是偏移量。使用您的 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 的说明。它需要在你的 openwrt 安装中添加一个名为 io 的包,并且它们提供了一个脚本来切换位的值。如果你只想回显,你可以修改它,总是将它设置为某个值,等等。它写在 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