;USER YOUR BROWSER'S BACK BUTTON TO GO BACK.
;Copy this text directly into your assembler editor.
;The code was writtent with AVR Studio 3.5.x
;Copyright 2003 Richard Cappels, projects(at)cappels.org,
; http://www.projects.cappels.org
;
;*********************************
;2313 waveform capture
;*********************************

.include "2313def.inc"


; This program captures a repetitive wavefor by comparing the incoming waveform with
; 64 successive DC levels using the on-chip analog comparitor. It also uses the UART
; to communicate with a simple user control panel (can be a terminal) and has a firmware
; UART to communicate with a dot graphic LCD. The dumptodisplay routine includes formatting
; for the display. The pulse width modulator that supplies the 64 different DC levels assumes
; a 5:1 divider on the output and an filter time constant of 1 millisecond. The PWM is operated
; in the 8 bit mode and data is shifted left twice before being written to the PWM. The UART
; communicates with the control panel at 9600/1/N and expects inverting buffers between the UART
; and the RS-232 channel. The soft UART communicates with the display at 19200 baud and does
; not expect iverting buffers between it and the serial channel. The expected display is a
; Seiko-Epson 1216 128 x 64 dot graphics display with a serial interface. The protocol is simple:
; a command of $80 erases the dispaly, $82 puts the display in binary mode, thereafter,
; the x and y coordinates of the dots to be turned on are sent, and a chararacter is expected
; as a handshake after each dot.

;The main routines are:
; scanspan -This is the main loop.
; capture - Does the actual waveform capture.
; incomingbyte - Interprets control panel commands and returns status.
; dumptodisplay - Formats and dumps data to dot graphics display.


;UART baud rate calculation
.equ clock = 10000000 ;clock frequency
.equ baudrate = 9600 ;choose a baudrate
.equ baudconstant = (clock/(16*baudrate))-1

;Assign space for array of sample values in RAM
.equ arraystart = $60 ;First byte of data array
.equ arrayend = $C4 ;Last byte of data array

;Assign working registers

.def delayselect = r02 ;index into list of sampling delays
.def toolowcount = r03 ;count of samples found too low out of range
.def toohighcount = r04 ;count of samples found too high our of range

.def temp = r16 ;general purpose variable
.def innerrloopc = r17 ;delay counter, innermost loop also used by soft UART
.def outerloopc = r18 ;delay counter, outer loop also used by soft UART
.def flagreg = r19 ;Flags for control. See definitions below
.def pwmval = r21 ;PWM value


;Assignment of flagreg bits
;bit 0 if set, indicates that display is to be erased before being rewritten
;bit 1 if set, allows sampling of analog signal
;bit 2 if set, selects for triggering on positive edge of trigger signal
;bit 3 if set, selects for free run (non-triggered operation)
;bit 4
;bit 5
;bit 6
;bit 7


.org $000
rjmp init ;Not needed but included to be consistent with practice.

init:
ldi temp,low(ramend)
out spl,temp ;Set stack pointer low byte (ther is no high byte)

ldi temp,$02 ;Default scan rate is 10 us per sample
mov delayselect,temp

ldi flagreg,$0F ;Set flag to call for erasing of display before writing
;sampling enabled, and postive edge trigger

ldi temp,$10 ;Set DDRB 4 as output for serial interface.
out DDRB,temp

ldi temp,baudconstant
out ubrr,temp ;Load baudrate.
sbi ucr,rxen ;Enable WAUT receive
sbi ucr,txen ;Enable UART Transmit

ldi pwmval,$20
rcall pwm8setup ;Start up PWM DAC.

wf1: ;Wait for SIN to go high (indicates power applied to display.)
sbic PORTB,SIN
rjmp wf1
rcall wait1000ms ;Wait for display to come on.
ldi temp,$38 ;Send $80 command to clear display
rcall xmit
ldi temp,$30
rcall xmit

