/*
 * AN14010 SW EXAMPLE
 * FREQME EVALUATION
 * V2.0
 *
 * Copyright 2023 NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "fsl_debug_console.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "board.h"
#include "LPC55S36.h"
#include "freemaster.h"
#include "fsl_inputmux_connections.h"
#include "fsl_freqme.h"
#include "fsl_clock.h"
#include "fsl_inputmux.h"
#include "fsl_usart.h"
#include "freemaster_serial_usart.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/
#define FREQ_MEAS			1
#define PWM_INIT_VAL		(int16_t)(0)
#define PWM_VAL1			(int16_t)(15000)

/*******************************************************************************
 * Prototypes
 ******************************************************************************/
static void PwmInit(void);
static void FreqmeInit(void);
static void Usart0Init(void);

/*******************************************************************************
 * Variables
 ******************************************************************************/
static FMSTR_U8 recBuffer[2048];     /* Recorder #1 sampling buffer */

uint8_t  ui32PulsePol;
uint32_t ui32FreqmeResultReg;
uint32_t ui32MeasFreq;
uint32_t ui32RefFreq;
uint32_t ui32FreqMeasLoLim;
uint32_t ui32FreqMeasHiLim;
uint32_t ui32RefScale;
uint32_t ui32FreqMeasIntStatus;
int16_t i16Duty;
uint32_t ui32ResultOverflowCnt;
uint32_t ui32ResultUnderflowCnt;
uint32_t ui32ResultReadyCnt;

freq_measure_config_t config;


/*******************************************************************************
 * Code
 ******************************************************************************/
static inline void FREQME_SetRefScale(FREQME_Type *base, uint32_t ui32Scale)
{
    uint32_t tmp32;

    tmp32 = base->CTRLSTAT;
    tmp32 &= ~(FREQME_CTRLSTAT_LT_MIN_STAT_MASK
    		 | FREQME_CTRLSTAT_PULSE_MODE_MASK
			 | FREQME_CTRLSTAT_GT_MAX_STAT_MASK
			 | FREQME_CTRLSTAT_REF_SCALE_MASK
             | FREQME_CTRLSTAT_RESULT_READY_STAT_MASK);
    tmp32 |= FREQME_CTRL_W_REF_SCALE(ui32Scale);

    base->CTRL_W = tmp32;
}

/* Init Freemaster and recorder */
void FreemasterInit()
{
	Usart0Init();
	FMSTR_Init();

	FMSTR_REC_BUFF recBuffCfg;
	recBuffCfg.addr          = (FMSTR_ADDR)recBuffer;
	recBuffCfg.size          = sizeof(recBuffer);
	recBuffCfg.basePeriod_ns = 50000;
	recBuffCfg.name          = "FMSTR_REC";
	FMSTR_RecorderCreate(0, &recBuffCfg);
}

/*!
 * @brief Main function
 */
int main(void)
{
    __disable_irq();
    ui32FreqMeasLoLim = 9000;
	ui32FreqMeasHiLim = 20000;
	i16Duty = 1000;
	ui32RefScale = 10;
	ui32PulsePol  = kFREQME_PulseLowPeriod;
    BOARD_BootClockPLL150M();
    BOARD_InitBootPins();
    SYSCON->CLOCK_CTRL |=
    SYSCON_CLOCK_CTRL_FRO1MHZ_UTICK_ENA_MASK  |
	SYSCON_CLOCK_CTRL_FRO12MHZ_FREQM_ENA_MASK |
    SYSCON_CLOCK_CTRL_FRO_HF_FREQM_ENA_MASK   |
	SYSCON_CLOCK_CTRL_CLKIN_ENA_MASK |
	SYSCON_CLOCK_CTRL_XTAL32MHZ_FREQM_ENA_MASK;
    FreqmeInit();
    PwmInit();
    FreemasterInit();
    __enable_irq();

    while (1)
    {
    	FMSTR_Poll();
    }
}

