Subversion Repositories svn.mios

Rev

Rev 52 | Rev 321 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
53 tk 1
; $Id: mios_isr.inc 53 2008-01-30 22:52:41Z tk $
1 tk 2
;
3
; IRQ Vector and Service Routines of MIOS
4
;
5
; ==========================================================================
6
;
7
;  Copyright 1998-2006 Thorsten Klose (tk@midibox.org)
8
;  Licensed for personal non-commercial use only.
9
;  All other rights reserved.
10
;
11
; ==========================================================================
12
 
13
 
14
;; --------------------------------------------------------------------------
15
;;  FUNCTION: USER_Timer
16
;;  C_DECLARATION: void Timer(void)
17
;;  DESCRIPTION: This function is periodically called by MIOS. The frequency
18
;;  has to be initialized with MIOS_Timer_Set<BR>
19
;;  Note that this is an interrupt service routine! Use FSR2 instead of FSR0
20
;;  and IRQ_TMPx instead of TMPx -- and make the routine as fast as possible!
21
;;  IN:	  -
22
;;  C_IN:  -
23
;;  OUT:  -
24
;;  C_OUT:  -
25
;;  ISR: yes
26
;; --------------------------------------------------------------------------
27
 
28
;; --------------------------------------------------------------------------
29
;;  FUNCTION: USER_SR_Service_Prepare
30
;;  C_DECLARATION: void SR_Service_Prepare(void)
31
;;  DESCRIPTION: This function is called by MIOS before the shift register
32
;;  are loaded.<BR>
33
;;  Note that this is an interrupt service routine! Use FSR2 instead of FSR0
34
;;  and IRQ_TMPx instead of TMPx -- and make the routine as fast as possible!
35
;;  IN:	  -
36
;;  C_IN:  -
37
;;  OUT:  -
38
;;  C_OUT:  -
39
;;  ISR: yes
40
;; --------------------------------------------------------------------------
41
 
42
;; --------------------------------------------------------------------------
43
;;  FUNCTION: USER_SR_Service_Finish
44
;;  C_DECLARATION: void SR_Service_Finish(void)
45
;;  DESCRIPTION: This function is called by MIOS after the shift register
46
;;  have been loaded.<BR>
47
;;  Note that this is an interrupt service routine! Use FSR2 instead of FSR0
48
;;  and IRQ_TMPx instead of TMPx -- and make the routine as fast as possible!
49
;;  IN:	  -
50
;;  C_IN:  -
51
;;  OUT:  -
52
;;  C_OUT:  -
53
;;  ISR: yes
54
;; --------------------------------------------------------------------------
55
 
56
 
57
;; ==========================================================================
58
;;  IRQ Vector
59
;; ==========================================================================
60
 
61
	;; note: bootloader jumps to 0x0408 on interrupts
62
	org	0x0408
63
 
64
#if PIC_DERIVATIVE_IRQ_WORKAROUND
65
	;; interrupt workaround for some buggy PIC devices like PIC18F4620
66
	call	MIOS_ISR, FAST
67
MIOS_ISR
68
	pop
69
#endif
70
 
71
	;; save FSR2[LH], required for SDCC
72
	movff	FSR2L, MIOS_IRQ_FSR2L
73
	movff	FSR2H, MIOS_IRQ_FSR2H
74
 
75
IRQ_Handler
76
	; which IRQ received?
77
	BRA_IFSET PIR1, RCIF, ACCESS, IRQ_UART_Rx	; UART Receive IRQ?
78
	BRA_IFSET PIR1, TMR1IF, ACCESS, IRQ_Timer1        ; Timer1 IRQ?
79
	BRA_IFSET PIR2, TMR3IF, ACCESS, IRQ_Timer3        ; Timer3 IRQ?
80
 
81
	BRA_IFCLR PIE1, TXIE, ACCESS, IRQ_Handler_NoTxIRQ
82
	BRA_IFSET PIR1, TXIF, ACCESS, IRQ_UART_Tx	; UART Transmit IRQ?
83
IRQ_Handler_NoTxIRQ
84
 
85
	;; check T0IF only if interrupt is enabled (allows to use Timer0 as alternative resource)
86
	BRA_IFCLR INTCON, T0IE, ACCESS, IRQ_Handler_NoT0IRQ
