PDA

View Full Version : SOLVED: Post #11 - IOC on negative edge sometimes triggers twice on single press



Demon
- 6th September 2024, 01:56
Any idea what's going on?

I removed the KHz variable and kept only MHz, but it still does the same thing:

- sometimes it triggers once,
- sometimes it triggers twice (IOC on positive edge is OFF),
- no pattern (that I could see),

16F18877

https://youtu.be/05fT5TKjUOs?si=-dj0n3NCdI6twxCl


@ ERRORLEVEL -306 ; turn off crossing page boundary message
include "C:\PBP Includes\DT_INTS-14_16F1885x-7x.bas"
include "C:\PBP Includes\ReEnterPBP.bas"

ASM
INT_LIST macro ;IntSource, Label, Type, ResetFlag?
INT_Handler IOC_INT, _IOCinterrupts, PBP, yes ;IOCC.3
endm
INT_CREATE ;Creates the interrupt processor
ENDASM

#CONFIG
__config _CONFIG1, _FEXTOSC_OFF & _RSTOSC_HFINT32 & _CLKOUTEN_OFF & _CSWEN_OFF & _FCMEN_ON
__config _CONFIG2, _MCLRE_ON & _PWRTE_OFF & _LPBOREN_OFF & _BOREN_ON & _BORV_LO & _ZCD_OFF & _PPS1WAY_OFF & _STVREN_ON & _DEBUG_OFF
__config _CONFIG3, _WDTCPS_WDTCPS_11 & _WDTE_ON & _WDTCWS_WDTCWS_7 & _WDTCCS_LFINTOSC
__config _CONFIG4, _WRT_OFF & _SCANE_available & _LVP_OFF
__config _CONFIG5, _CP_OFF & _CPD_OFF
#ENDCONFIG

DEFINE OSC 32

' LCD is used for debugging

DEFINE LCD_DREG PORTD ' Set LCD data port
DEFINE LCD_DBIT 4 ' Set starting data bit
DEFINE LCD_RSREG PORTD ' Set LCD register select port
DEFINE LCD_RSBIT 1 ' Set LCD register select bit
DEFINE LCD_EREG PORTD ' Set LCD enable port
DEFINE LCD_EBIT 0 ' Set LCD enable bit
DEFINE LCD_BITS 4 ' Set LCD bus size
DEFINE LCD_LINES 4 ' Set number of lines on LCD
DEFINE LCD_COM1MANDUS 1000 ' Set COM1mand delay time in microseconds
DEFINE LCD_DATAUS 50 ' Set data delay time in microseconds

' CCPx is used to control Contrast and Blacklight on LCD

define CCP3_REG PORTD ' PWM Pulse out to LCD contrast
DEFINE CCP3_BIT 2 ' 2N2907 PNP with 1K on base
define CCP4_REG PORTD ' PWM Pulse out to LCD backlight
DEFINE CCP4_BIT 3 ' 2N2222A NPN with 1K on base

IOCBP = %00000000 ;IOC Interrupt, Positive Edge, low-to-high
IOCBN = %00000100 ;IOC Interrupt, Negative Edge, from high-to-low

WPUB = %00000100 ; Pull-up resistor on pin B2

' PPS is used to move CCP functions to other pins

PinD2 CON $1A ' Datasheet table 13-2
PinD3 CON $1B
CCP3PPS = PinD2 ' CCP3 Peripheral input selection
CCP4PPS = PinD3 ' CCP4 Peripheral input selection

PeripheralCCP3 CON $0B ' Datasheet table 13-3
PeripheralCCP4 CON $0C
RD2PPS = PeripheralCCP3 ' Pin D2 output source selection
RD3PPS = PeripheralCCP4 ' Pin D3 output source selection
RB0PPS = 0 ' Disable CCP3 (moved to D2)
RB5PPS = 0 ' Disable CCP4 (moved to D3)

ANSELA = %00000000 ' No analog operations
ANSELB = %00000000
ANSELC = %00000000
ANSELD = %00000000
ANSELE = %00000000

TRISA = %00000000
TRISB = %00000100 ' Only pin B2 is Input
TRISC = %00000000
TRISD = %00000000
TRISE = %00000000

IOC_NAV2_Swap_flag var IOCBF.2 ' IOC flag on pin B2 change

NAV2_Swap_ON VAR BYTE

NAV2_MHz_Standby VAr BYTE
NAV2_MHz_Active VAr BYTE

SwapFrequency var WORD ' Temporary variable used for Swapping frequencies

Pause 500 ' Let PIC and LCD stabilize

NAV2_MHz_Standby = 111 : NAV2_MHz_Active = 222

HPWM 3,250,1953 ' Contrast
HPWM 4,150,1953 ' Backlight

