/*****************************************************************************/ /** * Description: main.c * * Date: 2023-05-07 13:19 * Last Edit Time: [2023-05-07 20:32] * * Revisions: Rev 0.0 * History: * [2023-05-07]: Initial edition. * * Copyright(c) 2021 Beijing Institute of Technology. * ******************************************************************************/ /***************************** Include Files *********************************/ // Standard #include #include #include // Xilinx #include "sleep.h" #include "xil_cache.h" #include "xscugic.h" #include "xscutimer.h" #include "xgpiops.h" #include "drivers/platform/xilinx_irq.h" #include "drivers/platform/xilinx_timer.h" #include "drivers/rf-transceiver/ad9361/ad9361_api.h" #include "drivers/axi_core/spi_engine/spi_engine.h" // App #include "common.h" #include "error.h" #include "timer.h" #include "config/app_config.h" #include "dev_profile/dev_profile.h" #include "systembus/systembus.h" #include "networking/phy_layer/phy_layer.h" #include "networking/link_layer/link_layer.h" /************************** Function Prototypes ******************************/ int32_t SetupInterruptSystem(struct irq_ctrl_desc *descPtr); void Phy_IntrHandler(void *context); void PeriodicPull_Handler(void *callBackRef); void ScuTimer_IntrHandler(void *context); void Systembus_RxIntrHandler(void *context); void Systembus_TxIntrHandler(void *context); /************************** Constant Definitions *****************************/ struct callback_desc phy_callback_desc = { .callback = Phy_IntrHandler, .ctx = NULL }; struct callback_desc periodicpull_callback_desc = { .callback = PeriodicPull_Handler, .ctx = NULL }; struct callback_desc sysbus_rx_callback_desc = { .callback = Systembus_RxIntrHandler, .ctx = NULL }; struct callback_desc sysbus_tx_callback_desc = { .callback = Systembus_TxIntrHandler, .ctx = NULL }; struct callback_desc scutm_callback_desc = { .callback = ScuTimer_IntrHandler, .ctx = NULL }; L2_CONFIG linkConfig = { .myType = L2_NODE_HEAD, .clustId = 1, .myId = 1, .headId = 1, .bkpHeadId = 0, .netScale = 2, .phyInstPtr = NULL, // physical layer reference .tmcInstPtr = NULL }; // L2_CONFIG linkConfig = { // .myType = L2_NODE_MEMBER, // .clustId = 1, // .myId = 2, // .headId = 1, // .bkpHeadId = 0, // .netScale = 2, // .phyInstPtr = NULL, // physical layer reference // .tmcInstPtr = NULL // }; static PHY_CONFIG phyConfig = { .devId = 0, .baseAddr = PHY_BASEADDR, .antBramId = PHY_ANTCONFIG_BRAM_DEVICE_ID, .txBramId = PHY_TXBUFF_BRAM_DEVICE_ID, .rxBramId = PHY_RXBUFF_BRAM_DEVICE_ID, .hwXadcId = PHY_HW_XADC_DEVICE_ID, .get_clk_state = NULL, .get_ad_lock_state = NULL, .get_ad0_temp = NULL, .get_ad1_temp = NULL }; TMC_CONFIG tmcConfig = { .baseAddr = TIME_CONTROLLER_BASEADDR, .reset = 10 }; static SYSBUS_CONFIG sysbusConfig = { .baseAddr = SYSBUS_BASE_ADDR, .txQueueMax = 16, .rxQueueMax = 16 }; /*********************** Driver Instance Definitions **************************/ static struct irq_ctrl_desc *intcDescPtr; // General interrupt controller descriptor static struct timer_desc *logTmPtr; static SYSBUS *sysbusDescPtr; static PHY_INST *phyInstPtr; static TMC_INST *tmcInstPtr = NULL; L2_INST *linkInstPtr; static struct hmc7044_dev *hmc7044_inst; static struct ad9361_reg_dev *ad9361_1_reg_inst; static struct ad9361_reg_dev *ad9361_2_reg_inst; // static struct ad9361_rf_phy *ad9361_phy; // static struct ad9361_rf_phy *ad9361_2_phy; /****************************************************************************/ /** * This function is responsible for initializing the SCUGIC instance, looking * for the device configuration based on the unique device ID, initializing a * SCUGIC instance, and initialize the interrupt at IRQ_F2P[0:0] * * @param intcDesc A pointer to INTC descriptor * * @return SUCCESS if initialize successful. * FAILURE if initialization failed. * *****************************************************************************/ int32_t SetupInterruptSystem(struct irq_ctrl_desc *descPtr) { int32_t Status; struct xil_irq_desc *xil_dev; Status = irq_ctrl_init(&descPtr, &intc_init_param); if (Status != SUCCESS) { DBG_ERROR("Intc Init FAILED, ErrorCode: %" PRId32 ".\n", Status); return Status; } xil_dev = (struct xil_irq_desc *)(descPtr->extra); // Clear any pending interrupt flags uint32_t intrState = XScuGic_CPUReadReg((XScuGic *)(xil_dev->instance), XSCUGIC_INT_ACK_OFFSET); XScuGic_CPUWriteReg((XScuGic *)(xil_dev->instance), XSCUGIC_EOI_OFFSET, intrState); /* Initialize physical layer interrupt. */ Status = irq_trigger_level_set(descPtr, PHY_INTR_ID, IRQ_EDGE_RISING); if (Status != SUCCESS) { DBG_ERROR("PHY_INTR trigger level set FAILED, ErrorCode: %" PRId32 ".\n", Status); return Status; } // Set highest interrupt priority Status = irq_set_priority(descPtr, PHY_INTR_ID, 0x08); if (Status != SUCCESS) { DBG_ERROR("PHY_INTR priority level set FAILED, ErrorCode: %" PRId32 ".\n", Status); return Status; } // Connect the interrupt service routine isr1 to the interrupt controller Status = irq_register_callback(descPtr, PHY_INTR_ID, &phy_callback_desc); if (Status != SUCCESS) { DBG_ERROR("PHY_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status); return Status; } /* Initialize linklayer layer interrupt. */ Status = irq_trigger_level_set(descPtr, PERIODIC_5MS_INTR_ID, IRQ_EDGE_RISING); if (Status != SUCCESS) { DBG_ERROR("PERIODIC_5MS_INTR_ID trigger level set FAILED, ErrorCode: %" PRId32 ".\n", Status); return Status; } // Set highest interrupt priority Status = irq_set_priority(descPtr, PERIODIC_5MS_INTR_ID, 0x00); if (Status != SUCCESS) { DBG_ERROR("PERIODIC_5MS_INTR_ID priority level set FAILED, ErrorCode: %" PRId32 ".\n", Status); return Status; } // Connect the interrupt service routine isr1 to the interrupt controller Status = irq_register_callback(descPtr, PERIODIC_5MS_INTR_ID, &periodicpull_callback_desc); if (Status != SUCCESS) { DBG_ERROR("PHY_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status); return Status; } /* Initialize system bus interrupt. */ Status = irq_trigger_level_set(descPtr, SYSBUS_TX_INTR_ID, IRQ_EDGE_RISING); if (Status != SUCCESS) { DBG_ERROR("PHY_INTR trigger level set FAILED, ErrorCode: %" PRId32 ".\n", Status); return Status; } // Set interrupt priority Status = irq_set_priority(descPtr, SYSBUS_TX_INTR_ID, 0x10); if (Status != SUCCESS) { DBG_ERROR("PHY_INTR priority level set FAILED, ErrorCode: %" PRId32 ".\n", Status); return Status; } // Connect the interrupt service routine isr1 to the interrupt controller Status = irq_register_callback(descPtr, SYSBUS_TX_INTR_ID, &sysbus_tx_callback_desc); if (Status != SUCCESS) { DBG_ERROR("PHY_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status); return Status; } Status = irq_trigger_level_set(descPtr, SYSBUS_RX_INTR_ID, IRQ_EDGE_RISING); if (Status != SUCCESS) { DBG_ERROR("PHY_INTR trigger level set FAILED, ErrorCode: %" PRId32 ".\n", Status); return Status; } // Set interrupt priority Status = irq_set_priority(descPtr, SYSBUS_RX_INTR_ID, 0x18); if (Status != SUCCESS) { DBG_ERROR("PHY_INTR priority level set FAILED, ErrorCode: %" PRId32 ".\n", Status); return Status; } // Connect the interrupt service routine isr1 to the interrupt controller Status = irq_register_callback(descPtr, SYSBUS_RX_INTR_ID, &sysbus_rx_callback_desc); if (Status != SUCCESS) { DBG_ERROR("PHY_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status); return Status; } /* Initialize Scu timer interrupt. */ // Connect the interrupt service routine isr1 to the interrupt controller Status = irq_register_callback(descPtr, SCUTIMER_INTR_ID, &scutm_callback_desc); if (Status != SUCCESS) { DBG_ERROR("PHY_INTR register callback FAILED, ErrorCode: %" PRId32 ".\n", Status); return Status; } // Enable interrupts irq_enable(descPtr, PHY_INTR_ID); irq_enable(descPtr, PERIODIC_5MS_INTR_ID); irq_enable(descPtr, SYSBUS_RX_INTR_ID); irq_enable(descPtr, SYSBUS_TX_INTR_ID); irq_enable(descPtr, SCUTIMER_INTR_ID); // Enable Exceptions Status = irq_global_enable(descPtr); if (Status != SUCCESS) { DBG_ERROR("IRQ global enable FAILED, ErrorCode: %" PRId32 ".\n", Status); return Status; } return SUCCESS; } // SetupInterruptSystem /****************************************************************************/ /** * This function is a interrupt service routine for IRQ_F2P[1:1], IRQ_F2P[1:1] * tells CPU that the data in OCM is ready! * * @param context * * @return None. * *****************************************************************************/ void Phy_IntrHandler(void *context) { Phy_UpdateState(phyInstPtr); } // PhyIntr_Handler /****************************************************************************/ /** * Handler of periodic 5ms interrupt * * @param callBackRef is the linklayer instance pointer. * * @return None. * *****************************************************************************/ void PeriodicPull_Handler(void *callBackRef) { int32_t Status; Status = Linklayer_Proc(linkInstPtr); if (Status != SUCCESS) { DBG_ERROR("Link layer runs failed, with error code: %" PRId32 "\n", Status); _nop_(); } } // PeriodicPull_Handler /*****************************************************************************/ /** * @brief Handler of System Bus RX done interrupt. * * @param context * * @return None. * ******************************************************************************/ void Systembus_RxIntrHandler(void *context) { int32_t Status; Status = SystemBus_RxIntrHandler(sysbusDescPtr); if (Status != SUCCESS) { DBG_ERROR("SystemBus_RxIntrHandler exit with error code %" PRId32 ",\n", Status); } } /*****************************************************************************/ /** * @brief Handler of System Bus TX done interrupt. * * @param context * * @return None. * ******************************************************************************/ void Systembus_TxIntrHandler(void *context) { int32_t Status; Status = SystemBus_TxIntrHandler(sysbusDescPtr); if (Status != SUCCESS) { DBG_ERROR("SystemBus_TxIntrHandler exit with error code %" PRId32 ",\n", Status); } } /*****************************************************************************/ /** * @brief Handler of ScuTimer interrupt. * * @param context * * @return None. * ******************************************************************************/ void ScuTimer_IntrHandler(void *context) { struct xil_timer_desc *xdesc; xdesc = (struct xil_timer_desc *)(logTmPtr->extra); if (XScuTimer_IsExpired((XScuTimer *)xdesc->instance)) { // Refresh log Phy_RefreshHwSate(phyInstPtr); XScuTimer_ClearInterruptStatus((XScuTimer *)xdesc->instance); } else { DBG_WARNING("UNEXPECTED CALL of ScuTimer_IntrHandler\n"); } } /*****************************************************************************/ /** * @brief Hardware_SwitchFreq * * @param devSysMonitor_UpdateHardwareStatus(newHwState); * @param freq * * @return None. * ******************************************************************************/ int Hardware_SwitchFreq(struct ad9361_reg_dev *dev, ad9361TxFreq freq) { int32_t status = 0; uint8_t value = 0; int32_t time_out_cnt = 0; switch (freq) { case TX_FREQ_125: { //************************************************************ // Setup Tx Frequency-Dependent Syntheisizer Registers //************************************************************ status = ad9361_reg_write(dev, 0x027A, 0x4A); // Set VCO Output level[3:0] status = ad9361_reg_write(dev, 0x0279, 0xC1); // Set Init ALC Value[3:0] and VCO Varactor[3:0] status = ad9361_reg_write(dev, 0x0282, 0x0E); // Set VCO Bias Tcf[1:0] and VCO Bias Ref[2:0] status = ad9361_reg_write(dev, 0x0278, 0x78); // Set VCO Cal Offset[3:0] status = ad9361_reg_write(dev, 0x0285, 0x00); // Set VCO Cal Ref Tcf[2:0] status = ad9361_reg_write(dev, 0x0291, 0x0B); // Set VCO Varactor Reference[3:0] status = ad9361_reg_write(dev, 0x0290, 0x70); // Set VCO Varactor Ref Tcf[2:0] and VCO Varactor Offset[3:0] status = ad9361_reg_write(dev, 0x027B, 0x94); // Set Synth Loop Filter charge pump current (Icp) status = ad9361_reg_write(dev, 0x027E, 0xF4); // Set Synth Loop Filter C2 and C1 status = ad9361_reg_write(dev, 0x027F, 0xDF); // Set Synth Loop Filter R1 and C3 status = ad9361_reg_write(dev, 0x0280, 0x0A); // Set Synth Loop Filter R3 //************************************************************ // Write Tx Frequency Words //************************************************************ status = ad9361_reg_write(dev, 0x0273, 0x00); // Write Tx Synth Fractional Freq Word[7:0] status = ad9361_reg_write(dev, 0x0274, 0x00); // Write Tx Synth Fractional Freq Word[15:8] status = ad9361_reg_write(dev, 0x0275, 0x00); // Write Tx Synth Fractional Freq Word[22:16] status = ad9361_reg_write(dev, 0x0272, 0x00); // Write Tx Synth Integer Freq Word[10:8] status = ad9361_reg_write(dev, 0x0271, 0xA0); // Write Tx Synth Integer Freq Word[7:0] (starts VCO cal) status = ad9361_reg_write(dev, 0x0005, 0x57); // Set LO divider setting //************************************************************ // Tx Quadrature Calibration Settings //************************************************************ status = ad9361_reg_write(dev, 0x00A0, 0x75); // Set TxQuadcal NCO frequency status = ad9361_reg_write(dev, 0x00A3, 0xC0); // Set TxQuadcal NCO frequency (Only update bits [7:6]) status = ad9361_reg_write(dev, 0x00A1, 0x7B); // Tx Quad Cal Configuration, Phase and Gain Cal Enable status = ad9361_reg_write(dev, 0x00A9, 0xFF); // Set Tx Quad Cal Count status = ad9361_reg_write(dev, 0x00A2, 0x7F); // Set Tx Quad Cal Kexp status = ad9361_reg_write(dev, 0x00A5, 0x01); // Set Tx Quad Cal Magnitude Threshhold status = ad9361_reg_write(dev, 0x00A6, 0x01); // Set Tx Quad Cal Magnitude Threshhold status = ad9361_reg_write(dev, 0x00AA, 0x22); // Set Tx Quad Cal Gain Table index status = ad9361_reg_write(dev, 0x00A4, 0xF0); // Set Tx Quad Cal Settle Count status = ad9361_reg_write(dev, 0x00AE, 0x00); // Set Tx Quad Cal LPF Gain index incase Split table mode used status = ad9361_reg_write(dev, 0x0169, 0xC0); // Disable Rx Quadrature Calibration before Running Tx Quadrature Calibration status = ad9361_reg_write(dev, 0x0016, 0x10); // Start Tx Quad cal break; } case TX_FREQ_126: { //************************************************************ // Setup Tx Frequency-Dependent Syntheisizer Registers //************************************************************ status = ad9361_reg_write(dev, 0x027A, 0x4A); // Set VCO Output level[3:0] status = ad9361_reg_write(dev, 0x0279, 0xC1); // Set Init ALC Value[3:0] and VCO Varactor[3:0] status = ad9361_reg_write(dev, 0x0282, 0x0E); // Set VCO Bias Tcf[1:0] and VCO Bias Ref[2:0] status = ad9361_reg_write(dev, 0x0278, 0x78); // Set VCO Cal Offset[3:0] status = ad9361_reg_write(dev, 0x0285, 0x00); // Set VCO Cal Ref Tcf[2:0] status = ad9361_reg_write(dev, 0x0291, 0x0B); // Set VCO Varactor Reference[3:0] status = ad9361_reg_write(dev, 0x0290, 0x70); // Set VCO Varactor Ref Tcf[2:0] and VCO Varactor Offset[3:0] status = ad9361_reg_write(dev, 0x027B, 0x93); // Set Synth Loop Filter charge pump current (Icp) status = ad9361_reg_write(dev, 0x027E, 0xF4); // Set Synth Loop Filter C2 and C1 status = ad9361_reg_write(dev, 0x027F, 0xDF); // Set Synth Loop Filter R1 and C3 status = ad9361_reg_write(dev, 0x0280, 0x0A); // Set Synth Loop Filter R3 //************************************************************ // Write Tx Frequency Words //************************************************************ status = ad9361_reg_write(dev, 0x0273, 0x06); // Write Tx Synth Fractional Freq Word[7:0] status = ad9361_reg_write(dev, 0x0274, 0xD7); // Write Tx Synth Fractional Freq Word[15:8] status = ad9361_reg_write(dev, 0x0275, 0x23); // Write Tx Synth Fractional Freq Word[22:16] status = ad9361_reg_write(dev, 0x0272, 0x00); // Write Tx Synth Integer Freq Word[10:8] status = ad9361_reg_write(dev, 0x0271, 0xA1); // Write Tx Synth Integer Freq Word[7:0] (starts VCO cal) status = ad9361_reg_write(dev, 0x0005, 0x57); // Set LO divider setting //************************************************************ // Tx Quadrature Calibration Settings //************************************************************ status = ad9361_reg_write(dev, 0x00A0, 0x75); // Set TxQuadcal NCO frequency status = ad9361_reg_write(dev, 0x00A3, 0xC0); // Set TxQuadcal NCO frequency (Only update bits [7:6]) status = ad9361_reg_write(dev, 0x00A1, 0x7B); // Tx Quad Cal Configuration, Phase and Gain Cal Enable status = ad9361_reg_write(dev, 0x00A9, 0xFF); // Set Tx Quad Cal Count status = ad9361_reg_write(dev, 0x00A2, 0x7F); // Set Tx Quad Cal Kexp status = ad9361_reg_write(dev, 0x00A5, 0x01); // Set Tx Quad Cal Magnitude Threshhold status = ad9361_reg_write(dev, 0x00A6, 0x01); // Set Tx Quad Cal Magnitude Threshhold status = ad9361_reg_write(dev, 0x00AA, 0x22); // Set Tx Quad Cal Gain Table index status = ad9361_reg_write(dev, 0x00A4, 0xF0); // Set Tx Quad Cal Settle Count status = ad9361_reg_write(dev, 0x00AE, 0x00); // Set Tx Quad Cal LPF Gain index incase Split table mode used status = ad9361_reg_write(dev, 0x0169, 0xC0); // Disable Rx Quadrature Calibration before Running Tx Quadrature Calibration status = ad9361_reg_write(dev, 0x0016, 0x10); // Start Tx Quad cal break; } case TX_FREQ_4125: { //************************************************************ // Setup Tx Frequency-Dependent Syntheisizer Registers //************************************************************ status = ad9361_reg_write(dev, 0x027A, 0x4A); // Set VCO Output level[3:0] status = ad9361_reg_write(dev, 0x0279, 0xC1); // Set Init ALC Value[3:0] and VCO Varactor[3:0] status = ad9361_reg_write(dev, 0x0282, 0x0E); // Set VCO Bias Tcf[1:0] and VCO Bias Ref[2:0] status = ad9361_reg_write(dev, 0x0278, 0x78); // Set VCO Cal Offset[3:0] status = ad9361_reg_write(dev, 0x0285, 0x00); // Set VCO Cal Ref Tcf[2:0] status = ad9361_reg_write(dev, 0x0291, 0x0B); // Set VCO Varactor Reference[3:0] status = ad9361_reg_write(dev, 0x0290, 0x70); // Set VCO Varactor Ref Tcf[2:0] and VCO Varactor Offset[3:0] status = ad9361_reg_write(dev, 0x027B, 0x93); // Set Synth Loop Filter charge pump current (Icp) status = ad9361_reg_write(dev, 0x027E, 0xF4); // Set Synth Loop Filter C2 and C1 status = ad9361_reg_write(dev, 0x027F, 0xDF); // Set Synth Loop Filter R1 and C3 status = ad9361_reg_write(dev, 0x0280, 0x0A); // Set Synth Loop Filter R3 //************************************************************ // Write Rx Frequency Words //************************************************************ status = ad9361_reg_write(dev, 0x0273, 0x00); // Write Tx Synth Fractional Freq Word[7:0] status = ad9361_reg_write(dev, 0x0274, 0x00); // Write Tx Synth Fractional Freq Word[15:8] status = ad9361_reg_write(dev, 0x0275, 0x00); // Write Tx Synth Fractional Freq Word[22:16] status = ad9361_reg_write(dev, 0x0272, 0x00); // Write Tx Synth Integer Freq Word[10:8] status = ad9361_reg_write(dev, 0x0271, 0xA5); // Write Tx Synth Integer Freq Word[7:0] (starts VCO cal) status = ad9361_reg_write(dev, 0x0005, 0x07); // Set LO divider setting //************************************************************ // Tx Quadrature Calibration Settings //************************************************************ status = ad9361_reg_write(dev, 0x00A0, 0x75); // Set TxQuadcal NCO frequency status = ad9361_reg_write(dev, 0x00A3, 0xC0); // Set TxQuadcal NCO frequency (Only update bits [7:6]) status = ad9361_reg_write(dev, 0x00A1, 0x7B); // Tx Quad Cal Configuration, Phase and Gain Cal Enable status = ad9361_reg_write(dev, 0x00A9, 0xFF); // Set Tx Quad Cal Count status = ad9361_reg_write(dev, 0x00A2, 0x7F); // Set Tx Quad Cal Kexp status = ad9361_reg_write(dev, 0x00A5, 0x01); // Set Tx Quad Cal Magnitude Threshhold status = ad9361_reg_write(dev, 0x00A6, 0x01); // Set Tx Quad Cal Magnitude Threshhold status = ad9361_reg_write(dev, 0x00AA, 0x28); // Set Tx Quad Cal Gain Table index status = ad9361_reg_write(dev, 0x00A4, 0xF0); // Set Tx Quad Cal Settle Count status = ad9361_reg_write(dev, 0x00AE, 0x04); // Set Tx Quad Cal LPF Gain index incase Split table mode used status = ad9361_reg_write(dev, 0x0169, 0xC0); // Disable Rx Quadrature Calibration before Running Tx Quadrature Calibration status = ad9361_reg_write(dev, 0x0016, 0x10); // Start Tx Quad cal break; } // Wait for cal to complete (Done when 0x016[4]==0) time_out_cnt = 0; do { status |= ad9361_reg_read(dev, 0x0016, &value); mdelay(1); // Wait 1ms time_out_cnt++; } while ((value & 0x10) != 0x00 && time_out_cnt <= AD9361_TIMEOUT_TH); } return status; } /*****************************************************************************/ /** * @brief Hardware_Init * * @param none. * * @return None. * ******************************************************************************/ int Hardware_Init(void) { int32_t Status; XGpioPs Gpio; XGpioPs_Config *ConfigPtr; ConfigPtr = XGpioPs_LookupConfig(AD9361_GPIO_DEVICE_ID); Status = XGpioPs_CfgInitialize(&Gpio, ConfigPtr, ConfigPtr->BaseAddr); if (Status != SUCCESS) { return FAILURE; } /**********************************************************/ /****************** HMC7044 Configuration *****************/ /**********************************************************/ Status = hmc7044_init(&hmc7044_inst, &hmc7044_default_init_param); if (Status != SUCCESS) { DBG_ERROR("hmc7044_init() error: %" PRId32 "\n", Status); return FAILURE; } /**********************************************************/ /***************** AD9361-1 Configuration *****************/ /**********************************************************/ XGpioPs_SetDirectionPin(&Gpio, AD9361_1_TXNRX, AD9361_GPIO_OUTPUT); XGpioPs_SetDirectionPin(&Gpio, AD9361_1_ENABLE, AD9361_GPIO_OUTPUT); XGpioPs_SetDirectionPin(&Gpio, AD9361_1_EN_AGC, AD9361_GPIO_OUTPUT); XGpioPs_SetDirectionPin(&Gpio, AD9361_1_RESET_B, AD9361_GPIO_OUTPUT); ad9361_reg_init(&ad9361_1_reg_inst, &ad9361_1_reg_default_init_param); XGpioPs_WritePin(&Gpio, AD9361_1_ENABLE, 0); ad9361_reg_config(ad9361_1_reg_inst); XGpioPs_WritePin(&Gpio, AD9361_1_ENABLE, 1); // Status = ad9361_init(&ad9361_phy, &ad9361_default_init_param); // if (Status != XST_SUCCESS){ // return XST_FAILURE; // }else{ // printf("Configurate AD9361 Completely!\n"); // } // ad9361_set_tx_fir_config(ad9361_phy, tx_fir_config); // ad9361_set_rx_fir_config(ad9361_phy, rx_fir_config); /**********************************************************/ /***************** AD9361-2 Configuration *****************/ /**********************************************************/ XGpioPs_SetDirectionPin(&Gpio, AD9361_2_TXNRX, AD9361_GPIO_OUTPUT); XGpioPs_SetDirectionPin(&Gpio, AD9361_2_ENABLE, AD9361_GPIO_OUTPUT); XGpioPs_SetDirectionPin(&Gpio, AD9361_2_EN_AGC, AD9361_GPIO_OUTPUT); XGpioPs_SetDirectionPin(&Gpio, AD9361_2_RESET_B, AD9361_GPIO_OUTPUT); ad9361_reg_init(&ad9361_2_reg_inst, &ad9361_2_reg_default_init_param); XGpioPs_WritePin(&Gpio, AD9361_2_ENABLE, 0); ad9361_reg_config(ad9361_2_reg_inst); XGpioPs_WritePin(&Gpio, AD9361_2_ENABLE, 1); // uint8_t rd_back; // Status = ad9361_reg_read(ad9361_1_reg_inst, 0x0002, &rd_back); // Status = ad9361_reg_read(ad9361_2_reg_inst, 0x0002, &rd_back); /**********************************************************/ /******* AD9361 Baseband Multichip Synchronization ********/ /**********************************************************/ XGpioPs_SetDirectionPin(&Gpio, AD9361_SYNC, AD9361_GPIO_OUTPUT); XGpioPs_SetDirectionPin(&Gpio, AD9361_RX_FIFO_RST, AD9361_GPIO_OUTPUT); // SYNC BBPLL and DIGITAL SAMPLING CLOCKS ad9361_reg_write(ad9361_1_reg_inst, 0x0001, 0x0D); // MCS RF Enable; MCS BBPLL Enable; MCS BB Enable ad9361_reg_write(ad9361_2_reg_inst, 0x0001, 0x0D); ad9361_reg_write(ad9361_1_reg_inst, 0x0047, 0x80); // MCS refclk Scale Enable ad9361_reg_write(ad9361_2_reg_inst, 0x0047, 0x80); XGpioPs_WritePin(&Gpio, AD9361_SYNC, 0); mdelay(20); XGpioPs_WritePin(&Gpio, AD9361_SYNC, 1); // Input a rising-edge pulse to the SYNC_IN pin mdelay(500); XGpioPs_WritePin(&Gpio, AD9361_SYNC, 0); mdelay(2000); ad9361_reg_write(ad9361_1_reg_inst, 0x0001, 0x0B); // MCS RF Enable; MCS Digital CLK Enable ; MCS BB Enable ad9361_reg_write(ad9361_2_reg_inst, 0x0001, 0x0B); XGpioPs_WritePin(&Gpio, AD9361_SYNC, 1); // Input another rising-edge pulse to the SYNC_IN pin mdelay(500); XGpioPs_WritePin(&Gpio, AD9361_SYNC, 0); ad9361_reg_write(ad9361_1_reg_inst, 0x0001, 0x08); // clear MCS bits ad9361_reg_write(ad9361_2_reg_inst, 0x0001, 0x08); XGpioPs_WritePin(&Gpio, AD9361_RX_FIFO_RST, 0); mdelay(20); XGpioPs_WritePin(&Gpio, AD9361_RX_FIFO_RST, 1); mdelay(20); XGpioPs_WritePin(&Gpio, AD9361_RX_FIFO_RST, 0); /**********************************************************/ /********* AD9361 Multichip Rx Phase Calibration **********/ /**********************************************************/ XGpioPs_SetDirectionPin(&Gpio, AD9361_TX_SWITCH, AD9361_GPIO_OUTPUT); XGpioPs_SetDirectionPin(&Gpio, AD9361_1_CAL_START, AD9361_GPIO_OUTPUT); XGpioPs_SetDirectionPin(&Gpio, AD9361_1_CAL_DONE, AD9361_GPIO_INPUT); XGpioPs_SetDirectionPin(&Gpio, AD9361_2_CAL_START, AD9361_GPIO_OUTPUT); XGpioPs_SetDirectionPin(&Gpio, AD9361_2_CAL_DONE, AD9361_GPIO_INPUT); // switch to lower frequency Status = Hardware_SwitchFreq(ad9361_1_reg_inst, TX_FREQ_126); XGpioPs_WritePin(&Gpio, AD9361_TX_SWITCH, 1); mdelay(20); // switch rx channel Status = ad9361_reg_write(ad9361_1_reg_inst, 0x0004, 0x30); Status = ad9361_reg_write(ad9361_2_reg_inst, 0x0004, 0x30); // enable dual ad9361 tx channels Status = ad9361_reg_write(ad9361_1_reg_inst, 0x0002, 0xE4); // Setup Tx Digital Filters/ Channels // switch ad9361 tx channel Status = ad9361_reg_write(ad9361_1_reg_inst, 0x0004, 0x70); // Select Rx input pin(A,B,C)/ Tx out pin (A,B) mdelay(20); // begin to calibrate the 1st ad9361 XGpioPs_WritePin(&Gpio, AD9361_1_CAL_START, 0); XGpioPs_WritePin(&Gpio, AD9361_1_CAL_START, 1); mdelay(1); XGpioPs_WritePin(&Gpio, AD9361_1_CAL_START, 0); // read calibration status int32_t time_out_cnt = 0; do { mdelay(1); // Wait 1ms time_out_cnt++; } while (((XGpioPs_ReadPin(&Gpio, AD9361_1_CAL_DONE) == 0) && time_out_cnt <= AD9361_TIMEOUT_TH)); if (time_out_cnt == AD9361_TIMEOUT_TH) { return FAILURE; } // begin to calibrate the 2nd ad9361 XGpioPs_WritePin(&Gpio, AD9361_2_CAL_START, 1); mdelay(1); XGpioPs_WritePin(&Gpio, AD9361_2_CAL_START, 0); // read calibration status time_out_cnt = 0; do { mdelay(1); // Wait 1ms time_out_cnt++; } while (((XGpioPs_ReadPin(&Gpio, AD9361_2_CAL_DONE) == 0) && time_out_cnt <= AD9361_TIMEOUT_TH)); if (time_out_cnt == AD9361_TIMEOUT_TH) { return FAILURE; } // enable single ad9361 tx channels Status = ad9361_reg_write(ad9361_1_reg_inst, 0x0002, 0xA4); // Setup Tx Digital Filters/ Channels // switch ad9361 tx & rx channel Status = ad9361_reg_write(ad9361_1_reg_inst, 0x0004, 0x03); Status = ad9361_reg_write(ad9361_2_reg_inst, 0x0004, 0x03); // switch to higher frequency Status = Hardware_SwitchFreq(ad9361_1_reg_inst, TX_FREQ_4125); XGpioPs_WritePin(&Gpio, AD9361_TX_SWITCH, 0); DBG_PRINT("Done.\n"); return 0; } /*****************************************************************************/ /** * @brief Main function, initialize all the device needed, initialize * interrupt system, halt in while(1) wait for event interrupt. * * @param none. * * @return * ******************************************************************************/ int main(void) { int32_t Status; DBG_PRINT("Application Version: %2d.%2d.%4d.\n", _APP_VER_MAIN, _APP_VER_MINOR, _APP_VER_PATCH); /* System Monitor Initialize */ Status = SysMonitor_Init(); if (Status == SUCCESS) { DBG_PRINT("System monitor Init SUCCESS! \n"); } else { DBG_PRINT("System monitor Init FAILED! \n"); return Status; } /* Hardware Initialize */ Status = Hardware_Init(); if (Status == SUCCESS) { DBG_PRINT("Hardware Init SUCCESS! \n"); } else { DBG_PRINT("Hardware Init FAILED! \n"); return Status; } /* Time controller Initialize */ Status = TimeCtrl_Init(&tmcInstPtr, &tmcConfig); if (Status == SUCCESS) { DBG_PRINT("TmcCtrl Init SUCCESS! \n"); } else { DBG_PRINT("TmcCtrl Init FAILED! \n"); return Status; } /* Physical Layer Initialize */ Status = Phy_InstInit(&phyInstPtr, &phyConfig); if (Status == SUCCESS) { DBG_PRINT("Physical layer Init SUCCESS! \n"); } else { DBG_PRINT("Physical layer FAILED! \n"); return Status; } /* Link Layer Initialize */ linkConfig.phyInstPtr = phyInstPtr; linkConfig.tmcInstPtr = tmcInstPtr; Status = Linklayer_Init(&linkInstPtr, &linkConfig); if (Status == SUCCESS) { DBG_PRINT("LinkLayer Init SUCCESS! \n"); } else { DBG_PRINT("Linklayer Init FAILED! \n"); return Status; } /* System Bus Initialize */ Status = SystemBus_Init(&sysbusDescPtr, &sysbusConfig); if (Status != SUCCESS) { DBG_ERROR("Systembus init FAILED, with error code: %" PRId32 "\n", Status); return Status; } /* System Monitor log timer Initialize */ Status = timer_init(&logTmPtr, &scutimer_init_param); if (Status != SUCCESS) { DBG_ERROR("SCU Timer init FAILED, with error code: %" PRId32 "\n", Status); return Status; } /* interrupts Initialize */ Status = SetupInterruptSystem(intcDescPtr); if (Status == SUCCESS) { DBG_INFO("Interrupt system setup SUCCESS!\n"); } else { DBG_ERROR("Interrupt system setup FAILED, ErrorCode: %" PRId32 ".\n", Status); return Status; } // Start System Monitor logging. timer_start(logTmPtr); DBG_PRINT("Physical started...\n"); Phy_Start(phyInstPtr); // Linklayer_Start(linkInstPtr); while (true) { // System bus handler if (SystemBus_IsReqPendding(sysbusDescPtr)) { Status = SystemBus_HandleCmd(sysbusDescPtr); if (Status != SUCCESS) { DBG_ERROR("SystemBus_HandleCmd exit with ErrorCode: %" PRId32 ".\n", Status); } } if (SystemBus_IsRsqPendding(sysbusDescPtr) && (!SystemBus_IsTxBusy(sysbusDescPtr))) { // FIXME: Required by 12 (CASC) udelay(4000); Status = SystemBus_MakeResp(sysbusDescPtr); if (Status != SUCCESS) { DBG_ERROR("SystemBus_HandleCmd exit with ErrorCode: %" PRId32 ".\n", Status); } } } } // main