Skip to content

Instantly share code, notes, and snippets.

@osvein
Last active September 17, 2020 08:25
Show Gist options
  • Select an option

  • Save osvein/e5e0cb4693dea5dbf11492028026f239 to your computer and use it in GitHub Desktop.

Select an option

Save osvein/e5e0cb4693dea5dbf11492028026f239 to your computer and use it in GitHub Desktop.
// Various useful I/O addresses and definitions for EFM32GG
// GPIO
GPIO_PA_BASE = 0x40006000
GPIO_PB_BASE = 0x40006024
GPIO_PC_BASE = 0x40006048
GPIO_PD_BASE = 0x4000606c
GPIO_PE_BASE = 0x40006090
GPIO_PF_BASE = 0x400060b4
// register offsets from base address
GPIO_CTRL = 0x00
GPIO_MODEL = 0x04
GPIO_MODEH = 0x08
GPIO_DOUT = 0x0c
GPIO_DOUTSET = 0x10
GPIO_DOUTCLR = 0x14
GPIO_DOUTTGL = 0x18
GPIO_DIN = 0x1c
GPIO_PINLOCKN = 0x20
GPIO_BASE = 0x40006100
// register offsets from base address
GPIO_EXTIPSELL = 0x00
GPIO_EXTIPSELH = 0x04
GPIO_EXTIRISE = 0x08
GPIO_EXTIFALL = 0x0c
GPIO_IEN = 0x10
GPIO_IF = 0x14
GPIO_IFC = 0x1c
// CMU
CMU_BASE = 0x400c8000
CMU_HFPERCLKDIV = 0x008
CMU_OSCENCMD = 0x020
CMU_OSCENCMD_LFRCOEN = 6
CMU_LFCLKSEL = 0x028
CMU_LFCLKSEL_LFAE = 16
CMU_HFCORECLKEN0 = 0x040
CMU_HFCORECLKEN0_LE = 4
CMU_HFPERCLKEN0 = 0x044
CMU_HFPERCLKEN0_GPIO = 13
CMU_LFACLKEN = 0x058
CMU_LFACLKEN_RTC = 1
// NVIC
ISER0 = 0xe000e100
ISER1 = 0xe000e104
ICER0 = 0xe000e180
ICER1 = 0xe000e184
ISPR0 = 0xe000e200
ISPR1 = 0xe000e204
ICPR0 = 0xe000e280
ICPR1 = 0xe000e284
IABR0 = 0xe000e300
IABR1 = 0xe000e304
IPR_BASE = 0xe000e400
IPR0 = 0x00
IPR1 = 0x04
IPR2 = 0x08
IPR3 = 0x0c
// EMU
EMU_BASE = 0x400c6000
EMU_CTRL = 0x000
// System Control Block
SCR = 0xe000ed10
AIRCR = 0xe000ed0c
// RTC
RTC_BASE = 0x40080000
RTC_CTRL = 0x000
RTC_CNT = 0x004
RTC_COMP0 = 0x008
RTC_IFC = 0x018
RTC_IEN = 0x01C
// DELAY is multiplied by 1-1/2^DELAY_MUL each bounce
DELAY = 10000
DELAY_MUL = 3
LEDMASK = 0xFF00
// player button masks
P1BTN = 0x0F
P2BTN = 0xF0
// player LED masks
P1LED = 1<<8
P2LED = 1<<15
.syntax unified
.include "efm32gg.s"
// Exception vector table
.section .vectors
.long stack_top // Top of Stack
.long _reset // Reset Handler
.long dummy_handler // NMI Handler
.long dummy_handler // Hard Fault Handler
.long dummy_handler // MPU Fault Handler
.long dummy_handler // Bus Fault Handler
.long dummy_handler // Usage Fault Handler
.long dummy_handler // Reserved
.long dummy_handler // Reserved
.long dummy_handler // Reserved
.long dummy_handler // Reserved
.long dummy_handler // SVCall Handler
.long dummy_handler // Debug Monitor Handler
.long dummy_handler // Reserved
.long dummy_handler // PendSV Handler
.long dummy_handler // SysTick Handler
// External Interrupts
.long dummy_handler
.long gpio_handler // GPIO even handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long gpio_handler // GPIO odd handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long rtc_handler // RTC handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.section .text
.globl _reset
.type _reset, %function
.thumb_func
_reset:
// enable GPIO and RTC clocks in CMU
// configure RTC to use ULFRCO for deeper sleep
ldr r0, =CMU_BASE
ldr r1, [r0, #CMU_HFCORECLKEN0]
orr r1, #1<<CMU_HFCORECLKEN0_LE
str r1, [r0, #CMU_HFCORECLKEN0]
ldr r1, [r0, #CMU_HFPERCLKEN0]
orr r1, #1<<CMU_HFPERCLKEN0_GPIO
str r1, [r0, #CMU_HFPERCLKEN0]
ldr r1, [r0, #CMU_LFCLKSEL]
orr r1, #1<<CMU_LFCLKSEL_LFAE
str r1, [r0, #CMU_LFCLKSEL]
ldr r1, [r0, #CMU_LFACLKEN]
orr r1, #1<<CMU_LFACLKEN_RTC
str r1, [r0, #CMU_LFACLKEN]
mov r1, #1<<CMU_OSCENCMD_LFRCOEN
str r1, [r0, #CMU_OSCENCMD]
// configure button GPIO input
ldr r0, =GPIO_PC_BASE
ldr r1, =0x33333333
str r1, [r0, #GPIO_MODEL]
ldr r1, =0xFF
str r1, [r0, #GPIO_DOUT]
// short delay to avoid pull-down triggering interrupt
ldr r0, =0x00100000
0: subs r0, #1
bne 0b
// configure button GPIO interrupt
ldr r0, =GPIO_BASE
ldr r1, =0x22222222
str r1, [r0, #GPIO_EXTIPSELL]
ldr r1, =0xFF
str r1, [r0, #GPIO_EXTIFALL]
str r1, [r0, #GPIO_IEN]
/* configure LED GPIO output
* only a single LED will be lit at a time
* the light will be rotated around
*/
ldr r0, =GPIO_PA_BASE
ldr r1, =0x2
str r1, [r0, #GPIO_CTRL]
ldr r1, =0x55555555
str r1, [r0, #GPIO_MODEH]
ldr r1, =LEDMASK & ~(1<<8) // leftmost LED on, rest off
str r1, [r0, #GPIO_DOUT]
// configure RTC (interrupt on COMP0)
ldr r0, =RTC_BASE
ldr r1, =DELAY
str r1, [r0, #RTC_COMP0]
ldr r1, =2
str r1, [r0, #RTC_IEN]
/* global direction state register
* 1 = left-to-right, 31 = right-to-left
* used to right-rotate LED register
* (right-rotating by 31 is equivalent to left-rotating by 1)
*/
ldr r4, =1
// enable interrupts
ldr r0, =ISER0
ldr r1, =(1<<30) | (1<<11) | (1<<1)
str r1, [r0]
// sleep
ldr r0, =SCR
ldr r1, =6
str r1, [r0]
wfi
b .
.thumb_func
gpio_handler:
// enable RTC to start the game, in case it's not already started
ldr r0, =RTC_BASE
ldr r1, =(1<<2) | (1<<0)
str r1, [r0, #RTC_CTRL]
// set PnLED in r2 if player n lost (n = 1,2)
ldr r0, =GPIO_BASE
ldr r1, [r0, #GPIO_IF]
ldr r0, =GPIO_PA_BASE
ldr r2, [r0, #GPIO_DOUT]
eor r2, #LEDMASK
ands r3, r1, #P1BTN
it ne
eorne r2, #P1LED
ands r3, r1, #P2BTN
it ne
eorne r2, #P2LED
cbnz r2, lose
// debounce buttons by disabling GPIO interrupt until next RTC tick
ldr r0, =GPIO_BASE
ldr r3, =0
str r3, [r0, #GPIO_IEN]
// increase speed
eor r4, #30
ldr r0, =RTC_BASE
ldr r1, =0
str r1, [r0, #RTC_CNT]
ldr r1, [r0, #RTC_COMP0]
sub r1, r1, r1, LSR #DELAY_MUL // r1 -= r1 * 1/2^DELAY_MUL
str r1, [r0, #RTC_COMP0]
bx lr
.thumb_func
rtc_handler:
ldr r0, =RTC_BASE
ldr r1, =7
str r1, [r0, #RTC_IFC]
// re-enable GPIO interrupt
ldr r0, =GPIO_BASE
ldr r1, =0xFF
str r1, [r0, #GPIO_IFC]
str r1, [r0, #GPIO_IEN]
// rotate LED register
ldr r0, =GPIO_PA_BASE
ldr r1, [r0, #GPIO_DOUT]
orn r1, #LEDMASK
ror r1, r1, r4
and r1, #LEDMASK
str r1, [r0, #GPIO_DOUT]
// somebody loses if the light was rotated out one of the sides
eors r1, #LEDMASK
beq lose
bx lr
lose:
// software reset
ldr r0, =AIRCR
ldr r1, =(0x5FA<<16) | (1<<2)
str r1, [r0]
b .
.thumb_func
dummy_handler:
b .
.syntax unified
.include "efm32gg.s"
// Exception vector table
.section .vectors
.long stack_top /* Top of Stack */
.long _reset/* Reset Handler */
.long dummy_handler /* NMI Handler*/
.long dummy_handler /* Hard Fault Handler */
.long dummy_handler /* MPU Fault Handler*/
.long dummy_handler /* Bus Fault Handler*/
.long dummy_handler /* Usage Fault Handler */
.long dummy_handler /* Reserved */
.long dummy_handler /* Reserved */
.long dummy_handler /* Reserved */
.long dummy_handler /* Reserved */
.long dummy_handler /* SVCall Handler */
.long dummy_handler /* Debug Monitor Handler */
.long dummy_handler /* Reserved */
.long dummy_handler /* PendSV Handler */
.long dummy_handler /* SysTick Handler */
/* External Interrupts */
.long dummy_handler
.long gpio_handler/* GPIO even handler */
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long gpio_handler/* GPIO odd handler */
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.section .text
cmu_base: .long CMU_BASE
gpio_pa_base: .long GPIO_PA_BASE
gpio_pc_base: .long GPIO_PC_BASE
gpio_base: .long GPIO_BASE
iser0: .long ISER0
scr: .long SCR
.globl _reset
.type _reset, %function
.thumb_func
_reset:
// enable GPIO clock in CMU
ldr r1, cmu_base
ldr r2, [r1, #CMU_HFPERCLKEN0]
orr r2, #1<<CMU_HFPERCLKEN0_GPIO
str r2, [r1, #CMU_HFPERCLKEN0]
// configure LED GPIO output
ldr r1, gpio_pa_base
mov r2, #0x2
str r2, [r1, #GPIO_CTRL]
mov r2, #0x55555555
str r2, [r1, #GPIO_MODEH]
// configure button GPIO input
ldr r1, gpio_pc_base
mov r2, #0x33333333
str r2, [r1, #GPIO_MODEL]
mov r2, #0xFF
str r2, [r1, #GPIO_DOUT]
// configure button GPIO interrupt
ldr r1, gpio_base
mov r2, #0x22222222
str r2, [r1, #GPIO_EXTIPSELL]
mov r2, #0xFF
str r2, [r1, #GPIO_EXTIFALL]
str r2, [r1, #GPIO_EXTIRISE]
str r2, [r1, #GPIO_IEN]
ldr r1, iser0
mov r2, #(1<<1)|(1<<11)
str r2, [r1]
ldr r1, scr
mov r2, #6
str r2, [r1]
wfi
b .
// The CPU will jump here when there is a GPIO interrupt
.thumb_func
gpio_handler:
// read button GPIO input
ldr r1, gpio_pc_base
ldr r2, [r1, #GPIO_DIN]
lsl r2, #8
// write LED GPIO output
ldr r1, gpio_pa_base
str r2, [r1, #GPIO_DOUT]
// clear interrupt flags
ldr r1, gpio_base
mov r2, #0xFF
str r2, [r1, #GPIO_IFC]
bx lr
.thumb_func
dummy_handler:
b .
.syntax unified
.include "efm32gg.s"
// Exception vector table
.section .vectors
.long stack_top /* Top of Stack */
.long _reset/* Reset Handler */
.long dummy_handler /* NMI Handler*/
.long dummy_handler /* Hard Fault Handler */
.long dummy_handler /* MPU Fault Handler*/
.long dummy_handler /* Bus Fault Handler*/
.long dummy_handler /* Usage Fault Handler */
.long dummy_handler /* Reserved */
.long dummy_handler /* Reserved */
.long dummy_handler /* Reserved */
.long dummy_handler /* Reserved */
.long dummy_handler /* SVCall Handler */
.long dummy_handler /* Debug Monitor Handler */
.long dummy_handler /* Reserved */
.long dummy_handler /* PendSV Handler */
.long dummy_handler /* SysTick Handler */
/* External Interrupts */
.long dummy_handler
.long gpio_handler/* GPIO even handler */
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long gpio_handler/* GPIO odd handler */
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.long dummy_handler
.section .text
.globl _reset
.type _reset, %function
.thumb_func
_reset:
// enable GPIO clock in CMU
ldr r1, 0f
0: .long CMU_BASE
ldr r2, [r1, #CMU_HFPERCLKEN0]
orr r2, #1<<CMU_HFPERCLKEN0_GPIO
str r2, [r1, #CMU_HFPERCLKEN0]
// configure LED GPIO output
ldr r1, 0f
0: .long GPIO_PA_BASE
mov r2, 0x2
str r2, [r1, #GPIO_CTRL]
mov r2, 0x55555555
str r2, [r1, #GPIO_MODEH]
// configure button GPIO output
ldr r2, 0f
0: .long GPIO_PC_BASE
mov r3, 0x33333333
str r3, [r2, #GPIO_MODEL]
mov r3, 0xFF
str r3, [r2, #GPIO_DOUT]
// main loop
loop:
ldr r3, [r2, #GPIO_DIN]
lsl r3, #8
str r3, [r1, #GPIO_DOUT]
b loop
// The CPU will jump here when there is a GPIO interrupt
.thumb_func
gpio_handler:
b .
.thumb_func
dummy_handler:
b .
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment