BF518/BF516/BF514/BF512系列DSP的开发教程三十六:播放PCM

硬件准备

BF518开发板

产品链接:https://item.taobao.com/item.htm?id=39906148347&spm=a1z10.5-c.w4002-5192690539.11.22951471QbeGrA

在这里插入图片描述

BF518仿真器

产品链接:https://item.taobao.com/item.htm?id=38007242820&spm=a1z10.5-c.w4002-5192690539.11.6e614901nd1XEO

在这里插入图片描述

代码实现了打开代码工程目录下的“test.snd”文件,并读取 6MB 的数据到内存中,然后将内存中的数据进行循环播放,实现播放 PCM 音乐的功能。将耳机插入绿色的音频接口,可以听到正在播放的音乐。

代码采用了 SPORT 接口的描述符 DMA 实现,通过 SPORT 口以 I2S 方式,将音频数据送给音频解码芯片,由音频解码芯片将数据转为音乐信号输出。

Audio INIT

#include <cdefBF518.h>
#include <ccblkfn.h>
#include “audio_regdef.h”

#define AIC23B_ADDRESS 0x34

#define PRESCALE_VALUE 8
#define RESET_TWI 0 /* RESET_TWI value for controller /
#define CLKDIV_HI 66 /
SCL high period /
#define CLKDIV_LO 67 /
SCL low period */

int TWISuccess;

unsigned char AudioConfig[] = {
PWDC, 0xFF,
LLVC, 0x1d,
RLVC, 0x1d,
LHVC, 0xff,
RHVC, 0xff,
AAPC, DAC,
DAPC, 0,
PWDC, 0,
DAIF, MS|FOR|LRP,
SARC, 0x23,
DIAC, ACT|RES
};
unsigned char AudioColse[]={
RSRE, 0 ,
};

void delay(int tem)
{
int j,i;
for(i=tem;i>0;i–)
{
for(j=1000;j>0;j–)
{
j=j;
}
}
}

