PDA

View Full Version : Simple way to adjust interrupt speed in DT_INTS-14 ?



CuriousOne
- 8th January 2015, 11:21
Hello.

I'm using this sample code on 16F628A:



;----[16F628A Hardware Configuration]-------------------------------------------
#IF __PROCESSOR__ = "16F628A"
#DEFINE MCU_FOUND 1
#CONFIG
cfg = _INTOSC_OSC_NOCLKOUT ; INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN
cfg&= _WDT_ON ; WDT enabled
cfg&= _PWRTE_OFF ; PWRT disabled
cfg&= _MCLRE_OFF ; RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD
cfg&= _BODEN_ON ; BOD enabled
cfg&= _LVP_OFF ; RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming
cfg&= DATA_CP_OFF ; Data memory code protection off
cfg&= _CP_OFF ; Code protection off
__CONFIG cfg

#ENDCONFIG

#ENDIF

;----[Verify Configs have been specified for Selected Processor]----------------
; Note: Only include this routine once, after all #CONFIG blocks
#IFNDEF MCU_FOUND
#ERROR "No CONFIGs found for [" + __PROCESSOR__ +"]"
#ENDIF

PCON=%00001010 'set int osc to 4mhz

LED1 VAR PORTB.1
wsave2 var byte $120 SYSTEM
wsave1 VAR BYTE $A0 SYSTEM
wsave VAR BYTE $20 SYSTEM

INCLUDE "DT_INTS-14.bas" ' Base Interrupt System
INCLUDE "ReEnterPBP.bas" ' Include if using PBP interrupts

ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, _ToggleLED1, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

T1CON = $01 ; Prescaler = 0, TMR1ON
@ INT_ENABLE TMR1_INT ; enable Timer 1 interrupts

Main:
PAUSE 1
GOTO Main

'---[TMR1 - interrupt handler]--------------------------------------------------
ToggleLED1:
TOGGLE LED1
@ INT_RETURN


By changing T1CON=$01 now I have about 7hz interrupt speed, but I want to make it faster.

Darrel's page lists another code for changing interrupt speeds, which is complex and I don't need that much code space to be wasted. So is it possible to modify above code, to make interrupt work say at 20, 50, 400hz speed?

If I understand properly, specific values are to be written to TMR1L and TMR1H registers each time interrupt occurs, right? but how to do that and which values?

HenrikOlsson
- 8th January 2015, 11:39
TMR1 generates an interrupt when it overflows from $FFFF to $0000.
If your clock is 4MHz and TMR1 prescaler is 1:1 then TMR1 will "tick" at 1MHz, ie it'll increment one count every us.
If you just let it freerun it'll interrupt once every 65536us or 0.065536s or 15.25Hz. Since you're toggling the LED in your ISR you get ~7.6Hz.

If you want it to interrupt at 400Hz (2500us) you need preload TMR1 to 65536-2500=63036 so that it takes 2500 "ticks" instead of 65536 before it interrupts. And yes, you need to do it every time or it will just start over from 0. If you want to be accurate you ADD the preload value TO the current value of TMR1 as that will account for any interrupt latency. If you want to be even more accurate you need to add a couple of counts TO the preload value since it actually takes some time to execute the instructions that preloads the timer while it's stopped.


Temp VAR WORD
ToggleLED1:
T1CON.0 = 0
Temp.HighWord = TMR1H ' Get current value of TMR1
Temp.LowWord = TMR1L
Temp = Temp + Preload ' Add the preload, this will account for the interrupt latency
T1CON.0 = 1 ' Restart TMR1
TOGGEL LED1
@ INT_RETURN

If a periodic interrupt is what you want then TMR2 might be a better option. It counts up from 0 and interrupts when its value equals PR2 and then automatically starts over from 0. No need for manually preloading but it's only 8 bits wide with a limited prescaler.

/Henrik.

richard
- 8th January 2015, 11:42
you will find links on this forum for a utility called PicMultiCalc it will assist you in finding tmr1h/l values for your chosen int rate.
then in your isr
stop the timer
load the new tmrl/h values
restart the timer

easy as pi

CuriousOne
- 8th January 2015, 12:01
Thanks, added the values, and used scope and "try and see" method to find required values :)