/*********************************************************************//**
 * @brief		I2S IRQ Handler
 * @param[in]	None
 * @return 		None
 **********************************************************************/
void I2S_IRQHandler()
{
	uint32_t RXLevel = 0;

	//Check RX interrupt
	if(I2S_GetIRQStatus(LPC_I2S, I2S_RX_MODE))
	{
		RXLevel = I2S_GetLevel(LPC_I2S, I2S_RX_MODE);
		if ( (RXLevel != RXFIFO_EMPTY) && !I2SRXDone )
		{
			while ( RXLevel > 0 )
			{
				if ( I2SReadLength == BUFFER_SIZE )
				{
					//Stop RX
					I2S_Stop(LPC_I2S, I2S_RX_MODE);
					// Disable RX
					I2S_IRQCmd(LPC_I2S, I2S_RX_MODE, DISABLE);
					I2SRXDone = 1;
					break;
				}
				else
				{
					I2SRXBuffer[I2SReadLength++] = LPC_I2S->I2SRXFIFO;
				}
				RXLevel--;
			}
		}
	}
	return;
}
/*******************************************************************************
* Function Name: I2S_Sleep
********************************************************************************
*
* Summary:
*  Prepares I2S goes to sleep.
*
* Parameters:
*  None.
*
* Return:
*  None.
*
* Global Variables:
*  I2S_backup - modified when non-retention registers are saved.
*
* Reentrant:
*  No.
*
*******************************************************************************/
void I2S_Sleep(void) 
{
    /* Get component state */
    I2S_backup.enableState = ((uint8) I2S_IS_ENABLE);

    /* Save registers configuration */
    I2S_SaveConfig();

    /* Stop component */
    I2S_Stop();
}
/**
  * @brief  I2S_Freq_Config 根据采样频率配置iis总线,在播放音频文件时可从文件中解码获取
  * @param  SampleFreq 采样频率
  * @retval none
  */
void I2S_Freq_Config(uint16_t SampleFreq)
{
	I2S_InitTypeDef I2S_InitStructure;

	I2S_Stop();
	I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx;						// 配置I2S工作模式
	I2S_InitStructure.I2S_Standard = I2S_Standard_LSB;				// 接口标准 
	I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b;		// 数据格式,16bit 
	I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Enable;	// 主时钟模式 
	I2S_InitStructure.I2S_AudioFreq = SampleFreq;							// 音频采样频率 
	I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low;  			
	I2S_Init(SPI2, &I2S_InitStructure);
	
	I2S_Cmd(SPI2, ENABLE);																		//使能iis总线
}
Exemple #4
0
void Audio_Init(uint32_t samplefreq)
{
	I2S_MODEConf_Type I2S_ClkConfig;
	I2S_CFG_Type I2S_ConfigStruct;

	Audio_Reset_Data_Buffer();
	NVIC_DisableIRQ(I2SIRQ);

	switch(samplefreq){
	case 11025:
	case 22050:
	case 44100:
		audio_buffer_size = 1764;
		break;
	case 8000:
	case 16000:
	case 32000:
	case 48000:
	default:
		audio_buffer_size = samplefreq * 4 * AUDIO_MAX_PC / 1000;
		break;
	}
	
	/* Reset UDA1380 on board Hitex */
//	scu_pinmux(8,2,MD_PUP, FUNC0);
//	GPIO_SetDir(4, 1<<2, 1);
//	GPIO_ClearValue(4, 1<<2);

/* Initialize I2S peripheral ------------------------------------*/
	/* Init I2C */
	I2C_Init(LPC_I2C, 100000);
	/* Enable Slave I2C operation */
	I2C_Cmd(LPC_I2C, ENABLE);
	/* Init UDA1380 CODEC */
	UDA1380_init();
/* Initialize I2S peripheral ------------------------------------*/
	scu_pinmux(6,0, MD_PUP, 4);			// I2S_RX_SCK
	scu_pinmux(6,1, MD_PUP, 3);			// I2S_RX_WS
	scu_pinmux(6,2, MD_PUP, 3);			// I2S_RX_SDA

	scu_pinmux(3,0, MD_PUP, 2);			// I2S_TX_SCK
	scu_pinmux(3,1, MD_PUP, 0);			// I2S_TX_WS
	scu_pinmux(3,2, MD_PUP, 0);			// I2S_TX_SDA

	I2S_Init(I2S);

	/* setup:
	 * 		- wordwidth: 16 bits
	 * 		- stereo mode
	 * 		- master mode for I2S_TX
	 * 		- Frequency = 44.1 kHz
	 */

	/* Audio Config*/
	I2S_ConfigStruct.wordwidth = I2S_WORDWIDTH_16;
	I2S_ConfigStruct.mono = I2S_STEREO;
	I2S_ConfigStruct.stop = I2S_STOP_ENABLE;
	I2S_ConfigStruct.reset = I2S_RESET_ENABLE;
	I2S_ConfigStruct.ws_sel = I2S_MASTER_MODE;
	I2S_ConfigStruct.mute = I2S_MUTE_DISABLE;
	I2S_Config(I2S,I2S_TX_MODE,&I2S_ConfigStruct);

	/* Clock Mode Config*/
	I2S_ClkConfig.clksel = I2S_CLKSEL_FRDCLK;
	I2S_ClkConfig.fpin = I2S_4PIN_DISABLE;
	I2S_ClkConfig.mcena = I2S_MCLK_DISABLE;
	I2S_ModeConfig(I2S,&I2S_ClkConfig,I2S_TX_MODE);

	I2S_FreqConfig(I2S, samplefreq, I2S_TX_MODE);

	I2S_Stop(I2S, I2S_TX_MODE);

	/* TX FIFO depth is 4 */
	I2S_IRQConfig(I2S,I2S_TX_MODE,I2S_TX_LEVEL);
	I2S_IRQCmd(I2S,I2S_TX_MODE,ENABLE);
	I2S_Start(I2S);
	NVIC_EnableIRQ(I2SIRQ);
}
/*********************************************************************//**
 * @brief		c_entry: Main program body
 * @param[in]	None
 * @return 		int
 **********************************************************************/
