module P2060 title 'P2060' "[24-JUN-10] H-Bridge Version. Remove uneccessary code from" "the P2060C01 file to make this one. Direct DC1 and DC2 to" "IO1 and IO2 directly to being the control of the H-bridge" "auxilliary circuits." "[20-JUL-10] H-Bridge Version 2. Put a one second limit on" "signals sent to the H-Bridge." "[1-AUG-10] H-Bridge Version 3. Allows an LWDAQ user to set" "the speed at which the motor turns using pulse width" "modulation. The hex LWDAQ command can range from 0000" "(0 in decimal) to 00FF (255). A 0080 (128) tells the motor" "not to move. A 0000 is max speed in one direction. FFFF is" "max speed in the other direction. The pulse width modulation" "combines pulses on both output pins." "[5-AUG-10] H-Bridge Version 4. Changes the pulse width" "modulation so that pulses only occur on one pin. In this" "version, the speed is controlled by the first seven DC bits." "Direction is controlled by the eighth. 0000 and 0080 represent" "no movement. 00FF represents maximum movement in one direction" "and 007F represents maximum movement in the other." "[27-SEP-10] H-Bridge Version 5. Faster switching frequency." "[17-MAR-11] H-Bridge Version 6. Added physical forward/reverse switches." "[17-MAR-11] H-Bridge Version 7. Added ability to renew 1 second commands" "by resending the command." "[24-MAY-11] Add power on indicator (TP1) and change CD to MCD plus a" "few other cosmetic changes, but no change to the way the code works." "Add timeout_count parameter. Added MCR node to reset the motor counter," "which avoids creation of 26 separate reset nodes by the compiler." "Increased motor counter to 32 bits to make sure we can handle longer" "timeouts in future." "[25-MAY-11] Change H-Bridge switching period to 400 us, was 100 us." "The switching frequency is 2.5 kHz. This is audible, but the power" "dissipated in the mosfets due to the switching energy is four times" "less. At 10 kHz, they were over-heating to the point where they melted" "their sockets." declarations "Parameters" enable_timeout=1; "Enables the timeout that turns off the motor." timeout_count=80000000; "Number of 40 MHz clock periods for timeout" "Pins" A pin 12;"LVDS input" B pin 64 istype 'com';"LVDS output" !RESET pin 37;"RESET" CK pin 38;"40 MHz clock input" WAKE pin 66 istype 'com';"WAKE" LB pin 65 istype 'com';"Loop Back, enables LVDS driver" TP1..TP4 pin 69,70,71,72 istype 'com';" LED16..LED1 pin 41..44,47..50,53..56,58..61 istype 'com'; IO5..IO10 pin 8,9,10,11,14,15 istype 'com'; IO1 pin 3 istype 'com'; IO2 pin 4 istype 'com'; IO3 pin 5; IO4 pin 6; "Nodes" SA node istype 'reg';"Synchornized A." DA node istype 'com';"Delayed SA" DDA node istype 'com';"Delayed Delayed SA" ACTIVE node istype 'reg';"transmission active" D1..D9 node istype 'reg';"delay pipeline." DRS0..DRS2 node istype 'reg';"Command Receiver State" CS node istype 'com';"Command Strobe" NCS node istype 'com';"New Command Strobe" AS node istype 'com';"Address Strobe" NAS node istype 'com';"New Address Strobe" DS node istype 'com';"Data Strobe" ER,Q1..Q16 node istype 'reg';"Receiver Bits" DA0..DA15 node istype 'reg';"Device Address Bits" DC1..DC16 node istype 'reg';"Device Command Bits" "Sets" drs=[DRS2..DRS0];"Command Receiver State" equations "Serial Input Decoding" "---------------------" "We synchronize the incoming LVDS logic signal to" "our 40-MHz clock." SA:=A; SA.clk=CK; "We put SA through a pipeline of registers clocked" "with CK so that we can generate the delayed timing" "pulses from the rising edge of SA." [D1..D9]:= [SA,D1..D8]; [D1..D9].clk= CK; [D1..D9].aclr=RESET; "Delayed SA provides is asserted for one CK period 125 ns" "after any rising edge of SA. We use DA and SA to obtain" "the LWDAQ data bit. If SA is high with DA, the data bit" "is one." DA = D4 & !D5; "Delayed Delayed SA is asserted for one CK period 250 ns" "after any rising edge of SA. We use DDA and SA to obtain" "the LWDAQ ACTIVE bit. If SA is low with DDA, ACTIVE is" "true." DDA = D8 & !D9; "We assert ACTIVE whenever the driver is transmitting" "a command data bit." ACTIVE.clk=CK; ACTIVE.aclr=RESET; when !SA & DDA then ACTIVE:=1; when SA & DDA then ACTIVE:=0; when !DDA then ACTIVE:=ACTIVE; "We clock the receiver shift register and the entry" "register with CK, and we clear them on RESET." [ER,Q1..Q16].clk=CK; [ER,Q1..Q16].aclr=RESET; "We shift the receiver bits whenever we have DA" "asserted. We clock the current value of SA into" "the entry register (ER), and shift all the other" "bits over by one. At the beginning of a LWDAQ" "transmission, ER contains a 1 if the transmission" "is a command, and 0 if it is an address. At the" "end of a transmission, ER contains a 1, and Q1" "to Q16 contain the transmitted sixteen-bit word," "either address or command." when DA then [ER,Q1..Q16]:=[SA,ER,Q1..Q15]; else [ER,Q1..Q16]:=[ER,Q1..Q16].fb; "Data Receiver" "-------------" "Data Receiver states." declarations rest=0; command_receive=1; clock_command_register=2; address_receive=3; clock_address_register=4; new_command_strobe=5; new_address_strobe=6; equations drs.clk=CK; drs.aclr=RESET; state_diagram drs; "Stay in the rest state until we receive ACTIVE." "When ACTIVE, we proceed with command receive" "if the data bit in ER is one, otherwise an address" "receive." state rest: if ACTIVE then { if ER then command_receive else address_receive; } else rest; "We stay in command_receive until !ACTIVE." state command_receive: if !ACTIVE then clock_command_register else command_receive; "As we pass through clock_command_register we" "indicate that it is time to clock the receiver" "bits into the command register." state clock_command_register:goto new_command_strobe; "As we pass through new_command_strobe we start" "any action that should be taken when the new command" "arrives. The variable NCS is true when drs is in" "the new_command_strobe state." state new_command_strobe:goto rest; "We stay in address_receive until !ACTIVE." state address_receive: if !ACTIVE then clock_address_register; else address_receive ; "As we pass through clock_address_register we" "indicate that it is time to clock the receiver" "bits into the address register." state clock_address_register:goto new_address_strobe; "As we pass through new_address_strobe we start" "any action that should be taken when the new address" "arrives. The variable NAS is true when drs is in" "the new_address_strobe state." state new_address_strobe:goto rest; equations "Command Strobe is asserted for one CK period at the" "end of a command transmission from the LWDAQ driver." CS = (drs==clock_command_register); "New Command Strobe follows CS when the new command" "is already established in the DC registers." NCS = (drs==new_command_strobe); "Address Strobe is asserted for one CK period at the" "end of an address transmission from the LWDAQ driver." AS = (drs==clock_address_register); "New Address Strobe follows AS when the new address" "is already established in the DA registers." NAS = (drs==new_address_strobe); "Data Strobe is asserted for one CK period after a" "solitary low pulse from the LWDAQ driver. The driver" "uses solitary low pulses that endure for 125 ns and" "are followed by a > 375 ns high pulse to initiate" "serial transmission of data from LWDAQ devices of type" "data_device, like this one." DS = (SA & DDA & (drs==rest)); "We clock the receiver bits into the command register" "on CS." [DC1..DC16].clk=CK; [DC1..DC16].aclr=RESET; when CS then [DC1..DC16]:=[Q1..Q16] else [DC1..DC16]:=[DC1..DC16]; "We clock the receiver bits into the address register" "on AS." [DA0..DA15].clk=CK; [DA0..DA15].aclr=RESET; when AS then [DA0..DA15]:=[Q1..Q16] else [DA0..DA15]:=[DA0..DA15].fb; "We wake up the +-15V power when DC8 is set." WAKE = DC8; "We enable the return LVDS driver when DC7 is set." when DC7 then LB = 1; "We loop back the synchronized value of A to the driver" "so long as DC5 is not set. On a data_device like this one," "!DC5 is required for loop-back." when !DC5 then B = SA; "H-Bridge Driver" "===============" declarations "Nodes" MC0..MC31 node istype 'reg';"Motor Counter" MCR node istype 'com,keep'; "Motor Counter Reset" PU0..PU6 node istype 'reg';"Pulse Up Counter" ON node istype 'reg';"Motor On" PULSE node istype 'reg';"Apply Pulse to Motor" MCB0F node istype 'com,keep';"Counter Byte 0 Full" MCB1F node istype 'com,keep';"Counter Byte 1 Full" MCB2F node istype 'com,keep';"Counter Byte 2 Full" MC6D node istype 'reg'; "MC6 Delayed" "Sets" mcb0=[MC7..MC0]; "motor counter byte zero" mcb1=[MC15..MC8]; "motor counter byte one" mcb2=[MC23..MC16]; "motor counter byte two" mcb3=[MC31..MC24]; "motor counter byte three" mcb=[MC31..MC0]; "motor counter" equations "Counter Byte Full nodes." MCB0F=(mcb0==255); MCB1F=(mcb1==255); MCB2F=(mcb2==255); "When command strobe is high, ON gets clocked high. ON is" "then unchanged until the counter reaches one second. If" "the one second limit is imposed, ON is then cleared." ON.clk=CK; when CS then { ON:=1 } else { when !CS & enable_timeout & (mcb==timeout_count) then { ON:=0; } else { ON:=ON; } } "Splits up the large counter into several small ones." "Increments counter byte 0. If it was already at zero," "increments counter byte 1. If counter byte 1 was already" "at zero, increments counter byte 2." mcb.clk=CK; MCR = (!ON) # CS; mcb.aclr=MCR; when ON then mcb0:=mcb0+1; else mcb0:=mcb0; when MCB0F & ON then mcb1:=mcb1+1; else mcb1:=mcb1; when MCB1F & MCB0F & ON then mcb2:=mcb2+1; else mcb2:=mcb2; when MCB2F & MCB1F & MCB0F & ON then mcb3:=mcb3+1; else mcb3:=mcb3; "Clocks are set. MC7 Delayed is the same as MC7 but delayed" "by one clock cycle." [PU6..PU0].clk=CK; PULSE.clk=CK; MC6D.clk=CK; MC6D:=MC6; "MC13..MC6 is zero every 400 us. Pulse Up Counter is set to" "the first seven bits of the device command. These represent" "the speed. When these bits are set, PU starts counting down," "decrementing after the falling edge of MC6. When it reaches" "zero, the motor turns off and waits until the next time our "chosen counter bits (MC13..MC6) are zero.When the speed is" "at its maximum, the entire cycle (except for one MC6 tick)" "is taken up by the PU counter so PULSE is nearly always high" "and the motor is nearly always running." when ([MC13..MC6]==0) $ ([MC13..MC6]==1) then { [PU6..PU0] := [DC7..DC1]; when ([DC7..DC1]==0) then PULSE:=0 else PULSE:=1; } else { when !MC6 & MC6D then [PU6..PU0] := [PU6..PU0]-1 else [PU6..PU0]:=[PU6..PU0]; when ([PU6..PU0] == 0) then PULSE:=0 else PULSE:=PULSE; } "Outputs" "=======" [LED1..LED16] = [DC1..DC16]; TP1 = 1; TP2 = WAKE; TP3 = IO1; TP4 = IO2; IO1 = (PULSE & ON & DC8) # (!IO3); IO2 = (PULSE & ON & !DC8) # (!IO4); end