およそ20年前に、68HC05 の開発の練習に書いた車のブレイクライト・方向指示器コントローラです。
リビジョン | 4ab5c3b066d5a8b0c0f5be069e9225e4601e9435 (tree) |
---|---|
日時 | 2013-07-08 20:10:59 |
作者 | Joel Matthew Rees <reiisi@user...> |
コミッター | Joel Matthew Rees |
Second backup. Nothing stands out besides work on debouncing and decoding.
@@ -2,15 +2,20 @@ | ||
2 | 2 | HEADER 'Turn Signal Switch by Joel Matthew Rees' |
3 | 3 | |
4 | 4 | * Electronic Turn Signal and Emergency Flasher Switch/Timer |
5 | +* Version 1.00 | |
5 | 6 | * Implemented on the 68HC(7)05Kx |
6 | 7 | * Assembled and tested on the M68HC705KICS |
8 | +* | |
7 | 9 | * Copyright 1993 Joel Matthew Rees |
10 | +* | |
11 | +* Permission granted in advance for strictly non-profit | |
12 | +* educational use. All other rights retained by the author. | |
8 | 13 | |
9 | 14 | * Authored by Joel Matthew Rees, June to August 1993 |
10 | 15 | * of |
11 | 16 | * South Salt Lake City |
12 | 17 | * Utah |
13 | -* | |
18 | +* | |
14 | 19 | |
15 | 20 | |
16 | 21 |
@@ -35,7 +40,8 @@ | ||
35 | 40 | * switch back to mind. I thought ten bits of I/O, internal timers, |
36 | 41 | * and the STOP mode would be sufficient to replicate the logic of that |
37 | 42 | * switch assembly, adding directional turn signal return switches and |
38 | -* flasher logic as well. It turned out to be a tight squeeze. | |
43 | +* flasher and turn sgnal return logic as well. It turned out to be a | |
44 | +* tight squeeze. | |
39 | 45 | |
40 | 46 | * The intent of this document is to focus on the problems of |
41 | 47 | * decoding inputs, directionalizing the turn signal return, eliminating |
@@ -44,7 +50,8 @@ | ||
44 | 50 | * electro-static discharge protection (very important in automotive |
45 | 51 | * applications), and details of lamp driver circuits are mostly set |
46 | 52 | * aside. The logic has been tested with the M68HC705KICS simulator |
47 | -* program, but has not been tested in physical mock up or real vehicle. | |
53 | +* program, but has not been tested in a physical mock up or real | |
54 | +* vehicle. | |
48 | 55 | |
49 | 56 | * One of the objects of this design was to replace mechanical |
50 | 57 | * parts (that tend to flow in hot climates and become brittle in cold) |
@@ -66,15 +73,16 @@ | ||
66 | 73 | * The turn signal return mechanism is a pair of reed relays |
67 | 74 | * mounted inside the bottom of the steering column cowling about ten |
68 | 75 | * degrees apart, with three magnetic actuators mounted to the steering |
69 | -* shaft at ten o'clock, two o'clock, and six o'clock. (Four magnets in | |
70 | -* an x pattern might also be workable, I haven't reworked the angular | |
71 | -* timing to be sure.) The shape and position of the magnets and reeds | |
72 | -* should be such that the reeds close only once as a magnet passes, and | |
73 | -* such that the reeds have about ten degrees of overlapping actuation. | |
74 | -* The overlap in actuation helps determine the direction the steering | |
75 | -* wheel is rotating. Minor changes to the software should allow the use | |
76 | -* of optical sensors, but I have the impression the magnetic devices are | |
77 | -* more immune to extremes of climate. | |
76 | +* shaft at ten o'clock, two o'clock, and six o'clock. (More magnets and | |
77 | +* other patterns might also be workable, but they should be tested in | |
78 | +* real steering assembly before the design is locked in. The shape and | |
79 | +* position of the magnets and reeds should be such that the reeds close | |
80 | +* only once as a magnet passes, and such that the reeds have about ten | |
81 | +* degrees of overlapping actuation. The overlap in actuation helps | |
82 | +* determine the direction the steering wheel is rotating. Minor changes | |
83 | +* to the design should allow the use of optical sensors, but I have the | |
84 | +* impression that magnetic devices are more immune to extremes of | |
85 | +* climate. | |
78 | 86 | |
79 | 87 | SUBHEADER 'Model Schematic' |
80 | 88 | PAGE |
@@ -106,11 +114,11 @@ | ||
106 | 114 | * +---5V_ZENER---GND |
107 | 115 | |
108 | 116 | * PA1>---DRVRS_ON_CNTRL |
109 | -* | |
117 | + | |
110 | 118 | * IRQ<---+---100K_OHM---Vdd |
111 | 119 | * | |
112 | 120 | * +---EMG_SW---GND |
113 | -* | |
121 | + | |
114 | 122 | * PB1<>--+----------LEFT_RETURN_SW---+ |
115 | 123 | * | | |
116 | 124 | * +---LEFT_TURN_SW---+ | |
@@ -140,9 +148,8 @@ | ||
140 | 148 | * active high. |
141 | 149 | |
142 | 150 | * I arbitrarily assume the signal lamp drivers will be active low. |
143 | -* Who could say why? I considered attempting to hide this assumption in | |
144 | -* a macro but I'll skip that complexity. It shouldn't be too hard to | |
145 | -* find all the places to invert the outputs. | |
151 | +* Who could say why? However, I have hidden this assumption in a macro | |
152 | +* so I don't have to remember it. | |
146 | 153 | |
147 | 154 | * Hanging the indicators and the audio feedback on the front lamp |
148 | 155 | * drivers separates them from brake activity. Two audio feedback |
@@ -167,27 +174,34 @@ | ||
167 | 174 | * natural match for IRQ. |
168 | 175 | |
169 | 176 | * The right turn signal return switch is positioned about five |
170 | -* degrees right of bottom, and the left return is positioned the same | |
171 | -* distance to the left. In this way, when the steering wheel rotates, | |
172 | -* the return switch for the direction of rotation actuates first, then | |
173 | -* the opposite direction switch closes, then the same direction switch | |
174 | -* opens, and then the opposite direction switch opens. Thus, when | |
175 | -* restoring from a turn, the return switch for the appropriate direction | |
176 | -* closes after the other switch. In other words, if you turn right, the | |
177 | -* steering wheel will be rotate to the left when you restore to the | |
178 | -* straight, and the switches actuate from left to right during the | |
179 | -* restore. | |
177 | +* degrees right of bottom of the steering column housing, and the left | |
178 | +* return is positioned the same distance to the left. In this way, when | |
179 | +* the steering wheel rotates, the return switch for the direction of | |
180 | +* rotation actuates first, then the opposite direction switch closes, | |
181 | +* then the same direction switch opens, and then the opposite direction | |
182 | +* switch opens. Thus, when restoring from a turn, the return switch for | |
183 | +* the appropriate direction closes after the other switch. In other | |
184 | +* words, if you turn right, the steering wheel will be rotate to the | |
185 | +* left when you return to straight, and the switches actuate from left | |
186 | +* to right during the restore. | |
180 | 187 | |
181 | 188 | * When both turn signals are off, both turn signal ports are set |
182 | 189 | * as inputs. When a turn signal switch input senses a closure, that |
183 | 190 | * port is made an output and driven high. When the cancel input senses |
184 | -* a closure, the turn signal ports are restored to both input. If the | |
185 | -* cancel input remains high, a manual cancel is decoded. If not, the | |
186 | -* other direction input is made output and driven high. If the cancel | |
187 | -* input remains high now, the other direction switch closed first, and a | |
188 | -* restoring rotation is decoded. If not, same direction rotation is | |
189 | -* decoded, so the opposite direction port is returned to input, and the | |
190 | -* original direction port is again made output and driven high. | |
191 | +* a closure, the turn signal ports are restored to both input. | |
192 | + | |
193 | +* If the cancel input remains high, a manual cancel is decoded. | |
194 | +* If not, the other direction input is made output and driven high. If | |
195 | +* the cancel input returns high now, the other direction switch closed | |
196 | +* first, and a restoring rotation is decoded. If not, same direction | |
197 | +* rotation is decoded; then the the opposite direction port is returned | |
198 | +* to input, and the original direction port is again made output and | |
199 | +* driven high to wait again. | |
200 | + | |
201 | +* In the meantime, if the opposite direction turn signal input | |
202 | +* senses a closure, then it is assumed that the operator changed his | |
203 | +* mind without hitting the manual cancel, and the roles of the turn | |
204 | +* signal I/O bits are reversed. | |
191 | 205 | |
192 | 206 | * A peculiar characteristic of this design is the apparent lack of |
193 | 207 | * use for the RESET input. Since power-on reset is built in to the |
@@ -196,6 +210,7 @@ | ||
196 | 210 | |
197 | 211 | SUBHEADER 'Obligatory Mnemonics' |
198 | 212 | PAGE |
213 | +$base $0A | |
199 | 214 | $include "68HC05K.EQU" |
200 | 215 | |
201 | 216 | SUBHEADER 'Program Mnemonics' |
@@ -227,38 +242,54 @@ RGT_BT_ equ B0_ | ||
227 | 242 | |
228 | 243 | |
229 | 244 | * logical input definitions for debounce and states |
230 | -F_LFT equ {LFT_BT < 4} ; fold onto output | |
231 | -F_LFT_ equ {LFT_BT + 4} | |
232 | -F_RGT equ {RGT_BT < 4} ; fold onto output | |
233 | -F_RGT_ equ {RGT_BT + 4} | |
234 | -F_BRK equ BRK_SW | |
235 | -F_BRK_ equ BRK_SW_ | |
236 | -F_ENG equ ENG_SW | |
237 | -F_ENG_ equ ENG_SW_ | |
238 | -F_EMG equ DRVDRV ; fold onto output | |
239 | -F_EMG_ equ DRVDRV_ | |
240 | -F_CAN equ CAN_BT | |
241 | -F_CAN_ equ CAN_BT_ | |
242 | - | |
245 | +* bits are remapped for debounce and queue speed | |
246 | +F_LFT equ LFT_BT | |
247 | +F_LFT_ equ LFT_BT_ | |
248 | +F_RGT equ RGT_BT | |
249 | +F_RGT_ equ RGT_BT_ | |
250 | +F_BRK equ {BRK_SW < 2} ; physical output bit | |
251 | +F_BRK_ equ {BRK_SW_ + 2} | |
252 | +F_ENG equ {ENG_SW < 2} ; physical output bit | |
253 | +F_ENG_ equ {ENG_SW_ + 2} | |
254 | +F_EMG equ {DRVDRV < 2} ; fold onto output bit | |
255 | +F_EMG_ equ {DRVDRV_ + 2} | |
256 | +F_CAN equ {CAN_BT < 2} | |
257 | +F_CAN_ equ {CAN_BT_ + 2} | |
258 | + | |
259 | +* Event queue constants | |
260 | +* We only have 6 bit events and only record 4 in the queue. | |
261 | +* Event scan algorithm wired to highest event bit in bit 3. | |
262 | + | |
263 | +MAXEVENTS equ 6 ; more than max bit changes in "time slice" | |
243 | 264 | |
244 | 265 | SUBHEADER 'Resource Definitions' |
245 | 266 | PAGE |
246 | 267 | |
247 | 268 | * crystal frequency, in MHz: |
248 | 269 | XTAL equ 1 |
270 | +RTIPOW equ 1 ; ls bits is right place for timer hardware | |
271 | +RTIRATE equ {2 < RTIPOW} ; 2 ^ RTIPOW stored is actual divide | |
272 | +TIMOUT equ {9155*XTAL/RTIRATE+1} ; 5 minutes (if XTAL equ is correct) | |
273 | +* only one flash rate, 2/3 duty cycle | |
274 | +FLASH0 equ {32*XTAL/RTIRATE/4} ; about 1/4 second | |
275 | +FLASH1 equ {32*XTAL/RTIRATE/2} ; about 1/2 second | |
249 | 276 | |
250 | 277 | org MOR |
251 | 278 | fcb {PIN3 | RC | PIRQ | COPEN} |
252 | 279 | |
253 | - | |
254 | 280 | org RAMBEG |
255 | 281 | DEBO rmb 3 ; the debounce record chain |
282 | +STABLE rmb 1 ; temporary record of stable bits | |
283 | +TOGGLQ equ STABLE ; temporary record of queue events | |
256 | 284 | TOGGLE rmb 1 ; record of toggles |
257 | -STABLE rmb 1 ; timer service temporary | |
258 | 285 | ISTATE rmb 1 ; record of the current input state |
286 | +QIN rmb 1 ; queue input point | |
287 | +QOUT rmb 1 ; queue output point | |
288 | +EVENTQ rmb MAXEVENTS ; no need to initialize this | |
259 | 289 | STATES rmb 1 ; current controller states |
260 | 290 | ENG_TIM rmb 2 ; engine time out timer |
261 | -SOFTIM rmb 2 ; flash timer | |
291 | +FLASH rmb 1 ; flash timer | |
292 | +FLTIME rmb 1 ; flash flash time to load | |
262 | 293 | |
263 | 294 | |
264 | 295 | * ROM definitions follow: |
@@ -266,22 +297,21 @@ SOFTIM rmb 2 ; flash timer | ||
266 | 297 | |
267 | 298 | SUBHEADER 'Timer Service Code -- debounce' |
268 | 299 | PAGE |
269 | -* The timer service routine has two functions: debouncing the | |
270 | -* inputs and maintaining the software clocks. Interrupts occur on timer | |
300 | +* The timer service routine has five functions: debouncing the | |
301 | +* inputs, directly setting the brake lights, loading the flasher event | |
302 | +* queue, and maintaining two software clocks. Interrupts occur on timer | |
271 | 303 | * overflow (1024 CPU cycles). |
272 | 304 | |
273 | 305 | * The debounce routine translates the physical inputs to logical |
274 | 306 | * inputs, maintains a record of the last three logical states sensed in |
275 | 307 | * DEBO, debounces each input on three identical states, flags changes in |
276 | 308 | * the debounced input in TOGGLE, and leaves the current debounced input |
277 | -* in ISTATE. STABLE is a local variable with dynamic scope. | |
278 | - | |
279 | -* Since debouncing occurs on three identical states, the debounce | |
280 | -* period is between two and three timer overflows -- 4 to 6 mS with a | |
281 | -* 1 MHz crystal, 2 to 3 mS with a 2 MHz crystal. | |
282 | - | |
283 | -* Debouncing ignores the return switch logic. | |
309 | +* in ISTATE. Since debouncing occurs on three identical states, the | |
310 | +* debounce period is between two and three timer overflows -- 4 to 6 mS | |
311 | +* with a 1 MHz crystal, 2 to 3 mS with a 2 MHz crystal. Debouncing | |
312 | +* ignores the return switch logic and related activities. | |
284 | 313 | |
314 | +$CYCLE_ADDER_ON | |
285 | 315 | TIMSRV bset TOFR_,TSCR |
286 | 316 | lda DEBO+1 ; move the debounce chain |
287 | 317 | sta DEBO+2 |
@@ -289,67 +319,147 @@ TIMSRV bset TOFR_,TSCR | ||
289 | 319 | sta DEBO+1 |
290 | 320 | * read the inputs, converting physical to logical |
291 | 321 | lda PORTB ; PB2-7 always read 0 |
292 | - lsla ; move bits to flag positions | |
293 | - lsla | |
294 | - lsla | |
295 | - lsla | |
296 | - sta DEBO ; B read complete | |
322 | + sta DEBO | |
297 | 323 | lda PORTA |
298 | 324 | and #{BRK_SW | ENG_SW | CAN_BT } ; clears F_EMG |
299 | 325 | bih TIM0MG ; invert EMG and fold it in |
300 | 326 | ora #F_EMG |
301 | -TIM0MG ora DEBO | |
327 | +TIM0MG lsra ; remap | |
328 | + lsra | |
329 | + ora DEBO | |
302 | 330 | sta DEBO ; current state |
303 | - | |
304 | 331 | * debounce inputs, set flags in TOGGLE |
305 | 332 | lda DEBO |
306 | 333 | eor DEBO+1 |
307 | - sta TOGGLE ; re-use! (TOGGLE not valid) | |
334 | + sta TOGGLE ; re-use TOGGLE, TOGGLE not valid | |
308 | 335 | lda DEBO+1 |
309 | 336 | eor DEBO+2 |
310 | 337 | ora TOGGLE ; a bit for any input that bounced |
311 | - coma ; bits that did not bounce are set | |
338 | + coma ; bits that bounced are clear | |
312 | 339 | tax |
313 | 340 | and DEBO+2 ; state of stable bits |
314 | - sta STABLE ; (unstable bits cleared) | |
341 | + sta STABLE ; (unstable bits still clear) | |
315 | 342 | txa |
316 | - and ISTATE ; clear bits that are now unstable | |
343 | + and ISTATE ; look only at bits that are stable | |
317 | 344 | eor STABLE ; flag bits that toggled |
318 | 345 | sta TOGGLE ; TOGGLE now valid |
319 | 346 | coma ; mask of non-toggles |
320 | 347 | and ISTATE ; old state of non-toggles |
321 | 348 | sta ISTATE ; (toggled bits cleared) |
322 | 349 | lda TOGGLE ; mask of toggles |
323 | - and DEBO+2 ; new states | |
350 | + and STABLE ; new states of bits that toggled | |
324 | 351 | ora ISTATE |
325 | 352 | sta ISTATE ; ISTATE now has current debounced inputs |
326 | 353 | |
327 | - SUBHEADER 'Timer Service Code -- timers' | |
354 | + SUBHEADER 'Timer Service Code -- brake lights' | |
355 | + PAGE | |
356 | +* Brake lights are the highest priority function, depending only | |
357 | +* on the ISTATE F_BRK. The STATES F_BRK is returned as a flag to other | |
358 | +* routines. | |
359 | + | |
360 | + brclr F_BRK_,ISTATE,TMBRK0 | |
361 | + bset F_BRK_,STATES | |
362 | + bclr R_LDRV_,PORTA ; brake lights on | |
363 | + bclr R_RDRV_,PORTA | |
364 | +* high center brake light connects directly to brake switch. | |
365 | + bra TMBRKDUN | |
366 | +TMBRK0 bclr F_BRK_,STATES | |
367 | + bset R_LDRV_,PORTA ; brake lights off | |
368 | + bset R_RDRV_,PORTA ; (flashers can turn them back on) | |
369 | +TMBRKDUN | |
370 | + | |
371 | + SUBHEADER 'Timer Service Code -- fill event queue' | |
372 | + PAGE | |
373 | +* General debounce complete; now put signal events in queue: | |
374 | +* Brake and engine-on are handled in TIMSRV, as synchronous events, and | |
375 | +* so are not queued. Turn signal and emergency inputs are positive edge | |
376 | +* sensitive, falling edges are ignored. | |
377 | + | |
378 | +* Queue is post-inc push and pull; QIN == QOUT is empty queue; | |
379 | +* queue overflow causes the oldest event to be discarded, but should | |
380 | +* never occur. | |
381 | + | |
382 | + lda TOGGLE ; F_BRK & F_ENG are not queued! | |
383 | + and #{$FF ^ F_BRK ^ F_ENG} ; KICS assembler has no bit not? | |
384 | + and ISTATE ; queue only TOGGLE on | |
385 | + sta TOGGLQ | |
386 | + beq TMCLOCK ; save time | |
387 | + ldx QIN | |
388 | + lda #$10 ; start with bit 3! | |
389 | +* cycles to this point, plus interrupt response (19 cycles) | |
390 | + | |
391 | +$CYCLE_ADDER_OFF | |
392 | +$CYCLE_ADDER_ON | |
393 | +TMQSCAN lsra ; scan TOGGLE | |
394 | + beq TMQDUN | |
395 | + bit TOGGLQ | |
396 | + beq TMQSCAN | |
397 | +* 12 cycles minimum time in loop | |
398 | +$CYCLE_ADDER_OFF | |
399 | +$CYCLE_ADDER_ON | |
400 | + sta ,x | |
401 | + incx | |
402 | + cpx #EVENTQ+MAXEVENTS | |
403 | + blo TMQNWRP | |
404 | + ldx #EVENTQ ; 2 cycles | |
405 | +TMQNWRP cpx QOUT | |
406 | + bne TMQSCAN | |
407 | + inc QOUT ; 5 cycles | |
408 | +TMQNBMP bra TMQSCAN ; 3 cycles | |
409 | +* 40 cycles maximum time in loop, (40 - 2 - 5 - 3) == 30 typical max; | |
410 | +* Minimum queue time is 12 * 3 + 30 == 66 (no wrap, no bump); | |
411 | +* max is 30 * 3 + 40 == 130 (one wrap, one bump max) | |
412 | +$CYCLE_ADDER_OFF | |
413 | +$CYCLE_ADDER_ON | |
414 | +TMQDUN stx QIN | |
415 | + | |
416 | + SUBHEADER 'Timer Service Code -- engine time out and flasher timers' | |
328 | 417 | PAGE |
329 | 418 | * Although the Real Time Interrupt is masked, the software clocks |
330 | 419 | * use the RTI flag. Selecting the fastest RTI rate gives the software |
331 | 420 | * clocks a resolution of eight timer overflows (8192 CPU cycles). |
332 | 421 | |
333 | -* The engine timeout counter is not allowed to underflow | |
334 | - | |
335 | -* time to clock? | |
422 | +TMCLOCK | |
336 | 423 | brclr RTIF_,TSCR,TIMDUN |
337 | 424 | bset RTIFR_,TSCR |
338 | -* engine time out counter: | |
339 | - brset F_ENG_,ISTATE,TIMFLH ; avoid wasting time here | |
425 | + | |
426 | +* The engine time-out counter resets if the engine toggles on. It | |
427 | +* runs only when the ISTATE F_ENG bit is low and the emergency flashers | |
428 | +* (STATES F_EMG) are off. It does not underfow. The timer flags | |
429 | +* timeout in STATES F_ENG. | |
430 | + | |
431 | + brclr F_ENG_,TOGGLE,TMENG0 | |
432 | + lda #{TIMOUT & $FF } ; reset the clock | |
433 | + sta ENG_TIM+1 | |
434 | + lda #{TIMOUT / $100 + 1} ; borrow on 0, not -1 | |
435 | + sta ENG_TIM | |
436 | + bra TMFLASH | |
437 | + | |
438 | +TMENG0 | |
439 | + brset F_ENG_,ISTATE,TMFLASH | |
440 | + brset F_EMG_,STATES,TMFLASH | |
441 | + brclr F_ENG_,STATES,TMFLASH ; do not underflow! | |
340 | 442 | dec ENG_TIM+1 |
341 | 443 | bne TIMFLH ; initial count is adjusted to make this work |
342 | 444 | dec ENG_TIM |
343 | 445 | bne TIMFLH |
344 | - clr ENG_TIM+1 ; no underflow | |
345 | - clr ENG_TIM | |
346 | - bset F_ENG_,STATES ; signal timed out | |
347 | -TIMFLH | |
348 | - inc SOFTIM+1 | |
446 | + bclr F_ENG_,STATES ; signal timed out | |
447 | + bset F_ENG_,TOGGLE ; communicate with MAINLOOP | |
448 | + | |
449 | +* flasher counter | |
450 | +TMFLASH lda #{F_EMG | F_LFT | F_RGT} | |
451 | + and STATES ; flasher active? | |
452 | + beq TIMDUN | |
453 | + dec FLASH | |
349 | 454 | bne TIMDUN |
350 | - inc SOFTIM | |
351 | -TIMDUN rti ; careful with the interrupt service time! | |
455 | + lda FLTIME | |
456 | + sta FLASH | |
352 | 457 | |
458 | +TIMDUN rti | |
459 | +$CYCLE_ADDER_OFF | |
460 | +* Keep the maximum clock cycles in TIMSRV below half of TOFR period. | |
461 | +* It is probably physically impossible to operate the switches fast | |
462 | +* enough to overflow the queue that way. | |
353 | 463 | |
354 | 464 | SUBHEADER 'Initializations' |
355 | 465 | PAGE |
@@ -357,9 +467,10 @@ TIMDUN rti ; careful with the interrupt service time! | ||
357 | 467 | * if SWI occurs, the machine is not in a defined state, and must reset |
358 | 468 | IRQSRV |
359 | 469 | SWISRV rsp ; now falls through to RSTSRV |
470 | + clra | |
471 | + sta COPR | |
360 | 472 | * general inits |
361 | -RSTSRV clr COPR ; just in case | |
362 | - lda #{F_LDRV | F_RDRV | R_LDRV | R_RDRV} | |
473 | +RSTSRV lda #{F_LDRV | F_RDRV | R_LDRV | R_RDRV} | |
363 | 474 | sta PORTA ; initial output values |
364 | 475 | lda #{F_LDRV | F_RDRV | R_LDRV | R_RDRV | DRVDRV} |
365 | 476 | sta DDRA ; set up directions |
@@ -373,67 +484,166 @@ RSTSRV clr COPR ; just in case | ||
373 | 484 | * disable external interrupts |
374 | 485 | bclr IRQE_,ISCR |
375 | 486 | bset IRQR_,ISCR ; clear the flag |
376 | -* clear RAM | |
377 | - ldx #RAMBEG | |
378 | - lda #RAMSIZ | |
379 | -RSTCLR clr ,x ; this is probably a waste? | |
380 | - incx | |
381 | - deca | |
382 | - bne RSTCLR | |
383 | 487 | * set up hardware timer |
384 | - clr COPR ; the manual suggests doing this before timer rate | |
385 | - lda #TOIE ; only timer overflow interrupts | |
386 | - sta TSCR ; and the fastest Real Time rate | |
488 | + clra | |
489 | + sta COPR ; b0 clear, about to change timer rate | |
490 | + lda #{TOIE | RTIPOW} ; only timer overflow interrupts | |
491 | + sta TSCR | |
387 | 492 | ora #{TOFR|RTIFR} ; clear the flags |
388 | 493 | sta TSCR |
389 | 494 | * set up specific variables |
495 | + clr DEBO ; start debounce chain clear | |
496 | + clr DEBO+1 ; DEBO+2 is thrown out on first timer interrupt | |
390 | 497 | lda #{F_ENG} |
391 | - sta ISTATE ; we know the engine is on! | |
498 | + sta ISTATE ; force TIMOUT to be set | |
392 | 499 | sta TOGGLE |
393 | - sta STATES | |
500 | + sta STATES ; we think the engine is on | |
501 | + ldx #EVENTQ ; empty QUEUE | |
502 | + stx QIN | |
503 | + stx QOUT | |
394 | 504 | |
395 | -MAINLOOP | |
396 | -* Assume interrupts enabled, except for brief critical sections | |
397 | -* Falls through to input filter functions | |
505 | +* Falls through to MAINLOOP | |
398 | 506 | |
399 | - SUBHEADER 'Main function: input filter state machines' | |
507 | + SUBHEADER 'STOP and dequeue' | |
400 | 508 | PAGE |
401 | 509 | |
402 | -* Engine on filter resets the toggle bit and sets the timer if | |
403 | -* toggled off. STATES bit is handled by TIMSRV. | |
510 | +MAINLOOP | |
511 | + cli ; leave interrupts enabled as much as possible | |
512 | + clra | |
513 | + sta COPR ; tell COP we're in control | |
514 | +* check for STOP, dequeue flasher events, wait if necessary | |
515 | + sei | |
516 | + brclr F_ENG_,STATES,MNSTOP | |
517 | + ldx QOUT | |
518 | + cpx QIN ; QUEUE empty? | |
519 | + bne MNDEQUEUE | |
520 | + lda STATES ; can we save power for a bit? | |
521 | + and #{F_LFT | F_RGT | F_BRK | F_EMG} | |
522 | + bne MNDRVWT | |
523 | + bclr DRVDRV_,PORTA | |
524 | +MNDRVWT wait ; enable interrupts, wait for timer | |
525 | + tst TOGGLE | |
526 | + beq MNDRVWT ; nothing changed, nothing to respond to | |
527 | +* with no activity, COP periodically resets the MCU system | |
528 | +* this is not generally good engineering practice. | |
529 | + bset DRVDRV_,PORTA ; IRQSRV might have driven the brake lights | |
530 | + bra MAINLOOP ; check STOP and QUEUE again | |
531 | + | |
532 | +* go to power conserving state | |
533 | +MNSTOP lda #{F_LDRV | F_RDRV | R_LDRV | R_RDRV} | |
534 | + sta PORTA ; shut everything down, organized! | |
535 | + lda #{F_LDRV | F_RDRV | R_LDRV | R_RDRV | DRVDRV} | |
536 | + sta DDRA ; set up directions | |
537 | + sta PDRA ; pull downs only on inputs | |
538 | + clr PORTB ; initial outputs (do port B just in case) | |
539 | + clr DDRB ; B initially input | |
540 | + clr PDRB ; with pull downs set | |
541 | +* make sure EPROM programming stuff is out of the way | |
542 | + clr EPROG | |
543 | + clr PESCR | |
544 | +* enable external interrupts | |
545 | + bset IRQE_,ISCR ; DO NOT clear the flag (IRQ won't return) | |
546 | + stop ; also shuts timer down | |
547 | + jmp SWISRV ; should never come here (resets stack pointer) | |
404 | 548 | |
405 | -TIMOUT EQU 18311/XTAL ; 5 minutes (if XTAL equ is correct) | |
549 | +MNDEQUEUE | |
550 | + lda ,x | |
551 | + incx | |
552 | + cpx #EVENTQ+MAXEVENTS | |
553 | + blo MNQNWRP | |
554 | + ldx #EVENTQ | |
555 | +MNQNWRP stx QOUT | |
556 | + cmp #F_EMG | |
557 | + bne MNCAN | |
558 | + eor STATES ; toggle STATES F_EMG emergency flashers bit | |
559 | + sta STATES | |
560 | + bra MNDOSTATES | |
561 | + | |
562 | +MNQCAN cmp #F_CAN | |
563 | + bne MNQLFT | |
564 | + lda DDRB | |
565 | + eor #3 | |
566 | + | |
567 | + clr DDRB | |
568 | + bsr CANDEBO | |
569 | + cmp #6 | |
570 | + blo MNQCAND | |
571 | + bset F_CAN_,STATES | |
572 | + bra MNDOSTATES | |
573 | +MNQCAND lda STATES | |
574 | + and #{F_LFT | F_RGT} | |
575 | + eor #{F_LFT | F_RGT} ; other port | |
576 | + sta DDRB | |
577 | + bsr CANDEBO | |
578 | + | |
579 | + | |
580 | +MNQLFT cmp #F_LFT | |
581 | + bne MNQRGT | |
582 | + bset F_LFT_,STATES | |
583 | + bclr F_RGT_,STATES | |
584 | + bra MNDOSTATES | |
585 | + | |
586 | +MNQRGT cmp #F_RGT | |
587 | + bne MNQDEF | |
588 | + bset F_RGT_,STATES | |
589 | + bclr F_LFT_,STATES | |
590 | + bra MNDOSTATES | |
591 | + | |
592 | +MNQDEF jmp SWISRV ; nothing else should be queued | |
593 | + | |
594 | +* subroutine to quickly "debounce" the cancel input | |
595 | +* reads CAN_BT eight times, summing the bits into A | |
596 | +* trashes X | |
597 | +$CYCLE_ADDER_ON | |
598 | +CANDEBO ldx #8 | |
599 | + clra | |
600 | + brclr CAN_BT_,PORTA,CANDEB1 ; get CAN_BT into carry | |
601 | +CANDEB1 adc #0 | |
602 | + decx | |
603 | + bne CANDEBO | |
604 | +$CYCLE_ADDER_OFF | |
605 | +* about 1/4 mS at 1 MHz, sufficient to believe the input bit | |
606 | + rts | |
607 | + | |
608 | + | |
609 | +* then make the output mirror the state | |
610 | + | |
611 | + | |
612 | +DOSTATE | |
613 | + brset F_BRK_,STATES,MAINLOOP ; if brakes set, do nothing else | |
614 | + brset F_EMG_,STATES,DOEMERG ; if emergency flash, skip engine | |
615 | + brset F_ENG_,STATES,DOTURN ; no turn signals if engine off | |
616 | +* engine off and timed out, no brakes, no emergency flashers | |
617 | + lda | |
406 | 618 | |
407 | -INFENG cli ; allow interrupts | |
408 | - sei ; critical: not seamless access | |
409 | - brclr F_ENG_,TOGGLE,INFEMG | |
410 | - bclr F_ENG_,TOGGLE | |
411 | - brset F_ENG_,ISTATE,INFEMG ; engine on input toggled off | |
412 | - lda #{TIMOUT & $FF} | |
413 | - sta ENG_TIM+1 | |
414 | - lda #{TIMOUT / 256 + 1} ; counter borrows on 0, not -1 | |
415 | - sta ENG_TIM | |
416 | -* fall through | |
417 | 619 | |
418 | 620 | * Emergency flasher filter simply toggles F_EMG bit of STATES |
419 | -* when emergency flasher button is pressed. | |
621 | +* when emergency flasher button is pressed. Release is ignored. | |
420 | 622 | |
421 | 623 | INFEMG cli ; allow interrupts |
422 | 624 | sei ; critical: not seamless access |
423 | 625 | brclr F_EMG_,TOGGLE,INFTRN |
424 | 626 | bclr F_EMG_,TOGGLE |
425 | 627 | brclr F_EMG_,ISTATE,INFTRN ; no action when button released |
426 | - lda #F_EMG | |
427 | - eor STATES | |
628 | + lda STATES | |
629 | + eor #F_EMG | |
428 | 630 | sta STATES |
429 | 631 | * fall through |
430 | 632 | |
431 | 633 | * |
634 | + | |
432 | 635 | INFTRN cli ; allow interrupts |
433 | 636 | sei ; critical: not seamless access |
434 | - | |
435 | - | |
436 | -* stuff in state machines: | |
637 | + lda STATES | |
638 | + and ISTATE | |
639 | + and #{F_LFT | F_RGT} ; mask | |
640 | + eor #{F_LFT | F_RGT} ; ignore if already on | |
641 | + and TOGGLE | |
642 | + beq FNENG | |
643 | + tax | |
644 | + and ISTATE ; too late at night, all my work this aft is gone | |
645 | +* check here for turning | |
646 | +FNENG | |
437 | 647 | |
438 | 648 | * support on and off states on signal timer. |
439 | 649 |
@@ -481,12 +691,8 @@ INFTRN cli ; allow interrupts | ||
481 | 691 | * EMG_NO (F_EMG==1 && EMG_FL==0)---> EMG_FL |
482 | 692 | * |
483 | 693 | |
484 | - wait | |
485 | - clr COPR | |
486 | - tst TOGGLE | |
487 | - beq FUNSTATE | |
488 | 694 | |
489 | - bra WAITLOOP | |
695 | + bra MAINLOOP | |
490 | 696 | |
491 | 697 | |
492 | 698 | org VECTORS |