CCD image sensors 驱动时序 S10420-1004-01系列

相信能来看本文章必定对CCD有一定深度了解,CCD的背景,用途将不做介绍,具体的细节可查阅其他相关资料,本文将详细的分析CCD的时序,以及代码的分享和后续内容,学习CCD来做拉曼光谱仪,以及拉曼光谱仪相关部分资料的也会在后续更新。

1.CCD的工作原理

CCD的工作原理可以参考视频,传感器与检测技术ccd图像传感器_哔哩哔哩_bilibili

以下图片来自视频20分钟处

三个电极相位相差1/3个周期,会使得信号电荷最终全部积累在电极2、5的势阱中。没错CCD的时序就是需要相位等差(4个电极信号,相位相差1/4个周期)的电极信号,通过电荷的积累,经过垂直转移光栅,存储在电容中,形成电压。

我相信看完CCD的工作原理后将会理解上图的用意。

2.CCD的时序

了解了CCD的工作原理之后,不难看懂上图,P1H----P4H,是4个驱动电极,相位相差1/4个周期,P1V和P2V是垂直转移光栅驱动信号。时序说明如下图所示:

具体时序选择和分析:

P1-P4的高电平持续时间最小是50ns,上升时间和下降时间10ns,因此整个周期持续时间10+50+10+50+10=130ns典型值100ns,10+100+10+100+10=230ns因此取160作为一个周期,占空比为50%;为什么要取160ns,还要考虑到RG信号,RG信号和P1H-P4H都是160ns为一个周期但是Tpwr在5-50ns之间,因此选用Tpwr在高电平期间持续40ns,40/160=25%,占空比为25%,由于本文用的是50MHZ的时钟进行测试,20ns一个周期,40ns刚好是2个周期,没有用PLL 的IP核,所以尽量取整数个周期以便于实现。P1V和P2V相差1/2个周期,一个周期是16us。

3.代码设计

