Skip to main content
Associate III
February 4, 2025
Question

LED blinking in assembler for STM32F103C8T6

Hello,

I am trying small example LED blinking written in assembly only - see below. LED is placed to PB15. I am able to compile the program without error using this commands:

arm-none-eabi-gcc -save-temps -nostdlib -nostartfiles -mcpu=cortex-m3 -ffreestanding -O2 led-stm32.s -o led-stm32.elf
arm-none-eabi-objcopy -O binary led-stm32.elf led-stm32.bin

I am using "gcc-arm-none-eabi-10.3-2021.10-win32.exe". I am able to write the program to processor STM32F103C8T6 using STLINKV2, but nothing happend. LED on PB15 is no blinking, LED is no shining. LED is off. .

Can someone help me where is problem ?  :)  Do you (someone) have working example in assembly ?

 

@@@ led-stm32.asm

@@@ Directives
 .cpu cortex-m3
 .code 16 @
 .syntax unified
 .global _start
 .align 2

@@@ Equates
 .equ GPIOB_CRH, 0x40010C04
 .equ GPIOB_ODR, 0x40010C0C
 .equ RCC_APB2ENR, 0x40021018
 .equ STACKINIT, 0x20005000

 .equ LEDDELAY, 0x4E20 @20000

.section .text
 .org 0

@@@ Vectors
vectors:
 .word STACKINIT @ stack pointer value when stack is empty
 .word _start + 1 @ reset vector (manually adjust to odd for thumb)
 .word _nmi_handler + 1 @
 .word _hard_fault + 1 @
 .word _memory_fault + 1 @
 .word _bus_fault + 1 @
 .word _usage_fault + 1 @

_start:

 @@ Enable the Port B peripheral clock by setting bit 4
 ldr r6, = RCC_APB2ENR
 mov r0, #0x08
 str r0, [r6]

 @@ Set the config and mode bits for Port B bit 15 so it will
 @@ be a open drain output (up to 8 MHz) by setting bits 19-16
 @@ to '0110'.

 ldr r6, = GPIOB_CRH
 ldr r0, = #0x64444444 @ 0110 0100 0100 0100 0100 0100 0100 0100
 str r0, [r6]

 @@ Load R2 and R3 with the "on" and "off" constants
 mov r2, #0 @ value to turn on LED
 mov r3, #0x8000 @ value to turn off LED

 ldr r6, = GPIOB_ODR @ point to Port B output data register

loop:
 str r2, [r6] @ clear Port B, pin 15, turning on LED
 ldr r1, = LEDDELAY
delay1:
 subs r1, #1
 bne delay1

 str r3, [r6] @ set Port B, pin 15, turning off LED
 ldr r1, = LEDDELAY
delay2:
 subs r1, #1
 bne delay2

 b loop @ continue forever

_dummy: @ if any int gets triggered, just hang in a loop
_nmi_handler:
_hard_fault:
_memory_fault:
_bus_fault:
_usage_fault:
 add r0, #1
 add r1, #1
 b _dummy

 

This topic has been closed for replies.

3 replies

Peter BENSCH
ST Technical Moderator
February 4, 2025

I haven't checked your code yet due to time constraints, but you can use my ASM example that I once created for STM32G4 and the STM32CubeIDE as a guide. As Cortex-M4 and Cortex-M3 are very similar, you only need to adapt the ASM syntax to your toolchain and check the register addresses.

Hope that helps?

Regards
/Peter

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
JerryMC22Author
Associate III
February 5, 2025

So, I tested your program in asm + CubeIDE, but I was NOT able to get the code up and running. So I downloaded free Keil MDK 5.4:1 and I found this example

https://www.youtube.com/watch?v=Zj4-fgRph1s

on youtube and the code is working ok. Source code is in attachments. The compiler is armclang. it means that I did not use the queer GNU arm assembler.

 

 

File1.asm

stackStartAddress EQU 0x20000100
 
 AREA mySection1, DATA, READONLY
 
 DCD stackStartAddress
 DCD myResetHandler
 
 AREA mySection2, CODE, READONLY
 ENTRY
 
 
myResetHandler 
 IMPORT myApplication
 
 B myApplication
 
 END


File2.asm

 EXPORT myApplication
 
RCC EQU 0x40021000
Port_C EQU 0x40010C00
 
 
 AREA mySection3, CODE, READONLY
 
myApplication
 ; enable the APB2 clock
 
 MOV r0, #0x08
 LDR r1, =RCC
 STR r0, [r1, #0x18]


 ; configure the GPIO C for output

 MOV r0, #0x20000000
 LDR r1, =Port_C
 STR r0, [r1, #0x04]


 ; set the builtin LED on/off
 
 MOV r0, #0x0000 ; #0x8000
 STR r0, [r1, #0x0C]


 B .

 ALIGN

 END


First.sct – script for linker

LR_IROM1 0x08000000 0x00010000 { ; load region size_region
 ER_IROM1 0x08000000 0x00010000 { ; load address = execution address
 file1.o (mySection1, +First)
 file1.o (mySection2)
 file2.o (mySection3)
 
 ; .ANY (+RO)
 }
 RW_IRAM1 0x20000000 0x00005000 { ; RW data
 .ANY (+RW +ZI)
 }
}
JerryMC22Author
Associate III
February 10, 2025

Hi Jerry,

I finally succeeded and LED PB15 blink example using GNU assebler is working ok :) See attached code.

gcc-arm-none-eabi-10.3-2021.10-win32.exe is used from  https://developer.arm.com/downloads/-/gnu-rm

:)