明德扬论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 511|回复: 0

【基于FPGA的图像处理工程】边缘检测工程之sccb传输模块代码解析

[复制链接]
发表于 2019-12-7 11:27:34 | 显示全部楼层 |阅读模式

马上注册,看完整文章,学更多FPGA知识。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
【基于FPGA的图像处理工程】
                                                                     —边缘检测工程:sccb传输模块代码解析
作者:肖肖肖
        本文为明德扬原创文章,转载请注明出处!
       Sccb传输模块的功能: 按照sccb传输协议的时序,传输上游模块的摄像头配置指令。

       一、        设计架构

       下图是官方中给出的SCCB时序图,虽然是三线的但是我们也可以用来学习二线的时序。
1.png

       1.        协议开始:在SIO_C高电平期间,SIO_D由高变低,表示传输的开始。如上图所示,在开始数据传输时,SIO_C要先处于高电平,由SIO_D(即本模块中的 sio_d_w 信号)先保持一段时间高电平并产生下降沿来标志传输开始,其中SIO_D 变低到 SIO_C 变低,最少 100ns。

2.png



       2.        协议结束:在SIO_C高电平期间,SIO_D由高变低,表示数据传输的停止。如上图所示,在停止数据传输时,SIO_C也要首先置于高电平,由SIO_D(即本模块中的sio_d_w信号)产生上升沿并保持一段时间来标志传输结束,其中 SIO_C 变高到 SIO_D 变高,最少100ns。


3.png

       3.        其他时候 ,SIO_D 只能在 SIO_C=0 时才变化。


4.png

       4.        时序图中的 SIO_D 和 SIO_C,分别是本模块中的 sio_d_w 和 sio_c 信号。
       5.        写寄存器的过程:a.协议开始;b.发送设备ID编号,等待;c. 发送要存入的寄存器地址,等待;d.发送要写入的数据;e.协议结束。

5.png
       6.        读寄存器的时序:a.协议开始;b.发送设备ID编号,等待;c. 发送要读取的寄存器地址,等待;d. 协议结束;e.协议开始;f. 发送设备ID编号,等待;g. 读取Byte数据,NACK=1;h. 协议结束。
6.png


7.png



       本模块计数器的架构图如下所示

8.png

       A、Count_sck:时钟计数器。使用此计数器,来对传输1位数据时钟进行计数。本模块时钟是25M,周期为40ns,而SCCB传输1bit本模块设定为 120*40ns,所以此计数器每次要数120个。
       B、Count_bit:位计数器。使用此计数器,要对传输1个阶段的位进行计数。根据sccb传输协议,读寄存器时序和写寄存器时序的位长度都是不一样的,可以通过变量bit_num来确定。
       C、Count_duan:阶段计数器。使用此计数器,对读或者写的阶段进行计数。根据sccb传输协议,读寄存器状态需要两个阶段,而写寄存器状态只有一个阶段,所以通过变量duan_num来确定。


       二、        举例说明


       收到写使能 wen=1(同一时刻过来了 写数据wdata 和 寄存器地址数据sub_addr )时,产生如下波形。

9.png
       如上图所示,收到 wen=1,并且 sub_addr=8’h12 和 wdata=8’h04,这意味着要向地址为8’h12的寄存器写数据8’h04因此各个信号如下变化:
sio_c 和 sio_d_w:波形首先产生了开始位。然后依次发送 8’h42(固定值)和 x=1,发送 8’h12(sub_addr)和 x=1,发送 8’h04(wdata)和 x=1。之后是结束位,最后是 2 个间隔位(固定发 11)。 至此整个过程结束。        
       en_sio_d_w:在收到 wr_en=1 开始,en_sio_d_w 就为 1,直到最后结束。


       收到读使能ren=1(同一时刻过来了寄存器地址数据sub_addr,而wdata不关心)时,产生如下波形。

1.0.png
       如上图所示,收到ren=1,并且sub_addr=8’h12(注意要展开来看,看rd_en=1时刻) ,这意味着要读地址为8’h12的寄存器的数据,因此各个信号如下变化
       sio_c、sio_d_w、rdata和rdata_vld:波形首先产生了开始位;然后依次发送8’h42(固定值)和x=1;然后再发送8’h12(sub_addr)和x=1,然后是结束位和间隔位。之后又是开始位,发送8’h43(固定值)和x=1。之后在8个sio_c周期内,取sio_d_r的值并保存到rdata中(8个值保存后,就可以产生1个时钟周期的rdata_vld=1脉冲)。最后是结束位和间隔位(固定发11)。 至此整个过程结束。