87
	BRA_IFSET INTCON, T0IF, ACCESS, IRQ_Timer0	; Timer0 IRQ?
88
IRQ_Handler_NoT0IRQ
89
 
90
IRQEnd
91
 
92
	;; restore FSR2[LH], especially saved for SDCC
93
	movff	MIOS_IRQ_FSR2L, FSR2L
94
	movff	MIOS_IRQ_FSR2H, FSR2H
95
 
96
        retfie	FAST
97
 
98
;; ==========================================================================
99
;;  Used to store all user registers
100
;; ==========================================================================
101
MIOS_IRQ_StoreUserRegs
102
	movff	FSR1L, MIOS_IRQ_FSR1L		; store FSR1 and TBL* in temp. register
103
	movff	FSR1H, MIOS_IRQ_FSR1H
104
	movff	TBLPTRL, MIOS_IRQ_TBLPTRL
105
	movff	TBLPTRH, MIOS_IRQ_TBLPTRH
106
#if PIC_DERIVATIVE_CODE_SIZE > 0x10000
107
	movff	TBLPTRU, MIOS_IRQ_TBLPTRU
108
#endif
109
	movff	TABLAT, MIOS_IRQ_TABLAT
110
	movff	MIOS_PARAMETER1, MIOS_IRQ_PARAMETER1
111
	movff	MIOS_PARAMETER2, MIOS_IRQ_PARAMETER2
112
	movff	MIOS_PARAMETER3, MIOS_IRQ_PARAMETER3
113
	return
114
 
115
;; ==========================================================================
116
;;  Used to restore all user registers
117
;; ==========================================================================
118
MIOS_IRQ_RestoreUserRegs
119
	movff	MIOS_IRQ_FSR1L, FSR1L			; restore FSR1 and TBL* from temp. register
120
	movff	MIOS_IRQ_FSR1H, FSR1H
121
	movff	MIOS_IRQ_TBLPTRL, TBLPTRL
122
	movff	MIOS_IRQ_TBLPTRH, TBLPTRH
123
#if PIC_DERIVATIVE_CODE_SIZE > 0x10000
124
	movff	MIOS_IRQ_TBLPTRU, TBLPTRU
125
#endif
126
	movff	MIOS_IRQ_TABLAT, TABLAT
127
	movff	MIOS_IRQ_PARAMETER1, MIOS_PARAMETER1
128
	movff	MIOS_IRQ_PARAMETER2, MIOS_PARAMETER2
129
	movff	MIOS_IRQ_PARAMETER3, MIOS_PARAMETER3
130
	return
131
 
132
;; ==========================================================================
133
;;  IRQ Handler for Timer0, called every 100 us
134
;; ==========================================================================
135
IRQ_Timer0
136
	;; reload timer
137
	movlw	0x08
138
	movwf	TMR0L		; (no add, because we need a minimum time for the ADC!)
139
 
140
	;; clear IRQ flag
141
	bcf	INTCON, T0IF
142
 
143
	BRA_IFSET MIOS_BOX_STAT, MIOS_BOX_STAT_SUSPEND_ALL, ACCESS, IRQ_Timer0_End
144
 
145
	call	MIOS_AIN_Tick
146
 
147
	;; SET_BSR	MIOS_AIN_CTRL	;(already set)
148
	CALL_IFSET MIOS_AIN_CTRL, MIOS_AIN_CTRL_MF, BANKED, MIOS_MF_SRM_Tick
149
 
150
IRQ_Timer0_End
151
	rgoto	IRQ_Handler
152
 
153
;; ==========================================================================
154
;;  IRQ Handler for Timer1, called every ms
155
;; ==========================================================================
156
IRQ_Timer1
157
	;; clear IRQ flag
158
	bcf	PIR1, TMR1IF
159
 
160
	; reload T1
161
	bcf	T1CON, TMR1ON
162
	movlw	-39-1
163
	addwf	TMR1H, F
164
	movlw	-16-1
165
	addwf	TMR1L, F
166
	bsf	T1CON, TMR1ON
167
 
168
	;; Decrement Delay Counter
169
	SET_BSR	MIOS_DELAY_CTR
170
	movf	MIOS_DELAY_CTR, W, BANKED
171
	skpz
