"
MODULE P3009

TITLE 'P3009A'

"Firmware Version 5, Last Modified 26-APR-06"

declarations

"Parameters"
analog_transmitter=0; "Analog or reference transmitter"
active_input=0; "Select the active input channel."
I3=0;I2=0;I1=1;I0=1; "Transmitter Identifier"
frequency_mid=7; "Average of 0 and 1 transmission frequencies"
frequency_range=2; "Deviation from mid frequency."
tcd_divisor=24; "Divide ring oscillator to get TCK."
half_tcd_divisor=14; "Sets mark-space ratio of TCK"
enable_rf=1; "Turns on the RF Oscillator During Transmission"

"Inputs and Outputs"
CK pin K8; "Clock From 32-kHz Oscillator"
RCK pin A5; "Slow Clock, or Global CLK0, Connected to Pin 44"
RCKO pin A4; "Source of RCK"
FCK pin H6; "Fast Clock, or Global CLK1 Connected to Pin 17"
FCKO pin H5 istype 'com'; "Source of CK1"
TCK pin K6; "Transmission Clock, or Global CLK2 Connected to Pin 20"
TCKO pin K7 istype 'reg'; "Source of CK2"
ECK pin C5; "Global CLK3 Connected to Pin 41"
ECKO pin C6 istype 'reg'; "Source of CK3"
RELAY pin D8 istype 'com'; "Relay Connection"
F0..F4 pin A3,A2,A1,C1,D1 istype 'reg'; "DAC for frequency"
!SHDN pin H7 istype 'com'; "Shutdown Control for Transmitter"
TP1..TP3 pin H1,G1,F1 istype 'com'; "Test Points for J1"
CONV pin C10 istype 'com'; "Convert for ADC"
SDI pin D10 istype 'com,pos'; "Serial Data In for ADC"
SDO pin E10; "Serial Data Out for ADC"
SCK pin G10 istype 'com'; "Serial Clock for ADC"

"Nodes"
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'; "Transmitter Done"
PMS1..PMS0 node istype 'reg,pos'; "Power Master State"
RELAYOE node istype 'com'; "Drive Relay Ouput"
TCD5..TCD0 node istype 'reg'; "Transmit Clock Divider"
ADC0..ADC3 node istype 'reg'; "ADC Bits"
TTS0..TTS3 node istype 'reg'; "Transmit Time Shift"
SDOS node istype 'reg'; "SDO Synchronized"

"Sets"
time = [T5..T0]; "Transmit Cycle Timer"
tcd = [TCD5..TCD0]; "Transmit Clock Divider"
txs = [TXS5..TXS0]; "Transmitter State"
pms = [PMS1..PMS0]; "Power Master 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"

"Constants"
pms_asleep_magnet = 0;
pms_asleep_no_magnet = 1;
pms_awake_magnet = 2;
pms_awake_no_magnet = 3;
num_xmit_bits = 36; "number of transmission bit periods"
txs_start_sck = 16; "txs state for first SCK falling edge"
txs_end_sck = 30; "txs state for last SCK falling edge"
tck_divisor = 64; "max transmit cycle timer + 1."

equations

"We set RCK, one of the global clock pins, equal to"
"the 32-kHz input via the RCKOT pin."
RCKO=CK;

"The transmit cycle timer runs off the 32-kHz clock"
time.clk=RCK;
time:=time+1;

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

"The RELAY pin is connected to 0V through a reed relay"
"and a resistor. Whever transmit_cycle becomes zero, we"
"drive the RELAY pin high for the next half-period of"
"RCK. The Power Master checks the voltage on the RELAY"
"pin at the next rising edge of RCK. If the relay is"
"closed, RELAY.pin will be LO. If the relay is open,"
"the bus hold circuits on the input will hold RELAY.pin"
"HI."
RELAY=1;
RELAYOE=(time==0) & CK;
RELAY.oe=RELAYOE;

