/******************************************************************************
*
* (c) Copyright 2015, Freescale Semiconductor Inc.
*
***************************************************************************//*!
/*****************************************************************************/
/*                                                                           */
/* FILE NAME     :  main_core1.c                                             */
/* DESCRIPTION   :  Injection Control Demo                                   */
/* DATE          :  September 8, 2015                                        */
/* AUTHOR	 :  Oskar Walder (WAL0058)				     */
/*                                                                           */
/*****************************************************************************/

#include "../headers/project.h"
#include "../headers/mpc5746r.h"
#include "../etpu/etpu_gct.h"            /* eTPU Configuration */
#include "../etpu/inj/etpu_inj.h"
#include "../etpu/utils/etpu_util.h"     /* General C Functions for the eTPU */
#include "../etpu/crank/etpu_crank.h"    /* eTPU CRANK API */
#include "../etpu/cam/etpu_cam.h"        /* eTPU CAM API */
#include "../FreeMASTER/freemaster.h"    /* Freemaste API */
#include "../REACM2/reacm2_util.h"	 /* REACM2 utilities */


extern void Clock_and_Mode_Init(void);

/******************************************************************************
* Global variables
******************************************************************************/
/* eTPU Engine A load as a percentage */
uint32_t etpu_engine_load;

/* Injection Control variables */
uint32_t pre_injection = 1;
uint32_t post_injection = 1;
/* Default length of injections */
uint32_t pre_inj_duration = 500;
uint32_t main_inj_duration = 1000;
uint32_t post_inj_duration = 500;

/* eTPU log arrays */
uint24_t etpu_cam_log[CAM_LOG_SIZE];
uint24_t etpu_tooth_period_log[TEETH_PER_CYCLE];

/******************************************************************************
* FreeMASTER TSA tables
******************************************************************************/
/*
 * With TSA enabled, the user describes the global and static variables using 
 * so-called TSA tables. There can be any number of tables defined in 
 * the project files. Each table does have the identifier which should be
 * unique across the project. 
 *
 * Note that you can declare variables as Read-Only or Read-Write.
 * The FreeMASTER driver denies any write access to the Read-Only variables
 * when TSA_SAFETY is enabled.
 */

FMSTR_TSA_TABLE_BEGIN(fmstr_tsa_table_etpu_load)
    FMSTR_TSA_RO_VAR(etpu_engine_load, FMSTR_TSA_UINT32)
    FMSTR_TSA_RW_VAR(pre_injection,FMSTR_TSA_UINT32)
    FMSTR_TSA_RW_VAR(post_injection,FMSTR_TSA_UINT32)
    FMSTR_TSA_RW_VAR(pre_inj_duration,FMSTR_TSA_UINT32)
    FMSTR_TSA_RW_VAR(main_inj_duration,FMSTR_TSA_UINT32)
    FMSTR_TSA_RW_VAR(post_inj_duration,FMSTR_TSA_UINT32)
FMSTR_TSA_TABLE_END()

FMSTR_TSA_TABLE_BEGIN(fmstr_tsa_table_etpu_logs)
    FMSTR_TSA_RO_VAR(etpu_cam_log, FMSTR_TSA_UINT32)
    FMSTR_TSA_RO_VAR(etpu_tooth_period_log, FMSTR_TSA_UINT32)
FMSTR_TSA_TABLE_END()

/*
 * This list describes all TSA tables which should be exported to the 
 * FreeMASTER application.
 */
FMSTR_TSA_TABLE_LIST_BEGIN()
    FMSTR_TSA_TABLE(fmstr_tsa_table_etpu_load)
    FMSTR_TSA_TABLE(fmstr_tsa_table_etpu_logs)
    FMSTR_TSA_TABLE(fmstr_tsa_table_etpu_scaling)
    FMSTR_TSA_TABLE(fmstr_tsa_table_crank)
    FMSTR_TSA_TABLE(fmstr_tsa_table_cam)
    FMSTR_TSA_TABLE(fmstr_tsa_table_inj)
    FMSTR_TSA_TABLE(fmstr_tsa_table_knock)
    FMSTR_TSA_TABLE(fmstr_tsa_table_tg)
FMSTR_TSA_TABLE_LIST_END()

/******************************************************************************
* Local function prototypes
******************************************************************************/
void fmpll_init(void);
void esci_a_init(void);
void LINFlex_init(void);
uint32_t get_etpu_load_a(void);
int ADC1_calibration(void);
int ADC2_calibration(void);
void ADC1_init(void);
void ADC2_init(void);
void eMIOS_init(void);
void BCTU_init(void);
void REACM2_init(void);

/******************************************************************************
* Interrupt handlers
******************************************************************************/
void etpu_crank_isr(void);
void etpu_cam_isr(void);
void etpu_knock_1_isr(void);
void etpu_knock_2_isr(void);
void etpu_knock_3_isr(void);
void etpu_knock_4_isr(void);
void etpu_inj_1_isr(void);
void etpu_inj_2_isr(void);
void etpu_tg_isr(void);