/* Freqme ISR handler */
void Freqme_IRQHandler()
{
	/* Get status register */
	ui32FreqMeasIntStatus = FREQME_GetInterruptStatusFlags(FREQME);
	/* If underflow flag */
	if (ui32FreqMeasIntStatus&kFREQME_UnderflowInterruptStatusFlag)
	{
		ui32ResultUnderflowCnt++;
		FREQME_ClearInterruptStatusFlags(FREQME, kFREQME_UnderflowInterruptStatusFlag);
	}
	/* If overflow flag */
	if (ui32FreqMeasIntStatus&kFREQME_OverflowInterruptStatusFlag)
	{
		ui32ResultOverflowCnt++;
		FREQME_ClearInterruptStatusFlags(FREQME, kFREQME_OverflowInterruptStatusFlag);
	}
	/* If result ready flag */
	if (ui32FreqMeasIntStatus&kFREQME_ReadyInterruptStatusFlag)
	{
		ui32ResultReadyCnt++;
		FREQME_ClearInterruptStatusFlags(FREQME, kFREQME_ReadyInterruptStatusFlag);
	}
	/* Read result */
	ui32FreqmeResultReg = FREQME_GetMeasurementResult(FREQME);
	/* Calculate frequency - valid result for frequency measurement mode only */
	ui32MeasFreq = FREQME_CalculateTargetClkFreq(FREQME, ui32RefFreq);
	/* Set new limits */
	FREQME_SetMinExpectedValue(FREQME,ui32FreqMeasLoLim);
	FREQME_SetMaxExpectedValue(FREQME,ui32FreqMeasHiLim);
	/* Set pulse polarity */
	FREQME_SetPulsePolarity(FREQME,ui32PulsePol);
	/* Set reference scale */
	FREQME_SetRefScale(FREQME,ui32RefScale);
	/* Start new measurement cycle */
	FREQME_StartMeasurementCycle(FREQME);
	/* Set PWM duty cycle */
	PWM0->SM[0].VAL3 = (uint16_t)i16Duty;
	/* Load OK */
	PWM0->MCTRL |= PWM_MCTRL_LDOK(15);
}

static void PwmInit(void)
{
	/* Enable FlexPWM submodule 0~3 function clock source in SYSCON */
	SYSCON->PWM0SUBCTL  = SYSCON_PWM0SUBCTL_CLK0_EN_MASK
						| SYSCON_PWM0SUBCTL_CLK1_EN_MASK
						| SYSCON_PWM0SUBCTL_CLK2_EN_MASK
						| SYSCON_PWM0SUBCTL_CLK3_EN_MASK;

	SYSCON->AHBCLKCTRLSET[3] |= SYSCON_AHBCLKCTRL3_PWM0_MASK;/* Enable interface clock of FlexPWM */

	PWM0->SM[0].INIT 		= (uint16_t)(-PWM_VAL1/2);		 /* Init Counter VAL */
	PWM0->SM[0].VAL2 		= (uint16_t)(-PWM_VAL1/2);
	PWM0->SM[0].VAL0 		= 0;
	PWM0->SM[0].VAL1 		= (uint16_t)((PWM_VAL1/2) - 1);
	PWM0->SM[0].VAL3 		= (int16_t)(0);					 /* Initial PWM duty */
	PWM0->SM[0].DISMAP[0] 	= 0xF111U;						 /* PWM output in fault status */


	/* Master reload is generated every n-th opportunity */
	PWM0->SM[0].CTRL   = (PWM0->SM[0].CTRL & ~PWM_CTRL_LDFQ_MASK) | PWM_CTRL_LDFQ(0) | PWM_CTRL_PRSC(0x0) | PWM_CTRL_FULL_MASK;
	PWM0->SM[0].CTRL2 |= PWM_CTRL2_INDEP_MASK | PWM_CTRL2_INIT_SEL(0b00);

	PWM0->FSTS   = (PWM0->FSTS & ~PWM_FSTS_FFULL_MASK) | PWM_FSTS_FFULL(0x1);		/* PWM outputs are re-enabled at the start of a full cycle */
	PWM0->FFILT  = (PWM0->FFILT & ~PWM_FFILT_FILT_PER_MASK) | PWM_FFILT_FILT_PER(2);/* Fault Filter Period */
	PWM0->FCTRL  = 0xF0F0;	/* A logic 1 on the fault input indicates a fault condition */
	PWM0->FSTS 	|= 0x000F;	/* Cause a simulated fault */

	/* Start PWMs (set load OK flags and run) */
	PWM0->MCTRL = (PWM0->MCTRL & ~PWM_MCTRL_CLDOK_MASK) | PWM_MCTRL_CLDOK(0xF);
	PWM0->MCTRL = (PWM0->MCTRL & ~PWM_MCTRL_LDOK_MASK)  | PWM_MCTRL_LDOK(0xF);
	PWM0->MCTRL = (PWM0->MCTRL & ~PWM_MCTRL_RUN_MASK)   | PWM_MCTRL_RUN(0xF);
	PWM0->FSTS  = (PWM0->FCTRL & ~PWM_FSTS_FFLAG_MASK)  | PWM_FSTS_FFLAG(0xF);

	/* Enable PWM outputs for submodules one, two and three */
	PWM0->OUTEN = (PWM0->OUTEN & ~PWM_OUTEN_PWMA_EN_MASK) | PWM_OUTEN_PWMA_EN(7);
}

