; ******************************************************************* ; * PCM2PWG-Decoder for AT90S2323, Version 0.4 as of 20.12.2000 * ; * Translates pulse coded input to Pulse Width Generator Output * ; * (C)2000 by info@avr-asm-tutorial.net * ; ******************************************************************* ; ; Currently adjusted for 800 to 2200 µs signals and 4 MHz. ; Adjust constants below to fit to other timings! ; ; VCC LED PWG PCM PCM-Inp: 25ms = 40 Hz cycle time ; Out Out Inp active high pulse encoded signal ; +-8----7----6----5--+ ; | | PWG-Out: 1.4 ms = 714 Hz cycle time ; O AT 90 S 2323 | active high for 0..1.4 ms ; | | ; +-1----2----3----4--+ LED-Out: Active low if error occurs ; RST XT1 XT2 GND ; ; ********* Input Signal PCM encoded ************************** ; ; Phase I II III IV V VI VII ; PCM 1---- -------------------- ------ ; Inp \\\\\ / \\\\\\\\\\\\ / ; 0------------ ------------------------ ; ; ********* Output Signal Pulse Width Generator *************** ; ; PWG 1 ------------- ------ ; Out / \ / ; 0---- ------------- ; Time µs |<--0..cCycl->|<-cCycl..0-->| 800 - 2200 µs: ; |<----------cCycl---------->| cCycl = 1400 µs ; ; ************************************************************* ; .NOLIST .INCLUDE "C:\avrtools\appnotes\2323def.inc" .LIST ; ; Used registers ; .DEF rmpr = R16 ; Multi Purpose register .DEF rdel = R17 ; Register for delay loops .DEF rpwc = R18 ; Counter for pulse width generator .DEF rpws = R19 ; Current setting of pulse width generator .DEF rpwn = R20 ; Next setting of the pulse width generator .DEF rtry = R21 ; Number of retries .DEF rctr = R22 ; Counter for active cycles .DEF rerr = R23 ; Number of failures ; ZL = R30 and ZH = R31 used for counting long times ; ; IO-Port-Bits ; .EQU pbmode = 0b00000110 ; Port B Output pins .EQU bIn = 0 ; Input pin is 0, active high .EQU bOut = 1 ; Output pin for PWG, pulse width generator .EQU bFail = 2 ; Output pin for failure LED, active low ; ; Constants (1 cycle = 6 µs = 24 clock cycles @ 4 MHz) ; ; Adjust the xtal frequency for other clocks ; .EQU cXtal = 4 ; Crystal frequency in MHz ; ; Adjust this cycle length for other total lengthes of the input signal ; .EQU cPulseDuration = 25000 ; Total pulse length in µs ; ; Adjust the timing for other active high encoder pulses ; .EQU cMinPulse = 800 ; Minimum pulse length in µs .EQU cMaxPulse = 2200 ; Maximum pulse length in µs ; ; Adjust this fallback value in % of total duration if errors or ; signal-losses occur, 0%: Output is low, 100%: output is high, ; 50%: Output is 50% pulse width ; .EQU cFallBackValue = 50 ; 50% pulse width ; ; The following are automatically calculated from the above, ; don't adjust these without knowing what you do! ; .EQU cUnitLength = 24 ; Clock cycles per unit loop .EQU cCycleLength = cUnitLength/cXtal ; Total cycle length in µs .EQU cCycl = cPulseDuration/cCycleLength ; Cycles in 25 ms .EQU cStep = (cMaxPulse-cMinPulse)/cCycleLength ; Active cycles .EQU cTolerance = cStep/10; Tolerated short/long signal length .EQU cMinSteps = cMinPulse/cCycleLength ; Start counting active pulse .EQU cMaxSteps = cMaxPulse/cCycleLength ; Stop counting active pulse .EQU cMin1 = cMinSteps-cTolerance-1 ; Unit loops that must be active high .EQU cTlp = cTolerance-1 ; Early low units that are tolerated as Zero .EQU cTla = cTolerance ; Late units tolerated as One .EQU cMin0 = (cCycl-cMaxSteps)*90/100 ; Units that must be inactive .EQU cFbck = 1 ; Number of false signals to tolerate before default is set .EQU cDflt = cstep*cFallbackValue/100 ; Default fallback value for PWG ; ; Macros for Error-LED-Out (Active low) ; .MACRO LedErrOn cbi PortB,bFail .ENDM .MACRO LedErrOff sbi PortB,bFail .ENDM ; ; Macros for delays ; .MACRO Delay1 ; Single delay step nop .ENDM ; .MACRO Delay2 ; Double delay step nop nop .ENDM ; .MACRO Delay3 ; Delay macro for multiples of 3 steps ldi rdel,@0 MD3: dec rdel brne MD3 .ENDM ; .MACRO Delay4 ; Delay Macro for multiples of 4 steps ldi rdel,@0 MD4: dec rdel nop brne MD4 .ENDM ; .MACRO MacPwm ; Macro for Pulse Width Generator dec rpwc ; 1 1 1 1 breq MAP2 ; 1 1 2 2 cp rpws,rpwc ; 1 1 brcs MAP1 ; 1 2 nop ; 1 cbi PortB,bOut; 2 rjmp MAP3 ; 2 MAP1: sbi PortB,bOut; 2 rjmp MAP3 ; 2 MAP2: mov rpws,rpwn ; 1 1 ldi rpwc,cstep; 1 1 sbi PortB,bOut; 2 2 nop ; 1 1 nop ; 1 1 MAP3: ;----------- ; 9 9 9 9 ;=========== .ENDM ; ; Start of main program, Init variables ; Start: ldi rpwc,cDflt ; Counter of the pwm ldi rpws,cDflt ; Current pwm value ldi rpwn,cDflt ; Next pwg value ; ; Init the Port B ; ldi rmpr,pbmode ; Set data direction mode out DDRB,rmpr ; on Port B sbi PortB,bIn ; Switch pull-up resistor on ; ; Start phase I : Wait until input is pulled low ; ; Set error condition until signal is correct ; PH1: macpwm ; 9 ldi rerr,cFbck; 1 ldi rpwn,cDflt; 1 lederron ; 2 delay3(3) ; 9 ; ; Set one cycle length for negative edge detection ; PH1a: ldi ZL,Low(cCycl); 1 ldi ZH,HIGH(cCycl);1 ; --- ; 24 ; === ; Wait until input is pulled low or timeout occurs ; PH1b: macpwm ; 9 9 9 sbis PinB,bIn ; 2 2 1 rjmp PH2 ; 2 sbiw ZL,1 ; 2 2 breq PH1c ; 1 2 delay4(2) ; 8 rjmp PH1b ; 2 ; --- ; 24 ; === ; Timed out with input high ; PH1c: ; (15) delay4(1) ; 4 ; ; Error occured with input high, count subsequent errors ; PH1d: ;(19 19) dec rerr ; 1 1 brne PH1a ; 2 1 ; ; Too many subsequent errors with input high, set error condition ; delay1 ; 1 rjmp PH1 ; 2 ; --- ; 24 ; === ; Start Phase II: Input is low, wait for pulse or timeout ; PH2: ; (12) delay3(2) ; 6 delay2 ; 2 rjmp PH2b ; 2 ; ; Error occured with input low, set error condition ; PH2a: macpwm ; 9 ldi rerr,cFbck; 1 ldi rpwn,cDflt; 1 lederron ; 2 delay3(3) ; 9 ; ; Set counter for time out during input low ; PH2b: ; (22 22) ldi ZL,LOW(cCycl); 1 1 ldi ZH,HIGH(cCycl); 1 1 ; ------ ; 24 24 ; ====== ; Wait until input goes high or time-out occurs ; PH2c: macpwm ; 9 9 9 9 sbic PinB,bIn ; 2 2 2 1 rjmp PH3 ; 2 sbiw ZL,1 ; 2 2 2 breq PH2d ; 1 2 2 delay4(2) ; 8 rjmp PH2c ; 2 ; --- ; 24 ; === ; Time out during input low, count subsequent errors ; PH2d: ; (15 15) delay4(1) ; 4 4 PH2e: ; (19 19) dec rtry ; 1 1 brne PH2b ; 1 2 nop ; 1 rjmp PH2a ; 2 ; --- ; 24 ; === ; Phase III: Input gone high, check for cMin1 phases if stable ; PH3: ; (12) delay3(3) ; 9 delay2 ; 2 ldi rtry,cMin1; 1 ; --- ; 24 ; === ; Wait until cMin1 phases passed with input high ; PH3a: macpwm ; 9 9 9 sbis PinB,bIn ; 2 2 1 rjmp PH3b ; 2 dec rtry ; 1 1 breq PH4 ; 1 2 delay3(3) ; 9 rjmp PH3a ; 2 ; --- ; 24 ; === ; Early low detected during cMin1-phase, error with input low ; PH3b: ; (12) delay3(1) ; 3 delay2 ; 2 rjmp PH2e ; 2 ; ; Phase IV: Input is high for cMin1, pre-tolerance time ; PH4: ;(14) delay4(2) ; 8 ldi rtry,cTlp ; 1 ldi rctr,cstep; 1 ; --- ; 24 ; === ; Wait for pre-tolerance time or input early low ; PH4a: macpwm ; 9 9 9 sbis PinB,bIn ; 2 2 1 rjmp PH7 ; 2 dec rtry ; 1 1 breq PH5 ; 1 2 delay3(3) ; 9 rjmp PH4a ; 2 ; --- ; 24 ; === ; ; Phase V: End of pre-tolerance has been reached, count down now ; PH5: ; (14) delay4(2) ; 8 delay2 ; 2 ; --- ; 24 ; === PH5a: macpwm ; 9 9 9 sbis PinB,bIn ; 2 2 1 rjmp PH7 ; 2 dec rctr ; 1 1 breq PH6 ; 1 2 delay3(3) ; 9 rjmp PH5a ; 2 ; --- ; 24 ; === ; Phase VI: End of count reached, tolerate overtime ; PH6: ; (14) delay3(3) ; 9 ldi rtry,cTla ; 1 ; --- ; 24 ; === ; Overtime for cTla, break if overtime or input low ; PH6a: macpwm ; 9 9 9 sbis PinB,bIn ; 2 2 1 rjmp PH7 ; 2 dec rtry ; 1 1 breq PH6b ; 1 2 delay3(3) ; 9 rjmp PH6a ; 2 ; --- ; 24 ; === ; Active signal too long, failure condition with input high ; PH6b: ; (14) delay3(1) ; 3 rjmp PH1d ; 2 ; ; Phase VII: Input inactive, check minimum inactive time ; ; PH7: ; (12) delay4(2) ; 8 delay2 ; 2 ldi ZL,LOW(cMin0); 1 ldi ZH,HIGH(cMin0); 1 ; --- ; 24 ; === PH7a: macpwm ; 9 9 9 sbic PinB,bIn ; 2 2 1 rjmp PH7b ; 2 sbiw ZL,1 ; 2 2 breq PH7c ; 1 2 delay4(2) ; 8 rjmp PH7a ; 2 ; --- ; 24 ; === ; Early end of minimum inactive time, failure condition with input high ; PH7b: ; (12) delay3(1) ; 3 delay2 ; 2 rjmp PH1d ; 2 ; ; End of minimum inactive time reached, set result, restart with input low ; PH7c: ; (15) mov rpwn,rctr ; 1 ldi rerr,cFbck; 1 lederroff ; 2 delay1 ; 1 rjmp PH2b ; 2 ; ; End of the program ;