DSP录音机设计课程设计
目录
1设计原理及内容 (1)
1.1语音编码原理 (1)
1.2设计内容 (1)
1.2.1 基本部分 (1)
1.2.2 扩展部分 (1)
2设计资源介绍 (2)
2.1多通道缓冲串行口MCBSP...................................................... .2
2.1.1 工作原理 (2)
2.1.2 相关头文件 (2)
2.2 TLC320AD50 CODEC编码译码器 (2)
2.3 存储器 (3)
2.4压扩硬件 (4)
2.5 麦克风和耳机接口 (5)
3 设计思想 (5)
3.1实验方案 (5)
4 .程序设计 (6)
4.1 程序流程图 (6)
4.2各个分块程序设计 (7)
5.程序清单 (9)
6 操作步骤和结果 (19)
7 参考文献 (20)
1.设计原理与实验内容
1.1语音编码原理:
(1)概念:语音编码一般分为两类:一类是波形编码,一类是被称为“声码器技术”的编码。PCM编码即脉冲编码调制。波形编码的最简单形式就是脉冲编码调制(Pulse code modulation),这种方式将语音变换成与其幅度成正比的二进制序列,而二进制数值往往采用脉冲表示,并用脉冲对采样幅度进行编码,所以叫做脉冲编码调制。脉冲编码调制没有考虑语音的性质,所以信号没有得到压缩。
(2)量化:脉冲编码调制用同等的量化级数进行量化,即采用均匀量化,而均匀量化是基本的量化方式。但是均匀量化有缺点,在信号动态范围较大而方差较国际上有两种非均匀量化的方法:A律和μ律,μ律是最常用的一种。在美国,7位μ律是长途电话质量的标准。而我国采用的是A律压缩,而且有标准的(3)DPCM&ADPCM:
降低传输比特率的方法之一是减少编码的信息量,这要消除语音信号中的冗余度。相邻的语音样本之间存在明显的相关性,因此对相邻样本间的差信号进行编码,便可使信息量得到压缩。因为差分信号比原语音信号的动态范围和平均能量都小。这种编码叫Differential PCM,简称DPCM,即差分脉冲编码调制。
1.2 设计内容:
1.2.1基本部分:
(1)使用DSP实现语音压缩和解压缩的基本算法,算法类型自定,例如可以采用G.711、G.729等语音压缩算法。
(2)采用A/D转换器从MIC输入口实时采集语音信号,进行压缩后存储到DSP的片内和片外RAM 存储器中,存储时间不小于10秒。
(3)存储器存满之后,使用DSP进行实时解压缩,并从SPEAKER输出口进行回放输出。(4)使用指示灯对语音存储和回放过程进行指示。
1.2.2发挥部分:
使用多种算法进行语音的压缩、存储和解压缩,比较它们之间的优缺点。
2. 设计资源介绍
2.1多通道缓冲串行口MCBSP
2.1.1工作原理
C5402 具有2 个高速的全双工同步串行口,可用来与系统中的其它C54x 器
件、编码解码器、串行A/D、D/A 转换器以及其它的串行器件直接接口。这两个串行口均为多通道缓冲串行口McBSP(Multi-channel Buffered Serial Port)。它支持全双工通信,双缓冲数据寄存器,允许连续的数据流,可以与工业标准的编/解码器、AICs 接口。支持多种方式的传输接口,如T1/E1 帧协议、MVIP 帧方式、H.100 帧方式、SCSA 帧方式、IIS 兼容设备等。可与多达128 个通道进行收发。支持传输的数据字长可以是8bit、12bit、16bit、20bit、24bit 或32bit。内置μ-律和A-律压扩硬件。其硬件结构图如左图1所示。
MCBSP接口提供了以下7个引脚信号用于与其他设
备的通讯:
DR:串行数据接收引脚,输入
DX:串行数据发送引脚,输出
CLKX:发送时钟,输入或输出,可编程
CLKR:接收时钟,输入或输出,可编程图1
FSX:发送帧同步信号,输入或输出,可编程
FSR:接收帧同步信号,输入或输出,可编程
CLKS:外部时钟,输入
2.1.2 相关头文件
在CCS 集成开发环境中,与MCBSP相关的头文件有:regs54xx.h、mcbsp54.h。在这两个头文件中,定义了MCBSP串口的寄存器资源以及使用方法。在reg54xx.h 头文件中,定义了MCBSP 中寄存器的地址和基本访问方式,以及寄存器的各个比特域和访问方法。在mcbsp54.h 头文件中,定义了与MCBSP 相关的宏函数(MACRO FUNCTIONS)和函数。Regs54xx.h、mcbsp54.h 这两个头文件是C 语言下对MCBSP 编程的基础,我们不仅可以用在5402 DSK 板的编程上,而且可以用在其它的C54X 的DSP 硬件编程上。
2.2 TLC320AD50 CODEC 编码译码器
AD50是一款SIGMA-DELTA型单片音频接口芯片。它内部集成了16位的D/A和A/D 转换器,采样速率最高可达22.05kb/s,其采样速率可通过DSP编程来设置。在DAC之前有一个插值滤波器以保证输出信号平滑和ADC之后有一个抽取滤波器以提高输入信号的信噪比。
(1)内部结构及工作原理
AD50内部有7个数据和控制寄存器,用于编程控制它们的工作状态。
寄存器0:空操作寄存器。
寄存器1:软件复位 ,软件掉电,选择16位或15位工作方式,硬件或软件二次通信请求方式的选择。
寄存器2:使能ALTDATA输入端 ,为ADC选择16/15位方式。
寄存器3:选择FS与FSD之间延迟SCLK的个数,告诉主机有几个从机被联上。
寄存器4:为输入和输出放大器选择放大器增益,选择N来设置采样频率,fs=MCLK/(128*N)或MCLK/(512*N),在MCLK输入端使能外部时钟输入并旁通内部的PLL 。
寄存器5,6:保留
(2)与AD50有关的相关头文件
在CCS 集成开发环境中,与tlc320ad50 CODEC 编译码器相关的头文件是codec.h。它位于C:\ti\c5400\dsk5402\include 目录下。在这个头文件中,定义了与ad50 CODEC 相关的枚举变量和库函数。除了可以调用codec.h 中提供的库函数之外,我们还可以利用这些枚举变量重新编写自己的codec 函数,使用枚举变量相或产生所需要的ad50 寄存器的初始化值。Codec.h 中的库函数位于函数库dsk5402.lib 和 drv5402.lib 中。函数库dsk5402.lib 和 drv5402.lib 是作为两个单独的文件,连同include 文件和头文件一起提供给用户的,如果你的应用程序中用到了其中的库函数,就需要与这两个函数库进行链接(link)dsk5402.lib 是一个主要的函数库,其内部使用了drv5402.lib 的头文件。
2.3 存储器
(1)外部数据存储器
DSK提供了64K*16位的SRAM,SRAM工作在+3V的电源电压。可以使用的外部数
据存储器的大小取决于DROM的设置。如果DROM=0,那么0x4000~0xFFF(48k字)的空间是外部存储器(FLASH或SRAM)。如果DROM=1,外部存储器只能使用
0x4000~0xEFFF.DMSEL控制寄存器位决定访问板上或扩展板的存储器。如果DMSEL=0(缺省),使用板上的数据存储器;如果DMSEL=1,使用扩展板存储器,并且地址开始于0x8000(块的大小取决于DROM位)。数据存储器空间资源也取决于MP/MC状态。
(2)I/O空间存储器
IO 空间是由2 部分组成,一个是系统基于CPLD 控制空间,另一个是扩展板存储器空间。DM_SEL 位能够控制IO 空间的访问。如果DSP 向此位写1,那么扩展板存储器的IO 空间是不能被访问的。如果向此位写0,那么扩展板存储器的IO 空间是可以被访问的。
2.4压扩硬件
在通信中常常利用u律和a律对数据进行压扩处理,TMS320C54X在McBSP中提供了专门的硬件实验这一功能。压扩处理时,CPU访问到的都是16位的,他
分别是利用线性的14位数据(u律)和13位(a律)数据左对齐获得的。
压扩处理有两种实现方法:
方法一:当串行口的发送和接受部分都处于复位状态时,DRR1和DXR1内部通过压扩逻辑连接在一起,数据从DXR1写入并根据XCOMPAND处理,然后根据RCOMPAND再处理,在4个CPU时钟后从DRR1中读出数据。该处理比软件实现快,不利之处在于处理完后没有同步信息通知CPU和DMA。
方法二:在数据环回模式下,McBSP也实现了一种内连。数据处理与第一种方法相同,但它可以提供中断信号(或同步事件)给CPU(或DMA)。这里数据处理的时间是根据串行口的比特律确定的。
2.5 麦克风和耳机接口
音频接口使用了2 个工业标准的3.5mm 的连接器:
一个连接麦克风的音频输入;
一个连接耳机的音频输出。
(1)音频输入是交流偶合的并且包括:1 个固定增益为10dB 的放大器;实现单端到差分的转换(在此之前,连接到DSP 的McBSP1 上的TLC320AD50对其进行数字化);电压偏置(支持电池电源和驻极体麦克风);被动滤波(在DSK 的音频插口和CODEC 之间)用来增强性能,为驻极体麦克风设计的麦克风的输入它需要一个电压偏置。如果使用电容来隔离偏置电压,就能够使用动态的麦克风。麦克风的输入信号最大允许标准是500mV (350mVrms )。在DSK 上有10dB 前置放大器增益。
(2)音频输出是可以编程控制的,在软件的控制下,可以在6dB 增幅的范围内,增加增益+0~+2dB 。音频输入可以编程控制的,在6dB 增幅范围内,提供+0~+12dB 的增益。
3 .设计思想
3.1实验方案:
用板内的AD/DA 转换器AD50将由MIC 输入的模拟信号转换为16位数字信号送入DSP 板中进行压缩处理,压缩处理后的数据经过解压后再送至DA 转换器转换为模拟信号,由SPEAKER 口输出,压缩和解压缩用A 律格式,从而实现语音信号的采集压缩与回放。
统计表明对于每一个讲话者来说,语音中小幅度成分出现的概率要比大幅度多得多,为了在语音信号的整个动态范围内都可以接受低电平信号,量化电平必须照顾到语音的低电平信号,极低电平的量化间隔要小,高电平的量化间隔要大。
A 律的压缩可以按照下列公式进行定义:
)1||1
(ln 1||ln 1)sgn()1||0(ln 1||)
sgn()(≤≤++=≤≤+=x A
A x A x A x A x A x x F
式中,A 是压缩参数(在欧洲,A=87.6)x 是需要压缩的归一化整数。
从线性到A 律的压缩转换如下表所示:
压缩后的码字组成:比特0-3表矢量化值,比特4-6表示段值,压缩后的码
)
1)
ln(11()ln()
sgn()
)
ln(11
0()]ln(1[)sgn()()]
ln(1[1≤≤++=+≤≤+=+-y A A A A e y A y A A y y y F A y
4. 程序设计
4.1程序流程图
4.2各个分块程序设计
(1)初始化DSK
程序段:
if (brd_init(100))
return;
程序分析:brd_init()函数原型为:s16 brd_init(unsigned int cpuFreq)
参数cpuFreq表示CPU的工作频率,单位为MHz。提供的频率必须是10倍数,最小为20MHz,最大为100 MHz。20,30,40,50,60,70都可以。brd_init()返回参数为0则表示初始化成功,如果返回1,则表示初始化失败,执行return,继续执行初始化。
(2)初始化A/D50C程序
程序段:
void initcodec(void)
{
/*获取设置DAC的句柄 */
hHandset = codec_open(HANDSET_CODEC); // Acquire handle to codec /*设置DAC的工作参数*/
codec_dac_mode(hHandset, CODEC_DAC_15BIT); // DAC in 15-bit mode codec_adc_mode(hHandset, CODEC_ADC_15BIT); // ADC in 15-bit mode codec_ain_gain(hHandset, CODEC_AIN_12dB); // 6dB gain on analog input to ADC
codec_aout_gain(hHandset, CODEC_AOUT_MINUS_6dB);
// -6dB gain on analog output from DAC codec_sample_rate(hHandset,SR_16000); // 16KHz sampling rate }
(3)FLASH存储器的初始化
void flashenable(void)
{
CPLD_CTRL2_REG|=0x0010;
CPLD_DMCTRL_REG|=0x0040;
}
(4)语音信号采集存储与回放程序
while(1)
{
//判断MCBSP是否做好接收准备
while (!MCBSP_RRDY(HANDSET_CODEC) ) {};
//从A/D读取转换数据
din = *(volatile u16*)DRR1_ADDR(HANDSET_CODEC);
din=amp*din;
dacdata[i]=din;
// 将数据写入D/A转换器
*(volatile u16*)DXR1_ADDR(HANDSET_CODEC) =dacdata[i];
i=i+1;
}
程序分析:
1. while (!MCBSP_RRDY(HANDSET_CODEC) ) {}; 获取McBSP是否做好接受的准备信息
2. *(volatile u16*)DRR1_ADDR(HANDSET_CODEC) 定义数据接收寄存器1的地址
3. din=amp*din;dacdata[i]=din; 对输入信号进行语音处理
(5)闪灯程序
程序段:
/*******闪灯******/
void led(s16 cnt)
{
while ( cnt-- )
{
brd_led_toggle(BRD_LED0);
delay(1000);
brd_led_toggle(BRD_LED1);
delay(1000);
brd_led_toggle(BRD_LED2);
delay(1000);
}
}
程序分析:此函数用了一个while循环语句实现cnt次灯闪,通过调用delay 子函数控制灯闪灭时间,其中brd_led_toggle()表示切换用户LED,改变用户控制LED0~2的状态。
五程序清单
#include
#include
#include
#include
#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */
#define QUANT_MASK (0xf) /* Quantization field mask. */
#define NSEGS (8) /* Number of A-law segments. */
#define SEG_SHIFT (4) /* Left shift for segment number. */ #define SEG_MASK (0x70) /* Segment field mask. */
/******************************************************************** *********/
/* 函数声明 */ /******************************************************************** *********/
void delay(s16 period);
void led(s16 cnt);
void initcodec(void);
void flashenable(void);
unsigned char data2alaw(s16 pcm_val);
int alaw2data(unsigned char a_val);
static int search(int val,short *table,int size);
/******************************************************************** *********/
/* 全局变量 */ /******************************************************************** *********/
HANDLE hHandset;
s16 data;
s16 data1;
u16 i=0;
u16 temp1;
u16 j=0;
u16 k,l=0;
u8 temp2;
u16 buffer[15000];
static short seg_end[8]={0x1F,0x3F,0x7F,0xFF,0x1FF,0x3FF,0x7FF,0xFFF}; /******************************************************************** *********/
/* 主函数*/
/******************************************************************** *********/
void main()
{
if (brd_init(100))
return;
led(2); //闪灯两次
initcodec(); //初始化codec
flashenable(); //选择片外FLASH为片外存储器
/*
delay(100);
brd_led_toggle(BRD_LED0);
for(i=0x9000;i<0xefff;i++)
{
REG_WRITE(i,*(volatile u16*)DRR1_ADDR(HANDSET_CODEC));
delay(20);
}
brd_led_toggle(BRD_LED1);
delay(200);
for(i=0x9000;i<0xefff;i++)
{
*(volatile u16*)DXR1_ADDR(HANDSET_CODEC)=REG_READ(i);
delay(20);
}
brd_led_toggle(BRD_LED2);
*/
while (1)
{
while (!MCBSP_RRDY(HANDSET_CODEC)) {}; //等待接收handset 处的采样
data = *(volatile u16*)DRR1_ADDR(HANDSET_CODEC); //从handset 处读取采样
temp1=data2alaw(data); //对采样进行a律压缩
/******************************************************************** ******/
/* 把低地址数据放在高八位高地址数据放在低八位*/
/******************************************************************** ******/
i=i+1;
if(i%2==1)
{
buffer[j]=(temp1<<=8);
/*奇数数据左移8位 temp1=abcdefgh00000000
buffer[j]=temp1*/
}
else
{
buffer[j]=(buffer[j]|temp1);
/*偶数数据与temp1取或组成新的数据
buffer[j]=abcdefghiabcdefghi*/
j++; //j加1
}
if(i>=30000)
{
i=0;
}
if(j>=15000)
{
j=0;
brd_led_toggle(BRD_LED1); //点亮二极管1
delay(1000); //延时1000
brd_led_toggle(BRD_LED1);
//熄灭二极管 1 表示放音开始
/******************************************************************** *********/
/* 放音部分 */ /******************************************************************** *********/
for(k=0;k<30000;k++)
{
if(k%2==0)
{
temp2=(buffer[l]>>8)&0x0ff;
}
else
{
temp2=buffer[l]&0x0ff;
l++;
}
if(l>=15000)
l=0;
data1=alaw2data(temp2);
while (!MCBSP_XRDY(HANDSET_CODEC)) {};
*(volatile u16*)DXR1_ADDR(HANDSET_CODEC) = data1;
}
/******************************************************************** ****/
/* 放音结束*/
/******************************************************************** ****/
if(k>=29999)
{
brd_led_toggle(BRD_LED0); //点亮二极管0
delay(1000); //延时1000
brd_led_toggle(BRD_LED0); //熄灭二极管0 表示录音开始
}
}
}
} //主程序结束
/******************************************************************** *********/
/* 子函数 */ /******************************************************************** *********/
/*******延时******/
void delay(s16 period)
{
int i, j;
for(i=0; i { for(j=0; j } } /*******闪灯******/ void led(s16 cnt) { while ( cnt-- ) { brd_led_toggle(BRD_LED0); delay(1000); brd_led_toggle(BRD_LED1); delay(1000); brd_led_toggle(BRD_LED2); delay(1000); } } /*****初始化codec**/ void initcodec(void) { /* Open Handset Codec */ hHandset = codec_open(HANDSET_CODEC); // Acquire handle to codec /* Set codec parameters */ codec_dac_mode(hHandset, CODEC_DAC_15BIT); // DAC in 15-bit mode codec_adc_mode(hHandset, CODEC_ADC_15BIT); // ADC in 15-bit mode codec_ain_gain(hHandset, CODEC_AIN_6dB); // 6dB gain on analog input to ADC codec_aout_gain(hHandset, CODEC_AOUT_MINUS_6dB); // -6dB gain on analog output from DAC codec_sample_rate(hHandset,SR_8000); // 8KHz sampling rate } /*****设置flash****/ void flashenable(void) { CPLD_CTRL2_REG|=0x0010; CPLD_DMCTRL_REG|=0x0040; } /*****a律压缩******/ unsigned char data2alaw(s16 pcm_val) int mask; int seg; unsigned char aval; if (pcm_val >= 0) { mask = 0xD5; // 标记 (7th) bit = 1 } else { mask = 0x55; // 标记 bit = 0 pcm_val = -pcm_val; } // Convert the scaled magnitude to segment number. seg = search(pcm_val, seg_end, 8); // Combine the sign, segment, and quantization bits. if (seg >= 8) // out of range, 返回最大数. return (0x7F ^ mask); else { aval = seg << SEG_SHIFT; if (seg < 2) aval |= (pcm_val >> 1) & QUANT_MASK; else aval |= (pcm_val >>seg) & QUANT_MASK; return (aval ^ mask); } } /****alaw的子程序**/ static int search(int val,short *table,int size) int i; for (i = 0; i < size; i++) { if (val <= *table++) return (i); } return (size); } /*****a律解压******/ int alaw2data(unsigned char a_val) { int t; int seg; a_val ^= 0x55; t = (a_val & QUANT_MASK) << 4; seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT; if(seg==0) { t += 8; t=(t>>3); } if((seg<4)&&(seg>0)) { t +=0x108; t=(t>>(4-seg)); } if(seg>3) { t+=0x108; t=(t<<=(seg-4)); } return ((a_val & SIGN_BIT) ? t : -t); } 实验中还需要添加5402.cmd文件,5402.cmd文件及其解释: MEMORY { PAGE 0: VECS: origin = 0080h, length = 0080h /*内部程序RAM */ PRAM: origin = 0100h, length = 0FFFh /* 内部程序 RAM */ PAGE 1: SCRATCH: origin = 1000h, length = 0020h /* Scratch Pad Data RAM */ DMARAM: origin = 1020h, length = 0300h /* DMA缓存*/ DATA: origin = 1320h, length = 0080h /*内部数据RAM */ STACK: origin = 1400h, length = 0500h /* 堆栈内存空间 */ INRAM: origin = 1900h, length = 0100h /*内部数据 RAM */ HPRAM0: origin = 1A00h, length = 0002h /* HPI */ HPRAM1: origin = 1A02h, length = 0280h /* HPI */ HPRAM2: origin = 1C82h, length = 0280h /* HPI */ EXRAM: origin = 1F10h, length = 0EA00h /* 外部内存*/ } SECTIONS { .cinit > PRAM PAGE 0 .text > PRAM PAGE 0 .vectors > VECS PAGE 0 init_var > PRAM PAGE 0 detect > PRAM PAGE 0 vrcprg > PRAM PAGE 0 matprg > PRAM PAGE 0 .stack > STACK PAGE 1 .trap > SCRATCH PAGE 1 .const > EXRAM PAGE 1 .data > EXRAM PAGE 1 .bss > EXRAM PAGE 1 .cio > EXRAM PAGE 1 .switch > EXRAM PAGE 1 tables > EXRAM PAGE 1 var > EXRAM PAGE 1 svctab > EXRAM PAGE 1 /* SS_V LSP table */ vctab > EXRAM PAGE 1 /* V LSP table */ uvctab > EXRAM PAGE 1 /* UV LSP table */ cuvtab > EXRAM PAGE 1 /* Stochastic codebook */ cdbktab > EXRAM PAGE 1 /* various codebook tables*/ logtab > EXRAM PAGE 1 /* table for log2 */ powtab > EXRAM PAGE 1 /* table for pow2 */ hamtab > EXRAM PAGE 1 /* table for hamming */ lgwtab > EXRAM PAGE 1 /* table for lag window */ acostab > EXRAM PAGE 1 /* table for arccos */ sqrtab > EXRAM PAGE 1 /* table for square root */ acbtab > EXRAM PAGE 1 /* table for thresholds in acb */ pm03tab > EXRAM PAGE 1 /* table for x^(-0.3) computation */ costab > EXRAM PAGE 1 /* table for cosine */ V23 > INRAM PAGE 1 FSK > INRAM PAGE 1 hpibuff0 > HPRAM0 PAGE 1 hpibuff1 > HPRAM1 PAGE 1 hpibuff2 > HPRAM2 PAGE 1 dma_buff > DMARAM PAGE 1 } 六 .操作步骤和结果 1、将5402 DSK板与计算机相连,连接好耳机,音频线,电源线等。 2、连接DSK板的电源,并启动计算机。