static void FreqmeInit(void)
{
    /*
     * config->operateMode = kFREQME_FreqMeasurementMode;
     * config->operateModeAttribute.refClkScaleFactor = 0U;
     * config->enableContinuousMode                   = false;
     */
    FREQME_GetDefaultConfig(&config);

#if FREQ_MEAS
    /* FREQUENCY MEASUREMENT MODE */
    /* Connect signals to FREQME inputs */
    INPUTMUX_Init(INPUTMUX);
    INPUTMUX_AttachSignal(INPUTMUX, 0UL, kINPUTMUX_FroOsc12MhzToFreqmeasRef);
    INPUTMUX_AttachSignal(INPUTMUX, 0UL, kINPUTMUX_MainSysClockToFreqmeasTarget);
    /* Get reference clock value */
    ui32RefFreq = CLOCK_GetFreq(kCLOCK_Fro12M);
    /* Configure  FREQME */
    config.operateMode = kFREQME_FreqMeasurementMode;
    config.operateModeAttribute.refClkScaleFactor = ui32RefScale;
    config.enableContinuousMode = false;

#else
    /* PULSE WIDTH MEASUREMENT MODE */
    /* Connect signals to FREQME inputs */
    INPUTMUX_Init(INPUTMUX);
    INPUTMUX_AttachSignal(INPUTMUX, 0UL, kINPUTMUX_FreqmeGpioClkAToFreqmeasRef);
    INPUTMUX_AttachSignal(INPUTMUX, 0UL, kINPUTMUX_MainSysClockToFreqmeasTarget);
    /* Configure  FREQME */
    config.operateMode = kFREOME_PulseWidthMeasurementMode;
    config.operateModeAttribute.pulsePolarity = ui8PulsePol;
    config.enableContinuousMode = false;
#endif
    /* Enable clock and init module */
    FREQME_Init(FREQME, &config);
    FREQME_SetMinExpectedValue(FREQME,ui32FreqMeasLoLim);
    FREQME_SetMaxExpectedValue(FREQME,ui32FreqMeasHiLim);
    FREQME_EnableInterrupts(FREQME,kFREQME_UnderflowInterruptEnable
    		                      |kFREQME_OverflowInterruptEnable
								  |kFREQME_ReadyInterruptEnable);
	NVIC_EnableIRQ(Freqme_IRQn);
	NVIC_SetPriority(Freqme_IRQn, 1);
    FREQME_StartMeasurementCycle(FREQME);
}

/*
 * USART Module initialization
 */
static void Usart0Init(void)
{
    /* attach main clock divide to FLEXCOMM0 (debug console) */
    CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);

    usart_config_t config;
    /*
     *   usartConfig->baudRate_Bps = 115200U;
     *   usartConfig->parityMode = kUSART_ParityDisabled;
     *   usartConfig->stopBitCount = kUSART_OneStopBit;
     *   usartConfig->bitCountPerChar = kUSART_8BitsPerChar;
     *   usartConfig->loopback = false;
     *   usartConfig->enableTx = false;
     *   usartConfig->enableRx = false;
    */
    USART_GetDefaultConfig(&config);
    /* Override the Default configuration to satisfy FreeMASTER needs */
    config.baudRate_Bps = 115200U;
    config.enableTx = true;
    config.enableRx = true;

    USART_Init((USART_Type*)BOARD_DEBUG_UART_BASEADDR, &config, BOARD_DEBUG_UART_CLK_FREQ);

    /* Register communication module used by FreeMASTER driver. */
    FMSTR_SerialSetBaseAddress((USART_Type*)BOARD_DEBUG_UART_BASEADDR);

#if FMSTR_SHORT_INTR || FMSTR_LONG_INTR
    /* Enable UART interrupts. */
    EnableIRQ(BOARD_UART_IRQ);
    EnableGlobalIRQ(0);
#endif

}