/***************************************************************************//*!
*
* @brief   Interrupt from eTPU channel CRANK
*
* @return  N/A
*
* @note    This interrupt is generated every time the engine position state
*          is changed. When the engine position state is 
*          FS_ETPU_ENG_POS_PRE_FULL_SYNC the logged Cam patern is decoded
*          in order to set tcr2_adjustment and achieve FULL_SYNC.
* 
******************************************************************************/
void etpu_crank_isr(void)
{
  uint24_t tcr2_adjustment;

  fs_etpu_clear_chan_interrupt_flag(ETPU_CRANK_CHAN);
 
  /* Follow Engine Position state */
  fs_etpu_crank_get_states(&crank_instance, &crank_states);
  switch(crank_states.eng_pos_state)
  {
  case FS_ETPU_ENG_POS_SEEK:
    /* Crank has stalled. Read Crank error to know the reason. */
    break;
  case FS_ETPU_ENG_POS_FIRST_HALF_SYNC:
    /* Crank has found the gap, or
       Crank did not received CRANK_HSR_SET_SYNC and hence Crank reset 
       the Cam log to repeat recording the Cam log. */
    break;
  case FS_ETPU_ENG_POS_PRE_FULL_SYNC:
    /* Cam signal is logged, the log corresponds to a segment of 
       teeth_per_sync Crank teeth starting from a gap.
       NOW THE CPU MUST RECOGNIZE THE LOGGED CAM PATTERN AND 
       1) SET tcr2_adjustment
       2) ASSIGN CRANK HSR = CRANK_HSR_SET_SYNC. */
    fs_etpu_cam_get_states(&cam_instance, &cam_states);
    fs_etpu_cam_copy_log(&cam_instance, &etpu_cam_log[0]);
    
    if((cam_states.log_idx == 3) && (etpu_cam_log[0] & 0x01000000))
    {
      /* 3 transition logged,
         the first transition is a rising one 
         => the  first half-cycle was logged */
      /* Set, what angle should have been at the last gap */
      tcr2_adjustment = DEG2TCR2(360);
    }
    else if((cam_states.log_idx == 3) && ~(etpu_cam_log[0] & 0x01000000))
    {
      /* 3 transitions logged,
         the first transition is a falling one
         => the second half-cycle was logged */
      /* Set, what angle should have been at the last gap */
      tcr2_adjustment = DEG2TCR2(0);
    }
    else
    {
      /* Cam pattern is not recognized */
      break;
    }
    fs_etpu_crank_set_sync(&crank_instance, tcr2_adjustment);
    break;
  case FS_ETPU_ENG_POS_FULL_SYNC:
    /* Regular interrupt on the first tooth every engine cycle. */
    /* Clear errors */
    crank_states.error = 0;
    cam_states.error = 0;
    break;
  }

  /* Interface CRANK eTPU function */
  fs_etpu_crank_get_states(&crank_instance, &crank_states);
  fs_etpu_crank_config(&crank_instance, &crank_config);
  fs_etpu_crank_copy_tooth_period_log(&crank_instance, &etpu_tooth_period_log[0]);
  /* Interface CAM eTPU function */
  fs_etpu_cam_get_states(&cam_instance, &cam_states);
  fs_etpu_cam_config(&cam_instance, &cam_config);
  fs_etpu_cam_copy_log(&cam_instance, &etpu_cam_log[0]);

  /* Evaluate eTPU load */
  etpu_engine_load = get_etpu_load_a();
}


/***************************************************************************//*!
*
* @brief   Interrupt from eTPU channel CAM
*
* @return  N/A
*
* @note    This interrupt is generated on detecting an error condition.
* 
******************************************************************************/
void etpu_cam_isr(void)
{
    /* Clear interrupt flag */
    fs_etpu_clear_chan_interrupt_flag(ETPU_CAM_CHAN);
    /* Interface CAM eTPU function */
    fs_etpu_cam_get_states(&cam_instance, &cam_states);
    fs_etpu_cam_config(&cam_instance, &cam_config);
    fs_etpu_cam_copy_log(&cam_instance, &etpu_cam_log[0]);
}

/***************************************************************************//*!
*
* @brief   Interrupt from eTPU channel KNOCK_1
*
* @return  N/A
*
* @note    This interrupt is generated at each window end. The Knock 
*          parameters can be adjusted.
* 
******************************************************************************/
void etpu_knock_1_isr(void)
{
    /* Clear interrupt flag */
    fs_etpu_clear_chan_interrupt_flag(ETPU_KNOCK_1_CHAN);
    /* Interface KNOCK eTPU function */;
    fs_etpu_knock_config(&knock_1_instance, &knock_config);
}


/***************************************************************************//*!
*
* @brief   Interrupt from eTPU channel KNOCK_2
*
* @return  N/A
*
* @note    This interrupt is generated at each window end. The Knock 
*          parameters can be adjusted.
* 
******************************************************************************/
void etpu_knock_2_isr(void)
{
    /* Clear interrupt flag */
    fs_etpu_clear_chan_interrupt_flag(ETPU_KNOCK_2_CHAN);
    /* Interface KNOCK eTPU function */
    fs_etpu_knock_config(&knock_2_instance, &knock_config);
}

/***************************************************************************//*!
*
* @brief   Interrupt from eTPU channel KNOCK_3
*
* @return  N/A
*
* @note    This interrupt is generated at each window end. The Knock 
*          parameters can be adjusted.
* 
******************************************************************************/
void etpu_knock_3_isr(void)
{
    /* Clear interrupt flag */
    fs_etpu_clear_chan_interrupt_flag(ETPU_KNOCK_3_CHAN);
    /* Interface KNOCK eTPU function */;
    fs_etpu_knock_config(&knock_3_instance, &knock_config);
}


