Search code examples
linuxbit-manipulationbitcpu-registersopenwrt

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


i am having the following register address: 0x18040028. Since I am pretty new to that stuff, how am I supposed to access that register address, change that one bit and then write it back (all other entries should stay the same)?
Do I need to write a program, or can I do it from the terminal ?

I am doing that on a linux (openwrt)

thanks


Solution

  • Option 1

    On many linux builds you can access the GPIO pins directly using the sysfs. On openwrt in particular it is nearly always exposed.

    on the openwrt device's terminal, see if this folder exists:

    ls -Al /sys/class/gpio
    

    If it is there, you usually need to export the specific GPIO pin you want to access. I looked at http://www.black-swift.ru/files/AR9331.pdf and can't figure it out. The problem is I don't think that particular pin on that register is exposed that way - at least I can't find it. I would have to be on that system digging around in the GPIO controller to have a chance to figure it out.

    The UART pins you want to enable are exposed - GPIO9 (RX) and GPIO10 (TX). So maybe this info will be helpful regardless.

    Option 2, below, is pretty much guaranteed to work; I found that after I had written this part.

    Depending on your kernel version, you either use that GPIO # directly, or add in an offset. Try:

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

    If it returns a number, thats the offset. Take your GPIO #, add that offset (making up 200 as an example) and use that as your GPIO #.

    Using whatever your GPIO number is (either with or without offset), enter the following (using 210 just as an example; 200 offset, GPIO10)

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

    then the GPIO pin will exposed in this directory, again using 210 as example, /sys/class/gpio210/ There will be at least two files created after the export, /sys/class/gpio240/value and /sys/class/gpio240/direction
    You can interact with them using cat to read them, e.g. cat /sys/class/gpio240/value and modify it using echo: echo 1 > /sys/class/gpio240/value

    There is a lot more info on accessing gpio via sysfs in the links I put at the bottom.

    This will work easily if you find the right GPIO #, but if not (or even if you do), use:

    Option 2

    Someone has already done all the work. There are instructions on how to interface with this register to disable / enable the UART. It requires adding a package to your openwrt install called io, and they provide a script that toggles the value of the bit. You can modify that if you want to just echo out, always set it to a certain value, etc. It's written in bash.

    You can add either the contents of the script or call the script itself from /etc/rc.local and it will get run at each boot; addressing that concern.

    Since you already know you have the AR9331, you can cut out a lot of the script, e.g.:

        #!/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
    

    It could be a one liner(fairly ugly one):

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

    Toggle uart_en on AR9331

    I couldn't test any of this, so I could have made a mistake anywhere, but if you follow that guide, and make the modifications to always set to 1 that I put in there (commented out at the moment), then you should be good. Make sure you only leave in one option to modify that register.

    Sources / more info:
    OpenWrt Wiki
    Working with GPIOs
    Kernel.org