In most cases, C project is generated and used. But assembly project has it’s own advantage, with assembly project, you can program with assembly language directly, can test assembly instruction with assembly mnemonic. Generally, C language is inefficient, so in order to test the performance of the core, or get peripheral highest performance, the assembly project is required.
The doc discusses the procedure to create an assembly language project, in the end, gives an example to toggle a LED, which demos how to initialize the NVIC, CTimer, GPIO with assembly language. It also gives the example of subroutine.
1.1 Load MCUXPresso tools and drag SDK to the Installed SDK menu
Then click “Create a new C/C++ project”
1.2 Select the board or processor, then clock “Next” software button
1.3 Name the project and Select the driver.
In the menu, it is okay to use default configuration, then clock “Finish”
1.4 A New project called MCXN947_project is created with C language
1.5 Delete the MCXN947_project.c and add the main.s
Click the “source” group with right mouse button, the click “New”->”source File”
1.6 Add the main.s as the following Fig and click “Finish”
1.7 The final project is like:
2.0 writing the assembly code in the main.s
This is the code in main.s
/* This assembly file uses GNU syntax */
.equ SYSCON_ANGCLKCTRLSET0,0x40000220
.equ SYSCON_AHBCLKCTRLSET1,0x40000224
.equ SYSCON_AHBCLKCTRLSET2,0x40000228
.equ SYSCON_CTIMER4CLKSEL, 0x4000027C
.equ SYSCON_CTIMER4CLKDIV, 0x400003E0
/*PIO3_4 LED blue*/
.equ PORT3_PCR_BASE,0x40119000
.equ PORT3_PCR4,PORT3_PCR_BASE+0x90
.equ GPIO3_BASE,0x4009C000
.equ GPIO3_PDDR,GPIO3_BASE+0x54
.equ GPIO3_PDOR,GPIO3_BASE+0x40
/*PIT configuration*/
.equ CTIMER4_BASE,0x40010000
.equ CTIMER4_IR,CTIMER4_BASE+0x00
.equ CTIMER4_TCR,CTIMER4_BASE+0x04
.equ CTIMER4_MCR,CTIMER4_BASE+0x14
.equ CTIMER4_MR0,CTIMER4_BASE+0x18
.equ CTIMER4_MSR0,CTIMER4_BASE+0x78
.equ CTIMER4_PWMC,CTIMER4_BASE+0x74
/*NVIC configuration*/
/*refer to 4.2 Nested Vectored Interrupt Controller in Cortex-M4 Generic User's Guide.pdf*/
.equ NVIC_ISER0,0xE000E100
.equ NVIC_ISER1,0xE000E104
.equ NVIC_ICPR0,0xE000E284
.equ NVIC_ICPR1,0xE000E288
.equ NVIC_IPR12,0xE000E430
.equ NVIC_IPR14,0xE000E438
.global __user_mem_buffer1,__user_mem_buffer2
.text
.section .rodata
.align 2
.LC0:
.text
.thumb
.align 2
.global main
.global CTIMER0_IRQHandler
.type main function
main:
push {r3, lr}
add r3, sp, #4
nop
BL peripheralInit
nop
nop
nop
nop
NOP
/*cpsie i*/
loop:
b loop
mov r3, #0
mov r0, r3
pop {r3, pc}
/*subroutine 1*/
/* copy 10 words from one place to another*/
.type MyFunc function
.func
MyFunc:
push {r0,r1,r2,lr}
MOV R2,#0x00
LDR R0,=USER_MEM_BUFFER1
MOV R1,#0x00
loop1:
NOP
STR R1,[R0]
ADD R1,#0x10
ADD R0,#4
ADD R2,#1
CMP R2,#0x10
BNE loop1
AND R5,R1,R5 ;
ASR R3,R2,#1
ORR R5,R1,R5
ADD R3,R2,R3
ADC R3,R2,R3
AND R2,R1,R2 ; /*#0x0F*/
LDR R0,=0x1234
/*LDR R0, [R1], #4*/
nop
pop {r0,r1,r2,pc}
.endfunc
/***************************************/
/*subroutine 2*/
.type peripheralInit function
.func
peripheralInit:
//enable CTimer4 gated clock
LDR R0,=0x400000
LDR R1,=SYSCON_AHBCLKCTRLSET2
nop
STR R0, [R1]
MOV R0,#0x03 //select
LDR R1,=SYSCON_CTIMER4CLKSEL
nop
STR R0, [R1]
MOV R0,#0x09 //select
LDR R1,=SYSCON_CTIMER4CLKDIV
nop
STR R0, [R1]
/*setting CTimer0*/
//set Ctimer0_IR
MOV R3,#0x01
LDR R1,=CTIMER4_IR
Nop
LDR R2,[R1]
ORR R2,R2,R3
STR R2,[R1]
//set CTIMER4_MCR
MOV R3,#0x03
LDR R1,=CTIMER4_MCR
LDR R2,[R1]
ORR R2,R2,R3
STR R2,[R1]
LDR R0,=6000000
LDR R1,=CTIMER4_MR0
STR R0,[R1]
LDR R0,=6000000
LDR R1,=CTIMER4_MSR0
STR R0,[R1]
MOV R0,#00
LDR R1,=CTIMER4_PWMC
STR R0,[R1]
nop
nop
//lop1:
// b lop1
/*setting interrupt, Ctimer4 IRQ 56*/
LDR R1,=NVIC_ISER1
LDR R0,[R1]
LDR R3,=0x01000000
ORR R0,R0,R3
STR R0,[R1]
LDR R1,=NVIC_ICPR1
LDR R0,[R1]
LDR R3,=0x01000000
ORR R0,R0,R3
STR R0,[R1]
MOV R0,#0x00
LDR R1,=NVIC_IPR14
STR R0,[R1]
/*pin mux setting*/
/*enable PORT3 and GPIO3 gated clock*/
LDR R0,=0x410000
LDR R1,=SYSCON_ANGCLKCTRLSET0
nop
STR R0, [R1]
/*set the GPIO3_4 as GPIO output mode*/
LDR R0,=#0x1000
LDR R1,=PORT3_PCR4
STR R0,[R1]
LDR R1,=GPIO3_PDDR
LDR R0,[R1]
LDR R3,=0x10
ORR R0,R0,R3
STR R0,[R1]
/*CTimer4 start*/
MOV R3,#0x01
LDR R1,=CTIMER4_TCR
LDR R0,[R1]
ORR R0, R0,R3
STR R0,[R1]
nop
nop
nop
/*cpsid i*/
BX LR
.endfunc
/*********************************************/
/*subroutine 3*/
.text
.type testcal function
.func
testCal:
LDR R0,=0x12345678
MOV R1,#0x0F
AND R0,R1
/*test saturation function*/
LDR R0,=0x8234
LDR R1,=0x8234
/*ADDS R5,R0,R1*/
QADD16 R6,R0,R1 /*saturation heppen, the R6 will become negative minumum 0x8000*/
nop
/***8888888*/
LDR R0,=0x6234
LDR R1,=0x6234
/*ADDS R5,R0,R1*/
SADD16 R6,R0,R1
nop
QADD16 R6,R0,R1 /*saturation heppen, the R6 will become negative minumum 0x7FFF*/
nop
SMUAD R6,R0,R1
BX LR
.endfunc
/*********************************************/
/*interrupt service routine*/
.global CTIMER4_IRQHandler
.text
.align 2
.type CTIMER4_IRQHandler function
.func
CTIMER4_IRQHandler:
/*clear interrupt*/
push {R0,R1,LR}
nop
nop
nop
LDR R1,=CTIMER4_IR
LDR R0,[R1] /*dummy reading*/
MOV R4,#0x10;
ORR R0,R0,R4
STR R0, [R1]
/*toggle a LED*/
LDR R1,=GPIO3_PDOR
LDR R0,[R1]
LDR R3,=0x10
EOR R0,R0,R3
STR R0,[R1]
NOP
POP {R0,R1,PC}
.endfunc
/******************************************************/
/*interrupt service routine*/
.global SVC_Handler
.text
.align 2
.type SVC_Handler function
.func
SVC_Handler:
push {R0,R1,LR}
NOP
POP {R0,R1,PC}
/******************************************************/
.align 2
.L3:
.word
.align 4
.section .contantData
HELLO_TXT:
.space 0x100
Hello_END:
.ALIGN 4
/*.lcomm */
.lcomm USER_MEM_BUFFER1 0x100
.lcomm USER_MEM_BUFFER2 0x100
.end
3.0 code explanation
In the code, you have to define the main function, after the core has executed the code ResetISR(void), which is defined in startup_mcxn847_cm33_core0.c, it jump to main() function
The example code implement the function to initialize CTimer, GPIO and NVIC, SYSCON module so that the CTImer can generate interrupt, in the ISR of CTimer, a LED is toggled.
After you run the code, you can see that the led is toggled.
The peripheralInit Subroutine is used to initialize the CTimer, NVIC, GPIO, SYSCON module so that the CTimer can fire an interrupt and toggle a LED.The CTIMER4_IRQHandler is an ISR of CTimer4, which is defined in startup_mcxn847_cm33_core0.
The MyFunc function and testCal Subroutines are just for testing a specific assembly instruction, and test how to establish and call a subroutines, they do not have a specific target.