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

📄 cmx990.c

📁 CMX990 demonstration board (DE9901)
💻 C
📖 第 1 页 / 共 3 页
字号:
/****h* DE9901/CMX
* FILE NAME
*  cmx990.c
* COPYRIGHT
*  (c) 2004-2005 Mobitex Technology AB - All rights reserved
* 
*  Redistribution and use in source and binary forms, with or without modification,
*  are permitted provided that the following conditions are met:
*  * 1. Redistributions of source code must retain the above copyright notice,
*       this list of conditions and the following disclaimer. 
*  * 2. Redistributions in binary form must reproduce the above copyright notice,
*       this list of conditions and the following disclaimer in the documentation
*       and/or other materials provided with the distribution.
*  * 3. The name Mobitex Technology AB may not be used to endorse or promote products
*       derived from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY MOBITEX TECHNOLOGY AB "AS IS" AND ANY EXPRESS OR
*  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
*  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
*  SHALL MOBITEX TECHNOLOGY AB BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
*  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
*  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
*  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
*  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
*  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* AUTHOR
*  MPN/Kjell Westerberg
* HISTORY
*  Changes in the file are recorded in this list.
*   Ver:  Date:       Responsible:         Comment:
*   R1A01 2005-01-26  Kjell Westerberg     Approved.
*   R1A02 2005-02-07  Kjell Westerberg     Added timeout for writing special commands.
*                                          Error handling for spurious interrupts from CMX990.
*   R1A03 2005-02-23  Kjell Westerberg     Changed message when interrupt overrun.
*   R1A04 2005-02-28  Kjell Westerberg     Check if Rx or Tx is active when set active.
*   R1A05 2005-03-17  Kjell Westerberg     Changed sync algorithm.
*   R1A06 2005-04-08  Kjell Westerberg     Adapted for CML radio board.
*   R1A08 2005-08-02  Kjell Westerberg     Adapted for rev C of CMX990.
* DESCRIPTION
*  Functions to handle the CMX990.
*  Interrupt routine for CMX990.
***/

#include "hel.h"
#include "cmx990_reg.h"
#include "version.h"

#define CMX_MODE_SETTING_RX (CMX_IRQEN|CMX_SCREN|CMX_ADC_EN)
#define CMX_MODE_SETTING_TX (CMX_IRQEN|CMX_TXRXN|CMX_SCREN|CMX_DAC_EN)

#define CMX_POWER2_SETTING_RX_OFF (CMX_DAC3|CMX_DAC2|CMX_DAC1|CMX_DAC0|CMX_PREREG|CMX_VBIAS)
#define CMX_POWER2_SETTING_RX_ON (CMX_DAC3|CMX_DAC2|CMX_DAC1|CMX_DAC0|CMX_LNA|CMX_PREREG|CMX_VBIAS)
//#define CMX_POWER2_SETTING_RX_OFF (CMX_DAC1|CMX_DAC0|CMX_VBIAS)
//#define CMX_POWER2_SETTING_RX_ON (CMX_DAC1|CMX_DAC0|CMX_LNA|CMX_VBIAS)


static cyg_handle_t isrHandle;
static cyg_interrupt isr;
static cyg_handle_t timer1IsrHandle;
static cyg_interrupt timer1Isr;

static u32 isrCounter = 0;
static OSTICK lastIsrTick = 0;

/* This variable is set false when a special command is given to the CMX990. */
/* The interrupt from CMX990 tells when the command is ready and sets this variable true again. */
static volatile bool spcCommandReady = TRUE;
static OSTICK lastSpcCommand = 0;

static CMX_PrbsStatistics_t prbsData;
static u16 prbsSyncPattern = 0x0ef0;
static u16 prbsRxRegister = 0x01ff;
static u32 prbsRecSeq = 0; /* Last 32 bits in the received prbs sequence. */

static s32 refClk = MCK; /* Set radio reference clock same as system clock as default. */

static s32 rxFreq = 938000000; /* Default rx freq */
static s32 txFreq = 899000000; /* Default tx freq */
static s32 minTxFreq = 896000000;
static s32 maxTxFreq = 902000000;
static s32 minRxFreq = 935000000;
static s32 maxRxFreq = 941000000;

