;*************************************************** ;* NMRA-DCC decoder based on ATtiny15 * ;* 2 ports used for h-bridge, no ADC * ;* * ;* write calibration byte to flash at adress 0x3FE * ;* brown-out detection level at VCC=2.7v * ;* CKSEL=10 Quickly rising power * ;* * ;* 08.04.2003 * ;*************************************************** ; This program is free software; you can redistribute it and/or ; modify it under the terms of the GNU General Public License as ; published by the Free Software Foundation; either version 2 of ; the License, or (at your option) any later version. ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ; General Public License for more details. ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ; Contact: ; Georg Ziegler ; Zwehrener Weg 23a ; 34121 Kassel ; -Germany- ; email: g.zi@gmx.de ;-------------------------------------------------------------------- ; 0000 0000 ... -> Broadcast Adress for all Lok Decoder ; 1111 1111 0000 0000 ... -> Idle Packet for all Decoder ; 0AAA AAAA ... -> short Adress ; 11AA AAAA AAAA AAAA ... -> long Adress ;... 01DL SSSS -> Lok Adress Direction Light & Speed ;... 100L FFFF -> Lok Function F1-F4 & FL ;... 1011 FFFF -> Lok Function F5-F8 ;... 1010 xxyy -> Lok Function up/down (01 inc; 10 dec; 00 reset) ;... 110D DDDD DDDD DDDD -> future expansion ;... 0011 1111 DSSS SSSS -> 128 FS ;... 0011 1110 DSSS SSSS -> restricted speed step ; programming modes =============================== ; 2B F9 D2 -> old ack mode ; DATA oack EXOR ;-------------------------------------------------- ; 7C 00 2B 57 -> direct mode ; DIR CV DATA EXOR ;0111w1vv vvvvvvvv DDDDDDDD -> dir mode ; ^0=verify/1=write ;011110vv vvvvvvvv 111wDBBB -> bit manipulation ; 0=verify/1=write^ ;-------------------------------------------------- ; 78 2B 53 -> register mode ; REG DATA EXOR ;0111 wRRR DDDD DDDD -> register mode ; ^verify/write cv = (reg6 - 1) * 4 + RRR ;-------------------------------------------------- ; 2B EC 00 64 A3 -> on the main programming ;addr otmp cv data exor ;0AAA AAAA 1110 11vv vvvv vvvv DDDD DDDD -> otm mode ;-------------------------------------------------- ; 7D 01 7C REG 6 -> paged mode prog ; 78 2B 53 REG 1-4 ;PAG+CV DATA EXOR ;011111RRR write ;011110RRR query ;-------------------------------------------------- ;CV29,0 ; direction inverted (+light) ;CV29,1 ; 14/28 speed step ;CV29,2 ; light inverted (PWRSRC never used) ;CV29,4 ; speedtab / CV2,CV5&CV6 ;CV29,5 ; long adress enable ;-------------------------------------------------- .equ pwm =4 ;ATtiny15=4, AT90S4433=6 .equ PWM_out =1 ;PWM = PB1(ATtiny15) .equ DIR_out =3 ; .equ flight =0 ; .equ rlight =4 ; .equ version =1 .equ cv7 =6 .equ manufacturer =$0D .equ cv8 =7 .equ dcc1lo =52 ;define low border of "1" .equ dcc1hi =64 ;define high border of "1" .equ dcc0 =90 ;define low border of "0" .equ preval =0x0B ; 0x0B ; eeprom adresses ............................. .equ cv1 =0 ;Primary Address .equ cv2 =1 ;Vstart .equ cv3 =2 ;Acceleration Rate .equ cv4 =3 ;Deceleration Rate .equ cv5 =4 ;Vhigh .equ cv6 =5 ;Vmid .equ cv33 =6 ;(Forward Headlight) .equ cv34 =7 ;(Reverse Headlight) .equ cv35 =8 ;(Function 1) .equ cv36 =9 ;(Function 2) .equ cv37 =10 ;(Function 3) .equ cv38 =11 ;(Function 4) .equ cv39 =12 ;(Function 5) .equ cv40 =13 ;(Function 6) .equ cv41 =14 ;(Function 7) .equ cv42 =15 ;(Function 8) .equ cv17 =16 ;Extended Address low .equ cv18 =17 ;Extended Address high .equ cv19 =18 ;Consist Address .equ cv29 =19 ;Configuration Data #1 ;....................Manufacturer Unique.............. .equ cv52 =20 ; .equ cv53 =21 ; .equ cv54 =22 ; .equ cv55 =23 ;(Vmax 2) .equ cv56 =24 ; .equ cv57 =25 ; .equ cv58 =26 ;Back EMF .equ cv59 =27 ;PWM frequency (113-127) 112=off 128=on ; non inv. PWM ( 97-111) .equ cv60 =28 ;PWM scale .equ cv61 =29 ; .equ cv62 =30 ; .equ cv63 =31 ; .equ cv64 =32 ;(configuration byte) ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .equ cv65 =33 ;Kick Start .equ cv66 =34 ;Forward Trim .equ cv67 =35 ;Speed Table 1 .equ cv68 =36 ;Speed Table 2 .equ cv69 =37 ;Speed Table 3 .equ cv70 =38 ;Speed Table 4 .equ cv71 =39 ;Speed Table 5 .equ cv72 =40 ;Speed Table 6 .equ cv73 =41 ;Speed Table 7 .equ cv74 =42 ;Speed Table 8 .equ cv75 =43 ;Speed Table 9 .equ cv76 =44 ;Speed Table 10 .equ cv77 =45 ;Speed Table 11 .equ cv78 =46 ;Speed Table 12 .equ cv79 =47 ;Speed Table 13 .equ cv80 =48 ;Speed Table 14 .equ cv81 =49 ;Speed Table 15 .equ cv82 =50 ;Speed Table 16 .equ cv83 =51 ;Speed Table 17 .equ cv84 =52 ;Speed Table 18 .equ cv85 =53 ;Speed Table 19 .equ cv86 =54 ;Speed Table 20 .equ cv87 =55 ;Speed Table 21 .equ cv88 =56 ;Speed Table 22 .equ cv89 =57 ;Speed Table 23 .equ cv90 =58 ;Speed Table 24 .equ cv91 =59 ;Speed Table 25 .equ cv92 =60 ;Speed Table 26 .equ cv93 =61 ;Speed Table 27 .equ cv94 =62 ;Speed Table 28 .equ cv95 =63 ;Reverse Trim ;******************************************************* ;dccin r0-r7 .def save =r8 .def cv1 =r9 .def cv17 =r9 .def cv18 =r10 .def cv19 =r9 .def xcount =r11 ;help r12 ;help register .def adcin =r13 ; # .def adcadd =r14 ; # .def mulH =r15 ;* result High byte ;dccin r16 .def status =r17 .equ ackbit =0 .equ progbit =1 .equ rom =2 .equ rst =3 .equ wait =4 .equ oldack =5 .equ lighton =6 .equ dir =7 .def w =r18 .def mulp =r18 ;* multiplier .def mulL =r18 ;* result Low byte .def count =r19 ;* loop counter .def cv29 =r20 .equ dirinv =0 ;direction inverted (+light) .equ fs28 =1 ;14/28 speed step .equ liinv =2 ;light inverted (pwrsrc never used) ;.equ free =3 ;advanced acknowledge .equ stab =4 ;speed table / cv2,cv5,cv6 .equ ladre =5 ;long adress enable ;.equ free =6 ; .equ fs126 =7 ;(Accessory decoder) .def soll =r21 .def f1f8 =r22 .def mulc =r23 ;* multiplicand .def byte =r24 .def pre =r25 .def acount =r26 ;X # adc counter ;free r27 ; .def bcount =r28 ;Y bit counter ;free r29 ; # .def nbyte =r30 ;Z byte counter .def zero =r31 .include "tn15def_mod.inc" .eseg ;EEPROM segment .org 0 .cseg ;CODE segment .org 0 ;ATtiny15 (AT90S4433) rjmp reset ;0 Reset handler (Reset handler) rjmp dccin ;1 External interrupt 0 ->PB2 (External interrupt 0 ->PD2) rjmp reset ;2 Pin change interrupt (External interrupt 1) rjmp reset ;3 timer1 compare match (timer1 capture event) rjmp reset ;4 timer1 overflow (timer1 compare match) rjmp reset ;5 timer0 overflow (timer1 overflow) rjmp reset ;6 EEPROM ready (timer0 overflow) rjmp reset ;7 analog comparator (SPI Transfer Complete Handler) rjmp reset ;8 ADC conversion complete (UART RX Complete Handler) reset: ; ldi w,149 ;147/148 low1 ldi w,0x68 ;internal value ; ldi w,255 ;fastest, has to be used with dcc calibration and preval=16 out OSCCAL,w ;Oscillator calibration ;load calibration byte from flash at adress 0x3FE................................. ; ldi zl,0xfe ;set low and high byte ; ldi zh,0x03 ;for indirect Z register ; lpm ;load flash 0x3FE (osccal value) ; out OSCCAL,r0 ;Oscillator calibration ;interrupt........................................................................ ; 00 low_level_int ; 01 toggle_int ; sleep_enable 10 falling_edge_int ; pull_up_disabled| 11 rising_edge_int ; || || ldi w,0b01000001 out MCUCR,w ldi w,0b01000000 ;enable ext int out GIMSK,w ;timer............................................................................ ldi w,0b00000010 ;timer prescaler /8 out TCCR0,w ;timer prescaler /8 for 1MHz <<<<<<<<<127 /\.. ldi mulc,cv6 rcall eeread ;mulc clc sbrc mulc,7 sec rol mulc ;sub/add in bit 0 rcall multip sbrs mulc,0 sub r12,mulH sbrc mulc,0 add r12,mulH mov w,r12 ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ;.cv2cv5.................................................................. cv2cv5: ldi mulc,cv2 rcall eeread ;mulc mov r12,mulc ldi mulc,cv5 rcall eeread ;mulc sub mulc,r12 rcall multip add mulH,r12 inc mulH ;speed to go ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ;forward(cv66), reverse(cv95) trim........................................ trim: mov mulp,mulH ; ldi mulc,cv66 ;forward trim sbrs status,dir ; ldi mulc,cv95 ;reverse trim rcall eeread ;mulc cpse mulc,zero ; trim? rcall multip ; rol mulL ;c<- cpse mulc,zero ; trim? rol mulH ;<-c (*2) ;step..................................................................... step: cpse xcount,zero ;xcount compare rjmp spdex ;exit mov w,pre ;calc_soll before ldi mulc,cv3 ;mov acceleration rate to multiplicant cp w,mulH ; breq spdex ;soll=ist brlo nocv4 ;sollist nocv4: inc w ;increment actual speed wrtpwm: rcall eeread ;mulc mov xcount,mulc ;load new counter value mov pre,w ;copy calc_soll to pre ;kick start............................................................... in r27,OCR10 ; cpse r27,zero ; rjmp kckend ;pwm not zero cp pre,zero ; breq kckend ;calc_soll is zero ldi mulc,cv65 ;mulc = adr EEPROM rcall eeread ; cp mulc,zero ; breq kckend ;no kickstart mov pre,mulc ;kick start kckend: ;out OCR10,pre ;write PWM spdex: ;rjmp loop ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ;.ADC.............................................................................. ADC: ldi mulc,cv58 ;mulc = adr EEPROM rcall eeread ;result in mulc ; cp mulc,zero ; ; breq adcend ;no back EMF inc acount ;counter for delay ;cpi acount,80 cp acount,mulc brbc 1,adcex ;not zero clr acount cbi PORTB,0 cbi PORTB,4 ; ldi mulc,cv57 ;mulc = adr EEPROM ; rcall eeread ;result in mulc ; cp adcin,pre ; ; brlo incadc ; ; add mulc,adcin ; ; brbc 0,nomax ; ; ldi mulc,255 ; ;nomax: cp mulc,pre ; ; brsh decadc ; ldi mulc,cv56 ;mulc = adr EEPROM rcall eeread ; cp adcin,mulc ; brlo incadc ldi mulc,cv57 ;mulc = adr EEPROM rcall eeread ; cp adcin,mulc ; brsh decadc ; adcend: out OCR10,pre ;write PWM rjmp loop ; incadc: sbi PORTB,0 ;LED gelb rjmp adcend ;test no adc inc adcadd ; brbc 1,adcex ;not zero dec adcadd ; rjmp adcex ; decadc: sbi PORTB,4 ;LED grün rjmp adcend ;test no adc cp adcadd,zero ; brbs 1,adcex ;zero dec adcadd ; rjmp adcex ; ; ldi w,0x3F ; out eear,w ;output address ; out eedr,adcadd ;output data ; sbi eecr,eemwe ;set master write enable ; sbi eecr,eewe ;set EEPROM Write strobe adcex: mov mulc,pre ; mov w,adcadd ; subi w,0b01111111 ; brbc 0,adcex2 ; com w ; sub mulc,w ; brbc 0,adcex1 ; ldi mulc,0 ; adcex1: out OCR10,mulc ;write PWM rjmp loop ; adcex2: add mulc,w ; brbc 0,adcex3 ; ldi w,255 ; adcex3: out OCR10,mulc ;write PWM rjmp loop ; ; sbrc adcin,7 ; sbi PORTB,0 ; sbrc adcin,6 ; sbi PORTB,4 ; rjmp loop ; ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ;......................................................................... eeread: sbic EECR,EEWE ;if EEWE not clear rjmp eeread ;wait more out EEAR,mulc ;write EEadress sbi EECR,EERE ;set read enable in mulc,EEDR ret ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ;...... external interrupt ............................................... dccin: in save,SREG ;save status ;int toggle mode, use with simulator...................................... in r7,MCUCR ;toggle between ldi r16,1 ;rising and eor r16,r7 ;falling edge ori r16,0b00000010 ;set "edge" int bit out MCUCR,r16 ;interrupt ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ sbic PINB,2 ;check port after int rjmp low ;low bit in r16,TCNT0 ;save timer inc bcount ;bit counter cpi r16,preval ;compare actual bit with bit before breq precnt ; inc r16 ; cpi r16,preval ;compare one higher breq precnt ; subi r16,2 ; cpi r16,preval ;compare one lower breq precnt ; inc r16 ; cpi r16,(preval/2+preval);preval timer value for one (7~52us) brlo preerr ;bit error (r166 byte command rjmp dccout ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ;.cv...................................................................... true: ;.ADCin............................................................................ in adcin,ADCL in r16,ADCH ror r16 ;->c ror adcin ; c-> ror r16 ;->c ror adcin ; c-> actual sampled speed ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ldi nbyte,1 ;one after adress cp r0,zero ;broadcast/reset = 0 breq decod cpse cv1,r0 rjmp chkprog sbrc cv29,ladre ;long adress enable sbrs r1,7 ;>04 byte packet brge prog ;pom mode 5/6 bytes ori status,0b00001000 ;set rst bit rjmp exit1 ;......................................................................... chkprog:mov nbyte,r7 ;restore byte counter dec nbyte ; ldi r16,0b01110000 eor r16,r0 andi r16,0b11110000 brne exit ;nothing to decode cpi nbyte,1 ; = 3 byte packet breq progreg sbrs r0,3 ;0111w1vv rjmp acknow ; ^verify/write prog: sbic EECR,EEWE ;if EEWE not clear rjmp prog ;wait more ld r16,Z ;load data byte out EEDR,r16 ;store data into EEdata dec nbyte ld r16,Z ;load adress byte ;...... exchange CVs to save eeprom adresses ............................. xchcv: ldi byte,version cpi r16,cv7 breq cvrom ldi byte,manufacturer cpi r16,cv8 breq cvrom cpi r16,28 ;cv29 brne nxtcv ldi r16,19 ;cv29 -> ee19 nxtcv: cpi r16,32 ;32-41 -> ee6-15 brlo cvram subi r16,(32-6) ;32 -> ee6 ;cv52-cv64 manufacturer, cv65 kick start, cv66 forward trim, cv67-94 speed table, cv95 reverse trim nxtcv1: cpi r16,(51-32+6) ;51-94 -> ee20-63 brlo cvram subi r16,(51-32+6-20);51 -> ee20 cpi r16,64 ;eeprom end brsh exit ;ignore > cv95 ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cvram: out EEAR,r16 ;store adress into EEadress romex: dec nbyte ld r16,Z cpi r16,0b01111000 ;bit manipulation breq bitman write: sbrc status,rom ;romcv? rjmp exit sbrc status,progbit ;prog set? <<<<<<<<<<<1T dir bld status,dir ;<-T dir lsl soll ;SSSSSSS0 advanex:rjmp exdir ftion: bst r16,4 ;->T light sbrc r16,4 bld cv29,fs28 ;<-T light sbrc cv29,fs28 bld status,lighton ;<-T light ftion2: andi r16,0b00001111 andi f1f8,0b11110000 or f1f8,r16 rjmp exit ftion1: sbrs r16,4 rjmp ftion2 ;1011 swap r16 andi r16,0b11110000 andi f1f8,0b00001111 or f1f8,r16 rjmp exit telnew: rjmp exit spd: ld soll,Z ;01DLSSSS bst soll,5 ;->T dir bld status,dir ;<-T dir bst soll,4 ;->T light lsl soll ;1DLSSSS0<- andi soll,0b00011110 sbrs cv29,fs28 ;light or speed bld status,lighton ;<-T light sbrc cv29,fs126 ;light or speed rjmp spd1 sbrs cv29,fs28 ;light or speed bld soll,0 ;<-T speed spd1: cbr cv29,0b10000000 ;fs126 rjmp exdir concon: rjmp exit ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ;...... multiply ......................................................... ;result, low_byte and multiplier share same register multip: clr mulH ;clear high_byte ldi count,8 ;init loop counter lsr mulp ;rotate multiplier mult1: brcc mult2 ;carry set add mulH,mulc ;add multiplicand to high_byte mult2: ror mulH ;rotate right high_byte ror mulL ;rotate right low_byte and multiplier dec count ;decrement loop counter brne mult1 ;if not done, loop more ret ; ;r19 count= loop counter ;r23 mulc = multiplicand ;r18 mulp = multiplier ;r15 mulH = result High byte ;r18 mulL = result Low byte ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^