172
	decf	MIOS_DELAY_CTR, F, BANKED
173
 
174
	;; Increment GP Counter
175
	incf	MIOS_GP_CTR, F, BANKED
176
 
177
	BRA_IFSET MIOS_BOX_STAT, MIOS_BOX_STAT_SUSPEND_ALL, ACCESS, IRQ_Timer1_End
178
 
179
	movf	MIOS_GP_CTR, W, BANKED	; every 8th cycle decrement message counter -> 256*8 = ca. 2 seconds
180
	andlw	0x07
181
	bnz	IRQ_Timer1_MessageCtrSkip
182
	;; Decrement message counter if counter != 0
183
	decf	MIOS_MESSAGE_CTR, W, BANKED
184
	bz	IRQ_Timer1_MessageCtrSkip	; mainloop reacts when display counter == 1 and sets it to 0 (simple semaphore)
185
	movf	MIOS_MESSAGE_CTR, W, BANKED
186
	skpz
187
	decf	MIOS_MESSAGE_CTR, F, BANKED
188
IRQ_Timer1_MessageCtrSkip
189
 
190
	;; start SRIO scan once the update counter has reached zero
191
	SET_BSR	MIOS_SRIO_UPDATE_CTR
192
	decf	MIOS_SRIO_UPDATE_CTR, F, BANKED
193
	bnz	IRQ_Timer1_SkipScan
194
	movf	MIOS_SRIO_UPDATE_FRQ, W, BANKED
195
	skpnz
196
	incf	MIOS_SRIO_UPDATE_FRQ, W, BANKED
197
	movwf	MIOS_SRIO_UPDATE_CTR, BANKED
198
 
199
	;; skip if number of SRIOs is 0
200
	movf	MIOS_SRIO_NUMBER, W, BANKED
201
	bz	IRQ_Timer1_SkipScan
202
 
203
	;; decrement debounce counter so long it isn't zero
204
	movf	MIOS_SRIO_DEBOUNCE_CTR, W, BANKED
205
	skpz
206
	decf	MIOS_SRIO_DEBOUNCE_CTR, F, BANKED
207
 
208
IRQ_Timer1_DoScan
209
	;; do the SRIO scan and handle rotary encoders
210
	rcall	MIOS_IRQ_StoreUserRegs
211
	CALL_IFCLR MIOS_BOX_STAT, MIOS_BOX_STAT_SUSPEND_USER, ACCESS, USER_SR_Service_Prepare	; call prepare hook
212
	call	MIOS_SRIO_Tick		; SRIO scan
213
	call	MIOS_ENC_Tick		; encoder handler
214
	CALL_IFCLR MIOS_BOX_STAT, MIOS_BOX_STAT_SUSPEND_USER, ACCESS, USER_SR_Service_Finish	; call finish hook
215
 
216
	;; So long debounce counter is != 0, clear all MIOS_SR_DIN_CHANGED_x registers to ignore the button movements at this time.
217
	;; In order to ensure, that a new final state of a button won't get lost, the DIN values are XORed with the CHANGED registers.
218
	;; Yes, this ill idea works! :)
219
	;; Even the encoder handler still works properly, because it clears the appr. _DIN_CHANGED_x flags, so that the _DIN_x flags
220
	;; won't be touched by the XOR operation
221
	SET_BSR	MIOS_SRIO_DEBOUNCE_CTR	; GRRRRR! never forget to change the bank after a user call
222
	movf	MIOS_SRIO_DEBOUNCE_CTR, W, BANKED
223
	bz	IRQ_Timer1_DoScan_NoDebounce
224
IRQ_Timer1_DoScan_Debounce
225
	lfsr	FSR2, MIOS_SR_DIN_CHANGED_0
226
	lfsr	FSR1, MIOS_SR_DIN_0
227
	movlw	16
228
	movwf	IRQ_TMP1
229
IRQ_Timer1_DoScan_DebounceLoop
230
	movf	INDF2, W	; XOR _DIN_x with _DIN_CHANGED_x
231
	xorwf	POSTINC1, F
232
	clrf	POSTINC2	; clear _DIN_CHANGED_x
233
	decfsz	IRQ_TMP1, F
234
	rgoto	IRQ_Timer1_DoScan_DebounceLoop
