|
本帖最后由 xhyzjiji 于 2013-12-24 20:55 编辑
在此声明一下,这里是基于5509型号的dsp,其他型号可能在McBSP功能上有些区别,但原理大致通用。
1.McBSP资源及支持的工作模式
5509的McBSP具有双缓冲发送,三缓冲接收,支持全双工通信;支持独立的(由内部产生或外部输入的)收发时钟信号(CLKX、CLKR)和帧同步信号(FSX、FSR);128通道时分复用;支持DMA触发事件和中断触发;传输字的长度(字长)可以是8、12、16、20、24、32位,一次可传输1~128个字(帧长);支持数据压缩和符号扩展功能;McBSP引脚可设置位通用IO口。
McBSP可以配置成的模式包括:GPIO模式、SPI模式、I2S模式、多通道模式。
关于多通道
多通道一般用作时分复用,帧长指定一次传输应该传输多少个字,等同于传输给多少个通道(每个通道可以接收一个字)。由于传输顺序默认从通道1~通道128,且通道使能是可以自定义的,因此帧长度设置必须大于或等于已经使能的通道中最大的通道号。例如:我使能了第0、15、39通道,McBSP一帧内将接收39个字,现在开始传输字0、字2……字N,McBSP通道0接收字0,通道15接收字15,通道39接收字39,但只有真正使能后的通道才有相应的硬件动作。详细见《TMS320VC5501/5502/5509/5510 DSP Multichannel Buffered Serial Port (McBSP) Reference Guide》的5.3一节。
2.McBSP的硬件引脚连接
假设使用McBSP1
McBSP1.DR和McBSP1.FSR作为数据接收端,McBSP1.DX作为数据发送端。
串口属于异步通信,因此数据时钟均不需要,但这里使用了McBSP1.FSR连接到数据接收端,是因为串口数据存在开始位,并强制将数据总线由高电平拉低,这个可以作为接收帧同步信号;而发送帧同步信号FSX在这里不需要,可以悬空。
3.传输原理
以前,使用单片机上的片上外设UART十分简单,计算波特率时钟以及配置所属寄存器就可以进行通信。由于McBSP属于同步串行通信设备,且dsp的速度远远高于串口通信的速度,因此需要使用过采样-->解码进行接收。
过采样原理与作用
过采样就是dsp对串口传输字节中每一个位进行多次采样,并根据采样值进行判决。如:这里使用16倍于波特率的过采样率,对串口数据进行过采样,由于dsp接收起始时间并非严格对齐起始位的下降沿,所以,数据位为1,并非每次过采样都可以检测到数据线电平为1,但当一位数据检测,采样到1的次数大于过采样率的一般,则认为该位为1,否则认为该位为0。(有同学可以提供个好用的画图工具吗?)
过采样的好处就是可以消除连续传输时候的延时累加。
传输具体步骤如下:
1.在通信对象发送开始位时,DR和FSR被拉低,低电平触发帧同步信号,McBSP接收器开始接收数据(接收器工作时钟由dsp内部时钟分频得到),由于串口数据常用帧结构为:开始位、8为数据位、停止位(1bit)(如果使用停止位为1.5bit或者2bit,需要使用多相位多通道传输方式),由于16倍波特率的过采样率,所以需要设置字长为16位。每当对一位采样完成或者整个字节传输完成(可选)时,随即进行解码。
2.将需要发送的字节扩展成10个16位数据,以接收器使用时钟将并行数据串行地发送出去即可。
明显地,发送比接收要简单得多;为尽量降低CPU使用率,我们可以使用DMA和中断方式使CPU尽可能不干涉数据的传输。这里纯粹以最简单方法进行实现,所以暂不使用DMA和中断。
4.存储器配置(不提及的寄存器位可以按复位默认值)
SPCR1寄存器
DLB(15)=0;//关闭回环模式 RJUST(14-13)=00b;//数据右对齐,高位补0 CLKSTP(12-11)=0;//数据传输结束时,不关闭发送/接收时钟 DXENA(7)=1;//dsp发送数据开始后,将延时一段时间后DX才输出数据 RRST(0)=1;//使能接收器
SPCR2寄存器
FRST(7)=1;//由CLKG分频(FPER)后产生帧同步信号 GRST(6)=1;//由采样率发生器产生CLKG XRST(0)=1;//使能发送器
SRGR1寄存器
FWID(15-8)=0x01;//帧同步信号FSG的脉冲宽度为1个CLKG CLKGDV(7-0)=CLKGDV_38400;//16倍过采样率,每个串口帧数据采样10位数据,经过160个CLKG时钟,因此决定接收时钟=DSP时钟/波特率/16-(1~5),以下是在144MHz的DSP主频下,经测试可用的CLKGDV值:
#define CLKGDV_115200 (0x004Du)
#define CLKGDV_57600 (0x009Bu)
#define CLKGDV_56000 (0x00A0u)
#define CLKGDV_38400 (0x00E8u)
SRGR2寄存器
CLKSM(13)=1;//选择dsp时钟作为采样率发生器 FSGM(12)=1;//发送帧同步信号使用FSG触发(FSXM=1,FSGM=0:当DXR内容被复制到XSR时,产生一个发送帧同步,FSXM=1,FSGM=1:发送帧同步信号由CLKG分频得到) FPER(11-0)=160;//一帧传输中需要过采样率*串口传输帧位数,这里为16*10=160
PCR寄存器
IDLEEN(14)=0;//取消省电模式 FSXM(11)=1;//发送帧同步由内部FSG提供 FSRM(10)=0;//接收帧同步有FSR引脚提供 CLKXM(9)=1;//发送器时钟使用内部产生的CLKG CLKRM(8)=1;//接收器时钟使用内部产生的CLKG SCLKME(7)=0;//与SCLKME CLKSM=0 0时,采样发生器输入时钟选择CPU时钟
R(X)CR1寄存器
R(X)FRLEN1(14-8)=9;//设置阶段1帧长为10个字(R(X)FRLEN1+1) R(X)WDLEN1(7-5)=15;//设置阶段1字长为16位(R(X)WDLEN1+1)
R(X)CR2寄存器
R(X)COMPAND(4-3)=00b;//高位先接受 RFIG(2)=0;//忽略第一个帧同步过后的帧同步信号,这里非常重要 XFIG(2)=1;//当数据移入发送寄存器后,产生发送帧同步信号,发送器开始工作 RDATDLY(1-0)=0;//从接受帧同步产生后不进行延时立即开始将数据移入接收寄存器 XDATDLY(1-0)=1;//从发送帧同步产生后延时一个CLKG时钟后开始发送数据
MCR1/2寄存器
R(X)MCME(9)=1;//使能128各通道并可以由R(X)CER指定使能通道 R(X)MCM(0)=1;//可以独立使能通道
R(X)CERA = 0x03FF; //使能通道0-9
5.过采样解码
过采样解码则对过采样得到的接收数据,判断数据中1的个数进行判别。由于16倍过采样率,因此对接收数据(16位)进行1的位数统计,如0x33,则'1'的统计数为4
unsigned int bitscan(unsigned int char_data){
unsigned int num=0;
while(char_data){
char_data &= (char_data-1);
num++;
}
return num;
}
这里的算法复杂度为log2(n),具体算法原理可以参考《编程之美》。
unsigned int rxbuf[10];
void char2rxbuf(unsigned int char_data){
unsigned int i;
unsigned int temp = 0x00FF&char_data;
for(i=0; i<8; i++){
//串口传输顺序:起始位,数据低位--数据高位,校验位(这里不用),停止位
if(temp&(0x0001<<i))
rxbuf[i+1] = 0xFFFF;
else
rxbuf[i+1] = 0x0000;
}
}
这里将需要发送的8位数据进行扩展并存入发送缓冲rxbuf。
当接收到数据,根据自定义的中断方式,将置位相应的中断标志位(在读取中断标志位时会自动将其清零)
if(MCBSP_rrdy(hMcbsp)){ //DRR寄存器已存在数据
if(frame_error){
if(reccnt == 9){
frame_error = 0;
recchar = 0;
reccnt = 0;
}
else{
reccnt++;
}
}
else{
recchar = MCBSP_read16(hMcbsp);
if(bitscan(recchar)>8){ //此位被视为1
switch(reccnt){
case 0:{ //检测起始位,这时起始位错误,发生帧错误
frame_error = 1;
reccnt++;
break;
}
case 1: recans |= 0x0001; reccnt++; break;
case 2: recans |= 0x0002; reccnt++; break;
case 3: recans |= 0x0004; reccnt++; break;
case 4: recans |= 0x0008; reccnt++; break;
case 5: recans |= 0x0010; reccnt++; break;
case 6: recans |= 0x0020; reccnt++; break;
case 7: recans |= 0x0040; reccnt++; break;
case 8: recans |= 0x0080; reccnt++; break;
case 9:{ //检测结束位
recflag = 1; //接收正确,正确的数据将存在recchar中,如若有需要,请将数据提取到有用位置
reccnt = 0;
recchar = 0;
frame_error = 0;
recans = 0;
break;
}
default: break;
}
}
else{
if(reccnt == 9){ //结束位出错
recflag = 0;
recchar = 0;
reccnt = 0;
recans = 0;
//frame_error = 0;
}
else{
reccnt++;
}
}
}
}
将需要发送的数据存储到rxbuf,并逐个移入发送寄存器
for(y=255; y>0; y--){
if(sendflag){ //sendflag有数据需要发送
char2rxbuf(y); //数据准备
for(i=0; i<10; i++){
#ifdef _USE_CSL_
while(!MCBSP_xrdy(hMcbsp));
#endif
#ifdef _USE_IOPORT_
while(SPCR2_1&0x0020);
#endif
MCBSP_write16(hMcbsp, rxbuf);
}
sendflag = 1;
}
}
这里在正常发送时,先发送一帧数据,是DX将发送总线拉高,否则传输第一个字节将发生错误,一般可以发现是0x00
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
阿莫论坛20周年了!感谢大家的支持与爱护!!
知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)
|