Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

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