rcall receive ;Wait for assterisk showing display completed task
ldi temp,$38 ;Send $82 command to set binary mode
rcall xmit
ldi temp,$32
rcall xmit

mov temp,flagreg ;Send flagreg to terminal
rcall emitcharp50
mov temp,delayselect ;Send delayselect to terminal
rcall emitcharp30

rjmp scanspan ;Main sampling control and I/O loop.


pwm8setup: ;Set up AT90S2313 Timer 1 as 8 bit PWM.
ldi temp,$81
out TCCR1A,temp ;Preload with $FF
ldi temp,$01
out TCCR1B,temp
ldi temp,$00
out OCR1AH,temp
ldi temp,$FF ;
out OCR1AL,temp ;Write PWM data
sbi DDRB,3 ;Set PWM output pin as output
ret ;To update PWM value, write a byte to OCR1AL



assignsampledelay: ;Set pointer to sample delay entry point
ldi ZH,high(2*delaylist) ;Load high part of byte address into ZH
ldi ZL,low(2*delaylist) ;Load low part of byte address into ZL
mov temp,delayselect
lsl temp
add ZL,temp
brcc nca ;If carry results, take care of it.
inc ZH
nca:


lpm ;Get address from pointer (r0) into ZH.ZL
push r0
adiw ZL,1
lpm
mov ZH,r0
pop ZL
ret



delaylist: ;Pointer table to entrances to generic delay routine. Used to select
;time scale for waveform sampling. The delay is delay time between
;individual samples.
.dw delay1us
.dw delay2us
.dw delay5us
.dw delay10us
.dw delay20us
.dw delay50us
.dw delay100us
.dw delay200us
.dw delay500us
.dw delay1000us
.dw delay2000us
.dw delay5000us
.dw delay10000us

delay2us: ;Total delay for 2.00 us (based on 10 mhz clock).
nop
nop
ldi innerrloopc,$02
l2: dec innerrloopc
brne l2
rjmp delay1us


delay5us: ;Total sample delay for 5.00 us (based on 10 mhz clock),
nop ;Before terminal priority accomodated two noops removed
ldi innerrloopc,$01
ldi outerloopc,$07
rjmp genericdelay

delay10us: ;Total sample delay for 10.0 us (based on 10 mhz clock).
nop
nop
nop
nop
nop
nop
nop
ldi innerrloopc,$01
ldi outerloopc,$12
rjmp genericdelay

delay20us: ;Total sample delay for 20.0 us (based on 10 mhz clock).
nop
nop
nop
ldi innerrloopc,$01
ldi outerloopc,$2C
rjmp genericdelay

delay50us: ;Total sample delay for 50.00 us (based on 10 mhz clock).
nop ;Before terminal priority accomodated was just one nop
nop
nop
ldi innerrloopc,$01
ldi outerloopc,$77
rjmp genericdelay


