/* External_Interrupt.asm
 *
 * Modified: 17 Sept 2024
 * Author: Dr. Schwartz
 * 
 * This program will generate an external interrupt on a
 * medium level input on PD0.
 * For demonstration, use the following Watch: 
 *   *(char*)PortD_IN
 * Use simulator (or board) to demonstrate.
 * Use F5 (NOT F11, i.e., do NOT single step) and pause,
 *   changing the value of PD0 as follows (put breakpoints at
 *   first line of MAIN, rjmp LOOP, and nop in ISR.
 * In IO View, use PORTD
 *      If PD0 is a 0, should get an interrupt. 
 *      If PD0 is a 1, should NOT get an interrupt.
 */ 
 .include "ATxmega128A1Udef.inc"
;******************************INITIALIZATIONS***************************************
.equ Bit0 = 0b00000001
.equ Bit1 = 0b00000010
.equ BIT10 = 0b00000011
.equ INV760 = 0b00111110	;Not used

.equ stack_init = 0x3FFF	

.org 0x0000
	rjmp MAIN

; Place code at the interrupt vector for PORTD_INT0 interrupt & jump to ISR
.org PORTD_INT0_vect
	rjmp EXT_INTR_ISR

; org program at 0x200 so we don't overwrite interrupt vectors at 0x0000-0x00FE
.org 0x0200		
MAIN:
;Inialize stack pointer
	ldi r16, low(stack_init)
	out CPU_SPL, r16
	ldi r16, high(stack_init)
	out CPU_SPH, r16

;Clear two counters in r18 and r19
	clr r18
	ldi r19, 0

;Call subroutine to initialize the interrupt
	rcall INIT_INTERRUPT	

;Loop forver while our interrupt fires
LOOP:
	inc  r19
 	rjmp LOOP

/************************************************************************************
* Name:     INIT_INTERRUPT
* Purpose:  Subroutine to initialize the PortD external pin interrupt PD0 using INT0
* Inputs:   None			 
* Outputs:  None
* Affected: r16, PMIC_CTRL, PORTD: _INT0MASK, _DIRCLR, _INTCTRL, _PIN0CTRL
 ***********************************************************************************/
INIT_INTERRUPT:
;Select PD0 as the interrupt source (PORTD_INT0MASK)
	ldi r16,BIT0
	sts PORTD_INT0MASK, r16

;Set external interrupt pin (PD0) as an input
	sts PORTD_DIRCLR, r16

;Select the external interrupt as a medium level priority interrupt 
;	Probably inappropriately cleared the INT1 interrupt level pins 
;	ldi r16, BIT1
	ldi r16, PORT_INT0LVL_MED_gc | PORT_INT1LVL_OFF_gc
	sts PORTD_INTCTRL, r16

;Select LOW level pin for external interrupt (not rising edge, 
;  falling edge, or any edge)
;	ldi r16, BIT10
	ldi r16, PORT_ISC_LEVEL_gc | PORT_OPC_TOTEM_gc
	sts PORTD_PIN0CTRL, r16

;Turn on medium level interrupts (in PMIC_CTRL)
;	ldi r16, BIT1
	ldi r16, PMIC_MEDLVLEX_bm
	sts PMIC_CTRL, r16

;Turn on the global interrupt enable LAST! 
	sei

	ret
/************************************************************************************
* Name:     EXT_INTR_ISR
* Purpose:  Interrupt service routine to deal with the PortD external 
*           pin interrupt PD0 when low.  Do NOT need to clear the interrupt flag,
*           but "it can't hurt!"
* Inputs:   r18
* Outputs:  r18
* Affected: PORTD_INTFLAGS
 ***********************************************************************************/
EXT_INTR_ISR:
;Below push not needed since routine where interrupt can happen uses no flags
;	push CPU_SREG

	push r17
	nop			;dummy instruction to set a breakpoint	
	inc  r18

; Clear the PORTD_INTFLAGS (bit 0)
	ldi r17, BIT0 ; PORT_INT0IF_bm
	sts PORTD_INTFLAGS, r17

	pop  r17
;	pop CPU_SREG

	reti		;return from the interrupt routine