/*******************************************************************

  • Function: Reset_TWI

  • Description: reset the TWI interface
    ******************************************************************/
    void Reset_TWI(void)
    {
    /
    reset TWI controller */
    *pTWI_CONTROL = RESET_TWI;
    ssync();

    /* clear errors before enabling TWI */
    *pTWI_MASTER_STAT = BUFWRERR | BUFRDERR | LOSTARB | ANAK | DNAK;
    ssync();

    /* clear interrupts before enabling TWI */
    *pTWI_INT_STAT = SINIT | SCOMP | SERR | SOVF | MCOMP | MERR | XMTSERV | RCVSERV;
    ssync();

    /* flush rx and tx fifos */
    *pTWI_FIFO_CTL = XMTFLUSH | RCVFLUSH;
    ssync();

    /* set this to 1 so that we go into the write sequence the very first time /
    TWISuccess = 1;
    }
    /
    ******************************************************************

  • Function: ClrSclSda

  • Description: restores control of the TWI interface
    *******************************************************************/
    bool ClrSclSda(void)
    {

    int cnt = 0;

    do {

    *pTWI_MASTER_CTL = SCLOVR;
    
    delay(6);
    
    *pTWI_MASTER_CTL = 0;                                                                     
    
    delay(6);
    

    } while ((*pTWI_MASTER_STAT & SDASEN) && (cnt++ < 8));

    *pTWI_MASTER_CTL = SDAOVR | SCLOVR;

    delay(6);

    *pTWI_MASTER_CTL = SDAOVR;

    delay(6);

    *pTWI_MASTER_CTL = 0;

    return ((*pTWI_MASTER_STAT & SDASEN) || (cnt == 8)) ? false : true;
    }

/*******************************************************************

  • Function: TWI_MasterMode_Write

  • Description: do a master mode write
    *******************************************************************/
    void TWI_MasterMode_Write(unsigned short DeviceAddr, unsigned char *TWI_Data_Pointer, unsigned short Count, unsigned short TWI_Length)
    {
    int i, j, timeout;

    if (*pTWI_MASTER_STAT & SDASEN)
    {
    if(!ClrSclSda())
    return;
    }

    /* make sure no previous errors occured */
    if (TWISuccess == 1)
    {

    *pTWI_FIFO_CTL = 0;									/* clear the bit manually */
    *pTWI_CONTROL = TWI_ENA | PRESCALE_VALUE;			/* PRESCALE = fsclk/10MHz */
    *pTWI_CLKDIV = ((CLKDIV_HI) << 8) | (CLKDIV_LO);	/* CLKDIV = (1/SCL)/(1/10MHz) */
    *pTWI_MASTER_ADDR = DeviceAddr;						/* target address (7-bits plus the read/write bit) */
    
    for (i = 0; i < Count; i++)
    {
        /* # of configurations to send */
    	*pTWI_XMT_DATA8 = *TWI_Data_Pointer++;	/* pointer to data */
    	ssync();
    
    	*pTWI_MASTER_CTL = (TWI_Length<<6) | MEN /*| FAST*/;	/* start transmission */
    
    	timeout = 0x1000;
    
    	for (j = 0; j < (TWI_Length-1); j++)
    	{
    	    /* # of transfers before stop condition */
    		while ((*pTWI_FIFO_STAT == XMTSTAT) && --timeout)	/* wait to load the next sample into the TX FIFO */ 	// TAR37913
    		{
    			ssync();
    		}
    		if(!timeout)
    			return;
    
    		*pTWI_XMT_DATA8 = *TWI_Data_Pointer++;		/* load the next sample into the TX FIFO */
    		ssync();
    	}
    	
    	timeout = 0x1000;
    	
    	while (!(*pTWI_INT_STAT & MCOMP) && --timeout)			/* wait until transmission complete and MCOMP is set */
    	{
    		ssync();
    	}
    	if(!timeout)
    		return;
    
    	/* check if an error occured */
    	if ((*pTWI_INT_STAT & MERR) == MERR)
    	{
    		*pTWI_INT_STAT |= MERR;
    		TWISuccess = 0;		
    	}
    
    	*pTWI_INT_STAT = XMTSERV | MCOMP;				/* service TWI for next transmission */
    }
    

    }

    asm(“nop;”);
    asm(“nop;”);
    asm(“nop;”);
    }

/*******************************************************************

  • Function: TWI_MasterMode_Read

  • Description: do a master mode read
    *******************************************************************/
    void TWI_MasterMode_Read(unsigned short DeviceAddr, unsigned char *TWI_Data_Pointer, unsigned short Count)
    {
    int i, j;

    pTWI_FIFO_CTL = 0; / clear the bit manually */
    pTWI_CONTROL = TWI_ENA | PRESCALE_VALUE; / PRESCALE = fsclk/10MHz */
    pTWI_CLKDIV = ((CLKDIV_HI) << 8) | (CLKDIV_LO); / CLKDIV = (1/SCL)/(1/10MHz) */
    pTWI_MASTER_ADDR = DeviceAddr; / target address (7-bits plus the read/write bit) */

    pTWI_MASTER_CTL = (Count<<6) | MEN | MDIR /| FAST*/; /* start transmission */

    /* for each item */
    for (i = 0; i < Count; i++)
    {
    while (pTWI_FIFO_STAT == RCV_EMPTY) / wait for data to be in FIFO */
    ssync();

    *TWI_Data_Pointer++ = *pTWI_RCV_DATA8;		/* read the data */
    ssync();
    

    }

    while ((pTWI_INT_STAT & MCOMP) == 0) / wait until transmission complete and MCOMP is set */
    ssync();

    *pTWI_INT_STAT = RCVSERV | MCOMP;			/* service TWI for next transmission */
    

    asm(“nop;”);
    asm(“nop;”);
    asm(“nop;”);
    }

void iic_init(void)
{
int j;
int TWI_Error = 0;

TWISuccess = 0;

while (TWISuccess == 0 && TWI_Error < 100)
{	
	TWISuccess = 1;
	Reset_TWI();		/* reset the TWI interface */
	
	
	TWI_MasterMode_Write( AIC23B_ADDRESS>>1, AudioConfig, 11, 2);			

	if(TWISuccess)
		for (j=0; j<0x1ffffff; j++) asm("nop;");

	/*** lastly activate the digital engine *******************/

	
	if(!TWISuccess)
		TWI_Error++;
}									

}

void audio_close(void)
{
int j;

int TWI_Error = 0;

TWISuccess = 0;

while (TWISuccess == 0 && TWI_Error < 100)
{	
	TWISuccess = 1;
	Reset_TWI();		/* reset the TWI interface */

	TWI_MasterMode_Write( AIC23B_ADDRESS>>1, AudioColse, 1, 2);	
		
	if(TWISuccess)
		for (j=0; j<0x1ffffff; j++) asm("nop;");

	/*** lastly activate the digital engine *******************/

	
	if(!TWISuccess)
		TWI_Error++;
} 		

}

CPU

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;”);
}
}
/
************************************************************************

  • 名称 :Init_EBIU
  • 功能 :初始化并允许异步BANK存储器工作
  • 入口参数 :无
  • 出口参数 :无
    ***/
    void Init_EBIU(void)
    {
    pEBIU_AMBCTL0 = 0x7bb07bb0;
    pEBIU_AMBCTL1 = 0xffc07bb0;
    pEBIU_AMGCTL = 0x000f;
    }
    /
  • 名称 :Init_SDRAM
  • 功能 :初始化SDRAM
  • 入口参数 :无
  • 出口参数 :无
    ***/
    void Init_SDRAM(void)
    {
    pEBIU_SDRRC = 0x00000817;
    pEBIU_SDBCTL = 0x00000025;
    pEBIU_SDGCTL = 0x0091998d;
    ssync();
    }
    /
  • 名称 :InitPorts
  • 功能 :初始化端口
  • 入口参数 :无
  • 出口参数 :无
    ****************************************************************************/
    void InitPorts(void)
    {
    *pPORTH_FER = PH0|PH1|PH2|PH3|PH4|PH5;
    *pPORTH_MUX = 0;
    }
    #endif

