typedef volatile unsigned int u32;
typedef volatile unsigned short u16;
#define GPDCON *(u32 *)0x7F008060
#define AC_GLBCTRL *(u32 *)0x7F001000
#define AC_GLBSTAT *(u32 *)0x7F001004
#define AC_CODEC_CMD *(u32 *)0x7F001008
#define AC_CODEC_STAT *(u32 *)0x7F00100C
#define AC_PCMDATA *(u32 *)0x7F001018
#define MUSIC_ADDR 0x54000000 //定义音乐编码存放的内存地址
#define LEN 44100*2*2*20
void (*printf)(char *,...)=(void *)0x57e11df8;
void delay(int count);
u16 read_mw9714l_cmd(char addr); //读值
void write_mw9714l_cmd(char addr,u16 data);//写值
void wm9714l_init();
void _start(){
//配置相关引脚寄存器,也就是WM9714L引出来的连在cpu上的
//先看底板原理图,在看核心板原理图,可以看到对应的是gpd
GPDCON = 0x44444;//设置为AC97使用
//配置声卡启动,这个很关键
//1,cold reset
//A cold reset is generated when the nRESET pin is asserted through the AC_GLBCTRL. Asserting anddeasserting nRESET activates BITCLK and SDATA_OUT. All AC97 control registers are initialized to their default power on reset values. nRESET is an asynchronous
AC97 input
//查看wm9714l芯片手册的cold reset的时序(大约14页)
//配置寄存器AC_GLBCTRL的第一位
AC_GLBCTRL = 1;
delay(1000);
AC_GLBCTRL &= ~1;//也许是上升沿有效吧!!
delay(1000);
//2.warm reset
//A Warm AC97 reset reactivates the AC-link without altering the current AC97 register values.
//A warm reset is generated when BITCLK is absent and SYNC is driven high. In normal audio frames, SYNC is a synchronous
// AC97 input. When BITCLK is absent, SYNC is treated as an asynchronous input used to generate a warm reset
// to AC97.The AC97 Controller must not activate BITCLK until it samples SYNC low again. This prevents a new audio frame from being falsely detected
//查看wm9714l芯片手册的warm reset的时序(大约14页)
//配置寄存器AC_GLBCTRL
AC_GLBCTRL |= (1 << 2)|(1 << 1);//打开AC-Link on,让BITCLK开启(见14页)
delay(1000);
AC_GLBCTRL &= ~(1 << 1);
delay(1000);
AC_GLBCTRL |= 1 << 3;//Transfer data enable using AC-link
//检查Controller main state是否工作(如果不active,后面的操作就没意义了)
//在这里需要读一下,否则后面的操作就会失败,有时人品好没问题就过去了
//原理见读函数
AC_CODEC_CMD = (1 << 23)|(0x04 << 16);
delay(1000);
//printf("%p
",AC_CODEC_STAT);
//AC_GLBSTAT的前三位
if((AC_GLBSTAT & 7) != 3){
printf("AC-link is not active!!
");
return;
}
//printf("go==%p
",AC_GLBSTAT);
/////////////////////////////////////////////////////////////////////////
//好吧!做了这么多其实就是打通了ac97总线和wm9714l的联系
//那下面就可以利用读的命令看看wm9714l的相关情况了,这个就不做了,感兴趣的可以结合wm9714l手册的80页进行查看
//当然我们的目标是配置wm9714l,让他工作来发声音,所以下面的操作是结合手册来配置wm9714l,
//总图在18页,配置寄存器在81-110页之间,我们接下来都是在这两点之前配置
//由于wm9714l的功能很多,但我们需要的只是配置ac97和耳机,其他一概不问
//封转一个函数吧
wm9714l_init();
//配置好了,就需要检验了吧!于是在内存中下载一段音乐,并把他由ac97直接噴给wm9714l,就可以听到音乐了
//采用查询方式
int num;
while(1){
if(AC_GLBSTAT & (1 << 18)){
AC_GLBCTRL |= 1 << 26;
AC_PCMDATA = *(u32 *)(MUSIC_ADDR+num*4);
num++;
}
}
return ;
}
//为了方便,我们再次封装一个读wm9714l的寄存器的值的函数
//这里使用两个寄存器AC_CODEC_STAT和AC_CODEC_CMD
//具体使用参见大约1153页的手册上,很简单的
u16 read_mw9714l_cmd(char addr){
AC_CODEC_CMD = (1 << 23)|(addr << 16);
delay(1000);
return AC_CODEC_STAT & 0xffff;
}
//有了读,那就有写的功能了,具体操作同读差不多,都是那两个寄存器
void write_mw9714l_cmd(char addr,u16 data){
AC_CODEC_CMD = (0 << 23)|(addr << 16)|data;
delay(1000);
}
//初始化wm9714l(注:这只是个简单的,要考虑音效什么的就需专业的了)
void wm9714l_init(){
write_mw9714l_cmd(0x04, (1 << 14)|(0xa << 8)|(1 << 6)|0xa); //no mute, max vol
write_mw9714l_cmd(0x0c, 0); //dac no mute, max vol
write_mw9714l_cmd(0x1c, (2 << 6)|(2 << 4)); //hpl/hpr source sel
//0x1e 3d
//0x20 tone, bass
//0x24 jack control
write_mw9714l_cmd(0x26, 0); //power
write_mw9714l_cmd(0x2a, 1); //variable rate control
write_mw9714l_cmd(0x2c, 0xac44); //441000
write_mw9714l_cmd(0x3c, 0); //power
write_mw9714l_cmd(0x3e, 0); //power
//0x40 3D enhance
//0x5a jack gpio detect
}
//延时函数
void delay(int count){
count *= 100;
while(count--)
;
}