硬件准备
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;
}
}