Log in

View Full Version : Converting PBP interrupt to ASM - 18F25K20



achilles03
- 12th February 2026, 18:10
I have a couple interrupt routines using DT's instant interrupts in PBP that I'd like to convert to asm to reduce execution time. One of the ISRs uses an external interrupt to time pulses and store the results in an array (ppm) and increments to the array index (ppm_n). Bit 4 of ppm_n is set to 0 so that ppm_n rolls over from 15 to 0. I read the array outside of the interrupt and verify the bit ppmwrite hasn't changed while reading the data, else the interrupt could have occured while reading the data.

This compiles but it appears none of the array values are updating except for index 15, which appears to be randomly assigned and never changes even though the array is cleared at startup. However it appears the index ppm_n is incrementing and ppmwrite is being toggled. Typical output from the code below looks like this (first 16 values are the ppm array, red is ppm_n, and blue is ppmwrite):

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 29184 8 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 29184 6 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 29184 5 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 29184 3 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 29184 2 0

I cobbled together the code below from some helpful posts in these forums and the datasheet. I still include "ReEnterPBP-18.bas" since I use that for another ISR that still uses PBP, but that is not included in this test code. I'm not that experienced with asm (yet), so any pointers are greatly appreciated!



pausetime var word
ppm var word[16]
ppm_n var byte
n var byte
ppmwrite var bit

T3CON = %10110000 'ppm timer: Prescaler = 8:1, Timer off; bit 5-4 is prescaler (00=1:1, 01=2:1 ... 11=8:1)

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

'----[High Priority PPM Interrupt]----------------------------------------------
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler INT0_INT, _PULSE_WIDTH, ASM, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

'clear ppm array
for n=0 to 15
ppm[n]=0
next n

ppm_n=0

@ bsf T3CON, TMR3ON ; Start timer
@ INT_ENABLE INT0_INT ; enable external (INT) interrupts

ppmloop:
pause 100
@ INT_DISABLE INT0_INT ; disble external (INT) interrupts
serout2 PIN_OUT,6,[dec ppm[0]," ",dec ppm[1]," ",dec ppm[2]," ",dec ppm[3]," ",dec ppm[4]," ",dec ppm[5]," ",dec ppm[6]," ",dec ppm[7]," ",dec ppm[8]," ",dec ppm[9]," ",dec ppm[10]," ",dec ppm[11]," ",dec ppm[12]," ",dec ppm[13]," ",dec ppm[14]," ",dec ppm[15]," ",dec ppm_n," ",dec ppmwrite,13,10]
@ INT_ENABLE INT0_INT ; enable external (INT) interrupts
goto ppmloop

PULSE_WIDTH:
ASM
movff TMR3L, _pausetime ; Read LB and store in variable 'pausetime' - also loads TMR3H into buffer
movff TMR3H, _pausetime + 1 ; Read HB from buffer
movf _ppm_n, W ; Get index value from variable 'ppm_n' for array address, store in WREG
rlncf WREG, W ; Multiply by 2 since ppm array is words (16bit)
addlw _ppm ; add base address of ppm array to offset in W
movwf FSR0 ; store the calculated address in FSR0
movf _pausetime, W ; load pausetime LB into WREG
movwf INDF0 ; move LB into ppm[ppm_n]
incf FSR0 ; move to next pointer loation for HB
movf _pausetime + 1, W ; load pausetime HB into WREG
movwf INDF0 ; move HB into ppm[ppm_n]
incf _ppm_n, f ; increment array index variable ppm_n
bcf _ppm_n, 4 ; clear bit 4 so array starts over after index 15 (b1111)
btg _ppmwrite ; toggle ppmwrite to check if interrupt occured in main program
INT_RETURN
ENDASM

achilles03
- 12th February 2026, 20:58
I might have figured it out. It looks like I wasn't loading the full pointer into FSR0 since it's a 12-bit pointer. Also I hit on the POSTINC0 option, which is nifty. I believe the ISR should be something like this (see below). I am currently assuming that word arrays in PBP are allocated with the low byte in the lower address and the high byte at the next address (I need to verify this). Any errors in the code or any suggestions to consolidate instructions are much appreciated!


PULSE_WIDTH:
ASM
movff TMR3L, _pausetime ; Read LB and store in variable 'pausetime' - also loads TMR3H into buffer
movff TMR3H, _pausetime + 1 ; Read HB from buffer
lfsr FSR0, _ppm ; Load the full 12-bit address of ppm into FSR0
movf _ppm_n, W ; Get index value from variable 'ppm_n' for array address, store in WREG
rlncf WREG, W ; Multiply by 2 since ppm array is words (16bit)
addwf FSR0L, f ; Add offset to low byte of pointer
movlw 0 ; clear WREG although carry flag is still active in STATUS REGISTER bit 0 (pretty sure that's how it works?)
addwfc FSR0H, f ; Add carry to high byte of pointer
movf _pausetime, W ; Load pausetime LB into WREG
movwf POSTINC0 ; Store pausetime LB in ppm location and automatically increment FSR0
movf _pausetime + 1, W ; Load pausetime HB into WREG
movwf INDF0 ; Store pausetime HB in ppm location
incf _ppm_n, f ; increment array index variable ppm_n
bcf _ppm_n, 4 ; clear bit 4 so array starts over after index 15 (b1111)
btg _ppmwrite ; toggle ppmwrite to check if interrupt occured in main program
INT_RETURN
ENDASM

richard
- 13th February 2026, 00:16
looks close but if the vars used in asm are not in access ram you still need to ensure the correct bank is set, it may look likes it works depending on where the compiler places your vars but its not safe

eg

movf _ppm_n, W // movf takes an 8bit address field, ppm would need to be in the currently set bank

ditto for bcf,btg etc