Code Examples from Class

From Class Wiki
Revision as of 17:57, 20 November 2013 by Frohro (talk | contribs)
Jump to navigation Jump to search
  • 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



  • 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, 1/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 beginning address of the code & initialize it as the pointer.
	ldr r2,=begin	; load the ending 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, mask 0xf, r5 & r6 for masked addends,
; working BCD_carry, r7 for
; working result in r4
; the summed digits go in r3
; inputs: r0+r1
; outupts: 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.
	bmi no_carry
	mov r7, #1 ; set the carry
	b roll_to_next_digit
no_carry
	mov r7, #0 ; set carry to zero
	add r4, r4, #10 ; Add the 10 back in as there was no carry needed.
roll_to_next_digit
	orr r3, r3, r4 ; Add thise digits into the sum.
	ror r0, #4
	ror r1, #4
	ror r3, #4
	subs r8, r8, #1	 ; Decrement 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


  • 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 sp, = Stack_Mem	; load stack pointer
	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