串并串转换(1)---- 整体介绍+并到串

整体过程

  • 目的:接收其他CPU(here用.vt 文件给)传过来的并行数据,并转为串行数据输出(之后有接收串行数据并转化为并行数据的例子);
  • 流程:.vt 给一个启动脉冲,在.v文件中接收此异步信号并处理为同步信号(点here跳转);对sys_clk分频,产生4个分频脉冲(点here跳转),进而模拟产生SCL控制时钟信号,并控制并行数据一位位输出为串行SDA数据。

程序说明

  • 并行数据接收
    像单片机、DSP那样,通过好多个输出引脚来输出一个数据的高位到低位,接收端接收到的就是并行数据,即一个data的各位都一起接收到了。
    here不管并行数据什么时候来,都每个时钟来把它锁存一下,赋给reg r_cpu_data保存一下。
    //.v
    always @(posedge i_sys_clk or negedge i_rst_n) begin
    	if(!i_rst_n) begin 
    		r_cpu_data <= 32'd0; end
    	else begin 
    		r_cpu_data <= i_cpu_data; end	
    end
    
    仿真信号直接在某个时间给 i_cpu_data赋值就行:#10 i_cpu_data = 32'h55aa55aa;

    想法:程序中我是直接判断启动脉冲来了就去状态跳转、转换数据,所以仿真限号得设置i_cpu_data 的在启动脉冲前赋值。 觉得状态的切换可以再设置一点东西,判断一下这是的r_cpu_data 是不是被赋值了(可能数据i_cpu_data 还没来,r_cpu_data 还全是零)。 得看实际情况怎么用,收发应该沟通好了就没问题。


  1. 启动脉冲来到时间提前不知道,相较系统时钟而言是异步信号,一般需要处理成同步信号来使用这个启动脉冲。这里一开始疑惑一个脉冲只是用一位数据的高低电平表示,又不是一串数据,那它怎么会通过取反、与操作来对齐波形呢?其实不需要是一串数据也可以就行取反、与操作等,assign是阻塞赋值,所以等式右边码值一变,等式左边码值就变,所以不是理解为一串数据与一串数据的操作,而是一位与一位的操作。
  2. 以上升沿的脉冲做启动脉冲时,沿同步的结果应为:(下降沿的脉冲做启动脉冲不同,另一个取反,具体见串并转换时
    assign startpulse_align = i_startpulse &&(~startpulse_dl);
    延迟锁存如下:
     always @(posedge i_sys_clk or negedge i_rst_n) begin
    	if(!i_rst_n) begin
    		startpulse_dl <= 1'd0; end
    	else begin
    		startpulse_dl <= i_startpulse; end
    end	
    
    波形示意如下:
    在这里插入图片描述(其中需要startpulse的持续时间不能太短,否则sys_clk还没检测到;)
  3. 在状态切换程序块中判断startpulse_align是不是为高来判断是否切换到下一状态,这里注意,状态切换程序块也是在sys_clk上升沿进行的判断,而由于非阻塞赋值,这里的startpulse_dl还为低(所有always块完了再一起更新值),所以startpulse_align还为高,所以判断若startpulse_align为高则跳转状态可以正常进行。

  1. 通过sys_clk设置了4个分频脉冲,四个脉冲走完相当于SCL一个周期走完(对应SCL的上升沿、高电平中间、下降沿、低电平中间),所以可以认为它们分别对应相位0/1/2/3。在各个脉冲到来时干特定的任务(觉得有点像时间片轮转法),而不是直接去判断SCL、SDA的沿(觉得这里考虑到传输协议,直接判断沿可能不好做,第一次接触到这种用法,不知道适用性怎么样);
  2. always @(posedge i_sys_clk or negedge i_rst_n) begin
    	if(!i_rst_n) begin
    		//都初始化为0
    	end
    	else begin
    		if(phase_cnt == 10'd39) begin//这里判断是不是40个sys_clk过去了
    			phase_cnt <= 10'b0; end	
    		else begin
    			phase_cnt <= phase_cnt + 10'b1;
    		end
    	
    		if(phase_cnt == 10'd39) begin//这里判断phase0是不是可以到了,并在一个sys_clk后置会0;
    			phase0 <= 1'd1; end
    		else begin
    			phase0 <= 1'd0;	
    		end	
    		//另几个phase同理
    	end	
    end	
    
  3. 这里判断条件的值还是注意非阻塞赋值
    ps:程序设置的4个phase共走40个sys_clk,这只是随便取的,差不多保证对应上面提到的SCL、SDA的四个特殊位置就行,怎么方便清楚怎么来。
  4. pahse0的判断条件不是用的phase_cnt =0,而是phase_cnt =尾,其他三个phase的判断仍按顺序就行

  • 根据四个分频脉冲,产生SCL信号时钟
    在phase0~1之间(指phase0来后到phase2来前)设置SCL信号为高电平;phase2-3(指phase2来后到phase0来前)之间为低电平;
    if(phase0 == 1'b1) begin
    	o_scl_clk <= 1'b1; end
    else if(phase2 == 1'b1) begin
    	o_scl_clk <= 1'b0;	 end
    else  o_scl_clk <= o_scl_clk;
    
    ps:同样由于非阻塞赋值,所以后面仿真可以看到波形上SCL是变沿是phase脉冲的尾部

  • 串行传输协议
  1. 这里用的是I2C:模拟产生SCL控制时钟线、SDA数据线;
    SCL为高时,SDA由高到低:数据传输开始;(1)
    SCL为低时,SDA由高到低 或 由低到高:传输码值;
    两个SCL低电平之间SDA码值不变;(2)
    SCL为高时,SDA由低到高:数据传输结束;
    即SCL为低时,SDA变的是数据码值;SCL为高时,SDA变是开始或结束传输。如下:
    在这里插入图片描述对于接收方来说,则以(1)做为启动脉冲,在(2)时读取稳定数据,这就只需要在SCL的上升沿读数据就行,也就不需要phase信号
  2. 结合4个分频脉冲,有:
    phase1为高 且 SCL为高时:若SDA由高到低,则开始传输数据,跳到TRANS状态;若 SDA由低到高,则结束传输,跳到IDLE;
    ps:这里得加一个“且SCL为高”,因为实际程序是先产生的phase1,之后才出现的phase0,所以防止SCL还没变高就开始传输数据了;
    phase3为高 (即SCL为低)时:接收数据并存储;

  • 状态机切换----结合传输协议
  1. IDLE:变量初始化;判断startpulse_align来没,来了去START;

  2. START:判断 SCL为高 且 phase1为高 不,是的去TRANS;

  3. TRANS:判断phase3为高不,为再判断数据个数够没有(一般收发双方会说好),够了去DELAY,不够继续接收;

    r_data_cnt <= r_data_cnt + 10'b1;//非阻塞赋值,so这两行位置欧克
    o_sda_data_com <= r_cpu_data[31 - r_data_cnt];
    

    这里并行数据 r_cpu_data 一开始就保存下来了,这里把它一位位的输出成串行数据;

  4. DELAY:延迟几个时钟单元(确保上个输出数据输出完整之类的),再把SDA线拉低(因为之后结束传输SDA需要由低到高);再去STOP;

    o_sda_data_com <= 1'b0;
    
  5. STOP:判断phase1为高不,为则把SDA拉高,并去IDLE;否则等phase1来;


  • 仿真结果
    在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值