⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cmx990.c

📁 CMX990 demonstration board (DE9901)
💻 C
📖 第 1 页 / 共 3 页
字号:
  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 + -