STM32F102C8T6 is programmed with Assembly-Code.
The on-board LED should "blink", that is not the case.
Please analyse my code-sample.
I need explanations to some code-parts:
(1) "MOVW"-use in right context of 32-bit code?
(2) Part of declaration with text like ~(1 << 20), possible?
(3) Right use of not global-declared sub-functions?
.syntax unified
.text
.global ASM_SystemInit
.global ASM_Function
.thumb_func
.equ RCC_BASE, 0x40021000
.equ RCC_APB2_ENR, 0x40021018 // STM32f103C8T6 - Adresse von RCC_APB2ENR - 0x18
.equ GPIOC_BASE, 0x40011000 // GPIOC-Basisadresse nach "memory-map", Datenblatt
.equ GPIOC_CRH, 0x40011004 // GPIOC-BASE + 0x04 ist das Konfigurationsregister
.equ GPIOC_ODR, 0x4001100C // GPIOC_BASE + 0x0C ist das Ausgaberegister (Rerenz-Handbuch, Seite 194)
.equ GPIOCEN, 1 << 4 // Seite 141, Referenz-Dokumentation, eventuell Wert 4, prüfen !!!
.equ CRH_OUT_1, ~(1 << 20) // Konfiguration GPIOC, Setzen der vier Konfigurations-Bits nach Datenblatt, Seite 161, Bit-Sequenz: 0010
.equ CRH_OUT_2, ~(1 << 21)
.equ CRH_OUT_3, 1 << 22
.equ CRH_OUT_4, ~(1 << 23)
.equ LED_BLUE, 1 << 13 // PC13
.equ COUNTER, 10000
//------------------------------------------------------------------------------------------------
ASM_SystemInit:
// Setzen der Uhr im Programm
LDR R0,=RCC_BASE
LDR R1,[R0]
ORR R1,GPIOCEN
STR R1,[R0] // Absatz beschreibt das Freischalten der Uhr für Port C
LDR R0,=GPIOC_CRH
LDR R1,=(CRH_OUT_4|CRH_OUT_3|CRH_OUT_2|CRH_OUT_1)
STR R1,[R0]
MOV R1,#0
LDR R2,=GPIOC_ODR // Absatz beschreibt Konfiguration von PC13 als Ouput
ASM_Function:
Blink:
MOVW R1,=#LED_BLUE
STR R1,[R2]
LDR R3,=#COUNTER
BL delay1
delay1:
SUBS R3,R3,#1
BNE delay1
B Blink
I tried the code sample on a ARMv7, 32-bit architecture, stm32f103C8T6
I can see two immediate problems. The first is as expected:
You asked it to be all ones and it is all ones. Which makes all the ports alternate function open drain.
Second is that you wanted 0010 for output max speed 2Mhz push pull which that is the correct pattern but if you were to use this then it is wrong.
that is 0100
this is 0010.
You should read-modify-write and outside the register, all too often in C folks do the clear and set steps against the register, which can cause problems or glitches...
Let's try:
That looks good:
another way perhaps for readability is:
That way you can see this is pin 13, the register starts at pin 8 (config register HIGH) and there are 4 bits per pin, so 13-8 times 4. And you want to generically just zero all four bits and then set them to the pattern you want, no games easy to read.
Next:
So you should make up your mind =# does not apply to either of these use cases, for the former it is #number the latter it is =address where the address can be a constant...
You already know how to do the ldr rd,=address trick so just use that, the gnu tools 1) support this syntax (assembly is specific to the tool not the target) 2) find the optimal instruction. Other assemblers do not necessarily do either of those things and you get into a game of figuring it out yourself or just generating a pool entry and a pc relative load.
And yes if you take this approach then you can put any (32 bit) value in the .equ and it will work:
This cortex-m3 is armv7-m NOT armv7, huge difference. You should not be doing any assembly language without the cortex-m3 technical reference manual from arm, not a generic cortex-m one but the pdf specific (not online) to cortex-m3 it is called specifically the technical reference manual. (The docs from st tell you this part uses an arm cortex-m3)(the reference manual for this part rm00008 from st is a must have as well as often the datasheet helps but the reference manual is the key document, not the programmers manual, in neither case do you necessarily want the programmers manual as it is as confusing as it helps).
And the cortex-m3 TRM tells you this is architecture armv7-m so you need the Architectural Reference Manual for armv7-m again not armv7 and not some online generic thing specifically the armv7-m architectural reference manual, pdf. In that document you will see the instruction set details and see the rules for movw.
Now the syntax in the ARM ARM is for ARMs tools, if you are using gnu which I suspect (you are not using arms tools) then the syntax can vary from the document to the assembly language you need for gnu and you would ideally want gnu documentation but that is...a nightmare...if you can navigate it and get certain nuggets. While using gnu is going to have the best success and support even if the output is medium quality, because of the sheer volume of users, but most are not bare metal. and most are not arm although many are.
So for syntax things you kinda need to look at the gazillion examples out there, more than you can ever read in your lifetime. And pull clues, or just search so as most syntax questions have been answered. movw deals with the lower 16 bits, if you want to do all 32 bits with the armv7-m level of thumb 2 extensions it takes two instructions if I remember, I gend to write for armv6-m unless I have to (if you want to mess with cortex-ms going forward you need the armv6-m as well which applies to the cortex-m0 and m0+ and some flavors of armv8-m (baseline? mainline is armv7-m?)).
If you go backward to the original thumb, which you can find in the thumb part of the armv5 architectural reference manual that covered armv4t and armv5t and some of armv6 (not the cortex-m) the older manuals have easier to read pseudo code btw. you can build basically for all thumb variants and it will run on all cortex-ms or you can build for cortex-m0 and it will run on all cortex-ms (if you get into the habit of movw code will fail or hang on a cortex-m0 and some m8s)
So, make up your mind here: you either want to call delay as a function or just have a loop with a delay.
Make it a loop:
It is a loop either way but if you want to call a function then return from the function and put the loop in the right place.
Also this will not make it blink you are simply setting the pin high which depending on the wiring on the pcb will either make the led always on or always off, if you want it to blink then you need to turn it on and then off and then on and then off... or you need toggle.
You can certainly use odr:
Or you can use bsrr, and maybe even get a little tricky. I am not running this on a board nor in this case building it so if I have typos you have to debug them: