/*******************************************************************************
* Freescale Semiconductor Inc.
* (c) Copyright 2004-2005 Freescale Semiconductor, Inc.
* ALL RIGHTS RESERVED.
********************************************************************************
Services performed by FREESCALE in this matter are performed AS IS and without 
any warranty. CUSTOMER retains the final decision relative to the total design 
and functionality of the end product. FREESCALE neither guarantees nor will be 
held liable by CUSTOMER for the success of this project.
FREESCALE DISCLAIMS ALL WARRANTIES, EXPRESSED, IMPLIED OR STATUTORY INCLUDING, 
BUT NOT LIMITED TO, IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR 
A PARTICULAR PURPOSE ON ANY HARDWARE, SOFTWARE OR ADVISE SUPPLIED TO THE PROJECT
BY FREESCALE, AND OR NAY PRODUCT RESULTING FROM FREESCALE SERVICES. IN NO EVENT
SHALL FREESCALE BE LIABLE FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF
THIS AGREEMENT.

CUSTOMER agrees to hold FREESCALE harmless against any and all claims demands or
actions by anyone on account of any damage, or injury, whether commercial, 
contractual, or tortuous, rising directly or indirectly as a result of an advise
or assistance supplied CUSTOMER in connection with product, services or goods 
supplied under this Agreement.
********************************************************************************
* File      main.c
* Owner     r62780
* Version   1.0
* Date      Oct-4-2010
* Classification   General Business Information
* Brief     COP (Watch Dog) usage example
********************************************************************************
* Detailed Description:
*
* - The SW demonstrates COP watchdog and MCU start after COP reset
*   It uses COP interrupt vector which is called after COP reset and inside the
*   COP interrupt it calls first program function _Startup() => Starts program 
*   from * the beginning
*
*
*  Recomendations: 
*   - Use as low capacitor connected to the reset pin as possible
*   - To see corect behavior disconnect BDM interface from board
*
*
* - tested on: TWR-S12G128
*   - OSCCLK = 8MHz oscillator, BUSCLK = 25MHz set by means of PLL in PEE mode
*   - Reference to documentation: MC9S12GRMV1 Rev.1.01
*
* - Important formulas for PLL setup:
*
*   if ext. oscillator is enabled (OSCE = 1);   fref = fosc / (REFDIV + 1)
*   if ext. oscillator is disabled (OSCE = 0);  fref = fIRC1M
*                                               fvco = 2 * fref * (SYNDIV + 1)
*   if PLL is locked (LOCK = 1);                fpll = fvco / (POSTDIV + 1)
*   if PLL is not locked (LOCK = 0);            fpll = fvco / 4
*   if PLL is selected (PLLSEL = 1);            fbus = fpll / 2
********************************************************************************
Revision History:
Version  Date         Author  Description of Changes
1.0      Aug-29-2011  R62780  Initial version
*******************************************************************************/
#include <hidef.h>           // common defines and macros 
#include "derivative.h"      //derivative-specific definitions 

//******************************************************************************
// Local types definitions
//******************************************************************************
#define     UBYTE       unsigned char
#define     SBYTE                char
#define     UWORD       unsigned  int

//******************************************************************************

#pragma DATA_SEG DEFAULT

//******************************************************************************
// Global variables
//******************************************************************************
static volatile UWORD  j,k,m;               // software delay constant      
//******************************************************************************
#pragma CODE_SEG DEFAULT
//******************************************************************************
// Local functions definitions
//******************************************************************************
void  main(void);
void _Startup(void);
void SetPEEmodeBUSCLK(UBYTE _synr, UBYTE _refdv, UBYTE _postdiv);

#pragma CODE_SEG NON_BANKED
interrupt 2  void COP_Isr(void);
interrupt 28 void PLL_LockIsr(void);
#pragma CODE_SEG DEFAULT

/*******************************************************************************
* Interrupt service routines
*******************************************************************************/
/*******************************************************************************
Function Name : main
Engineer      : R62780
Date          : Aug-29-2011
Parameters    : NONE
Modifies      : NONE
Returns       : NONE
Notes         : Interrupt function from PLL lock bit change.
Issues        : NONE
*******************************************************************************/
#pragma CODE_SEG NON_BANKED
interrupt 28 void PLL_LockIsr(void)
{
  if(CPMUFLG_LOCK == 0)
  {
    //do something here
  }
  else
  {
    //do something here
  }
}
#pragma CODE_SEG DEFAULT
/*******************************************************************************
* Interrupt service routines
*******************************************************************************/
/*******************************************************************************
Function Name : SetPEEmodeBUSCLK
Engineer      : R62780
Date          : Aug-29-2011
Parameters    : UBYTE _synr, UBYTE _refdv, UBYTE _postdiv
Modifies      : NONE
Returns       : NONE
Notes         : Changes BUSCLK
Issues        : NONE
*******************************************************************************/
void SetPEEmodeBUSCLK(UBYTE _synr, UBYTE _refdv, UBYTE _postdiv)
{
  // To enter PEE mode from PEI mode:
  // 1. Configure the PLL for the desired frequency, via the CPMUSYNR, 
  //    CPMUREFDIV and CPMUPOSTDIV registers.
  // 2. Enable the external oscillator bit (OSCE in CPMUOSC register).
  // 3. Wait for UPOSC bit - till the oscillator is qualified by the PLL   
  
  CPMUSYNR    = _synr;
  CPMUREFDIV  = _refdv;
  CPMUPOSTDIV = _postdiv;   
  
  CPMUOSC_OSCE = 1; //enable external oscillator OSCE
    
  while(CPMUFLG_UPOSC == 0);    
}
/*******************************************************************************
Function Name : Main
Engineer      : R62780
Date          : Aug-29-2011
Parameters    : NONE
Modifies      : NONE
Returns       : NONE
Notes         : Present COP reset generation by means of three different
                approaches setupble by means of definition 
                "#define APPROCH x" above.
Issues        : NONE
*******************************************************************************/
#pragma CODE_SEG DEFAULT

