"
MODULE P3013

TITLE 'P3013A'

"Firmware Version 4, Last Modified 28-FEB-07"

"This code supports analog and reference transmitters,"
"through analog_transmitter, and 5 MBPS and 2.5 MBPS"
"through tcd_divisor and half_tcd_divisor."

"The code defines constants for the transmission states"
"so you don't have to go through and change more than"
"one constant when you alter the message encoding."

"You set the logic 0 (LO) and 1 (HI) bit frequencies"
"in terms of five-bit ADC counts that drive the oscillator's"
"TUNE input. The LO frequency is at frequency_low. The HI"
"frequency is at frequency_low + frequency_step."

"To enable transmissions of the auxilliary channel, set"
"aux_period to the auxilliary sample period in multiples"
"of 1.953 ms. The auxilliary samples will replace main"
"channel samples. If you set aux_period to zero, the"
"auxilliary channel is disabled. The maximum value of"
"aux_period supported by this firmware is 8."


declarations

"Parameters"
analog_transmitter=1; "Analog or reference transmitter"
aux_period=8; "Set to 1 to activate second channel."
I3=0;I2=1;I1=0;I0=0; "Transmitter Identifier"
frequency_low=9; "LO frequency."
frequency_step=2; "HI frequency - LO frequency"
tcd_divisor=25; "Divide ring oscillator to get TCK (52 or 25)"
half_tcd_divisor=14; "Sets mark-space ratio of TCK (27 or 14)"
enable_rf=1; "Turns on RF oscillator during transmission"
num_sync_bits=11; "Number of synchronizing bits at transmission start."

"Inputs and Outputs"
CK pin 38; "Clock From 32-kHz Oscillator"
RY pin 9 istype 'com'; "Relay Connection"
F0..F4 pin 46,48,47,2,10 istype 'reg'; "DAC for frequency"
!SHDN pin 40 istype 'com'; "Shutdown Control for Transmitter"
TP1 pin 24 istype 'com'; "Test Point"
CONV pin 26 istype 'com'; "Convert for ADC"
SDI pin 34 istype 'com,pos'; "Serial Data In for ADC"
SDO pin 33; "Serial Data Out for ADC"
SCK pin 31 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"
PMS1..PMS0 node istype 'reg,pos'; "Power Master State"
RYOE node istype 'com,keep'; "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"
RSC3..RSC0 node istype 'reg'; "Reference Signal Counter"
AUX2..AUX0 node istype 'reg'; "Auxilliary Transmission Counter"
AUXSEL node istype 'com'; "Auxilliary Select"
AUXID node istype 'reg'; "Auxilliary ID"

"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"
ref_signal_count = [RSC3..RSC0]; "Reference Signal Counter"
aux = [AUX2..AUX0]; "Auxilliary Transmission Counter"

"Constants"
tck_divisor = 64; "max transmit cycle timer + 1"
pms_asleep_magnet = 0;
pms_asleep_no_magnet = 1;
pms_awake_magnet = 2;
pms_awake_no_magnet = 3;
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"
time.clk=CK;
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);

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

"The Power Master watches RY.pin and turns on and off"
"transmission as if the relay were a push-button."
pms.clk=CK;
state_diagram pms;
  state pms_asleep_no_magnet:
    if !RY.pin then pms_awake_magnet
    else pms_asleep_no_magnet;
  state pms_asleep_magnet:
    if RY.pin then pms_asleep_no_magnet
    else pms_asleep_magnet;
  state pms_awake_no_magnet:
    if !RY.pin then pms_asleep_magnet
    else pms_awake_no_magnet;
  state pms_awake_magnet:
    if RY.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=CK;
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==txs_done);

"We select the Auxilliary Channel whenever the auxilliary"
"counter is equal to aux_period-1."
when aux_period==0 then {
  AUXSEL=0;
} else {
  aux.clk=TXD;
  when aux==aux_period-1 then aux:=0
  else aux:=aux+1;
  AUXSEL=(aux==0);
}

"We choose the auxilliary channel ID for transmission in the"
"active cycle after we selected the channel."
  AUXID.clk=TXD;
  AUXID:=AUXSEL;

"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 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%."
TCK.aclr=!ACTIVE;
TCK.clk=FCK;
TCK:=(tcd>0) & (tcd0) & (txs=first_sync_bit)&(txs=first_start_bit)&(txs0) & (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;

"We select the main or auxilliary channel by setting"
"SDI equal to 1 for main (channel 1) and 0 for auxilliary"
"(channel 0) on the second rising edge of SCK after CONV"
"goes low. This selection affects the next ADC conversion."
when txs==start_sck+1 then SDI=!AUXSEL;

"Test Points"
TP1=(frequency==frequency_low+frequency_step);

END