针对OV5640(16位寄存器位宽)的sccb接口

sccb不需要判断应答位

        

/*qin*/
module sccb_io 
(
    input           clk,
    input           rst_n,
    input           sccb_write_req,
    input           sccb_read_req,
    output          sccb_ack,//数据发送完成
    output  [7:0]   sccb_read_data,
    input   [6:0]   lut_id,
    input   [15:0]  lut_addr,
    input   [7:0]   lut_data,

    inout           sccb_sda,
    output      reg sccb_scl
);
/*
sccb_io u_sccb_io(
    .clk            (clk            ),
    .rst_n          (rst_n          ),
    .sccb_write_req (sccb_write_req ),
    .sccb_read_req  (sccb_read_req  ),
    .sccb_ack       (sccb_ack       ),
    .lut_id         (lut_id         ),
    .lut_addr       (lut_addr       ),
    .lut_data       (lut_data       ),
    .sccb_sda       (sccb_sda       ),
    .sccb_scl       (sccb_scl       )
);
*/

localparam          cmoscnt_max    = 'd2000;
localparam          cmoscnt_half   = 'd1000;
localparam          comscnt_quater = 'd1500;

localparam          IDLE     = 8'b00000000;
localparam          START    = 8'b00000001;
localparam          ID_ADDR  = 8'b00000010;
localparam          REG_ADDR = 8'b00000100;
localparam          WRITE    = 8'b00001000;
localparam          READ     = 8'b00010000;
localparam          STOP     = 8'b00100000;

wire              sccb_en;
wire              scl_down;
reg               scl_frame;
reg               sdo;
reg               sdir;
reg               turnflag;
reg     [7:0]     read_data;//

reg     [15:0]    delay;//最大值必须是cmoscnt_max的两倍以上

reg     [7:0]     ID_CNT;  //发送从机地址
reg     [7:0]     REG_CNT; //发送寄存器地址
reg     [7:0]     DATA_CNT;//读写地址

reg     [15:0]    sccb_cnt;

reg     [7:0]     currentstate;
reg     [7:0]     nextstate;

assign      sccb_en = (sccb_cnt == cmoscnt_max)?1'b1:1'b0;
assign      scl_down = (!sccb_scl && scl_frame)?1'b1:1'b0;

