FPGA MPSOC-5EV高速摄像机+专业显示器功能之 硬件开发总结记录

本文分享了一位开发者使用FPGAMPSOC-5EV进行高速摄像机的硬件开发过程,包括12G-SDI和HDMIL2.0的输入输出、4K@60支持、千兆网口等关键功能的设计。开发者利用SMPTEUHD-SDITXSUBSYSTEMIP核进行12G-SDI输入,并通过IBERT测试验证硬件性能,目前硬件基本性能已通过测试。
摘要由CSDN通过智能技术生成

FPGA MPSOC-5EV高速摄像机+专业显示器功能之 硬件开发,我是用5EV,开发一个带HDMIL2.0输入输出显示功能,有6路12G-SDI输入输出显示一个专业显示器。主要跟大家一起分享,这个开发的过程,有很多不足,希望大家指整,欢迎各位老铁发邮件给我(1041503164@qq.com)指证。首先,把我们要需求理清楚,

 

 我会在重点前面两块---硬件与软件记录分享

我们目标产品是做一个高速摄像机,的硬件需求是有1-12GSDI输入,同时环出;2-HDMI输入输出,要支持4K@60;3-千兆网口;4-RS422接口出与入;5-EDP输出到屏;7-支持硬件存取;8-音频输入输出;9-按键有的快捷键;10-电池供电;11-TAILL灯指示;

FPGA图形化软件IP设计:

对应上面的接进行输入输出操作;1-12GSDI输入,我用的是SMPTE UHD-SDI TXSUB SYSTEM,赛林思自带IP核。这个还没有做,做好给大家分享。

根据上面的需求,我做成硬件框图:

我们调试口,高速网口是,UART,JTAG调试FLAHS,及EMMC都是在PS端,12G-SDI IN 和OUT,HDMI IN OUT,都是在PL端。接下来根每一个模块把原理图做上去,因为原理图比较大只贴几张图,12G-SDI图输出图

隔了很久没有更新了,把最近工作做一次总结,这部分与FPGA的高速走线进行连接,再有IBERT 进行硬件检测,得出硬件基本性能,用单例程对12G-SDI进行运行,情况:对12G-SDI,在没有打通v_smpte_uhdsdi_tx_ss的IP时可以用IBERT来测试这个接口的硬件是否可行的,我的测试如下:

在ERAR没有出现错误,STAT没有红就说明,硬件这块基本是通的,可以通过网眼图的大小看电路板相关指标。

接下来是对PS端的UART1,UART2,QSPI,要对各个模块的FPGA进行软件调试,首先要在VIVADO里把UART1,UART2勾选上。

导出FPGA的XSA文件

单程序UART调试成功:

VITIS代码,是自发,自收。从PC机通过串口发通过FPGA转发出来。具体效果如上图

****************************************************/

#include "sys_intr.h"
#include "uartps_intr.h"

/**********************************cxc***********************/
#include "xparameters.h"
#include "xgpiops.h"
#include "xstatus.h"
#include "xplatform_info.h"
#include <xil_printf.h>


#ifndef GPIO_DEVICE_ID
#define GPIO_DEVICE_ID        XPAR_XGPIOPS_0_DEVICE_ID
#endif

#define printf xil_printf    /* Smalller foot-print printf */

XGpioPs Gpio;    /* The driver instance for GPIO Device. */

#define LED0  (40)//MIO
#define LED1  (42)//MIO
#define LED2  (78)//EMIO
#define LED3  (79)//EMIO
#define BTN0  (43)//MIO
#define BTN1  (80)//EMIO
int uart_read_data ;    /* Buffer for uart_read_data Data */

/*************************cxc******************************/
extern XScuGic Intc; //GIC
extern XUartPs UartPs;//uart

extern u8 *SendBuffer;    /* Buffer for Transmitting Data */
extern u8 *RecvBuffer ;    /* Buffer for Receiving Data */

void init_intr_sys(void)
{
    Init_Intr_System(&Intc);

    Init_UartPsIntr(&UartPs,UART_DEVICE_ID);

    UartPs_Setup_IntrSystem(&Intc, &UartPs, UART_INT_IRQ_ID);

    Setup_Intr_Exception(&Intc);
}

int GpioPolledInit(u16 DeviceId);

