2013.7 多摩川编码器总结
2013.7 多摩川编码器总结
一、摘要
基于CPLD 和DSP 实现CPLD 与多摩川编码器的通讯,通过对编码器发送请求,得到编码器发回的数据并进行解码,得到绝对位置值。
二、学习步骤:
1、熟悉工作环境,掌握Modelsim 以及Quartus 的使用。
2、阅读多摩川编码器的通讯协议。
3、根据协议编写testbench ,并在Modelsim 上进行仿真调试。
4、仿真通过后,通过Quartus 编译后下载到CPLD 上并与编码器通讯,实际情况下运行。
5、完成各项要求的功能。
6、对代码进行优化,尽可能减少资源占用。
7、验收。
三、总体结构
双绞线,差分式,串行
RO,DI,DIR逻辑信号地址/数据总线接口结构分三部分:多摩川编码器,CPLD ,DSP 。
1、编码器跟CPLD 之间通过MAX485电平转换进行连接。
2、CPLD 与DSP 则通过总线进行连接(这一部分结构编写学长已经完成并且提供了端口连接)
3、主要工作是CPLD 的解码部分。
四、通讯协议
1、TS5668的技术指标:(物理层)
精度:单圈精度: 17位(131 072) 多圈精度: 16位(65 536)
最高转速/ ( r·min - 1 ): 6 000】
输出:差分NRZ 编码二进制
传输速度/Mbp s: 2. 5
发送、接收电路:差分形式
通信方式:主从模式
接口:3FG ,4sig+ ,5sig-,7VCC ,8DGND 。4和5为差分信号接口。
2、通信步骤如下图:(逻辑链路层)
1)CPLD 向编码器发送一个控制字CF
2)3us 后编码器返回数据包。
3)CPLD 对数据包进行解码,并将得到的数据放在总线上,等待DSP 获取。 具体流程如下图:
3、字的结构:下图分别为CF 、DF 、CRC 字的结构。
1)CF
字的开始位为0,再是010的同步位,以及4位的控制位,1位奇偶校验位(对控制位进行奇偶校验),结束位为1,共十位。
通过不同的Data ID code可以实现不同的功能,具体功能如下表:
2)SF
该字包含错误信息,如编码错误和通讯警报。通过检测相应位置上的值,就可以确定编码器的工作状态是否正常。
3)CRC
进行CRC 校验时,要对所有数据进行校验。计算时除掉每字的起始位和分隔符。
4)数据传输
正如CF 介绍中提到,不同的CF 控制命令会对应不同的数据结构传输。主要有三类,而我们用的是Data ID0,绝对数据传输。后面的空格表明没有数据传输。
数据传输中,低位在前,高位在后,每一字都是以0开始以1结束。由于是17位精度编码器,DF2数据位的高7位都是0。
五、需求分析
1、启动
DSP 每隔60us 向CPLD 发送一个启动脉冲,CPLD 捕捉到上升沿后开始向编码器发送CF 请求命令。如果CPLD 已经处于发送或接受状态,再接收到启动脉冲,不予响应。
2、485使能
由于CPLD 与编码器的通讯需要MAX485进行电平转换,而MAX485是一个半双工器件,因此,需要提供一个端口控制485的使能端,决定485的读写控制。
3、频率要求
板子上提供10M 频率的时钟,而多摩川编码器的通讯协议需要2.5M
频率时钟,因此
需要分频。
4、异常情况分析
考虑到传输过程中的异常情况(比如把“0”传输成“1”,或者反之),以及其他可能会出现的错误情况。
1)编码器接受到错误的CF ,给出了相应的回应。
2)编码器接受到错误的CF ,没有回应。
3)编码器自身出现错误(在SF 中会给出错误类型)。
5、与DSP 的通讯
得到绝对位置值之后,需要将读取的结果发送给DSP ,而这一过程需要提供一个端口使CPLD 与DSP 连接。
六、整体设计
1、流程图
基于多摩川编码器的通讯协议以及需求分析,可以做出以下流程图。
正确响应
2、分配状态
根据流程图,可以通过“状态机”来完成各个状态之间的切换,因此,分配状态为:Idle (闲置),Request (请求),Wait (等待),Receive (接收)四个状态。状态机的编写有一段式、两段式和三段式,这里状态比较简单,可以采用结构简单的一段式。(对于复杂的状态机,不推荐使用一段式)
具体写法如下:
reg[1:0] state
parameter
Idle = 2'b00, Request = 2'b01,
Wait = 2'b10, Receive = 2'b11;
…
case (state)
Idle: …
Request: …
Wait: …
Receive: …
3、闲置状态
CPLD 处于闲置状态,等待DSP 发送命令。当DSP 发送启动脉冲后,CPLD 检测到上升沿,即由闲置状态进入请求状态,同时,为请求状态做好初始化准备。而在其它状态检测到上升沿时,则不予响应。
具体代码如下:
1)检测启动脉冲
always @(posedge start or posedge start_fg1)
begin
if(start == 1) start_fg
if(start_fg1 == 1) start_fg
end
2)状态更改并为请求状态做好初始化准备
Idle:
begin
txd
if(start_fg == 1'b1)
begin
state
E_c
start_fg1
end
end
4、请求状态
CPLD 处于请求状态时,每一个时钟周期发送一个高低电平。请求命令为:0010000001。发送结束后,进入等待状态,等待编码器响应。
具体代码如下:
Request:
begin
if(i == 8'd10) //发送结束
begin
state
start_fg1
E_c
CF_r
txd
i
end
else
begin
txd
i
end
end
5、等待状态
CPLD 处于等待状态时,等待编码器相应。编码器一旦发送低电平过来,为避免传输干扰,设定了一个头部检测。头部检测的方式为,每次左移并接受一个数据,检测开始的头4位,如果头4位正确,则进入到接受状态;如果头4位不正确,则继续左移并接受数据,在指定时间内,如果没有成功接受到数据,则认为这一次通讯失败,并给出错误类型erro
在最初设计时,这里加入了一个“超时重发”的功能,即通讯失败后进入请求状态,重新发送请求命令,再次进入到等待状态,并且允许超时重发3次,3次都失败后则执行前面提到的错误处理办法。只是后来由于时间以及资源的闲置,把这一个模块删掉了,如果资源以及时间允许的话,可以考虑加上这一模块。
具体代码如下:
Wait:
begin
txd
E_b
if(CF_r[3:0] == 4'b0010) //头检测
begin
state
i
CF_r
i
end
else
begin
CF_r
if(i == 4'd14)
begin
state
erro
end
else
i
end
end
6、接受状态
这一状态是编码器的主要工作状态,同时由于接收的信息比较多,也是处理起来比较麻烦的一部分。首先,利用计数器计数10次,读出CF 信息,并且保存到CRC_buf里;再次利用计数器计数10次,读出SF 信息,也保存在CRC_buf里;再利用计数器计数30次,取出位置信息,这里需注意一点,编码器发回的位置信息是低位在前,高位在后,因此,在接受数据时,需要将其调整一下。最后,利用计数器计数10次,读出CRC 的信息。
接收完数据后,就进行CRC 校验。由于这一部分工作是同组另一位学长完成,这里不做具体阐述。如果CRC 校验通过,则输出位置信息;如果CRC 校验不通过,则输出错误信息,并且报全1。
以上是正常情况,同时还需要对CF 进行检查。如果发回的CF 与发送出去的CF 不同,则出错。出错的话,按照协议,编码器可能会发回一个最长的数据包,与实际情况不符。因此,也算作一种错误。
另外,SF 的错误信息是编码器自身的错误,根据要求,如果有这种错误的话,需要断电处理。因此,检测到这种错误时,给出错误信息,并不需要额外处理。
代码如下:
Receive:
begin
if(i
begin
CF_r
i
end
else if(i == 9) //CF检验
begin
if(CF_r == CF)
begin
CRC_buf
CF_r
i
end
else
begin
state
i
erro
end
end
else if(i
begin
CF_r
i
end
else if(i == 19)
begin
if(CF_r[4] | CF_r[3]) //检测SF ,出错应该断电处理
begin erro > 1)|{re, 29'd0}; i > 1)|{re, 29'd0}; i 7;i=i-1'b1) begin CRC_buf[47:40]={CRC_buf[46:40],(CRC_buf[47]^CRC_buf[39])}; CRC_buf[39:0]=CRC_buf[38:0]
end
if (!CRC_buf[47:40]) DATA=DATA1[23:0];
state
E_b
i
end
end
7、错误状况汇总
对于运行状态中,可能出现的一些错误情况进行了一些汇总。
首先,根据错误的处理方式进行分类。
1) 下一周期可以恢复正常的情况:
A 、 CF 错误。返回的CF 与发送的CF 不相同,此时按照程序逻辑继续运行。
B 、 通讯失败。CPLD 发送请求命令后,编码器没有相应。
C 、 C RC 错误。CRC 校验不通过,此时按照程序逻辑继续运行。
2) 下一周期不能恢复,需要断电处理:
SF 错误。
8、代码优化经验积累
代码在实现了预定功能之后,需要的就是资源优化了。在网上搜索了一些资料,并根据自己优化的情况,做了一些总结。
应该说,具体情况要具体分析,不过,也会有一些共性的问题。
1) 寄存器的位数尽可能少。
在一开始编写过程中,可能会有一些寄存器冗余。因此在资源优化时,要注意将这些冗余寄存器减掉。
2) 尽可能不要用不等比较。
在if 判断时,有时会用到不等比较,如if(i
3) 合理利用缓存寄存器。
对于位数较多的寄存器,直接进行处理可能会占用较多资源。这时,可以多设立一些小寄存器,先行储存下来,进行处理之后,再赋值给大的寄存器。