📄 interface.c
字号:
/***************************************************************************\
Copyright (c) 2004-2007 www.up-tech.com, All rights reserved.
by allan_hua 2005.12.28
\***************************************************************************/
/***************************************************************************\
#说明: 系统硬件与播放器软件的接口文件,包含系统硬件接口的初始化、缓冲区
的设置和使用,用户向不同平台移植只需修改这个文件和并完成函数
int mp3_input_read(unsigned char *buf, int len)功能即可。
\***************************************************************************/
#include "reg2410.h"
#include "macro.h"
#include "../inc/sys/io.h"
#include "isr.h"
enum audio_command {
AUDIO_COMMAND_INIT,
AUDIO_COMMAND_CONFIG,
AUDIO_COMMAND_PLAY,
AUDIO_COMMAND_STOP,
AUDIO_COMMAND_FINISH
};
struct audio_config {
enum audio_command command;
unsigned int channels;
unsigned int speed;
} ;
enum audio_mode {
AUDIO_MODE_ROUND,
AUDIO_MODE_DITHER
};
struct audio_play
{
enum audio_command command;
unsigned int nsamples;
signed int const *samples[2];
enum audio_mode mode;
struct audio_stats *stats;
};
struct audio_init {
enum audio_command command;
char const *path;
};
# define MAX_NSAMPLES (1152 * 3) /* allow for resampled frame */
static int opened;
# define NSLOTS 25 /* 大约3秒钟数据 (44.1 kHz) */
# define NBUFFERS 3 /* 3个缓冲区 */
static struct buffer {
int speed;
volatile int playing;
unsigned int pcm_length;
unsigned char pcm_data[NSLOTS * MAX_NSAMPLES * 2 * 2];
} output[NBUFFERS];
static int bindex; //要填入数据的缓冲数据索引 0->1->2->0->1....
static int playing_index; //正在播放的缓冲数据索引 0->1->2->0->1....
static c_speed=44100;
//========================================
typedef struct _SRT
{
unsigned int pllcon;
unsigned int div;
}SRT;
//================只适用于44.1k的 CBR =========================
SRT srt[9]={
{(0xa1<<12)|(0x03<<4)|1,0x42}, //48.0K
{(0xa1<<12)|(0x03<<4)|1,0x42}, //44.1K
{(0xa1<<12)|(0x03<<4)|1,0x42}, //32.0K
{(0xa1<<12)|(0x03<<4)|1,0x42}, //24.0K
{(0xa1<<12)|(0x03<<4)|1,0x42}, //22.050K
{(0xa1<<12)|(0x03<<4)|1,0x42}, //16.0K
{(0xa1<<12)|(0x03<<4)|1,0x42}, //12.0K
{(0xa1<<12)|(0x03<<4)|1,0x42}, //11.025K
{(0xa1<<12)|(0x03<<4)|1,0x42}, //8.0K
};
//============================================================
void IIS_PortSetting(void);
int Audio_Init(void);
static void uda1341_l3_address(U8 data);
static void uda1341_l3_data(U8 data);
unsigned Init_UDA1341(void);
int rate_index(unsigned int rate)
{
switch (rate) {
case 48000: return 0;
case 44100: return 1;
case 32000: return 2;
case 24000: return 3;
case 22050: return 4;
case 16000: return 5;
case 12000: return 6;
case 11025: return 7;
case 8000: return 8;
}
return -1;
}
//***************************************************************************
//重新置采样率
void set_sample_rate(int speed)
{
int sri;
static int curr_speed=0;
if(speed != curr_speed)
{
curr_speed=speed;
if((sri=rate_index(curr_speed))<0) sri=1;
rMPLLCON=srt[sri].pllcon;
rIISPSR=srt[sri].div;
}
}
#define ClearPending(x) do{rSRCPND &= ~(1 << (x)); rINTPND = 0;}while(0)
extern void INTS_OFF(void);
extern void INTS_ON(void);
//BDMA中断
void IIS_DMA_Done(int vector, void* data)
{
Disable_Irq(IRQ_DMA2);
ClearPending(IRQ_DMA2);
rIISCON &= ~(1<<0); //IIS Dis
rDMASKTRIG2 = (0<<1);
output[playing_index].pcm_length=0; //本缓冲区长度设为0
output[playing_index].playing=0; //清除本缓冲区播放标志,以便装放新的数据
playing_index=(playing_index+1) % NBUFFERS; //指到下一个缓冲区
if(output[playing_index].playing==0)
{ rDMASKTRIG2 = (0<<1); opened=0;return;} //如果没有数据,
//DMA2 for AudioOut
rDISRC2 = (U32)(output[playing_index].pcm_data);//For Src
rDCON2|=((output[playing_index].pcm_length)/2); //important to DMA count
rDMASKTRIG2 |= (1<<1); //DMA2En
rIISCON |= (1<<0); //IIS Enable;
set_sample_rate(output[playing_index].speed); //根据采样率设置主频
Enable_Irq(IRQ_DMA2);
}
//======================================================
int mp3_finish()
{
rIISCON=0x0; //IIS stop
rDCON2=0x0; //BDMA stop
Disable_Irq(IRQ_DMA2);
return 4;
}
//======================================================
int mp3_stop()
{
int i;
rDCON2 &=0xffefffff; //DMA2 stop
opened = 0;
for (i = 0; i < NBUFFERS; ++i)
{
output[i].playing = 0;
output[i].pcm_length = 0;
}
bindex = 0;
playing_index=0;
return 3;
}
//******************** 用户初始化硬件函数 **********************************
void Interrupt_Init(void)
{
INTS_OFF();
SetISR_Interrupt(IRQ_DMA2, IIS_DMA_Done, NULL);
INTS_ON();
}
void IIS_Init(void) /****** IIS Initialize ******/
{
//For S3C2410 IIS
rIISCON&=0;
rIISMOD&=0;
rIISFCON&=0;
rIISCON|=(1<<5)|(1<<2)|(1<<1);
//TxDMAReqEn,RxIdle,IISPrescalerEn
rIISMOD|=(0<<8)|(2<<6)|(0<<4)|(1<<3)|(1<<2)|(1<<0);
//Master,Tx,IisFormat,IIS,16bit,384fs,32fs
rIISFCON|=(1<<15)|(1<<13);
//TxFifo=DMA,TxFifoEn
}
void IISDMA2_init(void) //DMA初始化
{
//DMA2 for AudioOut
rDISRC2 = (U32)(output[playing_index].pcm_data); //For Src
rDISRCC2 = (0<<1)|(0<<0); //Src=AHB,Increment
rDIDST2 = (U32)0x55000010; //Tx FIFO address
rDIDSTC2 = (1<<1)|(1<<0); //Dst=APB,Fixed;
rDCON2 = (0<<31)|(0<<30)|(1<<29)|(0<<28)|(0<<27)|\
(0<<24)|(1<<23)|(1<<22)|(1<<20)|((output[playing_index].pcm_length)/2); // important to DMA count
//handshake,Sync=APB,IntEn,unit,single,dst=I2SSDO,HwReqMode,NoAutoReload,Halfword,
rDMASKTRIG2 = (1<<1); //DMA2En
rIISCON|=(1<<0); //IIS Enable;
}
//*********************************************************************/
int init(struct audio_init *init)
{
int i;
opened = 0;
for (i = 0; i < NBUFFERS; ++i)
{
output[i].playing = 0;
output[i].pcm_length = 0;
}
bindex = 0;
playing_index=0;
Interrupt_Init();
IIS_PortSetting();
IIS_Init();
Init_UDA1341();
return 0;
}
//======================================================
int config(struct audio_config *config)
{
c_speed=config->speed;
return 1;
}
//======================================================
void write_dev()
{
output[bindex].playing=1;
if(opened==0) //如果第一次播放,初始化BDMA
{
opened=1;
playing_index=bindex;
set_sample_rate(output[playing_index].speed);
IISDMA2_init();
}
}
//======================================================
//解码部分调用该函数进行数据播放
int play(struct audio_play *Audio_play)
{
struct buffer *buffer;
unsigned int len;
buffer = &output[bindex];
while(buffer->playing==1);
/* prepare block */
buffer->speed=c_speed;
//回调库函数
len = audio_pcm_s16le(&buffer->pcm_data[buffer->pcm_length], Audio_play->nsamples,
Audio_play->samples[0], Audio_play->samples[1], Audio_play->mode,Audio_play->stats);
buffer->pcm_length += len;
if ((buffer->pcm_length + MAX_NSAMPLES * 2 * 2) >= sizeof(buffer->pcm_data))
{
write_dev();
bindex = (bindex + 1) % NBUFFERS;
Uart_Printf(0,">"); // 输出播放进度
}
return 2;
}
/*****************************************************************************************
音频DAC的初始化函数,系统中使用的芯片为UDA1341,初始化函数参考芯片手册编写。
Changed by allan_hua 2005.12.28
\*****************************************************************************************/
static void uda1341_l3_address(U8 data) ///zhaoning
{
int i;
write_gpio_bit(GPIO_L3CLOCK, 1);
write_gpio_bit(GPIO_L3DATA, 0);
hudelay(10);
write_gpio_bit(GPIO_L3MODE, 0);
hudelay(5);
for (i = 0; i < 8; i++) {
if (data & 0x1) {
write_gpio_bit(GPIO_L3CLOCK, 0);
hudelay(1);
write_gpio_bit(GPIO_L3DATA, 1);
hudelay(1);
write_gpio_bit(GPIO_L3CLOCK, 1);
hudelay(1);
} else {
write_gpio_bit(GPIO_L3CLOCK, 0);
hudelay(1);
write_gpio_bit(GPIO_L3DATA, 0);
hudelay(1);
write_gpio_bit(GPIO_L3CLOCK, 1);
hudelay(1);
}
data >>= 1;
}
hudelay(5);
write_gpio_bit(GPIO_L3MODE, 1);
hudelay(1);
}
static void uda1341_l3_data(U8 data) ///zhaoning
{
int i;
write_gpio_bit(GPIO_L3MODE, 1);
hudelay(5);
for (i = 0; i < 8; i++) {
if (data & 0x1) {
write_gpio_bit(GPIO_L3CLOCK, 0);
hudelay(1);
write_gpio_bit(GPIO_L3DATA, 1);
hudelay(1);
write_gpio_bit(GPIO_L3CLOCK, 1);
hudelay(1);
} else {
write_gpio_bit(GPIO_L3CLOCK, 0);
hudelay(1);
write_gpio_bit(GPIO_L3DATA, 0);
hudelay(1);
write_gpio_bit(GPIO_L3CLOCK, 1);
hudelay(1);
}
data >>= 1;
}
//write_gpio_bit(GPIO_L3MODE, 1);
hudelay(1);
write_gpio_bit(GPIO_L3MODE, 0);
hudelay(2);
write_gpio_bit(GPIO_L3MODE, 1);
}
static int uda1341_volume;
static U8 uda_sampling;
static int uda1341_boost;
unsigned Init_UDA1341(void)
{
uda1341_volume = 62 - ((DEF_VOLUME * 61) / 100);
uda1341_boost = 0;
uda_sampling = DATA2_DEEMP_NONE | DATA2_PEAKAFTER;
uda_sampling &= ~(DATA2_MUTE);
write_gpio_bit(GPIO_L3CLOCK, 1);
write_gpio_bit(GPIO_L3MODE, 1);
uda1341_l3_address(UDA1341_REG_STATUS);
uda1341_l3_data(STAT0_RST);
uda1341_l3_address(UDA1341_REG_STATUS);
uda1341_l3_data(STAT0_SC_384FS | STAT0_IF_I2S | STAT0_DC_FILTER); // 256 system clock,IIS
uda1341_l3_data(STAT1 | STAT1_DAC_GAIN | STAT1_ADC_GAIN | STAT1_ADC_ON | STAT1_DAC_ON);
uda1341_l3_address(UDA1341_REG_DATA0);
uda1341_l3_data(DATA0 |DATA0_VOLUME(uda1341_volume)); // maximum volume
uda1341_l3_data(DATA1 |DATA1_BASS(uda1341_boost)| DATA1_TREBLE(0));
uda1341_l3_data(DATA2 |uda_sampling);
uda1341_l3_data(EXTADDR(EXT2));
uda1341_l3_data(EXTDATA(EXT2_MIC_GAIN(0x6)| EXT2_MIXMODE_CH2));
uda1341_l3_data(EXTADDR(EXT5));
uda1341_l3_data(EXTDATA(0x7));
write_gpio_bit(GPIO_L3CLOCK, 1);
write_gpio_bit(GPIO_L3MODE, 0);
return 1;
}
void IIS_PortSetting(void)
{
//----------------------------------------------------------
// PORT G GROUP
//Ports : GPG9 GPG10 GPG8
//Signal : L3CLOCK L3DATA L3MODE
//Setting: OUTPUT OUTPUT OUTPUT
// [18:19] [20:21] [16:17]
//Binary : 01 , 01 01
//----------------------------------------------------------
rGPGDAT = rGPGDAT & ~(UDA1341_MODE|L3CLK|L3DATA) |(UDA1341_MODE|L3CLK);
//Start condition : L3M=H, L3C=H
rGPGUP = rGPGUP & ~(0x7<<8)|(0x7<<8);
//The pull up function is disabled GPG[8:10]
rGPGCON = rGPGCON & ~(0x3f<<16)|(0x15<<16);
//GPB[8:10]=Output(L3CLOCK):Output(L3DATA):Output(L3MODE)
//----------------------------------------------------------
// PORT E GROUP
//Ports : GPE4 GPE3 GPE2 GPE1 GPE0
//Signal : I2SSDO I2SSDI CDCLK I2SSCLK I2SLRCK
//Binary : 10 , 10 10 , 10 10
//----------------------------------------------------------
rGPEDAT = 0x0;
rGPEUP = rGPEUP & ~(0x1f) | 0x1f;
//The pull up function is disabled GPE[4:0] 1 1111
rGPECON = rGPECON & ~(0x3ff) | 0x2aa;
//GPE[4:0]=I2SSDO:I2SSDI:CDCLK:I2SSCLK:I2SLRCK
}
int Audio_Init(void)
{
IIS_PortSetting();
Init_UDA1341();
return OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -