/******************************************************************************
 * @file     main.c
 * @version  V3.00
 * $Revision: 1 $
 * $Date: 14/08/05 10:14a $
 * @brief    Demonstrate APU paly 8kHz audio 
 *
 * @note
 * Copyright (C) 2014 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "N572.h"

extern char		u32audioBegin,u32audioEnd;

static  uint32_t s_u32ReadIndex = 0;
static	uint32_t s_bExit;
static  int16_t *s_pi16StartAdd=0;
static  int16_t *s_pi16EndAdd=0;



void APU_IRQHandler()
{
	int16_t *i16Buff;
	
	APU_CLR_INT_FLAG(APU);
	
	i16Buff = s_pi16StartAdd+s_u32ReadIndex;
	if (APU_GET_INT_THD(APU) == 3)
	{
		/* output (channel0+channel1)is clipped to 13 bits*/
		APU_SET_CH0DATA(APU, 0, i16Buff[0]>>3);
		APU_SET_CH0DATA(APU, 1, i16Buff[1]>>3);
		APU_SET_CH0DATA(APU, 2, i16Buff[2]>>3);
		APU_SET_CH0DATA(APU, 3, i16Buff[3]>>3);
		APU_SET_INT_THD(APU, 7);
	}
	else
	{
		APU_SET_CH0DATA(APU, 4, i16Buff[0]>>3);
		APU_SET_CH0DATA(APU, 5, i16Buff[1]>>3);
		APU_SET_CH0DATA(APU, 6, i16Buff[2]>>3);
		APU_SET_CH0DATA(APU, 7, i16Buff[3]>>3);
		APU_SET_INT_THD(APU, 3);
	}
	s_u32ReadIndex+=4;	
	if (s_u32ReadIndex>=(s_pi16EndAdd-s_pi16StartAdd+1))	 	 
		s_bExit = TRUE;
}


void SYS_Init(void)
{
/* Unlock protected registers */
    SYS_UnlockReg();
	
	/* Procedure to configure the wait state of SDRAM */
	SYS_SET_RAM_WAIT_STATE(SYS_IPRST0_RAMWS_ZERO_WAIT);
	/* Set flash access with 1 wait state, if system clock is greater than 24MHz*/
	SYS_SET_CPU_WAIT_STATE(SYS_IPRST0_CPUWS_1HCLK_WAIT);
	/* Enable external 32K oscillator */
	CLK_EnableXtalRC(CLK_PWRCTL_XTL32K_EN_Msk);
	/* Enable PLL1 & PLL2 */
	CLK_SetPLL1Mode(PLL_NORMAL_MODE);
	CLK_SetPLL2Mode(PLL_NORMAL_MODE);
#if defined(__N572F072__) 
	/* Select PLL1 as PLL2 input source, and PLL2 output 48MHz*/
	CLK_SetPLL2(PLL2_SRC_PLL1_FOUT, PLL2_48M);
	CLK_EnableLDO30();	
#endif
	
	/* Switch HCLK clock source to PLL2, system clock output 48MHz */
    CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_PLL2_FOUT,CLK_CLKDIV_HCLK(1));

    /* Lock protected registers */
    SYS_LockReg();
}

void APU_Init(void)
{
	uint8_t u8Loop;
	
	/* Enable ADC APB bus and reset IP */
	CLK_EnableModuleClock(APU_MODULE);
	SYS_ResetModule(APU_RST);
	/* Timer0 is used as the channel 0 sample rate control timer */
	CLK_EnableModuleClock(TMR0_MODULE);
	CLK_SetModuleClock(TMR0_MODULE, CLK_CLKSEL1_TMR0SEL_HCLK, MODULE_NoMsk);
	SYS_ResetModule(TMR0_RST);
	
	APU_Open(APU);
	APU_SetSampleRate(APU, 12000);
	APU_SET_BYPASSPA(APU, APU_NONBYPASS_PA);
	APU_DISABLE_PA(APU);
	APU_SetVolGaindB(APU, -18);
	for (u8Loop = 0; u8Loop< 8 ;u8Loop++)
		APU_SET_CH0DATA(APU, u8Loop, 0);
	APU_ENABLE_DAC(APU);
	APU_SET_INT_THD(APU,7);
	APU_ENABLE_INT(APU);
	APU_START_PLAY(APU);
	
	while(APU_GET_INT_FLAG(APU) == 0);
	
	APU_CLR_INT_FLAG(APU);
	APU_STOP_PLAY(APU);
	
	NVIC_ClearPendingIRQ(APU_IRQn);		
	NVIC_EnableIRQ(APU_IRQn);
	APU_SetVolGaindB(APU, -3);
	APU_SetSampleRate(APU, 8000);
	APU_SET_INT_THD(APU,3);
	APU_ENABLE_PA(APU);							 	
}

void PCMBuff_Init()/* Init PCM data to APU channel0 */							
{ 
	uint8_t u8Loop;
	
	s_u32ReadIndex = 0;
	s_bExit = FALSE;
	for (u8Loop = 0; u8Loop< 8 ;u8Loop++)
		APU_SET_CH0DATA(APU, u8Loop, 0);
	s_pi16StartAdd =  (int16_t *)&u32audioBegin;
	s_pi16EndAdd = (int16_t *)&u32audioEnd;
}

/*Main function*/
int main()
{																  
	uint8_t	u8Option;

	/* Lock protected registers */
    if(SYS->REGLCTL == 1) // In end of main function, program issued CPU reset and write-protection will be disabled.
        SYS_LockReg();
	
	/* Init System, IP clock and multi-function I/O */
    SYS_Init(); //In the end of SYS_Init() will issue SYS_LockReg() to lock protected register. If user want to write protected register, please issue SYS_UnlockReg() to unlock protected register.
	
	APU_Init();
	
	
	PCMBuff_Init();

	printf("\n\nCPU @ %dHz\n", SystemCoreClock);
		
	printf("\n\n");
	printf("+----------------------------------------------------------------------+\n");
	printf("|                       APU Driver Sample Code                         |\n");
	printf("+----------------------------------------------------------------------+\n");
	printf(" APU Playing Sample Rate : %dHz                                         \n", APU_GetSampleRate(APU));
	printf(" APU Volume Gain : %ddB                                                 \n", APU_GetVolGaindB(APU));
	
	while (1)
	{
		APU_START_PLAY(APU);
		
		while (!s_bExit);								 // wait file end
		
		APU_STOP_PLAY(APU);									 // disable timer0 count
		
		printf("Playback again: Y/N.\n");
	
		u8Option = getchar();	
	
		if (u8Option=='Y'||u8Option=='y')
		{
			PCMBuff_Init();
	   		s_bExit = FALSE;
	   		continue;
		}
		break;
	}

	APU_STOP_PLAY(APU);	

	
	SYS_ResetModule(APU_RST);
	SYS_ResetModule(TMR0_RST);
	CLK_DisableModuleClock(APU_MODULE);
	CLK_DisableModuleClock(TMR0_MODULE);

	return 0;
}

/*** (C) COPYRIGHT 2014 Nuvoton Technology Corp. ***/