"The Power Master watches RELAY.pin and turns on and off"
"transmission as if the relay were a push-button."
pms.clk=RCK;
state_diagram pms;
  state pms_asleep_no_magnet:
    if !RELAY.pin then pms_awake_magnet
    else pms_asleep_no_magnet;
  state pms_asleep_magnet:
    if RELAY.pin then pms_asleep_no_magnet
    else pms_asleep_magnet;
  state pms_awake_no_magnet:
    if !RELAY.pin then pms_asleep_magnet
    else pms_awake_no_magnet;
  state pms_awake_magnet:
    if RELAY.pin then pms_awake_no_magnet
    else pms_awake_magnet;
equations


"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=RCK;
ACTIVE:=
    (time==active_time) & (pms==pms_awake_no_magnet)
  # (time==active_time) & (pms==pms_awake_magnet);

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

"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"
"therefore 4 ns multiplied by the number of gates. Here"
"we use only two gates to give us a ring frequency of"
"125 MHz. The higher frequency makes our approximation"
"of the nominal bit transmission time accurate to half a"
"period, or +-4ns."
[FCKO,R1]=[R1,!FCKO & ACTIVE & !TXD];

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

"Here we set the mark-space ratio of TCK0 to roughly 50%."
TCKO.aclr=!ACTIVE;
TCKO.clk=FCK;
TCKO:=(tcd>0) & (tcd0) & (txs0) & (txs=17)&(txs<=32)&(SDOS$TCK) "ADC bits 15 down to 0"
      # (txs==33)&(!I3$TCK) "!id bit 3"
      # (txs==34)&(!I2$TCK) "!id bit 2"
      # (txs==35)&(!I1$TCK) "!id bit 1"
      # (txs==36)&(!I0$TCK) "!id bit 0"
       ) then {frequency := frequency_mid+frequency_range} "transmit a 1"
      else {frequency := frequency_mid-frequency_range} "transmit a 0"
  } else {frequency := 0;} "stops DAC current drain"
}

"The adc_bits register has different functions in"
"a reference and analog transmitter, but the same clock."
adc_bits.clk=TCK;

"In an analog transmitter, we record the lower ADC bits"
"so they may be used to set xmit_time_shift. Transmit"
"Time Shift dictates the next ACTIVE period by its"
"inclusion in active_time."
when analog_transmitter then {
  when (txs==28) then ADC3:=SDOS
  else ADC3:=ADC3;
  when (txs==29) then ADC2:=SDOS
  else ADC2:=ADC2;
  when (txs==31) then ADC1:=SDOS
  else ADC1:=ADC1;
  when (txs==32) then ADC0:=SDOS
  else ADC0:=ADC0;
  xmit_time_shift.clk=ECK;
  xmit_time_shift:=adc_bits;
} 

"In a reference transmitter, we use adc_bits to create"
"a square wave, and we set xmit_time_shift to zero."
when !analog_transmitter then {
  when (txs==num_xmit_bits) then adc_bits:=adc_bits+1
  else adc_bits:=adc_bits;
  xmit_time_shift.clk=ECK;
  xmit_time_shift:=0;
}

"SHDN turns off the RF transmitter"
when enable_rf then {
  SHDN=(txs==0)#TXD;
} else {
  SHDN=1;
}

"The CONV input to the ADC provokes conversion on"
"its rising edge, and must be low during readout."
"We don't want to leave it low any longer than we"
"have to, because the ADC goes to sleep only after"
"it is done converting following a CONV rising"
"edge, and when CONV is staying HI."
CONV=(txs==0)#TXD;

"We synchronize SDO with TCK."
SDOS.clk = TCK;
SDOS := SDO;

"We clock the ADC bits out of the chip as we transmit"
"them, so we have no need for a register in which"
"to save them."
SCK = (txs>=txs_start_sck) & (txs<=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==txs_start_sck then SDI=1;

"We select the active or reference channel by setting"
"SDI equal to 0 for active and 1 for reference on the"
"second rising edge of SCK after CONV goes low."
when txs==txs_start_sck+1 then SDI=!active_input;

"Test Points"
TP1=SHDN;
TP2=ACTIVE;
TP3=(frequency==frequency_mid+frequency_range);

END