static s32 rxIf = 45000000; /* Hz */
static s32 txIf = 90000000; /* Hz */
static s32 txIfDiv = CMX_TX_IF_DIV1;
static s32 txIfFilter;
static s32 txLODiv = CMX_TX_LO_DIV2;
static s32 rxIfSummer = CMX_RX_IF_SUMMER_POS; /* Using high side when mixing RX. */
static bool txIfHighSide = TRUE; /* Using high side when mixing TX. */
static bool invertBitStream = FALSE;
static s32 txMixFilter;
static s32 txVcoCharge;
static s32 txSlope;

static s32 rxAuxFreq;
static s32 txAuxFreq;
static s32 auxStep = 200000; /* Hz */
static s32 mainStep = 12500; /* Hz */

static bool rxActive = FALSE;
static bool txActive = FALSE;

static s32 clockDiv;

static CMX_Modes cmxWorkingMode = CMX_ModeIdle;
static bool expectBFREE = FALSE;

static u8 cmxWriteRegValue[CMX_MAX_REG_ADDR+1];
static bool cmxWriteRegRead[CMX_MAX_REG_ADDR+1];

/* This is a data structure for the configuration data stored in the flash. */
typedef struct {
  int id;
  int ver;
  int boardType;
  int refClk;
  int minRxFreq;
  int maxRxFreq;
  int minTxFreq;
  int maxTxFreq;
  int rxIfHighSide;
  int txIfHighSide;
  int invertBitStream;
  int rxIf;
  int txIf;
  int auxStep;
  int mainStep;
  int rxFreq;
  int txFreq;
  bool txIfDiv2;
  bool txLODiv2;
  bool txMixFilterHigh;
  bool txVcoCharge;
  bool txSlopePos;
  int  vctcxoCalibration;
} CmxConfig_t;

static CmxConfig_t cmxConfig;


/* The CMX_IsrStart function is compiled to ARM code and is used to call the CMX_Isr. */
cyg_uint32 CMX_IsrStart(cyg_vector_t vector, cyg_addrword_t data);
cyg_uint32 Timer1_IsrStart(cyg_vector_t vector, cyg_addrword_t data);

static void CMX_WriteCmd(u8 cmd);

#ifdef DE9901_BOARD
#define CMX_MEM_READ(x) (*(volatile u8*)(x))
#define CMX_MEM_WRITE(x, d) *((volatile u8*)(x))=(u8)(d)
#endif

#ifdef EB40A_BOARD
static u8 CMX_MEM_READ(u32 addr) {
  u8 val;
  u32 val32;
  val32 = ((addr&0x20) << 13) | ((addr&0x1E) << 2) | (addr&1);
  DISABLE_INTERRUPTS(); {
    OUTPUT32(PIO_CODR, 0x40079); // Address = 0
    OUTPUT32(PIO_SODR, val32); // Address = addr
    OUTPUT32(PIO_ODR, 0xEF800000); // Data inputs
    OUTPUT32(PIO_CODR, 0x082000); // CSN = 0, RDN = 0
    val32 = INPUT32(PIO_PDSR);
    OUTPUT32(PIO_SODR, 0x082000); // RDN = 1, CSN = 1    
  } ENABLE_INTERRUPTS();
  val = (u8)(((val32 >> 23) & 0x1F) | ((val32 >> 24) & 0xE0));
  return val;
}

static void CMX_MEM_WRITE(u32 addr, u8 data) {
  u32 val32;
  u32 address;

  val32 = ((u32)(data & 0xE0) << 24) | ((u32)(data &0x1F) << 23);
  address = ((addr&0x20) << 13) | ((addr&0x1E) << 2) | (addr&1);
  DISABLE_INTERRUPTS(); {
    OUTPUT32(PIO_CODR, 0x40079); // Address = 0
    OUTPUT32(PIO_SODR, address); // Address = addr
    OUTPUT32(PIO_OER, 0xEF800000); // Data outputs
    OUTPUT32(PIO_CODR, 0xEF800000); // Data = 0
    OUTPUT32(PIO_SODR, val32); // Data = data
    OUTPUT32(PIO_CODR, 0x102000); // CSN = 0, WRN = 0
    OUTPUT32(PIO_SODR, 0x102000); // WRN = 1, CSN = 1
  } ENABLE_INTERRUPTS();
}
#endif

/******************************************************************************
 * Routine    :  CMX_GetFreqBand
 * Description:  Returns the frequency band.
 ******************************************************************************/
void CMX_GetFreqBand(s32 *minRx, s32 *maxRx, s32 *minTx, s32 *maxTx) {
  *minRx = minRxFreq;
  *maxRx = maxRxFreq;
  *minTx = minTxFreq;
  *maxTx = maxTxFreq;
}

