"
module P2100A title 'P2100A' "Version 6: [16-JAN-08] We add code to allow the "LTC1865L to be operated in positive-polarity differential "mode. " "Version 5: [16-JAN-08] Finished RAM storage and "retrieval. Code is now fully-functional and fully- "tested with AD1865L. Have yet to test with AD7980 "or AD7982. "Version 4: [11-JAN-08] Slowed down SCK so we can "operate TLC1865 as well as the faster AD-series "ADCs. Remove 1 MHz sample rate. We simplify the "logic by adjusting the number of sample thresholds "and adding some dedicated nodes. We start the sss "machine with an instruction. Compile time is now "5 s and we use 136 out of 256 logic outputs. "Version 3: [10-JAN-08 We add the SRC, NSC, RST, "and SSS instructions. We implement a sample timer, "data address, sample session state machine, and "ADC state machine. "Version 2: [09-JAN-08] We add connections for the "analog multiplexer and ADCs. We remove the message "receiver code of P3007C04, which we don't need. Add "Instruction Processor and Analog Multiplexer. "Version 1: [27-DEC-07] This is the P3007C04 code, modified "to account for the new pin assignments in the A2100, but "not including the new outputs that drive the CMOS switches. "We set the A3007C's comparator input (C) to zero, so the "firmware will receive no messages, and store only timestamps. "We set the message clock equal to the data clock, and use an "80-MHz clock input to generate the data clock and synchronise "the reference clock. declarations fake_data=0; channel_0_id=1; channel_1_id=2; equations "Pins" declarations A pin 3; "LVDS input" B pin 10 istype 'com'; "LVDS output" C=0; "Comparator Output" LB pin 8 istype 'com'; "Loop Back" !RESET pin 22;"Hardware Reset" ARCK pin 38; "Asynchronous 32.768 kHz reference clock input" FCK pin 39; "Fast Clock 80 MHz." !RW pin 59 istype 'com,pos'; "RAM Write" !RCE pin 66 istype 'reg,pos'; "RAM Chip Enable" !ROE pin 6 istype 'com,pos'; "RAM Output Enable" RA18..RA0 pin 85,80,79,78,16,17,19,31,30,53, 54,55,56,58,67,69,70,71,72 istype 'reg'; "RAM Address" RD7..RD0 pin 9,11,14,15,60,61,64,65 istype 'com'; "RAM Data" ram_data = [RD7..RD0]; RECORD pin 97 istype 'com'; "Receive Indicator, through monostable" UPLOAD pin 94 istype 'com'; "Upload Indicator, through monostable" EMPTY pin 98 istype 'com'; "Empty Indicator, direct to LED" TP1 pin 47 istype 'com'; "Test Point 1" TP2 pin 48 istype 'com'; "Test Point 2" SS1 pin 41 istype 'com'; "Serial Select ADC 1" SCK1 pin 42 istype 'com'; "Serial Clock ADC 1" SDI1 pin 43 istype 'com'; "Serial Data In ADC 1" SDO1 pin 44; "Serial Data Out ADC 1" SS2 pin 35 istype 'com'; "Serial Select ADC 2" SCK2 pin 34 istype 'com'; "Serial Clock ADC 2" SDI2 pin 36 istype 'com'; "Serial Data In ADC 2" SDO2 pin 28; "Serial Data Out ADC 2" SVR1 pin 84 istype 'reg'; "Select ADC 1 Voltage Reference" SVA1 pin 50 istype 'reg'; "Select ADC 1 Voltage Analog" SVL1 pin 49 istype 'reg'; "Select ADC 1 Voltage Logic" SVR2 pin 86 istype 'reg'; "Select ADC 2 Voltage Reference" SVA2 pin 87 istype 'reg'; "Select ADC 2 Voltage Analog" SVL2 pin 93 istype 'reg'; "Select ADC 2 Voltage Logic" ON pin 29 istype 'reg'; "WAKE, turns on fixed voltages" SVB pin 92 istype 'com'; "Select Voltage Bottom Reference" SVT pin 81 istype 'reg'; "Select Voltage Top Reference" equations "Data Clock Generation" "---------------------" declarations DCK node istype 'reg'; "Data Clock" equations "We divide the 80 MHz clock by two to create" "the data clock." DCK.clk=FCK; DCK:=!DCK; "Reference Clock" "---------------" declarations RCK node istype 'reg'; "Reference Clock" equations "We synchronise the incoming 32.768 kHz clock" "to DCK to create RCK." RCK.clk=DCK; RCK:=ARCK; "LWDAQ Command and Address Decoding" "----------------------------------" "This LWDAQ receiver uses the 40-MHz data clock to generate" "the DA and DDA signals. We synchronise the incoming serial" "logic signal, A, with the data clock." declarations SA node istype 'reg'; "Synchronized A" DSA node istype 'reg'; "Delayed SA" DA node istype 'com,keep'; "Delayed A Rising Edge" DDA node istype 'com,keep'; "Delayed DA" AA node istype 'reg'; "Address Active" DAA node istype 'reg'; "Delayed AA" CA node istype 'reg'; "Command Active" DCA node istype 'reg'; "Delayed CA" ER,Q1..Q16 node istype 'reg'; "Receiver Bits" LT3..LT0 node istype 'reg'; "LWDAQ Timer" lt = [LT3..LT0]; AS node istype 'reg'; "Address Strobe" CS node istype 'reg'; "Command Strobe" DS node istype 'reg'; "Data Strobe" DC1..DC16 node istype 'reg';"Device Command Bits" DA0..DA15 node istype 'reg';"Device Address Bits" WAKE node istype 'com'; "WAKE" DTX node istype 'com'; "Device Transmit" equations "We synchronize A with DCK, and provide a delayed" "version of A that allows us to detect edges." [SA,DSA].clk = DCK; [SA,DSA].aclr = RESET; SA := A; DSA := SA; "This timer allows us to generate the Delayed A (DA)" "and Double-Delayed A (DDA) signals for serial reception." lt.clk = DCK; lt.aclr = RESET; when lt==^d0 then { when SA & !DSA then lt:=1 else lt:=0; } else { when lt==9 then lt:=0 else lt:=lt+1; } DA = (lt==4); DDA = (lt==9); "We use DCK to clock the receiver registers, and RESET to" "clear them." [ER,Q1..Q16,AA,DAA,AS,CA,DCA,CS,DS,DC1..DC16,DA0..DA15].clk = DCK; [ER,Q1..Q16,AA,DAA,AS,CA,DCA,CS,DS,DC1..DC16,DA0..DA15].aclr = RESET; "We move bits along the shift register on DA." when DA then [ER,Q1..Q16] := [SA,ER,Q1..Q15]; else [ER,Q1..Q16] := [ER,Q1..Q16]; "Address Active provides a pulse that begins with DDA" "on the start bit of an address transmission, and ends" "with the stop bit of an address transmission. Delayed" "AA allows us to create Address Strobe, or AS. Address" "Strobe provides a pulse at the end of an address" "reception. We clock the receiver bits into the address" "register on a rusing edge of AS." when DDA then AA := (!AA & !CA & !SA & !ER) # (AA & !SA) else AA := AA; DAA := AA; AS := DAA & !AA; when AS then [DA0..DA15] := [Q1..Q16] else [DA0..DA15] := [DA0..DA15]; "Command Active provides a pulse that begins with DDA" "on the start bit of a command transmission, and ends" "with the stop bit of a command transmission. Delayed" "CA allows us to create Command Strobe, or CS. Command" "strobe provides a pulse at the end of each command" "reception. We clock the receiver bits into the command" "register on a rising edge of CS." when DDA then CA := (!AA & !CA & !SA & ER) # (CA & !SA) else CA := CA; DCA := CA; CS := DCA & !CA; when CS then [DC1..DC16] := [Q1..Q16] else [DC1..DC16] := [DC1..DC16]; "Data Strobe identifies a solitary stop bit on A. A" "solitary stop bit, combined with DTX, indicates that" "the driver is expecting a byte transfer." DS := DDA & SA & !AA & !CA; "Device Transmit Bit" DTX = DC5; "We loop back A to B so long as DTX is not set." when !DTX then B = A; "We enable the return LVDS driver when DC7 is set." LB = DC7; "WAKE bit." WAKE = DC8; "Instruction Processor" "---------------------" "The instruction bits are Q16 down to Q9. We don't use" "the latched bits DC16 down to DC9 for the same reason" "we don't use DC6 in IS (see below)." declarations IS node istype 'com,keep'; "Instruction Strobe" instruction = [Q16..Q9]; operation = [Q16..Q13]; argument = [Q12..Q9]; NOP = 0; SSS = 1; SFV = 2; CMC = 3; SRC = 4; NSC = 5; RST = ^hF; IRST node istype 'com,keep'; "Instruction Reset" equations "When we receive a command with DC6 (called DRX in data" "devices like this) set to 1, we execute DC16..DC9 (called" "I7..I0 in the A2100) as an instruction. The IS (instruction" "strobe) signal provokes execution. We use Q6 instead of DC6" "in the strobe equation because Q6 is valid on the rising edge" "of CS, but DC6 is clocked some time during the assertion of" "CS." IS = CS & Q6; "The instruction reset is provoked by the instruction" "command or by the hardware reset." IRST = (IS & (operation == RST)) # RESET; "Fixed Voltages" "--------------" ON.ap = IRST; ON.clk = DCK; when IS & (operation == SFV) then ON := (argument > 0); else ON := ON; "Analog Multiplexer" "------------------" "Here we interpret the current measurement channel number, as" "set by the CMC operation, and select one of the eight current" "measurement channels. We select SVB by default because it is" "stable and small. Its analog return is not large enough to interfere" "with the digital return." [SVR1,SVA1,SVL1,SVR2,SVA2,SVL2,SVT].aclr = IRST; [SVR1,SVA1,SVL1,SVR2,SVA2,SVL2,SVT].clk = DCK; when IS & (operation == CMC) then { SVT := (argument == ^h1); SVR1 := (argument == 2); SVA1 := (argument == 3); SVL1 := (argument == 4); SVR2 := (argument == 5); SVA2 := (argument == 6); SVL2 := (argument == 7); } else { [SVR1,SVA1,SVL1,SVR2,SVA2,SVL2,SVT] :=[SVR1,SVA1,SVL1,SVR2,SVA2,SVL2,SVT] } SVB = !SVT & !SVR1 & !SVA1 & !SVL1 & !SVR2 & !SVA2 & !SVL2; "Number of Samples Code" "----------------------" declarations NSC0..NSC3 node istype 'reg'; "Number of Samples Code" nsc=[NSC3..NSC0]; equations nsc.aclr = IRST; nsc.clk = DCK; when IS & (operation == NSC) then { nsc := argument; } else { nsc := nsc; } "Sample Rate Code" "----------------" declarations SRC0..SRC3 node istype 'reg'; "Sample Rate Code" src=[SRC3..SRC0]; equations src.aclr = IRST; src.clk = DCK; when IS & (operation == SRC) then { src := argument; } else { src := src; } "Data Address" "------------" declarations DAI node istype 'reg,pos'; "Data Address Increment" DAR node istype 'reg,pos'; "Data Address Reset" data_addr = [RA18..RA0]; "Data Address" num_samples = [RA18..RA3]; "Number of Samples" equations "The data address is the RAM address at which we store" "sample bytes and read sample bytes. We increment the" "data address on the rising edge of DAI." data_addr.clk = DAI; data_addr.aclr = DAR; data_addr:=data_addr+1; "Data Transmitter" "----------------" "The transmitter sends bytes back to the driver. It waits for" "DS combined with DTX (DC5). When it receives DS and DTX, it" "waits for Transmission Byte Load (TBL). The transmitter uses" "DCK to time its serial transmission to the driver. It transmits" "a leading zero followed by the eight bits of the transmission" "byte (tb)." declarations TS4..TS0 node istype 'reg'; "Transmit State" TB7..TB0 node istype 'reg'; "Transmission Bits" ts=[TS4..TS0];"Transmission State" tb=[TB7..TB0]; "Transmission Byte" TBL node istype 'com,keep'; "Transmitter Byte Load" TBO node istype 'com,keep'; "Transmitter Bit Out" FDC0..FDC2 node istype 'reg'; "Fake Data Counter" fdc=[FDC2..FDC0]; FD0..FD7 node istype 'reg'; "Fake Data" fd=[FD7..FD0]; equations "The Transmit Byte, tb, holds a byte for transmission to" "the LWDAQ driver. We clock it on the rising edge of DCK." tb.clk = DCK; tb.aclr = RESET; "The Transmitter State, ts, controls serial transmission" "to the LWDAQ driver of the Transmi Byte." ts.clk = DCK; ts.aclr = RESET; state_diagram ts; state ^d0:if DS & DTX then 1 else 0; state 1: if !DTX then 0; if DTX & TBL then 2; if DTX & !TBL then 1; state 2:goto 3;"Start Bit" state 3:goto 4;"Start Bit" state 4:goto 5;"TB7" state 5:goto 6;"TB7" state 6:goto 7; state 7:goto 8; state 8:goto 9; state 9:goto 10; state 10:goto 11; state 11:goto 12; state 12:goto 13; state 13:goto 14; state 14:goto 15; state 15:goto 16; state 16:goto 17; state 17:goto 18; state 18:goto 19;"TB0" state 19:goto 20;"TB0" state 20:goto 0;"Stop Bit" equations; "TBO is the output of the bit transmitter. It passes through" "the LVDS return and so along the cables to the driver." TBO = ( (ts==0) & 1 "Idle Bit 1" # (ts==1) & 1 "Idle Bit 1" # (ts==2) & 0 "Start Bit 0" # (ts==3) & 0 "Start Bit 0" # (ts==4) & TB7 # (ts==5) & TB7 # (ts==6) & TB6 # (ts==7) & TB6 # (ts==8) & TB5 # (ts==9) & TB5 # (ts==10) & TB4 # (ts==11) & TB4 # (ts==12) & TB3 # (ts==13) & TB3 # (ts==14) & TB2 # (ts==15) & TB2 # (ts==16) & TB1 # (ts==17) & TB1 # (ts==18) & TB0 # (ts==19) & TB0 # (ts==20) & 1 "Stop Bit 1" ); "We return TBO to the driver when DTX is set." when DTX then B = TBO; "We load the transmitter byte from the RAM data bus. When" "some other part of the firmware asserts TBL." when !fake_data then { when TBL then tb:=ram_data.pin; else tb:=tb; } "We can generate fake data to check for errors in the" "upload to the LWDAQ driver, as opposed to errors in" "RF reception. The Recorder instrument will interpret" "the fake data as a time stamp." fdc.clk=DCK; fdc.aclr=IRST; fd.clk=DCK; fd.aclr=IRST; when fake_data then { TBL=1; when (ts==20) then fdc:=fdc+1; else fdc:=fdc; when (fdc==0) then tb:=1; when (fdc==1) then tb:=fd; when (fdc==2) then tb:=fd; when (fdc==3) then tb:=fd; when (fdc==4) then tb:=2; when (fdc==5) then tb:=fd; when (fdc==6) then tb:=fd; when (fdc==7) then tb:=fd; when (ts==20) & (fdc==7) then fd:=fd+1; else fd:=fd; } "Sample Session" "--------------" declarations SSS1..SSS0 node istype 'reg'; "Sample Session State" sss = [SSS1..SSS0]; ASS0..ASS5 node istype 'reg'; "ADC Sample Sate" ass = [ASS5..ASS0]; ST0..ST15 node istype 'reg'; "Sample Timer" st = [ST15..ST0]; STR node istype 'reg'; "Sample Timer Reset" START node istype 'com,keep'; "Start Sample Session" SDI node istype 'com,pos,keep'; "Serial Data Into ADC" equations "We need the START node to reduce the number" "of logic inputs to the sss state machine." START = IS & (operation == SSS); "The sample session state counts samples and" "terminates sample sessions." sss.aclr = IRST; sss.clk = DCK; state_diagram sss; state ^d0: if START then 1 else 0; state 1: if (nsc == 0) then "50" 1; if (nsc == 1) then { "51" if (num_samples >= 64) then 2 else 1 } if (nsc == 2) then { "52" if (num_samples >= 512) then 2 else 1 } if (nsc == 3) then { "53" if (num_samples >= 5120) then 2 else 1 } if (nsc == 4) then { "54" if (num_samples >= 50176) then 2 else 1 } if (nsc >= 5) then "55-5F" 2; state 2: goto 3; state 3: goto 0; equations "The ADC state determines the sample rate and operates" "the serial interface with the ADCs." ass.aclr = IRST; ass.clk = DCK; when (ass == 0) then { when (sss == 1) then ass := 1 else ass:=0; } when (ass >= 1) & (ass <= 62) then { ass := ass+1; } when (ass == 63) then { when (src == 0) then { "40 0Hz" ass := 63; } when (src == 1) then { "41 1kHz" when (st == 40000-2) then ass := 0 else ass := 63 } when (src == 2) then { "42 2kHz" when (st == 20000-2) then ass := 0 else ass := 63 } when (src == 3) then { "43 5kHz" when (st == 8000-2) then ass := 0 else ass := 63 } when (src == 4) then { "44 10kHz" when (st == 4000-2) then ass := 0 else ass := 63 } when (src == 5) then { "45 20kHz" when (st == 2000-2) then ass := 0 else ass := 63 } when (src == 6) then { "46 50kHz" when (st == 800-2) then ass := 0 else ass := 63 } when (src == 7) then { "47 100kHz" when (st == 400-2) then ass := 0 else ass := 63 } when (src == 8) then { "48 200kHz" when (st == 200-2) then ass:=0 else ass := 63 } when (src == 9) then { "49 500kHz" when (st == 80-2) then ass := 0 else ass := 63 } when (src >= 10) then { "4B-4F 1.25MHz" ass := 0; } } "We reset the sample timer whenever ass is zero." "We use a dedicated node for the reset signal. By" "resetting with the .aclr input instead of in logic," "we allow the chip to implement the sample timer" "as a synchronous ripple counter made out of T-type" "flip-flops, which greatly decreases the number of" "logic terms the sample counter requires." STR.clk = DCK; STR := (ass == 0); st.aclr = STR; st.clk = DCK; st:=st+1; "We select the ADC for serial transfer for 37 periods" "of DCK, which is 925 ns. The serial clock runs at 20 MHz." "during the transfer, and provides 18 falling edges to" "clock out up to 18 bits from the ADC. !SS1 = (ass >= 1) & (ass <= 37); SCK1 = !ASS0 & (ass >= 1) & (ass <= 36); "The clocks, serial select and incoming data lines" "for the second ADC are the same as the first." SS2 = SS1; SCK2 = SCK1; "The SDI lines onfigure the ADCs. For the LTC1865, the" "values of SDI on the first and second rising edges of" "SCK after we assert SS set the SGL/DIFF and ODD/SIGN" "bits respectively. With SGL/DIFF set to 1, the ADC has" "two single-ended inputs, in which case ODD/SIGN selects" "channel 0 or 1. With SGL/DIFF set to 0, the ADC has" "one differential input made by subtracting one input" "from the other. With ODD/SIGN set to 0, the channel 0" "input is the positive differential input. For the AD7980" "and AD7982 we leave SDI always 1." when (ass >= 0) & (ass <= 2) then SDI = 0; "SGL/DIFF" when (ass >= 3) then SDI = 0; "ODD/SIGN" SDI1 = SDI; SDI2 = SDI; "Data Receiver" "-------------" declarations ADC1D0..ADC1D17 node istype 'reg'; "ADC 1 Data" ADC2D0..ADC2D17 node istype 'reg'; "ADC 2 Data" equations "We clock the data shift register with the same" "clock we use to shift data out of the ADC. If" "the data bit shifts with !SCK (falling edge of" "SCK) at the ADC, we use this same edge to clock" "the existing bit into our shift register. By" "this means, we give the ADC as much time as" "possible to establish the bit value at our SDO" "input. We expect the most significant bit first" "out of the ADC, which is the case with the" "AD7980, AD7982, and the LTC1865L." [ADC1D0..ADC1D17].clk = !SCK1; [ADC1D0..ADC1D17].aclr = IRST; [ADC1D17..ADC1D0] := [ADC1D16..ADC1D0,SDO1]; [ADC2D0..ADC2D17].clk = !SCK2; [ADC2D0..ADC2D17].aclr = IRST; [ADC2D17..ADC2D0] := [ADC2D16..ADC2D0,SDO2]; "Data Storage" "------------" declarations RDOE node istype 'com,pos,keep'; "RAM Data Output Enable (from this chip)" store_start = 48; RRS0..RRS1 node istype 'reg'; "RAM Read State" rrs=[RRS1..RRS0]; equations "We increment DAI with the rising edge of FCK so we can" "give DAI a short pulse on consecutive rising edges of DCK." "The data address is clocked by DAI." DAI.clk = FCK; "We reset the data address at the end of a sample" "session, or on IRST." DAR.clk = DCK; DAR := (sss == 3) # IRST; "We clock the ram chip enable with !FCK so we can generate" "a 12.5-ns pulse on either side of the falling or rising" "edge of DCK." RCE.clk = !FCK; "We enable the logic chip's ram data drivers with our" "dedicated RDOE (ram data output enable). The ram chip's" "own data line drivers we enable with a separate signal" "called ROE (ram output enable)." ram_data.oe = RDOE; "From ass state store_start to store_start+7 we are storing" "an eight-byte sample." when (ass >= store_start) & (ass <= store_start+7) then { DAI := !DCK; "increment the data address after this state" RW = 1; "write to RAM" ROE = 0; "disable data lines from RAM." RCE := DCK; "select RAM either side of falling DCK edge." RDOE = 1; "drive data lines to RAM" when (ass == store_start+0) then ram_data = channel_0_id; when (ass == store_start+1) then ram_data = [ADC1D17..ADC1D10]; when (ass == store_start+2) then ram_data = [ADC1D9..ADC1D2]; when (ass == store_start+3) then ram_data = [ADC1D1,ADC1D0,0,0,0,0,0,0]; when (ass == store_start+4) then ram_data = channel_1_id; when (ass == store_start+5) then ram_data = [ADC2D17..ADC2D10]; when (ass == store_start+6) then ram_data = [ADC2D9..ADC2D2]; when (ass == store_start+7) then ram_data = [ADC2D1,ADC2D0,0,0,0,0,0,0]; } "When ts (the transmitter state) is 1, the transmitter is waiting" "for a byte to send to the driver. We give it the byte by asserting" "TBL for one DCK period around the rising edge of DCK. We set up" "the byte on the ram_data pins before this rising edge. We provide" "data only when there is no sample session running." rrs.clk = DCK; rrs.aclr = IRST; state_diagram rrs; state ^d0: if (sss == 0) & (ts == 1) then 1; else 0; state 1: goto 2; state 2: goto 3; state 3: if (ts != 1) # (sss != 0) then 0; else 3; equations when (rrs == 1) then { DAI := 0; "increment data address after this state." RW = 0; "read from RAM" ROE = 1; "enable the RAM data outputs." RCE := 1; "select RAM 6.25 ns after rising edge of DCK" RDOE = 0; "disable data lines to RAM" TBL = 1; "load transmit byte from ram pins at state end." } when (rrs == 2) then { DAI := 1; "ncrement the data address" RW = 0; "read from RAM" ROE = 1; "enable the RAM data outputs." RCE := 0; "de-select RAM 6.25 ns after rising edge of DCK" RDOE = 0; "disable data lines to RAM" TBL = 0; "don't load again." } "Indicators Lamps" "----------------" RECORD = RDOE; UPLOAD = DS; EMPTY = (data_addr == 0); "Test Points" "-----------" TP1 = SS1; TP2 = DS; end