本章节主要实现将命令转换成根据ISO1569中4取1的编码方式,实现对命令的PPM转换。这里对编码规则只作简单介绍。4取1,2bit编码,低位到高位;b2b1,b4b3,b6b5,b8b7。
基于这种编码方式,先进行8bit的数据PPM转换。 观察上述编码方式,
00:第一个位置;
01: 第三个位置;
10:第五个位置;
11:第七个位置。
低电平所在位置与编码存在一定关系,是编码后补一位“1”后的数值;也就是:
00: 001 = 1;
01: 011 = 3;
10: 101 = 5;
11: 111 = 7。
除此之外,在命令前需要加上起始帧,在命令结束后要加上结束帧。起始帧:
结束帧:
这样,就很容易进行PPM编码了。这里需要注意地是一个低脉冲的持续时间(9.44us),一个周期是8个低脉冲的持续时间,也就是8个脉冲构成一个周期。整个过程利用状态机实现。该模块以字节为单位进行编码。每次输入一byte数据,当1byte数据编码完成后更新。需要注意地是,代码中涉及到了两个时钟,所以在利用组合逻辑实现时,多了很多额外的标志位。其实后期可以对代码进行优化,利用一一个主时钟进行计数分配,实现对PPM编码。该顶层模块实现将在下一章节给出。
module nfc_tx_ppm
#(
parameter BYTE_CNT = 4
)(
input rstn, //ä˝çľĺšłĺ¤ä˝?
input clk_system,
input clk_ppm, //ĺ¨ćä¸?9.44us
input [BYTE_CNT:0] cnt, //ć°ćŽć°é
input datavaild, //ć°ćŽćć
input [7:0] crc, //ĺ ĺĽCRCĺbitć°ćŽ
output reg byte_shift, //ä¸?个ĺč轏ć˘ĺŽć?
output reg ppm_finish, //ĺ˝äť¤ĺé?ĺŽć?
output reg ppm_out //PPMčžĺş
);
localparam period = 8; //ä¸?帧ć8ä¸?
parameter idle = 3'd0; //犺é˛çść??
parameter start = 3'd1; //ĺź?ĺ§ĺé?
parameter start_cnt = 3'd2; //ĺé?SOL
parameter shift = 3'd3; //ĺé?ć°ć?
parameter finish = 3'd4; //ĺź?ĺ§ĺéçťć帧
parameter finish_cnt = 3'd5; //çťć帧莥ć?
reg [2:0]state; //ĺ˝ĺçść??
reg [2:0]next_state; //ä¸ä¸çść??
reg [7:0]crc_temp; //ĺĺ¨ĺ˝ĺĺé?çä¸?byteć°ćŽ
reg [3:0]period_cnt; //帧莥ć?
reg [2:0]pause_insert; //ćĺĽä˝ç˝Ž
reg [BYTE_CNT:0]byte_cnt; //ĺč莥ć°
reg [BYTE_CNT:0]temp_cnt;
reg [1:0]shift_cnt;
reg shift_flag;
reg flag_state;
reg flag_start_cnt;
reg flag_finish_cnt;
reg data_vaild_temp;
always @(posedge clk_system or negedge rstn) begin
if(!rstn)
data_vaild_temp <= 1'd0;
else if(datavaild & state == idle)
data_vaild_temp <= 1'd1;
else if(ppm_finish)
data_vaild_temp <= 1'd0;
end
//çść?ćş
always @(posedge clk_ppm or negedge rstn) begin
if (!rstn)begin
state <= idle;
end
else
state <= next_state;
end
//ćśĺşčżéčŚč°
always @(*)begin
case (state)
idle :if(data_vaild_temp) next_state = start;else next_state = idle; //ć°ćŽćć
start :if(flag_start_cnt)next_state = start_cnt;else next_state = start; //ĺé?SOLĺé??
start_cnt :if(flag_state) next_state = shift;else next_state = start_cnt; //ĺé?ĺŽć?
shift :if(byte_cnt == temp_cnt) next_state = finish;else next_state = shift; //ĺé?ć°ć?
finish :if(flag_finish_cnt)next_state = finish_cnt;else next_state = finish_cnt; //ĺé?EOF
finish_cnt:if(ppm_finish) next_state = idle;else next_state = finish_cnt; //ĺ˝äť¤ĺé?çťćďźč˝ŹĺĽçŠşé˛çść??
endcase
end
always @(posedge clk_ppm or negedge rstn) begin
if(!rstn)begin
ppm_out <= 1'd1;
ppm_finish <= 1'd0;
crc_temp <= 7'd0;
period_cnt <= 4'd0;
pause_insert <= 3'd0;
byte_shift <= 1'd0;
byte_cnt <= 0;
shift_cnt <= 2'd0;
shift_flag <= 1'd1;
flag_state <= 1'd0;
temp_cnt <= 0;
flag_start_cnt <= 1'd0;
flag_finish_cnt <= 1'd0;
end
else begin
case (next_state)
idle: begin
ppm_out <= 1'd1;
ppm_finish <= 1'd0;
end //犺é˛ďźčžĺşéŤ
start: begin
period_cnt <= 4'd0; //ć´ć°ĺé?ć°ć?
temp_cnt <= cnt;
crc_temp <= {2'd0,crc[7:2]}; //??
pause_insert <= {crc[1:0],1'd1}; //????
ppm_out <= 1'd0; //SOL
flag_start_cnt <= 1'd1;
end
start_cnt:begin
ppm_out <= 1'd1; //SOL
if(period_cnt == period/2)
ppm_out <= 1'd0;
else
ppm_out <= 1'd1;
if(period_cnt == period-1)begin //SOL??
period_cnt <= 4'd0;
flag_state <= 1'd1;
end
else
period_cnt <= period_cnt+1;
end
shift:begin
if(period_cnt == pause_insert-1) //??
ppm_out <= 1'd0;
else
ppm_out <= 1'd1;
if(period_cnt == period-1)
if(shift_cnt == 3)begin
pause_insert <= {crc[1:0],1'd1};
crc_temp <= {2'd0,crc[7:2]};
byte_cnt <= byte_cnt + 1'd1;
shift_cnt <= 2'd0;
if(byte_cnt!=cnt-2)
shift_flag <= 1'd1;
else
shift_flag <= 1'd0;
period_cnt <= 4'd0;
end
else begin
shift_cnt <= shift_cnt + 1'd1;
period_cnt <= 4'd0;
pause_insert <= {crc_temp[1:0],1'd1};
crc_temp <= {2'd0,crc_temp[7:2]};
end
else
period_cnt <= period_cnt + 1'd1;
if (shift_flag)begin
byte_shift <= 1'd1;
shift_flag <= 1'd0;
end
else
byte_shift <= 1'd0;
end
finish:begin
shift_flag <= 1'd1;
ppm_out <= 1'd1;
period_cnt <= period_cnt + 1'd1;
flag_finish_cnt <= 1'd1;
end
finish_cnt:begin
flag_start_cnt <= 1'd0;
flag_state <= 1'd0;
byte_cnt <= 0;
flag_finish_cnt <= 1'd0;
period_cnt <= period_cnt + 1'd1;
if(period_cnt == 1)
ppm_out <= 1'd0;
else
ppm_out <= 1'd1;
if (period_cnt == period/2-1)
ppm_finish <= 1'd1;
end
default: ;
endcase
end
end
endmodule