AC701 HDMI DEMO

手上有一块AC701,准备测试一下HDMI接口,查了一堆资料,ADI官方的实在太复杂,我就点个屏至于那么复杂吗,果断放弃。
adam-taylor大佬倒是有一个教程:
https://www.hackster.io/adam-taylor/ac701-hdmi-test-pattern-generation-9aa148
但是很遗憾的是图片看不清。
ADI还有个应用笔记AN-1270《基于ADV7511/ADV7511W/ADV7513的视频发生器》,我觉得这个比较简洁,直接CV大佬的代码。再加一个MB软核,挂载AXI IIC用来配置ADV7511。
XILINX官方也有个非常不错的视频系列教程:Xilinx Video Series and Blog Posts https://support.xilinx.com/s/question/0D52E00006hpsS0SAI/xilinx-video-series-and-blog-posts?language=en_US
我按照Xilinx Video Series and Blog Posts ,很快用ZEDBOARD上的HDMI输出了图像,但是把软件代码移植到AC701上,HDMI输出还是没显示,把初始化代码完全按照AN-1270《基于ADV7511/ADV7511W/ADV7513的视频发生器》,也不行。无意中发现,用ZEDBOARD的寄存器配置后,再运行AN-1270的配置,AC701的HDMI终于有输出了。
完整的初始化代码如下:

#include <stdio.h>
//#include "platform.h"
#include "xil_printf.h"
#include "xstatus.h"
#include "sleep.h"
#include "xiic_l.h"
#include "xil_io.h"
#include "xil_types.h"

#define PAGE_SIZE   16


#define IIC_BASE_ADDRESS	XPAR_IIC_0_BASEADDR

#define EEPROM_TEST_START_ADDRESS	0x80

#define IIC_SWITCH_ADDRESS 0x74
#define IIC_ADV7511_ADDRESS 0x39

#define ADV7511_HPD_CTRL_MASK	0x40 // bit 6 = state of HPD
#define ADV7511_HDP_REG_ADDR	0x42


typedef u8 AddressType;

typedef struct {
	u8 addr;
	u8 data;
	u8 init;
} HDMI_REG;

#define NUMBER_OF_HDMI_REGS  41
HDMI_REG hdmi_iic[NUMBER_OF_HDMI_REGS] = {
	{0x41, 0x00, 0x10},
	{0x98, 0x00, 0x03},
	{0x9A, 0x00, 0xE0},
	{0x9C, 0x00, 0x30},
	{0x9D, 0x00, 0x61},
	{0xA2, 0x00, 0xA4},
	{0xA3, 0x00, 0xA4},
	{0xE0, 0x00, 0xD0},
	{0xF9, 0x00, 0x00},
	{0x18, 0x00, 0xE7},
    {0x55, 0x00, 0x00},
    {0x56, 0x00, 0x28},
    {0xD6, 0x00, 0xC0},
    {0xAF, 0x00, 0x04},
	{0xF9, 0x00, 0x00},

	{0x01, 0x00, 0x00}, //Set N Value(6144)
	{0x02, 0x00, 0x18}, //Set N Value(6144)
	{0x03, 0x00, 0x00}, //Set N Value(6144)
	{0x15, 0x00, 0x00}, //Input 444 (RGB or YCrCb) with Separate Syncs
	{0x16, 0x00, 0x61}, //44.1kHz fs, YPrPb 444
	{0x18, 0x00, 0x46}, //CSC disabled
	{0x40, 0x00, 0x80}, //General Control Packet Enable
	{0x41, 0x00, 0x10}, //Power Down control
	{0x48, 0x00, 0x48}, //Reverse bus, Data right justified
	{0x48, 0x00, 0xA8}, //Set Dither_mode - 12-to-10 bit
	{0x4C, 0x00, 0x06}, //12 bit Output
	{0x55, 0x00, 0x00}, //Set RGB444 in AVinfo Frame
	{0x55, 0x00, 0x08}, //Set active format Aspect
	{0x96, 0x00, 0x20}, //HPD Interrupt clear
	{0x98, 0x00, 0x03}, //ADI required Write
	{0x98, 0x00, 0x02}, //ADI required Write
	{0x9C, 0x00, 0x30}, //ADI required Write
	{0x9D, 0x00, 0x61}, //Set clock divide
	{0xA2, 0x00, 0xA4}, //ADI required Write
	{0x43, 0x00, 0xA4}, //ADI required Write
	{0xAF, 0x00, 0x16}, //Set HDMI Mode
	{0xBA, 0x00, 0x60}, //No clock delay
	{0xDE, 0x00, 0x9C}, //ADI required write
	{0xE4, 0x00, 0x60}, //ADI required Write
	{0xFA, 0x00, 0x7D}  //Nbr of times to search for good phase,,
};


u8 EepromIicAddr;		/* Variable for storing Eeprom IIC address */

int IicLowLevelDynEeprom();

u8 EepromReadByte(AddressType Address, u8 *BufferPtr, u8 ByteCount);
u8 EepromWriteByte(AddressType Address, u8 *BufferPtr, u8 ByteCount);

int check_hdmi_hpd_status(void);