int c_entry (void) {                       /* Main Program */
	I2S_MODEConf_Type I2S_ClkConfig;
	I2S_CFG_Type I2S_ConfigStruct;
	PINSEL_CFG_Type PinCfg;

	uint32_t i;
	/* Initialize debug via UART0
	 * – 115200bps
	 * – 8 data bit
	 * – No parity
	 * – 1 stop bit
	 * – No flow control
	 */
	debug_frmwrk_init();

	//print menu screen
	print_menu();
/* Initialize I2S peripheral ------------------------------------*/
	/* Pin configuration:
	 * Assign: 	- P0.4 as I2SRX_CLK
	 * 			- P0.5 as I2SRX_WS
	 * 			- P0.6 as I2SRX_SDA
	 * 			- P0.7 as I2STX_CLK
	 * 			- P0.8 as I2STX_WS
	 * 			- P0.9 as I2STX_SDA
	 */
	PinCfg.Funcnum = 1;
	PinCfg.OpenDrain = 0;
	PinCfg.Pinmode = 0;
	PinCfg.Pinnum = 4;
	PinCfg.Portnum = 0;
	PINSEL_ConfigPin(&PinCfg);
	PinCfg.Pinnum = 5;
	PINSEL_ConfigPin(&PinCfg);
	PinCfg.Pinnum = 6;
	PINSEL_ConfigPin(&PinCfg);
	PinCfg.Pinnum = 7;
	PINSEL_ConfigPin(&PinCfg);
	PinCfg.Pinnum = 8;
	PINSEL_ConfigPin(&PinCfg);
	PinCfg.Pinnum = 9;
	PINSEL_ConfigPin(&PinCfg);

	Buffer_Init();

	I2S_Init(LPC_I2S);

	/* setup:
	 * 		- wordwidth: 16 bits
	 * 		- stereo mode
	 * 		- master mode for I2S_TX and slave for I2S_RX
	 * 		- ws_halfperiod is 31
	 * 		- not use mute mode
	 * 		- use reset and stop mode
	 * 		- select the fractional rate divider clock output as the source,
	 * 		- disable 4-pin mode
	 * 		- MCLK ouput is disable
	 * 		- Frequency = 44.1 kHz
	 * Because we use mode I2STXMODE[3:0]= 0000, I2SDAO[5]=0 and
	 * I2SRX[3:0]=0000, I2SDAI[5] = 1. So we have I2SRX_CLK = I2STX_CLK
	 * --> I2SRXBITRATE = 1 (not divide TXCLK to produce RXCLK)
	 */

	/* Audio Config*/
	I2S_ConfigStruct.wordwidth = I2S_WORDWIDTH_16;
	I2S_ConfigStruct.mono = I2S_STEREO;
	I2S_ConfigStruct.stop = I2S_STOP_ENABLE;
	I2S_ConfigStruct.reset = I2S_RESET_ENABLE;
	I2S_ConfigStruct.ws_sel = I2S_MASTER_MODE;
	I2S_ConfigStruct.mute = I2S_MUTE_DISABLE;
	I2S_Config(LPC_I2S,I2S_TX_MODE,&I2S_ConfigStruct);

	I2S_ConfigStruct.ws_sel = I2S_SLAVE_MODE;
	I2S_Config(LPC_I2S,I2S_RX_MODE,&I2S_ConfigStruct);

	/* Clock Mode Config*/
	I2S_ClkConfig.clksel = I2S_CLKSEL_FRDCLK;
	I2S_ClkConfig.fpin = I2S_4PIN_DISABLE;
	I2S_ClkConfig.mcena = I2S_MCLK_DISABLE;
	I2S_ModeConfig(LPC_I2S,&I2S_ClkConfig,I2S_TX_MODE);
	I2S_ModeConfig(LPC_I2S,&I2S_ClkConfig,I2S_RX_MODE);

	I2S_FreqConfig(LPC_I2S, 44100, I2S_TX_MODE);
	I2S_SetBitRate(LPC_I2S, 0, I2S_RX_MODE);

	I2S_Stop(LPC_I2S, I2S_TX_MODE);
	I2S_Stop(LPC_I2S, I2S_RX_MODE);

	NVIC_EnableIRQ(I2S_IRQn);

	/* RX FIFO depth is 1, TX FIFO depth is 8. */
	I2S_IRQConfig(LPC_I2S,I2S_TX_MODE,8);
	I2S_IRQConfig(LPC_I2S,I2S_RX_MODE,1);
	I2S_IRQCmd(LPC_I2S,I2S_RX_MODE,ENABLE);
	I2S_Start(LPC_I2S);

/* I2S transmit ---------------------------------------------------*/
	while ( I2SWriteLength < BUFFER_SIZE )
	{
		while(I2S_GetLevel(LPC_I2S, I2S_TX_MODE)==TXFIFO_FULL);
		I2S_Send(LPC_I2S, I2STXBuffer[I2SWriteLength++]);
	}

	I2STXDone = 1;

	/* Wait for transmit/receive complete */
	while ( !I2SRXDone || !I2STXDone );
	for(i=0;i<BUFFER_SIZE;i++)
	{
		_DBH32(I2SRXBuffer[i]);_DBG_("");
	}
	/* Verify RX and TX Buffer */
	if(Buffer_Verify())
	{
		_DBG_("Verify Buffer: OK...");
	}
	else
	{
		_DBG_("Verify Buffer: ERROR...");
	}


	return 0;
}
/**
  * @brief  wav_player 进行wav文件播放
	*					wav格式存储的就是PCM数据,不需要解码
  * @param  filename:要播放的文件路径
  * @retval none
  */