main

#include “sport.h”
#include <cdefBF518.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();
InitPorts();
iic_init();

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_SPORT1_TX();			
Init_DMA6_SPORT1_TX();			
Enable_DMA6_SPORT1_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;
};

}

sport

#include “sport.h”
#include <sys\exception.h>
#include <cdefBF518.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)
{
*pSIC_IAR2 = 0xffff2fff;
register_handler(ik_ivg9, SPORT1_TX_ISR);
*pSIC_IMASK0 = 1<<19;
}

void Init_SPORT1_TX()
{
*pSPORT1_TCR1 = TFSR |TCKFE ;
*pSPORT1_TCR2 = 15| TSFSE;
}

/
void Init_DMA6_SPORT1_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;

*pDMA6_NEXT_DESC_PTR = &des1;
asm("ssync;");
*pDMA6_CONFIG = 0x7900 | WDSIZE_16 | 0x20;
asm("ssync;");

}

void Enable_DMA6_SPORT1_TX()
{
*pDMA6_CONFIG = (*pDMA6_CONFIG | DMAEN);
asm(“ssync;”);
*pSPORT1_TCR1 |= TSPEN;
asm(“ssync;”);
}

void Stop_DMA6_SPORT1_TX(void)
{
*pDMA6_CONFIG &= ~DMAEN;
*pSPORT1_TCR1 &= ~TSPEN;

}

int mute_flag = 0;
//发送的中断程序
EX_INTERRUPT_HANDLER(SPORT1_TX_ISR)
{
*pDMA6_IRQ_STATUS = 0x0001;

if(current_play_buffer == 0)
{
	if(mute_flag==1)
		printf("mute\n");
	if(*pDMA6_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(*pDMA6_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;
}	

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ADI_OP

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值