IOCBF = %00000000 ' Clear all interrupt flags

NAV2_Swap_ON = 0 ' Clear Swap button is waiting for processing

goto Start

;--- Subroutines ---------------------------------------------------------------

IOCinterrupts:


if IOC_NAV2_Swap_flag = 1 then ' Swap frequencies
NAV2_Swap_ON = 1
IOC_NAV2_Swap_flag = 0
endif
@ INT_RETURN

Start:
LCDOUT $FE, 1 : Pauseus 1
LCDOUT $FE, $80, "COM/NAV ENCODER TEST" : Pauseus 1

@ INT_ENABLE IOC_INT
PAUSE 500

Mainloop:
if NAV2_Swap_ON = 1 then ' Swap button has been pressed
SwapFrequency = NAV2_MHz_Standby ' Swap MHz frequency
NAV2_MHz_Standby = NAV2_MHz_Active
NAV2_MHz_Active = SwapFrequency

NAV2_Swap_ON = 0 ' Turn OFF swap flag
endif

LCDOUT $FE, $D4, "NAV2:", dec3 NAV2_MHz_Standby,_
" ", dec3 NAV2_MHz_Active : Pauseus 1

goto mainloop
end



Gutted code and left only LCD for my observations.

HenrikOlsson
- 6th September 2024, 05:36
I'm not sure what I'm looking at in the video but inadequate debounce on the input would be my number one guess.

I believe DT_Ints resets the interrupt request flag on exit of ISR (@ INT_RETURN) so to test you could insert a simple PAUSE 5 or whatever before exiting.

richard
- 6th September 2024, 09:15
catching key presses with isr's is never a good look

a simple polling debounce is way more effective

if you are just using plain pwm for mccp ports
what is this about ?
'PinD2 CON $1A ' Datasheet table 13-2
'PinD3 CON $1B
'CCP3PPS = PinD2 ' CCP3 Peripheral input selection
'CCP4PPS = PinD3 ' CCP4 Peripheral input selection


like this (untested)


@ ERRORLEVEL -306 ; turn off crossing page boundary message
'include "C:\PBP Includes\DT_INTS-14_16F1885x-7x.bas"
'include "C:\PBP Includes\ReEnterPBP.bas"


'ASM
'INT_LIST macro ;IntSource, Label, Type, ResetFlag?
' INT_Handler IOC_INT, _IOCinterrupts, PBP, yes ;IOCC.3
' endm
' INT_CREATE ;Creates the interrupt processor
'ENDASM


#CONFIG
__config _CONFIG1, _FEXTOSC_OFF & _RSTOSC_HFINT32 & _CLKOUTEN_OFF & _CSWEN_OFF & _FCMEN_ON
__config _CONFIG2, _MCLRE_ON & _PWRTE_OFF & _LPBOREN_OFF & _BOREN_ON & _BORV_LO & _ZCD_OFF & _PPS1WAY_OFF & _STVREN_ON & _DEBUG_OFF
__config _CONFIG3, _WDTCPS_WDTCPS_11 & _WDTE_ON & _WDTCWS_WDTCWS_7 & _WDTCCS_LFINTOSC
__config _CONFIG4, _WRT_OFF & _SCANE_available & _LVP_OFF
__config _CONFIG5, _CP_OFF & _CPD_OFF
#ENDCONFIG


DEFINE OSC 32


' LCD is used for debugging

DEFINE LCD_DREG PORTD ' Set LCD data port
DEFINE LCD_DBIT 4 ' Set starting data bit
DEFINE LCD_RSREG PORTD ' Set LCD register select port
DEFINE LCD_RSBIT 1 ' Set LCD register select bit
DEFINE LCD_EREG PORTD ' Set LCD enable port
DEFINE LCD_EBIT 0 ' Set LCD enable bit
DEFINE LCD_BITS 4 ' Set LCD bus size
DEFINE LCD_LINES 4 ' Set number of lines on LCD
DEFINE LCD_COM1MANDUS 1000 ' Set COM1mand delay time in microseconds
DEFINE LCD_DATAUS 50 ' Set data delay time in microseconds


' CCPx is used to control Contrast and Blacklight on LCD


define CCP3_REG PORTD ' PWM Pulse out to LCD contrast
DEFINE CCP3_BIT 2 ' 2N2907 PNP with 1K on base
define CCP4_REG PORTD ' PWM Pulse out to LCD backlight
DEFINE CCP4_BIT 3 ' 2N2222A NPN with 1K on base


'IOCBP = %00000000 ;IOC Interrupt, Positive Edge, low-to-high
'IOCBN = %00000100 ;IOC Interrupt, Negative Edge, from high-to-low


WPUB = %00000100 ; Pull-up resistor on pin B2


' PPS is used to move CCP functions to other pins