//HDMI IIC
int IicLowLevelDynEeprom()
{
  u8 BytesRead;
  u32 StatusReg;
  u8 Index;
  int Status;
  u32 i;
  u8 channel[1] = {0x20};

  Status = XIic_DynInit(IIC_BASE_ADDRESS);
  if (Status != XST_SUCCESS) {
	return XST_FAILURE;
  }
  xil_printf("\r\nAfter XIic_DynInit\r\n");
  while (((StatusReg = XIic_ReadReg(IIC_BASE_ADDRESS,
				XIIC_SR_REG_OFFSET)) &
				(XIIC_SR_RX_FIFO_EMPTY_MASK |
				XIIC_SR_TX_FIFO_EMPTY_MASK |
				XIIC_SR_BUS_BUSY_MASK)) !=
				(XIIC_SR_RX_FIFO_EMPTY_MASK |
				XIIC_SR_TX_FIFO_EMPTY_MASK)) {

  }

  EepromIicAddr = IIC_SWITCH_ADDRESS;
  XIic_DynSend(IIC_BASE_ADDRESS, EepromIicAddr,
		  	  	  channel, sizeof(channel), XIIC_STOP);


  EepromIicAddr = IIC_ADV7511_ADDRESS;
  for ( Index = 0; Index < NUMBER_OF_HDMI_REGS; Index++)
  {
    EepromWriteByte(hdmi_iic[Index].addr, &hdmi_iic[Index].init, 1);
  }


  for ( Index = 0; Index < NUMBER_OF_HDMI_REGS; Index++)
  {
    BytesRead = EepromReadByte(hdmi_iic[Index].addr, &hdmi_iic[Index].data, 1);
    for(i=0;i<1000;i++) {};	// IIC delay
	if (BytesRead != 1) {
      return XST_FAILURE;
	}
  }



  return XST_SUCCESS;

}

u8 EepromReadByte(AddressType Address, u8 *BufferPtr, u8 ByteCount)
{
  u8 ReceivedByteCount;
  u8 SentByteCount;
  u16 StatusReg;

  /*
   * Position the Read pointer to specific location in the EEPROM.
   */
  do {
	StatusReg = XIic_ReadReg(IIC_BASE_ADDRESS, XIIC_SR_REG_OFFSET);
    if (!(StatusReg & XIIC_SR_BUS_BUSY_MASK)) {
	  SentByteCount = XIic_DynSend(IIC_BASE_ADDRESS, EepromIicAddr,
					  (u8 *) &Address, sizeof(Address), XIIC_REPEATED_START);
    }

  } while (SentByteCount != sizeof(Address));
  /*
   * Receive the data.
   */
  ReceivedByteCount = XIic_DynRecv(IIC_BASE_ADDRESS, EepromIicAddr,
		                                          BufferPtr, ByteCount);

  /*
   * Return the number of bytes received from the EEPROM.
   */

  return ReceivedByteCount;

}


u8 EepromWriteByte(AddressType Address, u8 *BufferPtr, u8 ByteCount)
{
  u8 SentByteCount;
  u8 WriteBuffer[sizeof(Address) + PAGE_SIZE];
  u8 Index;

  /*
   * A temporary write buffer must be used which contains both the address
   * and the data to be written, put the address in first based upon the
   * size of the address for the EEPROM
   */
  if (sizeof(AddressType) == 2) {
	WriteBuffer[0] = (u8) (Address >> 8);
	WriteBuffer[1] = (u8) (Address);
  } else if (sizeof(AddressType) == 1) {
	WriteBuffer[0] = (u8) (Address);
	EepromIicAddr |= (EEPROM_TEST_START_ADDRESS >> 8) & 0x7;
  }

  /*
   * Put the data in the write buffer following the address.
   */
  for (Index = 0; Index < ByteCount; Index++) {
	WriteBuffer[sizeof(Address) + Index] = BufferPtr[Index];
  }

  /*
   * Write a page of data at the specified address to the EEPROM.
   */
  SentByteCount = XIic_DynSend(IIC_BASE_ADDRESS, EepromIicAddr,
				WriteBuffer, sizeof(Address) + ByteCount,
				XIIC_STOP);

  /*
   * Return the number of bytes written to the EEPROM.
   */
  return SentByteCount - sizeof(Address);

}

int main()
{

//	XVtc_Timing vtcTiming;
	int Status;
//	XVtc_SourceSelect/ SourceSelect;
//    init_platf/orm();

    print("Hello World\n\r");
    print("Successfully ran Hello World application");

    Status = IicLowLevelDynEeprom();
    if (Status != XST_SUCCESS) {
    	xil_printf("ADV7511 IIC programming FAILED\r\n");
    	return XST_FAILURE;
      }
    xil_printf("ADV7511 IIC programming PASSED\r\n");

    check_hdmi_hpd_status();

    return 0;
}

int check_hdmi_hpd_status(void)
{
//	int Status;
	u8 data = 0x00;
	u8 BytesRead;

	//
//	Status = iic_read(IicPs, Address, ADV7511_HDP_REG_ADDR, &data, 1);
	// Status = iic_read2( IicPs, /*ZC702_HDMI_ADDR*/ 0x39, 0x42, &data, 1);
	BytesRead = EepromReadByte(0x42, &data, 1);


	if((data & ADV7511_HPD_CTRL_MASK) == ADV7511_HPD_CTRL_MASK) {
		// Monitor Connected
		xil_printf("Monitor Connected\n\r");
		return 1;
	}
	else
	{
		// Monitor not connected
		xil_printf("Monitor not Connected\n\r");
		return 0;
	}
}

verilog代码就不贴了,用AN-1270的,如果是1080P,给个148.5MHz的时钟就行了。
调试中还发现一个奇怪的问题,要把输出给ADV7511的信号,通过ILA抓波形才行,如果不加ILA,HDMI居然没输出,不知道是不是被优化掉了,算了,反正加个ILA有HDMI输出就行,不想折腾了。

// ila_0 ila_0_i (
// 	.clk(clk148p5mhz), // input wire clk


// 	.probe0(adv7511_hs), // input wire [0:0]  probe0  
// 	.probe1(adv7511_vs), // input wire [0:0]  probe1 
// 	.probe2(adv7511_de), // input wire [0:0]  probe2 
// 	.probe3(adv7511_d) // input wire [23:0]  probe3
// );
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值