void main(void)
{ 
 ECLKCTL_NECLK = 0;  //enable ECLK output (bus clock is visible on pin PB0)

 //--- PLL Initialization ----------------

 //SetPEEmodeBUSCLK(0x58, 0x03, 0x00);   // 25MHz BUSCLK from 4 MHZ oscclk, PEE mode
 //SetPEEmodeBUSCLK(0x58, 0x07, 0x00);   // 25MHz BUSCLK from 8 MHZ oscclk, PEE mode
 SetPEEmodeBUSCLK(0x03, 0x40, 0x00);   // 16MHz BUSCLK from 4 MHZ oscclk, PEE mode
 //SetPEEmodeBUSCLK(0x01, 0x80, 0x00);   // 16MHz BUSCLK from 8 MHZ oscclk, PEE mode
 //SetPEEmodeBUSCLK(0x01, 0x80, 0x07);   // 2MHz BUSCLK from 8 MHZ oscclk, PEE mode
 
 // select clocks
 CPMUCLKS = 0B10000011; // bus = fPLL / 2; COP is clocked from OSCCLK
 if(CPMUCLKS != 0B10000011)
  {
    // After writing CPMUCLKS register, it is strongly recommended to read
    // back CPMUCLKS register to make sure that write of PLLSEL,
    // RTIOSCSEL, COPOSCSEL0 and COPOSCSEL1 was successful.
  }
 
 // We can enable the interrupt which will be requested whenever LOCKIF is set
 // LOCKIF interrupt flag is set whenever the LOCK status bit has been changed  
 // CPMUFLG_LOCKIF = 1;   //clear flag
 // CPMUINT_LOCKIE = 1;   //enable interrupt 

 //--- Enable I-bit maskable interrupts --
 // EnableInterrupts;


 //--- Visualize start of main routine ---
 DDRT  = 0xF0;                            // PTT4~7 as output
 PTT   = 0x00;                            // switch on the diodes

 //--------------------------------------
 
 PTT=0xF0;
 CPMUCOP = 0x44;  // period 2^20*oscclk=0,262144 @ 4MHz OSCCLK, freeze COP in active BDM
 
 while(1);  // wait while COP reset


// for(;;)
//  {
//    CPMUARMCOP=0x55; CPMUARMCOP=0xAA; // or  _FEED_COP();  // kick the dog
// 
//  }
 //--------------------------------------
}
//******************************************************************************
// WATCH DOG ISR
//******************************************************************************
#pragma CODE_SEG NON_BANKED

interrupt 2 void COP_Isr(void)
{
  // WARNING: used variables "j" an "k" have to be a global or static
  // Note 1: port has to be set as an output again, since MCU was in reset 
  // Note 2: !!! stack pointer is not set after reset => any using stack before
  //         initialization can cause program crash 
  //         (made inside the function _Startup)
  // Note 3: Be aware that all registers are set to the RESET status. The RAM 
  //         remains unchanged.

  //--- Visualize COP reset on the port B diodes ---
  // Note that you have to set the port as output, since MCU was in reset 
  
  DDRT = 0xF0;               // PTT4~7 as output 
  PTT  = 0xA0;               // set LEDs

  for (j = 0;j < 0x20;j++)   // wait to be able to recognize reset on the diodes
   { 
     for(k=0;k<0xFFFF;k++) asm (nop); // SW delay
   	 PTT= (~PTT) & 0xE0;
   }	                                      

  //--------------------------------------------
  // run the program from the beginning                                      
  // startup code of the CodeWarrior S12 environment: void _Startup(void)    
  // located in the file Start12.c -> project tree directory: Startup Code   

  // you can us either this code (better solution)
  asm JMP _Startup;     // this code jumps to the _Startup
  // or this code
  // _Startup();        // this code leaves one address on the stack which
                        // has to be set because
                        // its value is unknown after reset
}
#pragma CODE_SEG DEFAULT
//******************************************************************************
/*
 We are testing the Software in Freescale evaluation board, still we didnt get the
 correct COP time out.

 Following cfg done for S12G128 micro - 8MHz OSCLK and 16MHz Bus clock.

 During startup sequence, setting CPMUCOP = (B_RSBCK|B_CR2)
 Again during write once call, setting CPMUCOP = (B_RSBCK|B_CR2)

 PLL wait loop is coded as below



    R_CPMUOSC |= (UINT8)B_OSCE;                             \

    do                                                      \
      {
    
       if ((R_CPMUFLG & (UINT8)B_LOCK) == (UINT8)B_LOCK)    \
        {                                                   \
          // select the PLL as system clock                 \
          R_CPMUCLKS |= (UINT8)(B_PLLSEL|B_COPOSCSEL0);
        }                                                   \
    
      }
    while ( (R_CPMUFLG & (UINT8)B_UPOSC)!=(UINT8)B_UPOSC);  \
    
    R_CPMUFLG = 0xff;                                       \
    R_CPMUCLKS |= (B_COPOSCSEL0|B_RTIOSCSEL);

 
 
 When the  CPMUCOP register is loaded twice, B_COPOSCSEL0 bit is not set in the R_CPMUCLKS.
 Could you please provide your comments for this? Will there any impact if CPMUCOP is set twice?
 When CPMUCOP register is loaded once, B_COPOSCSEL0 bit is set in the R_CPMUCLKS.
*/
















