'Clock Stamp.bsp ' {$STAMP BS2p} ' {$PBASIC 2.5} ' {$PORT COM9} 'Version Info '======================================================== 'Clock Stamp program, designed for BASIC stamp BS2P40 version 1.5 'Last Updated Friday, May 16, 2008 'version 0 Version CON 0 'Compiler directives '======================================================== #DEFINE DebugMode = 0 'Notes '======================================================== 'The Clock stamp is responsible for controlling the 8254 timer 'and all associated logic, in order to produce the programmable 'dwell time and programmable number of pulses 'this stamp also gates the channel advance out to the various peripheral 'devices and controls the logic which stops the clock in the event of a 'stop pulse received from a peripheral device 'The stamp communicates with the 8254 programable timer/counter chip through 'the following pins ' BASIC stamp pin 8254 pin ' X0 D0 ' X1 D1 ' X2 D2 ' X3 D3 ' X4 D4 ' X5 D5 ' X6 D6 ' X7 D7 ' X8 A0 ' X9 A1 ' X10 !CS ' X11 !RD ' X12 !WR 'The Clock Stamp uses various pins to control discrete electronic 'components, as well as monitor them. 'OUTPUTS: The outputs are all on the main IO line ' BASIC stamp pin Function ' 5 On/Off (level) ' 6 On/Off set (pulse) ' 7 Mode Select (level) 'INPUTS:The inputs are on the aux IO line ' BASIC stamp pin Function ' X13 Clock Status input ' X14 One-Shot Status input 'The upper byte of the Main IO is dedicated to the active level control of outputs ' BASIC stamp pin Function ' 8 Gate 0 ' 9 Gate 1 ' 10 Gate 2 ' 11 Gate 3 ' 12 Gate 4 ' 13 Gate 5 ' 14 Gate 6 ' 15 Gate 7 (Internal Channel Advance) 'finally, the Clock Stamp communicates with the Master Stamp through the 'Stamp Bus ' BASIC stamp pin Function ' 0 Serial Data ' 1 Serial Flow (RTS) ' 2 Channel Advance (output for Clock stamp only) ' 3 Attention (in) ' 4 Acknowledge (out) 'Stamp Bus Packet format: ' ' Byte Content ' 0 Packet size ' 1 Command ' 2+ Data 'PINS '======================================================== 'pins for 8254 communication (Aux ports only) WR PIN 12 RD PIN 11 CS PIN 10 A1 PIN 9 A0 PIN 8 'pins for discrete electronics control (Main ports only) OnOff PIN 5 OnOffSet PIN 6 ModeSelect PIN 7 'pins for status input read (Aux ports only) ActiveStatus PIN 13 OneShotStatus PIN 14 'note: pins 8 to 15 are accessed using the OUTH on the main ports 'pins for STAMP bus BusData PIN 0 BusFlow PIN 1 ChAdv PIN 2 'NOTE: this doesn't need to be assigned for clock stamp Attention PIN 3 AttAck PIN 4 'Variables and Registers '======================================================== 'Values used for operation of the Clock Envelope DwellTime VAR Word PassCount VAR Word OpMode VAR Byte DeviceEnable VAR Byte 'bitmask for NAND gated outputs 'the 8254 8-bit parallell data bus, stored in an internal register until its ready to 'be written to the bus, or read from the bus DataBus VAR Byte 'counter variables, used when programming a counter on the 8254 Counter VAR Word N VAR Word Mode VAR Byte CWRValue VAR Byte 'Latch variables, used to debounce transitions of inputs AttLatch VAR Bit 'variables used for stamp bus data transfer Packets VAR Byte(4) 'constants used for serial communication configuration T38K4 CON 45 Inverted CON $4000 Baud CON T38K4 + Inverted 'indexers and dummy variables i VAR Byte 'Main Code '======================================================== Startup: #IF DebugMode >= 1 #THEN DEBUG "Clock Stamp Initializing", CR, CR #ENDIF MAINIO OUTH = $00 'set pins 8 through 15 to low DIRH = %11111111 'set pins 8 through 15 to be outputs 'run an initialization/stop routine on the 8254 GOSUB Init8254: 'this disables the entire system and gets it ready for operation GOSUB Disable 'pause to wait for other stamps to finish their startup PAUSE 100 Main: 'main loop waiting for commands #IF DebugMode >= 2 #THEN DEBUG "At main loop", CR #ENDIF DO 'reset attention latch if attention line is seen low IF Attention = 0 THEN AttLatch = 1 LOW AttAck ENDIF 'if a rising edge on attention is detected IF (Attention & AttLatch) THEN GOTO GetCommand LOOP 'Serial In Code '======================================================== 'this executes serial communication on the STAMP Bus GetCommand: #IF DebugMode >= 3 #THEN DEBUG "Forced pause!", CR DO LOOP #ENDIF AttLatch = 0 'toggle the debouncer so we don't interpret more than once HIGH AttAck #IF DebugMode >= 2 #THEN DEBUG "Serial Communication with master stamp commencing", CR #ENDIF 'first, receive the packet size SERIN BusData\BusFlow, Baud, [Packets(0)] 'explicity set the flow line back to an input DIR1 = 0 DIR0 = 0 'then receive the packet depending on the packet size Packets(0) = Packets(0) - 1 #IF DebugMode >= 2 #THEN DEBUG "Packet Size: ", DEC Packets(0), CR #ENDIF #IF DebugMode >= 2 #THEN DEBUG "Data: " #ENDIF FOR i = 1 TO Packets(0) SERIN BusData\BusFlow, Baud, [Packets(i)] #IF DebugMode >= 2 #THEN DEBUG HEX2 Packets(i) #ENDIF NEXT 'explicity set the flow line back to an input DIR1 = 0 DIR0 = 0 #IF DebugMode >= 2 #THEN DEBUG CR #ENDIF 'this is the code that interprets the packet instruction and acts upon it SELECT Packets(1) CASE 0 'disable GOSUB Disable CASE 1 'enable GOSUB Enable CASE 2 'program GOSUB Program CASE 3 'program, then enable GOSUB Program GOSUB Enable CASE 4 'set operation mode GOSUB SetOpMode CASE 5 'set pass length GOSUB SetPassLength CASE 6 'set dwell time GOSUB SetDwellTime CASE 7 'set device enable register GOSUB SetDeviceEnable CASE $80 'global command - request version info GOSUB SendIdentification CASE $81 GOSUB SendStatus CASE ELSE #IF DebugMode >= 1 #THEN DEBUG "Invalid packet received", CR #ENDIF ENDSELECT GOTO Main: 'Command Execution Code '======================================================== 'Command 0: Disable envelope Disable: #IF DebugMode >= 1 #THEN DEBUG "Disabling envelope", CR #ENDIF GOSUB DisableDevices 'disable all output 'this may not be necessary AUXIO IF OneShotStatus = 0 THEN 'if the one-shot is active #IF DebugMode >= 1 #THEN DEBUG "Winding down one-shot..." #ENDIF 'set the clock (Counter 0) to be fast Counter = 0 Mode = 3 'mode 3: square wave generator with dwell N N = 2 'note: this cannot be less than 2 for mode 3 or the 8254 won't work properly GOSUB SetCounter 'set the one shot to end quickly 'program counter 1 TO mode 1(one-shot) with N = pulse counts Counter = 1 Mode = 1 'one-shot mode N = 1 GOSUB SetCounter 'set it going GOSUB EnableFlipFlop 'wait for one shot to end its pulse AUXIO DO : LOOP WHILE OneShotStatus = 0 #IF DebugMode >= 1 #THEN DEBUG " done!", CR #ENDIF ENDIF MAINIO GOSUB DisableFlipFlop #IF DebugMode >= 1 #THEN DEBUG "Disable complete", CR #ENDIF RETURN 'Command 1: Enable envelope Enable: #IF DebugMode >= 1 #THEN DEBUG "Enabling envelope", CR #ENDIF IF OpMode > 0 THEN GOSUB EnableFlipFlop IF OpMode & 4 THEN 'if we're set to stop on an input stop pulse #IF DebugMode >= 1 #THEN DEBUG "Ignoring external stop pulse", CR #ENDIF ELSE #IF DebugMode >= 1 #THEN DEBUG "Will stop on external stop pulse", CR #ENDIF GOSUB PrepareForStopPulse ENDIF ELSE #IF DebugMode >= 1 #THEN DEBUG "Error: OpMode not configured.", CR #ENDIF ENDIF RETURN 'Command 2: Program envelope with values stored in stamp's registers Program: #IF DebugMode >= 1 #THEN DEBUG "Programming 8254 and device enable registers", CR #ENDIF AUXIO 'program the 8254 Counter = 0 Mode = 3 N = DwellTime 'note: this cannot be less than 2 for mode 3 or the 8254 won't work ' properly GOSUB SetCounter IF ( OpMode & 2 ) = 0 THEN 'if the one-shot counter is used Counter = 1 Mode = 1 N = PassCount GOSUB SetCounter LOW ModeSelect 'let the one-shot gate output #IF DebugMode >= 1 #THEN DEBUG "Using pass count", CR #ENDIF ELSE HIGH ModeSelect 'ignore one-shot #IF DebugMode >= 1 #THEN DEBUG "Using infinite pulses", CR #ENDIF ENDIF GOSUB EnableDevices MAINIO RETURN 'Command 4: Set Operation Mode SetOpMode: #IF DebugMode >= 1 #THEN DEBUG "Setting Operation Mode", CR #ENDIF IF ( Packets(2) & 1 ) = 0 THEN 'even number means disable OpMode = 0 ELSEIF Packets(2) < 8 THEN OpMode = Packets(2) ELSE OpMode = 0 ENDIF #IF DebugMode >= 1 #THEN DEBUG "Operation Mode set to ", DEC OpMode, CR #ENDIF RETURN 'Command 5: Set Pass Length SetPassLength: PassCount = Packets(2) + ( Packets(3) << 8 ) #IF DebugMode >= 1 #THEN DEBUG "Setting Pass Count to ", DEC PassCount, CR #ENDIF RETURN 'Command 6: Set Dwell Time SetDwellTime: DwellTime = Packets(2) + ( Packets(3) << 8 ) #IF DebugMode >= 1 #THEN DEBUG "Setting Dwell Time to ", DEC DwellTime, CR #ENDIF RETURN 'Command 7: Disable envelope SetDeviceEnable: DeviceEnable = Packets(2) #IF DebugMode >= 1 #THEN DEBUG "Setting Device Enable register to ", BIN8 DeviceEnable, CR #ENDIF RETURN 'Command $80: Send Version # SendIdentification: #IF DebugMode >= 1 #THEN DEBUG "Sending Identification", CR #ENDIF Packets(0) = 3 Packets(1) = $00 '$00 - Clock Stamp identification code Packets(2) = Version 'version of clock stamp code currently installed 'respond with version report packet GOSUB SendPacket RETURN 'Command $81: Send Status SendStatus: Packets(0) = 2 'packet length AUXIO IF ActiveStatus = 0 OR DeviceEnable = 0 THEN Packets(1) = 0 'if the clock is off, or all outputs are off ELSEIF ( OneShotStatus = 1 ) XOR ( OpMode & 2 > 0 ) THEN Packets(1) = 0 'if the one-shot is off and we're using it ELSE Packets(1) = 1 'if we're active ENDIF MAINIO #IF DebugMode >= 1 #THEN DEBUG "Sending Status info: ", HEX2 Packets(1), CR #ENDIF GOSUB SendPacket RETURN 'Subroutines '======================================================== 'initialization: set read, write, control high Init8254: AUXIO 'this switches to the auxilliary IO pins as now used in the new configuration HIGH CS HIGH WR HIGH RD MAINIO RETURN 'counter setting method SetCounter: 'Debug "Setting Counter ", DEC Counter, " with Mode:", DEC Mode, ", COUNT: 0x", HEX4 N, CR AUXIO 'this switches to the auxilliary IO pins as now used in the new configuration GOSUB SetControlWord 'select the counter A0 = Counter & 1 A1 = Counter & 2 DataBus = N & $FF 'LSB of count GOSUB WriteTo8254 DataBus = N >> 8 'MSB of count GOSUB WriteTo8254 MAINIO RETURN 'this method sets the control word based on the desired counter and mode SetControlWord: 'preset read/write method to mode 3: LSB then MSB 'load in Mode 'load in Counter CWRValue = ( Mode << 1 ) | %00110000 | ( Counter << 6 ) 'Debug "Setting Control word register: ", BIN8 CWRValue, CR HIGH A0 'select control register HIGH A1 DataBus = CWRValue 'send the control word on the data bus GOSUB WriteTo8254 RETURN 'this method explicitly strobes data into the 8254 by setting the control 'and write registers low in the appropriate order WriteTo8254: 'put an init in here just in case? 'Debug "Writing to 8254: ", BIN8 DataBus, CR DIRL = $FF 'set data bus to output mode OUTL = DataBus 'send data onto bus LOW CS 'signal control operation LOW WR 'signal write operation HIGH WR 'end write HIGH CS 'end 8254 control operation DIRL = $00 'set data bus to input mode to avoid possible damage to BASIC stamp RETURN EnableFlipFlop: HIGH OnOff GOSUB PulseOnOffSet RETURN DisableFlipFlop: LOW OnOff GOSUB PulseOnOffSet RETURN PrepareForStopPulse: LOW OnOff RETURN PulseOnOffSet: LOW OnOffSet TOGGLE OnOffSet TOGGLE OnOffSet RETURN 'all devices are from 4 to 9 on the main IO pins. EnableDevices: OUTH = DeviceEnable RETURN 'disable all output devices DisableDevices: OUTH = $00 RETURN 'this code is used to send data on the Stamp Bus to the Master Stamp SendPacket: LOW AttAck DO : LOOP WHILE Attention = 0 HIGH AttAck #IF DebugMode >= 2 #THEN DEBUG "Transmitting data..." #ENDIF SEROUT BusData\BusFlow, Baud, [ STR Packets\Packets(0) ] #IF DebugMode >= 2 #THEN DEBUG "Done!", CR #ENDIF 'wait for the master stamp to acknowledge receipt DO : LOOP WHILE Attention DIR1 = 0 DIR0 = 0 RETURN