delay100us: ;delay for 100.1 us (based on 10 mhz clock. Trash innerrloopc and outerloopc.
ldi innerrloopc,$01
ldi outerloopc,$F5
rjmp genericdelay

delay200us: ;delay for 199.4 us (based on 10 mhz clock. Trash innerrloopc and outerloopc.
ldi innerrloopc,$02
ldi outerloopc,$F6
rjmp genericdelay

delay500us: ;delay for 500.1 us (based on 10 mhz clock. Trash innerrloopc and outerloopc.
ldi innerrloopc,$05
ldi outerloopc,$F8
rjmp genericdelay


delay1000us: ;delay for 1006 us (based on 10 mhz clock. Trash innerrloopc and outerloopc.
ldi innerrloopc,$0C
ldi outerloopc,$D0
rjmp genericdelay

delay2000us: ;delay for 2010.4 us (based on 10 mhz clock. Trash innerrloopc and outerloopc.
ldi innerrloopc,$18
ldi outerloopc,$D0
rjmp genericdelay


delay5000us: ;delay for 5023.6 us (based on 10 mhz clock. Trash innerrloopc and outerloopc.
ldi innerrloopc,$3C
ldi outerloopc,$D0
rjmp genericdelay



delay10000us: ;delay for 10045.6 us (based on 10 mhz clock. Trash innerrloopc and outerloopc.
ldi innerrloopc,$78
ldi outerloopc,$D0
rjmp genericdelay ;This instruction not really needed but kept for uniformity.



genericdelay: ;Actual sampling delay routine as set up by calling routine
;Enter with outer loop value in innerrloopc and
;outer loop value in outerloopc.
outergeneric:
sbic usr,rxc ;Check for byte in UART from terminal
rjmp delay1us ;and if char is waiting, shorten loop ;
mov temp,outerloopc
innergeneric:
nop
dec temp
brne innergeneric
dec innerrloopc
brne outergeneric
nop
rjmp delay1us


wait1ms: ;delay for 1.003 ms (based on 10 mhz clock). including call and return). Trash innerrloopc and outerloopc.
ldi innerrloopc,$0D
outerloop1:
ldi outerloopc,0
innerloop1:
dec outerloopc
brne innerloop1
dec innerrloopc
brne outerloop1
ret


wait5ms: ;delay for 5.0122 ms (based on 10 mhz clock). including call and return). Trash innerrloopc and outerloopc.
ldi innerrloopc,$41
outerloop3:
ldi outerloopc,0
innerloop3:
dec outerloopc
brne innerloop3
dec innerrloopc
brne outerloop3
ret




wait1000ms: ;delay for 1000ms (based on 10 mhz clock). including call and return). Trash innerrloopc and outerloopc.

ldi temp,$36
mostouter:
ldi innerrloopc,$0
outerloop31:
ldi outerloopc,0
innerloop31:
dec outerloopc
brne innerloop31

dec innerrloopc
brne outerloop31
dec temp
brne mostouter
ret



FillArray: ;Fill array with $FF.
ldi YL,arraystart
ldi YH,$FF
ldi temp,$FF
fillmore:
st Y+,temp
cpi YL,arrayend+1
brne fillmore
ret



scanspan: ;Test input voltage against all possible choices and write retults into array.
sbic usr,rxc ;Check for byte in UART from terminal
rcall incomingbyte
sbrs flagreg,1 ;Check to see if capturing is allowed
rjmp nocapture
rcall assignsampledelay
rcall capture
rcall dumptodisplay
nocapture:
rjmp scanspan

capture: ;Enter with ZH,ZL pointing to delay routine
;For 1 microsecond sampling interval, point to oneus
;Values of samples are stored in RAM from location
;arratystart to arrayend.

rcall FillArray ;Preset array.
ldi pwmval,64 ;PWM = 64
ldi temp,$00
out OCR1AH,temp ;Zero high register
mov temp,pwmval
lsl temp
lsl temp
out OCR1AL,temp ;Set pwm value
rcall wait5ms


decpwm: dec pwmval ;PWM = PWM 1 1.
cpi pwmval,$FF ;If PWM = -1 then finshed capturing.
breq capturefinsihed
ldi temp,$00
out OCR1AH,temp ;Zero high register
mov temp,pwmval
lsl temp
lsl temp
out OCR1AL,temp ;Set pwm value
rcall wait1ms ;Wait for small step settling time
ldi YH,$00 ;Y = array start.
ldi YL,arraystart
rcall waitingfortrigger

nextydelay: ;Includes NOPs come here if pwmval is not to be stored on this cycle
inc YL ;Inc YL and see if array boundary has been exceeded.
cpi YL,arrayend+1
breq decpwm
nop ;Equalize time between samples for pwmval saved and not saved
nop

nexty:
ijmp
delay1us:
sbic ACSR,$05 ;CAPTURE COMPARITOR OUTPUT STATE
rjmp nextydelay
st Y+,pwmval
cpi YL,arrayend+1
breq decpwm
rjmp nexty

capturefinsihed:
ret



waitingfortrigger:
sbrc flagreg,3
rjmp notriggerneeded
sbrc flagreg,2
rjmp waitingforpostrigger


waitingfornegtrigger:
waitforhigh1:
sbic usr,rxc ;Check for byte in UART from terminal
rjmp quittrigger ; and return if char waiting (no trigger)
sbis pind,$06
rjmp waitforhigh1
waitforlow1:
sbic usr,rxc ;Check for byte in UART from terminal
rjmp quittrigger ; and return if char waiting (no trigger)
sbic pind,$06
rjmp waitforlow1
ret


waitingforpostrigger:
waitforlow:
sbic usr,rxc ;Check for byte in UART from terminal
rjmp quittrigger ; and return if char waiting (no trigger)
sbic pind,$06
rjmp waitforlow
waitforhigh:
sbic usr,rxc ;Check for byte in UART from terminal
rjmp quittrigger ; and return if char waiting (no trigger)
sbis pind,$06
rjmp waitforhigh
ret


notriggerneeded: ;Come here when in free run
ret

quittrigger: ;Quit trigger routine and data collection
ldi YL,arrayend ;Set YL to look like all points tested
; ldi pwmval,$01 ;Set pwmval to look like last value tried
ret

incomingbyte: ;Get and handle incoming byte from terminal.
;Subtract $30 from incoming byte
;Results in rage 0..$D use as index to select sampling
;delay and results above $D interpret as command.

in temp,udr ;Read byte
rcall emitchar ;Echo byte
subi temp,$30
cpi temp,$0E
brpl itsacommand ;Over $D so interpert as command
mov delayselect,temp
ret
itsacommand:
andi temp,$5F ;Upper-case character
cpi temp,$15 ;Is it an "E"?
brne nc1
rjmp toggleerasebit ;If E toggle display erase bit
nc1:
cpi temp,$13 ;Is it an "C"?
brne nc2
rjmp togglecapturebit ;If C toggle capture enable bit
nc2:
cpi temp,$19 ;Is it an "I"?
brne nc3
rjmp incrementds ;If I Increment delayselect
nc3:

cpi temp,$14 ;Is it an "D"?
brne nc4
rjmp decrementds ;If D decrement delayselect
nc4:

cpi temp,$16 ;Is it an "F"?
brne nc5
rjmp toggletrigger ;If F toggle trigger polarity

nc5:
cpi temp,$11 ;Is it an "A"?
brne nc6
rjmp togglefreerun ;If A toggle trigger free run
nc6:

ret ;If no match, return.




decrementds: ;Decrement delay value
mov temp,delayselect
cpi temp,$00
brne ns6
rjmp ns7
ns6:
dec delayselect
ns7: mov temp,delayselect
rcall emitcharp30
ret



incrementds: ;Increment delay value.
mov temp,delayselect
cpi temp,$0C
brne ns4
rjmp ns5
ns4:
inc delayselect
ns5: mov temp,delayselect
rcall emitcharp30
ret


toggleerasebit: ;Topggle erase before write flag and send flags.
sbrs flagreg,0
rjmp ns2
andi flagreg,$FE
rjmp ns11
ns2:
ori flagreg,$01
ns11: mov temp,flagreg
rcall emitcharp50
ret



toggletrigger: ;Topggle trigger polarity and send flags.
sbrs flagreg,2
rjmp ns8
andi flagreg,$FB
rjmp ns9
ns8:
ori flagreg,$04
ns9: mov temp,flagreg
rcall emitcharp50
ret




togglefreerun: ;Topggle trigger/free run flag and send flags.
sbrs flagreg,3
rjmp ns12
andi flagreg,$F7
rjmp ns13
ns12:
ori flagreg,$08
ns13: mov temp,flagreg
rcall emitcharp50
ret



togglecapturebit:;Toggle capture enable bit and send flags.
sbrs flagreg,1
rjmp ns3
andi flagreg,$FD
rjmp ns10
ns3:
ori flagreg,$02
ns10: mov temp,flagreg
rcall emitcharp50
ret


dumptodisplay: ;Dump data buffer to display panel.
;Since this is an oscilloscope-like display, the signal
;should not clip at the top or bottom of the screen, so
;if the data value is $00 or $FF, do not send to display.


clr toohighcount ;Clear counts of samples too high and too low
clr toolowcount
sbrs flagreg,0
rjmp noerase
ldi temp,$80 ;Reset and clear display
rcall xmit
rcall receive
noerase:
rcall ygrat ;Write y graticle
rcall xgrat ;Write x graticle

ldi pwmval,14 Column counter - points to horizontal (x) address in display.
ldi YL,arraystart
ldi YH,$00
dumpmore1:

ld temp,Y ;Test data for clipped value ($0 of $FF)
cpi temp,$00 ;and don't send if clipped.
breq notransmit0
cpi temp,$FF
breq notransmitF

mov temp,pwmval ;Send horizontal address (x) of dot.
rcall xmit
ld temp,Y ;Send vertical address (y) f dot.
rcall xmit
rcall receive ;Get handshake (an asterisk) before continuing..
rjmp notransmit

notransmit0:
inc toolowcount
rjmp notransmit
notransmitF:
inc toohighcount


notransmit:
inc pwmval
inc YL
cpi YL,arrayend+1
brne dumpmore1

mov temp,toolowcount ;If more than predetermined no.of $00 set low indicators
cpi temp,25
brmi nottoolow
rcall inputtoolow ;Put indicator in display

nottoolow:

mov temp,toohighcount ;If more than predetermined no. of $FF set high indicators
cpi temp,25
brmi nottoohigh
rcall inputoohigh ;Put indicator in display

nottoohigh:

ret

;Emit character routines.
emitcharp50: ;Enter here to add $50 to char and emit
subi temp,-$20
emitcharp30: ;Add $30 to character and emit
subi temp,-$30
emitchar: ;send character
sbis usr,udre ;wait until the register is cleared
rjmp emitchar
out udr,temp ;send the byte
ret

;-----------------------------------------------------------------------------;
; The author of the soft UART routine below is not known and the copyright for it
;is not owned by Dick Cappels. If you are the author, contact me for attribution.
;-----------------------------------------------------------------------------;
;
; NOTE: SIN and SOUT are inverted signals directly connected to RS-232C line.
; SOUT pin must be configured as output before transmiting.
; Don't enable any interrupt during these routines being executed.
;
; (bps) 3.58M 4MHz 4.19M 6MHz 6.144 8MHz 10MHz 12MHz 12.288
; 115.2k - - - - 16 21 27 33 34
; 57.6k 19 21 22 33 34 44 56 68 69
; 38.4k 29 33 34 50 52 67 85 102 105
; 19.2k 60 67 71 102 105 138 173 208 211
; 9.6k 122 138 144 208 211 - - - -

.equ BPS = 173

.equ SIN = 5
.equ SOUT = 4


xmit: ; Transmit temp. r17 and r18 will be broken. (14 words)
com temp ;
sec ; Start bit
ldi r18,10 ; bit count
ldi r17,BPS-1 ; Wait for full bit time
dec r17 ;
brne PC-1 ;
brcs PC+2 ; SOUT = bit for send
cbi PORTB,SOUT ;
brcc PC+2 ;
sbi PORTB,SOUT ;
lsr temp ; next bit
dec r18 ; All sent ?
brne PC-9 ; no, coutinue
ret


receive:; Receive into temp. r17 will be broken. (16 words)
ldi temp,0x80 ; Shift register for receive
sbic PINB,SIN ; Wait for rise edge of SIN
rjmp PC-1 ;
sbis PINB,SIN ;
rjmp PC-1 ;
ldi r17,BPS/2 ; Wait for half bit time
dec r17 ;
brne PC-1 ;
ldi r17,BPS ; Wait for full bit time
dec r17 ;
brne PC-1 ;
lsr temp ; Next bit
sbis PINB,SIN ; Read SIN into temp.7
ori temp,0x80 ;
brcc PC-6 ; All bits received? no, continue
ret ; yes, end


;-----------------------------------------------------------------------------;
; End of soft UART code
;-----------------------------------------------------------------------------;




ygrat: ;Mark Y Graticle markings
;Starting with row 7, write dots every 12th row.

ldi pwmval,$00 ;Column counter - points to h. address in display
ldi YL,$07 ;Row counter
moreygrat:

mov temp,pwmval ;Send horizontal address of dot
rcall xmit
mov temp,YL ;Send vertical address of dot
rcall xmit
rcall receive ;Wait for display to complete action.
inc pwmval
cpi pwmval,3
brne moreygrat
ldi pwmval,$00
subi YL,-12
cpi YL,67
brne moreygrat
ldi temp,0
rcall xmit
ldi temp,30
rcall xmit
rcall receive
ldi temp,0
rcall xmit
ldi temp,32
rcall xmit
rcall receive
ldi temp,3
rcall xmit
ldi temp,31
rcall xmit
rcall receive
ldi temp,4
rcall xmit
ldi temp,31
rcall xmit
rcall receive
ret

xgrat: ;Mark X Graticle markings
;Starting with column 14, write every 10th column



ldi pwmval,14 ;Column counter - points to h. address in display
ldi YL,0 ;Row counter
morexgrat:
mov temp,pwmval ;Send horizontal address of dot
rcall xmit
mov temp,YL ;Send vertical address of dot
rcall xmit
rcall receive ;Wait for display to complete action.
subi pwmval,-10
cpi pwmval,124
brne morexgrat
ldi temp,63
rcall xmit
ldi temp,0
rcall xmit
rcall receive
ldi temp,65
rcall xmit
ldi temp,0
rcall xmit
rcall receive
ret



inputoohigh: ;Called when input signal is too high out of range. Put indicator in right column of display
;This method of writing marks on the top or bottom lines of the display is very crude, but
;lent itself to tweaking easily. A look-up table would look cleaner.

ldi temp,119
rcall xmit
ldi temp,63
rcall xmit
rcall receive

ldi temp,120
rcall xmit
ldi temp,63
rcall xmit
rcall receive

ldi temp,121
rcall xmit
ldi temp,63
rcall xmit
rcall receive

ldi temp,122
rcall xmit
ldi temp,63
rcall xmit
rcall receive

ldi temp,123
rcall xmit
ldi temp,63
rcall xmit
rcall receive

ldi temp,124
rcall xmit
ldi temp,63
rcall xmit
rcall receive

ldi temp,125
rcall xmit
ldi temp,63
rcall xmit
rcall receive
ldi temp,126
rcall xmit
ldi temp,63
rcall xmit
rcall receive
ldi temp,127
rcall xmit
ldi temp,63
rcall xmit
rcall receive
ret



inputtoolow: ;Called when input signal is too low out of range. Put indicator in right column of display



ldi temp,119
rcall xmit
ldi temp,00
rcall xmit
rcall receive

ldi temp,120
rcall xmit
ldi temp,00
rcall xmit
rcall receive


ldi temp,121
rcall xmit
ldi temp,00
rcall xmit
rcall receive


ldi temp,122
rcall xmit
ldi temp,00
rcall xmit
rcall receive

ldi temp,123
rcall xmit
ldi temp,00
rcall xmit
rcall receive


ldi temp,124
rcall xmit
ldi temp,00
rcall xmit
rcall receive


ldi temp,125
rcall xmit
ldi temp,00
rcall xmit
rcall receive
ldi temp,126
rcall xmit
ldi temp,00
rcall xmit
rcall receive
ldi temp,127
rcall xmit
ldi temp,00
rcall xmit
rcall receive
ret

;
;This is example code and is neither warranted to be useful for any particular purpose, nor to be safe to any degree.
;See http://www.projects.cappels.org for intellectual property and non-liability statement.
;
;  /////END OF DOCUMENT\\\\\\