How to read a GPIO input pin in ARM using the Raspberry Pi Pico?

419 views Asked by At

I am starting to learn assembly language and ARM using the raspberry pi pico.

I have even been following the book RP2040 Assembly Language programming but there is no instruction about how to read an input pin using only assembly.

Here is my set up: I have a push button that send 3,3V when not pressed and 0V when pressed.

I would like to be able to read the different states this has using a GPIO pin but despite looking into the functions of the datasheet (that I barely understand as it's the first time i'm dealing with it), I don't know if what I am doing makes sense.

Here is my code:

led_loop:
    @  set the control for the push
    ldr r0, =ctrl2      @  control register for GPIO1 0x40014008
    mov r1, #5          @  Function 5, select SIO for GPIO1 2.19.2
    str r1, [r0]        @  Store function_5 in GPIO1 control register
@ shifts over "1" the number of bits of GPIO pin
    mov r2, #1          @  load a 1 into register 1
    lsl r2, r2, #1      @  move the bit over to align with GPIO1
    ldr r0, =sio_base   @  SIO base 0xd0000000
    str r1, [r0, #0x00000004]   @  0x004 GPIO input enable
    ldr r0, =helloworld
    BL printf
    b led_loop          @  do the loop again

.data
    .align 4
helloworld: .asciz "Hello World %d\n"

So far I tried to consult the datasheet but I do not have enough knowledge to recognize if what I am doing is write or wrong.

1

There are 1 answers

0
old_timer On

You are on the right track but appear to be using wrong register values or using them the wrong way. You have a printf so that is very odd, and implies you have a ton, ton, more code which may or may not be helping.

This is C and uses the led on the original picos, which not sure if that is the case anymore.

void PUT32 ( unsigned int, unsigned int );
unsigned int GET32 ( unsigned int );
void DELAY ( unsigned int );

#define RESETS_BASE                 0x4000C000

#define RESETS_RESET_RW             (RESETS_BASE+0x0+0x0000)
#define RESETS_RESET_XOR            (RESETS_BASE+0x0+0x1000)
#define RESETS_RESET_SET            (RESETS_BASE+0x0+0x2000)
#define RESETS_RESET_CLR            (RESETS_BASE+0x0+0x3000)

#define RESETS_RESET_DONE_RW        (RESETS_BASE+0x8+0x0000)
#define RESETS_RESET_DONE_XOR       (RESETS_BASE+0x8+0x1000)
#define RESETS_RESET_DONE_SET       (RESETS_BASE+0x8+0x2000)
#define RESETS_RESET_DONE_CLR       (RESETS_BASE+0x8+0x3000)

#define SIO_BASE                    0xD0000000

#define SIO_GPIO_IN                 (SIO_BASE+0x04)

#define SIO_GPIO_OUT_RW             (SIO_BASE+0x10)
#define SIO_GPIO_OUT_SET            (SIO_BASE+0x14)
#define SIO_GPIO_OUT_CLR            (SIO_BASE+0x18)
#define SIO_GPIO_OUT_XOR            (SIO_BASE+0x1C)

#define SIO_GPIO_OE_RW              (SIO_BASE+0x20)
#define SIO_GPIO_OE_SET             (SIO_BASE+0x24)
#define SIO_GPIO_OE_CLR             (SIO_BASE+0x28)
#define SIO_GPIO_OE_XOR             (SIO_BASE+0x2C)

#define IO_BANK0_BASE               0x40014000

#define IO_BANK0_GPIO25_CTRL_RW     (IO_BANK0_BASE+0x0CC+0x0000)
#define IO_BANK0_GPIO25_CTRL_XOR    (IO_BANK0_BASE+0x0CC+0x1000)
#define IO_BANK0_GPIO25_CTRL_SET    (IO_BANK0_BASE+0x0CC+0x2000)
#define IO_BANK0_GPIO25_CTRL_CLR    (IO_BANK0_BASE+0x0CC+0x3000)

#define IO_BANK0_GPIO1_CTRL_RW     (IO_BANK0_BASE+0x00C+0x0000)
#define IO_BANK0_GPIO1_CTRL_XOR    (IO_BANK0_BASE+0x00C+0x1000)
#define IO_BANK0_GPIO1_CTRL_SET    (IO_BANK0_BASE+0x00C+0x2000)
#define IO_BANK0_GPIO1_CTRL_CLR    (IO_BANK0_BASE+0x00C+0x3000)

int notmain ( void )
{
    unsigned int ra;
    PUT32(RESETS_RESET_CLR,1<<5); //IO_BANK0
    while(1)
    {
        if((GET32(RESETS_RESET_DONE_RW)&(1<<5))!=0) break;
    }
    PUT32(SIO_GPIO_OE_CLR,1<<25);
    PUT32(SIO_GPIO_OUT_CLR,1<<25);
    PUT32(IO_BANK0_GPIO25_CTRL_RW,5); //SIO
    PUT32(SIO_GPIO_OE_SET,1<<25);
    for(ra=0;ra<10;ra++)
    {
        PUT32(SIO_GPIO_OUT_XOR,1<<25);
        DELAY(0x40000);
    }

    PUT32(SIO_GPIO_OE_CLR,1<<1);
    PUT32(SIO_GPIO_OUT_CLR,1<<1);
    PUT32(IO_BANK0_GPIO1_CTRL_RW,5); //SIO
    while(1)
    {
        ra=GET32(SIO_GPIO_IN);
        if(ra&2)
        {
            PUT32(SIO_GPIO_OUT_SET,1<<25);
        }
        else
        {
            PUT32(SIO_GPIO_OUT_CLR,1<<25);
        }
    }
    return(0);
}

finding all of those addresses and info strictly from docs is, well...

PUT32 is just a store word and GET32 is just a load word. and delay is just a counting to zero loop.

GPIO generally defaults/resets to inputs, the clearing of the out/oe and making it an input I probably got directly from their libraries, is it required? Do not know, could probably read those registers and see.

You do need to release reset on the I/O block for sure, so maybe you are doing that elsewhere.

The above blinks the led 5 times and then goes into a polling loop reading the gpio and isolating gpio 1 if high then light the led if low then not.

Trivial to convert this to asm and should be able to see the differences in what you did and what I did and decide if you need to clear the out/oe settings. You had wrong addresses and were writing things you should be reading and IO block out of reset at a minimum.