'DAC Stamp.bsp ' {$STAMP BS2p} ' {$PBASIC 2.5} ' {$PORT COM23} 'Version Info '======================================================== 'DAC Stamp program, designed for BASIC stamp BS2P40 version 1.5 'Last Updated Saturday, May 24, 2008 'version 0 Version CON 0 'Compiler directives '======================================================== 'DebugMode 1 tests general DAC functionality 'DebugMode 2 test Stamp Serial IO 'DebugMode 3 was made to test the ramp calculation. it removes the calculation and does a ' simple increment value. #DEFINE DebugMode = 0 'Notes '======================================================== 'this program is the main code for the DAC stamp 'The DAC stamp is responsible for controlling a 12-bit, '4-channel digital to analog (0-10V) output 'The stamp communicates with the DAC by the following pins ' BASIC stamp pin DAC pin ' X0 D0 ' X1 D1 ' X2 D2 ' X3 D3 ' X4 D4 ' X5 D5 ' X6 D6 ' X7 D7 ' X8 D8 ' X9 D9 ' X10 D10 ' X11 D11 ' X12 A0 ' X13 A1 ' X14 !WR 'D0 through D11 are the 12-bit data line for the program value 'A0, A1 is the 2-bit DAC address selection to program DAC channels 0 through 3 '!WR is strobed low, then high, so the DAC can read the D0-D11, A0-A1 values on 'downward-strobe 'the stamp communicates with the Master stamp through the 'stamp bus ' BASIC stamp pin Function ' 0 Serial Data ' 1 Serial Flow (RTS) ' 2 Channel Advance (in) ' 3 Attention (in) ' 4 Attention Acknowledge (out) 'Packet format: ' ' Byte Content ' 0 Packet size ' 1 Command ' 2 Data ' ... 'PINS '======================================================== 'pins for DAC communication (Aux ports only) WR PIN 14 'pins for STAMP bus (Main ports only) BusData PIN 0 BusFlow PIN 1 ChAdv PIN 2 Attention PIN 3 AttAck PIN 4 'Variables and Registers '======================================================== 'data bus, used as output latch to DAC line DACBus VAR Word 'Values used for operation of the DAC Envelope DACStart VAR Word DACEnd VAR Word DACNext VAR Word DACScratch VAR Word Channels VAR Word CurChannel VAR Word 'bitmask used to store which DAC channels are active ActiveFlag VAR Byte 'this tells whether the system is currently doing a ramp or not RampActive VAR Bit 'Latch variables, used to detect transitions of inputs AttLatch VAR Bit ChLatch VAR Bit 'variables used for data Packets VAR Byte(9) 'constants used for serial communication 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 "DAC Stamp Initializing", CR, CR #ENDIF GOSUB Init 'pause to wait for other stamps to finish their startup PAUSE 100 PassiveMain: 'main loop waiting for commands #IF DebugMode = 1 #THEN DEBUG "At passive loop", CR #ENDIF DO 'reset attention latch IF Attention = 0 THEN AttLatch = 1 LOW AttAck ENDIF 'if a rising edge on attention is detected IF (Attention & AttLatch) THEN GOTO GetCommand LOOP 'Active Loop Code '======================================================== ActiveMain: 'main loop waiting for commands #IF DebugMode = 1 #THEN DEBUG "At active loop", CR #ENDIF DO 'reset attention latch IF Attention = 0 THEN AttLatch = 1 LOW AttAck ENDIF 'reset channel advance latch to prepare to detect next falling edge IF ChAdv THEN ChLatch = 1 ENDIF 'if a falling edge on channel advance is detected IF (ChAdv = 0 AND ChLatch) THEN GOSUB RampDAC 'if a rising edge on attention is detected IF (Attention & AttLatch) THEN GOTO GetCommand 'if the ramp has finished IF CurChannel > Channels THEN RampActive = 0 GOTO PassiveMain ENDIF LOOP 'Serial In Code '======================================================== 'this executes serial communication on the STAMP Bus GetCommand: AttLatch = 0 HIGH AttAck #IF DebugMode = 1 #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 = 1 #THEN DEBUG "Receiving ", DEC Packets(0), " bytes", CR #ENDIF FOR i = 1 TO Packets(0) SERIN BusData\BusFlow, Baud, [Packets(i)] #IF DebugMode = 1 #THEN DEBUG HEX2 Packets(i) #ENDIF NEXT #IF DebugMode = 1 #THEN DEBUG CR #ENDIF 'explicity set the flow line back to an input DIR1 = 0 DIR0 = 0 'interpret what the packet wants you to do 'Packets(1) stores the command for what you're doing with it SELECT Packets(1) CASE( 0 ) 'disable stamp #IF DebugMode = 1 #THEN DEBUG "Disabling stamp", CR #ENDIF RampActive = 0 CASE( 1 ) 'direct set the DAC #IF DebugMode = 1 #THEN DEBUG "Setting output DAC value", CR #ENDIF GOSUB DirectDAC 'program the DAC and go back to main idle loop RampActive = 0 CASE( 2 ) 'ramp the DAC #IF DebugMode = 1 #THEN DEBUG "Preparing for ramp", CR #ENDIF GOSUB StartRamp 'prepare to do the ramp RampActive = 1 CASE( $80 ) 'request ID #IF DebugMode = 1 #THEN DEBUG "Sending identification", CR #ENDIF Packets( 0 ) = 3 Packets( 1 ) = $01 'ID # 1: DAC Stamp Packets( 2 ) = Version GOSUB SendPacket CASE( $81 ) 'request status #IF DebugMode = 1 #THEN DEBUG "Sending status", CR #ENDIF Packets( 0 ) = 2 Packets( 1 ) = RampActive GOSUB SendPacket ENDSELECT IF( RampActive ) THEN GOTO ActiveMain: ELSE GOTO PassiveMain: ENDIF 'Subroutines '======================================================== 'This initializes the output pins for the DAC communication bus Init: AUXIO HIGH WR 'NOTE: do we really want to leave these all as outputs? DIRS = %0111111111111111 'set data bus to output mode DACBus = %0100000000000000 MAINIO RETURN 'this subroutine transfers whatever is on the DAC DataBus and 'writes it to the output pins to the DAC, then strobes the !WR line WriteToDAC: OUTS = DACBus 'PAUSE 3 LOW WR 'signal write operation 'PAUSE 3 'this pulse width may need to be tampered with OUTS = %0100000000000000 'end write 'note: leaving the DAC bus pins as outputs speeds up this process RETURN 'this is used to directly program a DAC channel DirectDac: AUXIO 'DAC Bus format: 'Packet(2): LSB of DAC data bus 'Packet(3): X X A1 A0 D11 D10 D9 D8 DACBus = ( 1 << 14 ) + Packets(2) + ( Packets(3) << 8 ) #IF DebugMode = 1 #THEN DEBUG "Writing to DAC : ", BIN16 DACBus, CR #ENDIF GOSUB WriteToDac MAINIO RETURN StartRamp: CurChannel = 0 'format: 'Packet(2)&Packets(3) - 16-bit channel COUNt - number of steps 'Packets(4) - 4-bit active bitmask 'Packet(5)&Packets(6) - 12-bit ramp start value 'Packet(7)&Packets(8) - 12-bit ramp end value Channels = Packets(2) + (Packets(3) << 8 ) ActiveFlag = Packets(4) DACStart = Packets(5) + (Packets(6) << 8 ) DACEnd = Packets(7) + (Packets(8) << 8 ) #IF DebugMode = 3 #THEN DACNext = 0 #ENDIF 'initialize the DAC to start at the beginning of the ramp! DACNext = DACStart 'set DAC to the beginning GOSUB RampDAC RETURN RampDAC: ChLatch = 0 AUXIO 'NOTE: first channel is not set? DACNext is not set until the CalcNext is fired? FOR i = 0 TO 3 IF ActiveFlag & (1 << i) THEN #IF DebugMode = 1 #THEN DEBUG "Ramping DAC ", DEC i, " to ", DEC DACNext, CR #ENDIF DACBus = ( 1 << 14 ) + ( i << 12 ) + DACNext GOSUB WriteToDAC ENDIF NEXT MAINIO CurChannel = CurChannel + 1 GOSUB CalcNext RETURN 'this calculates the next value the DAC will sit at in the ramp CalcNext: '16 bit math with proper remainder: modulus method #IF DebugMode = 3 #THEN DACNext = DACNext + 1 #ELSE DACNext = DACStart + ( (DACEnd - DACStart) / Channels * CurChannel ) DACScratch = ( (DACEnd - DACStart) // Channels * CurChannel / Channels ) DACNext = DACNext + DACScratch #ENDIF #IF DebugMode = 1 #THEN DEBUG "Next DAC output: ", DEC DACNext, CR #ENDIF 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