📄 cmx990.c
字号:
/****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 + -