"

MODULE P3028

TITLE 'P3028A'

"NOTE: For all versions, make sure the compiler sets all inputs"
"to input HOLD rather than PULLUP or PULLDOWN."

"Version 1 [19-SEP-13] Based upon P3019A02. We change pin numbers to suit the"
"layout of the A3028. We modify the auxilliary channel code to support two main"
"channels at the same sample rate, or one channel either X or Y."

"Version 2 [31-DEC-13] Change the ring oscillator calibration so as to guarantee"
"the mark-space ratio is 50%, sacrificing frequency resolition."

declarations

"A3028A mouse-sized transmitter with two 512 SPS channels."
"A3028B mouse-sized transmitter with one 512 SPS channel."
"A3028D rat-sized transmitter with two 512 SPS channels."
"A3028E rat-sized transmitter with one 512 SPS channel."

"Channel Number (Channel X)"
x_id = 9;
y_id = x_id + 1;
DUAL_CHANNEL = 1;

"Calibration Parameters"
fck_divisor=12; "Fast Clock Divisor, gives 5 MHz from ring oscillator."
frequency_low=7; "LO frequency."

"Version-Dependent Parameters Set Automatically"
@IF (DUAL_CHANNEL == 1) {
  tck_divisor=32; "max transmit cycle timer + 1"
  enable_x=1; "enables x input"
  enable_y=1; "enables y input"
}
@IF (DUAL_CHANNEL == 0) {
  tck_divisor=64; "max transmit cycle timer + 1"
  enable_x=1; "enables x input"
  enable_y=0; "enables y input"
}

"Other Parameters"
scatter_xmit=1; "Turn on scattering of transmission instants."
frequency_step=2; "HI frequency - LO frequency"
enable_rf=1; "Turns on RF oscillator during transmission"
enable_test_pins=1; "Disable for final program, saves 2uA."

"Channel ID"
I3..I0 node istype 'com'; "Transmitter ID nodes"
id = [I3..I0];

"Inputs and Outputs"
CK pin K9; "Clock From 32-kHz Oscillator"
F4..F0 pin C10,D10,E10,G10,H10 istype 'reg'; "DAC for frequency"
!SHDN pin D1 istype 'com'; "Shutdown Control for Transmitter"
TP1 pin K7 istype 'com'; "Test Point"
TP2 pin F1 istype 'com'; "Test Point"
TP3 pin G1 istype 'com'; "Test Point"
CONV pin H1 istype 'com'; "Convert for ADC"
SDI pin K5 istype 'com,pos'; "Serial Data In for ADC"
SDO pin K4; "Serial Data Out for ADC"
SCK pin H4 istype 'com'; "Serial Clock for ADC"

"Nodes"
FCK node istype 'com,keep'; "Fast Clock"
TCK node istype 'reg'; "Transmission Clock"
ECK node istype 'reg'; "End Clock"
T0..T5 node istype 'reg'; "Timer Running off 32-kHz"
R1 node istype 'com,keep'; "Ring Oscillator Bit"
TXS0..TXS5 node istype 'reg,pos'; "Transmitter State"
ACTIVE node istype 'reg'; "Active period of 32-kHz"
TXD node istype 'com,keep'; "Transmitter Done"
TCD3..TCD0 node istype 'reg'; "Transmit Clock Divider"
TCDZ node istype 'reg'; "Transmit Clock Divider Zero"
ADC0..ADC3 node istype 'reg'; "ADC Bits"
TTS0..TTS3 node istype 'reg'; "Transmit Time Shift"
SDOS node istype 'reg'; "SDO Synchronized"
RSC3..RSC0 node istype 'reg'; "Reference Signal Counter"
XSEL node istype 'reg'; "Auxilliary Select"

"Sets"
time = [T5..T0]; "Transmit Cycle Timer"
tcd = [TCD3..TCD0]; "Transmit Clock Divider"
txs = [TXS5..TXS0]; "Transmitter State"
adc_bits = [ADC3..ADC0]; "ADC Bits"
xmit_time_shift = [TTS3..TTS0]; "Transmit Time Shift"
active_time = [0,0,TTS3..TTS0]; "Active Time"
frequency = [F4..F0]; "Frequency Voltage"
ref_signal_count = [RSC3..RSC0]; "Reference Signal Counter"

"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 transmit cycle timer runs off the 32-kHz clock and"
"counts up to tck_divisor-1."
time.clk=CK;
when (time==tck_divisor-1) then {
  time:=0;
} else {
  time:=time+1;
}

"The ECK clock sets the active_time register at the"
"end of a cycle of tck_divisor CK periods."
ECK.clk=CK;
ECK:=(time==tck_divisor-2);

"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.clk=CK;
ACTIVE:= (time==active_time);

"TXD is true when the transmitter completes its burst"
"transmission."
TXD=(txs==txs_done);

"We alternate between input channels with XSEL, which we"
"toggle every time we are done with a transmission."
XSEL.clk=TXD;
when enable_x & enable_y then XSEL:=!XSEL
else when enable_x then XSEL:=1
else XSEL:=0;

"We change the channel ID depending upon whether we are"
"transmitting X or Y."
when XSEL then id = x_id
else id = y_id;

"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."
[FCK,R1]=[R1,!FCK & ACTIVE & !TXD];

"The transmit clock divider runs off FCK and divides it down"
"to 5 MHz by correct choice of fck_divisor during transmitter"
"calibration."
tcd.aclr=!ACTIVE;
tcd.clk=FCK;
when (tcd==0) then {
  tcd:=fck_divisor-1;
}
when (tcd>0) then {
  tcd:=tcd-1;
}

"We detect the transmit clock divider being zero with TCDZ."
TCDZ.clk=FCK;
TCDZ.aclr=!ACTIVE;
TCDZ:=(tcd==0);

"The transmit clock should be close to or a little less than 5 MHz,"
"with a mark-space ratio of exactly 50%. So we clock it with the top"
"bit of the transmit clock divider."
TCK.aclr=!ACTIVE;
TCK.clk=TCDZ;
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 it"
"to zero."
txs.clk=TCK;
txs.aclr=!ACTIVE;
when (txs==txs_done) then txs:=txs
else txs:=txs+1;

"We clock frequency with the rising edge of FCK."
frequency.clk=FCK;

"Transmit sixteen ADC bits."
when ACTIVE & (txs>0) & (txs=1)&(txs=first_start_bit)&(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;

"The value of SDI on the second rising edge of SCK after"
"CONV determines which of the ADC's two input channels"
"will be digitized on the next conversion. With SDI set"
"to 0 we will digitize X, and with SDI set to 1 we will"
"digitize Y.Because XSEL indicates that we are about to"
"transmit the value of X digitized after the previous"
"CONV pulse, we select Y when XSEL is asserted."
when txs==start_sck+1 then SDI=!XSEL;

"Test Points"
when (enable_test_pins != 0) then {
  TP1=(frequency==frequency_low+frequency_step);
  TP2=CK;
  TP3=SCK;
} {
  TP1=0;
  TP2=0;
  TP3=0;
}

END