DSP录音机设计课程设计

DSP录音机设计课程设计
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>1; 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板的电源,并启动计算机。

相关主题
相关文档
最新文档