📄 bert.c
字号:
//---------------------------------------------------------------------------------------------------
// Project:- DE8681
// Filename:- BERT.C
// Description:- BERT routines for CMX868.
// Programmer:- D.T.F
// Version:- 2.0
// Created:- 28th February 2002
// Last modified:-
//---------------------------------------------------------------------------------------------------
// (C) Consumer Microcircuits Ltd 2002
//
// This firmware was designed by:-
// Consumer Microcircuits Ltd,
// Langford, Maldon,
// ESSEX
// CM9 6WG.
// in the UK for use with CML evaluation kits only and is based on UK originated technology.
// Please contact
// sales@cmlmicro.co.uk
// +44 (0)1621 875500
// for licensing details.
//---------------------------------------------------------------------------------------------------
#define BERT_C
#include "ef8681.h"
void bert()
{
init_bertporta(); // Configure and initialise Port A ready BERT
if (DATAXFER)
{
CMXTXMODE &= 0xFFE0; // Unmask Tx data format bit settings
CMXTXMODE ^= 0x001F; // Sync operation and data bytes from Tx Data Buffer
wr16_cbus(CMXTXMODE_ADDR, CMXTXMODE); // Update CBUS register
CMXRXMODE &= 0xFFC7; // Unmask Rx USART bit settings
CMXRXMODE ^= 0x0038; // Sync operation
wr16_cbus(CMXRXMODE_ADDR, CMXRXMODE); // Update CBUS register
}
else
{
bert868_init(); // Initialise CMX868 ready for BERT Tx
}
CMXGENCTRL &= 0xFF00;
if (BERTEND)
{
CMXGENCTRL ^= 0x0048; // Set bits for IRQN enable and Tx irq
}
else
{
CMXGENCTRL ^= 0x0041; // Set bits for IRQN enable and Rx irq
}
wr16_cbus(CMXGENCTRL_ADDR, CMXGENCTRL); // Update CBUS register
bertimer_init(); // Initialise BER timer
if (BERTEND) // If BERT Tx end (only Tx irq will have been enabled)
{
BERTXBYTE = 0; // Clear temporary BER Tx byte under construction
wr_cbus(CMXTXDATA_ADDR, 0xFF);
do
{
if (!PICIRQN) // If IRQN line goes low we can assume Tx Rdy flag is set
{
CMXSTAT = rd16_cbus(CMXSTAT_ADDR); // Update Status shadow register and clear irq
while (!BERTXRDY)
{
bert_txd();
}
wr_cbus(CMXTXDATA_ADDR, CMXTXDATA); // Write Tx Data to CMX868 reg
BERTXRDY = 0; // Clear BER Tx Ready flag
}
} while (!KEYABORT); // Loop until key pushed
}
else // Otherwise assume BERT Rx end (Tx and Rx irq will have been enabled)
{
BER_RXDCLK = 1; // Initially set BER Rx data clock hi
CMXSTAT = rd16_cbus(CMXSTAT_ADDR); // Update Status shadow register and clear irq
CMXRXDATA = rd_cbus(CMXRXDATA_ADDR); // Read CMX868 Rx Data reg and update shadow reg
BERCNT = 8; // Reload BER rx bit counter
BERRXDATACLR = 0; // Clear flag to indicate bit extraction required
do
{
if (!PICIRQN) // If IRQN line goes low we can assume Rx Rdy flag is set
{
while (!BERRXDATACLR)
{
bert_rxd();
}
CMXSTAT = rd16_cbus(CMXSTAT_ADDR); // Update Status shadow register and clear irq
CMXRXDATA = rd_cbus(CMXRXDATA_ADDR); // Read CMX868 Rx Data reg and update shadow reg
BERCNT = 8; // Reload BER rx bit counter
BERRXDATACLR = 0; // Clear flag to indicate bit extraction required
bert_rxd();
}
} while (!KEYABORT); // Loop until key pushed
}
BERTFLAG = 0; // Clear BERT flag
KEYABORT = 0; // Reset key abort flag
}
void bert868_init() // Setup CMX868 for BERT
{
reset_cbus(); // Reset the CBUS before we start, will clear all shadow write registers
pwrup(); // Power Up CMX868 with correct Xtal and fixed equalisers initially enabled.
FIX_EQU = USER_FIX_EQU; // Extract required Tx and Rx Fixed Equaliser settings from S24.
wr16_cbus(CMXGENCTRL_ADDR, CMXGENCTRL); // Update CBUS register
CMXTXDATA = 0xFF; // Initially load 1's into Tx Data
wr_cbus(CMXTXDATA_ADDR,CMXTXDATA); // Update CBUS register
// Set up Tx/Rx operating modes
switch(S27 & 0b11110000) // Determine selected protocol
{
case PROTB2:
if (BERTEND)
{
CMXTXMODE ^= 0x4000; // Configure Tx for V.23 75bps
CMXRXMODE ^= 0x5000; // Configure Rx for V.23 1200bps
}
else
{
CMXRXMODE ^= 0x4000; // Configure Rx for V.23 75bps
CMXTXMODE ^= 0x5000; // Configure Tx for V.23 1200bps
}
break;
case PROTB3:
if (BERTEND)
{
CMXTXMODE ^= 0x5000; // Configure Tx for V.23 1200bps
CMXRXMODE ^= 0x4000; // Configure Rx for V.23 75bps
}
else
{
CMXRXMODE ^= 0x5000; // Configure Rx for V.23 1200bps
CMXTXMODE ^= 0x4000; // Configure Tx for V.23 75bps
}
break;
case PROTB4:
if ((BERTEND && BERTBAND) || (!BERTEND && !BERTBAND))
{
CMXTXMODE ^= 0xB000; // Configure Tx for V.22 600bps high band
CMXRXMODE ^= 0xA000; // Configure Rx for V.22 600bps low band
}
else
{
CMXTXMODE ^= 0xA000; // Configure Tx for V.22 600bps low band
CMXRXMODE ^= 0xB000; // Configure Rx for V.22 600bps high band
}
break;
case PROTB5:
if ((BERTEND && BERTBAND) || (!BERTEND && !BERTBAND))
{
CMXTXMODE ^= 0x9000; // Configure Tx for V.21 300bps high band
CMXRXMODE ^= 0x8000; // Configure Rx for V.21 300bps low band
}
else
{
CMXTXMODE ^= 0x8000; // Configure Tx for V.21 300bps low band
CMXRXMODE ^= 0x9000; // Configure Rx for V.21 300bps high band
}
break;
case PROTB7:
if (BERTEND)
{
CMXTXMODE ^= 0x2000; // Configure Tx for Bell 202 150bps
CMXRXMODE ^= 0x3000; // Configure Rx for Bell 202 1200bps
}
else
{
CMXRXMODE ^= 0x2000; // Configure Rx for Bell 202 150bps
CMXTXMODE ^= 0x3000; // Configure Tx for Bell 202 1200bps
}
break;
case PROTB8:
if (BERTEND)
{
CMXTXMODE ^= 0x3000; // Configure Tx for Bell 202 1200bps
CMXRXMODE ^= 0x2000; // Configure Rx for Bell 202 150bps
}
else
{
CMXRXMODE ^= 0x3000; // Configure Rx for Bell 202 1200bps
CMXTXMODE ^= 0x2000; // Configure Tx for Bell 202 150bps
}
break;
case PROTB9:
if ((BERTEND && BERTBAND) || (!BERTEND && !BERTBAND))
{
CMXTXMODE ^= 0x7000; // Configure Tx for Bell 103 high band
CMXRXMODE ^= 0x6000; // Configure Rx for Bell 103 low band
}
else
{
CMXTXMODE ^= 0x6000; // Configure Tx for Bell 103 low band
CMXRXMODE ^= 0x7000; // Configure Rx for Bell 103 high band
}
break;
default:
if ((BERTEND && BERTBAND) || (!BERTEND && !BERTBAND))
{
CMXTXMODE ^= 0xD000; // Configure Tx for V.22/Bell 212A 1200bps high band
CMXRXMODE ^= 0xC000; // Configure Rx for V.22/Bell 212A 1200bps low Band
}
else
{
CMXTXMODE ^= 0xC000; // Configure Tx for V.22/Bell 212A 1200bps low band
CMXRXMODE ^= 0xD000; // Configure Rx for V.22/Bell 212A 1200bps high Band
}
break;
}
// Set up Tx/Rx Gains
CMXTXMODE ^= (((int) S25) << 9) & 0x0E00; // Extract required Tx level from S25.
CMXRXMODE ^= (((int) S26) << 9) & 0x0E00; // Extract required Rx level from S26.
// Set up Tx Guard Tones, Scrambler/Descrambler if required and initially disable Auto Equaliser
switch(S27 & 0b11110000) // Determine selected protocol
{
case PROTB0: case PROTB1: case PROTB4: case PROTB6: // Auto Equaliser will initially be disabled
if (BERTBAND) // High band operation
{
CMXTXMODE ^= (((int) S23) << 1) & 0x0180; // Extract Guard Tone setting from S23.
}
CMXTXMODE ^= (((int) S21) >> 1) & 0x0060; // Extract Scrambler setting from S21.
CMXRXMODE ^= ((int) S21) & 0x00C0; // Extract Descrambler setting from S21.
break;
}
// Set up Tx and Rx for sync mode
CMXTXMODE ^= 0x001F; // Sync operation using data from Tx Data Buffer
CMXRXMODE ^= 0x0038; // Sync operation
wr16_cbus(CMXTXMODE_ADDR, CMXTXMODE); // Update CBUS register
wr16_cbus(CMXRXMODE_ADDR, CMXRXMODE); // Update CBUS register
switch(S27 & 0b11110000) // Determine selected protocol
{
case PROTB0: case PROTB1: case PROTB4: case PROTB6:
if (BERTEND)
{
Delay1s(2); // 2s Delay
}
else
{
do
{
CMXSTAT = rd16_cbus(CMXSTAT_ADDR); // Read CMX868 Status reg and update shadow reg
if (KEYABORT)
{
return;
}
DelayMs(50); // Insert 50ms polling delay
} while(!RXENERGYDET || !CONTA); // Wait until Rx energy and 1's (Bit 7) has been detected
}
if ((S27 & 0b11110000) == PROTB0) // If 2400bps QAM is selected need to train at lower speed first
{
// Note backchannel will not sync
CMXTXMODE &= 0x0FFF; // Unmask Tx Mode bit settings
CMXRXMODE &= 0x0FFF; // Unmask Rx Mode bit settings
if ((BERTEND && BERTBAND) || (!BERTEND && !BERTBAND))
{
CMXTXMODE ^= 0xF000; // Now configure Tx for high band 2400bps V.22 bis
CMXRXMODE ^= 0xE000; // Configure Rx for V.22 bis 2400bps low Band
}
else
{
CMXTXMODE ^= 0xE000; // Now configure Tx for low band 2400bps V.22 bis
CMXRXMODE ^= 0xF000; // Configure Rx for V.22 bis 2400bps high band
}
wr16_cbus(CMXTXMODE_ADDR,CMXTXMODE); // Update CBUS register
AUTO_EQU = 1; // Enable Auto Equaliser
}
else
{
AUTO_EQU = USER_AUTO_EQU; // Extract Auto Equaliser setting from S24.
}
wr16_cbus(CMXRXMODE_ADDR,CMXRXMODE); // Update CBUS register
break;
}
}
void init_bertporta()
{
TRISA = CONFIGBERTPA; // Configure Port A for BERT
}
void undo_bertporta()
{
TRISA = CONFIGPA; // Configure Port A
}
void bert_txd()
{
bertimer_reload();
if (!BER_TXDCLK) // If Tx Data clock is low
{
BER_TXDCLK = 1; // Set Tx Data clock hi
return;
}
if (BERCNT != 1)
{
read_bertxdata();
return;
}
if (!BERTXRDY)
{
read_bertxdata();
}
}
void read_bertxdata()
{
BER_TXDCLK = 0; // !!!!!!!!!!!!!!!!!!!!! Becareful may be close to successive I/O port problem
// I don't think you can read BER_TXD straight away
BERTXBYTE >>= 1; // Shift carry bit into MSB of byte under construction.
BERTXBYTE &= 0b01111111;
if (BER_TXD)
{
BERTXBYTE ^= 0b10000000;
}
BERCNT--; // Decrement BERT Tx bit counter
if (BERCNT == 0) // If BERT Tx bit counter is zero
{
CMXTXDATA = BERTXBYTE; // Copy temporary BER Tx byte to new BER Tx Byte
BERCNT = 8; // Reload BERT Tx bit counter
BERTXRDY = 1; // Set flag to indicate a new BER Tx byte has been constructed
}
}
void modify_rxd()
{
CMXRXDATA >>= 1; // Shift Rx Data byte right 1 bit so LSB falls off into the carry bit.
BER_RXD = CARRY; // Set BER RXD line to mirror carry bit
BERCNT--; // Decrement BERT Rx bit counter
if (BERCNT == 0) // If BERT Rx bit counter is zero
{
BERRXDATACLR = 1; // Set flag to indicate a BER Rx byte has been emptied
}
}
void bert_rxd()
{
bertimer_reload();
if (BER_RXDCLK) // If Rx Data clock is hi
{
BER_RXDCLK = 0; // Set Rx Data clock lo
return;
}
if (!BERRXDATACLR)
{
modify_rxd(); // Modify the BER RXD line appropriately
BER_RXDCLK = 1; // Set Rx Data clock hi
}
}
void bertimer_reload()
{
TMR0 = 151 + BERTMR0ADJ; // TMR0 start count (will cause interrupt on overflow)
T0IF = 0; // Clear the interrupt flag
}
void bertimer_init()
{
T0CS = 0; // Timer increments on instruction clock
PSA=0; // Assign Prescaler to TMR0
BERTMR0ADJ = 18; // Initially set TMR0 adjustment variable for accurate 1200bps timing
switch(S27 & 0b11110000)
{
case PROTB0:
PS2=0; // 2400bps - Prescaler 1:2 TMR0
PS1=0;
PS0=0;
BERTMR0ADJ = 36; // Adjust TMR0 to give accurate timing at 2400bps
break;
case PROTB2:
PS2=1; // 75bps - Prescaler 1:64 TMR0
PS1=0;
PS0=1;
BERTMR0ADJ = 1; // Adjust TMR0 to give accurate timing at 75bps
break;
case PROTB4:
PS2=0; // 600bps - Prescaler 1:8 TMR0
PS1=1;
PS0=0;
BERTMR0ADJ = 9; // Adjust TMR0 to give accurate timing at 600bps
break;
case PROTB5: case PROTB9:
PS2=0; // 300bps - Prescaler 1:16 TMR0
PS1=1;
PS0=1;
BERTMR0ADJ = 5; // Adjust TMR0 to give accurate timing at 300bps
break;
case PROTB7:
PS2=1; // 150bps - Prescaler 1:32 TMR0
PS1=0;
PS0=0;
BERTMR0ADJ = 3; // Adjust TMR0 to give accurate timing at 150bps
break;
default:
PS2=0; // Default 1200bps - Prescaler 1:4 TMR0
PS1=0;
PS0=1;
break;
}
TMR0 = 151 + BERTMR0ADJ; // TMR0 start count (will cause interrupt on overflow)
T0IF = 0; // Clear the interrupt flag
T0IE = 1; // Enable interrupt on TMR0 overflow
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -