硬件准备
ADSP-EDU-BF533:BF533开发板
AD-HP530ICE:ADI DSP仿真器
软件准备
Visual DSP++软件
硬件链接
代码实现功能
代码实现了打开代码工程目录下的“test.snd”文件,并读取 6MB 的数据到内存中,然后将内存中的数据进行循环播放,实现播放 PCM 音乐的功能。将耳机插入绿色的音频接口,可以听到正在播放的音乐。
代码使用说明
代码采用了 SPORT 接口的描述符 DMA 实现,通过 SPORT 口以 I2S 方式,将音频数据送给音频解码芯片,由音频解码芯片将数据转为音乐信号输出。
代码实验步骤
- 在代码工程目录下存放了一个名为 test.snd 的声音文件,该文件可以由提供的 MP3 解码代码生成,也可以由 GoldWave 软件生成,文件格式必须为立体声 44.1KHz128Kbps 格式。
- 将耳机接入开发板上绿色的音频接口,板卡连接 VDSP 软件,编译并运行代码。
- 等待文件系统加载 PCM 数据,待数据加载完后,通过耳机能听到音乐输出。
通过耳机听到 PCM 数据音乐输出。
程序源码
audio.c
#include “i2c.h”
#include “audio_regdef.h”
#include <cdefBF533.h>
#define AIC23B_ADDRESS 0x34
static i2c_device mcu_i2c;
void init_aic23b(void);
int aic23b_write(unsigned char addr, unsigned char dat);
int aic23b_read(unsigned char addr, unsigned char * buf);
/****************************************************************************
- 名称 :aic23b_write
- 功能 : 写aic23b寄存器函数
- 入口参数 :addr:寄存器偏移地址
dat:寄存器配置值 - 出口参数 :返回0
****************************************************************************/
int aic23b_write(unsigned char addr, unsigned char dat)
{
int ret = -1;
i2c_start(&mcu_i2c);
if(i2c_write(&mcu_i2c, AIC23B_ADDRESS, 1)){
i2c_stop(&mcu_i2c);
return ret;
}
if(i2c_write(&mcu_i2c, addr, 1)){
i2c_stop(&mcu_i2c);
return ret;
}
i2c_write(&mcu_i2c, dat, 1);
i2c_stop(&mcu_i2c);
return 0;
}
/****************************************************************************
- 名称 :aic23b_read
- 功能 : 读aic23b寄存器函数
- 入口参数 :addr:寄存器偏移地址
buf:寄存器读取数据缓存 - 出口参数 :返回0
****************************************************************************/
int aic23b_read(unsigned char addr, unsigned char * buf)
{
unsigned char *p = buf;
int ret = -1;
i2c_start(&mcu_i2c);
//send slave address
if(i2c_write(&mcu_i2c, AIC23B_ADDRESS, 1)){
i2c_stop(&mcu_i2c);
return ret;
}
//send sub-address of slave
if(i2c_write(&mcu_i2c, addr, 1)){
i2c_stop(&mcu_i2c);
return ret;
}
i2c_stop(&mcu_i2c);
i2c_start(&mcu_i2c);
// send slave address (+1 read mode)
if(i2c_write(&mcu_i2c, AIC23B_ADDRESS+1, 1)){
i2c_stop(&mcu_i2c);
return ret;
}
if(i2c_wait_slave(&mcu_i2c, 1000)){
i2c_stop(&mcu_i2c);
return ret;
}
i2c_read(&mcu_i2c, p++, 1); // send ack
i2c_stop(&mcu_i2c);
return 0;
}
/****************************************************************************
- 名称 :Init_aic23b
- 功能 : 音频模块的内部初始化
- 入口参数 :无
- 出口参数 :无
****************************************************************************/
void init_aic23b(void)
{
unsigned char i;
mcu_i2c.sclk = PF0; //时钟PF脚
mcu_i2c.sdata = PF1; //数据PF脚
mcu_i2c.low_ns = 7000; //低电平延时 ns
mcu_i2c.high_ns = 6000; //高电平延时 ns
i2c_init(&mcu_i2c);
aic23b_write(PWDC,0x000FF);
aic23b_write(LLVC,0x1d);
aic23b_write(RLVC,0x1d);
aic23b_write(LHVC,0x73);
aic23b_write(RHVC,0x73);
aic23b_read(RHVC, i);
aic23b_write(AAPC,DAC);
aic23b_write(DAPC,0);
aic23b_write(PWDC,0);
aic23b_write(DAIF,MS|FOR|LRP);
aic23b_write(SARC,0x23);
aic23b_write(DIAC,ACT|RES);
}
cpu.c
#include <cdefBF533.h>
void Set_PLL(int pmsel,int pssel)
{
int new_PLL_CTL;
*pPLL_DIV = pssel;
asm(“ssync;”);
new_PLL_CTL = (pmsel & 0x3f) << 9;
*pSIC_IWR |= 0xffffffff;
if (new_PLL_CTL != *pPLL_CTL)
{
*pPLL_CTL = new_PLL_CTL;
asm(“ssync;”);
asm(“idle;”);
}
}
void Init_SDRAM(void)
{
*pEBIU_SDRRC = 0x00000817;
*pEBIU_SDBCTL = 0x00000013;
*pEBIU_SDGCTL = 0x0091998d;
ssync();
}
void Init_EBIU(void)
{
*pEBIU_AMBCTL0 = 0x7bb07bb0;
*pEBIU_AMBCTL1 = 0x7bb07bb0;
*pEBIU_AMGCTL = 0x000f;
}
void Setup_Flags(void)
{
*pFIO_INEN = 0x0020;
*pFIO_DIR = 0x001f;
*pFIO_EDGE = 0x0000;
*pFIO_MASKA_S = 0x0020;
*pFIO_POLAR = 0x0020;
}
i2c.c
#include <cdefBF533.h>
#include “i2c.h”
#define CORE_CLK_IN 24 * 1000 * 1000
#define SET_PF(pf)
do{
*pFIO_FLAG_S = (pf);
ssync();
}while(0)
#define CLR_PF(pf)
do{
*pFIO_FLAG_C = (pf);
ssync();
}while(0)
#define SET_PF_OUTPUT(pf)
do{
*pFIO_INEN &= ~(pf);
*pFIO_DIR |= (pf);
ssync();
}while(0)
#define SET_PF_INPUT(pf)
do{
*pFIO_DIR &= ~(pf);
*pFIO_INEN |= (pf);
ssync();
}while(0)
int get_core_clk(void)
{
int tempPLLCTL;
int _DF;
int VCO;
int MSEL1;
tempPLLCTL = *pPLL_CTL;
MSEL1 = ((tempPLLCTL & 0x7E00) >> 9);
_DF = tempPLLCTL & 0x0001;
VCO = MSEL1 * __CORE_CLK_IN__;
if(_DF == 1)
VCO /= 2;
return VCO;
}
void delay_ns(unsigned int core_clock, unsigned long long count)
{
count *= core_clock;
count /= 1000000000;
while(count–);
}
int _get_sdata(i2c_device * dev)
{
return ((*pFIO_FLAG_D & dev->sdata) ? 1 : 0);
}
void i2c_init(i2c_device * dev)
{
dev->core_clock = get_core_clk();
dev->delay_ns = delay_ns;
*pFIO_DIR |= dev->sclk | dev->sdata;
ssync();
}
void i2c_deinit(i2c_device * dev)
{
dev->sclk = 0;
dev->sdata = 0;
*pFIO_DIR &= ~(dev->sclk | dev->sdata);
ssync();
}
void i2c_start(i2c_device * dev)
{
SET_PF_OUTPUT(dev->sdata);
SET_PF_OUTPUT(dev->sclk);
SET_PF(dev->sdata);
SET_PF(dev->sclk);
delay_ns(dev->core_clock, dev->high_ns);
CLR_PF(dev->sdata);
delay_ns(dev->core_clock, dev->low_ns);
CLR_PF(dev->sclk);
delay_ns(dev->core_clock, dev->low_ns);
}
void i2c_stop(i2c_device * dev)
{
CLR_PF(dev->sclk);
delay_ns(dev->core_clock, dev->low_ns);
SET_PF_OUTPUT(dev->sdata);
CLR_PF(dev->sdata);
delay_ns(dev->core_clock, dev->low_ns);
SET_PF_INPUT(dev->sclk);
delay_ns(dev->core_clock, dev->high_ns);
SET_PF_INPUT(dev->sdata);
delay_ns(dev->core_clock, dev->high_ns);
}
int i2c_read_ack(i2c_device * dev)
{
int ret = 0;
SET_PF_INPUT(dev->sdata);
delay_ns(dev->core_clock, dev->high_ns/3);
SET_PF(dev->sclk);
delay_ns(dev->core_clock, dev->high_ns/3);
ret = _get_sdata(dev);
delay_ns(dev->core_clock, dev->high_ns/3);
CLR_PF(dev->sclk);
delay_ns(dev->core_clock, dev->low_ns);
SET_PF_OUTPUT(dev->sdata);
return ret;
}
int i2c_wait_slave(i2c_device * dev, unsigned int time_out)
{
int ret;
int count = time_out * 2 / dev->high_ns;
SET_PF_INPUT(dev->sclk);
delay_ns(dev->core_clock, dev->high_ns/2);
do{
ret = *pFIO_FLAG_D & dev->sclk;
if(ret)
break;
delay_ns(dev->core_clock, dev->high_ns/2);
}while(count--);
SET_PF_OUTPUT(dev->sclk);
return !ret;
}
void i2c_write_ack(i2c_device * dev)
{
SET_PF_OUTPUT(dev->sdata);
CLR_PF(dev->sdata);
delay_ns(dev->core_clock, dev->high_ns/2);
SET_PF(dev->sclk);
delay_ns(dev->core_clock, dev->high_ns);
CLR_PF(dev->sclk);
delay_ns(dev->core_clock, dev->low_ns);
}
int i2c_write(i2c_device * dev, unsigned char value, int need_ack)
{
int ret = -1;
unsigned char index;
SET_PF_OUTPUT(dev->sdata);
//send 8 bits to slave
for(index = 0; index < 8; index++){
//send one bit to the i2c bus
if((value<<index) & 0x80){
SET_PF(dev->sdata);
} else {
CLR_PF(dev->sdata);
}
delay_ns(dev->core_clock, dev->low_ns/2);
SET_PF(dev->sclk);
delay_ns(dev->core_clock, dev->high_ns);
CLR_PF(dev->sclk);
delay_ns(dev->core_clock, dev->low_ns/2);
}
if(need_ack){
ret = i2c_read_ack(dev);
}
return ret;
}
int i2c_read(i2c_device * dev, unsigned char * value, int send_ack)
{
unsigned char index;
*value = 0x00;
SET_PF_INPUT(dev->sdata);
delay_ns(dev->core_clock, dev->high_ns/2);
//get 8 bits from the device
for(index = 0; index < 8; index++){
SET_PF(dev->sclk);
delay_ns(dev->core_clock, dev->high_ns/2);
*value <<= 1;
*value |= _get_sdata(dev);
delay_ns(dev->core_clock, dev->high_ns/2);
CLR_PF(dev->sclk);
delay_ns(dev->core_clock, dev->low_ns);
}
// send ack to slave
if(send_ack){
i2c_write_ack(dev);
}
return *value;
}
main.c
#include “sport.h”
#include <cdefBF533.h>
#define LIST_NUM 20
typedef struct
{
unsigned short NDPL; // next descriptor pointer (lower 16-bits)
unsigned short NDPH; // next descriptor pointer (upper 16-bits)
unsigned short SAL; // start address (lower 16-bits)
unsigned short SAH; // start address (upper 16-bits)
unsigned short CFG; // DMA config
unsigned short XCNT; // X Count
unsigned short XMOD; // X Mod
unsigned short YCNT; // Y Count
unsigned short YMOD; // Y Mod
} sDMA_Descriptor_Long;
extern sDMA_Descriptor_Long current_des[2];
unsigned char buffer[102410246];
extern volatile int current_play_buffer;
extern int current_play_index;
extern int current_addr;
typedef struct
{
int flag;
void * next;
sDMA_Descriptor_Long des;
} audio_list_t;
extern audio_list_t sport_output[LIST_NUM];
extern void * sport_output_ptr;
extern void * sport_input_ptr;
FILE *fp;
void main(void)
{
unsigned char* ptr;
Set_PLL(16,4);
Init_SDRAM();
Init_EBIU();
IIC_Enable();
init_aic23b();
printf("initialization is ok!\n");
fp = fopen("../test.snd", "rb");
printf("open pcm file!\n");
printf("read pcm data!\n");
fread(buffer, 1, 1024*1024*6, fp);
fclose(fp);
printf("read pcm data ok!\n");
Init_Interrupts();
Init_Sport0_TX();
Init_DMA2_Sport0_TX();
Enable_DMA2_Sport0_TX();
ptr = buffer;
while(1)
{
while(current_play_buffer > 15)
{
}
((audio_list_t *)sport_input_ptr)->des.SAL = (unsigned long)ptr;
((audio_list_t *)sport_input_ptr)->des.SAH = ((unsigned long)ptr)>>16;
((audio_list_t *)sport_input_ptr)->des.CFG = 0x7900 | WDSIZE_16|DMAEN|DI_EN;
((audio_list_t *)sport_input_ptr)->des.XCNT = 1024*16;
((audio_list_t *)sport_input_ptr)->des.XMOD = 2;
((audio_list_t *)sport_input_ptr)->flag = 1;
sport_input_ptr = ((audio_list_t *)sport_input_ptr)->next;
current_play_buffer ++;
ptr += 1024*16*2;
if(ptr==buffer+1024*1024*6)
ptr = buffer;
};
}
sports.c
#include “sport.h”
typedef struct
{
unsigned short NDPL; // next descriptor pointer (lower 16-bits)
unsigned short NDPH; // next descriptor pointer (upper 16-bits)
unsigned short SAL; // start address (lower 16-bits)
unsigned short SAH; // start address (upper 16-bits)
unsigned short CFG; // DMA config
unsigned short XCNT; // X Count
unsigned short XMOD; // X Mod
unsigned short YCNT; // Y Count
unsigned short YMOD; // Y Mod
} sDMA_Descriptor_Long;
#define LINE_COUNT 1024*16
#define LIST_NUM 20
unsigned char mute_buffer[LINE_COUNT*2];
sDMA_Descriptor_Long des1;
sDMA_Descriptor_Long des2;
typedef struct
{
int flag;
void * next;
sDMA_Descriptor_Long des;
} audio_list_t;
audio_list_t sport_output[LIST_NUM];
void* sport_output_ptr, *sport_input_ptr;
sDMA_Descriptor_Long current_des[2], mute_des;
volatile int current_play_buffer = 0;
int current_play_index = 0;
int current_addr;
void Init_Interrupts(void)
{
register_handler(ik_ivg9, Sport0_TX_ISR);
*pSIC_IMASK = (*pSIC_IMASK | 0x00000400);
}
void Init_Sport0_TX()
{
*pSPORT0_TCR1 = TFSR |TCKFE ;
*pSPORT0_TCR2 = 15| TSFSE;
}
/
void Init_DMA2_Sport0_TX(void)
{
int i;
current_play_buffer = 0;
for(i=0; i<LINE_COUNT4; i++)
{
mute_buffer[i] = 0;
}
sport_output_ptr = (void)&sport_output[0];
sport_input_ptr = (void*)&sport_output[0];
sport_output[LIST_NUM-1].next = (void*)&sport_output[0];
for(i=0; i<LIST_NUM-1; i++)
{
sport_output[i].next = (void*)&sport_output[i+1];
sport_output[i].des.NDPL = (unsigned int)&sport_output[i].des;
sport_output[i].des.NDPH = (unsigned int)(&sport_output[i].des)>>16;
}
for(i=0; i<LIST_NUM; i++)
{
sport_output[i].flag = 0;
sport_output[i].des.SAL = (unsigned int)&mute_buffer;
sport_output[i].des.SAH = (unsigned int)(&mute_buffer)>>16;
sport_output[i].des.CFG = 0x7900 | WDSIZE_16|DMAEN|DI_EN;
sport_output[i].des.XCNT = LINE_COUNT;
sport_output[i].des.XMOD = 2;
}
mute_des.SAL = (unsigned int)&mute_buffer;
mute_des.SAH = (unsigned int)(&mute_buffer)>>16;
mute_des.CFG = 0x7900 | WDSIZE_16|DMAEN|DI_EN;
mute_des.XCNT = LINE_COUNT;
mute_des.XMOD = 2;
des1.NDPL = (unsigned int)&des2;
des1.NDPH = (unsigned int)(&des2)>>16;
des1.SAL = (unsigned int)&mute_buffer;
des1.SAH = (unsigned int)(&mute_buffer)>>16;
des1.CFG = 0x7900 | WDSIZE_16|DMAEN|DI_EN;
des1.XCNT = LINE_COUNT;
des1.XMOD = 2;
des2.NDPL = (unsigned int)&des1;
des2.NDPH = (unsigned int)(&des1)>>16;
des2.SAL = (unsigned int)&mute_buffer;
des2.SAH = (unsigned int)(&mute_buffer)>>16;
des2.CFG = 0x7900 | WDSIZE_16|DMAEN|DI_EN;
des2.XCNT = LINE_COUNT;
des2.XMOD = 2;
*pDMA2_NEXT_DESC_PTR = &des1;
asm("ssync;");
*pDMA2_CONFIG = 0x7900 | WDSIZE_16 | 0x20;
asm("ssync;");
}
void Enable_DMA2_Sport0_TX()
{
*pDMA2_CONFIG = (*pDMA2_CONFIG | DMAEN);
asm(“ssync;”);
*pSPORT0_TCR1 |= TSPEN;
asm(“ssync;”);
}
void Stop_DMA2_Sport0_TX(void)
{
*pDMA2_CONFIG &= ~DMAEN;
*pSPORT0_TCR1 &= ~TSPEN;
}
int mute_flag = 0;
//发送的中断程序
EX_INTERRUPT_HANDLER(Sport0_TX_ISR)
{
*pDMA2_IRQ_STATUS = 0x0001;
if(current_play_buffer == 0)
{
if(mute_flag==1)
printf("mute\n");
if(*pDMA2_NEXT_DESC_PTR == &des1)
{
des1.SAL = mute_des.SAL;
des1.SAH = mute_des.SAH;
des1.CFG = mute_des.CFG;
des1.XCNT = mute_des.XCNT;
des1.XMOD = mute_des.XMOD;
}else
{
des2.SAL = mute_des.SAL;
des2.SAH = mute_des.SAH;
des2.CFG = mute_des.CFG;
des2.XCNT = mute_des.XCNT;
des2.XMOD = mute_des.XMOD;
}
}else
{
mute_flag = 1;
if(*pDMA2_NEXT_DESC_PTR == &des1)
{
des1.SAL = ((audio_list_t *)sport_output_ptr)->des.SAL;
des1.SAH = ((audio_list_t *)sport_output_ptr)->des.SAH;
des1.CFG = ((audio_list_t *)sport_output_ptr)->des.CFG;
des1.XCNT = ((audio_list_t *)sport_output_ptr)->des.XCNT;
des1.XMOD = ((audio_list_t *)sport_output_ptr)->des.XMOD;
((audio_list_t *)sport_output_ptr)->flag = 0;
}else
{
des2.SAL = ((audio_list_t *)sport_output_ptr)->des.SAL;
des2.SAH = ((audio_list_t *)sport_output_ptr)->des.SAH;
des2.CFG = ((audio_list_t *)sport_output_ptr)->des.CFG;
des2.XCNT = ((audio_list_t *)sport_output_ptr)->des.XCNT;
des2.XMOD = ((audio_list_t *)sport_output_ptr)->des.XMOD;
((audio_list_t *)sport_output_ptr)->flag = 0;
}
current_play_buffer --;
sport_output_ptr = ((audio_list_t *)sport_output_ptr)->next;
}
}