/******************************************************************************
 * Routine    :  CMX_RefClock
 * Description:  Returns the radio reference clock frequency.
 ******************************************************************************/
s32 CMX_RefClock(void) {
  return refClk;
}

/******************************************************************************
 * Routine    :  CMX_GetFreqParameters
 * Description:  Returns the radio frequency parameters.
 ******************************************************************************/
void CMX_GetFreqParameters(s32 *rx, s32 *tx, bool *txHighSide) {
  *rx = rxIf;
  *tx = txIf;
  *txHighSide = txIfHighSide; 
}

/******************************************************************************
 * Routine    :  CMX_Write
 * Description:  Writes 8 bit value in the wanted Control Word.
 ******************************************************************************/
void CMX_Write(enum CMX_ControlWordsWrite cmd, u8 cmdData) {
  cmxWriteRegValue[cmd] = cmdData;
  if (cmd == CMX_Command) {
    CMX_WriteCmd(cmdData);
  } else {
    CMX_MEM_WRITE(((u32)CMX_BASE+(u32)cmd), cmdData);
    PrintEvent("cmx w%d=%d", cmd, cmdData);
  }
}

/******************************************************************************
 * Routine    :  CMX_Read
 * Description:  Reads the wanted Control Word from the CMX and returns a 8
 *            :  bit value.
 ******************************************************************************/
u8 CMX_Read(enum CMX_ControlWordsRead cmd) {
  u8 value;

  value = CMX_MEM_READ(((u32)CMX_BASE+(u32)cmd));
  return value;
}

/******************************************************************************
 * Routine    :  CMX_ReadWriteReg
 * Description:  Reads a value from a write register.
 ******************************************************************************/
u8 CMX_ReadWriteReg(enum CMX_ControlWordsWrite cmd, bool cmxRead) {
  u8 value;
  if ((cmxRead == FALSE) && (cmxWriteRegRead[cmd] == FALSE)) {
    value = cmxWriteRegValue[cmd];
  } else {
    DISABLE_INTERRUPTS(); {
      CMX_MEM_WRITE(CMX_HW_TESTACCESS_2, CMX_HW_SWAP_IO | CMX_HW_TRIM);
      value = CMX_MEM_READ(((u32)CMX_BASE+(u32)cmd));
      CMX_MEM_WRITE(CMX_HW_TESTACCESS_2, CMX_HW_TRIM);
    } ENABLE_INTERRUPTS();
  }
  return value;
}

/*****************************************************************************
 * Routine    :  CMX_LoadDataBlock
 * Description:  Loads the data on the CMX990, one byte per word.
 *****************************************************************************/
static void CMX_LoadDataBlock(u8 *pBlock, u8 noBytes) {
  u8 i;
  for(i = 0; i< noBytes; i++) {
    CMX_Write(CMX_DataBufferTx, pBlock[i]);
  }
}

/*****************************************************************************
 * Routine    :  CMX_GetDataBlock
 * Description:  Gets the data from the CMX990, one byte per word.
 *****************************************************************************/
static void CMX_GetDataBlock(u8 *pBlock, u8 noBytes) {
  u8 i;
  for(i = 0; i< noBytes; i++) {
    pBlock[i] = CMX_Read(CMX_DataBufferRx);
  }
}

/******************************************************************************
 * Routine    :  CMX_WaitSpecialCommand
 * Description:  Waits for a special command to be ready.
 *               If not ready a timeout will occur after 1 s.
 ******************************************************************************/
static void CMX_WaitSpecialCommand(void) {
  while ((spcCommandReady == FALSE) && (OS_GetTicks() - lastSpcCommand < 1000));
  if (spcCommandReady == FALSE) {
    PrintEvent("CMX990: Timeout on last special command", 0, 0);
  }
  spcCommandReady = FALSE;
  lastSpcCommand = OS_GetTicks();
}

/******************************************************************************
 * Routine    :  CMX_WriteSpecialCmdData0
 * Description:  Writes data to the special command data register 0.
 ******************************************************************************/
static void CMX_WriteSpecialCmdData0(u8 cmd, u8 msb, u8 lsb) {
  CMX_WaitSpecialCommand();
  /* Disable scheduler to be sure the writes here are not interrupted */
  DISABLE_INTERRUPTS(); {
    CMX_Write(CMX_SpecialData0MsbW, msb);
    CMX_Write(CMX_SpecialData0LsbW, lsb);
    CMX_Write(CMX_SpecialCommand, cmd);
  } ENABLE_INTERRUPTS();
}

