/*******************************************************************************
* 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      Nov-7-2011
* Classification   General Business Information
* Brief     EEPROM usage example
********************************************************************************
* Detailed Description:
*
* - The SW demonstrates EEPRO ERASE/WRITE functions
*
* - tested on: TWR-S12GN32
*   - OSCCLK = 8MHz oscillator, BUSCLK = 16MHz set by means of PLL in PEE mode
*   - Reference to documentation: MC9S12GRMV1 Rev.1.01
*
*
********************************************************************************
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 */
//******************************************************************************

#define EEPROM_START    0x000400 
#define EEPROM_END      0x0007FF
#define EEPROM_SECTOR   0x04


#define OK          0
#define ERASED      1
#define NON_ERASED  2
#define MISALIGNED_ADDRESS  3
#define ACCESS_ERROR        4
#define VERIFICATION_FAILED 5
#define LENGTH_OUT_OF_RANGE 6


//******************************************************************************
void SetPEEmodeBUSCLK(byte _synr, byte _refdv, byte _postdiv);

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

byte EEPROM_Erase_Verify_Section(word address, word number_of_words);
byte EEPROM_Program(word int address, word *ptr, byte number_of_words);
byte EEPROM_Erase_Sector(word int address);
word EEPROM_Read_Word(word int address);
void EEPROM_Init(byte fdiv);

