Code Examples from Class: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
No edit summary |
||
| (32 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
* Factorial | |||
<nowiki> | |||
; Factorial Calculation | |||
; The answer is in R10 | |||
; Rob Frohne 2013 | |||
GLOBAL Reset_Handler | |||
AREA Factorial, CODE, READONLY | |||
ENTRY | |||
Reset_Handler | |||
movs r8, #0 ; Take the factorial of this number, n. | |||
mov r10, #1 ; 0! and 1! are 1 | |||
beq stop ; If r8 is zero we are done | |||
cmp r8, #1 ; If r8 is 1, | |||
beq stop ; we are done | |||
subs r9, r8, #1 ; n-1 | |||
loop mulne r10, r9, r8 ; n(n-1) | |||
mov r8, r10 | |||
subs r9, r9, #1 | |||
bne loop | |||
stop b stop | |||
END | |||
</nowiki> | |||
---- | |||
*Factorial 2014 | |||
<nowiki> | |||
_ AREA Add, CODE | |||
ENTRY | |||
; This program takes the factorial of n (in r2) | |||
n EQU 0 | |||
ldr r2,=n ; Load r2 with the number to take the factorial of. | |||
cmp r2,#0 ; Is n=0 | |||
bne check_for_1 | |||
mov r4,#1 | |||
b stop | |||
check_for_1 | |||
cmp r2,#1 | |||
bne initialize_r4 | |||
mov r4,#1 | |||
b stop | |||
initialize_r4 | |||
mov r4,r2 | |||
sub r3,r4,#1 | |||
loop | |||
mul r5,r4,r3 | |||
mov r4,r5 | |||
subs r3,r3,#1 | |||
bne loop | |||
stop b stop | |||
END | |||
</nowiki> | |||
---- | |||
* 64 Bit Add | |||
VAL1A EQU 0xffffffff | |||
VAL1B EQU 0x0000000f | |||
VAL2A EQU 0x00000001 | |||
VAL2B EQU 0x00000001 | |||
AREA LongAdd, CODE | |||
ENTRY | |||
ldr R0, = VAL1A | |||
ldr R1, = VAL1B | |||
ldr R2, = VAL2A | |||
ldr R3, = VAL2B | |||
adds R8,R0,R1 | |||
adcs R9,R1,R3 | |||
stop b stop | |||
END | |||
---- | |||
* Copy to RAM | * Copy to RAM | ||
AREA Exaddress, CODE, READONLY | AREA Exaddress, CODE, READONLY | ||
| Line 5: | Line 81: | ||
LDR R9, =list | LDR R9, =list | ||
mov R7, #4 ; number in list | mov R7, #4 ; number in list | ||
ldr r6, =datastart | ldr r6, =datastart | ||
loop | loop | ||
ldr r8,[r9],#4 | ldr r8,[r9],#4 | ||
| Line 12: | Line 87: | ||
subs r7,r7,#1 | subs r7,r7,#1 | ||
bne loop | bne loop | ||
stop b stop | stop b stop | ||
ALIGN | ALIGN | ||
list DCW 0x1111, 0x2222, 0x3333, 0x4444, 0x5555 | list DCW 0x1111, 0x2222, 0x3333, 0x4444, 0x5555 | ||
ALIGN | ALIGN | ||
string DCB "This is a test.",0 | string DCB "This is a test.",0 ; This string is not used in the copy to ram program | ||
string2 DCB 'T','h','i' | string2 DCB 'T','h','i' ; This string2 is not used in the copy to ram program | ||
ALIGN | ALIGN | ||
AREA Thedata, DATA, NOINIT, READWRITE | AREA Thedata, DATA, NOINIT, READWRITE | ||
datastart SPACE 20 | datastart SPACE 20 | ||
END | END | ||
---- | |||
* Subroutine Example1 | |||
; First Subroutine Example | ; First Subroutine Example | ||
; This program demonstrates using a subroutine, | ; This program demonstrates using a subroutine, | ||
; saving registers on the stack, etc. | ; saving registers on the stack, etc. | ||
; Rob Frohne, | ; Rob Frohne, 11/3/2013 | ||
stack_start EQU 0x40001000 | stack_start EQU 0x40001000 | ||
| Line 41: | Line 117: | ||
ldr sp, =stack_start ; Tell where we will place the stack. | ldr sp, =stack_start ; Tell where we will place the stack. | ||
; (It goes down (lower addresses from here.) | ; (It goes down (lower addresses from here.) | ||
mov r1, #1 ; Store some numebers in some registers | |||
mov r1, #1 ; Store some numebers in some registers | |||
mov r2, #2 | mov r2, #2 | ||
mov r3, #3 | mov r3, #3 | ||
bl subroutine | bl subroutine | ||
stop b stop | stop b stop | ||
| Line 53: | Line 126: | ||
; messes up the registers locally, | ; messes up the registers locally, | ||
; then restores the registers and returns. | ; then restores the registers and returns. | ||
subroutine | subroutine | ||
stmfd sp!, {r1-r2,lr} ; save used registers and the link register (r14) | stmfd sp!, {r1-r2,lr} ; save used registers and the link register (r14) | ||
mov r1,#0xffffffff ; mess up the registers | mov r1,#0xffffffff ; mess up the registers | ||
mov r2, r1 | mov r2, r1 | ||
ldmfd sp!, {r1,r2,pc} ; pop the stack and return | ldmfd sp!, {r1,r2,pc} ; pop the stack and return | ||
END | |||
---- | |||
* Minimum of a Signed Number | |||
<nowiki> | |||
; This program finds the minimum of a list of constant words in signed format | |||
; The result is in r3 at the end of the routine. | |||
; Rob Frohne 10/30/2013 | |||
AREA Program, CODE, READONLY | |||
ENTRY | |||
ldr r0,=end ; load the end address of the code & initialize it as the pointer. | |||
ldr r2,=begin ; load the beginning address of the code. | |||
mov r3,#0x7fffffff ; Initialize r3 as the most positive number. | |||
loop | |||
ldr r6,[r2],#4 ; load the next data into r6 and post increment r2 for the next data. | |||
cmp r6,r3 ; Find out if r6 > r3. result from r6-r3 like subs r7,r6,r3 without r6 necessary. | |||
bgt no_update ; If it is no update. | |||
mov r3,r6 ; update if r6 is lower than r3. | |||
no_update | |||
cmp r0,r2 ; are we at the end yet | |||
bne loop ; if r7 != 0 then keep looping | |||
stop b stop | |||
ALIGN | |||
begin | |||
DCD 0x8fffffff, 0x55555555, 0x44444444, 0x77777777, 0xffffffff | |||
end | |||
END | |||
</nowiki> | |||
---- | |||
* Compare Two Null Terminated Strings | |||
<nowiki> | |||
; Subroutine to compare two null terminated ASCII strings. | |||
; The address where the two strings start are in r0 and r1 | |||
; The return is in r0, 1 for match and 0 for don't match. | |||
; If they don't match, r1 gives the number of the first | |||
; character that didn't match, starting with 0. | |||
; r2 and r3 are not protected. | |||
; Rob Frohne 11/6/2013 | |||
stack_start EQU 0x40001000 | |||
AREA String_Compare, CODE | |||
ENTRY | |||
Start | |||
ldr sp, =stack_start ; Tell where we will place the stack. | |||
; (It goes down (lower addresses from here.) | |||
ldr r0, =string1 | |||
ldr r1, =string2 | |||
bl compare_strings | |||
stop b stop | |||
compare_strings | |||
stmfd sp!, {r2,r4,r5,lr} ; save used registers and the link register (r14) | |||
mov r2, #0 ; Initialize the counter for the first position. | |||
loop | |||
ldrb r4,[r0],#1 | |||
ldrb r5,[r1],#1 | |||
cmp r5,r4 | |||
bne do_not_match | |||
cmp r4, #0 ; check for end of string. | |||
beq match | |||
add r2, #1 | |||
b loop | |||
do_not_match | |||
mov r0, #0 ; don't match | |||
b finish | |||
match | |||
mov r0, #1 | |||
finish | |||
mov r1,r2 ; Move the count into the result register. | |||
ldmfd sp!, {r2,r4,r5,pc} ; pop the stack and return | |||
string1 | |||
DCB "This is the first string.",00 ; For testing purposes. | |||
ALIGN | |||
string2 | |||
DCB "This is the first string.",00 | |||
ALIGN | |||
END | |||
</nowiki> | |||
---- | |||
* BCD Add | |||
<nowiki> | |||
; Subroutine to add two BCD numbers in 32 bit form with each nibble | |||
; representing a digit. | |||
; locals: r8 for digit counter, single digit mask 0xf, r5 & r6 for masked addends, | |||
; working BCD_carry, r7 | |||
; working result in r4 | |||
; the summed digits go in r3 | |||
; inputs: r0+r1 | |||
; outputs: r0 result and r1 carry | |||
; only r4-r8 are saved. | |||
; Rob Frohne 11/12/13 | |||
stack_start EQU 0x40001000 | |||
AREA ADD_BCD, CODE | |||
ENTRY | |||
Start | |||
ldr sp, =stack_start ; Tell where we will place the stack. | |||
; (It goes down (lower addresses from here.) | |||
ldr r0, =0x12345678 ; The two numbers to add. | |||
ldr r1, =0x87654321 | |||
bl bcd_add | |||
stop b stop | |||
bcd_add ; The subroutine | |||
stmfd sp!, {r4-r8,lr} | |||
mov r8, #8 ; Set the counter to move through the eight digits | |||
mov r7, #0 ; Set the carry to zero to start with | |||
mov r3, #0 ; This is where the resulting digits of the sum are stored. | |||
loop | |||
and r5, r0, #0xf ; mask for the rightmost digit. | |||
and r6, r1, #0xf | |||
add r4, r5, r7 ; add carry | |||
add r4, r4, r6 ; r4=r5+r6 | |||
subs r4, r4, #10 ; Subtract 10 (base 10) to see if there is a carry. | |||
bpl carry | |||
mov r7, #0 ; set carry to zero | |||
add r4, r4, #10 ; Add the 10 back in as there was no carry needed. | |||
b roll_to_next_digit | |||
carry | |||
mov r7, #1 ; set the carry | |||
roll_to_next_digit | |||
orr r3, r3, r4 ; Add these digits into the sum. | |||
ror r0, #4 | |||
ror r1, #4 | |||
ror r3, #4 | |||
subs r8, r8, #1 ; Decrement the digit counter | |||
bne loop ; If it isn't zero do the next digit. | |||
mov r0, r3 ; Set the output registers. r0 is result. r1 is carry. | |||
mov r1, r7 | |||
ldmfd sp!, {r4-r8,pc} | |||
END | |||
</nowiki> | |||
---- | |||
*Bubble Sort | |||
<nowiki> | |||
; This is a program to bubble sort a list. | |||
; Rob Frohne and the CPTR 215 class | |||
stack_start EQU 0x40001000 | |||
length EQU (end_of_list - begin) | |||
end_ram EQU (datastart + length) | |||
; EQU statements must be at the beginning of the program. | |||
AREA Subroutine_Example, CODE | |||
ENTRY | |||
; Copy list to RAM | |||
ldr sp, =stack_start | |||
LDR R9, =begin | |||
ldr R7, =end_of_list | |||
ldr r6, =datastart | |||
loop | |||
ldr r8,[r9],#4 | |||
str r8,[r6],#4 | |||
cmp r9,r7 | |||
bne loop | |||
; End copy to RAM | |||
start_sort | |||
ldr r5,=(end_ram - 4) | |||
loop_sort_outer ; r2 is our counter, it goes from 1 to item_count | |||
mov r1, #1 ; has_changed = false (0 is true) | |||
ldr r2,=datastart ; start of data in ram goes into r2 | |||
loop_sort_inner ; | |||
ldr r3,[r2],#4 | |||
ldr r4,[r2],#0 | |||
cmp r3,r4 | |||
blhi subroutine_swap ; swaps the last two and sets has_changed | |||
cmp r2,r5 | |||
bne loop_sort_inner | |||
sub r5,r5,#4 ; the last item is in order, so we don't need to check it again. | |||
cmp r1,#1 | |||
bne loop_sort_outer | |||
stop b stop | |||
subroutine_swap ; swaps the contents of the addresses held in | |||
; r2 and r2 -4 (the previous address) | |||
; has_changed is r1 and it sets it to 0 (true) | |||
stmfd sp!, {r0,r2-r4,lr} | |||
mov r1,#0 ; setting the has_changed to true. | |||
ldr r0,[r2],#-4 ; swapping data | |||
ldr r3,[r2] | |||
str r0,[r2],#4 | |||
str r3,[r2] | |||
ldmfd sp!, {r0,r2-r4,pc} | |||
ALIGN | |||
begin | |||
DCD 0x8fffffff, 0x55555555, 0x44444444, 0x77777777, 0xffffffff | |||
end_of_list | |||
AREA Thedata, DATA, NOINIT, READWRITE | |||
datastart SPACE 20 | |||
END | |||
</nowiki> | |||
---- | |||
*GPIO Example | |||
<nowiki> | |||
;--------------------------------------------------------------------------- | |||
; | |||
; Programmer : Larry Aamodt | |||
; | |||
; File name : shell_2148.s | |||
; Class : CPTR-215 | |||
; Language : ARM assembly | |||
; Assembler : Keil | |||
; Target MCU : NXP LPC-2148 on Embedded Artists board | |||
; Date Written: 11/30/09 | |||
; change history: 11/30/09 LDA Updated with hardware start-up | |||
; 12/03/09 LDA PWM register definitions added | |||
; Description : | |||
; | |||
; Inputs : | |||
; | |||
; Outputs : | |||
; | |||
; Special : | |||
; requirements | |||
; | |||
; | |||
; NOTES: | |||
; | |||
; | |||
; | |||
;--------------------------------------------------------------------------- | |||
; Put application program definitions (i.e. equates) here: | |||
; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs | |||
Mode_USR EQU 0x10 | |||
Mode_FIQ EQU 0x11 | |||
Mode_IRQ EQU 0x12 | |||
Mode_SVC EQU 0x13 | |||
Mode_ABT EQU 0x17 | |||
Mode_UND EQU 0x1B | |||
Mode_SYS EQU 0x1F | |||
I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled | |||
F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled | |||
; Memory addresses for standard GPIO definitions | |||
IO0PIN EQU 0xE0028000 | |||
IO0SET EQU 0xE0028004 | |||
IO0DIR EQU 0xE0028008 | |||
IO0CLR EQU 0xE002800C | |||
; Memory addresses for Pulse Width Modulation (PWM) | |||
PWM_TCR EQU 0xE0014004 ; PWM_TCR Timer Control Register | |||
PWM_PR EQU 0xE001400C ; PWM_PR Prescaler Register | |||
PWM_MCR EQU 0xE0014014 ; PWM_MCR Match Control Register | |||
PWM_MR0 EQU 0xE0014018 ; PWM_MR0 Match Register 0 (sets pulse period) | |||
PWM_MR4 EQU 0xE0014040 ; PWM_MR4 Match Register 4 (sets pulse length) | |||
PWM_MR6 EQU 0xE0014048 ; PWM_MR6 Match Register 6 (sets pulse length) | |||
PWM_PCR EQU 0xE001404C ; PWM_CR Control Register | |||
PWM_LER EQU 0xE0014050 ; PWM_LER Latch Enable Register | |||
PINSEL0 EQU 0xE002C000 ; Pin connect block - port 0 | |||
PINSEL1 EQU 0xE002C004 ; Pin connect block - port 1 | |||
; Stack size definitions | |||
UND_Stack_Size EQU 0x00000000 | |||
SVC_Stack_Size EQU 0x00000008 | |||
ABT_Stack_Size EQU 0x00000000 | |||
FIQ_Stack_Size EQU 0x00000000 | |||
IRQ_Stack_Size EQU 0x00000080 | |||
USR_Stack_Size EQU 0x00000400 | |||
ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \ | |||
FIQ_Stack_Size + IRQ_Stack_Size) | |||
AREA STACK, NOINIT, READWRITE, ALIGN=3 | |||
Stack_Mem SPACE USR_Stack_Size | |||
__initial_sp SPACE ISR_Stack_Size | |||
Stack_Top | |||
; Area Definition and Entry Point | |||
; Startup Code must be linked first at Address at which it expects to run. | |||
AREA RESET, CODE, READONLY | |||
ARM | |||
; Exception Vectors | |||
; Mapped to Address 0. | |||
; Absolute addressing mode must be used. | |||
; Dummy Handlers are implemented as infinite loops which can be modified. | |||
Vectors LDR PC, Reset_Addr | |||
LDR PC, Undef_Addr | |||
LDR PC, SWI_Addr | |||
LDR PC, PAbt_Addr | |||
LDR PC, DAbt_Addr | |||
NOP ; Reserved Vector | |||
; LDR PC, IRQ_Addr | |||
LDR PC, [PC, #-0x0FF0] ; Vector from VicVectAddr | |||
LDR PC, FIQ_Addr | |||
Reset_Addr DCD Reset_Handler | |||
Undef_Addr DCD Undef_Handler | |||
SWI_Addr DCD SWI_Handler | |||
PAbt_Addr DCD PAbt_Handler | |||
DAbt_Addr DCD DAbt_Handler | |||
DCD 0 ; Reserved Address | |||
IRQ_Addr DCD IRQ_Handler | |||
FIQ_Addr DCD FIQ_Handler | |||
Undef_Handler B Undef_Handler | |||
SWI_Handler B SWI_Handler | |||
PAbt_Handler B PAbt_Handler | |||
DAbt_Handler B DAbt_Handler | |||
IRQ_Handler B IRQ_Handler | |||
FIQ_Handler B FIQ_Handler | |||
; Reset Handler | |||
EXPORT Reset_Handler | |||
Reset_Handler | |||
; Setup Stack for each mode | |||
LDR R0, =Stack_Top | |||
; Enter Undefined Instruction Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #UND_Stack_Size | |||
; Enter Abort Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #ABT_Stack_Size | |||
; Enter FIQ Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #FIQ_Stack_Size | |||
; Enter IRQ Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #IRQ_Stack_Size | |||
; Enter Supervisor Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #SVC_Stack_Size | |||
; Enter User Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_USR | |||
MOV SP, R0 | |||
SUB SL, SP, #USR_Stack_Size | |||
; User program code goes here | |||
main | |||
ldr r1, =PINSEL0 | |||
mov r0, #0 ; set P0.0 to P0.15 as GPIO | |||
str r0,[r1] | |||
ldr r1, =IO0DIR ; Get ready to set direction of data | |||
ldr r0, =0xffff ; output | |||
str r0, [r1] ; set the direction | |||
ldr r1, =IO0PIN ; load the address of the port0 | |||
mov r0, #0 | |||
next | |||
str r0, [r1] | |||
add r0, r0, #1 | |||
ldr r2, =0x200 | |||
delay | |||
subs r2,r2,#1 | |||
bne delay | |||
b next | |||
AREA Thedata, DATA, READWRITE | |||
ALIGN | |||
datastart EQU 0x40000004 | |||
SPACE 20 | |||
;FILL 20, 0xff ; Why is this stored at 0x50 instead of 0x58? | |||
; Or maybe a better question: How do I set data at | |||
; a specific memory location? | |||
END | |||
</nowiki> | |||
---- | |||
* LCD Example | |||
<nowiki> | |||
;--------------------------------------------------------------------------- | |||
; | |||
; Programmer : Larry Aamodt | |||
; | |||
; File name : shell_2148.s | |||
; Class : CPTR-215 | |||
; Language : ARM assembly | |||
; Assembler : Keil | |||
; Target MCU : NXP LPC-2148 on Embedded Artists board | |||
; Date Written: 11/30/09 | |||
; change history: 11/30/09 LDA Updated with hardware start-up | |||
; 12/03/09 LDA PWM register definitions added | |||
; Description : | |||
; | |||
; Inputs : | |||
; | |||
; Outputs : | |||
; | |||
; Special : | |||
; requirements | |||
; | |||
; | |||
; NOTES: | |||
; | |||
; | |||
; | |||
;--------------------------------------------------------------------------- | |||
; Put application program definitions (i.e. equates) here: | |||
; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs | |||
Mode_USR EQU 0x10 | |||
Mode_FIQ EQU 0x11 | |||
Mode_IRQ EQU 0x12 | |||
Mode_SVC EQU 0x13 | |||
Mode_ABT EQU 0x17 | |||
Mode_UND EQU 0x1B | |||
Mode_SYS EQU 0x1F | |||
I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled | |||
F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled | |||
; Memory addresses for standard GPIO definitions | |||
IO0PIN EQU 0xE0028000 | |||
IO0SET EQU 0xE0028004 | |||
IO0DIR EQU 0xE0028008 | |||
IO0CLR EQU 0xE002800C | |||
; Memory addresses for Pulse Width Modulation (PWM) | |||
PWM_TCR EQU 0xE0014004 ; PWM_TCR Timer Control Register | |||
PWM_PR EQU 0xE001400C ; PWM_PR Prescaler Register | |||
PWM_MCR EQU 0xE0014014 ; PWM_MCR Match Control Register | |||
PWM_MR0 EQU 0xE0014018 ; PWM_MR0 Match Register 0 (sets pulse period) | |||
PWM_MR4 EQU 0xE0014040 ; PWM_MR4 Match Register 4 (sets pulse length) | |||
PWM_MR6 EQU 0xE0014048 ; PWM_MR6 Match Register 6 (sets pulse length) | |||
PWM_PCR EQU 0xE001404C ; PWM_CR Control Register | |||
PWM_LER EQU 0xE0014050 ; PWM_LER Latch Enable Register | |||
PINSEL0 EQU 0xE002C000 ; Pin connect block - port 0 | |||
PINSEL1 EQU 0xE002C004 ; Pin connect block - port 1 | |||
; Stack size definitions | |||
UND_Stack_Size EQU 0x00000000 | |||
SVC_Stack_Size EQU 0x00000008 | |||
ABT_Stack_Size EQU 0x00000000 | |||
FIQ_Stack_Size EQU 0x00000000 | |||
IRQ_Stack_Size EQU 0x00000080 | |||
USR_Stack_Size EQU 0x00000400 | |||
ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \ | |||
FIQ_Stack_Size + IRQ_Stack_Size) | |||
AREA STACK, NOINIT, READWRITE, ALIGN=3 | |||
Stack_Mem SPACE USR_Stack_Size | |||
__initial_sp SPACE ISR_Stack_Size | |||
Stack_Top | |||
; Area Definition and Entry Point | |||
; Startup Code must be linked first at Address at which it expects to run. | |||
AREA RESET, CODE, READONLY | |||
ARM | |||
; Exception Vectors | |||
; Mapped to Address 0. | |||
; Absolute addressing mode must be used. | |||
; Dummy Handlers are implemented as infinite loops which can be modified. | |||
Vectors LDR PC, Reset_Addr | |||
LDR PC, Undef_Addr | |||
LDR PC, SWI_Addr | |||
LDR PC, PAbt_Addr | |||
LDR PC, DAbt_Addr | |||
NOP ; Reserved Vector | |||
; LDR PC, IRQ_Addr | |||
LDR PC, [PC, #-0x0FF0] ; Vector from VicVectAddr | |||
LDR PC, FIQ_Addr | |||
Reset_Addr DCD Reset_Handler | |||
Undef_Addr DCD Undef_Handler | |||
SWI_Addr DCD SWI_Handler | |||
PAbt_Addr DCD PAbt_Handler | |||
DAbt_Addr DCD DAbt_Handler | |||
DCD 0 ; Reserved Address | |||
IRQ_Addr DCD IRQ_Handler | |||
FIQ_Addr DCD FIQ_Handler | |||
Undef_Handler B Undef_Handler | |||
SWI_Handler B SWI_Handler | |||
PAbt_Handler B PAbt_Handler | |||
DAbt_Handler B DAbt_Handler | |||
IRQ_Handler B IRQ_Handler | |||
FIQ_Handler B FIQ_Handler | |||
; Reset Handler | |||
EXPORT Reset_Handler | |||
Reset_Handler | |||
; Setup Stack for each mode | |||
LDR R0, =Stack_Top | |||
; Enter Undefined Instruction Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #UND_Stack_Size | |||
; Enter Abort Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #ABT_Stack_Size | |||
; Enter FIQ Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #FIQ_Stack_Size | |||
; Enter IRQ Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #IRQ_Stack_Size | |||
; Enter Supervisor Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #SVC_Stack_Size | |||
; Enter User Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_USR | |||
MOV SP, R0 | |||
SUB SL, SP, #USR_Stack_Size | |||
; User program code goes here | |||
main | |||
bl lcdReset ; set up the lcd | |||
bl lcdClear | |||
mov r0, #32 | |||
loop | |||
bl lcdWRdata ; write to the LCD | |||
add r0, r0, #1 ; increment the data | |||
mov r9, r0 | |||
ldr r0, =1000000 | |||
bl delay | |||
mov r0, r9 | |||
b loop | |||
; User data area definition follows | |||
AREA appdata, DATA, NOINIT, READWRITE | |||
;----------------------------------------------------------------------------- | |||
; Copyright (C) 2012 .... | |||
; | |||
; Programmer : Larry Aamodt | |||
; | |||
; File name : lcd_routines.asm | |||
; Language : ARM assembly | |||
; Assembler ; Keil | |||
; Target MCU : NXP LPC2148 on Embedded Artists education board | |||
; Date : 12/05/12 LDA lcd_routines.asm. debugged | |||
; | |||
; Description : LCD display routines | |||
; Copy this code to your own program | |||
; | |||
; Procedures you can call are: | |||
; lcdReset must be called first. no parameters. | |||
; lcdClear use to clear the display & home the cursor | |||
; no parameters are required. | |||
; lcdWRdata use to write one character on the display | |||
; place an ASCII char in r0 before calling. | |||
; The cursor will advance. | |||
; lcdCursorAt use to move the cursor. Two parameters | |||
; r0 = row (1 or 2) | |||
; r1 = column to move cursor to (0-15) | |||
; | |||
; Example use of the LCD routines: | |||
; bl lcdReset ; do this once at the top of your program | |||
; | |||
; mov r0,#31h ; place the ascii code for number one in r0 | |||
; bl lcdWRdata ; display the character '1' on LCD display | |||
; | |||
; bl lcdClear ; clear the display | |||
; | |||
; mov r0,#1 ; select LCD row 1 | |||
; mov r1,#4 ; select LCD column 4 | |||
; bl lcdCursorAt ; move the cursor | |||
; | |||
; | |||
; NOTE: All registers are saved by these routines, i.e. upon return | |||
; from the subroutine all registers, except flags, have the | |||
; same value in them as before the subroutine was called (this | |||
; breaks with the ARM convention for subroutines but is done | |||
; to make it easier for you). | |||
; | |||
;----------------------------------------------------------------------------- | |||
AREA lcdroutines,CODE,READONLY | |||
EXPORT lcdReset | |||
EXPORT lcdClear | |||
EXPORT lcdWRdata | |||
EXPORT lcdCursorAt | |||
EXPORT delay | |||
; ----------------------------------------------------------------------------- | |||
; LCD Procedures follow. | |||
;------------------------------------------------------------------------------ | |||
; ***** LCD equates ****** | |||
;IO0PIN EQU 0xE0028000 | |||
;IO0SET EQU 0xE0028004 | |||
;IO0DIR EQU 0xE0028008 | |||
;IO0CLR EQU 0xE002800C | |||
IO1PIN EQU 0xE0028010 | |||
IO1SET EQU 0xE0028014 | |||
IO1DIR EQU 0xE0028018 | |||
IO1CLR EQU 0xE002801C | |||
T0_TCR_ADDR EQU 0xE0004004 | |||
T0_PR_ADDR EQU 0xE000400C | |||
T0_MCR_ADDR EQU 0xE0004014 | |||
T0_MR0_ADDR EQU 0xE0004018 | |||
; ----------------------------------------------------------------------------- | |||
; Procedure lcdReset Must be called before writing to the LCD | |||
; No parameters required | |||
; ----------------------------------------------------------------------------- | |||
lcdReset STMFD SP!,{LR,r0,r1,r2,r3,r4,r5,r6,r7,r8,r9} | |||
LDR r1,=T0_PR_ADDR ; Prescale register | |||
MOV r2,#2 ; prescale count value | |||
STR r2,[r1] ; Prescaler will divide by 3 | |||
LDR r1,=T0_MCR_ADDR ; Match control register | |||
MOV r2,#0x6 ; bit 2 = one | |||
STR r2,[r1] ; stop counter when match reached | |||
LDR r5,=IO0CLR | |||
LDR r6,=IO0SET | |||
LDR r7,=IO1CLR | |||
LDR r8,=IO1SET | |||
LDR r0,=35000 | |||
BL delay ; delay 35ms | |||
LDR r0,=IO0DIR | |||
LDR r4,[r0] ; read current Port 0 direction bits | |||
LDR r3,=0x40408000 ; one's for pins to be set for output | |||
ORR r4,r4,r3 ; bits 22 & 30 to be outputs | |||
STR r4,[r0] ; set lcd port bits to output | |||
LDR r3,=0x00400000 ; | |||
STR r3,[r5] ; write 0 to LCD R/W signal | |||
LDR r3,=0x40008000 | |||
STR r3,[r6] ; turn on backlight - write 1 to P0.30 | |||
LDR r0,=IO1DIR | |||
LDR r4,[r0] ; read current Port 1 direction bits | |||
LDR r3,=0x03FF0000 ; one's for lcd pins - set for output | |||
ORR r4,r4,r3 ; bits 16 to 25 to be outputs | |||
STR r4,[r0] ; set lcd port direction bits to output | |||
STR r3,[r7] ; clear the LCD data & control bits | |||
LDR r9,=0x02000000 ; bit pattern to turn on/off E | |||
LDR r2,=0x00380000 ; function: 2 lines, 5x7 dots | |||
STR r2,[r8] ; set lcd function bits | |||
BL pulse_e | |||
STR r3,[r7] ; clear lcd bits | |||
MOV r0,#40 | |||
BL delay ; wait 40 microseconds | |||
LDR r2,=0x000E0000 ; function: display on, cursor on | |||
STR r2,[r8] ; set lcd function bits | |||
BL pulse_e | |||
STR r3,[r7] ; clear lcd bits | |||
MOV r0,#40 | |||
BL delay ; wait 40 microseconds | |||
LDR r2,=0x00010000 ; lcd function: clear display | |||
STR r2,[r8] ; set lcd function bits | |||
BL pulse_e | |||
STR r3,[r7] ; clear lcd bits | |||
MOV r0,#1600 | |||
BL delay ; delay for 1600 microseconds | |||
LDR r2,=0x00030000 ; lcd function: set entry mode | |||
STR r2,[r8] ; set lcd function bits | |||
BL pulse_e | |||
STR r3,[r7] ; clear lcd bits | |||
end_lcdReset LDMFD SP!,{PC,r0,r1,r2,r3,r4,r5,r6,r7,r8,r9} | |||
;------------------------------------------------------------------------------ | |||
; Procedure pulse_e uses r0. Not interuptable (r14 not saved) | |||
; assumes r9 has 0x02000000 in it | |||
; assumes r7 has IO1CLR address in it | |||
; assumes r8 has IO1SET address in it | |||
;------------------------------------------------------------------------------ | |||
pulse_e MOV r0,#4 | |||
STR r9,[r8] ; assert E | |||
ploop1 SUBS r0,r0,#1 ; delay 600ns or so | |||
BNE ploop1 | |||
STR r9,[r7] ; de-assert E | |||
MOV r0,#8 | |||
ploop2 SUBS r0,r0,#1 ; delay 1100ns or so | |||
BNE ploop2 | |||
end_pulse_e BX LR | |||
; ----------------------------------------------------------------------------- | |||
; Procedure lcdClear Clears the LCD and positions cursor to line1, left col | |||
; no parameters required | |||
; ----------------------------------------------------------------------------- | |||
lcdClear STMFD SP!,{LR,r0,r1,r2,r3,r7,r8,r9} | |||
LDR r9,=0x02000000 ; bit pattern to turn on/off E | |||
LDR r3,=0x03FF0000 ; one's for pins used for lcd | |||
LDR r7,=IO1CLR | |||
LDR r8,=IO1SET | |||
LDR r2,=0x00010000 ; lcd function: clear display | |||
STR r2,[r8] ; set lcd function bits | |||
BL pulse_e | |||
STR r3,[r7] ; clear lcd bits | |||
MOV r0,#1600 | |||
BL delay | |||
end_lcdClear LDMFD SP!,{PC,r0,r1,r2,r3,r7,r8,r9} | |||
; ----------------------------------------------------------------------------- | |||
; Procedure lcdCursorAt | |||
; r0 assumed to contain the row# (1 or 2) | |||
; r1 assumed to contain col#(0-15) | |||
; No cursor movement if invalid row or col # is found | |||
; ----------------------------------------------------------------------------- | |||
lcdCursorAt STMFD SP!,{LR,r0,r1,r2,r3,r7,r8,r9} | |||
CMP r1,#15 ; check column & row range | |||
BHI end_lcdCursorAt | |||
CMP r0,#0 | |||
BEQ end_lcdCursorAt | |||
CMP r0,#2 | |||
BHI end_lcdCursorAt | |||
ADDEQ r1,r1,#0x40 ; build the cursor address | |||
LDR r0,=0x00800000 | |||
ORR r2,r0,r1,LSL #16 ; r2 now has the address | |||
LDR r3,=0x03FF0000 ; one's for pins used for lcd | |||
LDR r7,=IO1CLR | |||
LDR r8,=IO1SET | |||
LDR r9,=0x02000000 ; bit pattern to turn on/off E | |||
STR r2,[r8] ; set lcd function bits | |||
BL pulse_e | |||
STR r3,[r7] ; clear lcd bits | |||
MOV r0,#40 | |||
BL delay | |||
end_lcdCursorAt LDMFD SP!,{PC,r0,r1,r2,r3,r7,r8,r9} | |||
; ----------------------------------------------------------------------------- | |||
; Procedure lcdWRdata Writes data (an ASCII character) to the | |||
; current cursor position on the LCD | |||
; r0 is assumed to contain the character to send | |||
; ----------------------------------------------------------------------------- | |||
lcdWRdata STMFD SP!,{LR,r0,r1,r2,r3,r7,r8,r9} | |||
LDR r9,=0x02000000 ; bit pattern to turn on/off E | |||
LDR r3,=0x03FF0000 ; one's for pins used for lcd | |||
LDR r7,=IO1CLR | |||
LDR r8,=IO1SET | |||
AND r0,r0,#0xFF ; make sure only 8 bits are non-zero | |||
ORR r0,r0,#0x100 ; set bit that indicates writing | |||
LSL r0,r0,#16 | |||
STR r0,[r8] ; write data | |||
BL pulse_e | |||
STR r3,[r7] ; clear lcd bits | |||
end_lcdWRData LDMFD SP!,{PC,r0,r1,r2,r3,r7,r8,r9} | |||
; ----------------------------------------------------------------------------- | |||
; Procedure delay microsecond delay using timer 0 | |||
; (12Mhz clock & VPB divide by 4 assumed) | |||
; reg R0 must contain a delay value in uS | |||
; Not interruptable (r14 not saved) | |||
; assumes lcdReset has been called prior to delay | |||
; r0, r1 not preserved | |||
; ----------------------------------------------------------------------------- | |||
delay LDR r1,=T0_MR0_ADDR ; Match register zero | |||
STR r0,[r1] ; load match count per R0 | |||
; ldr r0,=0x8000 | |||
; str r0,[r5] ; turn on p0.15 led | |||
LDR r1,=T0_TCR_ADDR ; Timer 0 Control Register | |||
MOV r0,#2 ; bit 1 = one | |||
STR r0,[r1] ; Clear counter & prescaler | |||
MOV r0,#0 | |||
STR r0,[r1] | |||
MOV r0,#1 ; bit 0 = one | |||
STR r0,[r1] ; Turn on counter | |||
dloop LDR r0,[r1] ; Read TCR register | |||
ANDS r0,r0,#1 | |||
BNE dloop | |||
; ldr r0,=0x8000 | |||
; str r0,[r6] ; turn off p0.15 led | |||
end_delay BX LR ; Return | |||
END | |||
</nowiki> | |||
* PWM Example for running the servos on the robots | |||
<nowiki> | |||
;--------------------------------------------------------------------------- | |||
; | |||
; Programmer : Larry Aamodt | |||
; | |||
; File name : shell_2148.s | |||
; Class : CPTR-215 | |||
; Language : ARM assembly | |||
; Assembler : Keil | |||
; Target MCU : NXP LPC-2148 on Embedded Artists board | |||
; Date Written: 11/30/09 | |||
; change history: 11/30/09 LDA Updated with hardware start-up | |||
; 12/03/09 LDA PWM register definitions added | |||
; Description : | |||
; | |||
; Inputs : | |||
; | |||
; Outputs : | |||
; | |||
; Special : | |||
; requirements | |||
; | |||
; | |||
; NOTES: | |||
; | |||
; | |||
; | |||
;--------------------------------------------------------------------------- | |||
; Put application program definitions (i.e. equates) here: | |||
; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs | |||
Mode_USR EQU 0x10 | |||
Mode_FIQ EQU 0x11 | |||
Mode_IRQ EQU 0x12 | |||
Mode_SVC EQU 0x13 | |||
Mode_ABT EQU 0x17 | |||
Mode_UND EQU 0x1B | |||
Mode_SYS EQU 0x1F | |||
I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled | |||
F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled | |||
; Memory addresses for standard GPIO definitions | |||
IO0PIN EQU 0xE0028000 | |||
IO0SET EQU 0xE0028004 | |||
IO0DIR EQU 0xE0028008 | |||
IO0CLR EQU 0xE002800C | |||
; Memory addresses for Timer/Counter | |||
T1TCR EQU 0xE0008004 | |||
T1CTCR EQU 0xE0008070 | |||
T1PR EQU 0xE000800C | |||
T1MCR EQU 0xE0008014 | |||
T1EMR EQU 0xE000803C | |||
; Memory addresses for Pulse Width Modulation (PWM) | |||
PWM_TCR EQU 0xE0014004 ; PWM_TCR Timer Control Register | |||
PWM_PR EQU 0xE001400C ; PWM_PR Prescaler Register | |||
PWM_MCR EQU 0xE0014014 ; PWM_MCR Match Control Register | |||
PWM_MR0 EQU 0xE0014018 ; PWM_MR0 Match Register 0 (sets pulse period) | |||
PWM_MR4 EQU 0xE0014040 ; PWM_MR4 Match Register 4 (sets pulse length) | |||
PWM_MR6 EQU 0xE0014048 ; PWM_MR6 Match Register 6 (sets pulse length) | |||
PWM_PCR EQU 0xE001404C ; PWM_CR Control Register | |||
PWM_LER EQU 0xE0014050 ; PWM_LER Latch Enable Register | |||
PINSEL0 EQU 0xE002C000 ; Pin connect block - port 0 | |||
PINSEL1 EQU 0xE002C004 ; Pin connect block - port 1 | |||
; Stack size definitions | |||
UND_Stack_Size EQU 0x00000000 | |||
SVC_Stack_Size EQU 0x00000008 | |||
ABT_Stack_Size EQU 0x00000000 | |||
FIQ_Stack_Size EQU 0x00000000 | |||
IRQ_Stack_Size EQU 0x00000080 | |||
USR_Stack_Size EQU 0x00000400 | |||
ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \ | |||
FIQ_Stack_Size + IRQ_Stack_Size) | |||
AREA STACK, NOINIT, READWRITE, ALIGN=3 | |||
Stack_Mem SPACE USR_Stack_Size | |||
__initial_sp SPACE ISR_Stack_Size | |||
Stack_Top | |||
; Area Definition and Entry Point | |||
; Startup Code must be linked first at Address at which it expects to run. | |||
AREA RESET, CODE, READONLY | |||
ARM | |||
; Exception Vectors | |||
; Mapped to Address 0. | |||
; Absolute addressing mode must be used. | |||
; Dummy Handlers are implemented as infinite loops which can be modified. | |||
Vectors LDR PC, Reset_Addr | |||
LDR PC, Undef_Addr | |||
LDR PC, SWI_Addr | |||
LDR PC, PAbt_Addr | |||
LDR PC, DAbt_Addr | |||
NOP ; Reserved Vector | |||
; LDR PC, IRQ_Addr | |||
LDR PC, [PC, #-0x0FF0] ; Vector from VicVectAddr | |||
LDR PC, FIQ_Addr | |||
Reset_Addr DCD Reset_Handler | |||
Undef_Addr DCD Undef_Handler | |||
SWI_Addr DCD SWI_Handler | |||
PAbt_Addr DCD PAbt_Handler | |||
DAbt_Addr DCD DAbt_Handler | |||
DCD 0 ; Reserved Address | |||
IRQ_Addr DCD IRQ_Handler | |||
FIQ_Addr DCD FIQ_Handler | |||
Undef_Handler B Undef_Handler | |||
SWI_Handler B SWI_Handler | |||
PAbt_Handler B PAbt_Handler | |||
DAbt_Handler B DAbt_Handler | |||
IRQ_Handler B IRQ_Handler | |||
FIQ_Handler B FIQ_Handler | |||
; Reset Handler | |||
EXPORT Reset_Handler | |||
Reset_Handler | |||
; Setup Stack for each mode | |||
LDR R0, =Stack_Top | |||
; Enter Undefined Instruction Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #UND_Stack_Size | |||
; Enter Abort Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #ABT_Stack_Size | |||
; Enter FIQ Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #FIQ_Stack_Size | |||
; Enter IRQ Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #IRQ_Stack_Size | |||
; Enter Supervisor Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #SVC_Stack_Size | |||
; Enter User Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_USR | |||
MOV SP, R0 | |||
SUB SL, SP, #USR_Stack_Size | |||
; User program code goes here | |||
main | |||
BL pwm_init | |||
mov r0, #3 | |||
ldr r1, =1600 | |||
mov r2, r1 | |||
bl pwm_update | |||
stop b stop | |||
;***************************************************************************** | |||
; Pulse width modulator initialization routine. | |||
; pulse period = 20ms; initial pulse length = 1.5ms | |||
; (values shown are for controlling model plane servos) | |||
; Inputs: none | |||
; Returned values: none | |||
; Uses registers r0, r1 | |||
; | |||
; Calling method: BL pwm_init | |||
; LDA rev 1.0 12/01/10 | |||
; Rob Frohne rev 1.1 12/3/13 | |||
;***************************************************************************** | |||
; Stepper motor connections on the Board of Education are from page 24 of the board | |||
; Users Guide. A stepper motor operation is explained at: | |||
; http://www.haydonkerk.com/Resources/StepperMotorTheory/tabid/192/Default.aspx | |||
; | |||
; PWM is explained in Chapter 16 (page 253 and following) of the reference manual. | |||
; Note the registers in the reference manual are labeled without the _, i.e. | |||
; PWMPR instead of PWM_PR. | |||
pwm_init STMFD sp!,{r14} ; save link register on the stack | |||
LDR r0,=PWM_PR | |||
LDR r1,=2 ; prescaler = 2 divides PCLK by 3 | |||
STR r1,[r0] ; load prescaler | |||
; PCLK rate is 1 MHZ (1 uSEC period) after division. | |||
LDR r0,=PWM_MCR ; PWMMCR PWM Match Control Register. | |||
; The PWMMCR is used to control if an | |||
; interrupt is generated and if the PWMTC | |||
; is reset when a Match occurs. See page 261 of the manual. | |||
LDR r1,=0x02 ; bit 1 is set, others are zero | |||
STR r1,[r0] ; load PWM_MCR: PWM_TC resets when PWM_TC=PWM_MR0 | |||
LDR r0,=PWM_MR0 | |||
LDR r1,=20000 ; count 20,000 1uSEC intervals = 20 milli secs | |||
STR r1,[r0] ; load match register 0. sets pulse period. Page 261. | |||
LDR r0,=PWM_MR4 | |||
LDR r1,=1500 ; initial pulse width = 1.5 milli secs | |||
STR r1,[r0] ; load match register 4. Page 261 | |||
LDR r0,=PWM_MR6 | |||
LDR r1,=1500 ; initial pulse width | |||
STR r1,[r0] ; load match register 6 | |||
LDR r0,=PWM_LER | |||
LDR r1,=0x51 | |||
STR r1,[r0] ; Enable latch registers 0, 4, & 6 | |||
LDR r0,=PWM_PCR | |||
LDR r1,=0x5000 ; bits 12 & 14 set | |||
STR r1,[r0] ; load PWM_CR: enables PWM4 and PWM6 outputs | |||
LDR r0,=PWM_TCR | |||
LDR r1,=0x09 ; bits 3,1,0 set | |||
STR r1,[r0] ; load PWM_TCR enable PWM counter & prescaler | |||
LDR r0,=PINSEL0 | |||
LDR r1,=0xA0000 ; bits 19 & 17 set. selects output PWM 6 & 4 | |||
STR r1,[r0] ; Enable PWM6 & PWM4 outputs | |||
end_pwm_init LDMFD sp!,{pc} ; Return from subroutine pwm_init | |||
;***************************************************************************** | |||
; Pulse width modulator update routine | |||
; Inputs: r0 = command | |||
; 1 = update PWM channel 4 | |||
; 2 = update PWM channel 6 | |||
; 3 = update both channel 4 and 6 | |||
; r1 = new pulse width (# of microseconds) for PWM channel 4 | |||
; r2 = new pulse width (# of microseconds) for PWM channel 6 | |||
; Returned values: none | |||
; Uses registers r0, r1, r2, r3 | |||
; | |||
; Calling method: first put values in r0, r1, r2 as appropriate | |||
; BL pwm_update | |||
; LDA rev 2.0 12/01/11 | |||
;***************************************************************************** | |||
pwm_update STMFD sp!,{r14} ; r0 specifies channels to update | |||
load_pwm4 CMP r0,#1 ; 1 = load PWM chan 4 | |||
BNE load_pwm6 | |||
LDR r3,=PWM_MR4 | |||
STR r1,[r3] ; load match register 4 | |||
load_pwm6 CMP r0,#2 ; 2 = load PWM chan 6 | |||
BNE load_both | |||
LDR r3,=PWM_MR6 | |||
STR r2,[r3] ; load match register 6 | |||
load_both CMP r0,#3 | |||
BNE pwm_reg_update | |||
LDR r3,=PWM_MR4 | |||
STR r1,[r3] | |||
LDR r3,=PWM_MR6 | |||
STR r2,[r3] | |||
pwm_reg_update CMP r0,#1 ; check for just pwm 4 update | |||
MOVEQ r1,#0x10 | |||
CMP r0,#2 ; check for just pwm 6 update | |||
MOVEQ r1,#0x40 | |||
CMP r0,#3 ; check for pwm 4 & 6 update | |||
MOVEQ r1,#0x50 | |||
LDR r3,=PWM_LER | |||
STR r1,[r3] ; enable latch registers | |||
end_pwm_update LDMFD sp!,{pc} ; Return from subroutine pwm_update | |||
; User data area definition follows | |||
AREA appdata, DATA, NOINIT, READWRITE | |||
END | |||
</nowiki> | |||
* Stepper Motor on the Embedded Artists Board of Education | |||
<nowiki> | |||
;--------------------------------------------------------------------------- | |||
; | |||
; Programmer : Larry Aamodt | |||
; : Modifications for propeller drive: Rob Frohne | |||
; | |||
; File name : shell_2148.s | |||
; Class : CPTR-215 | |||
; Language : ARM assembly | |||
; Assembler : Keil | |||
; Target MCU : NXP LPC-2148 on Embedded Artists board | |||
; Date Written: 11/30/09 | |||
; change history: 11/30/09 LDA Updated with hardware start-up | |||
; 12/03/09 LDA PWM register definitions added | |||
; Description : | |||
; | |||
; Inputs : | |||
; | |||
; Outputs : | |||
; | |||
; Special : | |||
; requirements | |||
; | |||
; | |||
; NOTES: | |||
; | |||
; | |||
; | |||
;--------------------------------------------------------------------------- | |||
; Put application program definitions (i.e. equates) here: | |||
; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs | |||
Mode_USR EQU 0x10 | |||
Mode_FIQ EQU 0x11 | |||
Mode_IRQ EQU 0x12 | |||
Mode_SVC EQU 0x13 | |||
Mode_ABT EQU 0x17 | |||
Mode_UND EQU 0x1B | |||
Mode_SYS EQU 0x1F | |||
I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled | |||
F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled | |||
; Memory addresses for standard GPIO definitions | |||
IO0PIN EQU 0xE0028000 | |||
IO0SET EQU 0xE0028004 | |||
IO0DIR EQU 0xE0028008 | |||
IO0CLR EQU 0xE002800C | |||
; Timer addresses | |||
T0_TCR_ADDR EQU 0xE0004004 | |||
T0_PR_ADDR EQU 0xE000400C | |||
T0_MCR_ADDR EQU 0xE0004014 | |||
T0_MR0_ADDR EQU 0xE0004018 | |||
; Memory addresses for Pulse Width Modulation (PWM) | |||
PWM_TCR EQU 0xE0014004 ; PWM_TCR Timer Control Register | |||
PWM_PR EQU 0xE001400C ; PWM_PR Prescaler Register | |||
PWM_MCR EQU 0xE0014014 ; PWM_MCR Match Control Register | |||
PWM_MR0 EQU 0xE0014018 ; PWM_MR0 Match Register 0 (sets pulse period) | |||
PWM_MR4 EQU 0xE0014040 ; PWM_MR4 Match Register 4 (sets pulse length) | |||
PWM_MR6 EQU 0xE0014048 ; PWM_MR6 Match Register 6 (sets pulse length) | |||
PWM_PCR EQU 0xE001404C ; PWM_CR Control Register | |||
PWM_LER EQU 0xE0014050 ; PWM_LER Latch Enable Register | |||
PINSEL0 EQU 0xE002C000 ; Pin connect block - port 0 | |||
PINSEL1 EQU 0xE002C004 ; Pin connect block - port 1 | |||
; Stack size definitions | |||
UND_Stack_Size EQU 0x00000000 | |||
SVC_Stack_Size EQU 0x00000008 | |||
ABT_Stack_Size EQU 0x00000000 | |||
FIQ_Stack_Size EQU 0x00000000 | |||
IRQ_Stack_Size EQU 0x00000080 | |||
USR_Stack_Size EQU 0x00000400 | |||
ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \ | |||
FIQ_Stack_Size + IRQ_Stack_Size) | |||
AREA STACK, NOINIT, READWRITE, ALIGN=3 | |||
Stack_Mem SPACE USR_Stack_Size | |||
__initial_sp SPACE ISR_Stack_Size | |||
Stack_Top | |||
; Area Definition and Entry Point | |||
; Startup Code must be linked first at Address at which it expects to run. | |||
AREA RESET, CODE, READONLY | |||
ARM | |||
; Exception Vectors | |||
; Mapped to Address 0. | |||
; Absolute addressing mode must be used. | |||
; Dummy Handlers are implemented as infinite loops which can be modified. | |||
Vectors LDR PC, Reset_Addr | |||
LDR PC, Undef_Addr | |||
LDR PC, SWI_Addr | |||
LDR PC, PAbt_Addr | |||
LDR PC, DAbt_Addr | |||
NOP ; Reserved Vector | |||
; LDR PC, IRQ_Addr | |||
LDR PC, [PC, #-0x0FF0] ; Vector from VicVectAddr | |||
LDR PC, FIQ_Addr | |||
Reset_Addr DCD Reset_Handler | |||
Undef_Addr DCD Undef_Handler | |||
SWI_Addr DCD SWI_Handler | |||
PAbt_Addr DCD PAbt_Handler | |||
DAbt_Addr DCD DAbt_Handler | |||
DCD 0 ; Reserved Address | |||
IRQ_Addr DCD IRQ_Handler | |||
FIQ_Addr DCD FIQ_Handler | |||
Undef_Handler B Undef_Handler | |||
SWI_Handler B SWI_Handler | |||
PAbt_Handler B PAbt_Handler | |||
DAbt_Handler B DAbt_Handler | |||
IRQ_Handler B IRQ_Handler | |||
FIQ_Handler B FIQ_Handler | |||
; Reset Handler | |||
EXPORT Reset_Handler | |||
Reset_Handler | |||
; Setup Stack for each mode | |||
LDR R0, =Stack_Top | |||
; Enter Undefined Instruction Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #UND_Stack_Size | |||
; Enter Abort Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #ABT_Stack_Size | |||
; Enter FIQ Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #FIQ_Stack_Size | |||
; Enter IRQ Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #IRQ_Stack_Size | |||
; Enter Supervisor Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #SVC_Stack_Size | |||
; Enter User Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_USR | |||
MOV SP, R0 | |||
SUB SL, SP, #USR_Stack_Size | |||
; User program code goes here | |||
quarter_period EQU 250000 ; uS | |||
main | |||
BL init_propeller | |||
mov r1, #1 ; for handy access | |||
mov r2, #0 ; for handy access | |||
mov r0, r1, LSL #12 ; turn one on | |||
mov r4, r2, LSL #21 ; two still off | |||
orr r0, r4, r0 ; both on | |||
ldr r3,=IO0PIN | |||
str r0,[r3] | |||
ldr r0,=quarter_period | |||
bl delay | |||
mov r0, r1, LSL #12 | |||
mov r4, r1, LSL #21 | |||
orr r0, r4, r0 ; both on | |||
ldr r3,=IO0PIN | |||
str r0,[r3] | |||
ldr r0,=quarter_period | |||
bl delay | |||
mov r0, r2, LSL #12 ; turn one off | |||
mov r4, r1, LSL #21 ; two still on | |||
orr r0, r4, r0 ; both on | |||
ldr r3,=IO0PIN | |||
str r0,[r3] | |||
ldr r0,=quarter_period | |||
bl delay | |||
mov r0, r2, LSL #12 ; turn one off | |||
mov r4, r2, LSL #21 ; turn two off | |||
orr r0, r4, r0 ; both on | |||
ldr r3,=IO0PIN | |||
str r0,[r3] | |||
ldr r0,=quarter_period | |||
bl delay | |||
b main | |||
; ----------------------------------------------------------------------------- | |||
; Procedure init_propeller Must be called before to initialize the propeller. | |||
; Set up the counter T0 and GPIO P0.12 and P0.21 for output. | |||
; No parameters required | |||
; ----------------------------------------------------------------------------- | |||
init_propeller STMFD SP!,{LR,r0,r1,r2,r3,r4} | |||
LDR r1,=T0_PR_ADDR ; Prescale register | |||
MOV r2,#2 ; prescale count value | |||
STR r2,[r1] ; Prescaler will divide by 3 (1 uS period) | |||
LDR r1,=T0_MCR_ADDR ; Match control register | |||
MOV r2,#0x4 ; bit 2 = one: Stop on MR0: the TC and PC | |||
; will be stopped and TCR[0] will be set to 0 if | |||
; MR0 matches the TC | |||
STR r2,[r1] ; stop counter when match reached | |||
LDR r0,=IO0DIR | |||
LDR r4,[r0] ; read current Port 0 direction bits | |||
LDR r3,=2101248 ; one's for pins to be set for output (2^12+2^21 = 2101248) | |||
; 2134016 = 2^12+2^21+2^15 (for debugging LED on P0.15 | |||
ORR r4,r4,r3 | |||
STR r4,[r0] ; set propeller port bits to output without changing others. | |||
LDR r0,=PINSEL0 | |||
LDR r4,[r0] ; read current Port 0 direction bits | |||
LDR r3,=50331648 ; zero's for pins to be set for output (2^24+2^25 = 50331648) | |||
BIC r4,r4,r3 ; | |||
STR r4,[r0] ; set propeller port P0.12 to GPIO without changing others. | |||
LDR r0,=PINSEL1 | |||
LDR r4,[r0] ; read current Port 0 direction bits | |||
LDR r3,=3072 ; zero's for pins to be set for output (2^10+2^11 = 3072) | |||
BIC r4,r4,r3 ; | |||
STR r4,[r0] ; set propeller port P0.21 to GPIO without changing others. | |||
end_init_propeller LDMFD SP!,{PC,r0,r1,r2,r3,r4} | |||
; ----------------------------------------------------------------------------- | |||
; Procedure delay microsecond delay using timer 0 | |||
; (12Mhz clock & VPB divide by 4 assumed) | |||
; reg R0 must contain a delay value in uS | |||
; Not interruptable (r14 not saved) | |||
; assumes lcdReset has been called prior to delay | |||
; r0, r1 not preserved | |||
; ----------------------------------------------------------------------------- | |||
delay STMFD SP!,{LR,r0,r1} | |||
LDR r1,=T0_MR0_ADDR ; Match register zero | |||
STR r0,[r1] ; load match count per R0 | |||
; ldr r0,=0x8000 | |||
; str r0,[r5] ; turn on p0.15 led | |||
LDR r1,=T0_TCR_ADDR ; Timer 0 Control Register | |||
MOV r0,#2 ; bit 1 = one | |||
STR r0,[r1] ; Clear counter & prescaler | |||
MOV r0,#0 | |||
STR r0,[r1] | |||
MOV r0,#1 ; bit 0 = one | |||
STR r0,[r1] ; Turn on counter | |||
dloop LDR r0,[r1] ; Read TCR register | |||
ANDS r0,r0,#1 | |||
BNE dloop | |||
; ldr r0,=0x8000 | |||
; str r0,[r6] ; turn off p0.15 led | |||
end_delay LDMFD SP!,{PC,r0,r1} ; Return | |||
END | |||
</nowiki> | |||
* Propeller Drive Using Interrupts (not polled) | |||
<nowiki> | |||
;--------------------------------------------------------------------------- | |||
; | |||
; Shell Programmer : Larry Aamodt, main: Rob Frohne | |||
; | |||
; | |||
; File name : shell_2148.s | |||
; Class : CPTR-215 | |||
; Language : ARM assembly | |||
; Assembler : Keil | |||
; Target MCU : NXP LPC-2148 on Embedded Artists board | |||
; Date Written: 11/30/09 | |||
; change history: 11/30/09 LDA Updated with hardware start-up | |||
; 12/03/09 LDA PWM register definitions added | |||
; Description : | |||
; | |||
; Inputs : | |||
; | |||
; Outputs : | |||
; | |||
; Special : | |||
; requirements | |||
; | |||
; | |||
; NOTES: | |||
; | |||
; | |||
; | |||
;--------------------------------------------------------------------------- | |||
; Put application program definitions (i.e. equates) here: | |||
; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs | |||
Mode_USR EQU 0x10 | |||
Mode_FIQ EQU 0x11 | |||
Mode_IRQ EQU 0x12 | |||
Mode_SVC EQU 0x13 | |||
Mode_ABT EQU 0x17 | |||
Mode_UND EQU 0x1B | |||
Mode_SYS EQU 0x1F | |||
I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled | |||
F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled | |||
; Memory addresses for standard GPIO definitions | |||
IO0PIN EQU 0xE0028000 | |||
IO0SET EQU 0xE0028004 | |||
IO0DIR EQU 0xE0028008 | |||
IO0CLR EQU 0xE002800C | |||
; Vector Interrupt Controller Addresses | |||
VICIntSelect EQU 0xFFFFF00C | |||
VICVectAddr4 EQU 0xFFFFF110 | |||
VICVectCntl4 EQU 0xFFFFF210 | |||
VICIntEnable EQU 0xFFFFF010 | |||
VICVectAddr EQU 0xFFFFF030 | |||
; Timer addresses | |||
T0PC EQU 0xE0004010 ; Timer 0 Prescale counter | |||
T0IR EQU 0xE0004000 ; Timer 0 Interrupt Register | |||
T0_TCR_ADDR EQU 0xE0004004 | |||
T0_PR_ADDR EQU 0xE000400C | |||
T0_MCR_ADDR EQU 0xE0004014 | |||
T0_MR0_ADDR EQU 0xE0004018 | |||
; Memory addresses for Pulse Width Modulation (PWM) | |||
PWM_TCR EQU 0xE0014004 ; PWM_TCR Timer Control Register | |||
PWM_PR EQU 0xE001400C ; PWM_PR Prescaler Register | |||
PWM_MCR EQU 0xE0014014 ; PWM_MCR Match Control Register | |||
PWM_MR0 EQU 0xE0014018 ; PWM_MR0 Match Register 0 (sets pulse period) | |||
PWM_MR4 EQU 0xE0014040 ; PWM_MR4 Match Register 4 (sets pulse length) | |||
PWM_MR6 EQU 0xE0014048 ; PWM_MR6 Match Register 6 (sets pulse length) | |||
PWM_PCR EQU 0xE001404C ; PWM_CR Control Register | |||
PWM_LER EQU 0xE0014050 ; PWM_LER Latch Enable Register | |||
PINSEL0 EQU 0xE002C000 ; Pin connect block - port 0 | |||
PINSEL1 EQU 0xE002C004 ; Pin connect block - port 1 | |||
; Stack size definitions | |||
UND_Stack_Size EQU 0x00000000 | |||
SVC_Stack_Size EQU 0x00000008 | |||
ABT_Stack_Size EQU 0x00000000 | |||
FIQ_Stack_Size EQU 0x00000000 | |||
IRQ_Stack_Size EQU 0x00000080 | |||
USR_Stack_Size EQU 0x00000400 | |||
ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \ | |||
FIQ_Stack_Size + IRQ_Stack_Size) | |||
AREA STACK, NOINIT, READWRITE, ALIGN=3 | |||
Stack_Mem SPACE USR_Stack_Size | |||
__initial_sp SPACE ISR_Stack_Size | |||
Stack_Top | |||
; Area Definition and Entry Point | |||
; Startup Code must be linked first at Address at which it expects to run. | |||
AREA RESET, CODE, READONLY | |||
ARM | |||
; Exception Vectors | |||
; Mapped to Address 0. | |||
; Absolute addressing mode must be used. | |||
; Dummy Handlers are implemented as infinite loops which can be modified. | |||
Vectors LDR PC, Reset_Addr | |||
LDR PC, Undef_Addr | |||
LDR PC, SWI_Addr | |||
LDR PC, PAbt_Addr | |||
LDR PC, DAbt_Addr | |||
NOP ; Reserved Vector | |||
; LDR PC, IRQ_Addr | |||
LDR PC, [PC, #-0x0FF0] ; Vector from VicVectAddr | |||
LDR PC, FIQ_Addr | |||
Reset_Addr DCD Reset_Handler | |||
Undef_Addr DCD Undef_Handler | |||
SWI_Addr DCD SWI_Handler | |||
PAbt_Addr DCD PAbt_Handler | |||
DAbt_Addr DCD DAbt_Handler | |||
DCD 0 ; Reserved Address | |||
IRQ_Addr DCD IRQ_Handler | |||
FIQ_Addr DCD FIQ_Handler | |||
; Exception Handlers | |||
Undef_Handler B Undef_Handler | |||
SWI_Handler B SWI_Handler | |||
PAbt_Handler B PAbt_Handler | |||
DAbt_Handler B DAbt_Handler | |||
IRQ_Handler B IRQ_Handler | |||
FIQ_Handler B FIQ_Handler | |||
; Reset Handler | |||
EXPORT Reset_Handler | |||
Reset_Handler | |||
; Setup Stack for each mode | |||
LDR R0, =Stack_Top | |||
; Enter Undefined Instruction Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #UND_Stack_Size | |||
; Enter Abort Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #ABT_Stack_Size | |||
; Enter FIQ Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #FIQ_Stack_Size | |||
; Enter IRQ Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #IRQ_Stack_Size | |||
; Enter Supervisor Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit | |||
MOV SP, R0 | |||
SUB R0, R0, #SVC_Stack_Size | |||
; Enter User Mode and set its Stack Pointer | |||
MSR CPSR_c, #Mode_USR | |||
MOV SP, R0 | |||
SUB SL, SP, #USR_Stack_Size | |||
step_time_uS EQU 250000 ; uS between steps of the propeller motor. | |||
main BL init_propeller ; Initialize GPIO and IRQ, and Timer 0. | |||
LDR r0,=step1 | |||
LDR r1,=NextRoutine_Address | |||
STR r0,[r1] | |||
bl delay ; start the whole automated thing | |||
do_nothing b do_nothing ; because the ISR will do it all! | |||
; ----------------------------------------------------------------------------- | |||
; Step the motor routines. These are called by the Timer0 ISR (timer0ISR) | |||
; ----------------------------------------------------------------------------- | |||
step1 STMFD SP!,{LR,r0-r12} | |||
mov r1, #1 ; for handy access | |||
mov r2, #0 ; for handy access | |||
mov r0, r1, LSL #12 ; turn one on | |||
mov r4, r2, LSL #21 ; two still off | |||
orr r0, r4, r0 ; both on | |||
ldr r3,=IO0PIN | |||
str r0,[r3] | |||
LDR r0,=step2 | |||
LDR r1,=NextRoutine_Address | |||
STR r0,[r1] | |||
bl delay | |||
LDMFD SP!,{PC,r0-r12} | |||
step2 STMFD SP!,{LR,r0-r12} | |||
mov r1, #1 ; for handy access | |||
mov r2, #0 ; for handy access | |||
mov r0, r1, LSL #12 | |||
mov r4, r1, LSL #21 | |||
orr r0, r4, r0 ; both on | |||
ldr r3,=IO0PIN | |||
str r0,[r3] | |||
LDR r0,=step3 | |||
LDR r1,=NextRoutine_Address | |||
STR r0,[r1] | |||
bl delay | |||
LDMFD SP!,{PC,r0-r12} | |||
step3 STMFD SP!,{LR,r0-r12} | |||
mov r1, #1 ; for handy access | |||
mov r2, #0 ; for handy access | |||
mov r0, r2, LSL #12 ; turn one off | |||
mov r4, r1, LSL #21 ; two still on | |||
orr r0, r4, r0 ; both on | |||
ldr r3,=IO0PIN | |||
str r0,[r3] | |||
LDR r0,=step4 | |||
LDR r1,=NextRoutine_Address | |||
STR r0,[r1] | |||
bl delay | |||
LDMFD SP!,{PC,r0-r12} | |||
step4 STMFD SP!,{LR,r0-r12} | |||
mov r1, #1 ; for handy access | |||
mov r2, #0 ; for handy access | |||
mov r0, r2, LSL #12 ; turn one off | |||
mov r4, r2, LSL #21 ; turn two off | |||
orr r0, r4, r0 ; both on | |||
ldr r3,=IO0PIN | |||
str r0,[r3] | |||
LDR r0,=step1 | |||
LDR r1,=NextRoutine_Address | |||
STR r0,[r1] | |||
bl delay | |||
LDMFD SP!,{PC,r0-r12} | |||
; ----------------------------------------------------------------------------- | |||
; Procedure init_propeller Must be called before to initialize the propeller. | |||
; Set up GPIO P0.12 and P0.21 for output. | |||
; Set up timer 0 and interrupts for IRQ (low priority) | |||
; No parameters required | |||
; ----------------------------------------------------------------------------- | |||
init_propeller STMFD SP!,{LR,r0,r1,r2,r3,r4} | |||
LDR r1,=T0_PR_ADDR ; Prescale register | |||
MOV r2,#2 ; prescale count value | |||
STR r2,[r1] ; Prescaler will divide by 3 (1 uS period | |||
; T0MCR = 0x00000003; //reset counter and generate IRQ on MR0 match | |||
LDR r1,=T0_MCR_ADDR ; Match control register | |||
MOV r2,#0x3 ; bit 2 = one: Stop on MR0: the TC and PC : bit 1 = 1 gives interrupt | |||
; will be stopped and TCR[0] will be set to 0 if | |||
; MR0 matches the TC | |||
STR r2,[r1] ; stop counter when match reached | |||
; VICIntSelect &= ~0x10; //Timer0 interrupt is assigned to IRQ (not FIQ) | |||
LDR r1,=VICIntSelect | |||
MOV r0,#~0x10 | |||
STR r0,[r1] | |||
; VICVectAddr4 = (tU32)timer0ISR; //register ISR address | |||
LDR r1,=VICVectAddr4 | |||
LDR r0,=timer0ISR | |||
STR r0,[r1] | |||
; VICVectCntl4 = 0x24; //enable vector interrupt for timer0 | |||
LDR r1,=VICVectCntl4 | |||
MOV r0,#0x24 | |||
STR r0,[r1] | |||
; VICIntEnable = 0x10; //enable timer0 interrupt | |||
LDR r1,=VICIntEnable | |||
MOV r0,#0x10 | |||
STR r0,[r1] | |||
LDR r0,=IO0DIR | |||
LDR r4,[r0] ; read current Port 0 direction bits | |||
LDR r3,=2101248 ; one's for pins to be set for output (2^12+2^21 = 2101248) | |||
; 2134016 = 2^12+2^21+2^15 (for debugging LED on P0.15 | |||
ORR r4,r4,r3 | |||
STR r4,[r0] ; set propeller port bits to output without changing others | |||
LDR r0,=PINSEL0 | |||
LDR r4,[r0] ; read current Port 0 direction bits | |||
LDR r3,=50331648 ; zero's for pins to be set for output (2^24+2^25 = 50331648) | |||
BIC r4,r4,r3 ; | |||
STR r4,[r0] ; set propeller port P0.12 to GPIO without changing others. | |||
LDR r0,=PINSEL1 | |||
LDR r4,[r0] ; read current Port 0 direction bits | |||
LDR r3,=3072 ; zero's for pins to be set for output (2^10+2^11 = 3072) | |||
BIC r4,r4,r3 ; | |||
STR r4,[r0] ; set propeller port P0.21 to GPIO without changing others. | |||
end_init_propeller LDMFD SP!,{PC,r0,r1,r2,r3,r4} | |||
; ----------------------------------------------------------------------------- | |||
; Timer 0 Interrupt Service Routine timer0ISR | |||
; Some comments are C equivalents. | |||
; ----------------------------------------------------------------------------- | |||
timer0ISR SUB LR,LR,#4 ; Update the LR | |||
STMFD SP!, {r0-r12,LR} ; Store registers (including LR) | |||
; T0IR = 0xff; //reset all IRQ flags | |||
LDR r1,=T0IR | |||
MOV r0,#~0xff | |||
STR r0,[r1] | |||
; VICVectAddr = 0x00; //dummy write to VIC to signal end of interrupt | |||
LDR r1,=VICVectAddr | |||
MOV r0,#~0x00 | |||
STR r0,[r1] | |||
; Here we will branch to the appropriate next step routine. | |||
LDR r0,=NextRoutine_Address | |||
push {r14} ; save LR for this return. | |||
ldr r14,=end_timer0ISR ; load the LR because we are using an LDR PC below. | |||
ldr PC,[r0] ; branch to the subroutine pointed to by NextRoutine_Address | |||
end_timer0ISR pop {r14} ; restore the LR for this return. | |||
LDMFD SP!, {r0-r12,PC}^ ; Return from ISR | |||
; ----------------------------------------------------------------------------- | |||
; Procedure delay microsecond delay using timer 0 | |||
; (12Mhz clock & VPB divide by 4 assumed) | |||
; Delay is set by step_time_uS | |||
; ----------------------------------------------------------------------------- | |||
delay STMFD SP!,{LR,r0,r1} | |||
; T0PC = 0x00000000; Didn't do this yet. Unnecessary? //no prescale of clock | |||
; LDR r1,=T0PC | |||
; MOV r0,#0x00000000 | |||
; STR r0,[r1] | |||
; T0IR = 0x000000ff; //reset all flags before enable IRQs | |||
LDR r1,=T0IR | |||
MOV r0,#0x000000ff | |||
STR r0,[r1] | |||
; T0MR0 = delayInMs * //calculate no of timer ticks | |||
; ((CRYSTAL_FREQUENCY * PLL_FACTOR) / (1000 * VPBDIV_FACTOR)); | |||
LDR r1,=T0_MR0_ADDR ; Match register zero | |||
LDR r0,=step_time_uS | |||
STR r0,[r1] ; load match count from step_time_uS | |||
; T0TCR = 0x00000002; //disable and reset Timer0 | |||
LDR r1,=T0_TCR_ADDR ; Timer 0 Control Register | |||
MOV r0,#2 ; bit 1 = one | |||
; T0TCR = 0x00000001; //start Timer0 | |||
STR r0,[r1] ; Clear counter & prescaler | |||
MOV r0,#0 | |||
STR r0,[r1] | |||
MOV r0,#1 ; bit 0 = one | |||
STR r0,[r1] ; Turn on counter | |||
end_delay LDMFD SP!,{PC,r0,r1} ; Return | |||
AREA Thedata, DATA, READWRITE | |||
ALIGN | |||
NextRoutine_Address SPACE 4 ; This holds the address of the next step subroutine. | |||
END | |||
</nowiki> | |||
Latest revision as of 11:58, 7 November 2014
- Factorial
; Factorial Calculation ; The answer is in R10 ; Rob Frohne 2013 GLOBAL Reset_Handler AREA Factorial, CODE, READONLY ENTRY Reset_Handler movs r8, #0 ; Take the factorial of this number, n. mov r10, #1 ; 0! and 1! are 1 beq stop ; If r8 is zero we are done cmp r8, #1 ; If r8 is 1, beq stop ; we are done subs r9, r8, #1 ; n-1 loop mulne r10, r9, r8 ; n(n-1) mov r8, r10 subs r9, r9, #1 bne loop stop b stop END
- Factorial 2014
_ AREA Add, CODE ENTRY ; This program takes the factorial of n (in r2) n EQU 0 ldr r2,=n ; Load r2 with the number to take the factorial of. cmp r2,#0 ; Is n=0 bne check_for_1 mov r4,#1 b stop check_for_1 cmp r2,#1 bne initialize_r4 mov r4,#1 b stop initialize_r4 mov r4,r2 sub r3,r4,#1 loop mul r5,r4,r3 mov r4,r5 subs r3,r3,#1 bne loop stop b stop END
- 64 Bit Add
VAL1A EQU 0xffffffff VAL1B EQU 0x0000000f VAL2A EQU 0x00000001 VAL2B EQU 0x00000001 AREA LongAdd, CODE ENTRY ldr R0, = VAL1A ldr R1, = VAL1B ldr R2, = VAL2A ldr R3, = VAL2B adds R8,R0,R1 adcs R9,R1,R3 stop b stop END
- Copy to RAM
AREA Exaddress, CODE, READONLY EXPORT Reset_Handler Reset_Handler LDR R9, =list mov R7, #4 ; number in list ldr r6, =datastart loop ldr r8,[r9],#4 str r8,[r6],#4 subs r7,r7,#1 bne loop stop b stop ALIGN list DCW 0x1111, 0x2222, 0x3333, 0x4444, 0x5555 ALIGN string DCB "This is a test.",0 ; This string is not used in the copy to ram program string2 DCB 'T','h','i' ; This string2 is not used in the copy to ram program ALIGN AREA Thedata, DATA, NOINIT, READWRITE datastart SPACE 20 END
- Subroutine Example1
; First Subroutine Example
; This program demonstrates using a subroutine,
; saving registers on the stack, etc.
; Rob Frohne, 11/3/2013
stack_start EQU 0x40001000
AREA Subroutine_Example, CODE
ENTRY
Start
ldr sp, =stack_start ; Tell where we will place the stack.
; (It goes down (lower addresses from here.)
mov r1, #1 ; Store some numebers in some registers
mov r2, #2
mov r3, #3
bl subroutine
stop b stop
; This subroutine saves the registers,
; messes up the registers locally,
; then restores the registers and returns.
subroutine
stmfd sp!, {r1-r2,lr} ; save used registers and the link register (r14)
mov r1,#0xffffffff ; mess up the registers
mov r2, r1
ldmfd sp!, {r1,r2,pc} ; pop the stack and return
END
- Minimum of a Signed Number
; This program finds the minimum of a list of constant words in signed format ; The result is in r3 at the end of the routine. ; Rob Frohne 10/30/2013 AREA Program, CODE, READONLY ENTRY ldr r0,=end ; load the end address of the code & initialize it as the pointer. ldr r2,=begin ; load the beginning address of the code. mov r3,#0x7fffffff ; Initialize r3 as the most positive number. loop ldr r6,[r2],#4 ; load the next data into r6 and post increment r2 for the next data. cmp r6,r3 ; Find out if r6 > r3. result from r6-r3 like subs r7,r6,r3 without r6 necessary. bgt no_update ; If it is no update. mov r3,r6 ; update if r6 is lower than r3. no_update cmp r0,r2 ; are we at the end yet bne loop ; if r7 != 0 then keep looping stop b stop ALIGN begin DCD 0x8fffffff, 0x55555555, 0x44444444, 0x77777777, 0xffffffff end END
- Compare Two Null Terminated Strings
; Subroutine to compare two null terminated ASCII strings.
; The address where the two strings start are in r0 and r1
; The return is in r0, 1 for match and 0 for don't match.
; If they don't match, r1 gives the number of the first
; character that didn't match, starting with 0.
; r2 and r3 are not protected.
; Rob Frohne 11/6/2013
stack_start EQU 0x40001000
AREA String_Compare, CODE
ENTRY
Start
ldr sp, =stack_start ; Tell where we will place the stack.
; (It goes down (lower addresses from here.)
ldr r0, =string1
ldr r1, =string2
bl compare_strings
stop b stop
compare_strings
stmfd sp!, {r2,r4,r5,lr} ; save used registers and the link register (r14)
mov r2, #0 ; Initialize the counter for the first position.
loop
ldrb r4,[r0],#1
ldrb r5,[r1],#1
cmp r5,r4
bne do_not_match
cmp r4, #0 ; check for end of string.
beq match
add r2, #1
b loop
do_not_match
mov r0, #0 ; don't match
b finish
match
mov r0, #1
finish
mov r1,r2 ; Move the count into the result register.
ldmfd sp!, {r2,r4,r5,pc} ; pop the stack and return
string1
DCB "This is the first string.",00 ; For testing purposes.
ALIGN
string2
DCB "This is the first string.",00
ALIGN
END
- BCD Add
; Subroutine to add two BCD numbers in 32 bit form with each nibble
; representing a digit.
; locals: r8 for digit counter, single digit mask 0xf, r5 & r6 for masked addends,
; working BCD_carry, r7
; working result in r4
; the summed digits go in r3
; inputs: r0+r1
; outputs: r0 result and r1 carry
; only r4-r8 are saved.
; Rob Frohne 11/12/13
stack_start EQU 0x40001000
AREA ADD_BCD, CODE
ENTRY
Start
ldr sp, =stack_start ; Tell where we will place the stack.
; (It goes down (lower addresses from here.)
ldr r0, =0x12345678 ; The two numbers to add.
ldr r1, =0x87654321
bl bcd_add
stop b stop
bcd_add ; The subroutine
stmfd sp!, {r4-r8,lr}
mov r8, #8 ; Set the counter to move through the eight digits
mov r7, #0 ; Set the carry to zero to start with
mov r3, #0 ; This is where the resulting digits of the sum are stored.
loop
and r5, r0, #0xf ; mask for the rightmost digit.
and r6, r1, #0xf
add r4, r5, r7 ; add carry
add r4, r4, r6 ; r4=r5+r6
subs r4, r4, #10 ; Subtract 10 (base 10) to see if there is a carry.
bpl carry
mov r7, #0 ; set carry to zero
add r4, r4, #10 ; Add the 10 back in as there was no carry needed.
b roll_to_next_digit
carry
mov r7, #1 ; set the carry
roll_to_next_digit
orr r3, r3, r4 ; Add these digits into the sum.
ror r0, #4
ror r1, #4
ror r3, #4
subs r8, r8, #1 ; Decrement the digit counter
bne loop ; If it isn't zero do the next digit.
mov r0, r3 ; Set the output registers. r0 is result. r1 is carry.
mov r1, r7
ldmfd sp!, {r4-r8,pc}
END
- Bubble Sort
; This is a program to bubble sort a list.
; Rob Frohne and the CPTR 215 class
stack_start EQU 0x40001000
length EQU (end_of_list - begin)
end_ram EQU (datastart + length)
; EQU statements must be at the beginning of the program.
AREA Subroutine_Example, CODE
ENTRY
; Copy list to RAM
ldr sp, =stack_start
LDR R9, =begin
ldr R7, =end_of_list
ldr r6, =datastart
loop
ldr r8,[r9],#4
str r8,[r6],#4
cmp r9,r7
bne loop
; End copy to RAM
start_sort
ldr r5,=(end_ram - 4)
loop_sort_outer ; r2 is our counter, it goes from 1 to item_count
mov r1, #1 ; has_changed = false (0 is true)
ldr r2,=datastart ; start of data in ram goes into r2
loop_sort_inner ;
ldr r3,[r2],#4
ldr r4,[r2],#0
cmp r3,r4
blhi subroutine_swap ; swaps the last two and sets has_changed
cmp r2,r5
bne loop_sort_inner
sub r5,r5,#4 ; the last item is in order, so we don't need to check it again.
cmp r1,#1
bne loop_sort_outer
stop b stop
subroutine_swap ; swaps the contents of the addresses held in
; r2 and r2 -4 (the previous address)
; has_changed is r1 and it sets it to 0 (true)
stmfd sp!, {r0,r2-r4,lr}
mov r1,#0 ; setting the has_changed to true.
ldr r0,[r2],#-4 ; swapping data
ldr r3,[r2]
str r0,[r2],#4
str r3,[r2]
ldmfd sp!, {r0,r2-r4,pc}
ALIGN
begin
DCD 0x8fffffff, 0x55555555, 0x44444444, 0x77777777, 0xffffffff
end_of_list
AREA Thedata, DATA, NOINIT, READWRITE
datastart SPACE 20
END
- GPIO Example
;---------------------------------------------------------------------------
;
; Programmer : Larry Aamodt
;
; File name : shell_2148.s
; Class : CPTR-215
; Language : ARM assembly
; Assembler : Keil
; Target MCU : NXP LPC-2148 on Embedded Artists board
; Date Written: 11/30/09
; change history: 11/30/09 LDA Updated with hardware start-up
; 12/03/09 LDA PWM register definitions added
; Description :
;
; Inputs :
;
; Outputs :
;
; Special :
; requirements
;
;
; NOTES:
;
;
;
;---------------------------------------------------------------------------
; Put application program definitions (i.e. equates) here:
; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
Mode_USR EQU 0x10
Mode_FIQ EQU 0x11
Mode_IRQ EQU 0x12
Mode_SVC EQU 0x13
Mode_ABT EQU 0x17
Mode_UND EQU 0x1B
Mode_SYS EQU 0x1F
I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled
F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled
; Memory addresses for standard GPIO definitions
IO0PIN EQU 0xE0028000
IO0SET EQU 0xE0028004
IO0DIR EQU 0xE0028008
IO0CLR EQU 0xE002800C
; Memory addresses for Pulse Width Modulation (PWM)
PWM_TCR EQU 0xE0014004 ; PWM_TCR Timer Control Register
PWM_PR EQU 0xE001400C ; PWM_PR Prescaler Register
PWM_MCR EQU 0xE0014014 ; PWM_MCR Match Control Register
PWM_MR0 EQU 0xE0014018 ; PWM_MR0 Match Register 0 (sets pulse period)
PWM_MR4 EQU 0xE0014040 ; PWM_MR4 Match Register 4 (sets pulse length)
PWM_MR6 EQU 0xE0014048 ; PWM_MR6 Match Register 6 (sets pulse length)
PWM_PCR EQU 0xE001404C ; PWM_CR Control Register
PWM_LER EQU 0xE0014050 ; PWM_LER Latch Enable Register
PINSEL0 EQU 0xE002C000 ; Pin connect block - port 0
PINSEL1 EQU 0xE002C004 ; Pin connect block - port 1
; Stack size definitions
UND_Stack_Size EQU 0x00000000
SVC_Stack_Size EQU 0x00000008
ABT_Stack_Size EQU 0x00000000
FIQ_Stack_Size EQU 0x00000000
IRQ_Stack_Size EQU 0x00000080
USR_Stack_Size EQU 0x00000400
ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
FIQ_Stack_Size + IRQ_Stack_Size)
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE USR_Stack_Size
__initial_sp SPACE ISR_Stack_Size
Stack_Top
; Area Definition and Entry Point
; Startup Code must be linked first at Address at which it expects to run.
AREA RESET, CODE, READONLY
ARM
; Exception Vectors
; Mapped to Address 0.
; Absolute addressing mode must be used.
; Dummy Handlers are implemented as infinite loops which can be modified.
Vectors LDR PC, Reset_Addr
LDR PC, Undef_Addr
LDR PC, SWI_Addr
LDR PC, PAbt_Addr
LDR PC, DAbt_Addr
NOP ; Reserved Vector
; LDR PC, IRQ_Addr
LDR PC, [PC, #-0x0FF0] ; Vector from VicVectAddr
LDR PC, FIQ_Addr
Reset_Addr DCD Reset_Handler
Undef_Addr DCD Undef_Handler
SWI_Addr DCD SWI_Handler
PAbt_Addr DCD PAbt_Handler
DAbt_Addr DCD DAbt_Handler
DCD 0 ; Reserved Address
IRQ_Addr DCD IRQ_Handler
FIQ_Addr DCD FIQ_Handler
Undef_Handler B Undef_Handler
SWI_Handler B SWI_Handler
PAbt_Handler B PAbt_Handler
DAbt_Handler B DAbt_Handler
IRQ_Handler B IRQ_Handler
FIQ_Handler B FIQ_Handler
; Reset Handler
EXPORT Reset_Handler
Reset_Handler
; Setup Stack for each mode
LDR R0, =Stack_Top
; Enter Undefined Instruction Mode and set its Stack Pointer
MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #UND_Stack_Size
; Enter Abort Mode and set its Stack Pointer
MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #ABT_Stack_Size
; Enter FIQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #FIQ_Stack_Size
; Enter IRQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #IRQ_Stack_Size
; Enter Supervisor Mode and set its Stack Pointer
MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #SVC_Stack_Size
; Enter User Mode and set its Stack Pointer
MSR CPSR_c, #Mode_USR
MOV SP, R0
SUB SL, SP, #USR_Stack_Size
; User program code goes here
main
ldr r1, =PINSEL0
mov r0, #0 ; set P0.0 to P0.15 as GPIO
str r0,[r1]
ldr r1, =IO0DIR ; Get ready to set direction of data
ldr r0, =0xffff ; output
str r0, [r1] ; set the direction
ldr r1, =IO0PIN ; load the address of the port0
mov r0, #0
next
str r0, [r1]
add r0, r0, #1
ldr r2, =0x200
delay
subs r2,r2,#1
bne delay
b next
AREA Thedata, DATA, READWRITE
ALIGN
datastart EQU 0x40000004
SPACE 20
;FILL 20, 0xff ; Why is this stored at 0x50 instead of 0x58?
; Or maybe a better question: How do I set data at
; a specific memory location?
END
- LCD Example
;---------------------------------------------------------------------------
;
; Programmer : Larry Aamodt
;
; File name : shell_2148.s
; Class : CPTR-215
; Language : ARM assembly
; Assembler : Keil
; Target MCU : NXP LPC-2148 on Embedded Artists board
; Date Written: 11/30/09
; change history: 11/30/09 LDA Updated with hardware start-up
; 12/03/09 LDA PWM register definitions added
; Description :
;
; Inputs :
;
; Outputs :
;
; Special :
; requirements
;
;
; NOTES:
;
;
;
;---------------------------------------------------------------------------
; Put application program definitions (i.e. equates) here:
; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
Mode_USR EQU 0x10
Mode_FIQ EQU 0x11
Mode_IRQ EQU 0x12
Mode_SVC EQU 0x13
Mode_ABT EQU 0x17
Mode_UND EQU 0x1B
Mode_SYS EQU 0x1F
I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled
F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled
; Memory addresses for standard GPIO definitions
IO0PIN EQU 0xE0028000
IO0SET EQU 0xE0028004
IO0DIR EQU 0xE0028008
IO0CLR EQU 0xE002800C
; Memory addresses for Pulse Width Modulation (PWM)
PWM_TCR EQU 0xE0014004 ; PWM_TCR Timer Control Register
PWM_PR EQU 0xE001400C ; PWM_PR Prescaler Register
PWM_MCR EQU 0xE0014014 ; PWM_MCR Match Control Register
PWM_MR0 EQU 0xE0014018 ; PWM_MR0 Match Register 0 (sets pulse period)
PWM_MR4 EQU 0xE0014040 ; PWM_MR4 Match Register 4 (sets pulse length)
PWM_MR6 EQU 0xE0014048 ; PWM_MR6 Match Register 6 (sets pulse length)
PWM_PCR EQU 0xE001404C ; PWM_CR Control Register
PWM_LER EQU 0xE0014050 ; PWM_LER Latch Enable Register
PINSEL0 EQU 0xE002C000 ; Pin connect block - port 0
PINSEL1 EQU 0xE002C004 ; Pin connect block - port 1
; Stack size definitions
UND_Stack_Size EQU 0x00000000
SVC_Stack_Size EQU 0x00000008
ABT_Stack_Size EQU 0x00000000
FIQ_Stack_Size EQU 0x00000000
IRQ_Stack_Size EQU 0x00000080
USR_Stack_Size EQU 0x00000400
ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
FIQ_Stack_Size + IRQ_Stack_Size)
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE USR_Stack_Size
__initial_sp SPACE ISR_Stack_Size
Stack_Top
; Area Definition and Entry Point
; Startup Code must be linked first at Address at which it expects to run.
AREA RESET, CODE, READONLY
ARM
; Exception Vectors
; Mapped to Address 0.
; Absolute addressing mode must be used.
; Dummy Handlers are implemented as infinite loops which can be modified.
Vectors LDR PC, Reset_Addr
LDR PC, Undef_Addr
LDR PC, SWI_Addr
LDR PC, PAbt_Addr
LDR PC, DAbt_Addr
NOP ; Reserved Vector
; LDR PC, IRQ_Addr
LDR PC, [PC, #-0x0FF0] ; Vector from VicVectAddr
LDR PC, FIQ_Addr
Reset_Addr DCD Reset_Handler
Undef_Addr DCD Undef_Handler
SWI_Addr DCD SWI_Handler
PAbt_Addr DCD PAbt_Handler
DAbt_Addr DCD DAbt_Handler
DCD 0 ; Reserved Address
IRQ_Addr DCD IRQ_Handler
FIQ_Addr DCD FIQ_Handler
Undef_Handler B Undef_Handler
SWI_Handler B SWI_Handler
PAbt_Handler B PAbt_Handler
DAbt_Handler B DAbt_Handler
IRQ_Handler B IRQ_Handler
FIQ_Handler B FIQ_Handler
; Reset Handler
EXPORT Reset_Handler
Reset_Handler
; Setup Stack for each mode
LDR R0, =Stack_Top
; Enter Undefined Instruction Mode and set its Stack Pointer
MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #UND_Stack_Size
; Enter Abort Mode and set its Stack Pointer
MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #ABT_Stack_Size
; Enter FIQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #FIQ_Stack_Size
; Enter IRQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #IRQ_Stack_Size
; Enter Supervisor Mode and set its Stack Pointer
MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #SVC_Stack_Size
; Enter User Mode and set its Stack Pointer
MSR CPSR_c, #Mode_USR
MOV SP, R0
SUB SL, SP, #USR_Stack_Size
; User program code goes here
main
bl lcdReset ; set up the lcd
bl lcdClear
mov r0, #32
loop
bl lcdWRdata ; write to the LCD
add r0, r0, #1 ; increment the data
mov r9, r0
ldr r0, =1000000
bl delay
mov r0, r9
b loop
; User data area definition follows
AREA appdata, DATA, NOINIT, READWRITE
;-----------------------------------------------------------------------------
; Copyright (C) 2012 ....
;
; Programmer : Larry Aamodt
;
; File name : lcd_routines.asm
; Language : ARM assembly
; Assembler ; Keil
; Target MCU : NXP LPC2148 on Embedded Artists education board
; Date : 12/05/12 LDA lcd_routines.asm. debugged
;
; Description : LCD display routines
; Copy this code to your own program
;
; Procedures you can call are:
; lcdReset must be called first. no parameters.
; lcdClear use to clear the display & home the cursor
; no parameters are required.
; lcdWRdata use to write one character on the display
; place an ASCII char in r0 before calling.
; The cursor will advance.
; lcdCursorAt use to move the cursor. Two parameters
; r0 = row (1 or 2)
; r1 = column to move cursor to (0-15)
;
; Example use of the LCD routines:
; bl lcdReset ; do this once at the top of your program
;
; mov r0,#31h ; place the ascii code for number one in r0
; bl lcdWRdata ; display the character '1' on LCD display
;
; bl lcdClear ; clear the display
;
; mov r0,#1 ; select LCD row 1
; mov r1,#4 ; select LCD column 4
; bl lcdCursorAt ; move the cursor
;
;
; NOTE: All registers are saved by these routines, i.e. upon return
; from the subroutine all registers, except flags, have the
; same value in them as before the subroutine was called (this
; breaks with the ARM convention for subroutines but is done
; to make it easier for you).
;
;-----------------------------------------------------------------------------
AREA lcdroutines,CODE,READONLY
EXPORT lcdReset
EXPORT lcdClear
EXPORT lcdWRdata
EXPORT lcdCursorAt
EXPORT delay
; -----------------------------------------------------------------------------
; LCD Procedures follow.
;------------------------------------------------------------------------------
; ***** LCD equates ******
;IO0PIN EQU 0xE0028000
;IO0SET EQU 0xE0028004
;IO0DIR EQU 0xE0028008
;IO0CLR EQU 0xE002800C
IO1PIN EQU 0xE0028010
IO1SET EQU 0xE0028014
IO1DIR EQU 0xE0028018
IO1CLR EQU 0xE002801C
T0_TCR_ADDR EQU 0xE0004004
T0_PR_ADDR EQU 0xE000400C
T0_MCR_ADDR EQU 0xE0004014
T0_MR0_ADDR EQU 0xE0004018
; -----------------------------------------------------------------------------
; Procedure lcdReset Must be called before writing to the LCD
; No parameters required
; -----------------------------------------------------------------------------
lcdReset STMFD SP!,{LR,r0,r1,r2,r3,r4,r5,r6,r7,r8,r9}
LDR r1,=T0_PR_ADDR ; Prescale register
MOV r2,#2 ; prescale count value
STR r2,[r1] ; Prescaler will divide by 3
LDR r1,=T0_MCR_ADDR ; Match control register
MOV r2,#0x6 ; bit 2 = one
STR r2,[r1] ; stop counter when match reached
LDR r5,=IO0CLR
LDR r6,=IO0SET
LDR r7,=IO1CLR
LDR r8,=IO1SET
LDR r0,=35000
BL delay ; delay 35ms
LDR r0,=IO0DIR
LDR r4,[r0] ; read current Port 0 direction bits
LDR r3,=0x40408000 ; one's for pins to be set for output
ORR r4,r4,r3 ; bits 22 & 30 to be outputs
STR r4,[r0] ; set lcd port bits to output
LDR r3,=0x00400000 ;
STR r3,[r5] ; write 0 to LCD R/W signal
LDR r3,=0x40008000
STR r3,[r6] ; turn on backlight - write 1 to P0.30
LDR r0,=IO1DIR
LDR r4,[r0] ; read current Port 1 direction bits
LDR r3,=0x03FF0000 ; one's for lcd pins - set for output
ORR r4,r4,r3 ; bits 16 to 25 to be outputs
STR r4,[r0] ; set lcd port direction bits to output
STR r3,[r7] ; clear the LCD data & control bits
LDR r9,=0x02000000 ; bit pattern to turn on/off E
LDR r2,=0x00380000 ; function: 2 lines, 5x7 dots
STR r2,[r8] ; set lcd function bits
BL pulse_e
STR r3,[r7] ; clear lcd bits
MOV r0,#40
BL delay ; wait 40 microseconds
LDR r2,=0x000E0000 ; function: display on, cursor on
STR r2,[r8] ; set lcd function bits
BL pulse_e
STR r3,[r7] ; clear lcd bits
MOV r0,#40
BL delay ; wait 40 microseconds
LDR r2,=0x00010000 ; lcd function: clear display
STR r2,[r8] ; set lcd function bits
BL pulse_e
STR r3,[r7] ; clear lcd bits
MOV r0,#1600
BL delay ; delay for 1600 microseconds
LDR r2,=0x00030000 ; lcd function: set entry mode
STR r2,[r8] ; set lcd function bits
BL pulse_e
STR r3,[r7] ; clear lcd bits
end_lcdReset LDMFD SP!,{PC,r0,r1,r2,r3,r4,r5,r6,r7,r8,r9}
;------------------------------------------------------------------------------
; Procedure pulse_e uses r0. Not interuptable (r14 not saved)
; assumes r9 has 0x02000000 in it
; assumes r7 has IO1CLR address in it
; assumes r8 has IO1SET address in it
;------------------------------------------------------------------------------
pulse_e MOV r0,#4
STR r9,[r8] ; assert E
ploop1 SUBS r0,r0,#1 ; delay 600ns or so
BNE ploop1
STR r9,[r7] ; de-assert E
MOV r0,#8
ploop2 SUBS r0,r0,#1 ; delay 1100ns or so
BNE ploop2
end_pulse_e BX LR
; -----------------------------------------------------------------------------
; Procedure lcdClear Clears the LCD and positions cursor to line1, left col
; no parameters required
; -----------------------------------------------------------------------------
lcdClear STMFD SP!,{LR,r0,r1,r2,r3,r7,r8,r9}
LDR r9,=0x02000000 ; bit pattern to turn on/off E
LDR r3,=0x03FF0000 ; one's for pins used for lcd
LDR r7,=IO1CLR
LDR r8,=IO1SET
LDR r2,=0x00010000 ; lcd function: clear display
STR r2,[r8] ; set lcd function bits
BL pulse_e
STR r3,[r7] ; clear lcd bits
MOV r0,#1600
BL delay
end_lcdClear LDMFD SP!,{PC,r0,r1,r2,r3,r7,r8,r9}
; -----------------------------------------------------------------------------
; Procedure lcdCursorAt
; r0 assumed to contain the row# (1 or 2)
; r1 assumed to contain col#(0-15)
; No cursor movement if invalid row or col # is found
; -----------------------------------------------------------------------------
lcdCursorAt STMFD SP!,{LR,r0,r1,r2,r3,r7,r8,r9}
CMP r1,#15 ; check column & row range
BHI end_lcdCursorAt
CMP r0,#0
BEQ end_lcdCursorAt
CMP r0,#2
BHI end_lcdCursorAt
ADDEQ r1,r1,#0x40 ; build the cursor address
LDR r0,=0x00800000
ORR r2,r0,r1,LSL #16 ; r2 now has the address
LDR r3,=0x03FF0000 ; one's for pins used for lcd
LDR r7,=IO1CLR
LDR r8,=IO1SET
LDR r9,=0x02000000 ; bit pattern to turn on/off E
STR r2,[r8] ; set lcd function bits
BL pulse_e
STR r3,[r7] ; clear lcd bits
MOV r0,#40
BL delay
end_lcdCursorAt LDMFD SP!,{PC,r0,r1,r2,r3,r7,r8,r9}
; -----------------------------------------------------------------------------
; Procedure lcdWRdata Writes data (an ASCII character) to the
; current cursor position on the LCD
; r0 is assumed to contain the character to send
; -----------------------------------------------------------------------------
lcdWRdata STMFD SP!,{LR,r0,r1,r2,r3,r7,r8,r9}
LDR r9,=0x02000000 ; bit pattern to turn on/off E
LDR r3,=0x03FF0000 ; one's for pins used for lcd
LDR r7,=IO1CLR
LDR r8,=IO1SET
AND r0,r0,#0xFF ; make sure only 8 bits are non-zero
ORR r0,r0,#0x100 ; set bit that indicates writing
LSL r0,r0,#16
STR r0,[r8] ; write data
BL pulse_e
STR r3,[r7] ; clear lcd bits
end_lcdWRData LDMFD SP!,{PC,r0,r1,r2,r3,r7,r8,r9}
; -----------------------------------------------------------------------------
; Procedure delay microsecond delay using timer 0
; (12Mhz clock & VPB divide by 4 assumed)
; reg R0 must contain a delay value in uS
; Not interruptable (r14 not saved)
; assumes lcdReset has been called prior to delay
; r0, r1 not preserved
; -----------------------------------------------------------------------------
delay LDR r1,=T0_MR0_ADDR ; Match register zero
STR r0,[r1] ; load match count per R0
; ldr r0,=0x8000
; str r0,[r5] ; turn on p0.15 led
LDR r1,=T0_TCR_ADDR ; Timer 0 Control Register
MOV r0,#2 ; bit 1 = one
STR r0,[r1] ; Clear counter & prescaler
MOV r0,#0
STR r0,[r1]
MOV r0,#1 ; bit 0 = one
STR r0,[r1] ; Turn on counter
dloop LDR r0,[r1] ; Read TCR register
ANDS r0,r0,#1
BNE dloop
; ldr r0,=0x8000
; str r0,[r6] ; turn off p0.15 led
end_delay BX LR ; Return
END
- PWM Example for running the servos on the robots
;---------------------------------------------------------------------------
;
; Programmer : Larry Aamodt
;
; File name : shell_2148.s
; Class : CPTR-215
; Language : ARM assembly
; Assembler : Keil
; Target MCU : NXP LPC-2148 on Embedded Artists board
; Date Written: 11/30/09
; change history: 11/30/09 LDA Updated with hardware start-up
; 12/03/09 LDA PWM register definitions added
; Description :
;
; Inputs :
;
; Outputs :
;
; Special :
; requirements
;
;
; NOTES:
;
;
;
;---------------------------------------------------------------------------
; Put application program definitions (i.e. equates) here:
; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
Mode_USR EQU 0x10
Mode_FIQ EQU 0x11
Mode_IRQ EQU 0x12
Mode_SVC EQU 0x13
Mode_ABT EQU 0x17
Mode_UND EQU 0x1B
Mode_SYS EQU 0x1F
I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled
F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled
; Memory addresses for standard GPIO definitions
IO0PIN EQU 0xE0028000
IO0SET EQU 0xE0028004
IO0DIR EQU 0xE0028008
IO0CLR EQU 0xE002800C
; Memory addresses for Timer/Counter
T1TCR EQU 0xE0008004
T1CTCR EQU 0xE0008070
T1PR EQU 0xE000800C
T1MCR EQU 0xE0008014
T1EMR EQU 0xE000803C
; Memory addresses for Pulse Width Modulation (PWM)
PWM_TCR EQU 0xE0014004 ; PWM_TCR Timer Control Register
PWM_PR EQU 0xE001400C ; PWM_PR Prescaler Register
PWM_MCR EQU 0xE0014014 ; PWM_MCR Match Control Register
PWM_MR0 EQU 0xE0014018 ; PWM_MR0 Match Register 0 (sets pulse period)
PWM_MR4 EQU 0xE0014040 ; PWM_MR4 Match Register 4 (sets pulse length)
PWM_MR6 EQU 0xE0014048 ; PWM_MR6 Match Register 6 (sets pulse length)
PWM_PCR EQU 0xE001404C ; PWM_CR Control Register
PWM_LER EQU 0xE0014050 ; PWM_LER Latch Enable Register
PINSEL0 EQU 0xE002C000 ; Pin connect block - port 0
PINSEL1 EQU 0xE002C004 ; Pin connect block - port 1
; Stack size definitions
UND_Stack_Size EQU 0x00000000
SVC_Stack_Size EQU 0x00000008
ABT_Stack_Size EQU 0x00000000
FIQ_Stack_Size EQU 0x00000000
IRQ_Stack_Size EQU 0x00000080
USR_Stack_Size EQU 0x00000400
ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
FIQ_Stack_Size + IRQ_Stack_Size)
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE USR_Stack_Size
__initial_sp SPACE ISR_Stack_Size
Stack_Top
; Area Definition and Entry Point
; Startup Code must be linked first at Address at which it expects to run.
AREA RESET, CODE, READONLY
ARM
; Exception Vectors
; Mapped to Address 0.
; Absolute addressing mode must be used.
; Dummy Handlers are implemented as infinite loops which can be modified.
Vectors LDR PC, Reset_Addr
LDR PC, Undef_Addr
LDR PC, SWI_Addr
LDR PC, PAbt_Addr
LDR PC, DAbt_Addr
NOP ; Reserved Vector
; LDR PC, IRQ_Addr
LDR PC, [PC, #-0x0FF0] ; Vector from VicVectAddr
LDR PC, FIQ_Addr
Reset_Addr DCD Reset_Handler
Undef_Addr DCD Undef_Handler
SWI_Addr DCD SWI_Handler
PAbt_Addr DCD PAbt_Handler
DAbt_Addr DCD DAbt_Handler
DCD 0 ; Reserved Address
IRQ_Addr DCD IRQ_Handler
FIQ_Addr DCD FIQ_Handler
Undef_Handler B Undef_Handler
SWI_Handler B SWI_Handler
PAbt_Handler B PAbt_Handler
DAbt_Handler B DAbt_Handler
IRQ_Handler B IRQ_Handler
FIQ_Handler B FIQ_Handler
; Reset Handler
EXPORT Reset_Handler
Reset_Handler
; Setup Stack for each mode
LDR R0, =Stack_Top
; Enter Undefined Instruction Mode and set its Stack Pointer
MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #UND_Stack_Size
; Enter Abort Mode and set its Stack Pointer
MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #ABT_Stack_Size
; Enter FIQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #FIQ_Stack_Size
; Enter IRQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #IRQ_Stack_Size
; Enter Supervisor Mode and set its Stack Pointer
MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #SVC_Stack_Size
; Enter User Mode and set its Stack Pointer
MSR CPSR_c, #Mode_USR
MOV SP, R0
SUB SL, SP, #USR_Stack_Size
; User program code goes here
main
BL pwm_init
mov r0, #3
ldr r1, =1600
mov r2, r1
bl pwm_update
stop b stop
;*****************************************************************************
; Pulse width modulator initialization routine.
; pulse period = 20ms; initial pulse length = 1.5ms
; (values shown are for controlling model plane servos)
; Inputs: none
; Returned values: none
; Uses registers r0, r1
;
; Calling method: BL pwm_init
; LDA rev 1.0 12/01/10
; Rob Frohne rev 1.1 12/3/13
;*****************************************************************************
; Stepper motor connections on the Board of Education are from page 24 of the board
; Users Guide. A stepper motor operation is explained at:
; http://www.haydonkerk.com/Resources/StepperMotorTheory/tabid/192/Default.aspx
;
; PWM is explained in Chapter 16 (page 253 and following) of the reference manual.
; Note the registers in the reference manual are labeled without the _, i.e.
; PWMPR instead of PWM_PR.
pwm_init STMFD sp!,{r14} ; save link register on the stack
LDR r0,=PWM_PR
LDR r1,=2 ; prescaler = 2 divides PCLK by 3
STR r1,[r0] ; load prescaler
; PCLK rate is 1 MHZ (1 uSEC period) after division.
LDR r0,=PWM_MCR ; PWMMCR PWM Match Control Register.
; The PWMMCR is used to control if an
; interrupt is generated and if the PWMTC
; is reset when a Match occurs. See page 261 of the manual.
LDR r1,=0x02 ; bit 1 is set, others are zero
STR r1,[r0] ; load PWM_MCR: PWM_TC resets when PWM_TC=PWM_MR0
LDR r0,=PWM_MR0
LDR r1,=20000 ; count 20,000 1uSEC intervals = 20 milli secs
STR r1,[r0] ; load match register 0. sets pulse period. Page 261.
LDR r0,=PWM_MR4
LDR r1,=1500 ; initial pulse width = 1.5 milli secs
STR r1,[r0] ; load match register 4. Page 261
LDR r0,=PWM_MR6
LDR r1,=1500 ; initial pulse width
STR r1,[r0] ; load match register 6
LDR r0,=PWM_LER
LDR r1,=0x51
STR r1,[r0] ; Enable latch registers 0, 4, & 6
LDR r0,=PWM_PCR
LDR r1,=0x5000 ; bits 12 & 14 set
STR r1,[r0] ; load PWM_CR: enables PWM4 and PWM6 outputs
LDR r0,=PWM_TCR
LDR r1,=0x09 ; bits 3,1,0 set
STR r1,[r0] ; load PWM_TCR enable PWM counter & prescaler
LDR r0,=PINSEL0
LDR r1,=0xA0000 ; bits 19 & 17 set. selects output PWM 6 & 4
STR r1,[r0] ; Enable PWM6 & PWM4 outputs
end_pwm_init LDMFD sp!,{pc} ; Return from subroutine pwm_init
;*****************************************************************************
; Pulse width modulator update routine
; Inputs: r0 = command
; 1 = update PWM channel 4
; 2 = update PWM channel 6
; 3 = update both channel 4 and 6
; r1 = new pulse width (# of microseconds) for PWM channel 4
; r2 = new pulse width (# of microseconds) for PWM channel 6
; Returned values: none
; Uses registers r0, r1, r2, r3
;
; Calling method: first put values in r0, r1, r2 as appropriate
; BL pwm_update
; LDA rev 2.0 12/01/11
;*****************************************************************************
pwm_update STMFD sp!,{r14} ; r0 specifies channels to update
load_pwm4 CMP r0,#1 ; 1 = load PWM chan 4
BNE load_pwm6
LDR r3,=PWM_MR4
STR r1,[r3] ; load match register 4
load_pwm6 CMP r0,#2 ; 2 = load PWM chan 6
BNE load_both
LDR r3,=PWM_MR6
STR r2,[r3] ; load match register 6
load_both CMP r0,#3
BNE pwm_reg_update
LDR r3,=PWM_MR4
STR r1,[r3]
LDR r3,=PWM_MR6
STR r2,[r3]
pwm_reg_update CMP r0,#1 ; check for just pwm 4 update
MOVEQ r1,#0x10
CMP r0,#2 ; check for just pwm 6 update
MOVEQ r1,#0x40
CMP r0,#3 ; check for pwm 4 & 6 update
MOVEQ r1,#0x50
LDR r3,=PWM_LER
STR r1,[r3] ; enable latch registers
end_pwm_update LDMFD sp!,{pc} ; Return from subroutine pwm_update
; User data area definition follows
AREA appdata, DATA, NOINIT, READWRITE
END
- Stepper Motor on the Embedded Artists Board of Education
;---------------------------------------------------------------------------
;
; Programmer : Larry Aamodt
; : Modifications for propeller drive: Rob Frohne
;
; File name : shell_2148.s
; Class : CPTR-215
; Language : ARM assembly
; Assembler : Keil
; Target MCU : NXP LPC-2148 on Embedded Artists board
; Date Written: 11/30/09
; change history: 11/30/09 LDA Updated with hardware start-up
; 12/03/09 LDA PWM register definitions added
; Description :
;
; Inputs :
;
; Outputs :
;
; Special :
; requirements
;
;
; NOTES:
;
;
;
;---------------------------------------------------------------------------
; Put application program definitions (i.e. equates) here:
; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
Mode_USR EQU 0x10
Mode_FIQ EQU 0x11
Mode_IRQ EQU 0x12
Mode_SVC EQU 0x13
Mode_ABT EQU 0x17
Mode_UND EQU 0x1B
Mode_SYS EQU 0x1F
I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled
F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled
; Memory addresses for standard GPIO definitions
IO0PIN EQU 0xE0028000
IO0SET EQU 0xE0028004
IO0DIR EQU 0xE0028008
IO0CLR EQU 0xE002800C
; Timer addresses
T0_TCR_ADDR EQU 0xE0004004
T0_PR_ADDR EQU 0xE000400C
T0_MCR_ADDR EQU 0xE0004014
T0_MR0_ADDR EQU 0xE0004018
; Memory addresses for Pulse Width Modulation (PWM)
PWM_TCR EQU 0xE0014004 ; PWM_TCR Timer Control Register
PWM_PR EQU 0xE001400C ; PWM_PR Prescaler Register
PWM_MCR EQU 0xE0014014 ; PWM_MCR Match Control Register
PWM_MR0 EQU 0xE0014018 ; PWM_MR0 Match Register 0 (sets pulse period)
PWM_MR4 EQU 0xE0014040 ; PWM_MR4 Match Register 4 (sets pulse length)
PWM_MR6 EQU 0xE0014048 ; PWM_MR6 Match Register 6 (sets pulse length)
PWM_PCR EQU 0xE001404C ; PWM_CR Control Register
PWM_LER EQU 0xE0014050 ; PWM_LER Latch Enable Register
PINSEL0 EQU 0xE002C000 ; Pin connect block - port 0
PINSEL1 EQU 0xE002C004 ; Pin connect block - port 1
; Stack size definitions
UND_Stack_Size EQU 0x00000000
SVC_Stack_Size EQU 0x00000008
ABT_Stack_Size EQU 0x00000000
FIQ_Stack_Size EQU 0x00000000
IRQ_Stack_Size EQU 0x00000080
USR_Stack_Size EQU 0x00000400
ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
FIQ_Stack_Size + IRQ_Stack_Size)
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE USR_Stack_Size
__initial_sp SPACE ISR_Stack_Size
Stack_Top
; Area Definition and Entry Point
; Startup Code must be linked first at Address at which it expects to run.
AREA RESET, CODE, READONLY
ARM
; Exception Vectors
; Mapped to Address 0.
; Absolute addressing mode must be used.
; Dummy Handlers are implemented as infinite loops which can be modified.
Vectors LDR PC, Reset_Addr
LDR PC, Undef_Addr
LDR PC, SWI_Addr
LDR PC, PAbt_Addr
LDR PC, DAbt_Addr
NOP ; Reserved Vector
; LDR PC, IRQ_Addr
LDR PC, [PC, #-0x0FF0] ; Vector from VicVectAddr
LDR PC, FIQ_Addr
Reset_Addr DCD Reset_Handler
Undef_Addr DCD Undef_Handler
SWI_Addr DCD SWI_Handler
PAbt_Addr DCD PAbt_Handler
DAbt_Addr DCD DAbt_Handler
DCD 0 ; Reserved Address
IRQ_Addr DCD IRQ_Handler
FIQ_Addr DCD FIQ_Handler
Undef_Handler B Undef_Handler
SWI_Handler B SWI_Handler
PAbt_Handler B PAbt_Handler
DAbt_Handler B DAbt_Handler
IRQ_Handler B IRQ_Handler
FIQ_Handler B FIQ_Handler
; Reset Handler
EXPORT Reset_Handler
Reset_Handler
; Setup Stack for each mode
LDR R0, =Stack_Top
; Enter Undefined Instruction Mode and set its Stack Pointer
MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #UND_Stack_Size
; Enter Abort Mode and set its Stack Pointer
MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #ABT_Stack_Size
; Enter FIQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #FIQ_Stack_Size
; Enter IRQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #IRQ_Stack_Size
; Enter Supervisor Mode and set its Stack Pointer
MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #SVC_Stack_Size
; Enter User Mode and set its Stack Pointer
MSR CPSR_c, #Mode_USR
MOV SP, R0
SUB SL, SP, #USR_Stack_Size
; User program code goes here
quarter_period EQU 250000 ; uS
main
BL init_propeller
mov r1, #1 ; for handy access
mov r2, #0 ; for handy access
mov r0, r1, LSL #12 ; turn one on
mov r4, r2, LSL #21 ; two still off
orr r0, r4, r0 ; both on
ldr r3,=IO0PIN
str r0,[r3]
ldr r0,=quarter_period
bl delay
mov r0, r1, LSL #12
mov r4, r1, LSL #21
orr r0, r4, r0 ; both on
ldr r3,=IO0PIN
str r0,[r3]
ldr r0,=quarter_period
bl delay
mov r0, r2, LSL #12 ; turn one off
mov r4, r1, LSL #21 ; two still on
orr r0, r4, r0 ; both on
ldr r3,=IO0PIN
str r0,[r3]
ldr r0,=quarter_period
bl delay
mov r0, r2, LSL #12 ; turn one off
mov r4, r2, LSL #21 ; turn two off
orr r0, r4, r0 ; both on
ldr r3,=IO0PIN
str r0,[r3]
ldr r0,=quarter_period
bl delay
b main
; -----------------------------------------------------------------------------
; Procedure init_propeller Must be called before to initialize the propeller.
; Set up the counter T0 and GPIO P0.12 and P0.21 for output.
; No parameters required
; -----------------------------------------------------------------------------
init_propeller STMFD SP!,{LR,r0,r1,r2,r3,r4}
LDR r1,=T0_PR_ADDR ; Prescale register
MOV r2,#2 ; prescale count value
STR r2,[r1] ; Prescaler will divide by 3 (1 uS period)
LDR r1,=T0_MCR_ADDR ; Match control register
MOV r2,#0x4 ; bit 2 = one: Stop on MR0: the TC and PC
; will be stopped and TCR[0] will be set to 0 if
; MR0 matches the TC
STR r2,[r1] ; stop counter when match reached
LDR r0,=IO0DIR
LDR r4,[r0] ; read current Port 0 direction bits
LDR r3,=2101248 ; one's for pins to be set for output (2^12+2^21 = 2101248)
; 2134016 = 2^12+2^21+2^15 (for debugging LED on P0.15
ORR r4,r4,r3
STR r4,[r0] ; set propeller port bits to output without changing others.
LDR r0,=PINSEL0
LDR r4,[r0] ; read current Port 0 direction bits
LDR r3,=50331648 ; zero's for pins to be set for output (2^24+2^25 = 50331648)
BIC r4,r4,r3 ;
STR r4,[r0] ; set propeller port P0.12 to GPIO without changing others.
LDR r0,=PINSEL1
LDR r4,[r0] ; read current Port 0 direction bits
LDR r3,=3072 ; zero's for pins to be set for output (2^10+2^11 = 3072)
BIC r4,r4,r3 ;
STR r4,[r0] ; set propeller port P0.21 to GPIO without changing others.
end_init_propeller LDMFD SP!,{PC,r0,r1,r2,r3,r4}
; -----------------------------------------------------------------------------
; Procedure delay microsecond delay using timer 0
; (12Mhz clock & VPB divide by 4 assumed)
; reg R0 must contain a delay value in uS
; Not interruptable (r14 not saved)
; assumes lcdReset has been called prior to delay
; r0, r1 not preserved
; -----------------------------------------------------------------------------
delay STMFD SP!,{LR,r0,r1}
LDR r1,=T0_MR0_ADDR ; Match register zero
STR r0,[r1] ; load match count per R0
; ldr r0,=0x8000
; str r0,[r5] ; turn on p0.15 led
LDR r1,=T0_TCR_ADDR ; Timer 0 Control Register
MOV r0,#2 ; bit 1 = one
STR r0,[r1] ; Clear counter & prescaler
MOV r0,#0
STR r0,[r1]
MOV r0,#1 ; bit 0 = one
STR r0,[r1] ; Turn on counter
dloop LDR r0,[r1] ; Read TCR register
ANDS r0,r0,#1
BNE dloop
; ldr r0,=0x8000
; str r0,[r6] ; turn off p0.15 led
end_delay LDMFD SP!,{PC,r0,r1} ; Return
END
- Propeller Drive Using Interrupts (not polled)
;---------------------------------------------------------------------------
;
; Shell Programmer : Larry Aamodt, main: Rob Frohne
;
;
; File name : shell_2148.s
; Class : CPTR-215
; Language : ARM assembly
; Assembler : Keil
; Target MCU : NXP LPC-2148 on Embedded Artists board
; Date Written: 11/30/09
; change history: 11/30/09 LDA Updated with hardware start-up
; 12/03/09 LDA PWM register definitions added
; Description :
;
; Inputs :
;
; Outputs :
;
; Special :
; requirements
;
;
; NOTES:
;
;
;
;---------------------------------------------------------------------------
; Put application program definitions (i.e. equates) here:
; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
Mode_USR EQU 0x10
Mode_FIQ EQU 0x11
Mode_IRQ EQU 0x12
Mode_SVC EQU 0x13
Mode_ABT EQU 0x17
Mode_UND EQU 0x1B
Mode_SYS EQU 0x1F
I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled
F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled
; Memory addresses for standard GPIO definitions
IO0PIN EQU 0xE0028000
IO0SET EQU 0xE0028004
IO0DIR EQU 0xE0028008
IO0CLR EQU 0xE002800C
; Vector Interrupt Controller Addresses
VICIntSelect EQU 0xFFFFF00C
VICVectAddr4 EQU 0xFFFFF110
VICVectCntl4 EQU 0xFFFFF210
VICIntEnable EQU 0xFFFFF010
VICVectAddr EQU 0xFFFFF030
; Timer addresses
T0PC EQU 0xE0004010 ; Timer 0 Prescale counter
T0IR EQU 0xE0004000 ; Timer 0 Interrupt Register
T0_TCR_ADDR EQU 0xE0004004
T0_PR_ADDR EQU 0xE000400C
T0_MCR_ADDR EQU 0xE0004014
T0_MR0_ADDR EQU 0xE0004018
; Memory addresses for Pulse Width Modulation (PWM)
PWM_TCR EQU 0xE0014004 ; PWM_TCR Timer Control Register
PWM_PR EQU 0xE001400C ; PWM_PR Prescaler Register
PWM_MCR EQU 0xE0014014 ; PWM_MCR Match Control Register
PWM_MR0 EQU 0xE0014018 ; PWM_MR0 Match Register 0 (sets pulse period)
PWM_MR4 EQU 0xE0014040 ; PWM_MR4 Match Register 4 (sets pulse length)
PWM_MR6 EQU 0xE0014048 ; PWM_MR6 Match Register 6 (sets pulse length)
PWM_PCR EQU 0xE001404C ; PWM_CR Control Register
PWM_LER EQU 0xE0014050 ; PWM_LER Latch Enable Register
PINSEL0 EQU 0xE002C000 ; Pin connect block - port 0
PINSEL1 EQU 0xE002C004 ; Pin connect block - port 1
; Stack size definitions
UND_Stack_Size EQU 0x00000000
SVC_Stack_Size EQU 0x00000008
ABT_Stack_Size EQU 0x00000000
FIQ_Stack_Size EQU 0x00000000
IRQ_Stack_Size EQU 0x00000080
USR_Stack_Size EQU 0x00000400
ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
FIQ_Stack_Size + IRQ_Stack_Size)
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE USR_Stack_Size
__initial_sp SPACE ISR_Stack_Size
Stack_Top
; Area Definition and Entry Point
; Startup Code must be linked first at Address at which it expects to run.
AREA RESET, CODE, READONLY
ARM
; Exception Vectors
; Mapped to Address 0.
; Absolute addressing mode must be used.
; Dummy Handlers are implemented as infinite loops which can be modified.
Vectors LDR PC, Reset_Addr
LDR PC, Undef_Addr
LDR PC, SWI_Addr
LDR PC, PAbt_Addr
LDR PC, DAbt_Addr
NOP ; Reserved Vector
; LDR PC, IRQ_Addr
LDR PC, [PC, #-0x0FF0] ; Vector from VicVectAddr
LDR PC, FIQ_Addr
Reset_Addr DCD Reset_Handler
Undef_Addr DCD Undef_Handler
SWI_Addr DCD SWI_Handler
PAbt_Addr DCD PAbt_Handler
DAbt_Addr DCD DAbt_Handler
DCD 0 ; Reserved Address
IRQ_Addr DCD IRQ_Handler
FIQ_Addr DCD FIQ_Handler
; Exception Handlers
Undef_Handler B Undef_Handler
SWI_Handler B SWI_Handler
PAbt_Handler B PAbt_Handler
DAbt_Handler B DAbt_Handler
IRQ_Handler B IRQ_Handler
FIQ_Handler B FIQ_Handler
; Reset Handler
EXPORT Reset_Handler
Reset_Handler
; Setup Stack for each mode
LDR R0, =Stack_Top
; Enter Undefined Instruction Mode and set its Stack Pointer
MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #UND_Stack_Size
; Enter Abort Mode and set its Stack Pointer
MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #ABT_Stack_Size
; Enter FIQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #FIQ_Stack_Size
; Enter IRQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #IRQ_Stack_Size
; Enter Supervisor Mode and set its Stack Pointer
MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #SVC_Stack_Size
; Enter User Mode and set its Stack Pointer
MSR CPSR_c, #Mode_USR
MOV SP, R0
SUB SL, SP, #USR_Stack_Size
step_time_uS EQU 250000 ; uS between steps of the propeller motor.
main BL init_propeller ; Initialize GPIO and IRQ, and Timer 0.
LDR r0,=step1
LDR r1,=NextRoutine_Address
STR r0,[r1]
bl delay ; start the whole automated thing
do_nothing b do_nothing ; because the ISR will do it all!
; -----------------------------------------------------------------------------
; Step the motor routines. These are called by the Timer0 ISR (timer0ISR)
; -----------------------------------------------------------------------------
step1 STMFD SP!,{LR,r0-r12}
mov r1, #1 ; for handy access
mov r2, #0 ; for handy access
mov r0, r1, LSL #12 ; turn one on
mov r4, r2, LSL #21 ; two still off
orr r0, r4, r0 ; both on
ldr r3,=IO0PIN
str r0,[r3]
LDR r0,=step2
LDR r1,=NextRoutine_Address
STR r0,[r1]
bl delay
LDMFD SP!,{PC,r0-r12}
step2 STMFD SP!,{LR,r0-r12}
mov r1, #1 ; for handy access
mov r2, #0 ; for handy access
mov r0, r1, LSL #12
mov r4, r1, LSL #21
orr r0, r4, r0 ; both on
ldr r3,=IO0PIN
str r0,[r3]
LDR r0,=step3
LDR r1,=NextRoutine_Address
STR r0,[r1]
bl delay
LDMFD SP!,{PC,r0-r12}
step3 STMFD SP!,{LR,r0-r12}
mov r1, #1 ; for handy access
mov r2, #0 ; for handy access
mov r0, r2, LSL #12 ; turn one off
mov r4, r1, LSL #21 ; two still on
orr r0, r4, r0 ; both on
ldr r3,=IO0PIN
str r0,[r3]
LDR r0,=step4
LDR r1,=NextRoutine_Address
STR r0,[r1]
bl delay
LDMFD SP!,{PC,r0-r12}
step4 STMFD SP!,{LR,r0-r12}
mov r1, #1 ; for handy access
mov r2, #0 ; for handy access
mov r0, r2, LSL #12 ; turn one off
mov r4, r2, LSL #21 ; turn two off
orr r0, r4, r0 ; both on
ldr r3,=IO0PIN
str r0,[r3]
LDR r0,=step1
LDR r1,=NextRoutine_Address
STR r0,[r1]
bl delay
LDMFD SP!,{PC,r0-r12}
; -----------------------------------------------------------------------------
; Procedure init_propeller Must be called before to initialize the propeller.
; Set up GPIO P0.12 and P0.21 for output.
; Set up timer 0 and interrupts for IRQ (low priority)
; No parameters required
; -----------------------------------------------------------------------------
init_propeller STMFD SP!,{LR,r0,r1,r2,r3,r4}
LDR r1,=T0_PR_ADDR ; Prescale register
MOV r2,#2 ; prescale count value
STR r2,[r1] ; Prescaler will divide by 3 (1 uS period
; T0MCR = 0x00000003; //reset counter and generate IRQ on MR0 match
LDR r1,=T0_MCR_ADDR ; Match control register
MOV r2,#0x3 ; bit 2 = one: Stop on MR0: the TC and PC : bit 1 = 1 gives interrupt
; will be stopped and TCR[0] will be set to 0 if
; MR0 matches the TC
STR r2,[r1] ; stop counter when match reached
; VICIntSelect &= ~0x10; //Timer0 interrupt is assigned to IRQ (not FIQ)
LDR r1,=VICIntSelect
MOV r0,#~0x10
STR r0,[r1]
; VICVectAddr4 = (tU32)timer0ISR; //register ISR address
LDR r1,=VICVectAddr4
LDR r0,=timer0ISR
STR r0,[r1]
; VICVectCntl4 = 0x24; //enable vector interrupt for timer0
LDR r1,=VICVectCntl4
MOV r0,#0x24
STR r0,[r1]
; VICIntEnable = 0x10; //enable timer0 interrupt
LDR r1,=VICIntEnable
MOV r0,#0x10
STR r0,[r1]
LDR r0,=IO0DIR
LDR r4,[r0] ; read current Port 0 direction bits
LDR r3,=2101248 ; one's for pins to be set for output (2^12+2^21 = 2101248)
; 2134016 = 2^12+2^21+2^15 (for debugging LED on P0.15
ORR r4,r4,r3
STR r4,[r0] ; set propeller port bits to output without changing others
LDR r0,=PINSEL0
LDR r4,[r0] ; read current Port 0 direction bits
LDR r3,=50331648 ; zero's for pins to be set for output (2^24+2^25 = 50331648)
BIC r4,r4,r3 ;
STR r4,[r0] ; set propeller port P0.12 to GPIO without changing others.
LDR r0,=PINSEL1
LDR r4,[r0] ; read current Port 0 direction bits
LDR r3,=3072 ; zero's for pins to be set for output (2^10+2^11 = 3072)
BIC r4,r4,r3 ;
STR r4,[r0] ; set propeller port P0.21 to GPIO without changing others.
end_init_propeller LDMFD SP!,{PC,r0,r1,r2,r3,r4}
; -----------------------------------------------------------------------------
; Timer 0 Interrupt Service Routine timer0ISR
; Some comments are C equivalents.
; -----------------------------------------------------------------------------
timer0ISR SUB LR,LR,#4 ; Update the LR
STMFD SP!, {r0-r12,LR} ; Store registers (including LR)
; T0IR = 0xff; //reset all IRQ flags
LDR r1,=T0IR
MOV r0,#~0xff
STR r0,[r1]
; VICVectAddr = 0x00; //dummy write to VIC to signal end of interrupt
LDR r1,=VICVectAddr
MOV r0,#~0x00
STR r0,[r1]
; Here we will branch to the appropriate next step routine.
LDR r0,=NextRoutine_Address
push {r14} ; save LR for this return.
ldr r14,=end_timer0ISR ; load the LR because we are using an LDR PC below.
ldr PC,[r0] ; branch to the subroutine pointed to by NextRoutine_Address
end_timer0ISR pop {r14} ; restore the LR for this return.
LDMFD SP!, {r0-r12,PC}^ ; Return from ISR
; -----------------------------------------------------------------------------
; Procedure delay microsecond delay using timer 0
; (12Mhz clock & VPB divide by 4 assumed)
; Delay is set by step_time_uS
; -----------------------------------------------------------------------------
delay STMFD SP!,{LR,r0,r1}
; T0PC = 0x00000000; Didn't do this yet. Unnecessary? //no prescale of clock
; LDR r1,=T0PC
; MOV r0,#0x00000000
; STR r0,[r1]
; T0IR = 0x000000ff; //reset all flags before enable IRQs
LDR r1,=T0IR
MOV r0,#0x000000ff
STR r0,[r1]
; T0MR0 = delayInMs * //calculate no of timer ticks
; ((CRYSTAL_FREQUENCY * PLL_FACTOR) / (1000 * VPBDIV_FACTOR));
LDR r1,=T0_MR0_ADDR ; Match register zero
LDR r0,=step_time_uS
STR r0,[r1] ; load match count from step_time_uS
; T0TCR = 0x00000002; //disable and reset Timer0
LDR r1,=T0_TCR_ADDR ; Timer 0 Control Register
MOV r0,#2 ; bit 1 = one
; T0TCR = 0x00000001; //start Timer0
STR r0,[r1] ; Clear counter & prescaler
MOV r0,#0
STR r0,[r1]
MOV r0,#1 ; bit 0 = one
STR r0,[r1] ; Turn on counter
end_delay LDMFD SP!,{PC,r0,r1} ; Return
AREA Thedata, DATA, READWRITE
ALIGN
NextRoutine_Address SPACE 4 ; This holds the address of the next step subroutine.
END