/* main.c - timer interrupt example for Dragon12-Plus
 * Copyright 2008 Colin D. Bennett <colin@gibibit.com>.
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * This program uses the timer overflow interrupt to cycle the LEDs 
 * on the Dragon12 board. The main program just has an infinite loop
 * with a "WAI" (enter wait mode) instruction in it, which puts
 * the 68HC12 MCU to sleep until an interrupt wakes it up.
 */

#include "hc12/hcs12.h"
#include "hc12/vectors12.h"
#include "hc12/interrupt.h"

/* Timer overflow ISR function needs to be declared 
 * so it can be referenced in main(). */
DECLARE_ISR(timer_ovf_isr);

int main(void)
{
	disable_interrupts();  // Globally disable interrupts while setting up.

	/*** Configure LEDs. ***/
	DDRB = 0xFF;   // Set port B to output for LEDs (PB7:0 are LED anodes).
	DDRJ = 0xFF;   // Set port J to output, so we can enable LEDs w/ PJ1.
	PTJ = 0;       // Pull PJ1 low to enable LEDs.
	DDRP = 0xFF;   // Set port P to output, (to turn off 7-seg display).
	PTP = 0xFF;    // PP3:0 are 7-segment common cathodes: turn them off.

	PORTB = 1;     // Initially light up PB0 LED.
	/* Every time the timer overflow ISR is called, 
	 * it will rotate the PORTB value to the left. */

	/*** Configure timer. ***/
	/* Prescale bits: See the 68HC12 manual for a list of options. */
	/* timer freq = 24 MHz / 32 = 0.75 MHz
	 *  => overflow freq = 750 000 cycles/s * (1 overflow / 65 536 cycles)
	 *  => overflow freq ~= 11.4441 s^-1 */
	const uint8_t prescale = 5;  // Prescale: ECLK/32.

	TSCR |= TEN;   // Set bit 7 of TSCR, timer enable (TEN).
	/* Enable timer overflow interrupt, and set TCNT prescale: */
	TMSK2 = TOI | prescale;  
	TFLG2 |= TOF;

	/* Set the interrupt vector to point to our interrupt service routine. */
	SET_INTERRUPT_VECTOR(UserTimerOvf, &timer_ovf_isr);
	enable_interrupts();    // Finally enable the interrupts.

	// Infinite loop -- the real work is in the timer_ovf_isr.
	while (1)
	{
		wait();    // Sleep until timer interrupt occurs.
		/* When the timer overflow interrupt is triggered by the timer
		 * module, the interrupt handler for UserTimerOvf is called,
		 * then the wait() call returns because the WAI machine instruction
		 * wakes up when the interrupt occurs. We simply go back to 
		 * sleep, however. */
	}
}

/* Define the timer overflow interrupt service routine. */
ISR(timer_ovf_isr)
{
	uint8_t x = PORTB;
	PORTB = (x << 1) | ((x & 0x80) >> 7);  // rotate PORTB value left
	TFLG2 |= TOF;   // clear timer overflow flag by writing a 1 to the TOF bit
}

