Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6400 punk_joker 1
;throttle_backemf.asm
2
 
3
.NOLIST
4
;  ***************************************************************************************
5
;  * PWM MODEL RAILROAD THROTTLE                                                          *
6
;  *                                                                                      *
7
;  * WRITTEN BY:  PHILIP DEVRIES                                                          *
8
;  *                                                                                      *
9
;  *  Copyright (C) 2003 Philip DeVries                                                   *
10
;  *                                                                                      *
11
;  *  This program is free software; you can redistribute it and/or modify                *
12
;  *  it under the terms of the GNU General Public License as published by                *
13
;  *  the Free Software Foundation; either version 2 of the License, or                   *
14
;  *  (at your option) any later version.                                                 *
15
;  *                                                                                      *
16
;  *  This program is distributed in the hope that it will be useful,                     *
17
;  *  but WITHOUT ANY WARRANTY; without even the implied warranty of                      *
18
;  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                       *
19
;  *  GNU General Public License for more details.                                        *
20
;  *                                                                                      *
21
;  *  You should have received a copy of the GNU General Public License                   *
22
;  *  along with this program; if not, write to the Free Software                         *
23
;  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA           *
24
;  *                                                                                      *
25
;  ***************************************************************************************
26
.LIST
27
 
28
.ifdef BACKEMF_ENABLED
29
;********************************************************************************
30
;* BACKEMF_ADJUST                                                                *
31
;* Top level routine                                                             *
32
;*                                                                               *
33
;* The throttle_set is compared against the back emf generated by the motor      *
34
;* and adjusted to reduce the error                                              *
35
;*                                                                               *
36
;* Inputs:     throttle_set         Target speed                                 *
37
;* Returns:    throttle_set         Adjusted target speed                        *
38
;* Changed:    error_hi             Adjusted throttle, upper 8 bits (local)      *
39
;*             error_lo             Adjusted throttle, lower 8 bits (local)      *
40
;*             error_hi_prev        Previous throttle, for filter (global)       *
41
;*             error_lo_prev        Previous throttle, for filter (global)       *
42
;*             emf_hi               Measured emf, upper 8 bits (local)           *
43
;*             emf_lo               Measured emf, lower 8 bits (local)           *
44
;*             B_Temp,B_Temp1                                                    *
45
;* Calls:      ADC_SETUP_EMF                                                     *
46
;*             div16u                                                            *
47
;*             DIVIDE_16_SIMPLE                                                  *
48
;* Goto:       none                                                              *
49
;********************************************************************************
50
 
51
   HILOCAL1    error_lo             ; assign local variables
52
   HILOCAL2    error_hi
53
 
54
   ;*****************************************************************
55
   ;*Convert throttle setting into 2 byte 2's compl.                 *
56
   ;*                                                                *
57
   ;* This is a 7 bit number plus 1 more bits after the radix        *
58
   ;* It is in (error_hi) -radix- (error_lo)                         *
59
   ;*****************************************************************
60
   mov   error_hi,throttle_set         ; Put throttle into 16 bit form
61
   clr   error_lo
62
 
63
   lsr   error_hi                      ; Convert to 2's compliment
64
   ror   error_lo
65
 
66
   ;********************************************************************************
67
   ;* READ_BACKEMF                                                                  *
68
   ;* Returns a 2 byte 2's compliment measurement of the motor backemf.             *
69
   ;*                                                                               *
70
   ;* 1. Add together 8 samples of the (8 bit) pwm value in the two byte            *
71
   ;*    emf_hi--emf_lo register.                                                   *
72
   ;* 2. Multiply by 16.                                                            *
73
   ;* 3. Result:  Minimum value = 0x000 (decimal 0)                                 *
74
   ;*             Maximum value = 0x7F8 (decimal 2040)                              *
75
   ;*                                                                               *
76
   ;* Time required:                                                                *
77
   ;* 1. 1st Sample:             125uS                                              *
78
   ;* 2. next 7 Samples:         455uS                                              *
