1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916
|
; ***************************************************************************************
; * PWM MODEL RAILROAD THROTTLE *
; * *
; * "throttle.asm" *
; * *
; * WRITTEN BY: PHILIP DEVRIES *
; * *
; * Copyright (C) 2003 Philip DeVries *
; * *
; * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
; * *
; ***************************************************************************************
; ***************************************************************************************
; * Fixed Version for avra >= 1.2.2 because .DSEG cannot be used, if device has no SRAM *
; * B.Arenfeld, 10.05.2007 *
; ***************************************************************************************
; ***************************************************************************************
; *For Attiny 15 *
; * *
; *For compilation with: Avra 0.70 or later *
; * *
; * Atmel avrasm32.exe will not work becaue of the *
; * use of preprocessor directives #ifdef, #ifndef *
; * , and #endif, which Atmel doesn't support! *
; * *
; *Compiling requires the following files: *
; * "tn15def.inc" Labels and identifiers for tiny15 *
; * "throttle_dev_set.inc" Tiny 15 device settings *
; * "throttle_op_set.inc" Operation settings (THIS IS THE ONE TO EDIT THE *
; * COMPLIE-TIME OPTIONS ON THE WAY THE THROTTLE *
; * PERFORMS *
; * *
; *Depending on the compile time options, the following files are also required: *
; * "throttle_divide.asm" Two division routines. (one from atmel) *
; * "throttle_set_lowpass.asm" Lowpass filter on throttle handle *
; * "throttle_momentum.asm" Compute speed according to momentum *
; * "throttle_momentum_lowpass.asm" Lowpass filter on momentum handle *
; * "throttle_backemf.asm" Adjust pwm based on motor speed *
; * "throttle_pulse.asm" Provide pulse assist at low motor speeds *
; * "throttle_multiply.asm" atmel multiplication routine *
; * *
; *Subroutine Categories and Stack *
; * *
; * The Tiny 15 has a three level stack which handles return addresses for *
; * subroutine calls and for interrupt service routines. The categories below *
; * ensure that the stack does not overflow. The four (4) categories are: *
; * *
; * -- Top Level Routines: These routines are never called, and never *
; * return ("ret") and so the stack is, "empty" *
; * These routines may call any subroutine. *
; * Register Variables: Temp, Temp1, ... *
; * *
; * -- First Level Subroutines: Stack has 1 entry. These routines may call *
; * Second Level Subroutines only. *
; * Register Variables: A_Temp, A_Temp1, ... *
; * *
; * -- Second Level Subroutines: Stack has 2 entries. These routines may NOT *
; * call any subroutines. *
; * Register Variables: B_Temp, B_Temp1, ... *
; * *
; * -- Interrupt Service These occur assynchronously, and therefor may *
; * occur during Second Level Subroutines. If so, *
; * the stack has 3 entries and IS FULL. These routines *
; * may NOT call any subroutines. *
; * Register Variables: I_Temp, I_Temp1, ... *
; * *
; * Register variables are reserved for each level of routine. Each level may freely *
; * use the register variables for it's own level. Some sharing of variables may *
; * occur subject to these guidelines: *
; * -- No category execpt Interrupt Service may use Interrupt Service variables. This *
; * is because ISRs occur asynchronously. *
; * -- A category may NOT use variables reserved for higher level categories. *
; * -- A category may use lower level routine variables as long as their use does not *
; * span any subroutine calls. *
; * *
; *Other settings *
; * There is no way to put these settings into this file, but these must also be *
; * done: *
; * *
; * BODLEVEL: 0 4.0V *
; * BOODEN: 0 ENABLED (brown out detection) *
; * SPIEN: 0 ENABLED (in circuit programming) *
; * RSTDISBL 0 DISABLED (reset on PB5) *
; * CKSEL 11 (very quickly rising power) *
; * LB1 1 (LB1 & LB2: No lock) *
; * LB2 1 *
; * *
; * Calibration byte into flash byte address as specified in *
; * osccal_location. *
; * *
; * Notes regarding these settings: *
; * --Brown out detection. The datasheet warns against using the EEPROM without *
; * brownout detection because of the possibility of errant execution at very low *
; * voltage levels. *
; * *
; **************************************************************************************
;*****************************************************************************************
;*****************************************************************************************
;* Included files *
;*****************************************************************************************
;*****************************************************************************************
.INCLUDE "tn15def.inc" ; Labels and identifiers for tiny15
.INCLUDE "throttle_op_set.inc" ; Operation settings
.INCLUDE "throttle_dev_set.inc" ; Tiny 15 device settings
;*****************************************************************************************
;*****************************************************************************************
;* DATA TABLE *
;*****************************************************************************************
;*****************************************************************************************
;.CSEG
;.ORG 0x01E0 ; Program .ORG 0x01E0 actually means byte
; location 0x03C0.
;*****************************************************************************************
;*****************************************************************************************
;* Data: reserved for OSCCAL byte *
;*****************************************************************************************
;*****************************************************************************************
; Fix : The Tiny15 has NO SRAM. Use of .DSEG is invalid !
;.DSEG
;
;.SET osccal_location = 0x3FF ;Place in the last byte of program memory.
; ;High byte of program memory 1FF
;
;.ORG osccal_location ;reserve this byte for oscillator
;.BYTE 1 ;calibration value
; Fixed Version for avra >= 1.2.2
.CSEG
.EQU osccal_location = 0x3FF ; The last flash byte is used for the calibration
; value and is replaced by the programmer
; Now reserve the last word in flash memory. If you are sure, that the program doesn't use
; the last flash word, you can disable the following lines. If not, it's better to enable
; them to check for overlapping code segments.
.ORG 0x01FF ; Last word in flash memory
.DB 0xff,0xff ; Fill with dummy values. Only last byte is used
; but flash is organized in words.
; 0xff is the value of unprogrammed flash
;*****************************************************************************************
;*****************************************************************************************
;* Reset and Interrupt Vectors *
;*****************************************************************************************
;*****************************************************************************************
.CSEG
.ORG 0x000
rjmp ST_RESET
.ifdef OVERLOAD_ENABLED
rjmp ST_PWM_LEVEL_OFF ; INT0 interrupt handler
.else
reti ; Not used.
.endif ;OVERLOAD_ENABLED
reti ; Not used. rjmp PIN_CHANGE
reti ; Not used. rjmp TIM1_CMP
reti ; Not used. rjmp TIM1_OVF
reti ; Not used. rjmp TIM0_OVF
reti ; Not used. rjmp EE_RDY
reti ; Not used. rjmp ANA_COMP
reti ; Not used. rjmp ADC
;*****************************************************************************************
;*****************************************************************************************
;* Top level routines. The basic program is a state machine, with states all being *
;* top level routines. These routines are never used as subroutines *
;* and therefore can call any subroutine. *
;*****************************************************************************************
;*****************************************************************************************
;********************************************************************************
;* ST_RESET *
;* This is power on reset. The reset vector points here. *
;* *
;* Inputs: none *
;* Returns: none *
;* Changed: B_Temp *
;* Calls: *
;* Goto: ST_MOTOR_OFF *
;********************************************************************************
ST_RESET:
cli ; Disable interrupts
ldi B_Temp,(dir_out_port_bit | pwm_port_bit | dir_in_port_bit | momentum_port_bit)
out DDRB,B_Temp ; Assign output port directions.
; Inclusion in the above list makes the
; port an output port
ldi B_Temp,0x00 ; A "1" makes output logic level high
out PORTB,B_Temp ; A "1" assigns pullups on inputs
; Therefore all outputs are at logic low, and
; all inputs do not have a pullup assigned
ldi B_Temp,acsr_val ; Disable comparator and interrupt
out ACSR,B_Temp ; Using port for PWM
; (comparator defaults to powered up)
ldi B_Temp,0b01000010 ; Disable pullups.
out MCUCR,B_Temp ; Set sleep mode (moot)
; INT0 interrupt on falling edge
ldi ZL,low(osccal_location) ; r30
ldi ZH,high(osccal_location) ; r31
lpm
out OSCCAL,Implicit ; Place calibration byte
ldi B_Temp,0b00001010 ; Enable watchdog
out WDTCR,B_Temp ; timout 64mS (nom)
ldi B_Temp1,pwm_period ; Set pwm oscillator period
out OCR1B,B_Temp1
ldi B_Temp1,tccr1_enable_t1 ; Turn on the PWM oscillator
out TCCR1,B_Temp1
ldi Flags_1,(0b00000000 | F_stop) ; Set emergency stop flag so that
; throttle doesn't start on powerup
.ifdef TRADITIONAL_ENABLED
.ifdef MOMENTUM_LOWPASS_ENABLED
clr momentum_lo_prev ; MOMENTUM LOWPASS
clr momentum_hi_prev ; Clear the history
.endif ;MOMENTUM_LOWPASS_ENABLED
.endif ;TRADITIONAL_ENABLED
; rjmp ST_EMERGENCY_STOP ; ***EXIT STATE***
;********************************************************************************
;* ST_EMERGENCY_STOP *
;* *
;* Reset to "off" state. *
;* Clear global variables associated with momentum and lowpass filters. *
;* *
;* Inputs: none *
;* Returns: none *
;* Changed: Global variables cleared *
;* Calls: None *
;* Goto: ST_PWM_LEVEL_OFF If throttle is zero *
;********************************************************************************
ST_EMERGENCY_STOP:
.ifdef BACKEMF_ENABLED
.ifdef LOWPASS_ENABLED ; BACKEMF LOWPASS
clr error_hi_prev ; Clear the history
clr error_lo_prev
.endif ;LOWPASS_ENABLED
.endif ;BACKEMF_ENABLED
.ifdef MOMENTUM_ENABLED ; MOMENTUM
clr speed_lo_prev ; Clear the history
clr speed_hi_prev
.endif ;MOMENTUM_ENABLED
.ifdef TRADITIONAL_ENABLED
.ifdef WALKAROUND_ENABLED
clr throttle_hold ; Clear the history
.endif ;WALKAROUND_ENABLED
.ifdef THROTTLE_LOWPASS_ENABLED
clr throttle_lo_prev ; THROTTLE LOWPASS
clr throttle_hi_prev ; Clear the history
.endif ;THROTTLE_LOWPASS_ENABLED
.endif ;TRADITIONAL_ENABLED
; rjmp ST_PWM_LEVEL_OFF ; ***EXIT STATE***
;********************************************************************************
;* ST_PWM_LEVEL_OFF *
;* ST_MEASUREMENT_SETTLE *
;* 1. If entered at ST_PWM_LEVEL_OFF turn pwm off *
;* 2. Set the ADC ports to input *
;* 3. Pause to let ADC inputs (including back-emf) settle. *
;* 4. Read the throttle controller. *
;* 5. Set LED ports and overload ports (also ADC inputs) to output *
;* 6. If throttle_set is not zero, or if motor is still running by momentum *
;* continue running motor (jump to ST_SET_NEW_PWM) *
;* 7. If throttle set is zero and motor is not running, then set the direction *
;* relay and test backemf input to determine backemf mode. *
;* 8. Turn of motor (jump to ST_PWM_LEVEL_OFF) *
;* *
;* Inputs: none *
;* Returns: none *
;* Changed: B_Temp, B_Temp1 *
;* Calls: READ_THROTTLE *
;* Goto: ST_PWM_LEVEL_OFF If throttle is zero *
;* ST_SET_NEW_PWM After delay *
;********************************************************************************
ST_PWM_LEVEL_OFF:
clr B_Temp ; Set PWM duty = 0.
rcall SET_PWM_DUTY ; i.e. turn off the power
ST_MEASUREMENT_SETTLE:
;********************************************
;* Set all measurement ports for input and pause.
;* During the pause:
;* 1. inductive current in the locomotive falls to zero, and
;* the backemf voltage appears on the backemf port
;* 2. the momentum, direction, and throttle voltages stabilize
;********************************************
.ifdef TRADITIONAL_ENABLED
.ifdef LEDS_ENABLED
cbi DDRB,momentum_port ; Make input port (pullup must be disabled)
cbi DDRB,dir_in_port ; Make input port (pullup must be disabled)
.endif ;LEDS_ENABLED
.ifdef OVERLOAD_ENABLED
in B_Temp,GIMSK ; disable INT0 interrupt
andi B_Temp,0b10111111
out GIMSK,B_Temp
cbi DDRB,throttle_port ; Make input port (pullup must be disabled)
.endif ;OVERLOAD_ENABLED
.endif ;TRADITIONAL_ENABLED
sei ; Enable interrupts
wdr ; Reset watchdog timer
ldi B_Temp1,pwm_full_count ; Pause for inputs to settle
rcall COUNT_PWM_CYCLES
clr Cycle_count
;********************************************
;* Read the input ports and make some
;* mode decisions based on those inputs.
;********************************************
rcall READ_THROTTLE ; Find throttle handle position in throttle_set
.ifdef TRADITIONAL_ENABLED
.ifdef MOMENTUM_ENABLED
.ifdef MOMENTUM_LOWPASS_ENABLED
.include "throttle_momentum_lowpass.asm"
.endif;MOMENTUM_LOWPASS_ENABLED
.endif; MOMENTUM_ENABLED
.endif ;TRADITIONAL_ENABLED
.ifdef DIRECTION_ENABLED ; Check Stop, and Adjust Direction
CHECKING_STOP:
sbrs Flags_1,BF_stop ; Check stop flag is set
rjmp DONE_CHECKING_STOP
cpi throttle_set,0x00 ; If throttle handle is at zero
brne ST_EMERGENCY_STOP ; reset the emergency stop flag
cbr Flags_1,F_stop ; reset emergency stop flag.
rjmp ST_EMERGENCY_STOP ; ALWAYS STOP
DONE_CHECKING_STOP:
CHECKING_DIRECTION:
.ifdef MOMENTUM_ENABLED
mov B_Temp,speed_hi_prev ; Don't set direction unless the actual
cpi B_Temp,direction_threshold ; speed is less than direction_threshold
brsh DONE_CHECKING_DIRECTION
.else
cpi throttle_set,0x00 ; Don't set direction unless the throttle
brne DONE_CHECKING_DIRECTION ; handle is at zero
.endif ;MOMENTUM_ENABLED
sbic PORTB,dir_out_port ; Find port direction
rjmp PORT_REVERSE
;rjmp PORT_FORWARD
PORT_FORWARD:
sbrs Flags_1,BF_reverse ; If port says forward
rjmp DONE_CHECKING_DIRECTION
sbi PORTB,dir_out_port ; But flag says reverse, then reverse
rjmp ST_EMERGENCY_STOP
PORT_REVERSE:
sbrc Flags_1,BF_reverse ; If port says reverse
rjmp DONE_CHECKING_DIRECTION
cbi PORTB,dir_out_port ; But flag says foreward, then forward
rjmp ST_EMERGENCY_STOP
DONE_CHECKING_DIRECTION:
.endif ;DIRECTION_ENABLED
.ifdef TRADITIONAL_ENABLED
.ifdef THROTTLE_LOWPASS_ENABLED
.include "throttle_set_lowpass.asm"
.endif ;THROTTLE_LOWPASS_ENABLED
.endif ;TRADITIONAL_ENABLED
cpi throttle_set,0x00 ; Run the pwm unless the throttle
brne ST_SET_NEW_PWM ; is zero
.ifdef MOMENTUM_ENABLED
mov B_Temp,speed_hi_prev ; In momentum mode, run the pwm unless
cpi B_Temp,0x00 ; the actual throttle setting reaches zero
brne ST_SET_NEW_PWM
.endif ;MOMENTUM_ENABLED
;********************************************
;* Only arrive here if the throttle is set for 0 speed
;* and the locomotive is actually stopped (momentum)
;********************************************
.ifdef BACKEMF_ENABLED
;********************************************
;* The backemf measurement should be at or near zero,
;* since the locomotive is stopped. If it isn't,
;* do not use backemf speed control.
;********************************************
sbr Flags_1,F_use_backemf ; Default to use backemf
rcall ADC_SETUP_EMF ; 4 lines read the backemf
WAIT_FOR_VALID:
sbis ADCSR,ADIF
rjmp WAIT_FOR_VALID
in B_Temp,ADCH ; Read the measurement
cpi B_Temp,0x40 ; Test measurement
brlo END_CHECK_BACKEMF_MODE ; If small, use backemf adjustment.
cbr Flags_1,F_use_backemf ; Otherwise, don't use backemf
END_CHECK_BACKEMF_MODE:
.endif ;BACKEMF_ENABLED
.ifdef TRADITIONAL_ENABLED
.ifdef LOCO_LIGHT_ENABLED
ldi throttle_set,light_pwm
rjmp STABLE_PWM_SET
.else
rjmp ST_PWM_LEVEL_OFF
.endif ;LOCO_LIGHT_ON
.else
rjmp ST_PWM_LEVEL_OFF
.endif ;TRADITIONAL_ENABLED
;********************************************************************************
;* ST_SET_NEW_PWM *
;* Compute the pwm setting based upon momentum, backemf, and throttle setting *
;* Inputs: throttle_set *
;* Returns: none *
;* Changed: throttle_set, other variables in included files *
;* Calls: various in included files *
;* Goto: ST_PWM_LEVEL_ON *
;********************************************************************************
ST_SET_NEW_PWM:
.ifdef TRADITIONAL_ENABLED
.ifdef LEDS_ENABLED
cbi PORTB,dir_in_port ; logic low out (turn off LED)
sbi DDRB,dir_in_port ; Assign output to drive led (output is low)
cbi PORTB,momentum_port ; logic low out (turn off LED)
sbi DDRB,momentum_port ; Assign output to drive led (output is low)
.endif ;LEDS_ENABLED
.ifdef OVERLOAD_ENABLED
;********************************************
;* The thottle port is driven to logic high. If this port gets pulled
;* low (overload), this triggers the INT0 interrupt, which will shut off
;* the pwm.
;********************************************
sbi PORTB,throttle_port ; Logic hi out.
sbi DDRB,throttle_port ; Make output port.
.endif ;OVERLOAD_ENABLED
.endif ;TRADITIONAL_ENABLED
.ifdef MOMENTUM_ENABLED
.include "throttle_momentum.asm" ; momentum adjustment
.endif ;MOMENTUM_ENABLED
.ifdef TRADITIONAL_ENABLED
.ifdef WALKAROUND_ENABLED
mov throttle_hold,throttle_set
.endif ;WALKAROUND_ENABLED
.endif ;TRADITIONAL_ENABLED
.ifdef BACKEMF_ENABLED ;********************************************
; Adjust throttle_set according to
; measured backemf.
;********************************************
sbrs Flags_1,BF_use_backemf ; If the flag is set, use backemf
rjmp DONT_BACKEMF ; Otherwise, don't
.include "throttle_backemf.asm"
; If using backemf, don't use throttle_scale
rjmp ST_PWM_LEVEL_ON ; ***EXIT STATE***
DONT_BACKEMF:
.endif ;BACKEMF
;*****************************************************************
;* Scale the throttle_set between 0 and pwm_period *
;* multiply pwm_period and throttle_set and divide by 256 *
;* read answer from hi byte of return. *
;*****************************************************************
HILOCAL1 _main_scale_multiplicand
B_TEMPLOCAL _main_scale_multiplier
B_TEMPLOCAL1 _main_scale_result_hi
ldi _main_scale_multiplicand,pwm_period - pwm_min
mov _main_scale_multiplier,throttle_set
rcall mpy8u ; multiply
mov throttle_set,_main_scale_result_hi ; read result
; rjmp ST_PWM_LEVEL_ON ; ***EXIT STATE***
;********************************************************************************
;* ST_PWM_LEVEL_ON *
;* 1. Enable overload testing *
;* 2. Produce pulse if required *
;* 3. Run pwm at throttle_set *
;* 4. Wait for a while *
;* *
;* Inputs: throttle_set *
;* Returns: none *
;* Changed: B_Temp, B_Temp1, various *
;* Calls: SET_PWM_DUTY *
;* COUNT_PWM_CYCLES *
;* Goto: ST_PWM_LEVEL_OFF After PWM goes to off state *
;********************************************************************************
ST_PWM_LEVEL_ON:
.ifdef TRADITIONAL_ENABLED
.ifdef OVERLOAD_ENABLED
ldi B_Temp,0b01000000 ; clear INT0 interrupt
out GIFR,B_Temp
in B_Temp,GIMSK ; enable INT0 interrupt
ori B_Temp,0b01000000
out GIMSK,B_Temp
.endif ;OVERLOAD_ENABLED
.endif ;TRADITIONAL_ENABLED
cpi throttle_set,light_pwm ; never run pwm lower than light_pwm level
brsh DONE_CHECKING_MINIMUM
ldi throttle_set,light_pwm
rjmp STABLE_PWM_SET
DONE_CHECKING_MINIMUM:
.ifdef PULSE_ENABLED ; Produce pulses during output
.ifdef BACKEMF_ENABLED
sbrc Flags_1,BF_use_backemf ; If the flag is set to use backemf
rjmp STABLE_PWM_SET ; don't pulse
.endif ;BACKEMF_ENABLED
; Pass in: throttle_set
.include "throttle_pulse.asm"
.endif ;PULSE_ENABLED
STABLE_PWM_SET:
mov B_Temp,throttle_set ; Stabilize at throttle_set
rcall SET_PWM_DUTY
ldi B_Temp1,pwm_full_count-pwm_settle_count
rcall COUNT_PWM_CYCLES ; Wait for end of interval
.ifdef BACKEMF_ENABLED
sbrc Flags_1,BF_use_backemf ; If the flag is set to use backemf
rjmp ST_PWM_LEVEL_OFF ; ***EXIT STATE***
.endif ;BACKEMF_ENABLED
rjmp ST_MEASUREMENT_SETTLE ; ***EXIT STATE***
;*****************************************************************************************
;*****************************************************************************************
;* First Level Subroutines. *
;* These routines include the routines which are called by other code and also call *
;* Second Level Subroutines. *
;*****************************************************************************************
;*****************************************************************************************
;********************************************************************************
;* READ_THROTTLE *
;* First Level Subroutine *
;* *
;* Read the throttle controls, which are: *
;* Momentum level (analog): Returned in "momentum_set" *
;* Returns and 8 bit number, with '0' meaning minimum momentum. *
;* *
;* Direction, brake, and stop switch. *
;* Returns value in flags: F_brake, F_reverse, and F_stop *
;* *
;* Throttle setting (analog: Returned in "throttle_set" *
;* Returns an 8 bit number (0x00 to 0xFF; 0 to 255), *
;* where '0' means "motor off" and 0xFF (255) means full speed. *
;* *
;* If a speed table is implemented, it will be in this routine *
;* *
;* Just now, this value comes from the analog input and is converted by the *
;* ADC. The raw 8 bit number is returned. *
;* *
;* Inputs: None *
;* Returns: Momentum setting in "momentum_set" *
;* Switch positions in F_brake, F_reverse, and F_stop *
;* Throttle setting in "throttle_set" *
;* Changed: Cycle_count incremented by up to 5 *
;* Calls: ADC_SETUP_MOMENTUM *
;* ADC_SETUP_DIRECTION *
;* ADC_SETUP_THROTTLE *
;********************************************************************************
READ_THROTTLE:
.ifdef TRADITIONAL_ENABLED
.ifdef DIRECTION_ENABLED
;********************************************
;* Measure the direction, brake, and stop switches and
;* set the flags appropriately
;********************************************
rcall ADC_SETUP_DIRECTION ; Setup to read
WAIT_FOR_VALID_DIRECTION:
sbis ADCSR,ADIF ; Check for ADC completion
rjmp WAIT_FOR_VALID_DIRECTION
in B_Temp,ADCH ; Read value
.ifdef WALKAROUND_ENABLED
cpi B_Temp,0x90 ; Above this threshold
; deactivates handheld controller
; brsh HOLD_THROTTLE
brlo HOLD_THROTTLE_NOT
rjmp HOLD_THROTTLE
HOLD_THROTTLE_NOT:
.endif ;WALKAROUND_ENABLED
cpi B_Temp,0x1B ; Below this threshold (0.53V) sets 'stop' flag
brsh TEST_BRAKE_LEVEL ; Typical stop voltage is 0.30V
.ifdef SWITCH_LOWPASS_ENABLED
sbrs Flags_2,BF_stop_count ; If the stop count flag is not set, then
clr Flags_2 ; set the counter to zero
cbr Flags_2,F_stop_count ; clear the stop count flag
inc Flags_2 ; increment the counter
cpi Flags_2,stop_count_max ; compare the count to the maximum
sbr Flags_2,F_stop_count ; set the stop count flag
brlo END_READ_DIRECTION ; if the count is lower, don't change status flag
dec Flags_2,F_stop_count ; decrement stop count flag
.endif;SWITCH_LOWPASS_ENABLED
sbr Flags_1,F_stop
rjmp END_READ_DIRECTION
TEST_BRAKE_LEVEL:
cpi B_Temp,0x37 ; Below this threshold (1.07V) sets 'brake' flag
brsh TEST_REVERSE_LEVEL ; Typical brake voltage 0.87V
.ifdef SWITCH_LOWPASS_ENABLED
sbrs Flags_2,BF_brake_count ; If the brake count flag is not set, then
clr Flags_2 ; set the counter to zero
cbr Flags_2,F_brake_count ; clear the break count flag
inc Flags_2 ; increment the counter
cpi Flags_2,brake_count_max ; compare the count to the maximum
sbr Flags_2,F_brake_count ; set the break count flag
brlo END_READ_DIRECTION ; if the count is lower, don't change status flag
dec Flags_2,F_brake_count ; decrement break count flag
.endif;SWITCH_LOWPASS_ENABLED
sbr Flags_1,F_brake
rjmp END_READ_DIRECTION
TEST_REVERSE_LEVEL:
cpi B_Temp,0x53 ; Below this threshold (1.62V) sets 'reverse' flag
brsh TEST_FOREWARD_LEVEL ; Typical reverse level 1.40V
.ifdef SWITCH_LOWPASS_ENABLED
sbrs Flags_2,BF_reverse_count ; If the reverse count flag is not set, then
clr Flags_2 ; set the counter to zero
cbr Flags_2,F_reverse_count ; clear the reverse count flag
inc Flags_2 ; increment the counter
cpi Flags_2,reverse_count_max ; compare the count to the maximum
sbr Flags_2,F_reverse_count ; set the reverse count flag
brlo END_READ_DIRECTION ; if the count is lower, don't change status flag
dec Flags_2,F_reverse_count ; decrement reverse count flag
.endif;SWITCH_LOWPASS_ENABLED
cbr Flags_1,F_brake ; Clear brake flag
sbr Flags_1,F_reverse ; Set brake flag
rjmp END_READ_DIRECTION
TEST_FOREWARD_LEVEL: ; Typical "nothing" 1.95V
;no test required
.ifdef SWITCH_LOWPASS_ENABLED
sbrs Flags_2,BF_foreward_count ; If the foreward count flag is not set, then
clr Flags_2 ; set the counter to zero
cbr Flags_2,F_foreward_count ; clear the foreward count flag
inc Flags_2 ; increment the counter
cpi Flags_2,foreward_count_max ; compare the count to the maximum
sbr Flags_2,F_foreward_count ; set the foreward count flag
brlo END_READ_DIRECTION ; if the count is lower, don't change status flag
dec Flags_2,F_foreward_count ; decrement forward count flag
.endif;SWITCH_LOWPASS_ENABLED
cbr Flags_1,F_brake ; Clear brake flag
cbr Flags_1,F_reverse ; Clear reverse flag (i.e., foreward)
END_READ_DIRECTION:
.endif ;DIRECTION_ENABLED
.ifdef MOMENTUM_ENABLED
;********************************************
;* Measure and adjust the momentum input
;********************************************
rcall ADC_SETUP_MOMENTUM ; Setup to read
WAIT_FOR_VALID_MOMENTUM:
sbis ADCSR,ADIF ; Wait for ADC completion
rjmp WAIT_FOR_VALID_MOMENTUM
in momentum_set,ADCH ; Read value
.ifdef WALKAROUND_ENABLED
ldi B_Temp,0x90
cp momentum_set,B_Temp ; Above this threshold
; deactivates handheld controller
brsh HOLD_THROTTLE
.endif ;WALKAROUND_ENABLED
ldi B_Temp,0x40
sub momentum_set,B_Temp ; Subtract offset (1/4 of 0xFF)
brsh END_READ_MOMENTUM
sub momentum_set,momentum_set ; If smaller than offset, make zero
END_READ_MOMENTUM:
.endif ;MOMENTUM_ENABLED
;********************************************
;* Read the throttle level
;********************************************
rcall ADC_SETUP_THROTTLE
WAIT_FOR_VALID_THROTTLE:
sbis ADCSR,ADIF ; Check for ADC completion
rjmp WAIT_FOR_VALID_THROTTLE
in throttle_set,ADCH ; Read throttle value
subi throttle_set,0x08 ; Subtract offset (force zero)
brcc DONE_READ_THROTTLE ; If new throttle is negative,
clr throttle_set ; make throttle zero.
DONE_READ_THROTTLE:
subi Cycle_count,256-3 ; Normal arrival here occurs after 3 adc
ret ; conversions, which take 195uS, or 4.875
; pwm cycles
.ifdef WALKAROUND_ENABLED
HOLD_THROTTLE: ; Normal arrival here occurs after 1 adc
; conversion, which takes 65uS, or 1.625
; pwm cycles
cbr Flags_1,F_brake ; Clear brake flag
mov throttle_set,throttle_hold ; Use previous value.
.ifdef SWITCH_LOWPASS_ENABLED
clr Flags_2
.endif;SWITCH_LOWPASS_ENABLED
.ifdef MOMENTUM_ENABLED
ldi B_Temp,0x40
mov momentum_set,B_Temp ; 'long' momentum
.endif ;MOMENTUM_ENABLED
ret
.endif ;WALKAROUND_ENABLED
.else ;NOT TRADITIONAL_THROTTLE
sbr Flags_1,F_stop
ret
.endif ;TRADITIONAL_THROTTLE
;********************************************************************************
;* COUNT_PWM_CYCLES *
;* First evel Subroutine *
;* *
;* Increment Cycle_count timer each PWM cycle. *
;* Return when Cycle_count = B_Temp1 *
;* *
;* Inputs: B_Temp1 Exit when count reaches this number *
;* Returns: None *
;* Changed: B_Temp,Cycle_count *
;* Calls: None *
;********************************************************************************
COUNT_PWM_CYCLES:
in B_Temp,TIFR ; Wait for pwm timer to reset
sbrs B_Temp,OCF1A
rjmp COUNT_PWM_CYCLES
ldi B_Temp,0b01000000 ; reset interrupt flag
out TIFR,B_Temp
inc Cycle_count ; increment counter and repeat
cp Cycle_count,B_Temp1
brne COUNT_PWM_CYCLES
ret
;*****************************************************************************************
;*****************************************************************************************
;* Second Level Subroutines. *
;* These routines make no further subroutine calls. *
;*****************************************************************************************
;*****************************************************************************************
.include "throttle_divide.asm"
.include "throttle_multiply.asm"
;********************************************************************************
;* SET_PWM_DUTY *
;* Second Level Subroutine *
;* *
;* Inputs: B_Temp PWM on count *
;* Returns: None *
;* Changed: None *
;* Calls: Not allowed *
;********************************************************************************
SET_PWM_DUTY:
out OCR1A,B_Temp ; Set the PWM equal to the input B_Temp
ret
;********************************************************************************
;* ADC_SETUP_DIRECTION *
;* ADC_SETUP_MOMENTUM *
;* ADC_SETUP_THROTTLE *
;* ADC_SETUP_BACK_EMF *
;* Second Level Subroutine *
;* *
;* The ADC is switched off, and restarted on the selected port. *
;* *
;* Inputs: None *
;* Returns: None *
;* Changed: Various B_Temp variables *
;* Calls: Not allowed *
;********************************************************************************
.ifdef DIRECTION_ENABLED
ADC_SETUP_DIRECTION:
ldi B_Temp,admux_direction ; Setup MUX for direction/brake measurement
rjmp ADC_SETUP
.endif ;DIRECTION_ENABLED
.ifdef MOMENTUM_ENABLED
ADC_SETUP_MOMENTUM:
ldi B_Temp,admux_momentum ; Setup MUX for momentum set measurement
rjmp ADC_SETUP
.endif ;MOMENUTM_ENABLED
.ifdef BACKEMF_ENABLED
ADC_SETUP_EMF:
ldi B_Temp,admux_emf ; Setup MUX for back_emf measurement
rjmp ADC_SETUP
.endif ;BACKEMF_ENABLED
.ifdef TRADITIONAL_ENABLED
ADC_SETUP_THROTTLE:
ldi B_Temp,admux_throttle ; Setup MUX for analog measure
; rjmp ADC_SETUP ; of throttle.
.endif ;TRADITIONAL_ENABLED
ADC_SETUP:
ldi B_Temp1,adcsr_off ; Turn off the ADC
out ADCSR,B_Temp1 ;
out ADMUX,B_Temp ; Setup MUX as per entry point
ldi B_Temp,adcsr_enable ; enable ADC, disable interrupt, clear
out ADCSR,B_Temp ; interrupt flag, free-running.
ret
;*****************************************************************************************
;*****************************************************************************************
;* Interrupt Service routines. *
;* These routines can occur assynchronously. Therfore, they might occur during a second *
;* level routine. Therefore THEY MAY NOT CALL ANY SUBROUTINES. *
;*****************************************************************************************
;*****************************************************************************************
|