"
MODULE P3048 TITLE 'P3048A' "Version 1 [12-APR-23] Based upon P3028P04. Remove dual-channel versions. "Version 2 [30-JUN-23] Re-work the fast clock divisor table so that any increase "in the fast clock divisor value results in an increase in transmit clock period. "Version 3 [19-JUL-23] Make CSS synchronous with TCK during ACTIVE. Add uniform "sampling at end of sample period, which eliminates scatter noise. "Version 4 [17-APR-24] Make SCK synchronous with TCK during ACTIVE. Make CSS "synchronous with CK during !ACTIVE ECK. "Version 5 [29-NOV-24] Remove CK from TP2 and replace with ACTIVE, so as to avoid "open-circuit coupling of CK into X input in the programming neck. Add linear shift "register calculation of scatter displacement. Change ECK to occur when sample "timer is zero, consistent with other transmitter firmware. declarations "Configuration Parameters "======================== "Version | Number | Description "------------------------------ " P0 0 64 SPS 20 Hz " P1 1 128 SPS 40 Hz " P2 2 256 SPS 80 Hz " P3 3 512 SPS 160 Hz " S0 0 64 SPS 20 Hz " S1 1 128 SPS 40 Hz " S2 2 256 SPS 80 Hz " S3 3 512 SPS 160 Hz " S4 4 1024 SPS 320 Hz " S5 5 2048 SPS 640 Hz "Set the transmitter version number VERSION = 2; "The channel number can be 1-14, 17-30, 33-46, 49-62, 65-78, 81-94, 97-110, 113-126, "129-142, 145-158, 161-174, 177-190, 193-206, 209-222. These ranges correspond to "sets 0-13 respectively. We reserve ranges 225-238 and 241-254 for test devices and "possible future channel number ranges expansions. channel_num = 1; "Calibration Parameters "====================== "Fast Clock Divisor, use to set TCK period in range 195-215 ns. Supported "range for fck_divisor is 8 to 30. fck_divisor = 24; "Frequency Low, use to center transmit spectrum in range 913-918 MHz. frequency_low = 22; "Parameters" "========== "Version-Dependent Parameters Set Automatically. @IF (VERSION == 0) { ck_divisor=512; "Total Sample Rate 64 SPS } @IF (VERSION == 1) { ck_divisor=256; "Total Sample Rate 128 SPS } @IF (VERSION == 2) { ck_divisor=128; "Total Sample Rate 256 SPS } @IF (VERSION == 3) { ck_divisor=64; "Total Sample Rate 512 SPS } @IF (VERSION == 4) { ck_divisor=32; "Total Sample Rate 1024 SPS } @IF (VERSION == 5) { ck_divisor=16; "Total Sample Rate 1024 SPS } "Set the transmit clock divisor, tck_divisor, and the ring oscillator length, "ring_length, to suit fck_divisor. The TCK period will be two gate delays "multiplied by tck_divisor multiplied by ring_length. For 7.5-ns chips, two "internal gate delays are roughly 9.3 ns. The ring length must be at least three. "A ring of two gates runs too fast, causing the counter to skip values. The maximum "ring length in this code is 13, but ultimately is limited by the available logic "outputs. The tck_divisor must be two or greater. We need at least two divider "states to create a symmetric transmit clock signal. And tck_divisor must also be "at most thirty-two because we have at most five divisor bits in this "code. @IF (fck_divisor == 8) {tck_divisor = 2; ring_length = 4;} @IF (fck_divisor == 9) {tck_divisor = 3; ring_length = 3;} @IF (fck_divisor == 10) {tck_divisor = 2; ring_length = 5;} @IF (fck_divisor == 11) {tck_divisor = 4; ring_length = 3;} @IF (fck_divisor == 12) {tck_divisor = 4; ring_length = 3;} @IF (fck_divisor == 13) {tck_divisor = 2; ring_length = 7;} @IF (fck_divisor == 14) {tck_divisor = 5; ring_length = 3;} @IF (fck_divisor == 15) {tck_divisor = 4; ring_length = 4;} @IF (fck_divisor == 16) {tck_divisor = 6; ring_length = 3;} @IF (fck_divisor == 17) {tck_divisor = 5; ring_length = 4;} @IF (fck_divisor == 18) {tck_divisor = 7; ring_length = 3;} @IF (fck_divisor == 19) {tck_divisor = 2; ring_length = 11;} @IF (fck_divisor == 20) {tck_divisor = 8; ring_length = 3;} @IF (fck_divisor == 21) {tck_divisor = 5; ring_length = 5;} @IF (fck_divisor == 22) {tck_divisor = 2; ring_length = 13;} @IF (fck_divisor == 23) {tck_divisor = 9; ring_length = 3;} @IF (fck_divisor == 24) {tck_divisor = 7; ring_length = 4;} @IF (fck_divisor == 25) {tck_divisor = 6; ring_length = 5;} @IF (fck_divisor == 26) {tck_divisor = 8; ring_length = 4;} @IF (fck_divisor == 27) {tck_divisor = 11; ring_length = 3;} @IF (fck_divisor == 28) {tck_divisor = 7; ring_length = 5;} @IF (fck_divisor == 29) {tck_divisor = 9; ring_length = 4;} @IF (fck_divisor == 30) {tck_divisor = 3; ring_length = 13;} @IF (fck_divisor == 31) {tck_divisor = 8; ring_length = 5;} @IF (fck_divisor == 32) {tck_divisor = 7; ring_length = 6;} "Other Parameters frequency_step=2; "HI frequency - LO frequency enable_rf=1; "Turns on RF oscillator during transmission "Channel ID I3..I0 node istype 'com'; "Transmitter ID nodes id = [I3..I0]; set_num = channel_num / 16; base_id = channel_num % 16; "Completion Code CC3..CC0 node istype 'com'; "Completion Code Bits cc =[CC3..CC0]; "Inputs and Outputs "================== CK pin E1; "Clock From 32-kHz Oscillator F4..F0 pin F1,D1,C1,B1,A1 istype 'reg'; "DAC for frequency !SHDN pin G8 istype 'com'; "Shutdown Control for Transmitter TP1 pin H2 istype 'com'; "Test Point TP2 pin H3 istype 'com'; "Test Point LOUT pin H4 istype 'com'; "Layout Output !CSS pin A6 istype 'com'; "Chip Select for ADC SDO pin A5; "Serial Data Out for ADC SCK pin A3 istype 'com'; "Serial Clock for ADC VL0..VL3 pin C4,E6,E7,E8; "VL Layout Pins TDI pin A2; "TDI through-pad GND0..GND9 pin D2,D3,E2,F2,F5,G1,G2,G3,G4,G5; "GND Layout Pins "Nodes "===== FCK node istype 'com,keep'; "Fast Clock TCK node istype 'reg,keep'; "Transmission Clock ECK node istype 'reg,keep'; "End Clock VCK node istype 'reg,keep'; "VCO Clock ST0..ST8 node istype 'reg'; "Sample Timer SCNT0..SCNT8 node istype 'reg'; "Sample Counter R1..R12 node istype 'com,keep'; "Ring Oscillator Bit TXS0..TXS5 node istype 'reg,pos'; "Transmitter State ACTIVE node istype 'reg,keep'; "Active period of 32-kHz TXD node istype 'com,keep'; "Transmitter Done TCKD0..TCKD4 node istype 'reg'; "Transmit Clock Divider TCKDZ node istype 'reg,keep'; "Transmit Clock Divider Zero ADC0..ADC3 node istype 'reg'; "ADC Bits TTS0..TTS3 node istype 'reg'; "Transmit Time Shift SDOS node istype 'reg,keep'; "SDO Synchronized YSEL node istype 'reg'; "Select Channel Y for Transmission YCONV node istype 'reg'; "Select Channel Y for Conversion BIT node istype 'com,keep'; "The output bit value RDS node istype 'reg,keep'; "Read Sample SCKEN node istype 'reg,keep'; "SCK Enable "Sets "==== "Sample Timer, depends upon ck_divisor to eliminate unused bits. "Likewise, the active time, which is the moment during the period "at which we transmit a sample, depends upon how many bits we have "in the Sample Timer. @IF (ck_divisor == 4) { "Frequency 8192 SPS, scatter is +-1 ticks. st = [ST1..ST0]; active_time = [0,TTS0]; } @IF (ck_divisor == 8) { "Frequency 4096 SPS, scatter is +-2 ticks. st = [ST2..ST0]; active_time = [0,TTS1,TTS0]; } @IF (ck_divisor == 16) { "Frequency 2048 SPS, scatter is +-4 ticks. st = [ST3..ST0]; active_time = [0,TTS2,TTS1,TTS0]; } @IF (ck_divisor == 32) { "Frequency 1024 SPS, scatter is +-8 ticks. st = [ST4..ST0]; active_time = [0,TTS3,TTS2,TTS1,TTS0]; } @IF (ck_divisor == 64) { "Frequency 512 SPS, scatter is +-8 ticks. st = [ST5..ST0]; active_time = [0,0,TTS3,TTS2,TTS1,TTS0]; } @IF (ck_divisor == 128) { "Frequency 256 SPS, scatter is +-8 ticks. st = [ST6..ST0]; active_time = [0,0,0,TTS3,TTS2,TTS1,TTS0]; } @IF (ck_divisor == 256) { "Frequency 128 SPS, scatter is +-8 ticks. st = [ST7..ST0]; active_time = [0,0,0,0,TTS3,TTS2,TTS1,TTS0]; } @IF (ck_divisor == 512) { "Frequency 64 SPS, scatter is +-8 ticks. st = [ST8..ST0]; active_time = [0,0,0,0,0,TTS3,TTS2,TTS1,TTS0]; } "Transmit Clock Divider, depends upon tck_divisor to eliminate unused "bits @IF (tck_divisor <= 4) { tckd = [TCKD1..TCKD0]; } @IF (tck_divisor >= 5) & (tck_divisor <= 8) { tckd = [TCKD2..TCKD0]; } @IF (tck_divisor >= 9) & (tck_divisor <= 16) { tckd = [TCKD3..TCKD0]; } @IF (tck_divisor >= 17) { tckd = [TCKD4..TCKD0]; } txs = [TXS5..TXS0]; "Transmitter State adc_bits = [ADC3..ADC0]; "ADC Bits transmit_time_shift = [TTS3..TTS0]; "Transmit Time Shift frequency = [F4..F0]; "Frequency Voltage for Five-Bit DAC "Constants "========= num_sync_bits=11; "Number of synchronizing bits at transmission start. num_id_bits = 4; "Number of ID bits num_start_bits = 1; "Transmitted zero to mark data start num_stop_bits = 2; "Not transmitted, for txs termination num_data_bits = 16; "Number of ADC data bits num_xmit_bits = "Number of transmission bit periods num_sync_bits + num_start_bits + num_id_bits + num_data_bits + num_id_bits; txs_done = "Final state of txs machine num_xmit_bits + num_stop_bits; first_sync_bit = 1; first_start_bit = first_sync_bit + num_sync_bits; first_id_bit = first_start_bit + num_start_bits; first_data_bit = first_id_bit + num_id_bits; first_cc_bit = first_data_bit + num_data_bits; start_sck = "The txs state for first SCK falling edge first_data_bit - 1; end_sck = "The txs state for last SCK falling edge start_sck + num_data_bits - 1; equations "The Sample Timer runs off the 32.678-kHz clock and counts up to "ck_divisor-1 to give a sample period of 32.768 kHz divided "by ck_divisor. st.clk=CK; when (st==ck_divisor-1) then { st:=0; } else { st:=st+1; } "The End Clock (ECK) is a positive pulse that coincides with "the Sample Timer being zero. We set up the ECK pulse when st "is at its maximum value. ECK.clk=CK; ECK:=(st==ck_divisor-1); "When ACTIVE is asserted, we begin a burst transmission. "When it is unasserted, we reset the burst transmission "state machine. We assert ACTIVE in the CK period after "the one in which the Sample Timer matches the active time. "This active time is a Galoise linear shift register fed "by the least significant bit of the ADC output, and so should "be well-randomised to provide transmission scatter. ACTIVE.clk=CK; ACTIVE:=(st==active_time); "Transmit Done (TXD) is true when the transmitter completes "its burst transmission. TXD=(txs==txs_done); "We change the channel ID depending upon whether we are "transmitting X or Y. id = base_id; cc = 15 - base_id + set_num; "The ring oscillator turns on when ACTIVE and remains "on until TXD. Each gate in the ring adds 2 ns to the "delay around the ring. The period of the oscillation is "4 ns multiplied by the number of gates. @IF (ring_length == 2) { [FCK,R1]=[R1,!FCK & ACTIVE & !TXD]; } @IF (ring_length == 3) { [FCK,R1..R2]=[R1..R2,!FCK & ACTIVE & !TXD]; } @IF (ring_length == 4) { [FCK,R1..R3]=[R1..R3,!FCK & ACTIVE & !TXD]; } @IF (ring_length == 5) { [FCK,R1..R4]=[R1..R4,!FCK & ACTIVE & !TXD]; } @IF (ring_length == 6) { [FCK,R1..R5]=[R1..R5,!FCK & ACTIVE & !TXD]; } @IF (ring_length == 7) { [FCK,R1..R6]=[R1..R6,!FCK & ACTIVE & !TXD]; } @IF (ring_length == 8) { [FCK,R1..R7]=[R1..R7,!FCK & ACTIVE & !TXD]; } @IF (ring_length == 9) { [FCK,R1..R8]=[R1..R8,!FCK & ACTIVE & !TXD]; } @IF (ring_length == 10) { [FCK,R1..R9]=[R1..R9,!FCK & ACTIVE & !TXD]; } @IF (ring_length == 11) { [FCK,R1..R10]=[R1..R10,!FCK & ACTIVE & !TXD]; } @IF (ring_length == 12) { [FCK,R1..R11]=[R1..R11,!FCK & ACTIVE & !TXD]; } @IF (ring_length == 13) { [FCK,R1..R12]=[R1..R12,!FCK & ACTIVE & !TXD]; } "The transmit clock divider runs off FCK and divides FCK down "to 5 MHz by correct choice of fck_divisor during transmitter "calibration. We compute two constants from fck_divisor. One "is tck_divisor, which sets the transmit clock period as a "multiple of the fast clock period. The other is ring_length, "which sets the number of gates in the ring oscillator that "generates the fast clock. We enable the transmit clock divider "only when the transmitter is active. tckd.aclr=!ACTIVE; tckd.clk=FCK; when (tckd==tck_divisor-1) then { tckd:=0; } else { tckd:=tckd+1; } "We detect the transmit clock divider being zero with TCKDZ. We "clear TCKDZ to zero when the transmitter is inactive. TCKDZ.aclr=!ACTIVE; TCKDZ.clk=FCK; TCKDZ:=(tckd==0); "The transmit clock should be close to or a little less than 5 MHz, "with a duty cycle of exactly 50%. Each time the transmit clock "counts down to zero, we invert the transmit clock. TCK.aclr=!ACTIVE; TCK.clk=TCKDZ; TCK:=!TCK; "The transmitter state machine steps through all its "states when ACTIVE is asserted, and then stops in its "final state, waiting for !ACTIVE, which will reset the "transmitter state to zero. txs.aclr=!ACTIVE; txs.clk=TCK; when (txs==txs_done) then txs:=txs else txs:=txs+1; "Transmit sixteen ADC bits. when (txs>0) & (txs=1)&(txs =first_data_bit)&(txs =start_sck-2) & (txs<=end_sck+1); CSS = ECK # RDS; "We clock the ADC bits out of the chip as we transmit them. The "ADC produces new bits on the falling edge of SCK. We use !TCK for "SCK during the readout. We want to avoid glitches on the SCK output, "so we enable SCK with a flag that goes HI on the rising edge of TCK "as txs enters start_sck, then goes LO on the rising edge of TCK when "txs enters end_sck. When SCKEN rises, !TCK has already fallen, so the "combination of SCKEN and !TCK will be LO until !TCK rises. When SCKEN "falls, !TCK has already fallen, so SCK will already be falling. SCKEN.clk = TCK; SCKEN := (txs>=start_sck-1) & (txs<=end_sck-1); SCK = SCKEN & !TCK; "We sample SDO on the rising edge of TCK, trusting that it has been "read out of the ADC on the falling edge of TCK. SDOS.clk = TCK; SDOS := SDO; "Test Points "=========== TP1=(frequency==frequency_low+frequency_step); TP2=ACTIVE; "Forcing Outputs. We assign TP3 to be a function of the "thirteen chip pin whose pads we use to route power to "the power pins at the center of the 8x8 ball grid array. "Without this declaration, these balls are treated by the "compiler as unconnected, and are assigned pull-up resistors "that consume current. We want to set them to HOLD in the "contraint manager. LOUT=([VL3..VL0] != 0) & ([GND9..GND0] != 0) & TDI; END