word buf[4] = {0xAABB, 0xCCDD, 0x1122, 0x3344};
byte err;
//******************************************************************************
// PLL Lock Isr
//******************************************************************************
#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
//******************************************************************************
// void SetPEEmodeBUSCLK(byte _synr, byte _refdv, byte _postdiv)
//******************************************************************************
void SetPEEmodeBUSCLK(byte _synr, byte _refdv, byte _postdiv)
{
 CPMUSYNR    = _synr;
 CPMUREFDIV  = _refdv;
 CPMUPOSTDIV = _postdiv;   
  
 CPMUOSC_OSCE = 1; //enable external oscillator OSCE
    
 while(!CPMUFLG_UPOSC)
  {// you can check for timeot here with error message report
  };    
 while(!CPMUFLG_LOCK)
  {// you can check for timeot here with error message report
  };    
 
  //--- 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,
     asm nop;                             // RTIOSCSEL, COPOSCSEL0 and COPOSCSEL1 was successful.
  }
 //--------------------------------------
}
//******************************************************************************
//EEPROM Send_Command
//******************************************************************************
//this function is stored in RAM memory
//in C language:
//  {
//    FSTAT_CCIF = 1;         //launch command
//    while(FSTAT_CCIF == 0); //wait for done
//  }
static byte Send_Command[]=
{
  0x1C, 0x01, 0x06, 0x80, 0x1F, 0x01, 0x06, 0x80, 0xFB, 0x3D
};
//******************************************************************************
void main(void) 
{
  unsigned int addr;

  //--- 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
  
  ECLKCTL_NECLK = 0;                      // enable ECLK output (bus clock is visible on pin PS7)
  //--------------------------------------
  // INITIALIZE THE EEPROM
  //------------------------------
  EEPROM_Init(0x0F);// default settings:
                    // internal oscillator is used = 1MHz => bus clk 8MHz => divide by 0x07 
                    // to achieve FCLK 1MHz
                    // Table 15-7. FDIV values for various BUSCLK Frequencies

  //------------------------------
  // check entire EEPROM whether required data are already written
  if( (*(word*)(0x400)) != 0xAABC)
    {
      // the flag at 0x0400 says there are not correct data 
      // check the eeprom is erased
      //------------------------------
      if(EEPROM_Erase_Verify_Section(EEPROM_START,512) == NON_ERASED)
        {
          // if no then erase entire EEPROM  
          //------------------------------
          for(addr = EEPROM_START; addr < EEPROM_END; addr+=EEPROM_SECTOR)   
            {
              err = EEPROM_Erase_Sector(addr);
            }
        }

      //...and write required data
      //------------------------------
      err = EEPROM_Program(EEPROM_START, buf, 4);
      
      for(addr = EEPROM_START+8; addr < EEPROM_END; addr+=2)   
        {
          err = EEPROM_Program(addr, &addr, 1);
        }
  
    }
  //------------------------------
  for(;;) 
   {
    _FEED_COP();
   }
  //------------------------------
}
//******************************************************************************
//EEPROM_Erase_Verify_Section
//******************************************************************************
byte EEPROM_Erase_Verify_Section(word address, word number_of_words)
{
  //check if address is aligned (global address [2:0] = 000)
  if((address & 0x0004) != 0)
    return MISALIGNED_ADDRESS; 
  
  while(FSTAT_CCIF == 0);   //wait if command in progress
  FSTAT = 0x30;             //clear ACCERR and PVIOL
  
  FCCOBIX = 0x00;
  FCCOB   = 0x1000;
  
  FCCOBIX = 0x01;
  FCCOB   = address;
  
  FCCOBIX = 0x02;
  FCCOB   = number_of_words;
  
  asm JSR Send_Command;
  
  if((FSTAT & (FSTAT_ACCERR_MASK | FSTAT_FPVIOL_MASK)) != 0)
    return ACCESS_ERROR;
  
  //check if phrases are erased and return result
  if(FSTAT_MGSTAT != 0)
    return NON_ERASED;
  else
    return ERASED;
}
//******************************************************************************
//EEPROM_Program
//******************************************************************************
byte EEPROM_Program(word address, word *ptr, byte number_of_words)
{  
  word i;
  
  if((number_of_words < 1) || (number_of_words > 4))
    return LENGTH_OUT_OF_RANGE;
  
  //check if address is aligned (global address [0] != 0)
  if((address & 0x0001) != 0)
    return MISALIGNED_ADDRESS; 
  
  //check if the word(s) is/are erased    
  if((EEPROM_Erase_Verify_Section(address, number_of_words)) == NON_ERASED)
    return NON_ERASED;  
    
  while(FSTAT_CCIF == 0);   //wait if command in progress
  FSTAT = 0x30;             //clear ACCERR and PVIOL    
  
  FCCOBIX = 0x00;
  FCCOB   = 0x1100;
  
  FCCOBIX = 0x01;
  FCCOB   = address;
  
  
  for(i=1; i<=number_of_words; i++)  //fill appropriate number of words to FCCOB
  {
    FCCOBIX = i+1;
    FCCOB = *ptr;
    ptr++;  
  }
      
  //asm JSR Send_Command;
  FSTAT_CCIF = 1;         //launch command
  //while(FSTAT_CCIF == 0); //wait for done    
  
  //if((FSTAT & (FSTAT_ACCERR_MASK | FSTAT_FPVIOL_MASK)) != 0) return ACCESS_ERROR;
  //if(FSTAT_MGSTAT != 0) return VERIFICATION_FAILED;    
  return OK;
}
//******************************************************************************
//EEPROM_Erase_Sector
//******************************************************************************
byte EEPROM_Erase_Sector(word address)
{
  //size of sector is 4B
  
  //check if address is aligned (global address [0] != 0)  
  if((address & 0x00000001) != 0)
    return MISALIGNED_ADDRESS; 
    
  while(FSTAT_CCIF == 0);   //wait if command in progress
  FSTAT = 0x30;             //clear ACCERR and PVIOL
  
  FCCOBIX = 0x00;
  FCCOB   = 0x1200;
  
  FCCOBIX = 0x01;
  FCCOB   = address;
   
  asm JSR Send_Command;
  
  if((FSTAT & (FSTAT_ACCERR_MASK | FSTAT_FPVIOL_MASK)) != 0) return ACCESS_ERROR;
  if(FSTAT_MGSTAT != 0) return VERIFICATION_FAILED;    
  return OK;
}
//******************************************************************************
//PFLASH_Read_Word
//******************************************************************************
word EEPROM_Read_Word(word address)
{
  word data16;
  data16 = *(word *)address;
  return data16;
}

//******************************************************************************
//PFLASH_Init
//******************************************************************************
void EEPROM_Init(byte fdiv)
{  
  FCLKDIV = fdiv;           
}
//******************************************************************************
