cancel
Showing results for 
Search instead for 
Did you mean: 

Why do I fail to turn on the user led on my nucleo stm32l152 using this assembly code?

BCora.1
Associate III

Hello everybody,

I'm trying to learn about stm32 microcontrollers and I thought the best way to do that was to start with assembly (well, maybe I was wrong about that, but I started with that). I'm just trying to turn on the user led on my nucleo stm32l152 (not even trying to make it blink, just trying to turn it on).

I read that the user led was on PA5, and that seems to match the layout of the board when you look at it.

Here is my code:

.equ RCC_BASE, (0x40023800)
.equ RCC_AHBENR,  (RCC_BASE + 0x1C)
.equ GPIOBEN_FLAG, (0x10)
.equ GPIOA, (0x40020000)
.equ GPIOA_MODER, (GPIOA + 0x00)
.equ GPIOA_OTYPER, (GPIOA + 0x04)
.equ GPIOA_OSPEEDR, (GPIOA + 0x08)
.equ GPIOA_PUPDR, (GPIOA + 0x0C)
.equ GPIOA_ODR, (GPIOA + 0x14)
 
@ Vector table start
.long 0x20001000
.long _start
@ Vector table end
 
_start:
  # setting RCC_AHBENR GPIOPEN bit to 1
  LDR R0, =RCC_AHBENR
  LDR R1, [R0]
  LDR R2, =GPIOBEN_FLAG
  ORR R1, R2
  STR R1, [R0]
 
  # GPIOA settings
  LDR R2, =0x100000000000
  MVN R2, R2
  LDR R3, =0x010000000000
  LDR R4, =0x110000000000
  MVN R4, R4
  
  LDR R0, =GPIOA_MODER
  LDR R1, [R0]
  AND R1, R2
  ORR R1, R3
  STR R1, [R0] 
 
  LDR R0, =GPIOA_OSPEEDR
  LDR R1, [R0]
  AND R1, R4
  STR R1, [R0]
 
  LDR R0, =GPIOA_PUPDR
  LDR R1, [R0]
  AND R1, R4
  STR R1, [R0]
 
  LDR R0, =GPIOA_OTYPER
  LDR R1, [R0]
  LDR R5, =0x100000
  MVN R6, R5
  AND R1, R6
  STR R1, [R0]
 
  # activating the pin
  LDR R0, =GPIOA_ODR
  LDR R1, [R0]
  ORR R1, R5
  STR R1, [R0]
 
.global _start

I'm also an assembly noob, so maybe it's that. However, I use only simple instructions here, so I think there must rather be something I'm missing about GPIO configuration or the stm32 architecture in general.

Any help would be greatly appreciated.

7 REPLIES 7
TDK
Guru

The only time you should be programming in assembly is when something needs the extra speed, and the task can be done in a reasonable amount of time. Things like transferring large chunks of memory where you can unroll loops and save a significant amount of time, such as the startup script.

Turning on an LED is not something that needs assembly. Stick to C or C++. You have limited mental resources. Your time will be better spent learning elsewhere.

Also:

> LDR R2, =0x100000000000

0x100000000000 = 17592186044416. You probably wanted a binary number.

If you feel a post has answered your question, please click "Accept as Solution".
gregstm
Senior III

Yes, assembly language is great - but in very small doses. I've written thousands of lines of assembly language - but only because that was all you had on certain micros. C is such a powerful and efficient language (if used carefully), you can do 99% of coding with that. My motivation to use assembly language occasionally is to save power (extend battery life) - ie. to do tasks with less megahertz/microamps. If possible, get things working with C first before contemplating moving an innermost loop/function to assembly language. You can step through the code using a simulator at the assembly level to see how the compiler does things.

Besides all that - looks like you are trying to enable the GPIOB clock rather than the GPIOA clock - and your constant for doing that is wrong anyway. As TDK mentioned, 0x prefix indicates hexadecimal numbers, not binary - recheck all your constants, better still, do it in relaxing C by just writing to registers..

RCC->AHBENR |= RCC_AHBENR_GPIOAEN

Piranha
Chief II
.equ GPIOBEN_FLAG, (0x10)
  # setting RCC_AHBENR GPIOPEN bit to 1
  LDR R2, =GPIOBEN_FLAG

There is no port P and the intended port B is also not port A. And, as TDK already pointed out, that constant is wrong anyway.

Why aren't you debugging this step by step and watching registers? You would find out all these problems immediately!

There are a couple more scenarios - hardware specific instructions not accessible from C and specific order of instructions. Mostly that can be done with inline assembly. Anyway, typically that will still be less than 1 % of the total project code.

BCora.1
Associate III

Thanks guys! This is working now! These were indeed the two problems: wrong flag constants because mistakenly written in hexadecimal instead of binary, and the GPIOBEN instead of GPIOAEN (I was adapting some of that code from an example I had found from someone using port B).

YAY.1
Senior

I could not understand your problem but maybe you can use GPIOA_BSRR register. because The mcu's working so fast, maybe it is opening but you can not see.

i don't recommend you that you use orr.

It will be more easy for you.

This is less complicated.

You can use this bits:

; Definitions are made for general purpose values.

BIT0 EQU 1 << 0

BIT1 EQU 1 << 1

BIT2 EQU 1 << 2

