/* External_Interrupt.asm
 *
 * Modified: 12 Feb 2026
 * 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 uPAD) 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 YL, low(stack_init)
	out CPU_SPL, YL
	ldi YL, high(stack_init)
	out CPU_SPH, YL

;Clear two counters in r18 and r19
	clr r18
	ldi r19, 0

;Call subroutine to initialize the interrupt
	rcall INIT_INTERRUPT	
	nop

;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
	sts PORTD_INTCTRL, r16
;Better would be below
;	ldi	r16, PORT_INT1LVL_OFF_gc | PORT_INT0LVL_MED_gc
;	sts PORTD_INTCTRL, r16

;Select LOW level pin for external interrupt (not rising edge, 
;  falling edge, or any edge)
	ldi	r16, BIT10			
;Above probably inappropriately cleared pins 7, 5, 4, 3. Below better!
;Sets it for low level pin ISC (and default OPC)
;	ldi r16, PORT_ISC_LEVEL_gc | PORT_OPC_TOTEM_gc ; do not enable SRLEN or INVEN
	sts	PORTD_PIN0CTRL, r16	;  

;Turn on medium level interrupts (in PMIC_CTRL)
	ldi r16, BIT1			; PMIC_MEDLVLEX_bm
	sts PMIC_CTRL, r16		;
;Also effected pins 7-1	
; bit 0 is LOLVLEX, bit 1 MEDLVLEX, bit 2 has HILVLEX, bit 7 has NMIEX

;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:
;	"push CPU_SREG"	;not needed since routine where interrupt can happen uses no flages
	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