static void wav_player(const char *filename)
{
	short *p;
	WavHead *wav;	

	//打开音频文件
	fres = f_open (&file, filename, FA_READ );
	
	//打开失败
	if (fres!=FR_OK)
	{
		printf("read file %s error  ! open another file\r\n",filename);
		fres = f_close (&file);
		
		if (++play_index>=file_num)	//索引值加1
		{
				play_index=0;						//归0,所以如果所有文件都打开失败会一直循环
		}				
		return ;										//文件无法打开,终止解码。进入下一次循环,读取下一个文件
	}
	
		//显示播放图标
	Lcd_GramScan(1);
	LCD_Clear(12,88,8,145,BACKGROUND);
	Lcd_show_bmp(320-(103+((play_index-((current_page-1)*8))*18)),240-20,"/mp3player/ui_playing.bmp");	
	
	
	fres = f_read(&file,buffer,512,&rw_num);							//读取文件头
	
	wav = (WavHead *)buffer;															//整理格式
		
	printf("\r\n samprate: %dHz", wav->dwSamplesPerSec);	//采样率

	if(wav->dwSamplesPerSec >= I2S_AudioFreq_Default)
		I2S_Freq_Config(wav->dwSamplesPerSec);							//设置采样率

		//播放循环	
		while(player_state != S_SWITCH)			//循环本过程播放音频,直到切歌
		{
			if (player_state == S_STOP)
				{			
					even_process();
					continue;											//暂停的时候跳出本循环
				}
				
			player_state = S_PLAY;						//状态更新为正在播放
		
				
			//读取wav文件
			p = (short *)(buffer+sizeof(buffer)/2*bufflag);		
			fres = f_read(&file, p, sizeof(buffer)/2, &rw_num);
			if(fres != FR_OK)
			{
				printf("读取%s失败! %d\r\n",filename,fres);
				break;
			}
			
			/* 等待DMA播放完,这段时间我们可以干其他的事,事件处理 */
			while((DMA1_Channel5->CCR & DMA_CCR1_EN) && !(DMA1->ISR&DMA1_IT_TC5))
			{
					even_process();
			}
        DMA_ClearFlag(DMA1_FLAG_TC5 | DMA1_FLAG_TE5);
        DMA_I2S_Configuration((uint32_t)p, rw_num/2);
				bufflag = 1 -bufflag;				//切换buffer																	
							
		
			if(file.fptr==file.fsize) 		//如果指针指向了文件尾,表示数据全部读完
			{
				printf("END\r\n");
				if(play_index<file_num-1)		//自动开始下一首歌曲
				{
					play_index++;
					player_state = S_SWITCH;	
				}
				else
				{
					play_index = 0;
					player_state = S_SWITCH;
				}
						
				break; 									//跳出这首歌的播放状态	while break; 
			}  	
	}
	
	f_close(&file);								//结束播放本歌曲,关闭文件
	I2S_Stop();
}
/**
  * @brief  mp3_player 进行mp3文件解码、播放
  * @param  filename:要播放的文件路径
  * @retval none
  */
