TACHYON { ADC_SD.fth } pri ADC_SD.fth ." Extensions to TACHYON by MJB - 121204.2100 " ; " !!!!!!!!!!!!!!!!!!!!! REQUIRES LATEST KERNEL V21_121114,1330 upwards !!!!!!!!!!!!!" DROP IFNDEF LEMIT : LEMIT DUP $0A <> IF $100 OR 2* (EMIT) ELSE DROP THEN ; \ Define these two symbols as dummy definitions so that Forth will do nothing except affect echo - they are meant for HS-SerialRxL \ start of load symbol - Intercepted by HS-SerialRxL and will automatically strip comments etc IFNDEF [~ : [~ 1 flags CLR ' LEMIT uemit W! ; \ end of load symbol - Intercepted by HS-SerialRxL will revert back to transparent mode IFNDEF ]~ : ]~ 1 flags SET 0 uemit W! ; [~ \ If HS-SerialRxL is used then it will already be filtering out all comments and redundancies because it just saw [~ { ******************* TACHYON FORTH EXTENSIONS by MJB Dr. Markus Baer ********************* ** Sigma-Delta ADC module (with ASM module) LOADSTATS: CHANGELOG: 121204 - contest version ADC plus PWM voltage / current controller 121021 - ADCSD Sigma-Delta single shot with ASM module (cyclic reading is on hold for later) 121019 - initial with ADCSD Sigma-Delta ADC module } HEX \ prepare everything { what I like very much about Tachyon (amoung to many things ...) is, that it is so nicely embedded within SPIN and ASM. Reading Peter's source was a great help in learning PASM ... Normally we try to do all in Forth itself, unless we need speed So here, to do sigma dellta ADC I used Parallax example code and put it into a PASM extemsion module for Tachyon. ' ADCSDsingle PASM Module by Markus Baer aka MJB based on Parallax examples org _RUNMOD _ADCSDsingle mov X,#1 shl X,tos ' number of bits resolution on TOS sub X,#1 ' create bit pattern with X bits set mov target,cnt 'Get the current counter value. add target,#16 'Add a little to get ahead. waitcnt target,X 'Sync to clock; add interval to time. neg tos,phsa 'Negate phsa into result. waitcnt target,#0 'Wait for interval to pass. add tos,phsa 'Add phsa into result. and return on TOS jmp #doNEXT \ usually this PASM code is included in the basic TACHYON SPIN file. \ but using BST I extracted the compiled ASM and put it into a table. \ This allows loading PASM modules into a running TACHYON image \ without changing the original TACHYON SPIN file. TABLE ADCSDsASM \ precompiled codes here - so can be just loaded as fth file \ (for Tachyon V2.0) in V2.1 the _RUNMOD has changed so this \ needs to be recompiled $01 | $4E | $FF | $A0 | $A8 | $4F | $BF | $2C | $01 | $4E | $FF | $84 | $F1 | $47 | $BF | $A0 | $10 | $46 | $FF | $80 | $A7 | $47 | $BF | $F8 | $FC | $51 | $BF | $A4 | $00 | $46 | $FF | $F8 | $FC | $51 | $BF | $80 | $00 | $01 | $7C | $5C | : [ADCSDs] ADCSDsASM 10 LOADMOD ; \ the number of bits of resolution can be set \ of course better is slower : RUN_ADC_SD ( nBitsResolution -- result ) RUNMOD ; \ NEWCNT 100 FOR 8 RUNMOD .DEC CR NEXT .LAP \ \ NEWCNT 100 FOR 12d RUNMOD .DEC CR NEXT .LAP \ \ NEWCNT 100 FOR 16d RUNMOD .DEC CR NEXT .LAP \ } \ for this contest I put the PASM code directly into the TACHYON SPIN file. \ so to see what is going on I recommend a file compare tool like \ beyond compare (you can get a free download) \ good part starts here \ from Peter's PWM code given in EXTEND.fth \ ( implement 8 PWM channels on P0..P7 - I only use channel 0 here ) \ setup area for PWM values TABLE pwm #256 ALLOT \ Set the frequecy 1kHz is fine for now #1000 PWMFREQ \ Start up PWM using from P0 for 8 channels 0 8 pwm RUNPWM \ Set PWM channel 0 for 50% $80 0 PWM! \ since I have only very limited code space in the reloadable ASM-Module \ a do a big part of the setup for IO-Pins and Counter here : INIT_ADC_SD ( -- ) \ for PropBoE [ADCSDs] \ load the single shot ADC sigma delta module into COG - raw no scaling done \ setup for PPDB \ the PBoE sigma delta ADC unfortunately is directly tied to the \ microphone and I have no acccess to the pin \ so I used my PPDB here #12 \ PBoE #20 SDInputPin PBoE Microphone 9 \ PBoE #21 SDFeedbackPin DUP MASK OUTPUTS \ make SDF pin an output 9 SHL \ shift SDFeedbackPin to destination OR \ or together with SDInputPin on source %01001 #26 SHL \ shift countermode 9 = POS detector with feedback to position OR CTRA COG! \ or in as well and store to CTRA of this COG 1 FRQA COG! \ load counter FRQ register ; \ to run it in the terminal init first manually \ INIT_ADC_SD \ 12 bit ADC with print for test : ADC12 12d RUNMOD .DEC CR ; { HW setup is as follows: Sigma Delta Circuit from Appnote 8 1 nF capacitor between GND and SDInputPin 150k Resistor from SDInputPin to input signal 100k Feedback resistor to feedback pin SDFeedbackPin PWM is generated on pin 0 filtered by 1k and 10uF and then feed to the ADC input at the 150k above one of the 10k potis of the PPDB is used to put variable load on the generated voltage } \ on my breadboard setup I have a lot of noise \ seems to be around 10MHz, which I need to checkout \ for now just do a 10 times average \ it is important to reload the ADC module because using PWM! \ loads the [PWM!] module into the cog !!! : ADC12avg [ADCSDs] 0 #10 FOR #12 RUNMOD + NEXT #10 / ; { some test code [ADCSDs] 10 FOR ADC12 NEXT #0 % 0 PWM! [ADCSDs] #10 FOR ADC12 NEXT #25 % 0 PWM! [ADCSDs] #10 FOR ADC12 NEXT #50 % 0 PWM! [ADCSDs] #10 FOR ADC12 NEXT #75 % 0 PWM! [ADCSDs] #10 FOR ADC12 NEXT #100 % 0 PWM! [ADCSDs] #10 FOR ADC12 NEXT } \ define a variable to be used for the PWM value BYTE pwmtarget 0 pwmtarget C! { some test code pwmtarget C@ .DEC \ show the pwmtarget pwmtarget C@ 0 PWM! \ store the pwmtarget to PWM channel 0 } \ this is the target value for my voltage - \ in ADC bit units - not scaled to Volts for now \ this value corresponds to about 50% PWM LONG utarget #2400 utarget ! utarget @ .DEC \ Voltage controller - VERY VERY simple for now \ of course some PID or higher level controller is much better \ final goal is to run 12 parallel current controllers \ for driving automotive solenoids at 2A 13V \ a FET will be used for driving and a shunt to measure the actual current \ Prop maybe can do this with the sigma delta ADC above \ or we need a separate multi channel ADC \ Then prop then drives the 12 channel PWM \ here the experiment uses just one PWM channel at pin 0 \ PWM all based on Peter's code in EXTEND.fth \ Voltage Controller : VCTR ADC12avg utarget @ < \ if current value less than target voltage IF pwmtarget C++ \ increment PWM by 1 ELSE pwmtarget C-- \ decrement PWM by 1 THEN \ pwmtarget C@ DUP .DEC CR 0 PWM! \ set new PWM with printout pwmtarget C@ 0 PWM! \ set new PWM ; { some test code VCTR pwmtarget C@ .DEC #250 FOR VCTR 5 ms pwmtarget C@ .DEC CR NEXT #2500 FOR VCTR 5 ms NEXT #25000 FOR VCTR NEXT } \ Task that runs the VoltageController engine in it's own COG pri VCTRCOG INIT_ADC_SD \ we need to do the init from inside this COG BEGIN VCTR \ infinite loop ATN@ UNTIL \ but exit if task command is recieved ; \ we store the cog number here so we can stop it later with \ 1 vctrcog ATN! BYTE vctrcog pub RUNVCTR ( -- ) \ wow Peter you made it so easy to do this ' VCTRCOG \ pointer to word we want to run in cog TASK? \ check for free cog DUP vctrcog C! \ store cog number for later RUN \ and run it in the cog ; \ now run the voltage controller RUNVCTR \ now we can play with the poti to vary the load \ the controller adapts the PWM to keep the voltage stable \ Startup code for background pub BOOT2 BOOT RUNVCTR ; \ if you like make this autorum \ AUTORUN BOOT2 ]~ \ HS-SerialRxL will intercept this and stop filtering comments etc and return to transparent mode END runtime ~ \ ?BACKUP