cancel
Showing results for 
Search instead for 
Did you mean: 

Programming for the Nucleo L432KC in Assembly; why won't the GPIO's work?

JMacd.1
Associate

Hi all,

I'm trying to program my Nucleo L432KC in pure asm, but even after following the data sheets and using the correct memory addresses I can't get any of the pins to turn on (nor get the onboard LED to ignite). Is there something key I'm missing here? This is my first time doing anything embedded; I've included my short assembly file below in case I AM missing something (this is just meant to turn GPIOB on, and set GPIOB_3 to be HIGH):

.syntax unified
.cpu cortex-m4
.thumb
.equ GPIOB_BASE, 0x48000400
.equ RCC_BASE, 0x40021000
 
ldr r0, =(1 << 1) @ Bit 1 is the GPIOB enable
ldr r1, =(RCC_BASE + 0x4C) @ Grab the address for AHB2ENR
str r0, [r1]
 
ldr r0, =(1 << 6) @ Bit 6 is needed to be 1 to set GPIOB_3 to OUTPUT
ldr r1, =(GPIOB_BASE)
str r0, [r1]
 
ldr r0, =(0x04) @ Now want to write to bit 3 to set it to output 1
ldr r1, =(GPIOB_BASE + 0x14)
str r0, [r1]
b .

I'm really stuck on this and am not sure how to proceed

6 REPLIES 6

Not much asm expertise here.

Is this code running at all? Is it called from reset, or is *this* addressed as reset routine, with address inserted properly into the vector table?

Do you have a debugger up and running? Single-stepping and observing registers behaviour is a great help.

@YAY.1​  can you please have a look?

JW

TDK
Guru

Pretty sure a delay is required between enabling the clock and using the peripheral. You should be able to inspect registers and step through code to see if the code is producing the desired results.

> (0x04) @ Now want to write to bit 3

0x04 = 0b100 = bit 2.

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

I like using assembly language when it provides a performance/energy advantage - but I would try to avoid it for simple things like initialising GPIOs. Plus, assembly language is an ugly thing for others to review/debug.

That said, try using the standard C approach first. Then step through it with the simulator to see how the compiler does it - observe the CPU register values as you do it. Do the same with your assembly language routine ie. step through it instruction by instruction observing the CPU registers.

Normally when you initialise registers you: read the register, "OR" the value with the bits you want to set, then write back the result to the register (similar technique for clearing bits with "AND"ing). With your code you are clobbering all the other bits in the register (setting them all to zero).

Also, as TDK mentioned, shouldn't the constant in line 15 be 8 instead of 4?

Also - you are much better to write to the BSRR register if you want to set/reset individual GPIO bits with a single write operation (offset 0x18) and not clobber all the other bits

sorry for delay

Of course i can, thanks for notification.

YAY.1
Senior

Are you using Keil uVision asm ?

You need REFERENCE MANUAL not Datasheet .

(Click REFERENCE MANUAL) 

But

I think you did not activate any RCC Clock.

First you need activate any RCC clock(HSE or HSI....) but if you making simple project, you can use HSE. Select system clock for which RCC clock you want (it should activated).

Second you need activate GPIO CLOCK(A PORT OR B ...)

THIRD you need write data or open GPIOX pin which you want.

Attention!!!!!!!:

Dont do like this if you want two pin open same time;

LDR R0, =GPIOA_BSRR

LDR R1, =(BIT0)

STR R1, [R0] /// CLOSE ALL BITS THEN OPEN BIT0

LDR R1, =(BIT1)

STR R1, [R0] /// CLOSE ALL BITS THEN OPEN BIT1

Do like this;

LDR R0, =GPIOA_BSRR

LDR R1, =(BIT0 + BIT1)

STR R1, [R0]

I advise to write your codes with bit definitions to understand more easy.

Do not change or delete these in your codes.

  1. .syntax unified
  2. .cpu cortex-m4
  3. .thumb

Your fixed codes here 😀 .

.syntax unified
.cpu cortex-m4
.thumb
 
; Definitions are made for general purpose values.
.equ BIT0, 1 << 0
.equ BIT1, 1 << 1
.equ BIT2, 1 << 2
.equ BIT3, 1 << 3
.equ BIT4, 1 << 4
.equ BIT5, 1 << 5
.equ BIT6, 1 << 6
.equ BIT7, 1 << 7
.equ BIT8, 1 << 8
.equ BIT9, 1 << 9
.equ BIT10, 1 << 10
.equ BIT11, 1 << 11
.equ BIT12, 1 << 12
.equ BIT13, 1 << 13
.equ BIT14, 1 << 14
.equ BIT15, 1 << 15
.equ BIT16, 1 << 16
.equ BIT17, 1 << 17
.equ BIT18, 1 << 18
.equ BIT19, 1 << 19
.equ BIT20, 1 << 20
.equ BIT21, 1 << 21
.equ BIT22, 1 << 22
.equ BIT23, 1 << 23
.equ BIT24, 1 << 24
.equ BIT25, 1 << 25
.equ BIT26, 1 << 26
.equ BIT27, 1 << 27
.equ BIT28, 1 << 28
.equ BIT29, 1 << 29
.equ BIT30, 1 << 30
.equ BIT31, 1 << 31
 
.equ RCC_BASE, 0x40021000
.equ RCC_CR, RCC_BASE + 0x00
.equ RCC_CFGR, RCC_BASE + 0x08
.equ RCC_AHB2ENR, RCC_BASE + 0x4C
.equ GPIOB_BASE, 0x48000400
.equ GPIOB_MODER, GPIOB_BASE + 0x00
.equ GPIOB_ODR, GPIOB_BASE + 0x14
 
; 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]
; GPIOB clock activated
		LDR R0, =RCC_AHBENR		
		LDR R1, =(BIT1)
                STR R1, [R0]				
; GPIOB.3 pin selected General purpose output mode
                LDR R0, =GPIOB_MODER
                LDR R1, =(BIT6)
                STR R1, [R0]
BLINKLEDON
                LDR R0, =GPIOA_BSRR
                LDR R1, =(BIT3)
                STR R1, [R0]
 
                b .

 I hope this will help you. 

Blind writing into the configuration registers is likely to dump the debug interface.

On an L432, setting PA5 high, for example

; PA5 EEPROM_LOAD HIGH
 
                ldr     r0, =0x40021000 ; RCC
 
                ldr     r1, [r0, #0x4C] ; RCC_AHB2ENR
                orr     r1, r1, #1      ; RCC_AHB2ENR_GPIOAEN
                str     r1, [r0, #0x4C]
 
                ldr     r0, =0x48000000 ; GPIOA
 
                ldr     r1, [r0, #0x04] ; GPIOx_OTYPER
                bic     r1, r1, #(0x3 << 4) ; 5 1 1 MASK
                                            ; 5 0 0 PP
                str     r1, [r0, #0x04]
 
                ldr     r1, [r0, #0x14] ; GPIOx_ODR
                orr     r1, r1, #(1 << 5)
                str     r1, [r0, #0x14]

And as Jan already indicated, you need a functional Vector Table.

I'd suggest starting with the stock startup.s file, and adding code or subroutines to that, until you actually understand what the requirements/expectations are of the MCU, and how you can fulfill those.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..