79
   ;* 3. balance of Subroutine:  10's of uS                                         *
80
   ;*    TOTAL                   580uS min                                          *
81
   ;*                                                                               *
82
   ;* Each cycle of the 25kHz PWM takes 40uS, therefore, this routine takes         *
83
   ;* at least 14.5 cycles of the 25kHz pwm.                                        *
84
   ;*                                                                               *
85
   ;* Inputs:  None                                                                 *
86
   ;* Returns: emf_hi--emf_lo:      2 Byte 2's compl (but always positive)          *
87
   ;*                               measure of motor backemf.                       *
88
   ;* Changed: B_Temp,B_Temp1                                                       *
89
   ;* Calls:   ADC_SETUP_EMF                                                        *
90
   ;********************************************************************************
91
LOWLOCAL1   emf_hi                     ; Names of local registers
92
LOWLOCAL2   emf_lo
93
 
94
;READ_BACKEMF:
95
   rcall ADC_SETUP_EMF                 ; Setup ADC to measure back_emf.
96
   clr   emf_lo                        ; Clear the value of emf.
97
   clr   emf_hi
98
 
99
   ldi   B_Temp,8                      ; Add 8 samples
100
WAIT_FOR_EMF_MEASURE:                  ; Wait for a measurement of the EMF
101
   sbis  ADCSR,ADIF
102
   rjmp  WAIT_FOR_EMF_MEASURE
103
 
104
   in    B_Temp1,ADCH                  ; Read the measurement
105
 
106
   sbi   ADCSR,4                       ; Clear the interrupt
107
 
108
   add   emf_lo,B_Temp1                ; Add to low byte (no carry)
109
 
110
   clr   B_Temp1
111
   adc   emf_hi,B_Temp1                ; Add carry to high byte.
112
 
113
   dec   B_Temp
114
   brne  WAIT_FOR_EMF_MEASURE          ; Measure for complete set
115
                                       ; Sum of 8 samples.
116
 
117
   ldi   B_Temp,4                      ; Convert 11 bit number into a 15 bit
118
COMPUTE_EMF_AVERAGE:                   ; number (only 11 significant figures
119
   lsl   emf_lo                        ; though)
120
   rol   emf_hi
121
   dec   B_Temp
122
   brne  COMPUTE_EMF_AVERAGE
123
 
124
   ;*****************************************************************
125
   ;* Compute the error.  That is, throttle = throttle - emf         *
126
   ;*                                                                *