/***************************************************************************//*!
*
* @brief   Interrupt from eTPU channel KNOCK_4
*
* @return  N/A
*
* @note    This interrupt is generated at each window end. The Knock 
*          parameters can be adjusted.
* 
******************************************************************************/
void etpu_knock_4_isr(void)
{
    /* Clear interrupt flag */
    fs_etpu_clear_chan_interrupt_flag(ETPU_KNOCK_4_CHAN);
    /* Interface KNOCK eTPU function */
    fs_etpu_knock_config(&knock_4_instance, &knock_config);
}

/***************************************************************************//*!
*
* @brief   Interrupt from eTPU channel INJ_1
*
* @return  N/A
*
* @note    This interrupt is generated before the start of injection sequence
*          on INJ 1 channel. The injection sequence parameters can be adjusted.
* 
******************************************************************************/
void etpu_inj_1_isr(void)
{
    /* Clear interrupt flag */
    fs_etpu_clear_chan_interrupt_flag(ETPU_INJ_1_CHAN);
    /* Interface INJ eTPU function */
    fs_etpu_inj_get_states(&inj_1_instance, &inj_1_states);
    fs_etpu_inj_config(&inj_1_instance, &inj_config);
}


/***************************************************************************//*!
*
* @brief   Interrupt from eTPU channel INJ_2
*
* @return  N/A
*
* @note    This interrupt is generated before the start of injection sequence
*          on INJ 1 channel. The injection sequence parameters can be adjusted.
* 
******************************************************************************/
void etpu_inj_2_isr(void)
{
    /* Clear interrupt flag */
    fs_etpu_clear_chan_interrupt_flag(ETPU_INJ_2_CHAN);
    /* Interface INJ eTPU function */
    fs_etpu_inj_get_states(&inj_2_instance, &inj_2_states);
    fs_etpu_inj_config(&inj_2_instance, &inj_config);
}


/***************************************************************************//*!
*
* @brief   Interrupt from eTPU channel TG
*
* @return  N/A
*
* @note    This interrupt is generated in each gap. The Tooth Generator 
*          parameters can be adjusted.
* 
******************************************************************************/
void etpu_tg_isr(void)
{
    /* Clear interrupt flag */
    fs_etpu_clear_chan_interrupt_flag(ETPU_TG_CRANK_CHAN);
    /* Interface TG eTPU function */
    fs_etpu_tg_get_states(&tg_instance, &tg_states);
    fs_etpu_tg_config(&tg_instance, &tg_config);
}

/***************************************************************************//*!
*
* @brief   SIUL2 configuration for eTPU input/output
*
* @return  N/A
* 
******************************************************************************/
void SIUL2_Configure(void)
{

    // SIUL2 configuration for eTPU A
    /* Setup eTPU A inputs */
    SIUL2.MSCR512_955[512-512].R = 9;  	  // eTPU A channel 00 = PH[11]
    SIUL2.MSCR0_255[123].R = 0x008A0000;  // PH[11] -> PH[11] - Cam
    SIUL2.MSCR512_955[514-512].R = 9;     // eTPU A channel 02 = PH[13]
    SIUL2.MSCR0_255[125].R = 0x008A0000;  // PH[13] -> PH[13] - Crank
    /* Setup eTPU A outputs */
    SIUL2.MSCR0_255[124].R = 0x12380001;  // eTPU A channel 01 = PH[12] -> PH[12] - TG Cam
    SIUL2.MSCR0_255[126].R = 0x12380001;  // eTPU A channel 03 = PH[14] -> PH[14] - TG Crank
    SIUL2.MSCR0_255[133].R = 0x12380001;  // eTPU A channel 10 = PI[05] -> PI[05] - Inj 1
    SIUL2.MSCR0_255[101].R = 0x12380001;  // eTPU A channel 11 = PG[05] -> PE[06] - Inj 2
    SIUL2.MSCR0_255[54].R = 0x12380001;   // eTPU A channel 14 = PD[06] -> PL[06] - Knock 1
    SIUL2.MSCR0_255[55].R = 0x12380001;   // eTPU A channel 15 = PD[07] -> PL[07] - Knock 2
    SIUL2.MSCR0_255[106].R = 0x12380001;  // eTPU A channel 16 = PG[10] -> PG[10] - Knock 3
    SIUL2.MSCR0_255[57].R = 0x12380001;   // eTPU A channel 17 = PD[09] -> PL[09] - Knock 4

    // SIUL2 configuration for LINFlex #2	// Port Pin	Number	MSCR_SSS	Function	Description	
    SIUL2.MSCR0_255[80].R = 0x32810009;		// PF[0]	80	0000_1001	LIN2TX		LINFlexD_2 Transmit Data Output
    SIUL2.MSCR0_255[81].R = 0x00080000;		// PF[1]	81	0000_0000	GPIO[81]	General Purpose	
    SIUL2.MSCR512_955[754 - 512].R = 0x00000002;// PF[1]	754	0000_0010	LIN2RX		LINFlexD_2 Receive Data Input

    // SIUL2 configuration for ADC
    SIUL2.MSCR0_255[237].B.APC = 1; // PY[13] => PT[13]		ADC 1 channel 9
    SIUL2.MSCR0_255[249].B.APC = 1; // PZ[09] => PB[01]		ADC 2 channel 9
    
    // SIUL2 configuration for REACM2
    SIUL2.MSCR0_255[49].R = 0x12380005;  // REACM2 Channel 4A PD[1] -> PL[1]
    SIUL2.MSCR0_255[112].R = 0x12380005; // REACM2 Channel 4B PH[0] -> PH[0]
    SIUL2.MSCR0_255[115].R = 0x12380005; // REACM2 Channel 4C PH[3] -> PH[3]
    SIUL2.MSCR0_255[58].R = 0x12380005;  // REACM2 Channel 5A PD[10] -> PL[10]

   
}