BIT3 EQU 1 << 3

BIT4 EQU 1 << 4

BIT5 EQU 1 << 5

BIT6 EQU 1 << 6

BIT7 EQU 1 << 7

BIT8 EQU 1 << 8

BIT9 EQU 1 << 9

BIT10 EQU 1 << 10

BIT11 EQU 1 << 11

BIT12 EQU 1 << 12

BIT13 EQU 1 << 13

BIT14 EQU 1 << 14

BIT15 EQU 1 << 15

BIT16 EQU 1 << 16

BIT17 EQU 1 << 17

BIT18 EQU 1 << 18

BIT19 EQU 1 << 19

BIT20 EQU 1 << 20

BIT21 EQU 1 << 21

BIT22 EQU 1 << 22

BIT23 EQU 1 << 23

BIT24 EQU 1 << 24

BIT25 EQU 1 << 25

BIT26 EQU 1 << 26

BIT27 EQU 1 << 27

BIT28 EQU 1 << 28

BIT29 EQU 1 << 29

BIT30 EQU 1 << 30

BIT31 EQU 1 << 31

for example:

  1. LDR R0, =GPIOA_ODR
  2. LDR R1, [R0]
  3. ORR R1, R5
  4. STR R1, [R0]

this will like this

LDR R0, =GPIOA_ODR

LDR R1, =BIT0

STR R1, [R0]

 Not: Now i am writing blink led program in assembly language for you

just wait...

; Definitions are made for general purpose values.
BIT0	EQU	1 << 0
BIT1	EQU	1 << 1
BIT2	EQU	1 << 2
BIT3	EQU	1 << 3
BIT4	EQU	1 << 4
BIT5	EQU	1 << 5
BIT6	EQU	1 << 6
BIT7	EQU	1 << 7
BIT8	EQU	1 << 8
BIT9	EQU	1 << 9
BIT10	EQU	1 << 10
BIT11	EQU	1 << 11
BIT12	EQU	1 << 12
BIT13	EQU	1 << 13
BIT14	EQU	1 << 14
BIT15	EQU	1 << 15
BIT16	EQU	1 << 16
BIT17	EQU	1 << 17
BIT18	EQU	1 << 18
BIT19	EQU	1 << 19
BIT20	EQU	1 << 20
BIT21	EQU	1 << 21
BIT22	EQU	1 << 22
BIT23	EQU	1 << 23
BIT24	EQU	1 << 24
BIT25	EQU	1 << 25
BIT26	EQU	1 << 26
BIT27	EQU	1 << 27
BIT28	EQU	1 << 28
BIT29	EQU	1 << 29
BIT30	EQU	1 << 30
BIT31	EQU	1 << 31
 
RCC_BASE        EQU 0x40023800
RCC_CR          EQU RCC_BASE + 0x00
RCC_CFGR        EQU RCC_BASE + 0x04
RCC_AHBENR      EQU RCC_BASE + 0x1C
 
GPIOA_BASE      EQU 0x40020000 
GPIOA_MODER     EQU GPIOA_BASE + 0x00
GPIOA_BSRR      EQU GPIOA_BASE + 0x18
     
SETUP
; HSE clock activated
                LDR R0, =RCC_CR	      
		LDR R1, =(BIT16)
		STR R1, [R0]
; System clock HSE selected
                LDR R0, =RCC_CFGR	
                LDR R1, =(BIT1)
                STR R1, [R0]
; GPIOA clock activated
		LDR R0, =RCC_AHBENR		
		LDR R1, =(BIT0)
                STR R1, [R0]				
; GPIOA.5 pins selected General purpose output mode
                LDR R0, =GPIOA_MODER                              
                LDR R1, =(BIT10)
                STR R1, [R0]
                
                
                
BLINKLEDON
                LDR R0, =GPIOA_BSRR
                LDR R1, =(BIT5)
                STR R1, [R0]
DELAY1SETUP
                LDR R2, =(0x55)
DELAY1
                LDR R0, =(0x1)
                SUB R2, R2, R0 ;  R2 = R2 - R0
                LDR R0, =(0x0)
                CMP R2, R0     ; COMPARE R2 AND R0
                BNE DELAY1     ; NOT EQUAL R2 AND R0 GO DELAY1
BLINKLEDOFF
                LDR R0, =GPIOA_BSRR
                LDR R1, =(BIT21)
                STR R1, [R0]
DELAY2SETUP
                LDR R2, =(0x55)
DELAY2          
                LDR R0, =(0x1)
                SUB R2, R2, R0 ;  R2 = R2 - R0
                LDR R0, =(0x0)
                CMP R2, R0     ; COMPARE R2 AND R0
                BNE DELAY2     ; NOT EQUAL R2 AND R0 GO DELAY2
                
                B BLINKLEDON   ; GO BLINKLEDON

I write for stm32l152.

You should use Reference manual.

For example , i used this for this codes.

In GPIOA 5. pin will turn on then after some time, will turn off.

You can change value of "DELAY2SETUP LDR R2, =(0x55) " and "DELAY1SETUP LDR R2, =(0x55) " to raise or down wait time

Not: equ expression can change with other programs for example this expression for iar embeded workbench.

It should work correctly :grinning_face: ...

GOOD LUCK.