📄 cmx990.c
字号:
static OSTICK lastStatusPrintTick = 0;
/*if (dsrCount > 2) {
CYG_FAIL("More then 2 CMX interrupts are pending!");
}*/
if (cmxIsrOverrun) {
PrintEvent("CMX990: Error interrupt overrun: IRQ is disabled in Mode register", 0, 0);
if (cmxIsrOverrun > 1) {
PrintEvent("CMX990: CMX ISR disabled in AIC", 0, 0);
}
cmxIsrOverrun = 0;
/* Indicate for GUI the mode register value. */
/* It was set in ISR but we set it here again to print the event. */
CMX_Write(CMX_Mode, cmxWriteRegValue[CMX_Mode]);
}
// Run all pending interrupt services.
while (dsrCount > 0) {
dsrCount--;
/* We decrement the ISR counter here. No synchronization protection is used since */
/* the ISR should not run again until the DSR is ready. */
/* If it happens and the count is incremented in the ISR at the same time as we decrement */
/* it here, the problem that can follow will be handled anyway. */
if (--cmxIsrCount < 0) {
cmxIsrCount = 0;
}
status1 = status1Isr[statusIndexDsr];
status2 = status2Isr[statusIndexDsr];
statusIndexDsr = 1 - statusIndexDsr;
if (status2 & CMX_DC_OFFSET) {
PrintEvent("IQ offset ready", 0, 0);
if (cmxWorkingMode == CMX_ModeAquireChannel) {
CMX_WriteCmd(CMX_AQAFC);
// Delay 96 bit times = 12 ms.
OUTPUT32(TC1_RC, (12*(MCK/clockDiv))/1000);
/* Start timer */
OUTPUT32(TC1_CCR, AT91_TC_CCR_TRIG);
/* Enable RC compare interrupt */
OUTPUT32(TC1_IER, AT91_TC_IER_CPC);
continue;
} else {
CYG_FAIL("CMX990: Got IQ offset but not running aquire channel mode.");
}
}
if ((status1 & CMX_BFREE) && expectBFREE) {
/* We have received a BFREE interrupt and we were expecting it. */
expectBFREE = FALSE;
/* Rx or Tx buffer ready */
switch (cmxWorkingMode) {
case CMX_ModeTxPrbs:
break;
case CMX_ModeRxPrbsStart:
/* We have loaded the synch pattern and now we */
/* wait 12 bit periods until we start SFSZ task. */
// Delay 12 bit times = 1.5 ms.
OUTPUT32(TC1_RC, 15*(MCK/clockDiv)/10000);
/* Start timer */
OUTPUT32(TC1_CCR, AT91_TC_CCR_TRIG);
/* Enable RC compare interrupt */
OUTPUT32(TC1_IER, AT91_TC_IER_CPC);
break;
case CMX_ModeRxPrbsSync:
CMX_GetDataBlock(&prbsByte, 1);
CMX_WriteCmd(CMX_RXTASK_RSB);
cmxWorkingMode = CMX_ModeRxPrbs;
CMX_ResetPrbsRx();
prbsRecSeq = 0;
PrintEvent("prbs=sync", 0, 0);
break;
case CMX_ModeRxPrbs:
// Already handled in the ISR.
break;
case CMX_ModeIdle:
// We skip this interrupt.
break;
default:
CYG_FAIL("CMX990: Illegal BFREE");
break;
}
}
/* We need to stop the printouts of status register when they come to tight. */
/* When an interrupt occur less then 40 ms after another we increase a limit variable. */
/* When the limit is more than 3 we don't print the status register. */
if ((lastStatus1 != status1) || (lastStatus2 != status2)) {
if (OS_GetTicks() - lastStatusPrintTick < 40) {
limitStatusPrint++;
} else {
limitStatusPrint = 0;
}
if (limitStatusPrint < 3) {
PrintEvent("cmx r%d=%d", CMX_Status1, status1);
PrintEvent("cmx r%d=%d", CMX_Status2, status2);
}
lastStatusPrintTick = OS_GetTicks();
}
lastStatus1 = status1;
lastStatus2 = status2;
if (status1 & CMX_IBEMPTY) {
/* Interleave buffer empty */
PrintEvent("CMX990: Interleave buffer empty.", 0, 0);
}
if (status1 & CMX_DIBOVF) {
PrintEvent("CMX990: De-interleave overflow, rx overrun", 0, 0);
}
if (status1 & CMX_DQRDY) {
//PrintEvent("Data quality ready", 0, 0);
}
if (status1 & CMX_PKTDET) {
}
if (status2 & CMX_SPC_RDY) {
spcCommandReady = TRUE;
PrintEvent("Special command ready", 0, 0);
}
/* Count the ISR and print every 15 seconds */
isrCounter++;
if (OS_GetTicks() - lastIsrTick > 15000) {
lastIsrTick = OS_GetTicks();
PrintEvent("ISR #%d at %d ms", isrCounter, (u32)lastIsrTick);
}
}
return;
}
/******************************************************************************
* Routine : Timer1_Isr
* Description: ISR for processing timer 1 interrupts.
* This is called in the sync algorithm 12 bit periods after
* IQ offset ready.
******************************************************************************/
cyg_uint32 Timer1_Isr(cyg_vector_t vector, cyg_addrword_t data) {
u32 dummy;
u8 sp[2];
cyg_drv_interrupt_acknowledge(vector);
dummy = INPUT32(TC1_SR);
/* Disable RC compare interrupt. */
OUTPUT32(TC1_IDR, AT91_TC_IER_CPC);
PrintEvent("Timer 1 ISR", 0, 0);
if (cmxWorkingMode == CMX_ModeAquireChannel) {
// We have now finished AQIQ and AQAFC.
sp[0] = (prbsSyncPattern >> 8) & 0xff;
sp[1] = prbsSyncPattern & 0xff;
CMX_LoadDataBlock(sp, 2);
CMX_WriteCmd(CMX_RXTASK_LFSB | CMX_AQBC);
cmxWorkingMode = CMX_ModeRxPrbsStart;
} else if (cmxWorkingMode == CMX_ModeRxPrbsStart) {
/* We have loaded the PRBS synch pattern and waited 12 bit periods, now */
/* search for PRBS synch. */
CMX_WriteCmd(CMX_RXTASK_SFSZ);
cmxWorkingMode = CMX_ModeRxPrbsSync;
} else {
CYG_FAIL("CMX990: Illegal timer 1 interrupt.");
}
return (CYG_ISR_HANDLED);
}
/******************************************************************************
* Routine : Timer1_Dsr
* Description: DSR for processing timer 1 interrupts.
******************************************************************************/
static void Timer1_Dsr(cyg_vector_t vector, cyg_ucount32 dsrCount, cyg_addrword_t dsrData) {
// Nothing to be done.
}
/******************************************************************************
* Routine : CMX_Reset
* Description: Reset function called by CMX_Init, Initializes the CMX990.
******************************************************************************/
void CMX_Reset(void) {
#ifdef DE9901_BOARD
/* Enable power to synth */
BINIO_SetPort(BINIO_VRF_ON, BINIO_HIGH);
/* Wait a while for power to stablize */
cyg_thread_delay(5);
#endif
/* Reset CMX990 chip */
CMX_Write(CMX_PowerUp2, CMX_RESET);
cyg_thread_delay(5);
CMX_Write(CMX_PowerUp2, 0);
cyg_thread_delay(5);
CMX_WriteCmd(CMX_TXTASK_RESET);
expectBFREE = FALSE;
/* Start CMX chip */
CMX_Write(CMX_PowerUp2, CMX_VBIAS);
cyg_thread_delay(5);
CMX_Write(CMX_PowerUp1, CMX_VREG);
cyg_thread_delay(5);
CMX_Write(CMX_PowerUp1, 0xf0); /* Enable all but RX and TX */
CMX_Write(CMX_PowerUp2, CMX_POWER2_SETTING_RX_OFF); /* Do not reset and set LNA off */
CMX_Write(CMX_Control, CMX_AGC_RUN|CMX_IQ_FINE|CMX_AFC_SLOW|CMX_PLL_NARROW);
CMX_Write(CMX_Mode, CMX_MODE_SETTING_RX | (invertBitStream ? CMX_INVBIT : 0));
CMX_Write(CMX_AnalogSetup1W, CMX_TX_ATT_10DB | 32);
/* Enable all ADC and set fast and continously conversions */
CMX_Write(CMX_AuxAdcControl1, 0x3f);
CMX_Write(CMX_AuxAdcControl2, 0x06);
/* Init ref. frequency to approx. 19.2 MHz */
/* This shall be a calibrated value stored e.g. in the I2C EEPROM. */
CMX_WriteDac(DAC_TCXO, cmxConfig.vctcxoCalibration);
/* Init PLL register to Rx frequency in the middle of the band. */
CMX_UpdateRxPll();
#ifdef DE9901_BOARD
cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_CMX);
#endif
#ifdef EB40A_BOARD
cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_IRQ2);
#endif
if (cmx990Revision[0] < 'C') {
/* New IQ Gain values from Jo Gibbins 2004-04-08 */
/* Poke address 0x00AE with 0xFDA8 */
CMX_WriteSpecialCmdData0(1, 0, 0xae);/* Set address command */
//CMX_WriteSpecialCmdData0(1, 0, 0xb4);/* Set address command */
CMX_WriteSpecialCmdData0(3, 0xfd, 0xa8);/* Poke data */
}
}
/******************************************************************************
* Routine : CMX_Init
* Description: Init function called by DSP_Init, Initializes the CMX interface,
* : enables interrupts. Init only context.
* Parameters : void
* :
* Return : void
* Globals : None
******************************************************************************/
void CMX_Init(void) {
int i;
int tcclks;
cyg_io_handle_t flash;
Cyg_ErrNo err;
cyg_uint32 len;
CMX_ResetPrbs();
/* Read configuration data from /dev/flash1 */
err = cyg_io_lookup("/dev/flash1", &flash);
if (err) {
CYG_FAIL("CMX_Init: Error opening /dev/flash1");
}
len = sizeof(CmxConfig_t);
err = cyg_io_bread(flash, (int*)&cmxConfig, &len, 0);
if (err) {
CYG_FAIL("CMX_Init: Error reading /dev/flash1");
}
if (cmxConfig.id != 0x12345678) {
printf("CMX_Init: Config data not found! Using default values.\n");
cmxConfig.vctcxoCalibration = 600;
/* We setup the system for a 400 MHz radio board from CML. */
refClk = 19200000;
#if 0
minTxFreq = 425500000;
maxTxFreq = 463000000;
minRxFreq = 440000000;
maxRxFreq = 452000000;
rxFreq = 451000000; /* Default frequency. */
txFreq = 461000000; /* Default frequency. */
/* Using low side when mixing RX and TX. */
rxIfSummer = CMX_RX_IF_SUMMER_NEG;
txIfHighSide = FALSE;
invertBitStream = TRUE;
txIfDiv = CMX_TX_IF_DIV2;
txLODiv = CMX_TX_LO_DIV2;
txMixFilter = CMX_TX_MIX_FILTER_LOW;
txVcoCharge = CMX_TX_VCO_CHARGE_HALF;
txSlope = CMX_TX_SLOPE_NEG;
mainStep = 12500;
#else
/* We setup the system for a 800 MHz radio board from CML. */
minTxFreq = 819000000;
maxTxFreq = 825000000;
minRxFreq = 864000000;
maxRxFreq = 870000000;
rxFreq = 867000000; /* Default frequency. */
txFreq = 822000000; /* Default frequency. */
/* Using high side when mixing RX and TX. */
rxIfSummer = CMX_RX_IF_SUMMER_POS;
txIfHighSide = TRUE;
invertBitStream = FALSE;
txIfDiv = CMX_TX_IF_DIV1;
txLODiv = CMX_TX_LO_DIV2;
txMixFilter = CMX_TX_MIX_FILTER_LOW;
txVcoCharge = CMX_TX_VCO_CHARGE_HALF;
txSlope = CMX_TX_SLOPE_NEG;
mainStep = 6250;
#endif
} else {
if (cmxConfig.ver >= 1) {
refClk = cmxConfig.refClk;
minRxFreq = cmxConfig.minRxFreq;
maxRxFreq = cmxConfig.maxRxFreq;
minTxFreq = cmxConfig.minTxFreq;
maxTxFreq = cmxConfig.maxTxFreq;
rxIfSummer = cmxConfig.rxIfHighSide ? CMX_RX_IF_SUMMER_POS : CMX_RX_IF_SUMMER_NEG;
txIfHighSide = cmxConfig.txIfHighSide ? TRUE : FALSE;
invertBitStream = cmxConfig.invertBitStream ? TRUE : FALSE;
rxIf = cmxConfig.rxIf;
txIf = cmxConfig.txIf;
auxStep = cmxConfig.auxStep;
mainStep = cmxConfig.mainStep;
rxFreq = cmxConfig.rxFreq;
txFreq = cmxConfig.txFreq;
txIfDiv = (cmxConfig.txIfDiv2 ? CMX_TX_IF_DIV2 : CMX_TX_IF_DIV1);
txLODiv = (cmxConfig.txLODiv2 ? CMX_TX_LO_DIV2 : CMX_TX_LO_DIV1);
txMixFilter = (cmxConfig.txMixFilterHigh ? CMX_TX_MIX_FILTER_HIGH : CMX_TX_MIX_FILTER_LOW);
txVcoCharge = (cmxConfig.txVcoCharge ? CMX_TX_VCO_CHARGE_HALF : CMX_TX_VCO_CHARGE_NONE);
txSlope = (cmxConfig.txSlopePos ? CMX_TX_SLOPE_POS : CMX_TX_SLOPE_NEG);
} else {
printf("CMX_Init: Wrong version of configuration data.\n");
}
}
rxAuxFreq = rxIf*4; /* Hz */
txAuxFreq = txIf*2*(txIfDiv == CMX_TX_IF_DIV1 ? 1 : 2); /* Hz */
if (txIf == 90000000) {
txIfFilter = CMX_TX_IF_FILTER_90;
} else if (txIf == 80000000) {
txIfFilter = CMX_TX_IF_FILTER_80;
} else if (txIf == 45000000) {
txIfFilter = CMX_TX_IF_FILTER_45;
} else if (txIf == 40000000) {
txIfFilter = CMX_TX_IF_FILTER_40;
} else {
CYG_FAIL("CMX990: Can't init TX IF FILTER value.");
}
/* Init an array indicating which CMX write registers that can be read back in test mode */
/* and which can not. Some of the CMX write registers is returning a wrong value when reading */
/* in test mode. */
for (i=0; i<=CMX_MAX_REG_ADDR; i++) {
cmxWriteRegRead[i] = TRUE;
}
/* This is the list of CMX write registers that can not be read. */
cmxWriteRegRead[CMX_Control] = FALSE;
cmxWriteRegRead[CMX_AnalogSetup1W] = FALSE;
cmxWriteRegRead[CMX_AnalogSetup2W] = FALSE;
cmxWriteRegRead[CMX_SpecialCommand] = FALSE;
cmxWriteRegRead[CMX_SpecialData0LsbW] = FALSE;
cmxWriteRegRead[CMX_SpecialData0MsbW] = FALSE;
cmxWriteRegRead[CMX_SpecialData1LsbW] = FALSE;
cmxWriteRegRead[CMX_SpecialData1MsbW] = FALSE;
cmxWriteRegRead[CMX_MainPllMLsb] = FALSE;
cmxWriteRegRead[CMX_MainPllMMsb] = FALSE;
cmxWriteRegRead[CMX_MainPllNLsb] = FALSE;
cmxWriteRegRead[CMX_MainPllNNsb] = FALSE;
cmxWriteRegRead[CMX_MainPllNMsb] = FALSE;
cmxWriteRegRead[CMX_AuxPllMLsb] = FALSE;
cmxWriteRegRead[CMX_AuxPllMMsb] = FALSE;
cmxWriteRegRead[CMX_AuxPllNLsb] = FALSE;
cmxWriteRegRead[CMX_AuxPllNMsb] = FALSE;
/* Setup CMX990 interrupt in HW. */
/* Interrupt is low level triggered. */
#ifdef DE9901_BOARD
/* We use IRQ0 on DE9901. */
/* Low Level trigged: level: up: */
cyg_drv_interrupt_configure(CYGNUM_HAL_INTERRUPT_CMX, TRUE, FALSE);
cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_CMX, CMX_ISR_PRIO, 0, CMX_IsrStart, CMX_Dsr, &isrHandle, &isr);
#endif
#ifdef EB40A_BOARD
/* We use IRQ2 on EB40A. */
cyg_drv_interrupt_configure(CYGNUM_HAL_INTERRUPT_IRQ2, TRUE, FALSE);
cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_IRQ2, CMX_ISR_PRIO, 0, CMX_IsrStart, CMX_Dsr, &isrHandle, &isr);
#endif
cyg_drv_interrupt_attach(isrHandle);
/* Find the clock div that gets at least 25 ms timer with a value less than 0x10000. */
if ((25*(MCK/8))/1000 < 0x10000) {
clockDiv = 8;
tcclks = 1;
} else if ((25*(MCK/32))/1000 < 0x10000) {
clockDiv = 32;
tcclks = 2;
} else {
clockDiv = 128;
tcclks = 3;
}
OUTPUT32(TC1_RC, (15*(MCK/clockDiv))/10000);
OUTPUT32(TC1_CMR, 0x0000C440 | tcclks);
OUTPUT32(TC1_CCR, AT91_TC_CCR_CLKEN);
cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_TIMER1, CMX_ISR_PRIO, 0, Timer1_IsrStart, Timer1_Dsr, &timer1IsrHandle, &timer1Isr);
cyg_drv_interrupt_attach(timer1IsrHandle);
cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_TIMER1);
CMX_Reset();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -