基于FPAG的NFC Reader端(六)——PPM产生

本文介绍了如何使用ISO1569的4取1编码方法对命令进行PPM转换,包括起始帧和结束帧的添加,以及利用状态机处理数据的编码过程,同时提及了代码中的两个时钟问题和优化潜力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        本章节主要实现将命令转换成根据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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Crystal(mercy)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值