/***************************************************************************//*!
*
* @brief   ADC1 module calibration 
*
* @return  N/A
* 
******************************************************************************/
int ADC1_calibration(void)
{
    uint32_t ADC1_calibration_failed = 1;	// Calibration has not passed yet
    /* Note: Since ADC is at max 80 MHz frequency, use default values */
    MC_CGM.AC0_DC2.R = 0x80010000; // SARADC - enable protocol clock 	 	- from PPL0 with divider 2
    
    ADC_1.MCR.B.PWDN = 1;			// Power down for starting calibration process
    ADC_1.MCR.B.ADCLKSEL = 1; 			// ADC clock = bus clock (80 MHz FS80)
    /* Note: Since ADC is at max 80 MHz frequency, use default values */
    /* for Calibration, BIST control and ADCx_CALBISTREG */
    ADC_1.MCR.B.PWDN = 0; 			// Power back up after setting ADCLKSEL
    ADC_1.CALBISTREG.B.TEST_EN = 1; 		// Enable calibration test
    while(ADC_1.CALBISTREG.B.C_T_BUSY){} 	// Wait for calibration to finish
    /* Check for Calibration Fail */
    if(ADC_1.CALBISTREG.B.TEST_FAIL)
    { 
	ADC1_calibration_failed = 1; // Calibration done but failed
    }
    else
    {
	ADC1_calibration_failed = 0; // Calibration done and passed
    }
    return ADC1_calibration_failed;
}

/***************************************************************************//*!
*
* @brief   ADC1 module calibration 
*
* @return  N/A
* 
******************************************************************************/
int ADC2_calibration(void)
{
    uint32_t ADC2_calibration_failed = 1;	// Calibration has not passed yet
    /* Note: Since ADC is at max 80 MHz frequency, use default values */
    MC_CGM.AC0_DC2.R = 0x80010000; // SARADC - enable protocol clock 	 	- from PPL0 with divider 2
    
    ADC_2.MCR.B.PWDN = 1;			// Power down for starting calibration process
    ADC_2.MCR.B.ADCLKSEL = 1; 			// ADC clock = bus clock (80 MHz FS80)
    /* Note: Since ADC is at max 80 MHz frequency, use default values */
    /* for Calibration, BIST control and ADCx_CALBISTREG */
    ADC_2.MCR.B.PWDN = 0; 			// Power back up after setting ADCLKSEL
    ADC_2.CALBISTREG.B.TEST_EN = 1; 		// Enable calibration test
    while(ADC_2.CALBISTREG.B.C_T_BUSY){} 	// Wait for calibration to finish
    /* Check for Calibration Fail */
    if(ADC_2.CALBISTREG.B.TEST_FAIL)
    { 
	ADC2_calibration_failed = 1; // Calibration done but failed
    }
    else
    {
	ADC2_calibration_failed = 0; // Calibration done and passed
    }
    return ADC2_calibration_failed;
}

/***************************************************************************//*!
*
* @brief   ADC1 module initialization 
*
* @return  N/A
* 
******************************************************************************/
void ADC1_init(void)
{
    /* Note: Since ADC is at max 80 MHz frequency, use default values */
    /* ADC 1 init */
    ADC_1.NCMR0.B.CH9 = 1;  	// Enable chan 9 for normal conversion on ADC 1
    ADC_1.MCR.B.PWDN = 1; 	// power down for starting module initialization 
    ADC_1.MCR.B.OWREN = 1; 	// older result is overwriten by newer result
    ADC_1.MCR.B.MODE = 0; 	// one shot mode	
    ADC_1.MCR.B.ADCLKSEL = 1; 	// ADC clock frequency is equal to bus clock
    ADC_1.MCR.B.CTUEN = 1; 	// enables the BCTU
    ADC_1.MCR.B.CTU_MODE = 1;	// triggered mode 
    ADC_1.MCR.B.PWDN = 0; 	// power up
    ADC_1.MCR.B.NSTART = 1; 	// normal start
}


/***************************************************************************//*!
*
* @brief   ADC2 module initialization 
*
* @return  N/A
* 
******************************************************************************/
void ADC2_init(void)
{
    /* Note: Since ADC is at max 80 MHz frequency, use default values */
    /* ADC 2 init */
    ADC_2.NCMR0.B.CH9 = 1;  	// Enable chan 9 for normal conversion on ADC 1
    ADC_2.MCR.B.PWDN = 1; 	// power down for starting module initialization 
    ADC_2.MCR.B.OWREN = 1; 	// older result is overwriten by newer result
    ADC_2.MCR.B.MODE = 0; 	// one shot mode	
    ADC_2.MCR.B.ADCLKSEL = 1; 	// ADC clock frequency is equal to bus clock
    ADC_2.MCR.B.CTUEN = 1; 	// enables the BCTU
    ADC_2.MCR.B.CTU_MODE = 1;	// triggered mode 
    ADC_2.MCR.B.PWDN = 0; 	// power up
    ADC_2.MCR.B.NSTART = 1; 	// normal start
}

