zik
Posts: 2
Joined: Wed Jan 09, 2013 2:55 pm

Baking PI: low-power OK4

Wed Jan 09, 2013 6:08 pm

In OK4 we start checking the system timer to get a betting idea when to stop our tight loop.
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

mark_3094
Posts: 74
Joined: Mon Jul 02, 2012 8:38 am
Location: Australia
Contact: Website

Re: Baking PI: low-power OK4

Thu Jan 10, 2013 4:02 am

zik wrote:I'm thinking it would be better to break this into two steps with OK4.1 showing how to add interrupts
I would definitely be interested in learning more about interrupts on the RPi if you were interested in writing a tutorial :)

Return to “Bare metal, Assembly language”