ADC-to-Millivolts running in background of Spin2
cgracey
Posts: 14,155
in Propeller 2
In the new PNut_v34p I just posted, there's a new program called ADC_to_VGA_millivolts.spin2.
It has a PASM program that runs in the background of Spin2 to perform calibrated ADC measurements, where it resolves to millivolt values. I changed the way REG[] works in Spin2, so that you can easily reference any registers declared under ORG blocks, and address them within your own cog. You can see in the 4th line below "PUB go() | i" how REG can be used:
The program assumes VIO is 3.300V. Because of mismatch in the calibration resistor paths, readings are offset by a few mV on top and bottom. If I get a chance to redesign the ADC, I will put the calibration switches BEFORE the big resistor. That would reduce the error by quite a bit. Note that the first pin is tied to GND, while the second pin is tied to VIO. Some pins are quieter than others and I'm not sure why. I believe it has to do with process variances between components within the ADC circuits.
Here is a picture of it running:
It has a PASM program that runs in the background of Spin2 to perform calibrated ADC measurements, where it resolves to millivolt values. I changed the way REG[] works in Spin2, so that you can easily reference any registers declared under ORG blocks, and address them within your own cog. You can see in the 4th line below "PUB go() | i" how REG can be used:
' Program reads 1..8 consecutive ADC pins and displays millivolts for each. ' A terminate-stay-resident PASM program performs conversions in background. ' Samples are always available via REG[samples][{0..7}]. CON _clkfreq = 297_000_000 'set clock frequency _pins = 16 addpins 7 'do conversions on these pins OBJ vga : "VGA_640x480_text_80x40" '_clkfreq >= 50MHz ' vga : "VGA_1280x1024_text_160x85" '_clkfreq >= 216MHz ' vga : "HDTV_1920x1080_text_240x90" '_clkfreq >= 297MHz ' vga : "HDTV_1920x1080_text_135x160" '_clkfreq >= 297MHz PUB go() | i vga.start(8) 'start vga reg[pins] := _pins 'set 'pins' variable regexec(@adc_pasm) 'launch PASM program (uses 'pins') send := @vga.print 'set send pointer repeat 'print samples set every 100ms repeat i from 0 to _pins >> 6 send(dec4(reg[samples][i]), "mV ") send(13) waitms(100) PRI dec4(value) | digflag, negflag, place, digit digflag~ negflag := value < 0 abs= value place := 1_000 repeat if digflag || (digit := value / place // 10) or place == 1 if not digflag~~ send(negflag ? "-" : " ") send("0" + digit) else send(" ") if place == 1_000 send(digflag ? "," : " ") while place /= 10 DAT '******************************************************** '* PASM Program which launches via REGEXEC * '* Sets up an interrupt and then runs in the background * '* Performs calibrated ADC measurements of up to 8 pins * '* Reports samples in millivolts * '******************************************************** ' ' ' REGEXEC header words ' adc_pasm word adc_start 'initial register to load word adc_end-adc_start-1 'additional registers to load org $B0 'put PASM code up high ' ' ' ADC program setup ' adc_start fltl pins 'set pins to ADC mode wrpin adc_modes,pins wxpin #9,pins '#9 is 512-clock, 10-bit conversion (8 per sample) drvl pins 'start pins on same clock mov pin_base,pins 'get pin base and pin_base,#$3F mov pin_count,pins 'get pin count shr pin_count,#6 add pin_count,#1 mov level_base,#adc_levels 'prepare level_base altd pointer sub level_base,pin_base bith level_base,#9 mov ijmp1,#adc_isr 'set interrupt jump mov x,pin_base 'set base pin IN-rise event or x,#%001<<6 setse1 x _ret_ setint1 #int_se1 'enable interrupt on event, return to Spin2 ' ' ' ADC interrupt service routine - runs in background of Spin2 interpreter ' adc_isr akpin pins 'ADC samples done, acknowledge pins alts cycle,#vio_levels 'lookup vio and gio levels for sample computation mov x,0 alts cycle,#gio_levels mov y,0 sub x,y '(3300 << 12) / (vio_level - gio_level) qdiv ##3300<<12,x 'cordic runs during REP rep #3,pin_count 'read ADC samples and sum into adc_levels rdpin x,pin_base altd pin_base,level_base add 0,x sub pin_base,pin_count 'restore pin_base getqx x 'get QDIV quotient alts cycle,#pin_levels '(quotient * (pin_level - gio_level)) >> 12 subr y,0 muls y,x sar y,#12 altd cycle,#samples 'write finished sample mov 0,y incmod cycle,#7 wc 'repeat for 8 cycles if_nc reti1 'return to Spin2 altd state,#adc_modes 'end of 8th cycle, switch to next gio/vio/pin wrpin 0,pins resi1 'return to Spin2, resume on next interrupt akpin pins '9th cycle, acknowledge pins alts state,#moves 'move adc_levels to gio/vio/pin_levels mov x,0 rep #2,pin_count alti x,#%111_111 mov 0,0 resi1 'return to Spin2, resume on next interrupt akpin pins '10th cycle, acknowledge pins setd x,#adc_levels 'clear adc_levels rep #2,pin_count alti x,#%111_000 mov 0,#0 incmod state,#3 'increment state mov ijmp1,#adc_isr 'return to Spin2, start over on next interrupt reti1 ' ' ' Defined data ' cycle long 0 'cycles {0..7, 0, 0} for each state state long 0 'states {0..3} adc_modes long p_adc_gio | p_adc 'adc modes, by state long p_adc_1x | p_adc long p_adc_vio | p_adc long p_adc_1x | p_adc moves long pin_levels<<9 | adc_levels 'moves, by state long gio_levels<<9 | adc_levels long pin_levels<<9 | adc_levels long vio_levels<<9 | adc_levels adc_end 'end of PASM code to load into registers ' ' ' Undefined data ' pins res 1 'initially set by Spin2 code to select the pins x res 1 y res 1 pin_base res 1 pin_count res 1 level_base res 1 adc_levels res 8 'conversions are accumulated into this buffer gio_levels res 8 '..and then copied to one of these three buffers vio_levels res 8 pin_levels res 8 samples res 8 'final samples, available via REG[samples][{0..7}] ' ' ' cycle operations ' ------------------------------------------------------------------------------------ ' 0 (1st) add conversions to levels, compute sample[0] ' 1 add conversions to levels, compute sample[1] ' 2 add conversions to levels, compute sample[2] ' 3 add conversions to levels, compute sample[3] ' 4 add conversions to levels, compute sample[4] ' 5 add conversions to levels, compute sample[5] ' 6 add conversions to levels, compute sample[6] ' 7 (8th) add conversions to levels, compute sample[7], switch to gio/vio/pin ' 0 (9th) move levels to gio/vio/pin_levels ' 0 (10th) clear levels, advance state ' ' state operations ' ------------------------------------------------------------------------------------ ' 0 sample gio for calibration ' 1 sample pin for signal ' 2 sample vio for calibration ' 3 sample pin for signal '
The program assumes VIO is 3.300V. Because of mismatch in the calibration resistor paths, readings are offset by a few mV on top and bottom. If I get a chance to redesign the ADC, I will put the calibration switches BEFORE the big resistor. That would reduce the error by quite a bit. Note that the first pin is tied to GND, while the second pin is tied to VIO. Some pins are quieter than others and I'm not sure why. I believe it has to do with process variances between components within the ADC circuits.
Here is a picture of it running:
Comments
There is another thread talking about chopper-handling a thermocouple signal, but I suspect the P2 noise floor may be too high for that direct use ?
I'm not sure, but it can digitize complex waveforms with 30 millivolts of amplitude at full scale.
In the new PNut_v34p I just posted, there's a new program called ADC_to_VGA_millivolts.spin2.
I have been out of the loop for three weeks. I see version Q. What is the latest version. Where is this posting about PNut_34 p and the es to ADC_to_VGA_millivolts.spin2.
I am confused.
Had to convert in class curriculum at my Aircraft Mechanic school to online in less than two weeks. Now finally coming up for air and getting back to the P2
Thanks
Martin
http://forums.parallax.com/discussion/171196/pnut-spin2-latest-version-v34q/p1