This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Reading GPIO_IDR assembly

Hello, I am using a discovery board with an STM32l152. The user push button is ported to PA0. I need to read from the IDR bit on the GPIOA when the button is pushed. I read that it can only be accessed via word only. I have already set up the moder, otyper, etc correctly and checked it against the debugger. Below is the offset address of GPIOA_IDR.

   LDR r0, =0x40000000 ;PERIPH_BASE
   ADD r0, #0x20000      ;AHBPERIPH_BASE
   ADD r0, #0x0400               ;GPIOA_BASE
   ADD r0, #0x10


   if((GPIOA-IDR & 0x1) == 1) turn on LED

I would like to do the the C statement above in assembly. Thank you very much

Parents
  • If you have a commercial license, you can ask the compiler to produce a list file.

    With the demo version, you'll have to settle for stepping in the debugger.

    If you are learning assembler, then one of the things you need to learn quickly is how to assign an arbitrary pointer - or integer - to a register. If the core can't perform a 32-bit immediate load, then you'll have to consider doing an indirect load, or combine two 16-bit loads.

    Often, it's a good idea to load a base pointer with specific enough address that the processor supports the relative offset directly when doing the following operations. So you basically ends up with something like (in C)

    port_1->reg1 = xx;
    port_1->reg2 = yy;
    


    or in array notation

    port_1[offset_reg1] = xx;
    port_1[offset_reg2] = yy;
    

    Remember that the assembler can add together multiple constants at build time, so you don't need your processor to add the numbers at run-time.

Reply
  • If you have a commercial license, you can ask the compiler to produce a list file.

    With the demo version, you'll have to settle for stepping in the debugger.

    If you are learning assembler, then one of the things you need to learn quickly is how to assign an arbitrary pointer - or integer - to a register. If the core can't perform a 32-bit immediate load, then you'll have to consider doing an indirect load, or combine two 16-bit loads.

    Often, it's a good idea to load a base pointer with specific enough address that the processor supports the relative offset directly when doing the following operations. So you basically ends up with something like (in C)

    port_1->reg1 = xx;
    port_1->reg2 = yy;
    


    or in array notation

    port_1[offset_reg1] = xx;
    port_1[offset_reg2] = yy;
    

    Remember that the assembler can add together multiple constants at build time, so you don't need your processor to add the numbers at run-time.

Children
  •   LDR r0, =0x40000000 ;PERIPH_BASE
       ADD r0, #0x20000      ;AHBPERIPH_BASE
       ADD r0, #0x0400               ;GPIOA_BASE
       ADD r0, #0x10
    

    Can be a single line

      LDR r0, =0x40000000+0x20000+0x0400+0x10 ;PERIPH_BASE+AHBPERIPH_BASE+GPIOA_BASE
    

  • And your C line

       if((GPIOA-IDR & 0x1) == 1) turn on LED
    

    can be something like:

            LDR r0, GPIOA_ADDR
    
            LDR  R1,[R0]
            TST  R1,#0x00000001
            BEQ  SkipIt
            ;TURN ON LED
    
    SkipIt: ;Carry on
    

    ARM assembler isn't the easiest but it can be good fun and not many programmers bother with it because they think they can do everything in C and don't think they need to understand the low level stuff.