en_sio_d_w:在收到rd_en=1开始,en_sio_d_w就为1,直到读取数据为0,读取数据后为1,整个过程结束后又为0。


       本模块准备好指示信号rdy在整个波形产生期间,以及wen=1和ren=1时,均为0(rdy可以组合逻辑产生并输出)。
11.png

12.png
      
       三、        信号意义

  
信号
  
类型
意义
clk
输入信号
时钟信号,时钟频率为25M。
rst_n
输入信号
复位信号,低电平有效。
ren
输入信号
读使能信号。
wen
输入信号
当读使能信号为1的时候,本模块进入忙状态,同时进入读数据状态和打开sccb数据总线的三态门。
sub_addr  
输入信号
写使能信号。
wdata
输入信号
当写使能信号为1的时候,本模块进入忙状态,同时进入写数据状态和打开sccb数据总线的三态门。
rdata
输出信号
寄存器地址。
rdata_vld
输出信号
读写的寄存器共用的地址。
rdy      
输出信号
向寄存器写的数据信号。
sio_c
输出信号
从寄存器读到的数据信号。
sio_d_r
输入信号
从寄存器读到的读出的数据有效指示信号。
en_sio_d_w
输出信号
设计逻辑:当SCCB传输完成并且是处于读寄存器状态时,表示数据接收完毕,并且一个时钟的有效指示信号。并且sccb传输数据完成时
sio_d_w   
输出信号
本模块准备好指示信号。
flag_addr   
内部信号
0:本模块忙,下一个时钟不要发命令过来;
flag_selw   
内部信号
1:本模块空闲,下一个时钟可以发命令过来。
count_sck
内部信号
sccb接口中的时钟信号,频率约为208.3100k。
add_count_sck
内部信号
设计逻辑:在SCCB时钟高变低时刻(sio_c_h2l)变低;在SCCB时钟低变高时刻(sio_c_l2h)变高。
end_count_sck
内部信号
从sccb数据总线中读到的信号。
count_bit
内部信号
设计逻辑:该信号直接取自三态门的数据。
add_count_bit
内部信号
sccb三态数据总线中三态门打开使能。
end_count_bit
内部信号
0:关闭;
bit_num   
内部信号
1:打开。
count_duan
内部信号
设计逻辑:收到读命令或者写命令时,就要立刻打开使能;当整个读写结束时,就要关闭三态门;此外,在读状态的第二个阶段,第10个至18个数据期间,三态门要关闭,因为此时要从总线上获取读到的数据。
add_count_duan
内部信号
每次写到sccb三态数据总线中的数据。
end_count_duan
内部信号
设计逻辑:在数据变换时刻,将待传输数据,按照位计数器的顺序,传输到本信号上。
duan_num  
内部信号
工作状态读寄存器状态信号。当其为1时,表示处于读或者写状态。
out_data  
内部信号
设计逻辑:当收到读或者写命令时,就进入工作状态;当阶段计数器数完后,就返回到空闲状态。
sio_c_h2l     
内部信号
读寄存器状态从收到读使能信号开始到一个完整的sccb传输时序结束。
sio_c_l2h     
内部信号
1:读寄存器状态,此时sccb时序有两个阶段,每个阶段有21 bit长,第一阶段设备ID编号为8’h42,第二阶段设备ID编号为8’h43,并把对应的sccb时序数据赋给Sccb传输数据信号。
en_sio_d_w_h2l
内部信号
读或者写状态区分写寄存器状态信号。
en_sio_d_w_l2h
内部信号
1:读状态
out_data_time
内部信号
0: 写状态
rdata_time   
内部信号
设计逻辑:收到写命令就处于写状态;收到读命令就处于读状态。写寄存器状态从收到写使能信号开始到一个完整的sccb传输时序结束。
rd_com        
内部信号
1:写寄存器状态,此时sccb时序只有一个阶段,该阶段有30 bit长,设备ID编号固定为8’h42,并把对应的sccb时序数据赋给Sccb传输数据信号。

      
       四、        参考代码
       下面展出本模块的设计,欢迎进一步交流,如果需要源代码,欢迎与本人联系。
  1. module sccb(
  2.     clk       ,
  3.     rst_n     ,
  4.     ren       ,
  5.     wen       ,
  6.     sub_addr  ,
  7.     rdata     ,
  8.     rdata_vld ,
  9.     wdata     ,
  10.     rdy       ,
  11.     sio_c     ,
  12.     sio_d_r   ,
  13.     en_sio_d_w,
  14.     sio_d_w         
  15. );

  16.     //参数定义
  17.     parameter      SIO_C  = 120 ;

  18.     //输入信号定义
  19.     input               clk      ;//25m
  20.     input               rst_n    ;
  21.     input               ren      ;
  22.     input               wen      ;
  23.     input [7:0]         sub_addr ;
  24.     input [7:0]         wdata    ;

  25.     //输出信号定义
  26.     output[7:0]         rdata    ;
  27.     output              rdata_vld;
  28.     output              sio_c    ;//208kHz
  29.     output              rdy      ;

  30.     input               sio_d_r   ;
  31.     output              en_sio_d_w;
  32.     output              sio_d_w   ;
  33.     reg                 en_sio_d_w;
  34.     reg                 sio_d_w   ;

  35.     //输出信号reg定义
  36.     reg [7:0]           rdata    ;
  37.     reg                 rdata_vld;
  38.     reg                 sio_c    ;
  39.     reg                 rdy      ;

  40.     //中间信号定义
  41.     reg  [7:0]          count_sck     ;
  42.     reg  [4:0]          count_bit     ;
  43.     reg  [1:0]          count_duan    ;
  44.     reg                 flag_add      ;
  45.     reg                 flag_sel        ;
  46.     reg  [4:0]          bit_num       ;
  47.     reg  [1:0]          duan_num      ;
  48.     reg  [29:0]         out_data      ;

  49.     wire                add_count_sck ;
  50.     wire                end_count_sck ;
  51.     wire                add_count_bit ;
  52.     wire                end_count_bit ;
  53.     wire                add_count_duan;
  54.     wire                end_count_duan;
  55.     wire                sio_c_h2l     ;
  56.     wire                sio_c_l2h     ;
  57.     wire                out_data_time ;
  58.     wire                rdata_time    ;
  59.     wire [7:0]          rd_com        ;
  60.    
  61.     always  @(posedge clk or negedge rst_n)begin
  62.         if(rst_n==1'b0)begin
  63.             count_sck <= 0;
  64.         end
  65.         else if(add_count_sck)begin
  66.             if(end_count_sck)begin
  67.                 count_sck <= 0;
  68.             end
  69.             else begin
  70.                 count_sck <= count_sck + 1;
  71.             end
  72.         end
  73.     end

  74.     assign add_count_sck = flag_add  ;
  75.     assign end_count_sck = add_count_sck && count_sck == SIO_C-1;

  76.     always  @(posedge clk or negedge rst_n)begin
  77.         if(rst_n==1'b0)begin
  78.             count_bit <= 0;
  79.         end
  80.         else if(add_count_bit)begin
  81.             if(end_count_bit)begin
  82.                 count_bit <= 0;
  83.             end
  84.             else begin
  85.                 count_bit <= count_bit + 1;
  86.             end
  87.         end
  88.     end

  89.     assign add_count_bit = end_count_sck;
  90.     assign end_count_bit = add_count_bit && count_bit == bit_num+2-1;

  91.     always  @(posedge clk or negedge rst_n)begin
  92.         if(rst_n==1'b0)begin
  93.             count_duan <= 0;
  94.         end
  95.         else if(add_count_duan)begin
  96.             if(end_count_duan)begin
  97.                 count_duan <= 0;
  98.             end
  99.             else begin
  100.                 count_duan <= count_duan + 1;
  101.             end
  102.         end
  103.     end

  104.     assign add_count_duan = end_count_bit;
  105.     assign end_count_duan = add_count_duan && count_duan == duan_num-1;

  106.     always  @(posedge clk or negedge rst_n)begin
  107.         if(rst_n==1'b0)begin
  108.             flag_add <= 0;
  109.         end
  110.         else if(ren || wen)begin
  111.             flag_add <= 1;
  112.         end
  113.         else if(end_count_duan)begin
  114.             flag_add <= 0;
  115.         end
  116.     end

  117.     always  @(posedge clk or negedge rst_n)begin
  118.         if(rst_n==1'b0)begin
  119.             flag_sel <= 0;
  120.         end
  121.         else if(wen)begin
  122.             flag_sel <= 0;
  123.         end
  124.         else if(ren)begin
  125.             flag_sel <= 1;
  126.         end
  127.     end

  128.     always  @(*)begin
  129.         if(flag_sel==1)begin
  130.             bit_num = 21;
  131.             duan_num = 2;
  132.         end
  133.         else begin
  134.             bit_num = 30;
  135.             duan_num = 1;
  136.         end
  137.     end

  138.     always  @(posedge clk or negedge rst_n)begin
  139.         if(rst_n==1'b0)begin
  140.             sio_c <= 1;
  141.         end
  142.         else if(sio_c_h2l)begin
  143.             sio_c <= 0;
  144.         end
  145.         else if(sio_c_l2h)begin
  146.             sio_c <= 1;
  147.         end
  148.     end

  149.     assign sio_c_h2l = count_bit >= 0 && count_bit < (bit_num-2) && add_count_sck && count_sck == SIO_C-1;
  150.     assign sio_c_l2h = add_count_sck && count_sck == SIO_C/2-1;


  151.     always @ (*)begin
  152.         if(flag_sel==1)begin
  153.             out_data <= {1'h0,rd_com,1'h1,sub_addr,1'h1,1'h0,1'h1,9'h0};
  154.         end
  155.         else begin
  156.             out_data <= {1'h0,8'h42,1'h1,sub_addr,1'h1,wdata,1'h1,1'h0,1'h1};
  157.         end
  158.     end

  159.     assign rd_com = (flag_sel==1 && count_duan == 0)? 8'h42 : 8'h43;

  160.     always  @(posedge clk or negedge rst_n)begin
  161.         if(rst_n==1'b0)begin
  162.             en_sio_d_w <= 0;
  163.         end
  164.         else if(ren || wen)begin
  165.             en_sio_d_w <= 1;
  166.         end
  167.         else if(end_count_duan)begin
  168.             en_sio_d_w <= 0;
  169.         end
  170.         else if(flag_sel==1 && count_duan == 1 && count_bit == 10 && add_count_sck && count_sck == 1-1)begin
  171.             en_sio_d_w <= 0;
  172.         end
  173.         else if(flag_sel==1 && count_duan == 1 && count_bit == 18 && add_count_sck && count_sck == 1-1)begin
  174.             en_sio_d_w <= 1;
  175.         end
  176.     end


  177.     always  @(posedge clk or negedge rst_n)begin
  178.         if(rst_n==1'b0)begin
  179.             sio_d_w <= 1;
  180.         end
  181.         else if(out_data_time)begin
  182.             sio_d_w <= out_data[30-count_bit-1];
  183.         end
  184.     end

  185.     assign out_data_time = count_bit >= 0 && count_bit < bit_num && add_count_sck && count_sck == SIO_C/4-1;

  186.     always  @(posedge clk or negedge rst_n)begin
  187.         if(rst_n==1'b0)begin
  188.             rdata <= 0;
  189.         end
  190.         else if(rdata_time)begin
  191.             rdata[17-count_bit] <= sio_d_r;
  192.         end
  193.     end

  194.     assign rdata_time = flag_sel==1 && count_duan==1 && count_bit>=10 && count_bit<18 && add_count_sck && count_sck==SIO_C/4*3-1;

  195.     always  @(posedge clk or negedge rst_n)begin
  196.         if(rst_n==1'b0)begin
  197.             rdata_vld <= 0;
  198.         end
  199.         else if(flag_sel==1 && end_count_duan)begin
  200.             rdata_vld <= 1;
  201.         end
  202.         else begin
  203.             rdata_vld <= 0;
  204.         end
  205.     end

  206.     always  @(*)begin
  207.         if(ren || wen || flag_add)begin
  208.             rdy = 0;
  209.         end
  210.         else begin
  211.             rdy = 1;
  212.         end
  213.     end

  214. endmodule

复制代码









        明德扬专注FPGA研究,我司正在连载两本书籍:《基于FPGA至简设计法实现的图像边缘检测系统》(http://www.fpgabbs.cn/forum.php?mod=viewthread&tid=691)、《ASIC和FPGA时序约束理论与应用》(http://www.fpgabbs.cn/forum.php?mod=viewthread&tid=705),有兴趣点击观看。也欢迎加入群(838209674),及时获取最新的文章信息,个性化问题也可以找我哦:Q1479512800(肖肖肖)





上一篇:【基于FPGA的图像处理工程】边缘检测工程:之摄像头配置指令模块代码解析
下一篇:【基于FPGA的图像处理工程】边缘检测工程之Ascii转十六进制模块代码解析
加QQ:1744527324,获取更多FPGA资料!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|MDYBBS ( 粤ICP备16061416号

GMT+8, 2020-1-20 22:29 , Processed in 0.606215 second(s), 41 queries , File On.

Powered by Discuz! X3.4

本论坛由广州健飞通信有限公司所有

© 2001-2019 Comsenz Inc.

快速回复 返回顶部 返回列表