;;; -*- Mode:Asm Mode:outline-minor-mode outline-regexp:";;;+" comment-start: "; " -*- ;;; led3.asm ;;; Frank Sergeant frank@pygmy.utoh.org ;;; Test program for the Olimex LPC P-2378 board. ;;; Flash the STAT LED connected to P1.19 ;; Leave the clock however it is set up by the bootloader. ;; Do not set up stacks (therefore no subroutines or interrupts). ;; Set the GPIOM bit, so we can use the Fast GPIO. ;; This is like led2.asm except the delay uses a timer ;; rather than counting down a value in a register .include "equates-lpc23xx.s" .include "olimex-lpc2378-equates.s" ;;; Timing related equates ;; In this program, we do not set any of the clock related items, ;; we just guess as to what they are then use that information ;; to calculate the delay value to put into the timer's match ;; register. ;; If you ask for 10 seconds (so the LED is on for 10 seconds ;; then off for 10 seconds, etc.) but the actual time the ;; LED is on and off is 5 seconds or 20 seconds or whatever, ;; then some of the guesses need to be revised. ;; See the next program (led4.asm) where we use the same equates ;; and calculations but with more comments *and* we use some of ;; the information to change the clock to the 12 MHz main ;; oscillator. ;; frequency is given in number of clocks per second .equ PLLCLKIN, 4000000 ; IRC clock frequency .equ PLLCLK, 4000000 ; PLL bypassed so PLLCLK = PLLCLKIN .equ CPUDIVISOR, 1 .equ CCLK, (PLLCLK / CPUDIVISOR) .equ PCLK_TIMER0_DIVISOR, 4 ; timer's PCLK is 1/4 of PLLCLK .equ TIMER0_PRESCALE_DIVISOR, 1 .equ TIMER0FREQ, ((PLLCLK / PCLK_TIMER0_DIVISOR) / TIMER0_PRESCALE_DIVISOR) ;; now that we know (or have guessed) the timer frequency we can ;; calculate the value for the timer's match register and/or ;; the timer's prescale register in order to kill the requested ;; amount of time. .equ SECONDS, 3 ; let's have the LED on for 3 seconds ; then off for 3 seconds .equ LEDDELAY, (SECONDS * TIMER0FREQ) ;;; Code .code 32 .section .text .global vectors .org 0 .global _start ;;; Vectors ; each interrupt vector runs an endless loop except for reset vectors: b _start b . b . b . b . b . b . b . .section .text _start: ;;;; Clock ;; leave the clock however it is set up by the bootloader ;;;; Ports ;; Set the GPIOM bit so we can use the Fast GPIO. ;; (The bootloader might have set the GPIOM bit but we set it ;; explicitly to be sure.) ;; select fast GPIO mode for ports 0 and 1 ldr r6, = SCS ldr r0, [r6] orr r0, r0, #1 ; set bit zero (GPIOM) to force fast GPIO mode str r0, [r6] ;; Clear all the mask bits so that no pins are masked ldr r6, = FIO0MASK mov r0, #0 str r0, [r6] ; FIO0MASK str r0, [r6, #0x20] ; FIO1MASK str r0, [r6, #0x40] ; FIO2MASK str r0, [r6, #0x60] ; FIO3MASK str r0, [r6, #0x80] ; FIO4MASK ;; set P1.19 as a GPIO pin ;; P1.19 is controlled by bits 7:6 of PINSEL3 ldr r6, = PINSEL3 ldr r0, [r6] bic r0, r0, # 0xc0 ; clear bits 7:6 to force GPIO mode str r0, [r6] ;; See the equate for STAT_LED_MASK in olimex-lpc2378-equates.asm ;; set LED output pin (i.e. P1.19) as an output ldr r6, = FIO1DIR ; for PORT1 mov r0, # STAT_LED_MASK ; all inputs except for pin 19 str r0, [r6] ;;;; Timer ;; Use timer0 to delay between LED blinks ;; With a prescale value of 0, the counter increments on ;; every rising edge of PCLK. ldr r6, = T0CTCR ; Put timer0 into timer (not counter) mode, mov r0, #0 ; almost certainly not needed as strb r0, [r6] ; bootloader probably did not disturb it. ldr r6, = T0TCR ; start timer0 mov r0, #1 strb r0, [r6] ldr r6, = T0PR ; set timer0 prescaler mov r0, #0 ; start with no prescaling str r0, [r6] ldr r6, = T0MCR ; Reset the counter when it mov r0, #3 ; matches the match register value str r0, [r6] ; and also generate an interrupt. ; That is, set the interrupt bit ; for it in the timer interrupt register ; but do not actually cause an interrupt ; because we have not turned it on in ; the VIC. ldr r6, = T0MR0 ; set the counter match value ldr r0, = LEDDELAY str r0, [r6] ldr r6, = FIO1PIN 1: eor r0, r0, # STAT_LED_MASK ; flip the bit controlling the LED str r0, [r6] ; set or clear P1.19, turning LED on or off ldr r5, = T0IR ; bit 0 goes high when timer count matches ; the value in match register 0 2: ldr r1, [r5] ; read timer interrupt register ands r1, r1, #1 ; set the zero flag if bit 0 is not high yet beq 2b ; loop until bit goes high str r1, [r5] ; write back the 1 just read to clear the bit. b 1b ; continue forever