MODULE P3028 TITLE 'P3028A' "NOTE: For all versions, make sure you have the global input constraint" "set to HOLD rather than PULLUP or PULLDOWN. Set the input constraint in the" "constraint editor, and when compiling this code, instruct the compiler to" "merge the constraints in this file (pin numbers) with the constraints from" "the constraint editor (input hold)." "Version 1 [27-FEB-18] Based upon P3028A15. This code transfers the functionality" "of P3028A to the LC4064ZE in csBGA-64 of the A3028PV1 circuit. This circuit provides" "only one input channel, but we preserve the other input in the logic in case we make" "a version with two channels at a future date." "Version 2 [01-JUN-18] Allocate new version numbers and letters for the A3028P" "transmitters. Version Px has version number x." "Version 3 [18-JAN-19] Add versions S1..S5 and S1Z..S5Z. These latter five are DC" "transmitters that require uniform sampling." "[07-JAN-22] use for A3028PV1, PV2, and up-coming PV3." declarations "Configuration Parameters" "========================" "Version | Number | Description" "------------------------------" " P1 1 128 SPS 40 Hz" " P2 2 256 SPS 80 Hz" " P3 3 512 SPS 160 Hz" " P4 4 1024 SPS 320 Hz" " P5 5 2048 SPS 640 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" " S1Z 6 128 SPS 40 Hz, no scatter" " S2Z 7 256 SPS 80 Hz, no scatter" " S3Z 8 512 SPS 160 Hz, no scatter" " S4Z 9 1024 SPS 320 Hz, no scatter" " S5Z 10 2048 SPS 640 Hz, no scatter" " T1 1 128 SPS 40 Hz" " T2 2 256 SPS 80 Hz" " T3 3 512 SPS 160 Hz" " T4 4 1024 SPS 320 Hz" " T5 5 2048 SPS 640 Hz" "Set the transmitter version number" VERSION = 1; "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," channel_num = 1; "The set number is the channel number divided by sixteen." set_num = channel_num / 16; "The base identifier is the channel number modulo sixteen." base_id = channel_num % 16; "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 = 27; "Frequency Low, use to center transmit spectrum in range 913-918 MHz." frequency_low = 7; "Parameters" "==========" "Version-Dependent Parameters Set Automatically. Note that the main body of" "this program presumes the existence of a Y-channel, which does not exist in" "the A3028P. We disable the Y-channel in all versions of the A3028P firmware." @IF (VERSION == 1) { ck_divisor=256; "Total Sample Rate 128 SPS enable_x=1; "X Input Enabled 128 SPS" enable_y=0; "Y Input Disabled 128 SPS" regular_sampling=0; "Sample with scatter" } @IF (VERSION == 2) { ck_divisor=128; "Total Sample Rate 256 SPS enable_x=1; "X Input Enabled 256 SPS" enable_y=0; "Y Input Disabled 0 SPS" regular_sampling=0; "Sample with scatter" } @IF (VERSION == 3) { ck_divisor=64; "Total Sample Rate 512 SPS enable_x=1; "X Input Enabled 512 SPS" enable_y=0; "Y Input Disabled 0 SPS" regular_sampling=0; "Sample with scatter" } @IF (VERSION == 4) { ck_divisor=32; "Total Sample Rate 1024 SPS enable_x=1; "X Input Enabled 512 SPS" enable_y=0; "Y Input Disabled 0 SPS" regular_sampling=0; "Sample with scatter" } @IF (VERSION == 5) { ck_divisor=16; "Total Sample Rate 2048 SPS enable_x=1; "X Input Enabled 2048 SPS" enable_y=0; "Y Input Disabled 0 SPS" regular_sampling=0; "Sample with scatter" } @IF (VERSION == 6) { ck_divisor=256; "Total Sample Rate 128 SPS enable_x=1; "X Input Enabled 128 SPS" enable_y=0; "Y Input Disabled 128 SPS" regular_sampling=1; "Sample without scatter" } @IF (VERSION == 7) { ck_divisor=128; "Total Sample Rate 256 SPS enable_x=1; "X Input Enabled 256 SPS" enable_y=0; "Y Input Disabled 0 SPS" regular_sampling=1; "Sample without scatter" } @IF (VERSION == 8) { ck_divisor=64; "Total Sample Rate 512 SPS enable_x=1; "X Input Enabled 512 SPS" enable_y=0; "Y Input Disabled 0 SPS" regular_sampling=1; "Sample without scatter" } @IF (VERSION == 9) { ck_divisor=32; "Total Sample Rate 1024 SPS enable_x=1; "X Input Enabled 1024 SPS" enable_y=0; "Y Input Disabled 0 SPS" regular_sampling=1; "Sample without scatter" } @IF (VERSION == 10) { ck_divisor=16; "Total Sample Rate 2048 SPS enable_x=1; "X Input Enabled 2048 SPS" enable_y=0; "Y Input Disabled 0 SPS" regular_sampling=1; "Sample without scatter" } "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 3." "A ring length of 2 runs too fast, causing glitches and counter failure." "The maximum ring length in this code is 13, but ultimately is limited by the" "available logic outputs. The tck_divisor must be 2 or greater. We need at least" "two divider states to create a symmetric transmit clock signal. And tck_divisor" "must also be less than 32 because we have at most five divisor bits in this" "code. As a result of these restrictions, some fck_divisor values do not have" "their own unique and correct combination of tck_divisor * ring_length. These are" "values 11, 13, 17, 19, 23, 29, 31, and 34." @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 = 2; ring_length = 5;} @IF (fck_divisor == 12) {tck_divisor = 4; ring_length = 3;} @IF (fck_divisor == 13) {tck_divisor = 4; ring_length = 3;} @IF (fck_divisor == 14) {tck_divisor = 2; ring_length = 7;} @IF (fck_divisor == 15) {tck_divisor = 5; ring_length = 3;} @IF (fck_divisor == 16) {tck_divisor = 4; ring_length = 4;} @IF (fck_divisor == 17) {tck_divisor = 4; ring_length = 4;} @IF (fck_divisor == 18) {tck_divisor = 6; ring_length = 3;} @IF (fck_divisor == 19) {tck_divisor = 6; ring_length = 3;} @IF (fck_divisor == 20) {tck_divisor = 5; ring_length = 4;} @IF (fck_divisor == 21) {tck_divisor = 7; ring_length = 3;} @IF (fck_divisor == 22) {tck_divisor = 2; ring_length = 11;} @IF (fck_divisor == 23) {tck_divisor = 8; ring_length = 3;} @IF (fck_divisor == 24) {tck_divisor = 8; ring_length = 3;} @IF (fck_divisor == 25) {tck_divisor = 5; ring_length = 5;} @IF (fck_divisor == 26) {tck_divisor = 2; ring_length = 13;} @IF (fck_divisor == 27) {tck_divisor = 9; ring_length = 3;} @IF (fck_divisor == 28) {tck_divisor = 7; ring_length = 4;} @IF (fck_divisor == 29) {tck_divisor = 7; ring_length = 4;} @IF (fck_divisor == 30) {tck_divisor = 6; ring_length = 5;} @IF (fck_divisor == 31) {tck_divisor = 6; ring_length = 5;} @IF (fck_divisor == 32) {tck_divisor = 8; ring_length = 4;} @IF (fck_divisor == 33) {tck_divisor = 11; ring_length = 3;} @IF (fck_divisor == 34) {tck_divisor = 11; ring_length = 3;} @IF (fck_divisor == 35) {tck_divisor = 7; ring_length = 5;} @IF (fck_divisor == 36) {tck_divisor = 9; ring_length = 4;} "Other Parameters" frequency_step=2; "HI frequency - LO frequency" enable_rf=1; "Turns on RF oscillator during transmission" @IF (enable_x == 1) { x_id = base_id; y_id = base_id + 1; } @IF (enable_x == 0) { x_id = base_id + 1; y_id = base_id; } "Channel ID" I3..I0 node istype 'com'; "Transmitter ID nodes" id = [I3..I0]; "Completion Code" CC3..CC0 node istype 'com'; "Completion Code Bits" cc =[CC3..CC0]; "Inputs and Outputs" "==================" CK pin F1; "Clock From 32-kHz Oscillator" F4..F0 pin E1,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" TP3 pin H4 istype 'com'; "Test Point" CONV pin C8 istype 'com'; "Convert for ADC" SDO pin A6; "Serial Data Out for ADC" SCK pin A5 istype 'com'; "Serial Clock for ADC" SDI pin A7 istype 'com,pos'; "Serial Data In for ADC" L0..L12 pin A2,A3,B4,C4,E6,E7,E8,G1,G2,G3,G4,G5,F5; "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" "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]; } "Sample Counter, depends upon enable_y to eliminate unused bits." @IF (enable_y <= 15) { scnt =[SCNT3..SCNT0]; } @IF (enable_y == 31) { scnt =[SCNT4..SCNT0]; } @IF (enable_y == 63) { scnt =[SCNT5..SCNT0]; } @IF (enable_y == 127) { scnt =[SCNT6..SCNT0]; } @IF (enable_y == 255) { scnt =[SCNT7..SCNT0]; } @IF (enable_y == 511) { scnt =[SCNT8..SCNT0]; } "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_iid_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 ECK clock occurs at the end of each sample period." ECK.clk=CK; ECK:=(st==ck_divisor-2); "The Sample Counter counts sample periods and allows us to decide" "which input to digitize and which channel number to apply to each" "sample transmission. We increment the counter at the end of each" "sample period. When the counter reaches enable_y, it returns to zero." scnt.clk=ECK; when (scnt == enable_y) then { scnt:=0; } else { scnt:=scnt+1; } "We assert YSEL when the next transmit cycle's sample transmission" "should receive the Y-input channel number." YSEL.clk=ECK; YSEL:=((scnt == 1) & (enable_y > 0)) # (enable_x == 0); "We assert YCONV when the conversion that occurs at the end of the" "next sample transmission should be a conversion of the Y-input." YCONV.clk=ECK; YCONV:= ((scnt == 0) & (enable_y > 0)) # (enable_x == 0); "When ACTIVE is asserted, we begin a burst transmission." "When it is unasserted, we reset the burst transmission" "state machine. We must make sure that ACTIVE remains true" "for long enough for the burst transmission to complete." "ACTIVE becomes true when the Sample Timer reaches the active" "time set at the end of the previous sample period. This" "active time is made up of the lower four bits of the sample" "transmitted in the previous sample period. Because these" "four bits are dominated by noise, they are random and so" "produce a random disturbance of the transmit instant, which" "avoids systematic collisions between transmitters." ACTIVE.clk=CK; ACTIVE:=(st==active_time); "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." when YSEL then { id = y_id; cc = 15 - y_id + set_num; } else { id = x_id; cc = 15 - x_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) & (txs<=end_sck) & !TCK; "We configure the ADC for single-ended input by setting" "SDI to 1 on the first rising edge of SCK after CONV goes" "low." when txs==start_sck then SDI=1; "We select ADC channel that will be digitized at the end" "of the CONV pulse with the value of SDI on the second" "rising edge of SCK after CONV goes low. With SDI = 0, the" "next sample from the ADC will be of X. But note that this" "selection does not affect the sample being read out by SCK" "during the CONV low pulse. The YSEL signal tells us that" "Y is being read out now, and YCONV means we should digitize" "Y at the end of this transmission." when txs==start_sck+1 then SDI=YCONV; "Test Points" TP1=(frequency==frequency_low+frequency_step); TP2=CK; "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." TP3=[L12..L0] != 0; END