235
IRQ_Timer1_DoScan_NoDebounce
236
 
237
	rcall	MIOS_IRQ_RestoreUserRegs
238
 
239
IRQ_Timer1_SkipScan
240
 
241
	;; handle auto repeats if debounce counter != 0
242
	movf	MIOS_SRIO_DEBOUNCE_CTR, W, BANKED
243
	skpnz
244
	call	MIOS_DIN_AutoRepeat_Tick
245
 
246
IRQ_Timer1_End
247
	rgoto	IRQ_Handler
248
 
249
 
250
;; ==========================================================================
251
;;  IRQ Handler for Timer3, called every 8*16*256 CPU cycles (= ca. 6.5 ms)
252
;; ==========================================================================
253
IRQ_Timer3
254
	;; clear IRQ flag
255
        bcf     PIR2, TMR3IF
256
 
257
	;; reload timer
258
	SET_BSR	MIOS_TIMER3_RELOAD_H
259
	bcf	T3CON, TMR3ON
260
	movf	MIOS_TIMER3_RELOAD_L, W, BANKED
261
	addwf	TMR3L, F
262
	movf	MIOS_TIMER3_RELOAD_H, W, BANKED
263
	addwfc	TMR3H, F
264
	bsf	T3CON, TMR3ON
265
 
266
	;; if MIOS_TIMER_Stop has been called, skip the rest
267
	BRA_IFCLR T3CON, TMR3ON, ACCESS, IRQ_Timer3_End
268
	;; also in suspend mode...
269
	BRA_IFSET MIOS_BOX_STAT, MIOS_BOX_STAT_SUSPEND_ALL, ACCESS, IRQ_Timer3_End
270
	BRA_IFSET MIOS_BOX_STAT, MIOS_BOX_STAT_SUSPEND_USER, ACCESS, IRQ_Timer3_End
271
 
272
	rcall	MIOS_IRQ_StoreUserRegs
273
	call	USER_Timer
274
	rcall	MIOS_IRQ_RestoreUserRegs
275
 
276
IRQ_Timer3_End
277
	rgoto	IRQ_Handler
278
 
279
 
280
;; ==========================================================================
281
;;  IRQ Handler for UART Transmitter
282
;; ==========================================================================
283
IRQ_UART_Tx
284
	SET_BSR	MIOS_TX_BUFFER_HEAD
285
	movf	MIOS_TX_BUFFER_HEAD, W, BANKED	; check if new byte has to be sent
286
	xorwf	MIOS_TX_BUFFER_TAIL, W, BANKED
287
	bnz	IRQ_UART_Tx_NextByte
288
 
289
	bcf	PIE1, TXIE			; prevent interrupts until this flag is set again by MIDI_SendByte
290
 
291
IRQ_UART_Tx_End
292
	rgoto	IRQ_Handler			; return to interrupt handler
293
 
294
IRQ_UART_Tx_NextByte
295
	rcall	MIOS_IRQ_StoreUserRegs
296
 
297
	rcall	MIOS_MIDI_TxBufferGet		; get byte from Tx buffer
298
	movwf	TXREG				; send it
299
 
300
	rcall	MIOS_IRQ_RestoreUserRegs
301
 
302
	rgoto	IRQ_Handler			; return to interrupt handler
303
 
304
;; ==========================================================================
305
;;  IRQ Handler for UART Receiver
306
;; ==========================================================================
307
IRQ_UART_Rx
308
	;; notify frame error in MIOS_BOX_STAT - this will lead to a timeout (or to an error response during SysEx transfer)
309
	btfsc	RCSTA, FERR
310
	bsf	MIOS_BOX_STAT, MIOS_BOX_STAT_FERR
311
 
312
	;; store received byte in MIOS internal register MIOS_IRQ_TMP_CTR
313
	;; (unfortunately this name has been choosen before I noticed that
314
	;; an internal TMP register is also required here)
315
	movff	RCREG, MIOS_IRQ_TMP_CTR
316
 
317
	rcall	MIOS_IRQ_StoreUserRegs
318
 
319
	SET_BSR	MIOS_IRQ_TMP_CTR
320
	BRA_IFSET MIOS_IRQ_TMP_CTR, 7, BANKED, IRQ_UART_Rx_Command
321
 