127
   ;* The result is a two byte number (signed two's compl) in        *
128
   ;* error_hi -radix- error_lo                                *
129
   ;*****************************************************************
130
   sub   error_lo,emf_lo               ; subtract low bytes (after radix)
131
   sbc   error_hi,emf_hi               ; subtract high bytes (before radix)
132
 
133
.ifdef   BACKEMF_SCALE_ENABLED
134
   ;*****************************************************************
135
   ;* Error multiplier (complex)                                     *
136
   ;*                                                                *
137
   ;* Error gain is equal to:                                        *
138
   ;*                                                                *
139
   ;* Error                       err_scale    err_mult              *
140
   ;* ------------------------ * 2          * 2                      *
141
   ;*  err_scale                                                     *
142
   ;* 2         + throttle_set                                       *
143
   ;*                                                                *
144
   ;* The maximum gain when throttle_set = 0 is 2^err_mult           *
145
   ;* is cut in half when throttle_set = 2^err_scale                 *
146
   ;*                                                                *
147
   ;* Result is signed two's compliment in                           *
148
   ;* error_hi--error_lo -radix-                                     *
149
   ;*****************************************************************
150
   cbr   Flags_1,F_negative_err        ; Assume error is positive
151
 
152
   sbrs  error_hi,7                    ; Test algebraic sign
153
   rjmp  POSITIVE_ERR
154
 
155
   sbr   Flags_1,F_negative_err        ; If error is negative, set flag.
156
   com   error_lo                      ; Convert to positive
157
   com   error_hi
158
   subi  error_lo,0xFF
159
   sbci  error_hi,0xFF
160
 
161
POSITIVE_ERR:
162
 
163
   B_TEMPLOCAL    _bemf_lo_byte
164
   B_TEMPLOCAL1   _bemf_hi_byte
165
 
166
   mov   _bemf_lo_byte,throttle_set    ; Divisor = throttle_set+2^err_scale
167
   clr   _bemf_hi_byte
168
   ldi   B_Temp2,EXP2(err_scale)
169
   add   _bemf_lo_byte,B_Temp2
170
   adc   _bemf_hi_byte,_bemf_hi_byte
171
 
172
;  mov   dd16uL,error_lo               ; Dividend = error (same register)
173
;  mov   dd16uH,error_hi
174
 
175
   rcall div16u                        ; Divide error by (throttle+offset)
176
                                       ; (almost 4 pwm cycles)
177
                                       ; adds 3 to Cycle_count
178
 
179
;  mov   error_lo,dres16uL             ; Same register
180
;  mov   error_hi,dres16uH
181
 
182
   sbrs  Flags_1,BF_negative_err       ; Check sign flag
183
   rjmp  POSITIVE_ERR_1
184
 
185
   com   error_lo                      ; Convert back to negative
186
   com   error_hi                      ; if necessary
187
   subi  error_lo,0xFF
188
   sbci  error_hi,0xFF
189
 
190
POSITIVE_ERR_1:                        ; Scale for maximum
191
   ldi   _bemf_lo_byte, 7 - error_mult - err_scale
192
   rcall DIVIDE_16_SIMPLE
193
 
194
.else    ;case BACKEMF_SCALE_ENABLED is NOT enabled
195
   ;*****************************************************************
196
   ;* Error multiplier (simple)                                      *
197
   ;*                                                                *
198
   ;* The error multiplier setting (error_mult) can range            *
199
   ;* from -8 to +7, and the actual error multiplier is              *
200
   ;* 2^(error_mult), which therefore ranges from 1/256 to 128.      *
201
   ;*                                                                *
202
   ;* Step 1.  Multiply by 2^8.                                      *
203
   ;*          Equivalent to moving the radix point to after         *
204
   ;*          error_lo.  THIS STEP REQUIRES NO CODE                 *
205
   ;*                                                                *
206
   ;* Step 2.  Divide by 2^(error_mult - 8)                          *
207
   ;*                                                                *
208
   ;* Result is signed two's compliment in                           *
209
   ;* error_hi--error_lo -radix-                                     *
210
   ;*****************************************************************
211
 
212
   ldi   _bemf_lo_byte, 7 - error_mult
213
   rcall DIVIDE_16_SIMPLE
214
 
215
.endif   ;BACKEMF_SCALE_ENABLED
216
 
217
 
218
COMPUTE_NEW_PWM:
219
   ;*****************************************************************
220
   ;* Add in the original throttle                                   *
221
   ;*****************************************************************
222
   add   error_lo,throttle_set
223
   clr   B_Temp
224
   adc   error_hi,B_Temp
225
 
226
   ;*****************************************************************
227
   ;* Clamp to between 0 and +255                                    *
228
   ;*****************************************************************
229
   brmi  SET_ZERO_PWM                  ; If result is NEGATIVE, set to zero.
230
 
231
   cpi   error_hi,0x00                 ; If hi byte is zero, result is ok.
232
   breq  LOWPASS
233
   ldi   error_lo,0xFF                 ; otherwise, clamp
234
   rjmp  LOWPASS
235
 
236
SET_ZERO_PWM:
237
   clr   error_lo
238
 
239
LOWPASS:
240
 
241
.ifdef   LOWPASS_ENABLED
242
   ;*****************************************************************
243
   ;* A transversal low pass filter                                  *
244
   ;* Lowpass on the emf-adjusted pwm                                *
245
   ;*                                                                *
246
   ;* gain input "emf_lowpass_gain", range = 0 to 8                  *
247
   ;*                                                                *
248
   ;* The actual filter time constant "tau" is equal to              *
249
   ;* tau = 2^emf_lowpass_gain * sample_interval                     *
250
   ;*                                                                *
251
   ;* The sample interval is nominally 10mS, so the time             *
252
   ;* constant values are:                                           *
253
   ;* 0    1    2    3    4     5     6     7     8                  *
254
   ;* 10mS,20mS,40mS,80mS,160mS,320mS,640mS,1.28S,2.56S              *
255
   ;*                                                                *
256
   ;* The current sample is added to an attenuated sum of previous   *
257
   ;* samples as follows:                                            *
258
   ;*                                                                *
259
   ;* Adjusted Value = 1/(2^gain) x                                  *
260
   ;*                   (  1x sample number (i)                      *
261
   ;*                   +  gain x sample number (i-1)                *
262
   ;*                   +  gain^2 x sample number (i-2)              *
263
   ;*                   +  gain^3 x sample number (i-3)              *
264
   ;*                   + ....                                       *
265
   ;*                   )                                            *
266
   ;* Where:                                                         *
267
   ;* Gain values: gain =  (2^emf_lowpass_gain -  1) / 2^n           *
268
   ;*                      0,1/2,3/4,7/8,15/16 ... 255/256           *
269
   ;*                                                                *
270
   ;* Algorithm:                                                     *
271
   ;*                                                                *
272
   ;*    -Input (current sample) in error_lo (error_hi=0)            *
273
   ;*       0x00FF max                                               *
274
   ;*                                                                *
275
   ;*    -Input (scaled sum of previous samples) in                  *
276
   ;*       error_hi_prev--error_lo_prev.                            *
277
   ;*       0x00FF * (2^emf_lowpass_gain - 1 ) max                   *
278
   ;*                                                                *
279
   ;* 1. The error_hi_prev--error_lo_prev is added to                *
280
   ;*    error_hi--error_lo                                          *
281
   ;*       0x00FF * (2^emf_lowpass_gain) max                        *
282
   ;*                                                                *
283
   ;* 2. This value is also stored in                                *
284
   ;*    error_hi_prev--error_lo_prev                                *
285
   ;*                                                                *
286
   ;* 3. The value (error_hi--error_lo) is divided by                *
287
   ;*    2^emf_lowpass_gain (resulting in lowpass value,             *
288
   ;*    max 0x00FF)                                                 *
289
   ;*                                                                *
290
   ;* 4. The value (error_hi--error_lo) is subtracted from           *
291
   ;*    error_hi_prev--error_lo_prev.  This is the new              *
292
   ;*    stored value.                                               *
293
   ;*****************************************************************
294
   clr   error_hi
295
 
296
   ;****
297
   ;* 1. Add in cumulative previous error
298
   ;****
299
   add   error_lo,error_lo_prev        ; Add in scaled previous samples
300
   adc   error_hi,error_hi_prev        ;
301
 
302
   ;****
303
   ;* 2. Store
304
   ;****
305
   mov   error_lo_prev,error_lo        ; Store new value
306
   mov   error_hi_prev,error_hi        ; Store new value
307
 
308
   ;****
309
   ;* 3. Divide new value
310
   ;****
311
   ldi   _bemf_lo_byte,emf_lowpass_gain
312
   rcall DIVIDE_16_SIMPLE
313
 
314
   ;****
315
   ;* 4. New value in error_prev
316
   ;****
317
ADJUST_STORED:
318
   sub   error_lo_prev,error_lo
319
   sbc   error_hi_prev,error_hi
320
 
321
.endif ;LOWPASS_FILTER
322
 
323
   mov   throttle_set,error_lo
324
   subi  Cycle_count,256-15            ; Normal arrival here occurs after 3.5 + 14.5 +
325
                                       ; pwm cycles.  Add 15 counts here, also 3 added in
326
                                       ; div16u
327
 
328
.endif BACKEMF_ENABLED