/***************************************************************************//*!
*
* @brief   BCTU module initialization 
*
* @return  N/A
* 
******************************************************************************/
void BCTU_init(void)
{
    
    BCTU.MCR.B.GTRGEN = 0;// disable all triggers

    // BCTU input trigger #19 for eMIOS channel #12
    BCTU.TRGCFG[19].B.CCP = 1;		// pointer to conversion configuration register
    BCTU.TRGCFG[19].B.TRIGEN = 1; 	// enable hardware trigger
    BCTU.TRGCFG[19].B.TRG_FLAG = 1; 	// clear previous input trigger event
    BCTU.TRGCFG[19].B.TRS = 0;		// set normal trigger resolution
    BCTU.TRGCFG[19].B.ADC_SEL1 = 1;	// select ADC #1 for conversion
    BCTU.TRGCFG[19].B.CHANNEL_VALUE_OR_LADDR = 0x9;	// select ADC channnel for conversion

    // BCTU input trigger #18 for eMIOS channel #13
    BCTU.TRGCFG[18].B.CCP = 2;		// pointer to conversion configuration register
    BCTU.TRGCFG[18].B.TRIGEN = 1; 	// enable hardware trigger
    BCTU.TRGCFG[18].B.TRG_FLAG = 1; 	// clear previous input trigger event
    BCTU.TRGCFG[18].B.TRS = 0;		// set normal trigger resolution
    BCTU.TRGCFG[18].B.ADC_SEL2 = 1;	// select ADC #2 for conversion
    BCTU.TRGCFG[18].B.CHANNEL_VALUE_OR_LADDR = 0x9;	// select ADC channnel for conversion

    
    BCTU.CCR[0].B.DEST = 2;		// send ADC result to BCTU result register and to PSI
    BCTU.CCR[0].B.TAG = 4;		// tag for identification ADC1 result
    BCTU.CCR[1].B.DEST = 2;		// send ADC result to BCTU result register and to PSI
    BCTU.CCR[1].B.TAG = 5;		// tag for identification ADC2 result
    
    BCTU.MCR.B.GTRGEN = 1; 		// enable all trigers
}


/***************************************************************************//*!
*
* @brief   eMIOS 0 Channel 9 configuration
*	   MODE: OPWFM - 50% duty cycle, 1MHz
*
* @return  N/A
* 
******************************************************************************/
void eMIOS_init(void)
{
    MC_CGM.AC5_DC1.R = 0x80010000; // eMIOS - enable protocol clock		- from PPL0 with divider 2
    eMIOS200_0.MCR.B.MDIS = 0; 		// enable modul
    eMIOS200_0.MCR.B.GPRE = 0; 		// set global divider
    /* pause modul for configuration */
    eMIOS200_0.MCR.B.GPREN = 0; 	// disable global prescaler

    /*
       B,A CALCULATION
       
       PPL0 - 80MHz
       PPL0 / required frequency = B
       B / 2 = A
    */
    
    /* Set-up output channel 12 for ADC1 */
    eMIOS_0_UC12.C.B.UCPREN = 0;	// disable channel prescaler
    eMIOS_0_UC12.A.B.A = 40;		// counter in state 0-40 produces logical zero on output
    eMIOS_0_UC12.B.B.B = 80;		// counter in state 40-80 produces logacal one on output
    eMIOS_0_UC12.C.B.BSL = 3;		// set internal clock as clock source
    eMIOS_0_UC12.C.B.MODE = 0x1B;	// Output Pulse Width and Frequency Modulation (OPWFM) with next period update
    eMIOS_0_UC12.C.B.EDPOL = 1;		// triggering on a rising edge
    eMIOS_0_UC12.C.B.UCPRE = 0;		// set channel prescaler
    eMIOS_0_UC12.C.B.UCPREN = 1; 	// enable channel prescaler

    /* Set-up output channel 13 for ADC2 */
    eMIOS_0_UC13.C.B.UCPREN = 0;	// disable channel prescaler
    eMIOS_0_UC13.A.B.A = 40;		// counter in state 0-40 produces logical zero on output
    eMIOS_0_UC13.B.B.B = 80;		// counter in state 40-80 produces logacal one on output
    eMIOS_0_UC13.C.B.BSL = 3;		// set internal clock as clock source
    eMIOS_0_UC13.C.B.MODE = 0x1B;	// Output Pulse Width and Frequency Modulation (OPWFM) with next period update
    eMIOS_0_UC13.C.B.EDPOL = 1;		// triggering on a rising edge
    eMIOS_0_UC13.C.B.UCPRE = 0;		// set channel prescaler
    eMIOS_0_UC13.C.B.UCPREN = 1; 	// enable channel prescaler

    /* resume modul */
    eMIOS200_0.MCR.B.GPREN = 1;		// enable global prescaler
    eMIOS200_0.MCR.B.GTBE = 1;		// Global Time Base Enable Out signal asserted

}