322
	movf	MIOS_MIDI_RUNSTATUS, W, BANKED	; on sysex: don't take care for the expected bytes
323
	xorlw	0xf0
324
	bz	IRQ_UART_Rx_ForwardSysEx
325
 
326
	movf	MIOS_MIDI_EXPBYTES, W, BANKED
327
	bnz	IRQ_UART_Rx_RunningData
328
 
329
	movf	MIOS_MIDI_RUNSTATUS, W, BANKED	; send running data status byte
330
	rcall	MIOS_MIDI_RxBufferPut
331
 
332
	movf	MIOS_MIDI_RUNSTATUS, W, BANKED	; store number of expected bytes in MIDI_EXPBYTES
333
	rcall	IRQ_UART_Rx_Hlp_GetCMax
334
	movwf	MIOS_MIDI_EXPBYTES, BANKED
335
 
336
IRQ_UART_Rx_RunningData
337
	decf	MIOS_MIDI_EXPBYTES, F, BANKED
338
IRQ_UART_Rx_ForwardSysEx
339
	movf	MIOS_IRQ_TMP_CTR, W, BANKED
340
	rcall	MIOS_MIDI_RxBufferPut
341
	rgoto	IRQ_UART_Rx_End
342
 
343
IRQ_UART_Rx_Command
344
	;; Command < 0xf8?
345
	movlw	0xf8 - 1
346
	cpfsgt	MIOS_IRQ_TMP_CTR, BANKED
347
	rgoto IRQ_UART_Rx_CommandLTF8
348
 
349
IRQ_UART_Rx_SystemCommand
350
	;; System >= F8: don't change Running Status and number of expected bytes!
351
	movf	MIOS_IRQ_TMP_CTR, W, BANKED	; just forward received byte
352
	rcall	MIOS_MIDI_RxBufferPut
353
	rgoto	IRQ_UART_Rx_End
354
 
355
IRQ_UART_Rx_CommandLTF8
356
	;; command less than F8: store running status, send byte, calc number of expected bytes
357
	movf	MIOS_IRQ_TMP_CTR, W, BANKED
358
	movwf	MIOS_MIDI_RUNSTATUS, BANKED
359
	movf	MIOS_MIDI_RUNSTATUS, W, BANKED
360
	rcall	IRQ_UART_Rx_Hlp_GetCMax
361
	movwf	MIOS_MIDI_EXPBYTES, BANKED
362
 
363
	movf	MIOS_MIDI_RUNSTATUS, W, BANKED
364
	rcall	MIOS_MIDI_RxBufferPut
365
 
366
IRQ_UART_Rx_End
367
	bcf	PIR1, RCIF
368
 
369
	rcall	MIOS_IRQ_RestoreUserRegs
370
 
371
	rgoto	IRQ_Handler
372
 
373
;; --------------------------------------------------------------------------
374
 
375
;; --------------------------------------------------------------------------
376
;;  Rx Hlp GetCMax: get number of expected MIDI bytes depending on MIDI status
377
;;  In:	Status byte in W
378
;; --------------------------------------------------------------------------
379
IRQ_UART_Rx_Hlp_GetCMax
380
	movwf	IRQ_TMP2
381
	btfss	IRQ_TMP2, 6	; 8n, 9n, An, Bn
382
	retlw	0x02
383
 
384
IRQ_UART_Rx_Hlp_GetCMax_CDEF
385
	BRA_IFSET IRQ_TMP2, 5, ACCESS, IRQ_UART_Rx_Hlp_GetCMax_EF
386
IRQ_UART_Rx_Hlp_GetCMax_CD
387
	retlw	0x01		; Cn, Dn
388
 
389
IRQ_UART_Rx_Hlp_GetCMax_EF
390
	btfss	IRQ_TMP2, 4	; En
391
	retlw	0x02
392
 
393
	;; Fx:
394
	movf	IRQ_TMP2, W
395
	andlw	0xfe		; 0xf0 and 0xf1: expected bytes = 1
396
	xorlw	0xf0
397
	skpnz
398
	retlw	0x01
399
 
400
	movf	IRQ_TMP2, W	; 0xf2:	expected bytes = 2
401
	xorlw	0xf2
402
	skpnz
403
	retlw	0x02
404
 
405
	retlw	0x00		; others: expected bytes = 0