@ Assignment 2 - Group 36
@ Pavlo Kostianov
@ Neil Lawrence
@ Conor McCarthy
@ Shuban Thoppe
@ Oliver Mitchell
#include "hardware/regs/addressmap.h"
#include "hardware/regs/io_bank0.h"
#include "hardware/regs/m0plus.h"
#include "hardware/regs/timer.h"
.syntax unified
.cpu cortex-m0plus
.thumb
.global main_asm
.align 4
.equ RISING_EDGE_MASK, 0x00800000 @ Bit-22 for falling-edge event on GP21
.equ FALLING_EDGE_MASK, 0x00400000 @ Bit-23 for rising-edge event on GP21
.equ GPIO_ISR_OFFSET, 0x74 @ GPIO is int #13 (vector table entry 29)
.equ GPIO_BTN, 21 @ Specify pin for the button
.equ GPIO_DIR_IN, 0 @ Specify input direction for a GPIO pin
.equ GPIO_DIR_OUT, 1 @ Specify output direction for a GPIO pin
@ Import C functions
.extern dot
.extern dash
.extern blank
@ Entry point to the ASM portion of the program
main_asm:
@ Install the GPIO and alarm ISRs
bl install_gpio_isr @ Call the subroutine to install the GPIO ISR
@ Initialize button
movs r0, #GPIO_BTN @ Load pin number
bl asm_gpio_init @ Call the subroutine to initialise the GPIO pin specified by r0
movs r0, #GPIO_BTN @ Load pin number
movs r1, #GPIO_DIR_IN @ Load input direction for the pin
bl asm_gpio_set_dir @ Set GP21 as input
@ Enable button interrupts for both edges
movs r0, #GPIO_BTN @ Load GP21 pin number
bl asm_gpio_set_irq_fall @ Enable falling-edge interrupt
movs r0, #GPIO_BTN @ Load GP21 pin number
bl asm_gpio_set_irq_rise @ Enable rising-edge interrupt
@start watchdog
bl asm_watchdog_init
@ Load r5 with sentinel to check if empty later
ldr r5, =0xFFFFFFFF
main_loop:
wfi @ Wait for interrupt
b main_loop @ Create infinite loop
@ Install the GPIO ISR
install_gpio_isr:
ldr r2, =(PPB_BASE + M0PLUS_VTOR_OFFSET)
ldr r1, [r2] @ Get vector table address
adds r1, #GPIO_ISR_OFFSET @ Calculate GPIO ISR offset
ldr r0, =gpio_isr @ Load GPIO ISR address
str r0, [r1] @ Store GPIO ISR address
ldr r2, =(PPB_BASE + M0PLUS_NVIC_ICPR_OFFSET)
movs r1, #1
lsls r1, #13 @ GPIO is IRQ13
str r1, [r2] @ Clear pending GPIO interrupt
ldr r2, =(PPB_BASE + M0PLUS_NVIC_ISER_OFFSET)
str r1, [r2] @ Enable GPIO interrupt
bx lr @ Return
@ GPIO ISR
.thumb_func
gpio_isr:
push {lr}
ldr r0, =(IO_BANK0_BASE + IO_BANK0_PROC0_INTS2_OFFSET)
ldr r0, [r0] @ Read interrupt status
movs r1, r0
movs r0, r1
ldr r2, =FALLING_EDGE_MASK
ands r0, r2
cmp r0, #0
bne button_pressed @ Handle button press
movs r0, r1
ldr r2, =RISING_EDGE_MASK
ands r0, r2
cmp r0, #0
bne button_released @ Handle button release
b end_button_check
button_pressed:
@ reset watchdog
bl asm_watchdog_reset
@ Store press timestamp
ldr r3, =(TIMER_BASE + TIMER_TIMELR_OFFSET)
ldr r4, [r3] @ r4 holds press time
@ Check if release happened before
ldr r1, =FALLING_EDGE_MASK
ldr r0, =0xFFFFFFFF
cmp r5, r0 @ Compare register with sentinel
beq end_button_check @ Exit if empty
@ Calculate release duration
subs r5, r4, r5 @ r5 = press - release
ldr r1, =BLANK_TIME
ldr r1, [r1]
cmp r1, r5
blo blank_press
ldr r1, =FALLING_EDGE_MASK
b end_button_check
blank_press:
bl blank
ldr r1, =FALLING_EDGE_MASK
b end_button_check
button_released:
@ Store release timestamp
ldr r3, =(TIMER_BASE + TIMER_TIMELR_OFFSET)
ldr r5, [r3] @ r5 holds release time
@ Calculate press duration
subs r4, r5, r4 @ r4 = release - press
ldr r1, =DASH_TIME
ldr r1, [r1]
cmp r4, r1
blo dot_press
bl dash
ldr r1, =RISING_EDGE_MASK
b end_button_check
dot_press:
bl dot
ldr r1, =RISING_EDGE_MASK
end_button_check:
ldr r0, =(IO_BANK0_BASE + IO_BANK0_INTR2_OFFSET)
str r1, [r0] @ Clear pending interrupt
pop {pc} @ Return
.align 4