/***************************************************************************//*!
*
* @brief   REACM2 init & modulation word structures
*	   
*
* @return  N/A
* 
******************************************************************************/
/* module initialization structure */
REACM2_INIT_T my_module_setup = 
    {
	/* MCR init */
	FS_REACM2_MDIS_ENABLE 
	| FS_REACM2_TPREN_ENABLE
	| FS_REACM2_HPREN_ENABLE,
	/* TCR init */
	FS_REACM2_HPRE(2)
	| FS_REACM2_TPRE(2),
	/* THRR init */
	FS_REACM2_WREN1_DISABLE
	| FS_REACM2_WREN0_DISABLE,
	/* PCR init */
	FS_REACM2_PERPRESC(1) // no division
	| FS_REACM2_PER(0), // period generator stopped
	/* PSCR init */
	FS_REACM2_DLY(0), // no delay between the period pulses of the consecutive channel 
	/* ADCMAX init */
	FS_REACM2_ADCMAX(0), //when set to 0 the adc max limit checking disabled
	/* RANGE_PWD init */
	FS_REACM2_RANGE_PWD(0), // no pwd range checking is performed
	/* MIN_PWD init */
	FS_REACM2_MIN_PWD(0) // no minimum pulse width checking is performed
    };

/* channel initialization structure */
REACM2_CHANNEL_INIT_T ch_bank1=
    {
	/* CHCR init */
	FS_REACM2_CHEN_ENABLE
	| FS_REACM2_DOFF_C_LOW
	| FS_REACM2_DOFF_B_LOW
	| FS_REACM2_DOFF_A_LOW,
	/* CHRR init */
	FS_REACM2_ADCR(FS_REACM2_ADC_TAG_4)
	| FS_REACM2_CHIR(0)
    };

/* channel initialization structure */
REACM2_CHANNEL_INIT_T ch_bank2 =
    {
	/* CHCR init */
	FS_REACM2_CHEN_ENABLE
	| FS_REACM2_DOFF_C_LOW
	| FS_REACM2_DOFF_B_LOW
	| FS_REACM2_DOFF_A_LOW,
	/* CHRR init */
	FS_REACM2_ADCR(FS_REACM2_ADC_TAG_5)
	| FS_REACM2_CHIR(1)
    };

/* threshold and time definitions */
THRESHOLD_T thsB00 = {0xb00 , NAN};
THRESHOLD_T thsA00 = {0xa00 , NAN};
THRESHOLD_T ths800 = {0x800 , NAN};
THRESHOLD_T ths600 = {0x600 , NAN};

SH_TIME_T stm0E00 = {0x0e00, NAN};
SH_TIME_T stm3000 = {0x3000, NAN};
SH_TIME_T stm0250 = {0x0250, NAN};

/* modulation word parameters definition */
MODULATION_WORD_T my_phases [4] = {
/* loop,               ioss,               mod,             sequencer mode,               HOD_C out             HOD_B out             HOD_A out             LOD_C out            LOD_B out            LOD_A out,           threshold 1, threshold 2, sh_time,  hold_time */ 
    {FS_REACM2_LOOP_OFF, FS_REACM2_IOSS_LOD, FS_REACM2_MM_TT, FS_REACM2_SM_THRESHOLD_EVENT, FS_REACM2_HOD_C_HIGH, FS_REACM2_HOD_B_HIGH, FS_REACM2_HOD_A_HIGH, FS_REACM2_LOD_C_LOW, FS_REACM2_LOD_B_LOW, FS_REACM2_LOD_A_LOW, &thsB00,     &thsA00,     &stm0E00, NULL},
    {FS_REACM2_LOOP_OFF, FS_REACM2_IOSS_LOD, FS_REACM2_MM_TT, FS_REACM2_SM_TIMER_EVENT,     FS_REACM2_HOD_C_HIGH, FS_REACM2_HOD_B_HIGH, FS_REACM2_HOD_A_HIGH, FS_REACM2_LOD_C_LOW, FS_REACM2_LOD_B_LOW, FS_REACM2_LOD_A_LOW, &thsB00,     &thsA00,     &stm3000, NULL},
    {FS_REACM2_LOOP_OFF, FS_REACM2_IOSS_LOD, FS_REACM2_MM_TT, FS_REACM2_SM_TIMER_EVENT,     FS_REACM2_HOD_C_HIGH, FS_REACM2_HOD_B_HIGH, FS_REACM2_HOD_A_HIGH, FS_REACM2_LOD_C_LOW, FS_REACM2_LOD_B_LOW, FS_REACM2_LOD_A_LOW, NULL,        NULL,        &stm0250, NULL},
    {FS_REACM2_LOOP_ON,  FS_REACM2_IOSS_LOD, FS_REACM2_MM_TT, FS_REACM2_SM_NO_TRANSITION,   FS_REACM2_HOD_C_HIGH, FS_REACM2_HOD_B_HIGH, FS_REACM2_HOD_A_HIGH, FS_REACM2_LOD_C_LOW, FS_REACM2_LOD_B_LOW, FS_REACM2_LOD_A_LOW, &ths800,     &ths600,     NULL,     NULL}
};