int main(void)
{
    //xil_printf(“Hello World”);
    init_intr_sys();
    XUartPs_Recv(&UartPs, RecvBuffer, TEST_BUFFER_SIZE);
    //uart_read_data=XUartPs_ReceiveBuffer();
    if (uart_read_data==2)
    {
        XGpioPs_WritePin(&Gpio, LED1, 1);
    }
    else
    {
      XGpioPs_WritePin(&Gpio, LED1, 0);
     }


   // while(1);
    return 0;
}

/*******cxc*********************************/
int GpioPolledInit(u16 DeviceId)
{
    int Status;
    XGpioPs_Config *ConfigPtr;
    /* Initialize the GPIO driver. */
    ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
    Status = XGpioPs_CfgInitialize(&Gpio, ConfigPtr,ConfigPtr->BaseAddr);

   //set LED0~LED5 output

    XGpioPs_SetDirectionPin(&Gpio, LED0, 0x1);
    XGpioPs_SetDirectionPin(&Gpio, LED1, 0x1);
    XGpioPs_SetDirectionPin(&Gpio, LED2, 0x1);
    XGpioPs_SetDirectionPin(&Gpio, LED3, 0x1);

    //set BTN0~BTN2 input
    XGpioPs_SetDirectionPin(&Gpio,BTN0, 0x0);
    XGpioPs_SetDirectionPin(&Gpio,BTN1, 0x0);

    XGpioPs_SetOutputEnablePin(&Gpio, LED0, 1);
    XGpioPs_SetOutputEnablePin(&Gpio, LED1, 1);
    XGpioPs_SetOutputEnablePin(&Gpio, LED2, 1);
    XGpioPs_SetOutputEnablePin(&Gpio, LED3, 1);

    XGpioPs_WritePin(&Gpio, LED0, 1);
    XGpioPs_WritePin(&Gpio, LED1, 1);
    XGpioPs_WritePin(&Gpio, LED2, 1);
    XGpioPs_WritePin(&Gpio, LED3, 1);

    return Status;
}
/**************cxc*************************/

通串口输入1关闭GPIO,为后面的各个子模块合并做基础,这里有几个知识点,1-GOPI操作只用CXC围起来的哪些代码进行修改就是可以操作任何一个GPIO口了。

操作效果如下:在串口输1,两个灭了

近期把一个7010的PL端一个串口程序移到4EV上,自发自收,波特率不对,这块一直没有解决先做一个记号,继续板砖。移植这个程有几点是原来没有的第一个是把差分时钟转成单端时钟,还有就是原来是50M现在改成200M这也可能是波特率不对原因----------备注:此程序可以UART进行自发自收,能控制GPIO口,但还有一个问题收发波特率不对。

把代码发出来,TOP的代码:

//****************************************Copyright (c)***********************************//
                               
//----------------------------------------------------------------------------------------
// File name:           uart_loop
// Last modified Date:  2019/10/8 17:25:36
// Last Version:        V1.1
// Descriptions:        串口数据环回模块
//----------------------------------------------------------------------------------------
// Created by:          
// Created date:        2019/10/8 17:25:36
// Version:             V1.0
// Descriptions:        The original version
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//

module uart_loop(
    input             sys_clk,                   //系统时钟
    input            sys_rst_n,                 //系统复位,低电平有效
     
    input            recv_done,                 //接收一帧数据完成标志
    input      [7:0] recv_data,                 //接收的数据
     
    input            tx_busy,                   //发送忙状态标志      
    output reg       send_en,                   //发送使能信号
    output reg [7:0] send_data                //待发送数据
    
    );

//reg define
reg recv_done_d0;
reg recv_done_d1;
reg tx_ready;

//wire define
wire recv_done_flag;

//*****************************************************
//**                    main code
//*****************************************************

//捕获recv_done上升沿,得到一个时钟周期的脉冲信号
assign recv_done_flag = (~recv_done_d1) & recv_done_d0;
                                                 
//对发送使能信号recv_done延迟两个时钟周期
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin
        recv_done_d0 <= 1'b0;                                  
        recv_done_d1 <= 1'b0;
    end                                                      
    else begin                                               
        recv_done_d0 <= recv_done;                               
        recv_done_d1 <= recv_done_d0;                            
    end
end

//判断接收完成信号,并在串口发送模块空闲时给出发送使能信号
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin
        tx_ready  <= 1'b0; 
        send_en   <= 1'b0;
        send_data <= 8'd0;
    end                                                      
    else begin                                               
        if(recv_done_flag)begin                 //检测串口接收到数据
            tx_ready  <= 1'b1;                  //准备启动发送过程
            send_en   <= 1'b0;
            send_data <= recv_data;             //寄存串口接收的数据
        end
        else if(tx_ready && (~tx_busy)) begin   //检测串口发送模块空闲
            tx_ready <= 1'b0;                   //准备过程结束
            send_en  <= 1'b1;                 //拉高发送使能信号
        end
    end
