环境:
a)硬件:官方ZCU106开发板 , tb-fmch-vfmc-dp子卡。
b)软件:vivado2021.1,vitis2021.1,裸机程序。
1、官方例程:

2、DP RX IP :

3、DP RX寄存器:

4、时钟:

5、像素:
Stream模式:

native模式:

6、timming:注意de非连续,每帧hsync个数和h_active一致。

7、vitis代码分析:
a)、iic使用ps测,和官方例程不一样,所以在MCDP6000这个文件夹定义iic:
PS侧iic初始化代码:iIc速率:100K
void ps_iic_init()
{
int Status;
XIicPs_Config *Config;
/* * Initialize the IIC driver so that it's ready to use
* Look up the configuration in the config table,
* then initialize it. */
Config = XIicPs_LookupConfig(XPAR_XIICPS_1_DEVICE_ID);
if (NULL == Config) {
printf("XIicPs_LookupConfig Failed\r\n");
return XST_FAILURE;
}
Status = XIicPs_CfgInitialize(&Iic, Config, Config->BaseAddress);
if (Status != XST_SUCCESS) {
printf("XIicPs_CfgInitialize Failed\r\n");
return XST_FAILURE;
}
/* * Perform a self-test to ensure that the hardware was built correctly. */
Status = XIicPs_SelfTest(&Iic);
if (Status != XST_SUCCESS) {
printf("XIicPs_SelfTest Failed\r\n");
return XST_FAILURE;
}
/* * Set the IIC serial clock rate. */
XIicPs_SetSClk(&Iic, 100000);
}
DP RX的初始化:
u32 Dprx_init(void)
{
u32 Status;
XDpRxSs_Config *ConfigPtr_rx;
xil_printf("config dp rx \n\r");
ConfigPtr_rx = XDpRxSs_LookupConfig(XDPRXSS_DEVICE_ID);
if (!ConfigPtr_rx) {
xil_printf("DPRXSS Lookup Config failed.\n\r");
return XST_FAILURE;
}
Status = XDpRxSs_CfgInitialize(&DpRxSsInst, ConfigPtr_rx,ConfigPtr_rx->BaseAddress);
if (Status != XST_SUCCESS) {
xil_printf("DPRXSS config initialization failed.\n\r");
return XST_FAILURE;
}
/* Check for SST/MST support */
if (DpRxSsInst.UsrOpt.MstSupport) {
xil_printf("INFO:DPRXSS is MST enabled. DPRXSS can be " "switched to SST/MST\n\r");
} else {
xil_printf("INFO:DPRXSS is SST enabled. DPRXSS works " "only in SST mode.\n\r");
}
xil_printf("Dprx_init end .\n\r");
return XST_SUCCESS;
}
中断初始化:这里RX,TX都有包含
u32 DpSs_SetupIntrSystem(void)
{
u32 Status;
XINTC *IntcInstPtr = &IntcInst;
// Tx side
DpTxSs_SetupIntrSystem();
// Rx side
#ifdef DP_RX_EN
DpRxSs_SetupIntrSystem();
#endif
/* The configuration parameters of the interrupt controller */
XScuGic_Config *IntcConfig;
/* Initialize the interrupt controller
* driver so that it is ready to use. */
IntcConfig = XScuGic_LookupConfig(XINTC_DEVICE_ID);
if (NULL == IntcConfig) {
xil_printf("XINTC_DEVICE_ID XScuGic_LookupConfig failed!\n\r");
return XST_FAILURE;
}
Status = XScuGic_CfgInitialize(IntcInstPtr, IntcConfig, IntcConfig->CpuBaseAddress);
if (Status != XST_SUCCESS) {
xil_printf("XINTC_DEVICE_ID XScuGic_CfgInitialize failed!\n\r");
return XST_FAILURE;
}
/* Connect the device driver handler that will be called when an
* interrupt for the device occurs, the handler defined
* above performs the specific interrupt processing for the device.
* */
#ifdef DP_RX_EN
Status = XScuGic_Connect(IntcInstPtr, XINTC_DPRXSS_DP_INTERRUPT_ID, (Xil_InterruptHandler)XDpRxSs_DpIntrHandler,&DpRxSsInst);
if (Status != XST_SUCCESS) {
xil_printf("ERR: DP RX SS DP interrupt connect failed!\n\r");
return XST_FAILURE;
}
/* Enable the interrupt for the DP device */
XScuGic_Enable(IntcInstPtr, XINTC_DPRXSS_DP_INTERRUPT_ID);
#endif
/* Connect the device driver handler that will be called when an
* interrupt for the device occurs, the handler defined above performs
* the specific interrupt processing for the device
*/
Status = XScuGic_Connect(IntcInstPtr, XINTC_DPTXSS_DP_INTERRUPT_ID, (Xil_InterruptHandler)XDpTxSs_DpIntrHandler,&DpTxSsInst);
if (Status != XST_SUCCESS) {
xil_printf("ERR: DP TX SS DP interrupt connect failed!\r\n");
return XST_FAILURE;
}
/* Enable the interrupt */
XScuGic_Enable(IntcInstPtr, XINTC_DPTXSS_DP_INTERRUPT_ID);
/* Initialize the exception table. */
Xil_ExceptionInit();
/* Register the interrupt controller handler with the exception
* table.*/
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XINTC_HANDLER,IntcInstPtr);
/* Enable exceptions. */
Xil_ExceptionEnable();
return (XST_SUCCESS);
}
DP RX的中断申请:
u32 DpRxSs_SetupIntrSystem(void)
{
// u32 Status;
// XINTC *IntcInstPtr = &IntcInst;
/* Set callbacks for all the interrupts */
XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_DP_PWR_CHG_EVENT, &DpRxSs_PowerChangeHandler, &DpRxSsInst);//2
XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_DP_NO_VID_EVENT, &DpRxSs_NoVideoHandler, &DpRxSsInst); //3
// XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_DP_VM_CHG_EVENT, &DpRxSs_VmChangeHandler, &DpRxSsInst);
XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_DP_VBLANK_EVENT, &DpRxSs_VerticalBlankHandler, &DpRxSsInst);//4
XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_DP_TLOST_EVENT, &DpRxSs_TrainingLostHandler, &DpRxSsInst);//5
XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_DP_VID_EVENT, &DpRxSs_VideoHandler, &DpRxSsInst); //6
XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_DP_TDONE_EVENT, &DpRxSs_TrainingDoneHandler, &DpRxSsInst);//9
XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_UNPLUG_EVENT, &DpRxSs_UnplugHandler, &DpRxSsInst); //17
XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_LINKBW_EVENT, &DpRxSs_LinkBandwidthHandler, &DpRxSsInst);//18
XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_PLL_RESET_EVENT, &DpRxSs_PllResetHandler, &DpRxSsInst); //19
XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_DP_BW_CHG_EVENT, &DpRxSs_BWChangeHandler, &DpRxSsInst); //10
// XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_ACCESS_LINK_QUAL_EVENT, &DpRxSs_AccessLinkQualHandler, &DpRxSsInst);
// XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_ACCESS_ERROR_COUNTER_EVENT,&DpRxSs_AccessErrorCounterHandler, &DpRxSsInst);
// XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_DP_CRC_TEST_EVENT, &DpRxSs_CRCTestEventHandler, &DpRxSsInst);
// XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_DP_INFO_PKT_EVENT, &DpRxSs_InfoPacketHandler, &DpRxSsInst);
// XDpRxSs_SetCallBack(&DpRxSsInst, XDPRXSS_HANDLER_DP_EXT_PKT_EVENT, &DpRxSs_ExtPacketHandler, &DpRxSsInst);
/* Set custom timer wait */
XDpRxSs_SetUserTimerHandler(&DpRxSsInst, &CustomWaitUs, &TmrCtr);
return (XST_SUCCESS);
}
PHY的初始化:
u32 DpSs_PhyInit(u16 DeviceId)
{
XVphy_Config *ConfigPtr;
u32 Status;
/* Obtain the device configuration for the DisplayPort RX Subsystem */
ConfigPtr = XVphy_LookupConfig(DeviceId);
if (!ConfigPtr) {
return XST_FAILURE;
}
XVphy_DpInitialize(&VPhyInst, ConfigPtr, 0,
ONBOARD_REF_CLK,
ONBOARD_REF_CLK,
XVPHY_PLL_TYPE_QPLL1,
XVPHY_PLL_TYPE_CPLL,
DP_LINK_RATE);
//set the default vswing and pe for v0po
PLLRefClkSel (&VPhyInst, DP_LINK_RATE);
#if 1
//setting vswing
XVphy_SetTxVoltageSwing(&VPhyInst, 0, XVPHY_CHANNEL_ID_CH1, XVPHY_GTHE4_DIFF_SWING_DP_V0P0);
XVphy_SetTxVoltageSwing(&VPhyInst, 0, XVPHY_CHANNEL_ID_CH2, XVPHY_GTHE4_DIFF_SWING_DP_V0P0);
XVphy_SetTxVoltageSwing(&VPhyInst, 0, XVPHY_CHANNEL_ID_CH3, XVPHY_GTHE4_DIFF_SWING_DP_V0P0);
XVphy_SetTxVoltageSwing(&VPhyInst, 0, XVPHY_CHANNEL_ID_CH4, XVPHY_GTHE4_DIFF_SWING_DP_V0P0);
//setting postcursor
XVphy_SetTxPostCursor(&VPhyInst, 0, XVPHY_CHANNEL_ID_CH1, XVPHY_GTHE4_PREEMP_DP_L0);
XVphy_SetTxPostCursor(&VPhyInst, 0, XVPHY_CHANNEL_ID_CH2, XVPHY_GTHE4_PREEMP_DP_L0);
XVphy_SetTxPostCursor(&VPhyInst, 0, XVPHY_CHANNEL_ID_CH3, XVPHY_GTHE4_PREEMP_DP_L0);
XVphy_SetTxPostCursor(&VPhyInst, 0, XVPHY_CHANNEL_ID_CH4, XVPHY_GTHE4_PREEMP_DP_L0);
#endif
PHY_Two_byte_set (&VPhyInst, SET_RX_TO_2BYTE, SET_TX_TO_2BYTE);//SET_TX_TO_2BYTE
XVphy_ResetGtPll(&VPhyInst, 0, XVPHY_CHANNEL_ID_CHA, XVPHY_DIR_TX,(TRUE));
XVphy_BufgGtReset(&VPhyInst, XVPHY_DIR_TX,(TRUE));
XVphy_ResetGtPll(&VPhyInst, 0, XVPHY_CHANNEL_ID_CHA, XVPHY_DIR_TX,(FALSE));
XVphy_BufgGtReset(&VPhyInst, XVPHY_DIR_TX,(FALSE));
XVphy_ResetGtPll(&VPhyInst, 0, XVPHY_CHANNEL_ID_CHA, XVPHY_DIR_RX,(TRUE));
XVphy_BufgGtReset(&VPhyInst, XVPHY_DIR_RX,(TRUE));
XVphy_ResetGtPll(&VPhyInst, 0, XVPHY_CHANNEL_ID_CHA, XVPHY_DIR_RX,(FALSE));
XVphy_BufgGtReset(&VPhyInst, XVPHY_DIR_RX,(FALSE));
xil_printf("DpSs_PhyInit end .\n\r");
Status = XVphy_ReadReg(XVPHY_BASEADDR, XVPHY_RX_INIT_STATUS_REG);
xil_printf("\n DpSs_PhyInit rx initialization Status 0x28 data = %x \n\r",Status);
Status = XVphy_ReadReg(XVPHY_BASEADDR, XVPHY_PLL_LOCK_STATUS_REG);
xil_printf("\n DpSs_PhyInit rx initialization Status 0x18 data = %x \n\r",Status);
return XST_SUCCESS;
}
PHY的速率设置:
u32 config_phy(int LineRate_init_tx){
u32 Status=0;
// u8 linerate;
// u32 dptx_sts = 0;
switch(LineRate_init_tx){
case XDP_LINK_BW_SET_162GBPS:
Status = PHY_Configuration(&VPhyInst,PHY_User_Config_Table[(is_TX_CPLL) ? 0 : 3]);
break;
case XDP_LINK_BW_SET_270GBPS:
Status = PHY_Configuration(&VPhyInst,PHY_User_Config_Table[(is_TX_CPLL) ? 1 : 4]);
break;
case XDP_LINK_BW_SET_540GBPS:
Status = PHY_Configuration(&VPhyInst,PHY_User_Config_Table[(is_TX_CPLL) ? 2 : 5]);
break;
case XDP_LINK_BW_SET_810GBPS:
Status = PHY_Configuration(&VPhyInst,PHY_User_Config_Table[(is_TX_CPLL) ? 9 : 10]);
break;
}
xil_printf ("config_phy LineRate_init_tx = %x \r\n",LineRate_init_tx);
if (Status != XST_SUCCESS) {
xil_printf ("++++++++++ TX GT configuration encountered a failure +++++++\r\n");
}
return Status;
}
u32 PHY_Configuration(XVphy *InstancePtr,XVphy_User_Config PHY_User_Config_Table)
{
XVphy_PllRefClkSelType QpllRefClkSel;
XVphy_PllRefClkSelType CpllRefClkSel;
XVphy_PllType TxPllSelect;
XVphy_PllType RxPllSelect;
XVphy_ChannelId TxChId;
XVphy_ChannelId RxChId;
u8 QuadId = 0;
u32 Status = XST_FAILURE;
u32 retries = 0;
QpllRefClkSel = PHY_User_Config_Table.QPLLRefClkSrc;
CpllRefClkSel = PHY_User_Config_Table.CPLLRefClkSrc;
TxPllSelect = PHY_User_Config_Table.TxPLL;
RxPllSelect = PHY_User_Config_Table.RxPLL;
TxChId = PHY_User_Config_Table.TxChId;
RxChId = PHY_User_Config_Table.RxChId;
//Set the Ref Clock Frequency
XVphy_CfgQuadRefClkFreq(InstancePtr, QuadId, QpllRefClkSel, PHY_User_Config_Table.QPLLRefClkFreqHz);
XVphy_CfgQuadRefClkFreq(InstancePtr, QuadId, CpllRefClkSel, PHY_User_Config_Table.CPLLRefClkFreqHz);
XVphy_CfgLineRate(InstancePtr, QuadId, TxChId, PHY_User_Config_Table.LineRateHz);
// XVphy_CfgLineRate(InstancePtr, QuadId, RxChId, PHY_User_Config_Table.LineRateHz);
// Initialize GT with ref clock and PLL selects
XVphy_PllInitialize(InstancePtr, QuadId, TxChId,QpllRefClkSel, CpllRefClkSel,TxPllSelect, RxPllSelect);
while (Status != XST_SUCCESS) {
Status = XVphy_ClkInitialize(InstancePtr, QuadId, TxChId, XVPHY_DIR_TX);
if (retries > 100) {
retries = 0;
xil_printf ("exhausted\r\n");
break;
}
retries++;
}
// Initialize GT with ref clock and PLL selects
Status = XVphy_ClkInitialize(InstancePtr, QuadId, RxChId, XVPHY_DIR_RX);
XVphy_WriteReg(InstancePtr->Config.BaseAddr,XVPHY_PLL_RESET_REG,(XVPHY_PLL_RESET_CPLL_MASK | XVPHY_PLL_RESET_QPLL1_MASK)); // 0x06
XVphy_WriteReg(InstancePtr->Config.BaseAddr,XVPHY_PLL_RESET_REG, 0x0);
// XVphy_ResetGtPll(InstancePtr, QuadId, RxChId, XVPHY_DIR_RX,(TRUE));
// XVphy_ResetGtPll(InstancePtr, QuadId, RxChId, XVPHY_DIR_RX,(FALSE));
XVphy_ResetGtPll(InstancePtr, QuadId,XVPHY_CHANNEL_ID_CHA, XVPHY_DIR_TX,(FALSE));
// Status = XVphy_WaitForResetDone(&VPhyInst, 0, XVPHY_CHANNEL_ID_CHA, XVPHY_DIR_RX);
// xil_printf("\n step_phy XVphy_WaitForResetDone Status = %x \n\r",Status);
// Status = XVphy_WaitForPllLock(&VPhyInst, 0, XVPHY_CHANNEL_ID_CHA);
// xil_printf("\n step_phy XVphy_WaitForPllLock Status = %x \n\r",Status);
Status = XVphy_WaitForPmaResetDone(InstancePtr, QuadId, TxChId, XVPHY_DIR_TX);
Status += XVphy_WaitForPllLock(InstancePtr, QuadId, TxChId);
Status += XVphy_WaitForResetDone(InstancePtr, QuadId,TxChId, XVPHY_DIR_TX);
if (Status != XST_SUCCESS) {
xil_printf ("++++TX GT config encountered error++++\r\n");
}
return Status;
}
DP RX速率,lane的数目设置:
u32 DPRx_step(void)
{
u32 Status;
u32 tmp_rd;
/* Set Link rate and lane count to maximum */
XDpRxSs_SetLinkRate(&DpRxSsInst, DP_LINK_RATE);
XDpRxSs_SetLaneCount(&DpRxSsInst, DP_LANE_COUNT);
/* Start DPRX Subsystem set */
Status = XDpRxSs_Start(&DpRxSsInst);
if (Status != XST_SUCCESS) {
xil_printf("ERR:DPRX SS start failed\n\r");
return XST_FAILURE;
}
xil_printf("\r\n DPRx_step done.\n\r");
tmp_rd = XDp_ReadReg(DpRxSsInst.DpPtr->Config.BaseAddr, 0x4);
tmp_rd |= tmp_rd | 0x06000000;
XDp_WriteReg(DpRxSsInst.DpPtr->Config.BaseAddr, 0x4, tmp_rd);
return (XST_SUCCESS);
}
DP RX 的开始training函数:
u32 DpRxSs_Setup(void)
{
u32 ReadVal;
u32 Status;
/*Disable Rx*/
XDp_WriteReg(DpRxSsInst.DpPtr->Config.BaseAddr, XDP_RX_LINK_ENABLE, 0x0);//hpd 拉低
/*Setting BS Idle timeout value to long value*/
XDp_WriteReg(DpRxSsInst.DpPtr->Config.BaseAddr, XDP_RX_BS_IDLE_TIME, 0x047868C0);//这个参数,在某些应用上要适当的更改。
/* Load Custom EDID */
LoadEDID();
// XDp_WriteReg(DpRxSsInst.DpPtr->Config.BaseAddr, XDP_RX_INTERRUPT_MASK, 0xFFF87FFD);
/*Disable All Interrupts*/
// XDp_RxInterruptDisable(DpRxSsInst.DpPtr, 0xFFFFFFFF);
xil_printf("RX Link & Lane Capability is set to %x, %x\r\n",
(XDp_ReadReg(DpRxSsInst.DpPtr->Config.BaseAddr ,XDP_RX_DPCD_LINK_BW_SET)),
(XDp_ReadReg(DpRxSsInst.DpPtr->Config.BaseAddr, XDP_RX_DPCD_LANE_COUNT_SET)));
/*Enable Training related interrupts*/
XDp_RxInterruptEnable(DpRxSsInst.DpPtr,
XDP_RX_INTERRUPT_MASK_TP1_MASK|XDP_RX_INTERRUPT_MASK_TP2_MASK|
XDP_RX_INTERRUPT_MASK_TP3_MASK|
XDP_RX_INTERRUPT_MASK_POWER_STATE_MASK|
XDP_RX_INTERRUPT_MASK_BW_CHANGE_MASK);
/* Setting AUX Defer Count of Link Status Reads to 8 during Link Training
* 8 Defer counts is chosen to handle worst case time interrupt service
* load (PL system working at 100 MHz) when working with R5
* */
ReadVal = XDp_ReadReg(DpRxSsInst.DpPtr->Config.BaseAddr,XDP_RX_AUX_CLK_DIVIDER);
ReadVal |= ReadVal | (AUX_DEFER_COUNT<<24);
XDp_WriteReg(DpRxSsInst.DpPtr->Config.BaseAddr, XDP_RX_AUX_CLK_DIVIDER, ReadVal);
//-------------------------------------------------------------------------------------------------------------------
Status = XVphy_WaitForResetDone(&VPhyInst, 0, XVPHY_CHANNEL_ID_CHA, XVPHY_DIR_RX);
Status = XVphy_WaitForPllLock(&VPhyInst, 0, XVPHY_CHANNEL_ID_CHA);
xil_printf("\n step_dp_rx XVphy_WaitForPllLock Status = %x \n\r",Status);
xil_printf("\r\n addr =%x XDP_RX_PHY_STATUS = %x \r\n",XDP_RX_PHY_STATUS,XDp_ReadReg(XDPRXSS_BASEADDR, XDP_RX_PHY_STATUS));
XScuGic_Enable(&IntcInst, XINTC_DPRXSS_DP_INTERRUPT_ID);
//resetting AUX logic. Needed for some Type C based connectors
XDp_WriteReg(DpRxSsInst.DpPtr->Config.BaseAddr, 0x1C, 0x80);
XDp_WriteReg(DpRxSsInst.DpPtr->Config.BaseAddr, 0x1C, 0x0);
//********************************************
if(LINK_TRAINING_DEBUG)
{
/*Updating Vswing Iteration Count*/
RxTrainConfig.ChEqOption = 1;
RxTrainConfig.ClockRecoveryOption = 2;
RxTrainConfig.Itr1Premp = 0;
RxTrainConfig.Itr2Premp = 0;
RxTrainConfig.Itr3Premp = 0;
RxTrainConfig.Itr4Premp = 0;
RxTrainConfig.Itr5Premp = 0;
RxTrainConfig.MinVoltageSwing = 1;
RxTrainConfig.SetPreemp = 1;
RxTrainConfig.SetVswing = 0;
RxTrainConfig.VswingLoopCount = 3;
XDp_WriteReg(DpRxSsInst.DpPtr->Config.BaseAddr, XDP_RX_MIN_VOLTAGE_SWING,
RxTrainConfig.MinVoltageSwing |
(RxTrainConfig.ClockRecoveryOption << 2) |
(RxTrainConfig.VswingLoopCount << 4) |
(RxTrainConfig.SetVswing << 8) |
(RxTrainConfig.ChEqOption << 10) |
(RxTrainConfig.SetPreemp << 12) |
(RxTrainConfig.Itr1Premp << 14) |
(RxTrainConfig.Itr2Premp << 16) |
(RxTrainConfig.Itr3Premp << 18) |
(RxTrainConfig.Itr4Premp << 20) |
(RxTrainConfig.Itr5Premp << 22)
);
}
XDp_WriteReg(DpRxSsInst.DpPtr->Config.BaseAddr, XDP_RX_LINK_ENABLE, 0x1);//此时HPD会拉高,开始training
xil_printf("\r\n DpRxSs_Setup done.\n\r");
return XST_SUCCESS;
}
DP RX中断说明:
void DpRxSs_VerticalBlankHandler(void *InstancePtr) //检测到v_blank,当检测到200个就表示接收到视频
{
// xil_printf("\r\n 4 \r\n");
DpRxSsInst.VBlankCount++;
dp_rx_ok =0;
video_cnt =0;
if(DpRxSsInst.VBlankCount==200){
XDp_RxInterruptDisable(DpRxSsInst.DpPtr, XDP_RX_INTERRUPT_MASK_VBLANK_MASK);
DpRxSsInst.VBlankCount=0;
XDp_RxDtgDis(DpRxSsInst.DpPtr);
XDp_RxDtgEn(DpRxSsInst.DpPtr);
XDp_RxSetLineReset(DpRxSsInst.DpPtr,1);
XDp_RxSetUserPixelWidth(DpRxSsInst.DpPtr,0x04);
xil_printf("\r\n 4 VBlankCount=200 \r\n");
video_flag = 1;
}
else if(DpRxSsInst.VBlankCount==80)
{
video_flag =0;
xil_printf("\r\n 4 :VBlankCount= 80 \r\n");
}
else if(DpRxSsInst.VBlankCount==20)
{
video_flag =0;
xil_printf("\r\n 4 :VBlankCount= 20 \r\n");
XDp_RxInterruptEnable(DpRxSsInst.DpPtr,0x80000000);
}
}
void DpRxSs_TrainingLostHandler(void *InstancePtr)
{
xil_printf("\r\n 5 \r\n");
XDp_RxGenerateHpdInterrupt(DpRxSsInst.DpPtr, 750);
XDpRxSs_AudioDisable(&DpRxSsInst);
sink_power_down(); // close dp tx
vdma_stop(); // close vdma write
video_flag =0;
dp_rx_ok=0;
dp_rx_lost=1;
}
void DpRxSs_VideoHandler(void *InstancePtr) //此中断,在检测到不同的msa会进入此中断,如果一直在进入此中断,表示training ok,但是msa的数据异常,且在变化
{
xil_printf("\r\n 6 \r\n");
video_cnt++;
if((video_cnt==1)|(video_cnt==2))
dp_rx_ok = 1;
else
dp_rx_ok =0;
if(video_cnt==8)
{
// XDp_RxGenerateHpdInterrupt(DpRxSsInst.DpPtr, 750);
XDp_WriteReg(DpRxSsInst.DpPtr->Config.BaseAddr, XDP_RX_LINK_ENABLE, 0x0);
usleep(250000);
XDp_WriteReg(DpRxSsInst.DpPtr->Config.BaseAddr, XDP_RX_LINK_ENABLE, 0x1);
}
if(0)//video_flag
{
xil_printf("\r\n 6 \r\n");
dp_rx_ok =1;
}
}
void DpRxSs_UnplugHandler(void *InstancePtr)
{
xil_printf("\r\n 17 \r\n");
video_flag =0;
/*Enable Training related interrupts*/
XDp_RxInterruptDisable(DpRxSsInst.DpPtr, XDP_RX_INTERRUPT_MASK_ALL_MASK);
// XDp_WriteReg(DpRxSsInst.DpPtr->Config.BaseAddr, XDP_RX_LINK_ENABLE, 0x0);
XDp_RxInterruptEnable(DpRxSsInst.DpPtr,
XDP_RX_INTERRUPT_MASK_TP1_MASK |
XDP_RX_INTERRUPT_MASK_TP2_MASK |
XDP_RX_INTERRUPT_MASK_TP3_MASK|
XDP_RX_INTERRUPT_MASK_POWER_STATE_MASK|
XDP_RX_INTERRUPT_MASK_CRC_TEST_MASK|
XDP_RX_INTERRUPT_MASK_BW_CHANGE_MASK);
XDp_RxGenerateHpdInterrupt(DpRxSsInst.DpPtr, 5000);
}
void DpRxSs_LinkBandwidthHandler(void *InstancePtr) // 根据 tx发送的 速率,进行更改phy的速率
{
u32 Status;
// xil_printf("\r\n 18 \r\n");
/*Program Video PHY to requested line rate*/
PLLRefClkSel (&VPhyInst, DpRxSsInst.UsrOpt.LinkRate);
XVphy_ResetGtPll(&VPhyInst, 0, XVPHY_CHANNEL_ID_CHA,XVPHY_DIR_RX,(TRUE));
XVphy_PllInitialize(&VPhyInst, 0, XVPHY_CHANNEL_ID_CHA, ONBOARD_REF_CLK, ONBOARD_REF_CLK,XVPHY_PLL_TYPE_QPLL1, XVPHY_PLL_TYPE_CPLL);
Status = XVphy_ClkInitialize(&VPhyInst, 0, XVPHY_CHANNEL_ID_CHA, XVPHY_DIR_RX);
if(Status != XST_SUCCESS)
xil_printf("XVphy_ClkInitialize failed\r\n");
}
void DpRxSs_PllResetHandler(void *InstancePtr) //在phy的速率更改后,重新复位。
{
// xil_printf("\r\n 19 \r\n");
// u32 ReadVal;
/* Issue resets to Video PHY - This API
* called after line rate is programmed */
XVphy_BufgGtReset(&VPhyInst, XVPHY_DIR_RX,(TRUE));
XVphy_ResetGtPll(&VPhyInst, 0, XVPHY_CHANNEL_ID_CHA, XVPHY_DIR_RX,(TRUE));
XVphy_ResetGtPll(&VPhyInst, 0, XVPHY_CHANNEL_ID_CHA, XVPHY_DIR_RX, (FALSE));
XVphy_BufgGtReset(&VPhyInst, XVPHY_DIR_RX,(FALSE));
XVphy_WaitForResetDone(&VPhyInst, 0, XVPHY_CHANNEL_ID_CHA, XVPHY_DIR_RX);
XVphy_WaitForPllLock(&VPhyInst, 0, XVPHY_CHANNEL_ID_CHA);
/*Enable all interrupts */
XDp_RxInterruptEnable(DpRxSsInst.DpPtr, XDP_RX_INTERRUPT_MASK_ALL_MASK);
}
我正在处理旧代码的一部分。beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)endRubocop错误如下:Avoidstubbingusing'allow_any_instance_of'我读到了RuboCop::RSpec:AnyInstance我试着像下面那样改变它。由此beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)end对此:let(:sport_
我有一个非常简单的RubyRack服务器,例如:app=Proc.newdo|env|req=Rack::Request.new(env).paramspreq.inspect[200,{'Content-Type'=>'text/plain'},['Somebody']]endRack::Handler::Thin.run(app,:Port=>4001,:threaded=>true)每当我使用JSON对象向服务器发送POSTHTTP请求时:{"session":{"accountId":String,"callId":String,"from":Object,"headers":
SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手
我很难理解Ruby中sender和receiver的实际含义。它们一般是什么意思?到目前为止,我只是将它们理解为方法调用和获取其返回值的调用。但是,我知道我的理解还远远不够。谁能给我一个Ruby中发送者和接收者的具体解释? 最佳答案 面向对象中的一个核心概念是消息传递和早期概念化,这在很大程度上借鉴了计算的Actor模型。艾伦·凯(AlanKay)创造了面向对象一词并发明了最早的OO语言之一SmallTalk,他拥有voicedregretatusingatermwhichputthefocusonobjectsinsteadofo
我有一个或多或少这样的场景classAdefinitialize(&block)b=B.new(&block)endend我正在对A类进行单元测试,我想知道B#new是否正在接收传递给A#new的block。我使用Mocha作为模拟框架。这可能吗? 最佳答案 我用Mocha和RSpec都试过了,虽然我可以通过测试,但行为不正确。从我的实验中,我得出结论,验证block是否已通过是不可能的。问题:为什么要传递一个block作为参数?block将用于什么目的?什么时候调用?也许这确实是您应该用类似的东西测试的行为:classBlockP
我刚刚升级到Rails5。在我的规范中,我有以下内容期望(模型).toreceive(:update).with(foo:'bar')但是,由于params不再扩展Hash而现在是ActionController::Parameters规范失败了,因为with()期待一个散列,但它实际上是ActionController::Parameters是否有更好的方法在Rspec中做同样的事情,例如不同的方法with_hash?我可以使用解决这个问题expect(model).toreceive(:update).with(hash_including(foo:'bar'))但这只是检查参数是
在Ruby中,我的理解是self是任何裸方法调用的隐含接收者。然而:~:irb>>puts"foo"foo=>nil>>self.puts"foo"NoMethodError:privatemethod`puts'calledformain:Object这是什么原因?如果有任何帮助:>>method(:puts).owner=>Kernel 最佳答案 私有(private)方法不能有接收者我认为答案是这样的:Ruby强制方法隐私的方式是它不允许使用显式接收者调用私有(private)方法。一个例子:classBakerdefbake
我有一个Rails应用程序,可以在某些事件上触发电子邮件。这些电子邮件被发送到一个单独的公司,该公司将在回复时向电子邮件添加一些额外的数据。这一切都已理解并有效,我正在解析回复、提取数据并且一切正常。我现在被要求加密电子邮件。有没有人对执行此操作的最佳方法有任何经验/想法?我无法保证第3方将使用哪种电子邮件客户端,因此我需要一个可以在许多电子邮件客户端中通用的解决方案。加密必须在我发送电子邮件时由我的应用程序进行,在回复时由客户端应用程序(Outlook、Thunderbird、Entourage等)进行。然后我需要接收加密的电子邮件,对其进行解密和解析以提取我需要的新信息。谁能指出可
给定这样的代码:p=procdo|*args,&block|pselfpargspblock[]ifblockendq=procdo|*args,&block|p'before'instance_exec(*args,&p)endo=Object.newo.define_singleton_method(:my_meth,q)o.my_meth(1,2){3}如何在保留q的接收者的同时将调用从p完全转发到q?基本上我也想打印3,但是instance_exec和所有ruby方法一样,只能占用一个block。是否可以在不更改p的情况下,让我可以互换使用p和q(我的想法是让q有时包装p)
假设我有方法#sum,它接受一个数组并计算所有元素的总和。我正在stub:beforedoexpect(calculation_service).toreceive(:sum?).with([1,2,3]){6}end不幸的是,我的测试服以随机顺序传递数组。由于引发了该错误:Failure/Error:subject{do_crazy_stuff!}#received:sum?withunexpectedargumentsexpected:([1,2,3])got:([3,2,1])是否可以忽略数组元素的顺序对方法调用进行stub?array_including(1,2,3)无法确保数