module  ccd (

        clk               ,
        rst_n             ,    
        
        en                ,
        din               ,

        p1v               ,   //8us
        p2v_tg            ,
        p1h               ,  //200ns
        p2h               ,
        p3h               ,
        p4h_sg            ,
        //160ns,  pwm25%  40ns    
        rg                
                             
       
        
);
                
 
               parameter             IDLE = 2'b00                ;
               parameter             IT   = 2'b01                ;      
               parameter             VP   = 2'b10                ;
               parameter             RP   = 2'b11                ;
              
               input                  clk                        ;
               input                  rst_n                      ;
              
               input                  en                         ;
               input   [10:0]         din                        ;

               output  reg            p1v                        ;
               output  reg            p2v_tg                     ;
               output  reg            p1h                        ;
               output  reg            p2h                        ;
               output  reg            p3h                        ;
               output  reg            p4h_sg                     ;
               output  reg            rg                         ;
               
          //   output                os                          ; 
               
          //   wire   [10:0]         din                         ;
               reg                   flag_tovr                   ;
               reg                   flag                        ;
               reg    [2:0]          flag_switch_zt              ;
               wire                  idle2it_start               ;  
               wire                  it2vp_start                 ;
               wire                  vp2rp_start                 ;
               wire                  rp2idle_start               ;

               wire                  add_cnt0                    ;
               wire                  add_cnt1                    ; 
               wire                  end_cnt0                    ;
               wire                  end_cnt1                    ;
              
               wire                  add_cnt2                    ;
               wire                  add_cnt3                    ; 
               wire                  end_cnt2                    ;
               wire                  end_cnt3                    ;
                
               wire                  add_cnt4                    ;
               wire                  end_cnt4                    ;
               wire                  add_cnt5                    ;
               wire                  end_cnt5                    ;

          
               reg    [10: 0]        cnt0                        ;  //  800  800*20=16000ns
               reg    [3: 0]         cnt1                        ;  //  8   20*8=160ns
               reg    [5: 0]         cnt2                        ;  //  22   period
               reg    [12:0]         cnt3                        ;  //  1044 period
               reg    [8:0]          cnt4                        ;  //  100  period
               reg    [10:0]         cnt5                        ;  //  din  period


               reg    [2: 0]         state_c                     ;
               reg    [2: 0]         state_n                     ;
              
                always@(posedge clk or negedge rst_n)begin
                    if(!rst_n)begin
                        state_c <= IDLE;
                    end
                    else begin
                        state_c <= state_n;
                    end
                end

    
                always@(*)begin
                    case(state_c)
                         IDLE:begin
                            if(idle2it_start)begin
                                state_n = IT;
                            end
                            else begin
                                state_n = state_c;
                            end
                        end
                        IT:begin
                            if(it2vp_start)begin
                                state_n = VP;
                            end
                            else begin
                                state_n = state_c;
                            end
                        end
                        VP:begin
                            if(vp2rp_start)begin
                                state_n = RP;
                            end
                            else begin
                                state_n = state_c;
                            end
                        end
                        RP:begin
                            if(rp2idle_start)begin
                                state_n = IDLE;
                            end
                            else begin
                                state_n = state_c;
                            end
                        end
                        default:begin
                            state_n = IDLE;
                        end
                    endcase
                end


                assign idle2it_start  = state_c==  IDLE     &&  flag ==1      ;
                assign it2vp_start    = state_c==  IT       &&  end_cnt5      ;  // din
                assign vp2rp_start    = state_c==  VP       &&  end_cnt4      ;  //  22 + Tovr2us=100period
                assign rp2idle_start  = state_c==  RP       &&  end_cnt3      ;  //  1044


                always  @(posedge clk or negedge rst_n)begin
                    if(!rst_n)begin
                        flag_switch_zt <= 3'b000 ;     //初始化
                    end
                    else if(state_c==IDLE)begin
                        flag_switch_zt <= 3'b001 ;
                    end
                    else if(state_c==IT)begin
                        flag_switch_zt <= 3'b010 ;
                    end
                    else if(state_c==VP) begin
                        flag_switch_zt <= 3'b011 ;
                    end
                    else begin 
                        flag_switch_zt <= 3'b100 ;
                    end
                end

     always @(posedge clk or negedge rst_n)begin
               if(!rst_n)begin
                   cnt5 <= 0;
               end
               else if(add_cnt5)begin
                   if(end_cnt5)
                       cnt5 <= 0;
                   else
                       cnt5 <= cnt5 + 1;
               end
           end

           assign add_cnt5 = state_c == IT && end_cnt1           ; //    cnt1=8
           assign end_cnt5 = add_cnt5      && cnt5  ==  din - 1  ;



        

           always  @(posedge clk or negedge rst_n)begin
               if(rst_n==1'b0)begin
                     flag <= 0;
               end
               else if(en)begin
                     flag <= 1;
               end
               else if(state_c==  RP  &&  end_cnt3 )begin
                     flag <= 0;
               end
           end


       //20ns*800=16000ns=16us

           always @(posedge clk or negedge rst_n)begin
               if(!rst_n)begin
                   cnt0 <= 0;
               end
               else if(add_cnt0)begin
                   if(end_cnt0)
                       cnt0 <= 0;
                   else
                       cnt0 <= cnt0 + 1;
               end
           end

           assign add_cnt0 = state_c  ==  VP  ;
           assign end_cnt0 = add_cnt0 && cnt0== 800 - 1  ;
//16+6 period 
     always @(posedge clk or negedge rst_n)begin
          if(!rst_n)begin
              cnt2 <= 0;
          end
          else if(add_cnt2)begin
              if(end_cnt2)
                  cnt2 <= 0;
              else
                  cnt2 <= cnt2 + 1;
          end
      end

    assign add_cnt2 = end_cnt0 && state_c  ==  VP     ;
    assign end_cnt2 = add_cnt2 && cnt2     ==  22 - 1 ;

      
           

          always  @(posedge clk or negedge rst_n)begin
              if(rst_n==1'b0)begin
                  p1v    <= 0;
                  p2v_tg <= 0;  
              end
              else if( state_c == VP )begin
                  if(cnt0>=0   && cnt0 <400 )
                          p1v <= 0;
                  if(cnt0>=400 && cnt0 <800 )
                          p1v <= 1;
                  if(cnt0>=400 && cnt0 <800 )
                          p2v_tg <= 0;
                  if(cnt0>=0   && cnt0 <400 )
                          p2v_tg <= 1;               
              end 
              else begin 
                          p1v    <= 0;
                          p2v_tg <= 0;  
              end

          end

    
    //20ns * 8=160 ns  
             always @(posedge clk or negedge rst_n)begin 
               if(!rst_n)begin
                   cnt1 <= 0;
               end
               else if(add_cnt1)begin
                   if(end_cnt1)
                       cnt1 <= 0;
                   else
                       cnt1 <= cnt1 + 1;
               end
           end

           assign add_cnt1 = state_c == IT || state_c == RP     ;
           assign end_cnt1 = add_cnt1      && cnt1    == 8 - 1  ;
               

    //1044 period

              always @(posedge clk or negedge rst_n)begin
                   if(!rst_n)begin
                       cnt3 <= 0;
                   end
                   else if(add_cnt3)begin
                       if(end_cnt3)
                           cnt3 <= 0;
                       else
                           cnt3 <= cnt3 + 1;
                   end
               end
           
             assign add_cnt3 = end_cnt1;
             assign end_cnt3 = add_cnt3 && cnt3== 1044  - 1 ;

           
                  
                   always  @(posedge clk or negedge rst_n)begin
                       if(rst_n==1'b0)begin
                           flag_tovr <= 0 ;
                       end
                       else if(end_cnt2)begin
                           flag_tovr <= 1 ;
                       end
                       else if(end_cnt4)begin
                           flag_tovr <= 0 ;
                       end
                   end

              always @(posedge clk or negedge rst_n)begin
                   if(!rst_n)begin
                       cnt4 <= 0;
                   end
                   else if(add_cnt4)begin
                       if(end_cnt4)
                           cnt4 <= 0;
                       else
                           cnt4 <= cnt4 + 1;
                   end
               end
           
             assign add_cnt4 = flag_tovr == 1;
             assign end_cnt4 = add_cnt4  && cnt4 == 100 - 1 ;
      

 
 


       always  @(posedge clk or negedge rst_n)begin
              if(rst_n==1'b0)begin
                  p1h      <= 1;
                  p2h      <= 0; 
                  p3h      <= 0;
                  p4h_sg   <= 0;
              end
  
              else if( state_c == IT || state_c == RP )begin
                      
                    if (cnt1>=1 && cnt1<5)
                         p2h    <= 0;
                    if ((cnt1>=0 && cnt1<2) || (cnt1>=6 && cnt1<7))
                         p2h    <= 1;
                    if ( cnt1>=0 && cnt1<4  )
                         p1h    <= 0;
                    if ( cnt1>=4 && cnt1<8  )
                         p1h    <= 1;                   
                    if ( (cnt1>=0 && cnt1<2 ) || (cnt1>=6 && cnt1<7) )
                         p3h    <= 0;
                    if ( (cnt1>=1 && cnt1<5))
                         p3h    <= 1;

                    if ( cnt1>=4 && cnt1<8  )
                         p4h_sg    <= 0;
                    if ( cnt1>=0 && cnt1<4  )
                         p4h_sg    <= 1;
              end 
              else begin
                  p1h      <= 1;
                  p2h      <= 0; 
                  p3h      <= 0;
                  p4h_sg   <= 0;
              end
                
          end
          
  

        always  @(posedge clk or negedge rst_n)begin
              if(rst_n==1'b0)begin
                  rg <= 1;     
              end
              else if(state_c == RP )begin
                       
                    if ( cnt1>=2 && cnt1<8  )
                         rg    <= 0;
                    if ( cnt1>=0 && cnt1<2  )
                         rg    <= 1;                     
              end  
              else begin 
                          rg <= 1; 
              end           
          end

endmodule


4.测试代码

  

`timescale 1 ns/1 ns

module tb_ccd();


                               reg                   clk                                        ;
                               reg                   rst_n                                      ;
                               reg    [10:0]         din                                        ;
                               reg                   en                                         ;

                  
                                 
                               wire                  p1v                                        ;
                               wire                  p2v_tg                                     ;

                               wire                  p1h                                        ;
                               wire                  p2h                                        ;
                               wire                  p3h                                        ;
                               wire                  p4h_sg                                     ;
                               wire                  rg                                         ;
    

        //时钟周期,单位为ns,可在此修改时钟周期。
        parameter CYCLE    = 20;

        //复位时间,此时表示复位3个时钟周期的时间。
        parameter RST_TIME = 3 ;

        //待测试的模块例化
                               ccd uut(
                                 .clk                             (clk      ), 
                                 .rst_n                           (rst_n    ),
                                 .en                              (en       ),
                                 .din                             (din      ),

                                 .p1v                             (p1v      ),
                                 .p2v_tg                          (p2v_tg   ),
                                 .p1h                             (p1h      ),
                                 .p2h                             (p2h      ),
                                 .p3h                             (p3h      ),
                                 .p4h_sg                          (p4h_sg   ),
                                 .rg                              (rg       )

                                    );


            //生成本地时钟50M
            initial begin
                clk = 0;
                forever
                #(CYCLE/2)
                clk=~clk;
            end

            //产生复位信号
            initial begin
                rst_n = 1;
                #2;
                rst_n = 0;
                #(CYCLE*RST_TIME);
                rst_n = 1;
            end


            initial begin
                #1;
           
                en  = 0  ;
                din = 33;     //可调参数
     

            end
          
            initial begin
                #(200*CYCLE);
                # 1 ;
                //赋初值
                en = 1;
                #(1*CYCLE);
                en = 0;
                //开始赋值

            end

         

            endmodule

代码有2个接口,一个是en,使能信号,整个CCD时序触发信号,驱动电极P1H-P4H,持续的时钟数,用来调节光积分的周期,可用串口URAT方式传递参数,和上位机配合使用。

那么看到这里会发现驱动信号都写好了,那么输出信号OS呢?

看模拟输入和CCD时序的OS输出有没有觉得很像啊,这是AD9826的驱动时序,CCD的输出是模拟信号,经过ADC转换后经AD9826输出,具体里的AD9826时序和驱动代码将会再后续更新,如有错漏之处,敬请指正。如需CCD和AD9826的相关资料,可私信获取。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值