'PinD2 CON $1A ' Datasheet table 13-2
'PinD3 CON $1B
'CCP3PPS = PinD2 ' CCP3 Peripheral input selection
'CCP4PPS = PinD3 ' CCP4 Peripheral input selection


PeripheralCCP3 CON $0B ' Datasheet table 13-3
PeripheralCCP4 CON $0C
RD2PPS = PeripheralCCP3 ' Pin D2 output source selection
RD3PPS = PeripheralCCP4 ' Pin D3 output source selection
RB0PPS = 0 ' Disable CCP3 (moved to D2)
RB5PPS = 0 ' Disable CCP4 (moved to D3)


ANSELA = %00000000 ' No analog operations
ANSELB = %00000000
ANSELC = %00000000
ANSELD = %00000000
ANSELE = %00000000


TRISA = %00000000
TRISB = %00000100 ' Only pin B2 is Input
TRISC = %00000000
TRISD = %00000000
TRISE = %00000000


'IOC_NAV2_Swap_flag var IOCBF.2 ' IOC flag on pin B2 change
NAV2_Swap_Pin var PORT.2
NAV2_Swap_ON VAR BYTE
NAV2_Swap_Debounce var WORD
NAV2_MHz_Standby VAr BYTE
NAV2_MHz_Active VAr BYTE


SwapFrequency var WORD ' Temporary variable used for Swapping frequencies


Pause 500 ' Let PIC and LCD stabilize


NAV2_MHz_Standby = 111 : NAV2_MHz_Active = 222

HPWM 3,250,1953 ' Contrast
HPWM 4,150,1953 ' Backlight


' IOCBF = %00000000 ' Clear all interrupt flags

NAV2_Swap_ON = 0 ' Clear Swap button is waiting for processing
NAV2_Swap_Debounce =0
goto Start


;--- Subroutines ---------------------------------------------------------------


'IOCinterrupts:




' if IOC_NAV2_Swap_flag = 1 then ' Swap frequencies
' NAV2_Swap_ON = 1
' IOC_NAV2_Swap_flag = 0
' endif
'@ INT_RETURN


ProcessEncoder:


Start:

LCDOUT $FE, 1 : Pauseus 1
LCDOUT $FE, $80, "COM/NAV ENCODER TEST" : Pauseus 1

'@ INT_ENABLE IOC_INT
' PAUSE 500


Mainloop:
NAV2_Swap_Debounce = (NAV2_Swap_Debounce<<1) + NAV2_Swap_Pin
if NAV2_Swap_Debounce == $f then ' Swap button has been debounced and found to have been pressed and now released
SwapFrequency = NAV2_MHz_Standby ' Swap MHz frequency
NAV2_MHz_Standby = NAV2_MHz_Active
NAV2_MHz_Active = SwapFrequency


' NAV2_Swap_ON = 0 ' Turn OFF swap flag
endif

LCDOUT $FE, $D4, "NAV2:", dec3 NAV2_MHz_Standby,_
" ", dec3 NAV2_MHz_Active : Pauseus 1


goto mainloop
end

Demon
- 6th September 2024, 09:28
I'm not sure what I'm looking at in the video but inadequate debounce on the input would be my number one guess....

The graphs show the signal at the switch and PIC pins; to confirm the absence of bounce on the signal.

The LCD in the foreground shows the frequencies being swapped back and forth.



... I believe DT_Ints resets the interrupt request flag on exit of ISR (@ INT_RETURN)...

- I changed checking IOCBF.2 to checking Port pin; no change, random double-processing.
- I changed clearing IOCBF.2 = 0 to IOCBF = %00000000; no change, random double-processing.
- I added an IOC counter, Interrupt is definitely entered TWICE when double-processing.



... to test you could insert a simple PAUSE 5 or whatever before exiting.

I'm not sure what this would test. But I still get double-processing with PAUSE 5 in ISR.


I'm definitely missing proper flag reset out of ISR.

Demon
- 6th September 2024, 09:36
catching key presses with isr's is never a good look

a simple polling debounce is way more effective ...

But isn't IOC specifically designed to handle this? The 16F18877 has IOC across all pins...?



...what is this about ?
'PinD2 CON $1A ' Datasheet table 13-2
'PinD3 CON $1B
'CCP3PPS = PinD2 ' CCP3 Peripheral input selection
'CCP4PPS = PinD3 ' CCP4 Peripheral input selection
...

It's PWM on Contrast and Backlight on LCD. I have at least 4 LCDs. That would equate to 8 pots to control contrast and backlight.

I prefer a HPW solution, that way I can control all LCDs with 1 dual encoder; 1 shaft for contrast, 1 shaft for backlight, and SPST-switch can toggle across each LCD.


I'm still digesting the code.