/******************************************************************************
 * Routine    :  CMX_WriteSpecialCmd
 * Description:  Writes a command to the special command register.
 ******************************************************************************/
static void CMX_WriteSpecialCmd(u8 cmd) {
  CMX_WaitSpecialCommand();
  CMX_Write(CMX_SpecialCommand, cmd);
}

/******************************************************************************
 * Routine    :  CMX_WriteCmd
 * Description:  Writes a command to the command register.
 ******************************************************************************/
static void CMX_WriteCmd(u8 cmd) {
  static u8 lastCmd = 0;
  cmxWriteRegValue[CMX_Command] = cmd;
  CMX_MEM_WRITE(((u32)CMX_BASE+(u32)CMX_Command), cmd);
  if (!(((cmd&0x0F) == CMX_RXTASK_NULL) || ((cmd&0x0F) == CMX_RXTASK_RESET) || (txActive && ((cmd&0x0F) == CMX_TXTASK_TSO)))) {
    expectBFREE = TRUE;
  } else {
    if ((cmd&0x0F) == CMX_RXTASK_RESET) {
      expectBFREE = FALSE;
    }
  }
  if (lastCmd != cmd) {
    PrintEvent("cmx w1=%d", cmd, 0);
    lastCmd = cmd;
  }
}

/******************************************************************************
 * Routine    :  CMX_WriteDac
 * Description:  Writes a 10-bit value to a DAC in the CMX990.
 ******************************************************************************/
void CMX_WriteDac(DacSelect_t dacNo, u16 dacValue) {
  enum CMX_ControlWordsWrite dacRegMsb;
  enum CMX_ControlWordsWrite dacRegLsb;

  switch(dacNo) {
    case VREF_PA:
      dacRegMsb = CMX_Dac0Msb;
      dacRegLsb = CMX_Dac0Lsb;
      break;
    case DAC_TCXO:
      dacRegMsb = CMX_Dac1Msb;
      dacRegLsb = CMX_Dac1Lsb;
      break;
    case DAC_EXT:
      dacRegMsb = CMX_Dac2Msb;
      dacRegLsb = CMX_Dac2Lsb;
      break;
    case DAC_OUT:
      dacRegMsb = CMX_Dac3Msb;
      dacRegLsb = CMX_Dac3Lsb;
      break;
    default:
      CYG_FAIL("Illegal DAC number.");
      break;
  }
  CMX_MEM_WRITE(((u32)CMX_BASE+(u32)dacRegLsb), (u8)(dacValue&0x03));
  CMX_MEM_WRITE(((u32)CMX_BASE+(u32)dacRegMsb), (u8)((dacValue>>2)&0x0ff));
  PrintEvent("dac %d=%d", dacNo, dacValue);
}

/******************************************************************************
 * Routine    :  CMX_ReadDac
 * Description:  Reads out a 10-bit value from a DAC in the CMX990.
 ******************************************************************************/
u16 CMX_ReadDac(DacSelect_t dacNo) {
  enum CMX_ControlWordsWrite dacRegMsb;
  enum CMX_ControlWordsWrite dacRegLsb;
  u16 value;

  switch(dacNo) {
    case VREF_PA:
      dacRegMsb = CMX_Dac0Msb;
      dacRegLsb = CMX_Dac0Lsb;
      break;
    case DAC_TCXO:
      dacRegMsb = CMX_Dac1Msb;
      dacRegLsb = CMX_Dac1Lsb;
      break;
    case DAC_EXT:
      dacRegMsb = CMX_Dac2Msb;
      dacRegLsb = CMX_Dac2Lsb;
      break;
    case DAC_OUT:
      dacRegMsb = CMX_Dac3Msb;
      dacRegLsb = CMX_Dac3Lsb;
      break;
    default:
      CYG_FAIL("Illegal DAC number.");
      break;
  }
  DISABLE_INTERRUPTS(); {
    CMX_MEM_WRITE(CMX_HW_TESTACCESS_2, CMX_HW_SWAP_IO | CMX_HW_TRIM);
    value = ((u16)CMX_MEM_READ(((u32)CMX_BASE+(u32)dacRegMsb)))<<2;
    value |= (u16)CMX_MEM_READ(((u32)CMX_BASE+(u32)dacRegLsb))&0x03;
    CMX_MEM_WRITE(CMX_HW_TESTACCESS_2, CMX_HW_TRIM);
  } ENABLE_INTERRUPTS();
  return value;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -