"Baking Pi: OK03" - Not understanding a function

174 views Asked by At

Im completely new to the assembler language and just bought a raspberry pi. I know that i can use an OS and start programming with python etc. but i wanted to take a deeper look. Since my raspberry pi did not arrive yet, i can not test the asm code. In Lesson OK03, i looked at the extension solution (download), i tried to understand it myself but i am running into this problem: why is gpioAddr str'ed onto pinFunc in the end (again)? I took the first call in main.s as example to put my comments:

pinNum .req r0
pinFunc .req r1
mov pinNum,#16
mov pinFunc,#1
bl SetGpioFunction
.unreq pinNum
.unreq pinFunc

the SetGpioFunction:

/* NEW
* SetGpioFunction sets the function of the GPIO register addressed by r0 to the
* low  3 bits of r1.
* C++ Signature: void SetGpioFunction(u32 gpioRegister, u32 function)
*/
.globl SetGpioFunction
SetGpioFunction:
    pinNum .req r0
    pinFunc .req r1
    cmp pinNum,#53
    cmpls pinFunc,#7
    movhi pc,lr

    push {lr}
    mov r2,pinNum
    .unreq pinNum
    pinNum .req r2
    bl GetGpioAddress
    gpioAddr .req r0

    functionLoop$:
        cmp pinNum,#9
        subhi pinNum,#10
        addhi gpioAddr,#4
        bhi functionLoop$

    /*  pinNum = 6
        gpioAddr = 0x20200004
    */

    add pinNum, pinNum,lsl #1
    /*
        pinNum = 18 (10010)
    */
    lsl pinFunc,pinNum
    /*
        pinFunc = 1000000000000000000
    */

    mask .req r3
    mov mask,#7                 /* r3 = 111 in binary */
    /*
        mask = 111
    */
    lsl mask,pinNum             /* r3 = 11100..00 where the 111 is in the same position as the function in r1 */
    /*
        mask = 111000000000000000000
    */
    .unreq pinNum

    mvn mask,mask               /* r3 = 11..1100011..11 where the 000 is in the same poisiont as the function in r1 */
    /*
        mask = 11..11000111111111111111111
    */
    oldFunc .req r2
    ldr oldFunc,[gpioAddr]      /* r2 = existing code */
    /*
        oldFunc = 0x12 + (gpioaddr)0x20200004 = 0x20200016
        oldFunc = 100000001000000000000000010110
        mask    = 111111111000111111111111111111
    */
    and oldFunc,mask            /* r2 = existing code with bits for this pin all 0 */
    /*
        oldFunc = 100000001000000000000000010110
    */
    .unreq mask

    /* 
        pinFunc = 000000000001000000000000000000
        oldFunc = 100000001000000000000000010110
    */
    orr pinFunc,oldFunc         /* r1 = existing code with correct bits set */
    /*
        pinFunc = 100000001001000000000000010110
        pinFunc = 0x20240016
    */
    .unreq oldFunc

    str pinFunc,[gpioAddr]
    /* 
        Why do we add gpioaddr again?
        pinFunc = 0x40440016
    */
    .unreq pinFunc
    .unreq gpioAddr
    pop {pc}

What am I getting wrong here? Thank you in advance.

1

There are 1 answers

2
old_timer On BEST ANSWER
read the old setting for this register
 ldr oldFunc,[gpioAddr]      /* r2 = existing code */
mask off, zero out the bits we want to change, leaving the others unchanged
 and oldFunc,mask            /* r2 = existing code with bits for this pin all 0 */
or in the new bits we want to change the ones related to the pin in question
 orr pinFunc,oldFunc         /* r1 = existing code with correct bits set */
write the new value to the register so the changes for that pin function take effect
 str pinFunc,[gpioAddr]

it is a simple read-modify-write function.