end
/*
ila_0 u_ila_0 (
    .clk(sys_clk), // input wire clk

    .probe0(send_data), // input wire [0:0] probe0
    .probe1(send_en),
    .probe2(tx_ready)
    //.probe1(led_o) // input wire [0:0] probe0
);
*/


endmodule 

UART接收模块的代码:

//`timescale 1ns / 1ps
                      
//----------------------------------------------------------------------------------------
// File name:           uart_recv
// Last modified Date:  2019/10/9 9:56:36
// Last Version:        V1.1
// Descriptions:        UART串口接收模块
//----------------------------------------------------------------------------------------
// Created by:          
// Created date:        2019/10/9 9:56:36
// Version:             V1.0
// Descriptions:        The original version
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//

module uart_recv(
    input              sys_clk,                  //系统时钟
    input             sys_rst_n,                //系统复位,低电平有效
    
    input             uart_rxd,                 //UART接收端口
    output  reg       uart_done,                //接收一帧数据完成标志
    output  reg [7:0] uart_data                 //接收的数据
    );
    
//parameter define
parameter  CLK_FREQ = 200000000;                //系统时钟频率
parameter  UART_BPS = 9600;                    //串口波特率
localparam  BPS_CNT  = CLK_FREQ/UART_BPS;       //为得到指定波特率,
                                                //需要对系统时钟计数BPS_CNT次
//reg define
reg        uart_rxd_d0;
reg        uart_rxd_d1;
reg [15:0] clk_cnt;                             //系统时钟计数器
reg [ 3:0] rx_cnt;                              //接收数据计数器
reg        rx_flag;                             //接收过程标志信号
reg [ 7:0] rxdata;                              //接收数据寄存器

//wire define
wire       start_flag;

//*****************************************************
//**                    main code
//*****************************************************
//捕获接收端口下降沿(起始位),得到一个时钟周期的脉冲信号
assign  start_flag = uart_rxd_d1 & (~uart_rxd_d0);    

//对UART接收端口的数据延迟两个时钟周期
always @(posedge sys_clk or negedge sys_rst_n) begin 
    if (!sys_rst_n) begin 
        uart_rxd_d0 <= 1'b0;
        uart_rxd_d1 <= 1'b0;          
    end
    else begin
        uart_rxd_d0  <= uart_rxd;                   
        uart_rxd_d1  <= uart_rxd_d0;
    end   
end

//当脉冲信号start_flag到达时,进入接收过程           
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n)                                  
        rx_flag <= 1'b0;
    else begin
        if(start_flag)                          //检测到起始位
            rx_flag <= 1'b1;                    //进入接收过程,标志位rx_flag拉高
                                                //计数到停止位中间时,停止接收过程
        else if((rx_cnt == 4'd9) && (clk_cnt == BPS_CNT/2))
            rx_flag <= 1'b0;                    //接收过程结束,标志位rx_flag拉低
        else
            rx_flag <= rx_flag;
    end
end

//进入接收过程后,启动系统时钟计数器
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n)                             
        clk_cnt <= 16'd0;                                  
    else if ( rx_flag ) begin                   //处于接收过程
        if (clk_cnt < BPS_CNT - 1)
            clk_cnt <= clk_cnt + 1'b1;
        else
            clk_cnt <= 16'd0;                   //对系统时钟计数达一个波特率周期后清零
    end
    else                                              
        clk_cnt <= 16'd0;                        //接收过程结束,计数器清零
end

//进入接收过程后,启动接收数据计数器
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n)                             
        rx_cnt  <= 4'd0;
    else if ( rx_flag ) begin                   //处于接收过程
        if (clk_cnt == BPS_CNT - 1)                //对系统时钟计数达一个波特率周期
            rx_cnt <= rx_cnt + 1'b1;            //此时接收数据计数器加1
        else
            rx_cnt <= rx_cnt;       
    end
     else
        rx_cnt  <= 4'd0;                        //接收过程结束,计数器清零
end