assign      sccb_sda = (sdir)?sdo:1'hz;
assign      sccb_ack = (delay == 16'd5000)?1'b1:1'b0;
assign      sccb_read_data = read_data;
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        sccb_cnt <= 'd0;
    else if(currentstate == IDLE)
        sccb_cnt <= 'd0;
    else if(currentstate == STOP)
    begin
        if(sccb_scl == 1'b1 && sdo == 1'b1)
             sccb_cnt <= sccb_cnt;
        else
            sccb_cnt <= (sccb_cnt < 2*cmoscnt_max)?sccb_cnt + 1'b1:sccb_cnt;
    end
    // else if(currentstate == START)
    // begin
    //     if(turnflag)begin
    //         sccb_cnt <= (sccb_cnt > cmoscnt_half)?'d0:(sccb_cnt + 1'b1);
    //         turnflag <= 1'b0;
    //     end
    //     else
    //         sccb_cnt <= sccb_cnt + 1'b1;
    // end
    else if(sccb_cnt == cmoscnt_max)
        sccb_cnt <= 'd0;
    else 
        sccb_cnt <= sccb_cnt + 1'b1;
        
end

 always @(posedge clk or negedge rst_n)
 begin
     if(!rst_n)
         scl_frame <= 1'b1;
     else
         scl_frame <= sccb_scl; 
 end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        sccb_scl <= 1'b1;
    else if(currentstate == IDLE)
        sccb_scl <= 1'b1;
    else if(currentstate == START)
    begin
        if(sccb_cnt == comscnt_quater)
            sccb_scl <= 1'b0;
        else
            sccb_scl <= sccb_scl;
    end
    else if(currentstate == STOP)
    begin
        if(sccb_en)
            sccb_scl <= 1'b1;
        else
            sccb_scl <= sccb_scl;
    end
    else if(sccb_en)
        sccb_scl <= ~sccb_scl;
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        turnflag <= 1'b0;
    else if(currentstate == STOP && nextstate == START)
        turnflag <= 1'b1;
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)begin
        ID_CNT  <= 'd0;
        REG_CNT <= 'd0;
        DATA_CNT<= 'd0;
    end
    else begin
        ID_CNT    <= (currentstate == ID_ADDR)?((sccb_en && sccb_scl)?(ID_CNT + 1'b1):ID_CNT):'d0;
        REG_CNT   <= (currentstate == REG_ADDR)?((sccb_en && sccb_scl)?(REG_CNT + 1'b1):REG_CNT):'d0;
        DATA_CNT  <= (currentstate == WRITE || currentstate == READ)?((sccb_en && sccb_scl)?(DATA_CNT + 1'b1):DATA_CNT):'d0;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        sdir <= 1'b1;
    else if (sccb_scl == 1'b0 && sccb_cnt == cmoscnt_half)begin
        case(currentstate)
            IDLE:       sdir <= 1'b1;
            START:      sdir <= 1'b1;
            ID_ADDR:    sdir <= (ID_CNT == 8'd8)?1'b0:1'b1;
            REG_ADDR:   sdir <= (REG_CNT == 8'd8 || REG_CNT == 8'd17)?1'b0:1'b1;
            WRITE:      sdir <= (DATA_CNT == 8'd8)?1'b0:1'b1;
            READ:       sdir <= (DATA_CNT == 8'd8)?1'b1:1'b0;
            STOP:       sdir <= 1'b1;//(bit_cnt == )?1'b0:1'b1;
            default:    sdir <= 1'b1;
        endcase
    end
end

always @(posedge clk or negedge rst_n)
begin
    
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        delay <= 'd0;
    else if(currentstate == STOP)
        delay <= delay + 1'b1;
    else
        delay <= 'd0;
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        currentstate <= IDLE;
    else 
        currentstate <= nextstate; 
end

always @(*)
begin
    case(currentstate)
        IDLE:begin
            if(sccb_read_req || sccb_write_req)
                nextstate = START;
            else
                nextstate = IDLE;
        end
        START:begin
            if(sccb_read_req || sccb_write_req)begin    
                 if(sccb_scl == 1'b0 && sccb_cnt == cmoscnt_max)
                    nextstate = ID_ADDR;
                else
                    nextstate = START;
            end
            else
                nextstate = IDLE;
        end
        ID_ADDR:begin
            if(sccb_read_req || sccb_write_req)begin
                if(ID_CNT == 8'd9)
                    nextstate = REG_ADDR;
                else
                    nextstate = ID_ADDR;
            end
            else
                nextstate = IDLE;
        end
        REG_ADDR:begin
            if(sccb_read_req || sccb_write_req)begin
                if(REG_CNT == 8'd18)begin
                    if(sccb_write_req)
                        nextstate = WRITE;
                    else
                        nextstate = READ; 
                end
                else
                    nextstate = REG_ADDR;
            end
            else
                nextstate = IDLE;
        end
        WRITE:begin
            if(sccb_read_req || sccb_write_req)begin
                if(DATA_CNT == 8'd9)
                    nextstate = STOP;
                else
                    nextstate = WRITE;
            end
            else
                nextstate = IDLE;
        end
        READ:begin
            if(sccb_read_req || sccb_write_req)begin
                if(DATA_CNT == 8'd9)
                    nextstate = STOP;
                else
                    nextstate = READ;
            end
            else
                nextstate = IDLE;
        end
        STOP:begin
            // if(delay == 'd5000)begin
                // if(sccb_read_req || sccb_write_req)
                //     nextstate = START;
                // else
            // end
            if(delay == 'd5000)
                nextstate = IDLE;
            else
                nextstate = STOP;
        end
        default:;
    endcase
end


always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)begin
        sdo <= 1'b1;
        read_data <= 'd0;
    end
    else begin
        case(currentstate)
            IDLE:begin
                sdo <= 1'b1;
            end
            START:begin
                if(sccb_cnt == cmoscnt_half)
                    sdo <= 1'b0;
                else
                    sdo <= sdo;
            end
            ID_ADDR:begin
                if(ID_CNT < 8'd7)begin
                    if(sccb_scl == 1'b0 && sccb_cnt == cmoscnt_half)
                        sdo <= lut_id[8'd6 - ID_CNT];
                    else
                        sdo <= sdo;
                end
                else begin
                    if(sccb_scl == 1'b0 && sccb_cnt == cmoscnt_half)
                    begin
                        if(sccb_write_req)
                            sdo <= 1'b0;
                        else 
                            sdo <= 1'b1;
                    end
                    else
                        sdo <= sdo;
                end
            end
            REG_ADDR:begin
                if(REG_CNT < 8'd8)begin
                    if(sccb_scl == 1'b0 && sccb_cnt == cmoscnt_half)
                        sdo <= lut_addr[8'd15 - REG_CNT];//高8位
                    else
                        sdo <= sdo;
                end
                else if(REG_CNT < 8'd17 && REG_CNT > 8'd8)begin
                    if(sccb_scl == 1'b0 && sccb_cnt == cmoscnt_half)
                        sdo <= lut_addr[8'd16 - REG_CNT];//低8位
                    else
                        sdo <= sdo;
                end
                else
                    sdo <= 1'b1;
            end
            WRITE:begin
                if(DATA_CNT < 8'd8 )begin
                    if(sccb_scl == 1'b0 && sccb_cnt == cmoscnt_half)
                        sdo <= lut_data[8'd7 - DATA_CNT];
                    else
                        sdo <= sdo;
                end
                else
                    sdo <= 1'b1;        
            end
            READ:begin
                if(DATA_CNT < 8'd8 )begin
                    if(sccb_scl == 1'b1 && sccb_cnt == cmoscnt_half)
                        read_data[8'd7 - DATA_CNT] <= sccb_sda;
                    else
                        read_data <= read_data;
                end
                else begin
                    read_data <= read_data; 
                    if(DATA_CNT == 8'd8)
                        sdo <= 1'b0;
                    else
                        sdo <= sdo;
                end
            end
            STOP:begin
                if(sccb_scl == 1'b1 && sccb_cnt == 2*cmoscnt_max)
                    sdo <= 1'b1;
                else 
                    sdo <= 1'b0;
            end
            default:;
        endcase
    end
end


endmodule

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
根据引用\[1\]和引用\[2\]的内容,OV5640寄存器配置是通过SCCB总线进行的。SCCB总线是由OmniVision公司定义和发展的串行摄像头控制总线,控制着摄像头的大部分功能,包括图像数据格式、分辨率以及图像处理参数等。OV5640使用的是两线式SCCB接口总线,寄存器地址使用16(两个字节)表示。在写传输协议中,ID Address是由7器件地址和1读写控制构成,OV5640的器件地址为7'h3c,所以在写传输协议中,ID Address(W)= 8'h78(器件地址左移1,低补0)。Sub-address(H)为高8寄存器地址,Sub-address(L)为低8寄存器地址。每一个寄存器地址对应8的配置数据。因此,ov5640寄存器配置的方向是通过SCCB总线向OV5640写入配置数据。 #### 引用[.reference_title] - *1* [ov5640帧率配置_基于OV5640FPGARAM HDMI显示](https://blog.csdn.net/weixin_39743722/article/details/111621868)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [ZYNQ图像处理(2)——ov5640_hdmi显示环境搭建](https://blog.csdn.net/qq_40995480/article/details/126404742)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值