AS V1.42 Beta [Bld 20] - source file dcc_lok.asm - page 1 - 4/23/2002 0:20:28 1/ 0 : ;*************************************************************************** 2/ 0 : INCLUDE at90s1200.inc 3/ 0 : LISTING ON 4/ 0 : PAGE 92 5/ 0 : 6/ 0 : =0.25 CLOCK: EQU 0.25 ; cycle time in usec 7/ 0 : =0x40 BIT_HI: EQU 64 ; '1' is at most 64 usec 8/ 0 : =0x5A BIT_LO: EQU 90 ; '0' is at least 90 usec 9/ 0 : =2 T0_RES: EQU 8*CLOCK ; T0 increments in 8 * cycle time intervals 10/ 0 : =0x2710 ACKWID: EQU 10000 ; acknowledge pulse width in usec 11/ 0 : 12/ 0 : ; Threshold value to distinguish '1' from '0' 13/ 0 : =0x27 THRESH: EQU int ((BIT_HI+BIT_LO+T0_RES)/(2*T0_RES)) 14/ 0 : 15/ 0 : ; Acknowledge pulse width in timer0 overflows 16/ 0 : =0x13 ACKPLS: EQU int (ACKWID/(T0_RES*256)) 17/ 0 : 18/ 0 : ; Interrupt mask 19/ 0 : =0x40 GI_MSK: EQU (1 << INT0) ; only INT0 interrupt 20/ 0 : 21/ 0 : ; Output mapping 22/ 0 : =0x18 FLOWER: EQU PORTB ; port for F1-F4 outputs (bits 0-3) 23/ 0 : =0x18 FUPPER: EQU PORTB ; port for F5-F8 outputs (bits 4-7) 24/ 0 : =0x1F PORTBD: EQU 0x1F ; set F1-F5 as output 25/ 0 : 26/ 0 : =0x12 FLPRTF: EQU PORTD ; port for FL output forward 27/ 0 : =0x4 FLBITF: EQU 4 ; bit for FL output forward 28/ 0 : =0x12 FLPRTR: EQU PORTD ; port for FL output forward 29/ 0 : =0x5 FLBITR: EQU 5 ; bit for FL output reverse 30/ 0 : =0x12 MOTPRT: EQU PORTD ; port for motor pwm output 31/ 0 : =0x0 MOTPWM: EQU 0 ; bit for motor pwm output 32/ 0 : =0x12 DIRPRT: EQU PORTD ; port for direction output 33/ 0 : =0x1 DIREC1: EQU 1 ; bit for direction output 1 34/ 0 : =0x3 DIREC2: EQU 3 ; bit for direction output 2 35/ 0 : =0x3B PORTDD: EQU (1<= 0x80, then no correction 167/ 16 : 9433 INC R3 ; rollover, so increment high byte 168/ 17 : E207 EXT_RI1:LDI R16,THRESH ; load threshold 169/ 18 : 0E20 ADD R2,R16 ; add to capture low byte 170/ 19 : 2700 CLR R16 ; extend to 16 bit 171/ 1A : 1E30 ADC R3,R16 ; add to high byte with carry 172/ 1B : E400 EXT_RET:LDI R16,GI_MSK ; load interrupt mask 173/ 1C : BF0B OUT GIMSK,R16 ; move to mask register 174/ 1D : BE0F OUT SREG,R0 ; restore status register 175/ 1E : 9518 RETI ; all done 176/ 1F : 177/ 1F : 6001 EXT_FAL:ORI R16,(1 << ISC00) ; falling edge, so select 178/ 20 : BF05 OUT MCUCR,R16 ; rising edge now 179/ 21 : B702 IN R16,TCNT0 ; get timer0 low byte 180/ 22 : 1A20 SUB R2,R16 ; subtract from capture low byte 181/ 23 : 0831 SBC R3,R1 ; subtract from capture high byte 182/ 24 : 2300 TST R16 ; if capture low byte is 183/ 25 : F022 BRMI EXT_FA1 ; >= 0x80, then no correction 184/ 26 : B708 IN R16,TIFR AS V1.42 Beta [Bld 20] - source file dcc_lok.asm - page 3 - 4/23/2002 0:20:28 185/ 27 : FB01 BST R16,TOV0 ; test for timer0 overflow 186/ 28 : F40E BRTC EXT_FA1 ; no overflow, so no correction 187/ 29 : 943A DEC R3 ; rollover, so decrement(!) high byte 188/ 2A : 9430 EXT_FA1:COM R3 ; bit 7 of R3 is received bit now 189/ 2B : 2D0A MOV R16,R10 190/ 2C : 3100 CPI R16,BYTE_1 ; if preamble already 191/ 2D : F468 BRSH EXT_DAT ; detected, collect data bit 192/ 2E : 300A CPI R16,PREAMB ; if preamble not 193/ 2F : F439 BRNE EXT_PRE ; complete, jump 194/ 30 : FE37 SBRS R3,7 ; if '0' start bit, 195/ 31 : E100 LDI R16,BYTE_1 ; then proceed to first byte 196/ 32 : 2EA0 MOV R10,R16 ; update state variable 197/ 33 : 2466 CLR R6 198/ 34 : 2477 CLR R7 ; clear R6,R7,R8 for checksum 199/ 35 : 2488 CLR R8 200/ 36 : CFE4 RJMP EXT_RET 201/ 37 : 202/ 37 : 94A3 EXT_PRE:INC R10 ; here: preamble not complete 203/ 38 : FE37 SBRS R3,7 ; if '0' bit detected, 204/ 39 : 24AA EXT_ERR:CLR R10 ; then start over 205/ 3A : CFE0 RJMP EXT_RET 206/ 3B : 207/ 3B : FAA3 EXT_DAT:BST R10,3 ; if bit 3 of state variable is 208/ 3C : F026 BRTS EXT_STP ; set, expect start or stop bit 209/ 3D : 0C33 LSL R3 ; shift data bit into carry 210/ 3E : 1C99 ROL R9 ; then into byte 6 register 211/ 3F : 94A3 INC R10 ; increment state variable 212/ 40 : CFDA RJMP EXT_RET 213/ 41 : 214/ 41 : 2033 EXT_STP:TST R3 215/ 42 : F052 BRMI EXT_STO ; jump if stop bit received 216/ 43 : 2C45 MOV R4,R5 217/ 44 : 2C56 MOV R5,R6 218/ 45 : 2C67 MOV R6,R7 ; shift bytes one position downwards 219/ 46 : 2C78 MOV R7,R8 220/ 47 : 2C89 MOV R8,R9 221/ 48 : 3600 CPI R16,BYTE_6 ; if at least 6 bytes received yet, 222/ 49 : F778 BRSH EXT_ERR ; discard packet and start over 223/ 4A : 5F08 SUBI R16,-0x08 ; to next byte start 224/ 4B : 2EA0 MOV R10,R16 ; update state variable 225/ 4C : CFCE RJMP EXT_RET ; no error, so continue 226/ 4D : 227/ 4D : 3300 EXT_STO:CPI R16,BYTE_3 ; at least 3 bytes received? 228/ 4E : F350 BRLO EXT_ERR ; no, then error 229/ 4F : 2494 EOR R9,R4 230/ 50 : 2495 EOR R9,R5 231/ 51 : 2496 EOR R9,R6 ; calculate checksum 232/ 52 : 2497 EOR R9,R7 233/ 53 : 2498 EOR R9,R8 234/ 54 : 2099 TST R9 ; if checksum not ok, then 235/ 55 : F719 BRNE EXT_ERR ; discard packet and start over 236/ 56 : 24AA CLR R10 ; prepare for next packet, stop 237/ 57 : 94A3 INC R10 ; bit is start bit for next packet 238/ 58 : 31E0 CPI R30,BUFEND ; if last packet not consumed by 239/ 59 : F2F8 BRLO EXT_ERR ; main loop, discard new one 240/ 5A : 2CB4 MOV R11,R4 241/ 5B : 2CC5 MOV R12,R5 242/ 5C : 2CD6 MOV R13,R6 ; hand data to main loop 243/ 5D : 2CE7 MOV R14,R7 244/ 5E : 2CF8 MOV R15,R8 245/ 5F : 9502 SWAP R16 ; shift right 4 positions 246/ 60 : 700F ANDI R16,0x0F ; this yield byte count 247/ 61 : 950A DEC R16 ; don't need checksum anymore 248/ 62 : E1E0 LDI R30,BUFEND 249/ 63 : 1BE0 SUB R30,R16 ; pointer to first valid byte 250/ 64 : 27FF CLR R31 ; clear Z high byte for compat. 251/ 65 : 95A8 WDR ; successfull transfer 252/ 66 : CFB4 RJMP EXT_RET ; all done!!! 253/ 67 : 254/ 67 : ; Main entry 255/ 67 : 95A8 RESET: WDR ; reset watchdog 256/ 68 : ; LDI R16,XRAMEND ; initialize 257/ 68 : ; OUT SPL,R16 ; stack pointer 258/ 68 : 259/ 68 : ; Setup watchdog 260/ 68 : E00F LDI R16,(1 << WDE)|(1 << WDP2)|(1 << WDP1)|(1 << WDP0) 261/ 69 : BD01 OUT WDTCR,R16 ; configure watchdog 262/ 6A : 263/ 6A : ; Setup external interrupt 264/ 6A : E003 LDI R16, (1 << ISC01)|(1 << ISC00) 265/ 6B : BF05 OUT MCUCR,R16 ; set INT0 to rising edge triggered 266/ 6C : E400 LDI R16,GI_MSK ; load interrupt mask 267/ 6D : BF0B OUT GIMSK,R16 ; move to mask register 268/ 6E : 269/ 6E : ; Setup timer0 270/ 6E : E002 LDI R16,(0 << CS02)|(1 << CS01)|(0 << CS00) 271/ 6F : BF03 OUT TCCR0,R16 ; set timer0 prescaler to CK/8 272/ 70 : E002 LDI R16,(1 << TOIE0) 273/ 71 : BF09 OUT TIMSK,R16 ; enable timer0 interrupt 274/ 72 : 275/ 72 : ; Setup port direction 276/ 72 : E10F LDI R16,PORTBD ; set F1-F4 to AS V1.42 Beta [Bld 20] - source file dcc_lok.asm - page 4 - 4/23/2002 0:20:28 277/ 73 : BB07 OUT DDRB,R16 ; output 278/ 74 : E30B LDI R16,PORTDD ; set FL f/r and 279/ 75 : BB01 OUT DDRD,R16 ; motor/dir. to output 280/ 76 : 281/ 76 : ; Setup registers 282/ 76 : 24AA CLR R10 ; initialize state variable 283/ 77 : D17C RCALL CHCKSM ; compute checksum 284/ 78 : 176F CP R22,R31 ; check against stored 285/ 79 : F021 BREQ RESET1 ; if match, then o.k. 286/ 7A : 2722 CLR R18 ; desired speed = 0 287/ 7B : 2733 CLR R19 ; current speed = 0 288/ 7C : 2744 CLR R20 ; F1-F8 off 289/ 7D : 2755 CLR R21 ; FL forw & revr off 290/ 7E : 2799 RESET1: CLR R25 ; initialize acc./dec. 291/ 7F : 27AA CLR R26 ; for EEPROM security 292/ 80 : 9478 SEI ; enable interrupts now! 293/ 81 : 294/ 81 : ; Start with definite state 295/ 81 : EFEF RESET2: SER R30 ; no valid packet yet 296/ 82 : 297/ 82 : ; Entry point for main loop. 298/ 82 : D171 LOOP: RCALL CHCKSM ; compute checksum 299/ 83 : 2F6F MOV R22,R31 ; store checksum 300/ 84 : 301/ 84 : ; First do motor PWM. Additionally, accelaration and 302/ 84 : ; decelaration is handled. CV009 = %0000PPPP where 303/ 84 : ; PPPP = 0001, ..., 1111. 128 speed steps are used, 304/ 84 : ; so the total PWM period is 305/ 84 : ; (%0000PPPP << 3) * 128 * T0_RES = 2 ms ... 31 ms, 306/ 84 : ; or 32 ... 500 Hz. So the greatest output compare 307/ 84 : ; difference is 15360 which fits into 14 bits. 308/ 84 : 2DD1 MOV R29,R1 ; capture timer0 high byte 309/ 85 : B7C2 IN R28,TCNT0 ; capture timer0 low byte 310/ 86 : 15D1 CP R29,R1 ; check for overflow 311/ 87 : F7D1 BRNE LOOP ; if yes, then capture again 312/ 88 : 1BC7 SUB R28,R23 ; compare capture to compare 313/ 89 : 0BD8 SBC R29,R24 ; value, if not passed 314/ 8A : F142 BRMI DX_PW3 ; yet, do nothing here 315/ 8B : E0F9 LDI R31,CV009 ; read pwm period 316/ 8C : D14B RCALL READ ; into R31 317/ 8D : 70FF ANDI R31,0x0F ; discard upper nibble 318/ 8E : F409 BRNE DO_PW1 ; value ok? 319/ 8F : E0F8 LDI R31,0x08 ; if not, use default 320/ 90 : 321/ 90 : ; Multiply CV009 lower nibble by current speed R19 322/ 90 : 27CC DO_PW1: CLR R28 ; clear result low byte 323/ 91 : 27DD CLR R29 ; clear result high byte 324/ 92 : FB37 BST R19,7 ; save direction flag 325/ 93 : 773F ANDI R19,0x7F ; discard direction flag 326/ 94 : F411 BRNE DO_NO0 ; if current speed equals 327/ 95 : F937 BLD R19,7 ; zero, restore direction 328/ 96 : C01D RJMP PWM_OF ; flag and turn motor off 329/ 97 : FDF0 DO_NO0: SBRC R31,0 ; test multiplier bit 0 330/ 98 : 0FD3 ADD R29,R19 ; add mutiplicand to result 331/ 99 : 95D6 LSR R29 ; shift result, bit 0 of high 332/ 9A : 95C7 ROR R28 ; byte via carry into low one 333/ 9B : FDF1 SBRC R31,1 ; test multiplier bit 1 334/ 9C : 0FD3 ADD R29,R19 ; add mutiplicand to result 335/ 9D : 95D6 LSR R29 ; shift result, bit 0 of high 336/ 9E : 95C7 ROR R28 ; byte via carry into low one 337/ 9F : FDF2 SBRC R31,2 ; test multiplier bit 2 338/ A0 : 0FD3 ADD R29,R19 ; add mutiplicand to result 339/ A1 : 95D6 LSR R29 ; shift result, bit 0 of high 340/ A2 : 95C7 ROR R28 ; byte via carry into low one 341/ A3 : FDF3 SBRC R31,3 ; test multiplier bit 3 342/ A4 : 0FD3 ADD R29,R19 ; add mutiplicand to result 343/ A5 : 95D6 LSR R29 ; shift result, bit 0 of high 344/ A6 : 95C7 ROR R28 ; byte via carry into low one 345/ A7 : 95D6 LSR R29 ; shift result, bit 0 of high 346/ A8 : 95C7 ROR R28 ; byte via carry into low one 347/ A9 : F937 BLD R19,7 ; restore direction flag 348/ AA : 349/ AA : 2D81 DO_PW2: MOV R24,R1 ; capture timer0 high byte 350/ AB : B772 IN R23,TCNT0 ; capture timer0 low byte 351/ AC : 1581 CP R24,R1 ; check for overflow 352/ AD : F7E1 BRNE DO_PW2 ; if yes, then capture again 353/ AE : 9990 SBIC MOTPRT,MOTPWM ; test motor control bit 354/ AF : C004 RJMP PWM_OF ; if set, then goto motor off 355/ B0 : 9A90 PWM_ON: SBI MOTPRT,MOTPWM ; else motor on 356/ B1 : 0F7C ADD R23,R28 ; and add motor on period 357/ B2 : 1F8D ADC R24,R29 ; to timer0 capture value 358/ B3 : C025 DX_PW3: RJMP DO_PW3 359/ B4 : 360/ B4 : 9890 PWM_OF: CBI MOTPRT,MOTPWM ; motor off 361/ B5 : 1B7C SUB R23,R28 ; subtract motor on period 362/ B6 : 0B8D SBC R24,R29 ; from timer0 capture value 363/ B7 : 0F9F ADD R25,R31 ; update acc./dec. timer 364/ B8 : 0FFF LSL R31 ; calculate cycle time 365/ B9 : 0FFF LSL R31 ; in timer0 clocks 366/ BA : 0F8F ADD R24,R31 ; add to capture value 367/ BB : 368/ BB : ; Acceleration/deceleration is by CV003/CV004 times 2ms AS V1.42 Beta [Bld 20] - source file dcc_lok.asm - page 5 - 4/23/2002 0:20:28 369/ BB : ; per speed step based on 128 steps 370/ BB : 2FC2 ACCDEC: MOV R28,R18 ; get desired speed 371/ BC : 2FF2 MOV R31,R18 ; check whether desired/ 372/ BD : 27F3 EOR R31,R19 ; current direction differ 373/ BE : FDF7 SBRC R31,7 ; if yes, then set 374/ BF : 27CC CLR R28 ; desired speed to zero 375/ C0 : 77CF ANDI R28,0x7F ; discard direction 376/ C1 : 2FD3 MOV R29,R19 ; get current speed 377/ C2 : 77DF ANDI R29,0x7F ; discard direction 378/ C3 : 17CD CP R28,R29 ; accelerate/decelerate? 379/ C4 : F079 BREQ CH_DIR ; no, change direction 380/ C5 : F018 BRLO DECELE ; goto deceleration 381/ C6 : E0F3 ACCELE: LDI R31,CV003 ; acceleration rate 382/ C7 : 95D3 INC R29 ; increment speed 383/ C8 : C002 RJMP AC_DEC 384/ C9 : E0F4 DECELE: LDI R31,CV004 ; deceleration rate 385/ CA : 95DA DEC R29 ; decrement speed 386/ CB : D10C AC_DEC: RCALL READ ; get value 387/ CC : 23FF TST R31 ; if acceleration 388/ CD : F411 BRNE AC_DE1 ; then delay required 389/ CE : 2FDC MOV R29,R28 ; set new speed without 390/ CF : C006 RJMP AC_DE2 ; any delay 391/ D0 : 392/ D0 : 179F AC_DE1: CP R25,R31 ; count reached? 393/ D1 : F038 BRLO DO_PW3 ; if not, do nothing 394/ D2 : 1B9F SUB R25,R31 ; update count 395/ D3 : C002 RJMP AC_DE2 ; set speed now 396/ D4 : 397/ D4 : 2F32 CH_DIR: MOV R19,R18 ; only if speed = 0 ! 398/ D5 : 2799 CLR R25 ; clear count 399/ D6 : FB37 AC_DE2: BST R19,7 ; save current direction 400/ D7 : 2F3D MOV R19,R29 ; update speed 401/ D8 : F937 BLD R19,7 ; restore direction 402/ D9 : E1C4 DO_PW3: LDI R28,CV055 ; get CV057 address 403/ DA : 2DD1 MOV R29,R1 ; get timer0 high byte 404/ DB : FBD3 BST R29,3 ; if phase 00-07, then 405/ DC : F456 BRTC DO_PW4 ; offset equals 0 406/ DD : 95C3 INC R28 ; else at least 1 407/ DE : FBD2 BST R29,2 ; if phase 08-0B, then 408/ DF : F43E BRTC DO_PW4 ; offset equals 1 409/ E0 : 95C3 INC R28 ; else at least 2 410/ E1 : FBD1 BST R29,1 ; if phase 0C-0D, then 411/ E2 : F426 BRTC DO_PW4 ; offset equals 2 412/ E3 : 95C3 INC R28 ; else at least 3 413/ E4 : FBD0 BST R29,0 ; if phase 0E, then 414/ E5 : F40E BRTC DO_PW4 ; offset equals 3 415/ E6 : 95C3 INC R28 ; else (in phase 0F) 4 416/ E7 : 2FFC DO_PW4: MOV R31,R28 ; copy pointer into 417/ E8 : D0EF RCALL READ ; FL array and get value 418/ E9 : FB37 BST R19,7 ; copy direction flag 419/ EA : F456 BRTC FL_REV ; dir. = 0 means reverse 420/ EB : 9A91 FL_FOR: SBI DIRPRT,DIREC1 ; set direction output 1 421/ EC : 9893 CBI DIRPRT,DIREC2 ; clear direction output 2 422/ ED : 9895 CBI FLPRTR,FLBITR ; clear FL reverse output 423/ EE : B3D2 IN R29,FLPRTF 424/ EF : FB50 BST R21,STFLFO ; copy FL forward status 425/ F0 : FFF0 SBRS R31,STFLFO 426/ F1 : 94E8 CLT 427/ F2 : F9D4 BLD R29,FLBITF ; to FL forward output 428/ F3 : BBD2 OUT FLPRTF,R29 429/ F4 : C009 RJMP DO_PW5 430/ F5 : 431/ F5 : 9891 FL_REV: CBI DIRPRT,DIREC1 ; clear direction output 1 432/ F6 : 9A93 SBI DIRPRT,DIREC2 ; set direction output 2 433/ F7 : 9894 CBI FLPRTF,FLBITF ; clear FL forward output 434/ F8 : B3D2 IN R29,FLPRTR 435/ F9 : FB51 BST R21,STFLRE ; copy FL reverse status 436/ FA : FFF1 SBRS R31,STFLRE 437/ FB : 94E8 CLT 438/ FC : F9D5 BLD R29,FLBITR ; to FL reverse output 439/ FD : BBD2 OUT FLPRTR,R29 440/ FE : 441/ FE : 2FFC DO_PW5: MOV R31,R28 ; pointer into FL array 442/ FF : 5FFB SUBI R31,CV055-CV060 ; adjust to F1-F8 array 443/ 100 : D0D7 RCALL READ ; get value 444/ 101 : 23F4 AND R31,R20 ; and to F1-F8 state 445/ 102 : BBF8 OUT PORTB,R31 ; output F1-F8 PWM state 446/ 103 : 447/ 103 : ; Now copy CV029 to R17 for easy access, then compare various addresses 448/ 103 : 31E0 LOOPAD: CPI R30,BUFEND ; if there is no packet to 449/ 104 : F590 BRSH LOOPX ; process, just take care of PWM 450/ 105 : E1F0 LDI R31,CV029 ; point to configuration variable 451/ 106 : BBFE OUT EEAR,R31 ; set address register 452/ 107 : 9AE0 SBI EECR,EERE ; read configuration variable 453/ 108 : B31D IN R17,EEDR ; save CV029 for faster access 454/ 109 : 731F CBR R17,(1 << PRIADD)|(1 << CONADD) 455/ 10A : 27FF CLR R31 ; clear Z high byte for comp. 456/ 10B : 80B0 LD R11,Z ; get first data byte 457/ 10C : 95E3 INC R30 ; byte consumed now 458/ 10D : 20BB TST R11 ; check for broadcast address 459/ 10E : F411 BRNE LOOPCP ; if yes, then both primary 460/ 10F : 6C10 SBR R17,(1 << PRIADD)|(1 << CONADD) ; and consist AS V1.42 Beta [Bld 20] - source file dcc_lok.asm - page 6 - 4/23/2002 0:20:28 461/ 110 : C00F RJMP COMPAR ; address match 462/ 111 : 463/ 111 : F092 LOOPCP: BRMI LOOPEX ; jump if 2 byte address 464/ 112 : FB15 BST R17,CFGEXT ; ignore primary address if 465/ 113 : F02E BRTS LOOPCO ; extended addressing enabled 466/ 114 : E0F1 LDI R31,CV001 ; point to primary address 467/ 115 : D0C2 RCALL READ ; get value in R31 468/ 116 : 25FB EOR R31,R11 ; compare to primary address 469/ 117 : F409 BRNE LOOPCO ; check consist if no match 470/ 118 : 6410 SBR R17,(1 << PRIADD) ; set primary match flag 471/ 119 : E0FC LOOPCO: LDI R31,CV019 ; point to consist address 472/ 11A : D0BD RCALL READ ; get value in R31 473/ 11B : 77FF ANDI R31,0x7F ; ignore bit 7 of consist address 474/ 11C : F021 BREQ LOOPCN ; jump if consist inactive 475/ 11D : 16BF CP R11,R31 ; compare to consist address 476/ 11E : F409 BRNE COMPAR ; jump if no match 477/ 11F : 6810 SBR R17,(1 << CONADD) ; set consist match flag 478/ 120 : C014 COMPAR: RJMP COMMND ; process command 479/ 121 : 480/ 121 : FB16 LOOPCN: BST R17,PRIADD ; copy primary match flag 481/ 122 : F917 BLD R17,CONADD ; to consist match flag 482/ 123 : C011 RJMP COMMND ; process command 483/ 124 : 484/ 124 : ; Check extended address, note that extended address can't ever match 485/ 124 : ; consist address as that is (by definition) always a 7 bit address 486/ 124 : D0AF LOOPEX: RCALL GET2ND ; get lsb of address 487/ 125 : FB15 BST R17,CFGEXT ; ignore extended address if 488/ 126 : F476 BRTC COMMND ; extended addressing disabled 489/ 127 : E0FA LDI R31,CV017 ; point to msb of ext. address 490/ 128 : D0AF RCALL READ ; get value in R31 491/ 129 : 11FB CPSE R31,R11 ; compare to msb of ext. address 492/ 12A : CF56 RJMP RESET2 ; no match at all, discard packet 493/ 12B : E0FB LDI R31,CV018 ; point to lsb of ext. address 494/ 12C : D0AB RCALL READ ; get value in R31 495/ 12D : 11FC CPSE R31,R12 ; compare to lsb of ext. address 496/ 12E : CF52 RJMP RESET2 ; no match at all, discard packet 497/ 12F : 6410 SBR R17,(1 << PRIADD) ; set primary match flag 498/ 130 : E0FC LDI R31,CV019 ; point to consist address 499/ 131 : D0A6 RCALL READ ; get value in R31 500/ 132 : 77FF ANDI R31,0x7F ; ignore bit 7 of consist address 501/ 133 : F409 BRNE COMMND ; jump if consist active 502/ 134 : 6810 SBR R17,(1 << CONADD) ; copy prim. to cons. match 503/ 135 : 504/ 135 : ; Command processing 505/ 135 : 31E0 COMMND: CPI R30,BUFEND ; if there is no command 506/ 136 : F008 BRLO COMMN1 ; left, then wait 507/ 137 : CF4A LOOPX: RJMP LOOP ; for next packet 508/ 138 : 27FF COMMN1: CLR R31 ; clear Z high byte for comp. 509/ 139 : 80B0 LD R11,Z ; get command byte 510/ 13A : 95E3 INC R30 ; byte consumed now 511/ 13B : FCB7 SBRC R11,7 ; 512/ 13C : C041 RJMP GRP4_7 ; handle groups 4-7 513/ 13D : FCB6 SBRC R11,6 514/ 13E : C01E RJMP GRP2_3 ; handle groups 2-3 515/ 13F : FCB5 SBRC R11,5 516/ 140 : C012 RJMP GRP1_1 ; handle group 1 517/ 141 : 518/ 141 : FCB4 GRP0_0: SBRC R11,4 519/ 142 : C003 RJMP CONCTR ; it's a consist control 520/ 143 : FD16 DECCTR: SBRC R17,PRIADD ; decoder control, if prim. addr. 521/ 144 : C0A5 RJMP ACKNOW ; match, then do acknowledge only 522/ 145 : CFEF RJMP COMMND ; else ignore command 523/ 146 : 524/ 146 : D08D CONCTR: RCALL GET2ND ; get next byte 525/ 147 : FF16 SBRS R17,PRIADD ; if primary address didn't 526/ 148 : CFEC RJMP COMMND ; match, then ignore command 527/ 149 : 0CCC LSL R12 ; msb of byte 2 into carry 528/ 14A : F350 BRCS COMMND ; error if msb of byte 2 set 529/ 14B : 94B6 LSR R11 ; direction bit into carry 530/ 14C : 94C6 LSR R12 ; add direction bit to address 531/ 14D : E0F9 LDI R31,(0x12 >> 1) ; check for correct 532/ 14E : 16BF CP R11,R31 ; first byte, if there is no 533/ 14F : F729 BRNE COMMND ; match, ignore command 534/ 150 : BACD OUT EEDR,R12 ; set up data for EEPROM 535/ 151 : E0FC LDI R31,CV019 ; set up address for EEPROM 536/ 152 : C08A RJMP WRITE 537/ 153 : 538/ 153 : D080 GRP1_1: RCALL GET2ND ; get next byte 539/ 154 : FF17 SBRS R17,CONADD ; if consist address didn't 540/ 155 : CFDF RJMP COMMND ; match, then ignore command 541/ 156 : E3FF LDI R31,0x3F ; check for correct 542/ 157 : 16BF CP R11,R31 ; first byte, if there is no 543/ 158 : F6E1 BRNE COMMND ; match, ignore command 544/ 159 : 2CBC MOV R11,R12 ; desired speed to R11 545/ 15A : 2D2B MOV R18,R11 ; save command for later 546/ 15B : 772F ANDI R18,0x7F ; discard direction bit 547/ 15C : C012 RJMP NSPEED 548/ 15D : 549/ 15D : FF17 GRP2_3: SBRS R17,CONADD ; if consist address didn't 550/ 15E : CFD6 RJMP COMMND ; match, then ignore command 551/ 15F : FB11 BST R17,CFGFLL ; if bit cleared, then 552/ 160 : F01E BRTS GRP2_X ; bit 4 of command byte AS V1.42 Beta [Bld 20] - source file dcc_lok.asm - page 7 - 4/23/2002 0:20:28 553/ 161 : D027 RCALL UPD_FL ; sets/clears FL 554/ 162 : 94E8 CLT ; clear T bit and insert 555/ 163 : F8B4 BLD R11,4 ; into FL bit in command 556/ 164 : 2D2B GRP2_X: MOV R18,R11 ; save command for later 557/ 165 : 702F ANDI R18,0x0F ; leave lower nibble only 558/ 166 : 559/ 166 : 2FF2 MOV R31,R18 ; copy lower nibble 560/ 167 : 0FFF LSL R31 ; create space for bit 4 561/ 168 : FAB4 BST R11,4 ; extract bit 4 562/ 169 : F9F0 BLD R31,0 ; insert bit at position 0 563/ 16A : 5EF4 SUBI R31,4-CV067 ; pointer into speed table 564/ 16B : D06C RCALL READ ; get table value 565/ 16C : FAB5 BST R11,5 ; extract direction bit 566/ 16D : F9F7 BLD R31,7 ; insert direction bit 567/ 16E : 2EBF MOV R11,R31 ; move final speed 568/ 16F : E0FC NSPEED: LDI R31,CV019 ; point to CV019 569/ 170 : D067 RCALL READ ; get CV019 value 570/ 171 : 78F0 ANDI R31,0x80 ; retain direction reversal 571/ 172 : FD16 SBRC R17,PRIADD ; if primary address matches 572/ 173 : 27FF CLR R31 ; ignore consist dir. reversal 573/ 174 : 26BF EOR R11,R31 ; final direction reversal 574/ 175 : 2FF2 MOV R31,R18 ; copy saved command 575/ 176 : 2D2B MOV R18,R11 ; update desired speed 576/ 177 : 30F2 CPI R31,2 ; check for (emergency) stop 577/ 178 : F478 BRSH COMMNX ; if not, then continue 578/ 179 : 7820 CBR R18,0x7F ; set desired speed to 0 579/ 17A : 23FF TST R31 ; check for emergency stop 580/ 17B : F061 BREQ COMMNX ; normal stop, then continue 581/ 17C : 7830 CBR R19,0x7F ; set current speed to 0 582/ 17D : CFB7 RJMP COMMND 583/ 17E : 584/ 17E : FCB6 GRP4_7: SBRC R11,6 585/ 17F : C025 RJMP GRP6_7 ; handle groups 6-7 586/ 180 : FCB5 SBRC R11,5 587/ 181 : C011 RJMP GRP5_5 ; handle group 5 588/ 182 : FB11 GRP4_4: BST R17,CFGFLL ; if bit cleared, then FL 589/ 183 : F40E BRTC GRP4_F ; controlled by groups 2,3 590/ 184 : D004 RCALL UPD_FL 591/ 185 : D014 GRP4_F: RCALL SUB_FX ; find bits to be changed 592/ 186 : 70FF ANDI R31,0x0F ; mask for bits to be affected 593/ 187 : 274F EOR R20,R31 ; yields new port bits 594/ 188 : CFAC COMMNX: RJMP COMMND ; that's all 595/ 189 : 596/ 189 : E0FF UPD_FL: LDI R31,CV022 ; point to CV022 597/ 18A : D04D RCALL READ ; get CV022 value 598/ 18B : FD16 SBRC R17,PRIADD ; if prim. matches, FL forw./revr. 599/ 18C : 60F3 SBR R31,(1 << STFLFO)|(1 <