bert.c
上传用户:sdttscl
上传日期:2010-01-04
资源大小:683k
文件大小:13k
源码类别:

Modem编程

开发平台:

C/C++

  1. //---------------------------------------------------------------------------------------------------
  2. // Project:- DE8681
  3. //   Filename:- BERT.C
  4. // Description:- BERT routines for CMX868.
  5. // Programmer:- D.T.F
  6. // Version:- 2.0
  7. // Created:- 28th February 2002
  8. // Last modified:- 
  9. //---------------------------------------------------------------------------------------------------
  10. // (C) Consumer Microcircuits Ltd 2002
  11. //
  12. // This firmware was designed by:-
  13. // Consumer Microcircuits Ltd,
  14. // Langford, Maldon,
  15. // ESSEX
  16. // CM9 6WG.
  17. // in the UK for use with CML evaluation kits only and is based on UK originated technology.
  18. // Please contact
  19. // sales@cmlmicro.co.uk
  20. // +44 (0)1621 875500
  21. // for licensing details.
  22. //---------------------------------------------------------------------------------------------------
  23. #define BERT_C
  24. #include "ef8681.h"
  25. void bert()
  26. {
  27. init_bertporta(); // Configure and initialise Port A ready BERT
  28. if (DATAXFER)
  29. {
  30. CMXTXMODE &= 0xFFE0; // Unmask Tx data format bit settings
  31. CMXTXMODE ^= 0x001F; // Sync operation and data bytes from Tx Data Buffer 
  32. wr16_cbus(CMXTXMODE_ADDR, CMXTXMODE); // Update CBUS register
  33. CMXRXMODE &= 0xFFC7; // Unmask Rx USART bit settings
  34. CMXRXMODE ^= 0x0038; // Sync operation
  35. wr16_cbus(CMXRXMODE_ADDR, CMXRXMODE); // Update CBUS register
  36. }
  37. else
  38. {
  39. bert868_init(); // Initialise CMX868 ready for BERT Tx
  40. }
  41. CMXGENCTRL &= 0xFF00;
  42. if (BERTEND)
  43. {
  44. CMXGENCTRL ^= 0x0048; // Set bits for IRQN enable and Tx irq
  45. }
  46. else
  47. {
  48. CMXGENCTRL ^= 0x0041; // Set bits for IRQN enable and Rx irq
  49. }
  50. wr16_cbus(CMXGENCTRL_ADDR, CMXGENCTRL); // Update CBUS register
  51. bertimer_init(); // Initialise BER timer
  52. if (BERTEND) // If BERT Tx end (only Tx irq will have been enabled)
  53. {
  54. BERTXBYTE = 0; // Clear temporary BER Tx byte under construction
  55. wr_cbus(CMXTXDATA_ADDR, 0xFF);
  56. do
  57. {
  58. if (!PICIRQN) // If IRQN line goes low we can assume Tx Rdy flag is set
  59. {
  60. CMXSTAT = rd16_cbus(CMXSTAT_ADDR);   // Update Status shadow register and clear irq
  61. while (!BERTXRDY)
  62. {
  63. bert_txd();
  64. }
  65. wr_cbus(CMXTXDATA_ADDR, CMXTXDATA); // Write Tx Data to CMX868 reg
  66. BERTXRDY = 0; // Clear BER Tx Ready flag
  67. }
  68. } while (!KEYABORT); // Loop until key pushed
  69. }
  70. else // Otherwise assume BERT Rx end (Tx and Rx irq will have been enabled)
  71. {
  72. BER_RXDCLK = 1; // Initially set BER Rx data clock hi
  73. CMXSTAT = rd16_cbus(CMXSTAT_ADDR);    // Update Status shadow register and clear irq
  74. CMXRXDATA = rd_cbus(CMXRXDATA_ADDR); // Read CMX868 Rx Data reg and update shadow reg
  75. BERCNT = 8; // Reload BER rx bit counter
  76. BERRXDATACLR = 0; // Clear flag to indicate bit extraction required
  77. do
  78. {
  79. if (!PICIRQN) // If IRQN line goes low we can assume Rx Rdy flag is set
  80. {
  81. while (!BERRXDATACLR)
  82. {
  83. bert_rxd();
  84. }
  85. CMXSTAT = rd16_cbus(CMXSTAT_ADDR);   // Update Status shadow register and clear irq
  86. CMXRXDATA = rd_cbus(CMXRXDATA_ADDR); // Read CMX868 Rx Data reg and update shadow reg
  87. BERCNT = 8; // Reload BER rx bit counter
  88. BERRXDATACLR = 0; // Clear flag to indicate bit extraction required
  89. bert_rxd();
  90. }
  91. } while (!KEYABORT); // Loop until key pushed
  92. }
  93. BERTFLAG = 0; // Clear BERT flag
  94. KEYABORT = 0; // Reset key abort flag
  95. }
  96. void bert868_init() // Setup CMX868 for BERT
  97. {
  98. reset_cbus(); // Reset the CBUS before we start, will clear all shadow write registers
  99. pwrup(); // Power Up CMX868 with correct Xtal and fixed equalisers initially enabled.
  100. FIX_EQU = USER_FIX_EQU; // Extract required Tx and Rx Fixed Equaliser settings from S24.
  101. wr16_cbus(CMXGENCTRL_ADDR, CMXGENCTRL); // Update CBUS register
  102. CMXTXDATA = 0xFF; // Initially load 1's into Tx Data
  103. wr_cbus(CMXTXDATA_ADDR,CMXTXDATA); // Update CBUS register
  104. // Set up Tx/Rx operating modes
  105. switch(S27 & 0b11110000) // Determine selected protocol
  106. {
  107. case PROTB2:
  108. if (BERTEND)
  109. {
  110. CMXTXMODE ^= 0x4000; // Configure Tx for V.23 75bps
  111. CMXRXMODE ^= 0x5000; // Configure Rx for V.23 1200bps
  112. }
  113. else
  114. {
  115. CMXRXMODE ^= 0x4000; // Configure Rx for V.23 75bps
  116. CMXTXMODE ^= 0x5000; // Configure Tx for V.23 1200bps
  117. }
  118. break;
  119. case PROTB3:
  120. if (BERTEND)
  121. {
  122. CMXTXMODE ^= 0x5000; // Configure Tx for V.23 1200bps
  123. CMXRXMODE ^= 0x4000; // Configure Rx for V.23 75bps
  124. }
  125. else
  126. {
  127. CMXRXMODE ^= 0x5000; // Configure Rx for V.23 1200bps
  128. CMXTXMODE ^= 0x4000; // Configure Tx for V.23 75bps
  129. }
  130. break;
  131. case PROTB4:
  132. if ((BERTEND && BERTBAND) || (!BERTEND && !BERTBAND))
  133. {
  134. CMXTXMODE ^= 0xB000; // Configure Tx for V.22 600bps high band
  135. CMXRXMODE ^= 0xA000; // Configure Rx for V.22 600bps low band
  136. }
  137. else
  138. {
  139. CMXTXMODE ^= 0xA000; // Configure Tx for V.22 600bps low band
  140. CMXRXMODE ^= 0xB000; // Configure Rx for V.22 600bps high band
  141. }
  142. break;
  143. case PROTB5:
  144. if ((BERTEND && BERTBAND) || (!BERTEND && !BERTBAND))
  145. {
  146. CMXTXMODE ^= 0x9000; // Configure Tx for V.21 300bps high band
  147. CMXRXMODE ^= 0x8000; // Configure Rx for V.21 300bps low band
  148. }
  149. else
  150. {
  151. CMXTXMODE ^= 0x8000; // Configure Tx for V.21 300bps low band
  152. CMXRXMODE ^= 0x9000; // Configure Rx for V.21 300bps high band
  153. }
  154. break;
  155. case PROTB7:
  156. if (BERTEND)
  157. {
  158. CMXTXMODE ^= 0x2000; // Configure Tx for Bell 202 150bps
  159. CMXRXMODE ^= 0x3000; // Configure Rx for Bell 202 1200bps
  160. }
  161. else
  162. {
  163. CMXRXMODE ^= 0x2000; // Configure Rx for Bell 202 150bps
  164. CMXTXMODE ^= 0x3000; // Configure Tx for Bell 202 1200bps
  165. }
  166. break;
  167. case PROTB8:
  168. if (BERTEND)
  169. {
  170. CMXTXMODE ^= 0x3000; // Configure Tx for Bell 202 1200bps
  171. CMXRXMODE ^= 0x2000; // Configure Rx for Bell 202 150bps
  172. }
  173. else
  174. {
  175. CMXRXMODE ^= 0x3000; // Configure Rx for Bell 202 1200bps
  176. CMXTXMODE ^= 0x2000; // Configure Tx for Bell 202 150bps
  177. }
  178. break;
  179. case PROTB9:
  180. if ((BERTEND && BERTBAND) || (!BERTEND && !BERTBAND))
  181. {
  182. CMXTXMODE ^= 0x7000; // Configure Tx for Bell 103 high band
  183. CMXRXMODE ^= 0x6000; // Configure Rx for Bell 103 low band
  184. }
  185. else
  186. {
  187. CMXTXMODE ^= 0x6000; // Configure Tx for Bell 103 low band
  188. CMXRXMODE ^= 0x7000; // Configure Rx for Bell 103 high band
  189. }
  190. break;
  191. default:
  192. if ((BERTEND && BERTBAND) || (!BERTEND && !BERTBAND))
  193. {
  194. CMXTXMODE ^= 0xD000; // Configure Tx for V.22/Bell 212A 1200bps high band
  195. CMXRXMODE ^= 0xC000; // Configure Rx for V.22/Bell 212A 1200bps low Band
  196. }
  197. else
  198. {
  199. CMXTXMODE ^= 0xC000; // Configure Tx for V.22/Bell 212A 1200bps low band
  200. CMXRXMODE ^= 0xD000; // Configure Rx for V.22/Bell 212A 1200bps high Band
  201. }
  202. break;
  203. }
  204. // Set up Tx/Rx Gains
  205. CMXTXMODE ^= (((int) S25) << 9) & 0x0E00; // Extract required Tx level from S25.
  206. CMXRXMODE ^= (((int) S26) << 9) & 0x0E00; // Extract required Rx level from S26.
  207. // Set up Tx Guard Tones, Scrambler/Descrambler if required and initially disable Auto Equaliser
  208. switch(S27 & 0b11110000) // Determine selected protocol
  209. {
  210. case PROTB0: case PROTB1: case PROTB4: case PROTB6: // Auto Equaliser will initially be disabled
  211. if (BERTBAND) // High band operation
  212. {
  213. CMXTXMODE ^= (((int) S23) << 1) & 0x0180; // Extract Guard Tone setting from S23.
  214. }
  215. CMXTXMODE ^= (((int) S21) >> 1) & 0x0060; // Extract Scrambler setting from S21.
  216. CMXRXMODE ^= ((int) S21) & 0x00C0; // Extract Descrambler setting from S21.
  217. break;
  218. }
  219. // Set up Tx and Rx for sync mode
  220. CMXTXMODE ^= 0x001F; // Sync operation using data from Tx Data Buffer
  221. CMXRXMODE ^= 0x0038; // Sync operation
  222. wr16_cbus(CMXTXMODE_ADDR, CMXTXMODE); // Update CBUS register
  223. wr16_cbus(CMXRXMODE_ADDR, CMXRXMODE); // Update CBUS register
  224. switch(S27 & 0b11110000) // Determine selected protocol
  225. {
  226. case PROTB0: case PROTB1: case PROTB4: case PROTB6:
  227. if (BERTEND)
  228. {
  229. Delay1s(2); // 2s Delay
  230. }
  231. else
  232. {
  233. do
  234. {
  235. CMXSTAT = rd16_cbus(CMXSTAT_ADDR); // Read CMX868 Status reg and update shadow reg
  236. if (KEYABORT)
  237. {
  238. return;
  239. }
  240. DelayMs(50); // Insert 50ms polling delay
  241. } while(!RXENERGYDET || !CONTA); // Wait until Rx energy and 1's (Bit 7) has been detected
  242. }
  243. if ((S27 & 0b11110000) == PROTB0) // If 2400bps QAM is selected need to train at lower speed first
  244. {
  245. // Note backchannel will not sync
  246. CMXTXMODE &= 0x0FFF; // Unmask Tx Mode bit settings
  247. CMXRXMODE &= 0x0FFF; // Unmask Rx Mode bit settings
  248. if ((BERTEND && BERTBAND) || (!BERTEND && !BERTBAND))
  249. {
  250. CMXTXMODE ^= 0xF000; // Now configure Tx for high band 2400bps V.22 bis
  251. CMXRXMODE ^= 0xE000; // Configure Rx for V.22 bis 2400bps low Band
  252. }
  253. else
  254. {
  255. CMXTXMODE ^= 0xE000; // Now configure Tx for low band 2400bps V.22 bis
  256. CMXRXMODE ^= 0xF000; // Configure Rx for V.22 bis 2400bps high band
  257. }
  258. wr16_cbus(CMXTXMODE_ADDR,CMXTXMODE); // Update CBUS register
  259. AUTO_EQU = 1; // Enable Auto Equaliser
  260. }
  261. else
  262. {
  263. AUTO_EQU = USER_AUTO_EQU; // Extract Auto Equaliser setting from S24.
  264. }
  265. wr16_cbus(CMXRXMODE_ADDR,CMXRXMODE); // Update CBUS register
  266. break;
  267. }
  268. }
  269. void init_bertporta()
  270. {
  271. TRISA = CONFIGBERTPA; // Configure Port A for BERT
  272. }
  273. void undo_bertporta()
  274. {
  275. TRISA = CONFIGPA; // Configure Port A
  276. }
  277. void bert_txd()
  278. {
  279. bertimer_reload();
  280. if (!BER_TXDCLK) // If Tx Data clock is low
  281. {
  282. BER_TXDCLK = 1; // Set Tx Data clock hi
  283. return;
  284. }
  285. if (BERCNT != 1)
  286. {
  287. read_bertxdata();
  288. return;
  289. }
  290. if (!BERTXRDY)
  291. {
  292. read_bertxdata();
  293. }
  294. }
  295. void read_bertxdata()
  296. {
  297. BER_TXDCLK = 0; // !!!!!!!!!!!!!!!!!!!!! Becareful may be close to successive I/O port problem
  298. // I don't think you can read BER_TXD straight away 
  299. BERTXBYTE >>= 1; // Shift carry bit into MSB of byte under construction.
  300. BERTXBYTE &= 0b01111111;
  301. if (BER_TXD)
  302. {
  303. BERTXBYTE ^= 0b10000000;
  304. }
  305. BERCNT--; // Decrement BERT Tx bit counter
  306. if (BERCNT == 0) // If BERT Tx bit counter is zero 
  307. {
  308. CMXTXDATA = BERTXBYTE; // Copy temporary BER Tx byte to new BER Tx Byte
  309. BERCNT = 8; // Reload BERT Tx bit counter
  310. BERTXRDY = 1; // Set flag to indicate a new BER Tx byte has been constructed
  311. }
  312. }
  313. void modify_rxd()
  314. {
  315. CMXRXDATA >>= 1; // Shift Rx Data byte right 1 bit so LSB falls off into the carry bit.
  316. BER_RXD = CARRY; // Set BER RXD line to mirror carry bit
  317. BERCNT--; // Decrement BERT Rx bit counter
  318. if (BERCNT == 0) // If BERT Rx bit counter is zero 
  319. {
  320. BERRXDATACLR = 1; // Set flag to indicate a BER Rx byte has been emptied
  321. }
  322. }
  323. void bert_rxd()
  324. {
  325. bertimer_reload();
  326. if (BER_RXDCLK) // If Rx Data clock is hi
  327. {
  328. BER_RXDCLK = 0; // Set Rx Data clock lo
  329. return;
  330. }
  331. if (!BERRXDATACLR)
  332. {
  333. modify_rxd(); // Modify the BER RXD line appropriately
  334. BER_RXDCLK = 1; // Set Rx Data clock hi
  335. }
  336. }
  337. void bertimer_reload()
  338. {
  339. TMR0 = 151 + BERTMR0ADJ; // TMR0 start count (will cause interrupt on overflow)
  340. T0IF = 0; // Clear the interrupt flag
  341. }
  342. void bertimer_init()
  343. {
  344. T0CS = 0; // Timer increments on instruction clock
  345. PSA=0; // Assign Prescaler to TMR0
  346. BERTMR0ADJ = 18; // Initially set TMR0 adjustment variable for accurate 1200bps timing
  347. switch(S27 & 0b11110000)
  348. {
  349. case PROTB0:
  350. PS2=0; // 2400bps - Prescaler 1:2 TMR0
  351. PS1=0;
  352. PS0=0;
  353. BERTMR0ADJ = 36; // Adjust TMR0 to give accurate timing at 2400bps
  354. break;
  355. case PROTB2:
  356. PS2=1; // 75bps - Prescaler 1:64 TMR0
  357. PS1=0;
  358. PS0=1;
  359. BERTMR0ADJ = 1; // Adjust TMR0 to give accurate timing at 75bps
  360. break;
  361. case PROTB4:
  362. PS2=0; // 600bps - Prescaler 1:8 TMR0
  363. PS1=1;
  364. PS0=0;
  365. BERTMR0ADJ = 9; // Adjust TMR0 to give accurate timing at 600bps
  366. break;
  367. case PROTB5: case PROTB9:
  368. PS2=0; // 300bps - Prescaler 1:16 TMR0
  369. PS1=1;
  370. PS0=1;
  371. BERTMR0ADJ = 5; // Adjust TMR0 to give accurate timing at 300bps
  372. break;
  373. case PROTB7:
  374. PS2=1; // 150bps - Prescaler 1:32 TMR0
  375. PS1=0;
  376. PS0=0;
  377. BERTMR0ADJ = 3; // Adjust TMR0 to give accurate timing at 150bps
  378. break;
  379. default:
  380. PS2=0; // Default 1200bps - Prescaler 1:4 TMR0
  381. PS1=0;
  382. PS0=1;
  383. break;
  384. }
  385. TMR0 = 151 + BERTMR0ADJ; // TMR0 start count (will cause interrupt on overflow)
  386. T0IF = 0; // Clear the interrupt flag
  387. T0IE = 1; // Enable interrupt on TMR0 overflow
  388. }