858 lines
30 KiB
C
858 lines
30 KiB
C
/*****************************************************************************/
|
|
/**
|
|
* 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 <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
// 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
|
|
};
|
|
|
|
// static L2_CONFIG linkConfig = {
|
|
// .myType = L2_NODE_MEMBER,
|
|
// .clustId = 1,
|
|
// .myId = 2,
|
|
// .headId = 1,
|
|
// .bkpHeadId = 0,
|
|
// .netScale = 2,
|
|
// .phyInstPtr = NULL, // pyhsical 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
|
|
};
|
|
|
|
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))
|
|
{
|
|
// Update log
|
|
Phy_UpdateHwSate(phyInstPtr);
|
|
XScuTimer_ClearInterruptStatus((XScuTimer *)xdesc->instance);
|
|
}
|
|
else
|
|
{
|
|
DBG_WARNING("UNEXPECTED CALL of ScuTimer_IntrHandler\n");
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
* @brief Hardware_SwitchFreq
|
|
*
|
|
* @param dev
|
|
* @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(200);
|
|
Status = SystemBus_MakeResp(sysbusDescPtr);
|
|
if (Status != SUCCESS)
|
|
{
|
|
DBG_ERROR("SystemBus_HandleCmd exit with ErrorCode: %" PRId32 ".\n", Status);
|
|
}
|
|
}
|
|
}
|
|
} // main
|