| |
adc.pwp
//-------------------------------------------------------------------------
//
// PicoWeb Project File for WebADC
//
//-------------------------------------------------------------------------
//
// application-specific preprocessor definitions
//
#define BANNER "\r\nPicoWeb WebADC\r\n"
#define NET_CONFIG_IP /* allow IP address reconfiguration via net */
#define EEPROM_IP /* use file "ip" for IP address (store in EEPROM) */
#define ENABLE_WATCHDOG /* use Atmel watchdog timer hardware */
#define DEBUGGER /* include debugger firmware */
#define ADC_BLINK_LED /* will blink PicoWeb LED on ADC reads */
#define CLOCK 8000000
///#define CLOCK 7372000
#define BAUD_RATE 19200
//
// application-specific HTML and image file names
//
adc.htm // ii00 (default Web page)
adc1.htm // ii01
adc2.htm // ii02
adc3.htm // ii03
read.htm // ii04
info.htm // ii05
block.png // ii06
pwadc.png // ii07
//
// application-specific CGI routines
//
readtemp.cgi // iu00 (returns temperature in deg-C)
readpwr.cgi // iu01 (returns power supply voltage in mV)
readhigh.cgi // iu02 (returns 0-1V differential input voltage in mV)
readlow.cgi // iu03 (returns 0-0.5V differential input voltage in mV)
rawtemp.cgi // iu04 (returns raw 10-bit temperature reading)
rawpwr.cgi // iu05 (returns raw 10-bit power supply reading)
rawhigh.cgi // iu06 (returns raw 10-bit differential input reading (0-1V))
rawlow.cgi // iu07 (returns raw 10-bit differential input reading (0-.5V))
//
// application-specific assmbly language files
//
//
// included application-specific pcode and/or AVR assembly language follows
//
#avr_reset
;--------------------------------------------------------------------------
; this code is executed each time microcontroller is reset
;--------------------------------------------------------------------------
;
; Define LTC1392 connetions to PicoWeb
;
#define DDR(port) (port-1)
#define PINS(port) (port-2)
#define MAKE_INPUT(port, bit) cbi DDR(port),bit
#define MAKE_OUTPUT(port, bit) sbi DDR(port),bit
#define ADC_CS_BIT 0 /* ADC_CS (CS_), output, DB-25 pin 4, PB0 */
#define ADC_CS_PORT PORTB
#define ADC_CLK_BIT 1 /* ADC_CLK (clock), output, DB-25 pin 6, PB1 */
#define ADC_CLK_PORT PORTB
#define ADC_D_BIT 2 /* ADC_D (data in/out), input, DB-25 pin 8, PB2 */
#define ADC_D_PORT PORTB
#define ADC_CLK_HIGH sbi ADC_CLK_PORT,ADC_CLK_BIT /* ADC CLK high */
#define ADC_CLK_LOW cbi ADC_CLK_PORT,ADC_CLK_BIT /* ADC CLK low */
sbi ADC_CS_PORT,ADC_CS_BIT ; "ADC_CS" => high
MAKE_OUTPUT(ADC_CS_PORT,ADC_CS_BIT) ; make CS an output
MAKE_OUTPUT(ADC_CLK_PORT,ADC_CLK_BIT) ; make CLK an output
cbi ADC_CLK_PORT,ADC_CLK_BIT ; "ADC_CLK" => low
MAKE_INPUT(ADC_D_PORT,ADC_D_BIT) ; make D an input
cbi ADC_D_PORT,ADC_D_BIT ; ...and turn off pull-up!!
#ifdef ADC_BLINK_LED
#define LED_ON cbi portd,LED_BIT /* turn LED on */
#define LED_OFF sbi portd,LED_BIT /* turn LED off */
#define PLED_ON pledon /* turn LED on with pcode */
#define PLED_OFF pledoff /* turn LED off with pcode */
sbi DDRD,LED_BIT ; make LED driver pin an output
LED_OFF ; turn LED off
#else /* !ADC_BLINK_LED */
#define LED_ON
#define LED_OFF
#define PLED_ON
#define PLED_OFF
#endif /* !ADC_BLINK_LED */
#avr_slow
;--------------------------------------------------------------------------
; this code is executed each trip through "slow idle" loop (~1 sec period)
;--------------------------------------------------------------------------
;
#avr_fast
;--------------------------------------------------------------------------
; this code is executed each trip through "fast idle" loop
;--------------------------------------------------------------------------
;
#avr_asm
;--------------------------------------------------------------------------
; application-specific CGI pcode and AVR assembly routines go here
;--------------------------------------------------------------------------
;
;--------------------------------------------------------------------------
;+
; pread_adc - take reading using LTC1392 chip (micropower data
; acquisition chip from Linear Technology Corp)
;
; pcode use:
;
; pread_adc a,n
;
; where:
;
; a - address in SRAM to get 16-bit result
; n - LTC1392 registers to read as follows:
;
; n Reading Formula
; - ------- -------
; 0 Temperature Temp(°C) = (10-bit code) / 4 - 130
; 1 Supply Voltage VCC = [(10-bit code) * 4.84/1024] + 2.42
; 2 Input (0-1 V) Diff Volts = 1.0V * (10-bit code) / 1024
; 3 Input (0-.5 V) Diff Volts = 0.5V * (10-bit code) / 1024
;-
;--------------------------------------------------------------------------
#define ADC_TWAKEUP 10 /* normal Twakeup (usecs) */
#define ADC_TWAKEUPT 80 /* temperature Twakeup (usecs) */
#define ADC_THALF 2 /* length of normal 1/2 clock cycle (usecs) */
#define ADC_THALFT 2 /* length of temp 1/2 clock cycle (usecs) */
.cseg
pread_adc: pcode_routine 2
LED_ON ; turn on PicoWeb's LED
ADC_CLK_LOW ; drive CLK low
MAKE_OUTPUT(ADC_D_PORT,ADC_D_BIT) ; make D an output
cbi ADC_D_PORT,ADC_D_BIT ; and drive low
cbi ADC_CS_PORT,ADC_CS_BIT ; "ADC_CS" => low (active)
ldi r16l,ADC_TWAKEUP ; default delay for "wakeup" period (after CS)
ldi r17,ADC_THALF ; get half-period clock (usec)
tst r12l ; r10 == 0?
brne pread_adc0 ; nope...skip ahead
ldi r17,ADC_THALFT ; yes (temp)...use different period
ldi r16l,ADC_TWAKEUPT ; use extra long delay for "wakeup" (after CS)
pread_adc0:
ADC_CLK_LOW
rcall pusecdly ; r16l still had delay (in usec)
ADC_CLK_HIGH ; toggle clock signal
mov r16l,r17 ; delay for 1/2 normal clock period
rcall pusecdly
;
; send command nibble
;
mov r20l,r12l ; r12 has device register
lsl r20l ; shift up to make room for START/MSBF bits
ldi r16l,((1<<3)|(1<<0)) ; add in START=1 and MSBF=1
eor r20l,r16l
ldi r18,4 ; write 4 bits
pread_adc_loop1:
sbrc r20,3 ; skip if bit 3 not set
sbi ADC_D_PORT,ADC_D_BIT ; D bit = 1
sbrs r20,3 ; skip if bit 3 set
cbi ADC_D_PORT,ADC_D_BIT ; D bit = 0
rcall adc_toggle_clk ; toggle clock
lsl r20l ; shift bits
dec r18 ; loop again?
brne pread_adc_loop1 ; yes
;
; switchover data bus
;
MAKE_INPUT(ADC_D_PORT,ADC_D_BIT) ; make D an input
cbi ADC_D_PORT,ADC_D_BIT ; ...and turn off pull-up!!
rcall adc_toggle_clk ; one more clock toggle before read-back
;
; read back bits from device
;
movwi r20,0 ; accumlate 16-bit value here
ldi r18,10 ; read 10 bits
pread_adc_loop2:
rcall adc_toggle_clk
clc ; shift 16-bit value left
rol r20l
rol r20h
in r22,PINS(ADC_D_PORT) ; read I/O port with D bit
sbrc r22,ADC_D_BIT ; skip if D-bit not set
inc r20l ; add 1 to value
dec r18 ; loop again?
brne pread_adc_loop2 ; yes
sbi ADC_CS_PORT,ADC_CS_BIT ; "ADC_CS" => high (inactive)
movw x,r10 ; return 16-bit value
st x+,r20l
st x+,r20h
ret
;
; delay for number of usec in r16l (0-128)
;
pusecdly: ; assume 8 MHz clock
lsl r16l ; double trip count (0.5 usec/trip)
pusecdly1:
dec r16l ; +1
nop ; +1
brne pusecdly1 ; +2
;----
ret ; 4 clocks * 2 total (1 usec/loop)
;
; cycle ADC CLK (low->high) with proper delays
;
; _ ______
; CLK \______/
;
adc_toggle_clk: ; toggle CLK
ADC_CLK_LOW ; clock => low
mov r16l,r17 ; delay 2 usec
rcall pusecdly ; delay
ADC_CLK_HIGH ; clock => high
mov r16l,r17 ; delay 2 usec
rcall pusecdly ; delay
ret
#ifdef ADC_BLINK_LED
pledon: pcode_routine 0
LED_ON
ret
pledoff: pcode_routine 0
LED_OFF
ret
#endif /* ADC_BLINK_LED */
;--------------------------------------------------------------------------
;
; Debug routines
;
;--------------------------------------------------------------------------
.eseg
#ifdef SHOW_ADC_HEX_WITH_URL_PARAM
# define SHOW_ADC_HEX pcall adc_show_hex
adc_show_hex:
ppushwi [buf+2] ; save temp
pmovwi buf+2,[data_addr] ; get data address (skip over "GET ")
; 0123456789
paddwi buf+2,10 ; GET /iuNN?xxxxxxxxxxx
pr2s buf+2,[buf+2],1 ; get next byte after ?
pandwi buf+2,0xff
pcmpwi buf+2,'X'
pjumpne adc_no_show_hex
pprint "(0x" ; print value in hex
phexbi [buf+1]
phexbi [buf]
pprint ") "
adc_no_show_hex:
ppopw buf+2
pret
#else
# define SHOW_ADC_HEX
#endif
#ifdef TEST_DECCONV
test_printdec:
pprint "\n";
pmovwi buf,0
pcall printdec
pprint "\n";
pmovwi buf,-1
pcall printdec
pprint "\n";
pmovwi buf,-123
pcall printdec
pprint "\n";
pmovwi buf,-10005
pcall printdec
pprint "\n";
pmovwi buf,10005
pcall printdec
pprint "\n";
pret
#endif
;--------------------------------------------------------------------------
;+
; **-readXXX-read ADC and return converted reading as ASCII text
;-
;--------------------------------------------------------------------------
.cseg
readtemp:
pread_adc buf,0 ; read LTC1392 ADC register 0 (temp)
pread_adc buf,0 ; do second time for stable reading!!!
pcall convert_adc_temp
adc_printdec:
SHOW_ADC_HEX ; output reading in hex (if debug)
pcall printdec ; output reading in decimal
PLED_OFF ; turn off PicoWeb's LED
pret
readpwr:
pread_adc buf,1 ; read LTC1392 ADC register 1 (4.5-6.0 VDC)
pcall convert_adc_pwr
pjump adc_printdec ; output reading in decimal
readhigh:
pread_adc buf,2 ; read LTC1392 ADC register 2 (0-1 VDC)
pcall convert_adc_volts
pjump adc_printdec ; output reading in decimal
readlow:
pread_adc buf,3 ; read LTC1392 ADC register 3 (0-0.5 VDC)
pcall convert_adc_volts
pshnw buf,-1 ; divide by 2 before output (0-0.5V range)
pjump adc_printdec ; output reading in decimal
;--------------------------------------------------------------------------
;+
; **-rawXXX-read ADC and return raw reading as ASCII text
;-
;--------------------------------------------------------------------------
rawtemp:
#ifdef ADC_OSCOPE_LOOP
pread_adc buf,0 ; read LTC1392 ADC
pjump readtemp
#endif
pread_adc buf,0 ; read LTC1392 ADC register 0 (temp)
pread_adc buf,0 ; do second time for stable reading!!!
pjump adc_printdec ; output reading in decimal
rawpwr:
#ifdef ADC_OSCOPE_LOOP
pread_adc buf,1 ; read LTC1392 ADC
pjump readpwr
#endif
pread_adc buf,1 ; read LTC1392 ADC register 1 (4.5-6.0 VDC)
pjump adc_printdec ; output reading in decimal
rawhigh:
pread_adc buf,2 ; read LTC1392 ADC register 2 (0-1 VDC)
pjump adc_printdec ; output reading in decimal
rawlow:
pread_adc buf,3 ; read LTC1392 ADC register 3 (0-0.5 VDC)
pjump adc_printdec ; output reading in decimal
;--------------------------------------------------------------------------
;
; Conversion routines
;
;--------------------------------------------------------------------------
;
; Temperature (°C) = (10-bit code) / 4 - 130
;
convert_adc_temp:
pdiv buf,[buf],4 ; deg-C = val/4 - 130
psubwi buf,130
pret
;
; Measured VCC = [(10-bit code) * 4.84/1024] + 2.42
;
convert_adc_pwr:
pmul buf,[buf],47 ; V = (val * 47) / 10 + 2420
pdiv buf,[buf],10 ; !!! approximate (0.6% error) !!!
paddwi buf,2420
pret
;
; Differential Voltage = 1.0V * (10-bit code) / 1024; (0-1.0 V range)
; 0.5V * (10-bit code) / 1024; (0-0.5 V range)
;
convert_adc_volts:
#ifdef DEBUG_CONVERT
ppushwi [buf]
pcall printdec ; output reading in decimal
ppopw buf
pprint "->"
#endif
pmovwi buf+2,[buf] ; delta = ((val * 24) + 500) / 1000
pmul buf+2,[buf+2],24
paddwi buf+2,500
pdiv buf+2,[buf+2],1000
psubwi buf,[buf+2] ; val = val - 0.024 * val;
pret
;--------------------------------------------------------------------------
;+
; **-printdec-output signed 16-bit integer in decimal (pcode)
;
; inputs:
; buf = word to convert
;
; outputs:
; result printed (with pputc)
;
; working SRAM:
; buf - buf+14 (save/restores on stack)
;
;--------------------------------------------------------------------------
#define DIG_BUF buf+10 /* uses 5 bytes for ASCII digit storage */
#define DIG_SGN buf+8
#define DIG_CNT buf+6
#define DIG_CH DIG_CNT
#define DIG_PTR buf+4
#define DEC_REM buf+2
#define DIG_LST DEC_REM
#define DEC_VAL buf
.cseg
printdec:
ppushn buf,15 ; stack everything we use
pmovwi DIG_SGN,' ' ; set default sign
pbitwi DEC_VAL,0x8000 ; check the sign
pjumpeq printdec0 ; positive - start conversion
pnegw DEC_VAL ; negate it
pmovwi DIG_SGN,'-' ; change sign to negative
printdec0:
pmovwi DIG_PTR,DIG_BUF ; get input word
pmovwi DIG_CNT,5 ; we will do 5 bytes
printdec1:
pdiv DEC_VAL,[DEC_VAL],10 ; get next one
paddwi DEC_REM,'0' ; convert digit for display
pmovbi [DIG_PTR],[byte DEC_REM] ; save digit
pincw DIG_PTR ; bump past digit just stored
pdecw DIG_CNT ; decrement count
pjumpne printdec1 ; more to do if non-zero
pclrw DIG_CH ; setup to output digits
pmovwi DIG_LST,' ' ; make "last character" a space
printdec2:
pdecw DIG_PTR ; point to next digit
pmovb DIG_CH,[byte DIG_PTR] ; get next digit
pcmpwi DIG_CH,'0' ; is it '0'?
pjumpne printdec4 ; no - may need sign char
pcmpwi DIG_LST,' ' ; last char ' '?
pjumpne printdec3 ; no - continue as normal
pcmpwi DIG_PTR,DIG_BUF ; this is the very last digit?
pjumpeq printdec4 ; yes - check on sign
pmovwi DIG_CH,' ' ; output a ' ' instead
printdec3:
pputcb DIG_CH ; output the current digit
pmovb DIG_LST,DIG_CH ; save last digit output
pcmpwi DIG_PTR,DIG_BUF ; check if just did last one
pjumpne printdec2 ; no - do the next digit
ppopn buf,15 ; restore everything from stack
pret
printdec4:
pcmpwi DIG_SGN,0 ; have we output sign char?
pjumpeq printdec3 ; no - continue as normal
pputcb DIG_SGN ; output sign
pclrw DIG_SGN ; zap sign character
pjump printdec3 ; continue as normal
;--------------------------------------------------------------------------
.cseg
#include "muldiv.asm"
Back
|
|
|