static void mp3_player(const char *filename)
{
	int err, i, outputSamps, current_sample_rate = 0;	

	int						read_offset = 0;				/* 读偏移指针				*/
	int						bytes_left = 0;					/* 剩余字节数				*/	
	unsigned long	Frames = 0;							/* mP3帧计数				*/
	unsigned char	*read_ptr = buffer;			/* 缓冲区指针				*/
	HMP3Decoder		Mp3Decoder;						  /* mp3解码器指针		*/
	

	
	//打开音频文件
	fres = f_open (&file, filename, FA_READ );
	
	//打开失败
	if (fres!=FR_OK)
	{
		printf("read file %s error  ! open another file\r\n",filename);
		fres = f_close (&file);
		
		if (++play_index>=file_num)	//索引值加1
		{
				play_index=0;						//归0,所以如果所有文件都打开失败会一直循环
		}				
		return ;										//文件无法打开,终止解码。进入下一次循环,读取下一个文件
	}
		
	//打开成功
	//初始化MP3解码器
	Mp3Decoder = MP3InitDecoder();	
	
	//获取输入数据流,调用helix库解码,输出PCM数据,约20ms完成一次循环
	//开始进入播放状态,期间中断会修改touch_even状态
	while(player_state != S_SWITCH)	//循环1, 如果touch_even不是切歌状态则继续呆在循环体里 
	{
		//有时出现解码错误,错误后继续在本循环体内,继续播放
		
		//显示播放图标
		Lcd_GramScan(1);
		LCD_Clear(12,88,8,145,BACKGROUND);
		Lcd_show_bmp(320-(103+((play_index-((current_page-1)*8))*18)),240-20,"/mp3player/ui_playing.bmp");
		
		//读取mp3文件
		fres = f_read(&file, buffer, sizeof(buffer), &rw_num);
		if(fres != FR_OK)
		{
			printf("读取%s失败! %d\r\n",filename,fres);
			break;
			//return;
		}
		read_ptr = buffer;									//指向mp3输入流
		bytes_left = rw_num;								//实际读到的输入流大小大小

		//按帧处理	
		while(player_state != S_SWITCH)			//循环2,循环本过程播放音频,直到按了下一首、上一首	
		{
			if (player_state == S_STOP)
			{								
				even_process();									//检查是否有事件需要处理
				continue;												//暂停的时候结束本次循环
			}
				
			player_state = S_PLAY;						//状态更新为正在播放
			
			read_offset = MP3FindSyncWord(read_ptr, bytes_left);	//寻找帧同步,返回第一个同步字的位置
			if(read_offset < 0)																		//没有找到同步字
			{
				break;																							//跳出循环2,回到循环1	
			}
			
			read_ptr += read_offset;					//偏移至同步字的位置
			bytes_left -= read_offset;				//同步字之后的数据大小	
			if(bytes_left < 1024)							//补充数据
			{
				/* 注意这个地方因为采用的是DMA读取,所以一定要4字节对齐  */
				i=(uint32_t)(bytes_left)&3;									//判断多余的字节
				if(i) i=4-i;														//需要补充的字节
				memcpy(buffer+i, read_ptr, bytes_left);	//从对齐位置开始复制
				read_ptr = buffer+i;										//指向数据对齐位置
				fres = f_read(&file, buffer+bytes_left+i, sizeof(buffer)-bytes_left-i, &rw_num);//补充数据
				bytes_left += rw_num;										//有效数据流大小
			}
			err = MP3Decode(Mp3Decoder, &read_ptr, &bytes_left, outBuf[bufflag], 0);					//开始解码 参数:mp3解码结构体、输入流指针、输入流大小、输出流指针、数据格式
			Frames++;			
			
			if (err != ERR_MP3_NONE)									//错误处理
			{
				switch (err)
				{
					case ERR_MP3_INDATA_UNDERFLOW:
						printf("ERR_MP3_INDATA_UNDERFLOW\r\n");
						read_ptr = buffer;
						fres = f_read(&file, read_ptr, sizeof(buffer), &rw_num);
						bytes_left = rw_num;
						break;
			
					case ERR_MP3_MAINDATA_UNDERFLOW:
						/* do nothing - next call to decode will provide more mainData */
						printf("ERR_MP3_MAINDATA_UNDERFLOW\r\n");
						break;
			
					default:
						printf("UNKNOWN ERROR:%d\r\n", err);
			
						// 跳过此帧
						if (bytes_left > 0)
						{
							bytes_left --;
							read_ptr ++;
						}	
						break;
				}
			}
			else		//解码无错误,准备把数据输出到PCM
			{
				MP3GetLastFrameInfo(Mp3Decoder, &Mp3FrameInfo);		//获取解码信息				

		    /* 根据解码信息设置采样率 */
				if (Mp3FrameInfo.samprate != current_sample_rate)	//采样率 
				{
					current_sample_rate = Mp3FrameInfo.samprate;

					printf(" \r\n Bitrate       %dKbps", Mp3FrameInfo.bitrate/1000);
				  printf(" \r\n Samprate      %dHz", current_sample_rate);
					printf(" \r\n BitsPerSample %db", Mp3FrameInfo.bitsPerSample);
					printf(" \r\n nChans        %d", Mp3FrameInfo.nChans);
					printf(" \r\n Layer         %d", Mp3FrameInfo.layer);
					printf(" \r\n Version       %d", Mp3FrameInfo.version);
					printf(" \r\n OutputSamps   %d", Mp3FrameInfo.outputSamps);

					if(current_sample_rate >= I2S_AudioFreq_Default)	//I2S_AudioFreq_Default = 2,正常的帧,每次都要改速率
					{
						I2S_Freq_Config(current_sample_rate);						//根据采样率修改iis速率
					}
				}
				
				/* 输出到DAC */
				outputSamps = Mp3FrameInfo.outputSamps;							//PCM数据个数
				
				if (outputSamps > 0)
				{
					if (Mp3FrameInfo.nChans == 1)	//单声道
					{
						//单声道数据需要复制一份到另一个声道
						for (i = outputSamps - 1; i >= 0; i--)
						{
							outBuf[bufflag][i * 2] = outBuf[bufflag][i];
							outBuf[bufflag][i * 2 + 1] = outBuf[bufflag][i];
						}
						outputSamps *= 2;
					}
				
					//非单声道数据可直接由DMA传输到IIS交给DAC
					/* 等待DMA播放完,这段时间我们可以干其他的事,扫描事件进行处理 */
					while((DMA1_Channel5->CCR&DMA_CCR1_EN) && !(DMA1->ISR&DMA1_IT_TC5))
					{
							even_process();							
						}
						
					/*DMA传输完毕*/
			    DMA_ClearFlag(DMA1_FLAG_TC5 | DMA1_FLAG_TE5);
			    DMA_I2S_Configuration((uint32_t)outBuf[bufflag], outputSamps);
					bufflag = 1 -bufflag;																			//切换buffer

				}//if (outputSamps > 0)
			}//else 解码正常
			
		
		if(file.fptr==file.fsize) 		//如果指针指向了文件尾,表示数据全部读完
		{
			printf("END\r\n");
			if(play_index<file_num-1)		//自动开始下一首歌曲
			{
				play_index++;
				player_state = S_SWITCH;	//进入切歌状态,跳出
			}
			else
			{
				play_index = 0;
				player_state = S_SWITCH;
			}
					
			break; 										//跳出这首歌的播放状态	while break; 
		}
  	
	}//循环2		内 while(player_state != S_SWITCH)	
	
 }//循环1  	外 while(player_state != S_SWITCH)

	f_close(&file);							//结束播放本歌曲,关闭文件
	MP3FreeDecoder(Mp3Decoder);
	I2S_Stop();
	
}