//根据接收数据计数器来寄存uart接收端口数据
always @(posedge sys_clk or negedge sys_rst_n) begin 
    if ( !sys_rst_n)  
        rxdata <= 8'd0;                                     
    else if(rx_flag)                            //系统处于接收过程
        if (clk_cnt == BPS_CNT/2) begin         //判断系统时钟计数器计数到数据位中间
            case ( rx_cnt )
             4'd1 : rxdata[0] <= uart_rxd_d1;   //寄存数据位最低位
             4'd2 : rxdata[1] <= uart_rxd_d1;
             4'd3 : rxdata[2] <= uart_rxd_d1;
             4'd4 : rxdata[3] <= uart_rxd_d1;
             4'd5 : rxdata[4] <= uart_rxd_d1;
             4'd6 : rxdata[5] <= uart_rxd_d1;
             4'd7 : rxdata[6] <= uart_rxd_d1;
             4'd8 : rxdata[7] <= uart_rxd_d1;   //寄存数据位最高位
             default:;                                    
            endcase
        end
        else 
            rxdata <= rxdata;
    else
        rxdata <= 8'd0;
end

//数据接收完毕后给出标志信号并寄存输出接收到的数据
always @(posedge sys_clk or negedge sys_rst_n) begin        
    if (!sys_rst_n) begin
        uart_data <= 8'd0;                               
        uart_done <= 1'b0;
    end
    else if(rx_cnt == 4'd9) begin               //接收数据计数器计数到停止位时           
        uart_data <= rxdata;                    //寄存输出接收到的数据
        uart_done <= 1'b1;                      //并将接收完成标志位拉高
    end
    else begin
        uart_data <= 8'd0;                                   
        uart_done <= 1'b0; 
    end    
end

endmodule    

中转模块代码:

//****************************************Copyright (c)***********************************//
                               
//----------------------------------------------------------------------------------------
// File name:           uart_loop
// Last modified Date:  2019/10/8 17:25:36
// Last Version:        V1.1
// Descriptions:        串口数据环回模块
//----------------------------------------------------------------------------------------
// Created by:          
// Created date:        2019/10/8 17:25:36
// Version:             V1.0
// Descriptions:        The original version
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//

module uart_loop(
    input             sys_clk,                   //系统时钟
    input            sys_rst_n,                 //系统复位,低电平有效
     
    input            recv_done,                 //接收一帧数据完成标志
    input      [7:0] recv_data,                 //接收的数据
     
    input            tx_busy,                   //发送忙状态标志      
    output reg       send_en,                   //发送使能信号
    output reg [7:0] send_data                //待发送数据
    
    );

//reg define
reg recv_done_d0;
reg recv_done_d1;
reg tx_ready;

//wire define
wire recv_done_flag;

//*****************************************************
//**                    main code
//*****************************************************

//捕获recv_done上升沿,得到一个时钟周期的脉冲信号
assign recv_done_flag = (~recv_done_d1) & recv_done_d0;
                                                 
//对发送使能信号recv_done延迟两个时钟周期
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin
        recv_done_d0 <= 1'b0;                                  
        recv_done_d1 <= 1'b0;
    end                                                      
    else begin                                               
        recv_done_d0 <= recv_done;                               
        recv_done_d1 <= recv_done_d0;                            
    end
end

//判断接收完成信号,并在串口发送模块空闲时给出发送使能信号
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin
        tx_ready  <= 1'b0; 
        send_en   <= 1'b0;
        send_data <= 8'd0;
    end                                                      
    else begin                                               
        if(recv_done_flag)begin                 //检测串口接收到数据
            tx_ready  <= 1'b1;                  //准备启动发送过程
            send_en   <= 1'b0;
            send_data <= recv_data;             //寄存串口接收的数据
        end
        else if(tx_ready && (~tx_busy)) begin   //检测串口发送模块空闲
            tx_ready <= 1'b0;                   //准备过程结束
            send_en  <= 1'b1;                 //拉高发送使能信号
        end
    end
end
/*
ila_0 u_ila_0 (
    .clk(sys_clk), // input wire clk

    .probe0(send_data), // input wire [0:0] probe0
    .probe1(send_en),
    .probe2(tx_ready)
    //.probe1(led_o) // input wire [0:0] probe0
);
*/


endmodule 

发送模块代码:

//`timescale 1ns / 1ps
               
//----------------------------------------------------------------------------------------
// File name:           uart_send
// Last modified Date:  2019/10/9 10:07:36
// Last Version:        V1.1
// Descriptions:        UART串口发送模块
//----------------------------------------------------------------------------------------
// Created by:          
// Created date:        2019/10/9 10:07:36
// Version:             V1.0
// Descriptions:        The original version
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//

module uart_send(
    input          sys_clk,                  //系统时钟
    input         sys_rst_n,                //系统复位,低电平有效
    
    input         uart_en,                  //发送使能信号
    input  [7:0]  uart_din,                 //待发送数据
    output        uart_tx_busy,             //发送忙状态标志      
    output  reg   uart_txd                  //UART发送端口
    );
    
//parameter define
parameter  CLK_FREQ = 200000000;            //系统时钟频率
parameter  UART_BPS = 9600;                //串口波特率
localparam  BPS_CNT  = CLK_FREQ/UART_BPS;   //为得到指定波特率,对系统时钟计数BPS_CNT次

//reg define
reg        uart_en_d0; 
reg        uart_en_d1;  
reg [15:0] clk_cnt;                         //系统时钟计数器
reg [ 3:0] tx_cnt;                          //发送数据计数器
reg        tx_flag;                         //发送过程标志信号
reg [ 7:0] tx_data;                         //寄存发送数据

//wire define
wire       en_flag;

//*****************************************************
//**                    main code
//*****************************************************
//在串口发送过程中给出忙状态标志
assign uart_tx_busy = tx_flag;

//捕获uart_en上升沿,得到一个时钟周期的脉冲信号
assign en_flag = (~uart_en_d1) & uart_en_d0;

//对发送使能信号uart_en延迟两个时钟周期
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin
        uart_en_d0 <= 1'b0;                                  
        uart_en_d1 <= 1'b0;
    end                                                      
    else begin                                               
        uart_en_d0 <= uart_en;                               
        uart_en_d1 <= uart_en_d0;                            
    end
end

//当脉冲信号en_flag到达时,寄存待发送的数据,并进入发送过程          
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin                                  
        tx_flag <= 1'b0;
        tx_data <= 8'd0;
    end 
    else if (en_flag) begin                 //检测到发送使能上升沿                      
            tx_flag <= 1'b1;                //进入发送过程,标志位tx_flag拉高
            tx_data <= uart_din;            //寄存待发送的数据
        end
                                            //计数到停止位结束时,停止发送过程
        else if ((tx_cnt == 4'd9) && (clk_cnt == BPS_CNT -(BPS_CNT/16))) begin                                       
            tx_flag <= 1'b0;                //发送过程结束,标志位tx_flag拉低
            tx_data <= 8'd0;
        end
        else begin
            tx_flag <= tx_flag;
            tx_data <= tx_data;
        end 
end

//进入发送过程后,启动系统时钟计数器
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n)                             
        clk_cnt <= 16'd0;                                  
    else if (tx_flag) begin                 //处于发送过程
        if (clk_cnt < BPS_CNT - 1)
            clk_cnt <= clk_cnt + 1'b1;
        else
            clk_cnt <= 16'd0;               //对系统时钟计数达一个波特率周期后清零
    end
    else                             
        clk_cnt <= 16'd0;                     //发送过程结束
end

//进入发送过程后,启动发送数据计数器
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n)                             
        tx_cnt <= 4'd0;
    else if (tx_flag) begin                 //处于发送过程
        if (clk_cnt == BPS_CNT - 1)            //对系统时钟计数达一个波特率周期
            tx_cnt <= tx_cnt + 1'b1;        //此时发送数据计数器加1
        else
            tx_cnt <= tx_cnt;       
    end
    else                              
        tx_cnt  <= 4'd0;                    //发送过程结束
end

//根据发送数据计数器来给uart发送端口赋值
always @(posedge sys_clk or negedge sys_rst_n) begin        
    if (!sys_rst_n)  
        uart_txd <= 1'b1;        
    else if (tx_flag)
        case(tx_cnt)
            4'd0: uart_txd <= 1'b0;         //起始位 
            4'd1: uart_txd <= tx_data[0];   //数据位最低位
            4'd2: uart_txd <= tx_data[1];
            4'd3: uart_txd <= tx_data[2];
            4'd4: uart_txd <= tx_data[3];
            4'd5: uart_txd <= tx_data[4];
            4'd6: uart_txd <= tx_data[5];
            4'd7: uart_txd <= tx_data[6];
            4'd8: uart_txd <= tx_data[7];   //数据位最高位
            4'd9: uart_txd <= 1'b1;         //停止位
            default: ;
        endcase
    else 
        uart_txd <= 1'b1;                   //空闲时发送端口为高电平
end

endmodule              

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值