/*    REACM2_INIT_T reacm_sett = {
 - 	FS_REACM2_TPREN_ENABLE | FS_REACM2_HPREN_ENABLE, // MCR
 - 	FS_REACM2_HPRE(2) | FS_REACM2_TPRE(2), // TCR
 - 	0x0, // THRR
 - 	0x0, // PCR
 - 	0x0, // PSCR
 - 	0x0, // MAX_ADC
 - 	0x0, // MIN_PWD
 -     };
 - 
 -     @/@*$ REACM2 Utilities - Global variables $*@/@
 -     THRESHOLD_T thsB00 = { 0xb00 , NAN};
 -     THRESHOLD_T thsA00 = { 0xa00 , NAN};
 -     THRESHOLD_T ths800 = { 0x800 , NAN};
 -     THRESHOLD_T ths600 = { 0x600 , NAN};
 - 
 -     SH_TIME_T stm0E00 = {0x0e00, NAN};
 -     SH_TIME_T stm3000 = {0x3000, NAN};
 -     SH_TIME_T stm0250 = {0x0250, NAN};
 -     
 - 
 -     REACM2_CHANNEL_INIT_T ch_bank1 = {
 - 	FS_REACM2_CHEN_ENABLE | FS_REACM2_SWMC_ON,
 - 	FS_REACM2_ADCR(4) | FS_REACM2_CHIR(0)
 -     };
 - 
 -     REACM2_CHANNEL_INIT_T ch_bank2 = {
 - 	FS_REACM2_CHEN_ENABLE | FS_REACM2_SWMC_ON,
 - 	FS_REACM2_ADCR(5) | FS_REACM2_CHIR(1)
 -     };
 - 
 -     
 -     MODULATION_WORD_T phases[4] = {
 - 	    {FS_REACM2_LOOP_OFF, FS_REACM2_IOSS_LOD, FS_REACM2_MM_TT, FS_REACM2_SM_THRESHOLD_EVENT, FS_REACM2_HOD_C_HIGH, FS_REACM2_HOD_B_HIGH, FS_REACM2_HOD_A_HIGH, FS_REACM2_HOD_C_LOW, FS_REACM2_HOD_B_LOW, FS_REACM2_HOD_A_LOW, &thsB00, &thsA00, &stm0E00, NULL },
 - 	    {FS_REACM2_LOOP_OFF, FS_REACM2_IOSS_LOD, FS_REACM2_MM_TT,     FS_REACM2_SM_TIMER_EVENT, FS_REACM2_HOD_C_HIGH, FS_REACM2_HOD_B_HIGH, FS_REACM2_HOD_A_HIGH, FS_REACM2_HOD_C_LOW, FS_REACM2_HOD_B_LOW, FS_REACM2_HOD_A_LOW, &thsB00, &thsA00, &stm3000, NULL },
 - 	    {FS_REACM2_LOOP_OFF, FS_REACM2_IOSS_LOD, FS_REACM2_MM_TT,     FS_REACM2_SM_TIMER_EVENT, FS_REACM2_HOD_C_HIGH, FS_REACM2_HOD_B_HIGH, FS_REACM2_HOD_A_HIGH, FS_REACM2_HOD_C_LOW, FS_REACM2_HOD_B_LOW, FS_REACM2_HOD_A_LOW,    NULL,    NULL, &stm0250, NULL },
 - 	    { FS_REACM2_LOOP_ON, FS_REACM2_IOSS_LOD, FS_REACM2_MM_TT,   FS_REACM2_SM_NO_TRANSITION, FS_REACM2_HOD_C_HIGH, FS_REACM2_HOD_B_HIGH, FS_REACM2_HOD_A_HIGH, FS_REACM2_HOD_C_LOW, FS_REACM2_HOD_B_LOW, FS_REACM2_HOD_A_LOW, &ths800, &ths600,     NULL, NULL }
 -     };*/
    
/*****************************************************************************/
/*         Function: main                                                    */
/*         Content:  main function for core 1                                */
/*         Argument: void                                                    */
/*         Return value: void                                                */
/*****************************************************************************/
int main(void)
{
    uint8_t address = 0;
    int *temp;
    uint32_t prepared_set;
    volatile uint32_t i;
    struct inj_config_t * p_inj_config = &inj_config;
    struct inj_injection_config_t *p_injection_config = p_inj_config->p_injection_config;
    
    struct inj_injection_config_t *p_pre_injection_config = &p_injection_config[0];
    struct inj_injection_config_t *p_main_injection_config = &p_injection_config[1];
    struct inj_injection_config_t *p_post_injection_config = &p_injection_config[2];


    uint32_t *pre_phase_config = p_pre_injection_config->p_phase_config;
    uint32_t *main_phase_config = p_main_injection_config->p_phase_config;
    uint32_t *post_phase_config = p_post_injection_config->p_phase_config;


    /* Confifure SIUL2 output and input*/
    SIUL2_Configure();

    /* Initialize LINFlex, UART */
    LINFlex_init();
    
    /* Initialize eTPU */
    my_system_etpu_init();

    /* Initialize FreeMASTER */
    FMSTR_Init();
    
    /* Initialize interrupts */
    Irq_Init_Core0(); // - not necessary
    Irq_Init_Core1();

    /* Start eTPU */
    my_system_etpu_start();
    get_etpu_load_a();

    /* Calibrate ADC */
    ADC1_calibration();
    ADC2_calibration();
    
    /* Initialize ADC */
    ADC1_init();
    ADC2_init();
    
    /* Initialize eMIOS */
    eMIOS_init();
    /* Initialize BCTU */
    BCTU_init();

    /* Initialize REACM2 */
    fs_reacm2_module_init(&my_module_setup);

    address = fs_reacm2_modword_set(&my_phases, (sizeof(my_phases) / sizeof(MODULATION_WORD_T)));

    fs_reacm2_channel_init(FS_REACM2_CH_4, &ch_bank1, address);
    fs_reacm2_channel_init(FS_REACM2_CH_5, &ch_bank2, address);
    fs_reacm2_channel_enable(FS_REACM2_CH_4, &ch_bank1);
    fs_reacm2_channel_enable(FS_REACM2_CH_5, &ch_bank2);
    

    /* Main While Loop */
    while(1)
    {
	/* Pre injection */
	prepared_set = USEC2TCR1(pre_inj_duration);
	if(pre_injection == 1)
	{
	    prepared_set |= 1 << 24;
	}   
	else
	{
	    prepared_set &= ~(1 << 24);
	}   
	*pre_phase_config = prepared_set;
	/* Main injection */
	prepared_set = USEC2TCR1(main_inj_duration);
	prepared_set |= 1 << 24; // activation
	*main_phase_config = prepared_set;

	/* Post injection */
	prepared_set = USEC2TCR1(post_inj_duration);
	if(post_injection == 1)
	{
	    prepared_set |= 1 << 24;
	}
	else
	{
	    prepared_set &= ~(1 << 24);
	}  
	*post_phase_config = prepared_set;
	// single-line equivalent
	// *p_phase_config ^= (-pre_injection ^ *p_phase_config) & (1 << 24);
	
	// Interface TG eTPU function - this sets engine speed updated by FreeMASTER
	fs_etpu_tg_get_states(&tg_instance, &tg_states);
	fs_etpu_tg_config(&tg_instance, &tg_config);
	
	// update Crank and Cam latest states to see them in FreeMaster
	fs_etpu_crank_get_states(&crank_instance, &crank_states);
	fs_etpu_cam_get_states(&cam_instance, &cam_states);

	// FreeMASTER processing on background
	FMSTR_Poll();
    }
}

