I thought this was a disappointing place to leave it.
This code adds an interrupt to the timer and drops to low-power until it's time to change the LED.
I'm thinking it would be better to break this into two steps with OK4.1 showing how to add interrupts and OK4.2 replacing the tight loop with a wait-for-interrupt.
Code: Select all
.equ INTERVAL, 500000 @ .5 seconds .equ CLOCK_BASE, 0x20003000 .equ CSTATUS, 0x00000000 .equ CLO, 0x00000004 .equ C3, 0x00000018 .equ IRQ_BASE, 0x2000B000 .equ IRQPEND1, 0x00000204 .equ IRQEN1, 0x00000210 .equ GPIO_BASE,0x20200000 .equ GPFSEL1, 0x00000004 .equ GPSET0, 0x0000001C .equ GPCLR0, 0x00000028 @ declare the purpose of several registers Rgpio .req r1 Rirq .req r2 Rclock .req r3 Rled .req r4 @ LED status register: 0 = off, 1 = on. Rinterval .req r5 .section .init, "ax" .code 32 @ vector table b reset_handler @ reset b . @ undef b . @ swi b . @ prefetch_abort b . @ data_abort b . @ unused b irq_handler @ irq b . @ fiq irq_handler: subs pc,lr,#4 @ do nothing but break out of sleep state reset_handler: @ initialize registers with base pointers and other values ldr Rgpio, gpio_base ldr Rclock, clock_base ldr Rirq, irq_base ldr Rinterval, interval mov Rled, #0x1 @ make the gpio pin tied to the led an output without changing the @ settings of the other pins @ settings for pin 16 are stored in bits 18-20 of GPIO function select reg 1 ldr r0, [Rgpio, #GPFSEL1] @ get the settings for the register with pin 16 bic r0, r0, #0x001C0000 @ clear the settings for pin 16 orr r0, r0, #0x00040000 @ make pin 16 an output str r0, [Rgpio, #GPFSEL1] @ save the settings mov r0, #0x00010000 @ turn the LED: str r0, [Rgpio, #GPCLR0] @ on @ set up the timer interrupt ldr r0, [Rclock, #CLO] @ get the current time add r0, r0, Rinterval @ increment by an interval str r0, [Rclock, #C3] @ set timer 3 mov r0, #0x8 @ clear match on timer 3 and corresponding irq str r0, [Rclock, #CSTATUS] str r0, [Rirq, #IRQEN1] @ enable irq3 loop: mov r0,#0 @ r0 Should Be Zero (sbz) for the WFI call mcr p15,0,r0,c7,c0,4 @ Wait For Interrupt @ something woke us up. check if it was our timer and irq3 ldr r0, [Rirq, #IRQPEND1] @ get pending interrupts 0-31 tst r0, #0x8 @ check if irq3 is set beq loop @ no? go back to sleep @ our timer woke us up mov r0, #0x8 @ clear match on timer 3 and corresponding irq str r0, [Rclock, #CSTATUS] @ change the LED mov r0, #0x00010000 @ turn the LED: tst Rled, #0x1 strne r0, [Rgpio, #GPSET0] @ off streq r0, [Rgpio, #GPCLR0] @ on eor Rled, Rled, #0x1 @ remember state of LED @ set the new time to wake up ldr r0, [Rclock, #CLO] @ get the current time add r0, r0, Rinterval @ calculate time to wake up str r0, [Rclock, #C3] @ set timer 3 b loop clock_base: .word CLOCK_BASE irq_base: .word IRQ_BASE gpio_base: .word GPIO_BASE interval: .word INTERVAL