Demon
- 6th September 2024, 09:42
Look what I just found on p. 208:


The INLVLB register (Register 12-8) controls the input
voltage threshold for each of the available PORTB input
pins. A selection between the Schmitt Trigger CMOS or
the TTL Compatible thresholds is available. The input
threshold is important in determining the value of a read
of the PORTB register and also the level at which an
interrupt-on-change occurs, if that feature is enabled.

EDIT: Hmmm, p.212 has 1 as default on port B (ST input).

Ill try with INLVLB = %00000100, but I doubt it'll make a difference.


EDIT SOME MORE: Nope, still random double-processing.

richard
- 6th September 2024, 11:07
But isn't IOC specifically designed to handle this? The 16F18877 has IOC across all pins...?

no,
why would you ever need microsecond responses to a key press ?
how are you determining the key was held for a reasonable time and not just noise ?
how are you determining the key was released ?
how are you determining the key was in fact repressed?

isr for an emergency stop switch or a limit switch on fast moving machinery that needs protection sure , a human interface device
i don't think so.



It's PWM on Contrast and Backlight on LCD. I have at least 4 LCDs. That would equate to 8 pots to control contrast and backlight.
none of which require an i/p pin


The graphs show the signal at the switch and PIC pins; to confirm the absence of bounce on the signal.
if the sample rate of your digital oscilloscope is too low you will never see the bounces, the effective bandwidth is far to low
what you are viewing is an interpretation not reality. use the highest sample rate/resolution in single channel mode to get the best possible view

richard
- 6th September 2024, 11:23
9747

see the white negative going spikes that indicate when samples are taken by my routine,

the spikes are 1 uS in width , on my rigol 100MHz 1Gs/S oscilloscope @ 0.5mS/div they are not accurately rendered nether are all that are in scope always even visible . saleae to the rescue at max res.
digital tools need to be understood and taken with a pinch of salt

i should point out @100uS/div all are visible but the display window is too small to see what i was looking for

tumbleweed
- 6th September 2024, 13:57
just a comment...

If you look at your code in post #1, the only thing the ISR does is set a flag that's read in your mainline code (NAV2_Swap_ON = 1).
You could drop all the interrupt stuff and just poll the IOCIF flag (or the individual flag bit) in the main loop with the same effect, much as Richard's done.

The interrupt flag bits get set even if interrupts aren't enabled.

HenrikOlsson
- 6th September 2024, 16:42
Yes!
Quite often I see comments like don't do any work in the ISR, just set a flag and do the work in the main loop.

That's totally fine if what the ISR is doing is, for example, putting UART characters into a buffer and when CR is received sets a flag. When the main loop sees that flag it processes the message.

But simply setting a flag that there's been an interrupt and then poll that flag in the main loop is...well of not much use and a waste resources. Just poll the interrupt flag (and remember to reset it) instead.

In general, the ISR should be kepts short and tight (no blocking commands like PAUSE etc (again, in general)) but if you're not actually DOING anytning in the ISR then you might not need an interrupt to begin with.

Sorry for the rant ;-)

Demon
- 6th September 2024, 20:13
...But simply setting a flag that there's been an interrupt and then poll that flag in the main loop is...well of not much use and a waste resources. Just poll the interrupt flag (and remember to reset it) instead....

It's not a rant if you guys help me. I didn't know that about the IOC flag being set regardless (I've done a lot of reading on Interrupt - remembering what I read is something else entirely).

Richard did find the real problem. I was using 0.01uF for the encoder and the switch. This is what it looked like at higher resolution:

https://i.imgur.com/E91rDnC.jpeg


Then I changed for 0.1uF:

https://i.imgur.com/PmcNPA9.jpeg

Just a blip on this one:

https://i.imgur.com/L6cjPQh.jpeg


But I have to use 0.01uF on the encoder or else they don't act properly.


So now I have to decide if I keep the 16F18877 and poll the IOC flag, or go back to the 16F1937 and poll the Port pin. I'm leaning towards the 16F1937 cause it costs a bit less.

Demon
- 7th September 2024, 08:49
Turns out I don't really have a choice to stay with the 16F18877:

- 16F1937 has TTL General Purpose pins.
- 16F18877 has TTL and ST General Purpose pins.

74HC14 only costs $0.09 at JLCPCB, but there's other costs associated with assembly, as well as lost real-estate on the PCB:
https://jlcpcb.com/parts/componentSearch?searchTxt=C97666

tumbleweed
- 7th September 2024, 15:10
- 16F1937 has TTL General Purpose pins.
- 16F18877 has TTL and ST General Purpose pins.

You should be able to set the pin type in the 16F18877 to either ST or TTL to match the 1937 type if that's what you're after.
I don't think your 'INLVLB = %00000100' statement changed anything for RB2... it's still the default setting.