/*********************************************************************//** * @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总线 }
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(); }