11/*
22 * main.c - p18clock source file
33 *
4- * Copyright (C) 2011-2023 Javier Lopez-Gomez
4+ * Copyright (C) 2011-2024 Javier Lopez-Gomez
55 *
66 * This program is free software; you can redistribute it and/or modify
77 * it under the terms of the GNU General Public License as published by
@@ -78,8 +78,8 @@ LEDMTX_END_MODULES_INIT
7878
7979LEDMTX_FRAMEBUFFER_RES (28 )
8080
81- #define CLASS_INPUT 0x00
82- #define CLASS_RTC 0x40
81+ #define CLASS_INPUT (0 << 6)
82+ #define CLASS_RTC (1 << 6)
8383
8484/// A circular buffer is used to communicate ISR code with the main loop. Data
8585/// is typically queued from an ISR and dispatched from the main loop. The 2 MSb
@@ -98,9 +98,18 @@ LEDMTX_FRAMEBUFFER_RES(28)
9898
9999DECLARE_RBUF (_mbuf , 32 )
100100
101+ // # Summary of PIC peripheral usage:
102+ // - Timer0: used by libledmtx ISR and INT0 interrupt unmasking
103+ // - Timer1: used by RTC; external 32.768 kHz clock
104+ // - Timer2/CCP1: used by CCP1 module in PWM mode (for buzzer)
105+ // - Timer3: used for keystroke repetition
106+ //
107+ // # External interrupt sources:
108+ // - INT0: user input (keystroke)
101109DEF_INTHIGH (_high_int )
102110DEF_HANDLER (SIG_TMR1 , _tmr1_handler )
103111DEF_HANDLER (SIG_INT0 , _int0_handler )
112+ DEF_HANDLER (SIG_TMR3 , _tmr3_handler )
104113END_DEF
105114
106115DEF_INTLOW (_low_int )
@@ -174,7 +183,7 @@ SIGHANDLERNAKED(_tmr1_handler)
174183 banksel __time + 3
175184 incf __time + 3 , f ; _time .mday ++
176185 cpfsgt __time + 3
177- bra @tmr1_ret
186+ bra @tmr1__ret
178187
179188 ; _time .mday overflow
180189 movlw 1
@@ -183,7 +192,7 @@ SIGHANDLERNAKED(_tmr1_handler)
183192 incf __time + 4 , f ; _time .mon ++
184193 movlw 12
185194 cpfsgt __time + 4
186- bra @tmr1_ret
195+ bra @tmr1__ret
187196
188197 ; _time .mon overflow
189198 movlw 1
@@ -202,7 +211,7 @@ SIGHANDLERNAKED(_tmr1_handler)
202211 movlw 2
203212 addwf _FSR1L , f , 0
204213
205- @tmr1_ret :
214+ @tmr1__ret :
206215 movff _PREINC1 , _FSR0L ; pop FSR0x
207216 movff _PREINC1 , _FSR0H
208217 retfie 1
@@ -211,23 +220,18 @@ SIGHANDLERNAKED(_tmr1_handler)
211220// clang-format on
212221
213222#define INT0_UNMASK_TIMEOUT 7
214- /// An INT0 interrupt is triggered externally when PORTB value changes . PORTB
215- /// is indirectly driven by push buttons, an thus requires some debouncing
216- /// logic. In particular, the INT0 handler below masks INT0 interrupts for some
217- /// time after which they are enabled again (see `_tmr0_handler`) . This amount
218- /// of time is given by `INT0_UNMASK_TIMEOUT`.
223+ /// INT0 interrupt is externally triggered on RB0/INT0 pin . RB0:RB3 is
224+ /// ( indirectly) driven by push buttons, and thus requires some debouncing
225+ /// logic. In particular, `_int0_handler` masks INT0 interrupts for some
226+ /// time after which they are enabled again. This interval is given by
227+ /// `INT0_UNMASK_TIMEOUT`.
219228static volatile unsigned char _int0_timeout ;
220229
230+ /// Queue user input (4 LSb of PORTB) in the `_mbuf` message buffer.
221231// clang-format off
222- SIGHANDLERNAKED ( _int0_handler )
232+ void I_queue_keystroke ( void ) __naked
223233{
224234 __asm
225- bcf _INTCON , 1 , 0 ; ack interrupt
226- btfsc _INTCON2 , 6 , 0 ; INTEDG0 falling edge ?
227- bra @int0_rising
228-
229- movff _FSR0H , _POSTDEC1 ; push FSR0x
230- movff _FSR0L , _POSTDEC1
231235 movlw high __mbuf ; push & _mbuf
232236 movwf _POSTDEC1 , 0
233237 movlw low __mbuf
@@ -238,17 +242,80 @@ SIGHANDLERNAKED(_int0_handler)
238242 call _rbuf_put
239243 movlw 2
240244 addwf _FSR1L , f , 0
245+ return
246+ __endasm ;
247+ }
248+ // clang-format on
249+
250+ /// Base delay for re-queueing last keystroke, in Timer3 ticks after prescaler.
251+ /// The effective delay can be adjusted by changing Timer3 prescaler. Default to
252+ /// initial repetition after 1s; all other repetitions happen every 0.125s.
253+ #define INPUT_REP_DELAY_BASE 4096
254+ #define INPUT_REP_PRESCALER_INITIAL 0x3
255+ #define INPUT_REP_PRESCALER 0x1
256+
257+ // clang-format off
258+ SIGHANDLERNAKED (_int0_handler )
259+ {
260+ __asm
261+ bcf _INTCON , 1 , 0 ; ack interrupt
262+ btfsc _INTCON2 , 6 , 0
263+ bra @int0__rising_edge
264+
265+ ;; Triggered due to falling edge , i .e . key press
266+ movff _FSR0H , _POSTDEC1 ; push FSR0x
267+ movff _FSR0L , _POSTDEC1
268+ call _I_queue_keystroke
241269 movff _PREINC1 , _FSR0L ; pop FSR0x
242270 movff _PREINC1 , _FSR0H
243-
244- @int0_rising :
271+
272+ movlw ((0xffff - INPUT_REP_DELAY_BASE ) >> 8 )
273+ movwf _TMR3H , 0
274+ movlw ((0xffff - INPUT_REP_DELAY_BASE ) & 0xff )
275+ movwf _TMR3L , 0
276+ movlw (0x83 | (INPUT_REP_PRESCALER_INITIAL << 3 ))
277+ movwf _T3CON , 0
278+ @int0__toggle_edge :
245279 bcf _INTCON , 4 , 0 ; mask INT0 interrupt
246280 btg _INTCON2 , 6 , 0 ; toggle edge
247-
248281 movlw INT0_UNMASK_TIMEOUT ; INT0 unmasking is done in _tmr0_handler
249282 banksel __int0_timeout
250283 movwf __int0_timeout
251284 retfie 1
285+
286+ ;; Triggered due to rising edge , i .e . key release
287+ @int0__rising_edge :
288+ bcf _T3CON , 0 , 0
289+ bra @int0__toggle_edge
290+ __endasm ;
291+ }
292+ // clang-format on
293+
294+ // clang-format off
295+ SIGHANDLERNAKED (_tmr3_handler )
296+ {
297+ __asm
298+ bcf _PIR2 , 1 , 0 ; TMR3IF ack interrupt
299+ btfsc _PORTB , 0 , 0 ; INT0 pin driven high , i .e . key released ; stop Timer3
300+ bra @tmr3__stop
301+
302+ movff _FSR0H , _POSTDEC1 ; push FSR0x
303+ movff _FSR0L , _POSTDEC1
304+ call _I_queue_keystroke
305+ movff _PREINC1 , _FSR0L ; pop FSR0x
306+ movff _PREINC1 , _FSR0H
307+
308+ movlw ((0xffff - INPUT_REP_DELAY_BASE ) >> 8 )
309+ movwf _TMR3H , 0
310+ movlw ((0xffff - INPUT_REP_DELAY_BASE ) & 0xff )
311+ movwf _TMR3L , 0
312+ movlw (0x83 | (INPUT_REP_PRESCALER << 3 ))
313+ movwf _T3CON , 0
314+ retfie 1
315+
316+ @tmr3__stop :
317+ bcf _T3CON , 0 , 0
318+ retfie 1
252319 __endasm ;
253320}
254321// clang-format on
@@ -265,15 +332,14 @@ SIGHANDLERNAKED(_tmr0_handler)
265332
266333 __asm
267334 btfsc _INTCON , 4 , 0 ; INT0 interrupt masked ?
268- bra @int0_unmasked
335+ bra @int0__unmasked
269336
270337 movff _BSR , _POSTDEC1 ; push BSR
271338 banksel __int0_timeout
272339 dcfsnz __int0_timeout , f ; _int0_timeout --
273340 bsf _INTCON , 4 , 0 ; _int0_timeout == 0 ? unmask INT0 interrupt
274341 movff _PREINC1 , _BSR ; pop BSR
275-
276- @int0_unmasked :
342+ @int0__unmasked :
277343 __endasm ;
278344
279345 LEDMTX_END_ISR
@@ -300,11 +366,16 @@ void uc_init(void) {
300366
301367 lm35_init ();
302368
303- /* TMR1 RTC , see p18f2550 datasheet */
369+ /* Timer1 , see p18f2550 datasheet. RTC */
304370 TMR1H = 0x80 ;
305371 TMR1L = 0x00 ;
306372 T1CON = 0x0f ;
307373 PIE1bits .TMR1IE = 1 ;
374+ IPR1bits .TMR1IP = 1 ;
375+
376+ /* Timer3 */
377+ PIE2bits .TMR3IE = 1 ;
378+ IPR2bits .TMR3IP = 1 ;
308379
309380 PR2 = CCP1_PR2 ;
310381 CCPR1L = (CCP1_R >> 2 );
0 commit comments