/***************************************************************************//*!
*
* @brief    Init LINFlex #2 to 115kbd @ 80MHz, for FreeMASTER.
*
* @return  N/A
*
******************************************************************************/
void LINFlex_init(void)
{
    MC_CGM.AC0_DC4.R = 0x80010000; // LINFlex - enable LINCLK  			- from PLL0 with divider 2
    // UART LINFlex #2 Configuration
    LINFlexD_2.LINCR1.B.SLEEP = 0x0;	// exit sleep mode
    LINFlexD_2.LINCR1.B.INIT = 0x1;	// Put LINFlex hardware in init mode  
    LINFlexD_2.UARTCR.B.UART = 0x1;	// Enable UART mode 
    LINFlexD_2.UARTCR.B.WL0 = 0x1;	// 8 bit Word Length in UART mode
    LINFlexD_2.UARTCR.B.WL1 = 0x0;	// 8 bit Word Length in UART mode
    LINFlexD_2.UARTCR.B.PCE = 0x0;	// no Parity
    LINFlexD_2.UARTCR.B.TxEn = 0x1;	// Enable transmission of data now
    LINFlexD_2.UARTCR.B.TDFLTFC = 0x0;	// Transmitter Data Field Length/TX FIFO Counter = 1 byte

    LINFlexD_2.LINIBRR.B.IBR = 0x00002B;	// LDIV Mantissa baud rate divider component (Integer Baud Rate Register - IBR)
    LINFlexD_2.LINFBRR.B.FBR = 0x6;		// Fraction baud rate divider component (Fractional Baud Rate Register - FBR)
    LINFlexD_2.LINCR1.B.INIT = 0x0;		// set LINFlex hardware to normal mode

}

/***************************************************************************//*!
*
* @brief   Evaluate eTPU engine A load.
*
* @warning - This function is applicable on eTPU2 only.
*          - The first call of this function does not return a correct result.
*          - This function presumes the TCR1 clock is configured for system 
*            clock div 1.
*
* @return  eTPU engine A load percentage (0 - 100).
*
******************************************************************************/
uint32_t get_etpu_load_a(void)
{
  static uint24_t tcr1;
         uint24_t tcr1_last;
         uint24_t idle_cnt;
         uint24_t time_cnt;

  tcr1_last = tcr1;
  tcr1 = eTPU->TB1R_A.R;
  idle_cnt = fs_etpu_get_idle_cnt_a();
  fs_etpu_clear_idle_cnt_a();

  time_cnt = 0xFFFFFF & (tcr1 - tcr1_last);
  return(100*(time_cnt - idle_cnt)/time_cnt);
}


/*******************************************************************************
 *
 * Copyright:
 *  Freescale Semiconductor, INC. All Rights Reserved.
 *  You are hereby granted a copyright license to use, modify, and
 *  distribute the SOFTWARE so long as this entire notice is
 *  retained without alteration in any modified and/or redistributed
 *  versions, and that such modified versions are clearly identified
 *  as such. No licenses are granted by implication, estoppel or
 *  otherwise under any patents or trademarks of Freescale
 *  Semiconductor, Inc. This software is provided on an "AS IS"
 *  basis and without warranty.
 *
 *  To the maximum extent permitted by applicable law, Freescale
 *  Semiconductor DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
 *  INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
 *  PARTICULAR PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH
 *  REGARD TO THE SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF)
 *  AND ANY ACCOMPANYING WRITTEN MATERIALS.
 *
 *  To the maximum extent permitted by applicable law, IN NO EVENT
 *  SHALL Freescale Semiconductor BE LIABLE FOR ANY DAMAGES WHATSOEVER
 *  (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
 *  BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER
 *  PECUNIARY LOSS) ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
 *
 *  Freescale Semiconductor assumes no responsibility for the
 *  maintenance and support of this software
 ******************************************************************************/
