Code Examples from Class: Difference between revisions
Jump to navigation
Jump to search
(Created page with "* 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 …") |
No edit summary |
||
(33 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 |
|||
---- |
|||
* 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 |
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 10: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