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

📄 bert.c

📁 CML CMX868 modem
💻 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 + -