【发布时间】:2016-05-15 15:09:03
【问题描述】:
我有以下寄存器地址:0x18040028。由于我对这些东西很陌生,我应该如何访问该寄存器地址,更改一位然后将其写回(所有其他条目应保持不变)?
我需要编写程序,还是可以从终端编写程序?
我在 linux (openwrt) 上这样做
谢谢
【问题讨论】:
标签: linux bit-manipulation bit cpu-registers openwrt
我有以下寄存器地址:0x18040028。由于我对这些东西很陌生,我应该如何访问该寄存器地址,更改一位然后将其写回(所有其他条目应保持不变)?
我需要编写程序,还是可以从终端编写程序?
我在 linux (openwrt) 上这样做
谢谢
【问题讨论】:
标签: linux bit-manipulation bit cpu-registers openwrt
在许多 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 #,这将很容易工作,但如果没有(或者即使您找到了),请使用:
有人已经完成了所有的工作。有关于如何与该寄存器接口以禁用/启用 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")))
我无法对此进行任何测试,因此我可能在任何地方都犯了错误,但是如果您按照该指南进行修改,并将我放入的始终设置为 1(目前已注释掉),那么你应该很好。确保您只保留一个选项来修改该寄存器。
来源/更多信息:
OpenWrt Wiki
Working with GPIOs
Kernel.org
【讨论】:
快速而肮脏的方法是尝试将内存区域映射到 /dev/mem 之外。看到这两个问题:
Accessing hardware registers in Linux userspace
Accessing physical address from user space
但是,我不建议您对生产系统执行此操作。更清洁的是编写内核驱动程序。一种选择是编写一个使用 ioremap 和 ioread/iowrite 操作的常规内核模块,并通过 sysfs 公开寄存器。
在我看来,另一个特别巧妙的选择是通过你的板支持文件中的 platform_device 系统公开这些寄存器。
基本上你需要读取值,然后做:
readvalue |= 1<<1;
然后将值写回寄存器。
【讨论】: