/*
 * RTC.asm
 *
 * Last Modified: 9/27/2017
 * Author: Dr. Schwartz
 *
 * Use RTC to blink lights on uPAD v1.4 every 1 second.
 * The 3-color LED at the bottom left of the uPAD, labeled D5,
 * uses PortD4, PortD5, and PortD6 for red, green, and blue 
 * LEDs,  respectively.  Note that these LEDs are active-low.
 * See also GPIO_Output.asm.
*/ 

.include "ATxmega128A1Udef.inc"	;ATxmega128A1U definitions file

.EQU	stack_init = 0x3FFF

.equ	BIT0 = 0x01
.equ	BIT654 = 0b01110000
.equ	INV654 = ~(BIT654)
.equ	WHITE = INV654

.org 0x0000			;At reset, PC points to 0x0000
	rjmp MAIN		;Jump to start of program

.org RTC_OVF_vect	;place code at the interrupt vector for the RTC_OVF_vect interrupt
	rjmp RTC_ISR	;relative jump to our interrupt routine

.org 0x200
MAIN:
	ldi R16, low(stack_init)
	out CPU_SPL, R16			;initialize low byte of stack pointer 
	ldi R16, high(stack_init)
	out CPU_SPH, R16			;initialize high byte of stack pointer 

	ldi R16, BIT654			;set all the GPIO's in the 3-colored LED to 
	sts PORTD_DIRSET, R16	;  on PORTD for outputs
	; Notice that the 3 LEDs (RED, GREEN, and BLUE) are all now on, creating white

	ldi	R16, BIT654
	sts PORTD_OUTTGL, R16

	rcall	INIT_RTC
HERE:						;Infinite loop
	rjmp HERE

; **********************
INIT_RTC:
; Below 6 instructions work together to get RTC interrupt every 1s
	ldi	R16, BIT0			;Use defalut ULP (1kHz=32 kHz/32) oscillator, 
	sts	CLK_RTCCTRL, R16	;  Bits3:1=000 for ULP, Enable Clk Bit0=1
; Could slow this down in half by using BIT1 = 0b00000010 instead of above
; Could slow this down in 8th by using BIT10 = 0b00000011 instead of above

; Set period to 0x3FF => 1 second delay. This is **NOT** very accurate
; 0x3FF = 1023 => 1023/ 1kHz = ~1sec 
; (For more precision, 1000 = 0x3E8 => 1sec)
; Change this number to EASILY change the RTC interrupt period
	ldi	R16, 0xFF	;this will give 1023/ 1kHz = ~1sec
;@@	ldi	R16, 0xFF	;@@ this will give 255/ 1kHz = 255ms = 0.255s
	sts	RTC_PER, R16
	ldi	R16, 0x03	;this will give 1023/ 1kHz = ~1sec
;@@	ldi	R16, 0x00 ;@@ this will give 255/ 1kHz = 255ms = 0.255s
	sts	RTC_PER+1, R16
;***********
; Can NOT get internal 32.768kHz oscillator to work
; enable oscillator
;	OSC_CTRL
; wait for osc to be ready
;	OSC_STATUS	
; tried below without above (did not work)
; TAs say that it will work but give 1kHz instead of 32.768kHz 
;	ldi	R16, 0b00001101		;Use internal 32.768kHz oscillator (T=31us)
;	sts	CLK_RTCCTRL, R16	;  Bits3:1=110, Enable Clk Bit0=1
; Set period to 0x7FFF => 1 second delay. This is **NOT** very accurate
; 0x7FFF = 32,768 => 32,768/32.768kHz = 1sec
;	ldi	R16, 0xFF
;	sts	RTC_PER, R16
;	ldi	R16, 0x7F
;	sts	RTC_PER+1, R16
;*************************
	ldi	R16, 0x0			;Set counter value to 0
	sts	RTC_CNT, R16
	ldi	R16, 0x0
	sts	RTC_CNT+1, R16

	ldi R16, 0x01			;Select the overflow interrupt as a  
	sts RTC_INTCTRL, R16	;  low level priority interrupt
	ldi R16, 0x01			;Turn on low level interrupt 
	sts PMIC_CTRL, R16		;  for PMIC

	ldi	R16, 0x01			;No prescaling on RTC clock (1kHz). Do this
	sts RTC_CTRL, R16		;  last!!!

	sei						;Enable global interrupts
	ret
; **********************
RTC_ISR:
	;Always (almost) do next 3 lines at the beginning of ISRs
	push R16				;Always do this at the beginning of ISRs
	lds	R16, CPU_SREG		;Save the status bits
	push R16				;  ...

	ldi	R16, 0x01			; Clear the flag, even if you don't have to
	sts	RTC_INTFLAGS, R16	;   ...
	
; Toggle the LEDs (or change this to another algorithm!)
	ldi	R16, BIT654
	sts PORTD_OUTTGL, R16
		
;Always (almost) do next 4 lines at the end of ISRs
	pop	R16					;Restore the status bits
	sts	CPU_SREG, R16		;  ...
	pop R16
	reti
