News:

Let's find out together what makes a PIC Tick!

Main Menu

18F05Q41 PPS

Started by joesaliba, Oct 11, 2024, 07:58 PM

Previous topic - Next topic

joesaliba

PIC18F05Q41.

I am trying to change some input pins using the PPS wizard.

However, it seems that nothing is changing, at least that what I think, or I did not understand how this PPS works.

Be easy please, first time using PPS.  ;D  ;D

I am using the following. Practically I want to change INT0 from RA2 to RA5. But it looks that it is still tied to RA2.

I have a flashing LED at 1 second interval on RA2, and INT0 is triggering when LED goes high. At least I know INT0 is being triggered.

'--------------------------------------------------------------------------------------------------
 ' Setup the program and any peripherals
 ' Input     : None
 ' Output    : None
 ' Notes     : Assign and setup INT0, USART1 and USART2 pins
 '

 Proc InitPPS()
    PP_UnLock()
    RA5PPS  = 0x5   'INT0(RA5) Input to EXT_INT
    RA4PPS  = 0x10  'TX1(RA4) Output from UART1
    U1RXPPS = 0x15  'RX1(RC5) Input to UART1
    RC2PPS  = 0x13  'TX2(RC2) Output from UART2
    U2RXPPS = 0x10  'RX2(RC0) Input to UART2
    PP_Lock()
 EndProc

 '--------------------------------------------------------------------------------------------------

 proc PP_Lock()
    INTCON0bits_GIE = 0         ' Suspend interrupts
    PPSLOCK = 0x55              ' Required sequence
    PPSLOCK = 0xAA              ' Required sequence
    PPSLOCKbits_PPSLOCKED = 0   ' Clear PPSLOCKED bit
    INTCON0bits_GIE = 1         ' Restore interrupt
 endproc

 '--------------------------------------------------------------------------------------------------

 proc PP_Unlock()
    INTCON0bits_GIE = 0         ' Suspend interrupts
    PPSLOCK = 0x55              ' Required sequence
    PPSLOCK = 0xAA              ' Required sequence
    PPSLOCKbits_PPSLOCKED = 1   ' Set PPSLOCKED bit
    INTCON0bits_GIE = 1         ' Restore interrupt
 endproc

 '==================================================================================================

joesaliba

Here is the full code as a test. I cannot understand why INT0 is being triggered while it is pulled up.



device = 18f05q41

 declare Xtal = 64
        InitPPS()
 '==================================================================================================
 '--------------------------------------------------------------------------------------------------
 ' Variables

  ' Global variables

    Dim Hz             As word  = 0         ' Variable used to hold Hz value

 '--------------------------------------------------------------------------------------------------
 ' Timing variables

    dim TMR0_REL    as word heap
    Dim Tim0        As TMR0L.word   ' Variable used to hold Timer0 ISR timing

 '==================================================================================================

 Declare Dead_Code_Remove = 1           ' Remove dead code
 Declare Optimiser_Level  = 2

 ' Setup USART1

    Declare Hserial1_Baud = 57600
    Declare HRSOut1_Pin   = PORTA.4
    Declare HRSIn1_Pin    = PORTC.5

  ' Setup USART2

    Declare Hserial2_Baud = 9600
    Declare HRSOut2_Pin   = PORTC.2
    Declare HRSIn2_Pin    = PORTC.0


 Declare Hserial1_Clear = On        ' Clear overflow automatically
 Declare Hserial2_Clear = On        ' Clear overflow automatically

 'Declare Hserial1_Parity even

 '--------------------------------------------------------------------------------------------------
 '==================================================================================================
 '************
 '* Includes *
 '************
 '>>>Includes<<<

 '===================================================================================================
 '*********************
 '* Set Pic registers *
 '*********************
 '>>>Analog, comparators etc..<<<

 CM1CON0  = %00000000       ' Turn OFF comparator 1
 CM2CON0  = %00000000       ' Turn OFF comparator 2

 ansela   = %00000000       ' Set all of PORTA to digital
 anselc   = %00000000       ' Set all of PORTC to digital

 wpua     = %00000000       ' Turn OFF Weak pull-up on PORTA
 wpuc     = %00000000       ' Turn OFF Weak pull-up on PORTC

 inlvla   = %00000000       ' PORTA set to TTL input
 inlvlC   = %00000000       ' PORTC set to TTL input

 ADCON0   = %00000000       ' Disable analog on startup
 ADCON1   = %00000000       '
 ADCON2   = %00000000       '
 ADCON3   = %00000000       '

 TRISA    = %00100000       ' Configure PORTB I/O
 TRISC    = %00100001       ' Configure PORTB I/O

 portc    = 0               ' Turn OFF PORTA
 PORTC    = 0               ' Turn OFF PORTC

 '==================================================================================================
 ' Setup peripherals

 'InitPPS()

 '--------------------------------------------------------------------------------------------------
 '==================================================================================================
 '******************
 ' DECLARE SYMBOLS *
 '******************

 Symbol OUTPS0   = T0CON0.0     ' TMR0 Output Prescaler (Divider) Select bit 0
 Symbol OUTPS1   = T0CON0.1     ' TMR0 Output Prescaler (Divider) Select bit 1
 Symbol OUTPS2   = T0CON0.2     ' TMR0 Output Prescaler (Divider) Select bit 2
 Symbol OUTPS3   = T0CON0.3     ' TMR0 Output Prescaler (Divider) Select bit 3
 Symbol MD16     = T0CON0.4     ' TMR0 8-bit/16-bit timer
 Symbol OUT      = T0CON0.5     ' TMR0 Output
 Symbol T0_NA    = T0CON0.6     ' Not in uSe
 Symbol T0_EN    = T0CON0.7     ' TMR0 Enable / Disable

 '--------------------------------------------------------------------------------------------------

 Symbol T0CKPS0  = T0CON1.0     ' TMR0 Prescaler Rate select bit 0
 Symbol T0CKPS1  = T0CON1.1     ' TMR0 Prescaler Rate select bit 1
 Symbol T0CKPS2  = T0CON1.2     ' TMR0 Prescaler Rate select bit 2
 Symbol T0CKPS3  = T0CON1.3     ' TMR0 Prescaler Rate select bit 3
 Symbol ASYNC    = T0CON1.4     ' TMR0 Input Asynchronization Enable
 Symbol CS0      = T0CON1.5     ' Timer0 Clock Source Select bit 0
 Symbol CS1      = T0CON1.6     ' Timer0 Clock Source Select bit 1
 Symbol CS2      = T0CON1.7     ' Timer0 Clock Source Select bit 2

 '--------------------------------------------------------------------------------------------------

 symbol T1_EN    = t1con.0      ' TMR1 Enable / Disable
 symbol RD16     = t1con.1      ' 16-Bit Read/Write Mode Enable
 symbol SYNC     = t1con.2      ' Timer External Clock Input Synchronization Control
 symbol T1CKPS0  = T1con.4      ' Timer Input Clock Prescaler Select bit 0
 symbol T1CKPS1  = t1con.5      ' Timer Input Clock Prescaler Select bit 1

 '--------------------------------------------------------------------------------------------------

 Symbol INT0EDG = INTCON0.0     ' External Interrupt 0 Edge Select
 Symbol INT1EDG = INTCON0.1     ' External Interrupt 1 Edge Select
 Symbol INT2EDG = INTCON0.2     ' External Interrupt 2 Edge Select
 Symbol IPEN    = INTCON0.5     ' Interrupt Priority Enable
 Symbol GIEL    = INTCON0.6     ' Global Low-Priority Interrupt Enable
 Symbol GIE     = INTCON0.7     ' Global Interrupt Enable

 '--------------------------------------------------------------------------------------------------

 symbol STAT0   = intcon1.6     ' Interrupt State Status
 symbol STAT1   = intcon1.7     ' Interrupt State Status

 '--------------------------------------------------------------------------------------------------

 symbol INT0IE  = pie1.0        ' External Interrupt 0 Interrupt Enable
 symbol INT1IE  = pie6.0        ' External Interrupt 1 Interrupt Enable
 symbol INT2IE  = pie10.0       ' External Interrupt 2 Interrupt Enable

 Symbol TMR1IE  = PIE3.4        ' TMR1 Interrupt Enable bit
 Symbol TMR0IE  = PIE3.7        ' TMR0 Interrupt Enable bit

 symbol INT0IF  = pir1.0        ' External Interrupt 0 Interrupt Flag
 symbol TMR1IF  = pir3.4        ' TMR1 Interrupt Flag
 Symbol TMR0IF  = PIR3.7        ' TMR0 Interrupt Flag bit
 symbol INT1IF  = pir6.0        ' External Interrupt 1 Interrupt Flag
 symbol INT2IF  = pie10.0       ' External Interrupt 2 Interrupt Flag

 '--------------------------------------------------------------------------------------------------
 '==================================================================================================
 ' Alias PORT pins

 symbol ICSPDAT = porta.0       ' ICSPDAT
 symbol ICSPCLK = porta.1       ' ICSPCLK
 symbol pStrobe = lata.2        ' Strobe light output
 symbol MCLR    = porta.3       ' MCLR pin
 Symbol TX1     = porta.4       ' USART transmitt to FrSky receiver
 symbol pFlow   = porta.5       ' Flow sensor input pin

 symbol RX2     = portc.0       ' USART receive from ECU
 symbol St_LED  = latc.1        ' Status LED
 symbol TX2     = portc.2       ' USART transmitt to ECU
 symbol Spare1  = portc.3       ' Spare 1
 Symbol Spare2  = portc.4       ' Spare 2
 symbol RX1     = portc.5       ' USART receive from FrSky receiver

 '==================================================================================================

 On_Interrupt Isr               ' Where to go on an Interrupt

 GoTo Over_ISR                  ' Jump over ISR

 '==================================================================================================
 '*********************
 '* INTERRUPT ROUTINE *
 '*********************

 Isr:                               ' Interrupt Service Routine
 Context Save                       ' Save registers before continue ISR

 '--------------------------------------------------------------------------------------------------
 ' External interrupt

 If INT0IF = 1 Then                 ' If we have an interrupt from INT0 then we have an input pulse
  '  Inc FueL_Pulse                  ' so increase our interrupt counter Fuel_Pulse
  '  inc Flow_Pulse                  ' increase flow pulse so to calculate flow rate
    ' high spare2
     toggle spare2

  '  If FueL_Pulse = 22 Then         ' If Fuel_Pulse equals 22 then; equivalent to 1ml
  '      Inc Tot_Flow                ' increase Tot_Flow
  '      FueL_Pulse = 0              ' Clear Fuel_Pulse
  '  EndIf                           ' End If...Then instruction

    Clear INT0IF                    ' Clear the interrupt flag now

    GoTo Int_Exit1                  ' exit interrupt routine
 EndIf                              ' End If...Then instruction

 '--------------------------------------------------------------------------------------------------

 if tmr0if = 1 then
   ' tmr0_rel = 25212
    Tim0 = TMR0_rel
    inc hz

    if hz = 50 then
        toggle st_led
        hz = 0
    endif

   ' Clear TMR0IF                    ' Reset TMR0 interrupt flag
   ' goto Int_Exit1

 endif

 '--------------------------------------------------------------------------------------------------

 Clear TMR0IF                       ' Reset TMR0 interrupt flag

 '--------------------------------------------------------------------------------------------------

 Int_Exit1:                         ' Interrupt Exit label

 Context Restore                    ' END OF INTERRUPT ROUTINE

 '==================================================================================================
 '**********************************
 '* Over Interrupt Service Routine *
 '**********************************

 Over_ISR:                          ' Over ISR label

 While GIE = 1  : GIE = 0 : Wend    ' Make sure that global interrupts are disabled
 While giel = 1 : giel = 0 :Wend    ' Make sure that peripheral interrupts are disabled

 '--------------------------------------------------------------------------------------------------
 ' External interrupt

 INT0IF  = 0            ' Clear the external 2 interrupt flag now
 INT1IF  = 0            ' Clear the external 2 interrupt flag now
 INT2IF  = 0            ' Clear the external 2 interrupt flag now

 TMR0IE  = 0            ' TMR0 External Interrupt Enable bit; 0 = Disabled, 1 = Enabled

 int0edg = 1            ' Interrupt on rising edge of the INT0 pin

 int0ie  = 1            ' External Interrupt 0 Interrupt Enable
 int1ie  = 0            ' External Interrupt 1 Interrupt Enabl
 int2ie  = 0            ' External Interrupt 2 Interrupt Enabl

 '--------------------------------------------------------------------------------------------------
 ' Timer 0

 TMR0IF  = 0            ' Clear the TMR0 Interrupt Flag bit

 T0ckps0 = 0            ' \
 T0ckps1 = 1            '   Timer0 Prescaler Select bits                      this was for a 1:4
 T0ckps2 = 0            '  /
 t0ckps3 = 0            ' /
 async   = 0            ' The input to the TMR0 counter is synchronized to Fosc/4
 cs0     = 0            ' \
 cs1     = 1            '  Timer0 Clock Source Select
 cs2     = 0            ' /

 t0_en   = 0            ' TMR0 Enabled

 TMR0IE  = 1            ' TMR0 Interrupt enabled

 T0CON0 = %10010000     ' Postscaler is 1:1. Timer0 enabled and set for 16-bit mode

 '--------------------------------------------------------------------------------------------------

 Clear TMR0H            ' Reset Timer0 to 0
 Clear TMR0L

 tmr0_rel = 25212

 Tim0 = TMR0_rel        ' Load Timer 0 offset value


 GIE  = 1               ' Enables all masked interrupts

 '==================================================================================================
 '****************
 '* Main routine *
 '****************

 Main:

 toggle pstrobe
 delayms 500
 toggle pstrobe
 delayms 500

 goto main

 '==================================================================================================

  Proc InitPPS()
    PP_UnLock()
    RA5PPS  = 0x5   'INT0(RA5) Input to EXT_INT
    RA4PPS  = 0x10  'TX1(RA4) Output from UART1
    U1RXPPS = 0x15  'RX1(RC5) Input to UART1
    RC2PPS  = 0x13  'TX2(RC2) Output from UART2
    U2RXPPS = 0x10  'RX2(RC0) Input to UART2
    PP_Lock()
 EndProc

 '--------------------------------------------------------------------------------------------------

 proc PP_Lock()
    INTCON0bits_GIE = 0         ' Suspend interrupts
    PPSLOCK = 0x55              ' Required sequence
    PPSLOCK = 0xAA              ' Required sequence
    PPSLOCKbits_PPSLOCKED = 0   ' Clear PPSLOCKED bit
    INTCON0bits_GIE = 1         ' Restore interrupt
 endproc

 '--------------------------------------------------------------------------------------------------

 proc PP_Unlock()
    INTCON0bits_GIE = 0         ' Suspend interrupts
    PPSLOCK = 0x55              ' Required sequence
    PPSLOCK = 0xAA              ' Required sequence
    PPSLOCKbits_PPSLOCKED = 1   ' Set PPSLOCKED bit
    INTCON0bits_GIE = 1         ' Restore interrupt
 endproc

 '==================================================================================================
 '--------------------------------------------------------------------------------------------------
'-------------------------------------------------------------------------------
'**** Added by Fuse Configurator ****
' Use the Fuses Tab to change these settings

Config_Start
  FEXTOSC = OFF              ;Oscillator not enable
  RSTOSC = HFINTOSC_64MHZ    ;HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:
  CLKOUTEN = OFF             ;CLKOUT function is disable
  PR1WAY = OFF               ;PRLOCKED bit can be set and cleared repeatedl
  CSWEN = ON                 ;Writing to NOSC and NDIV is allowe
  FCMEN = ON                 ;Fail-Safe Clock Monitor enable
  FCMENP = ON                ;Fail-Safe Clock Monitor enabled; timer will flag FSCMP bit and OSFIF interrupt on EXTOSC failur
  FCMENS = ON                ;Fail-Safe Clock Monitor enabled; timer will flag FSCMP bit and OSFIF interrupt on SOSC failur
  MCLRE = INTMCLR            ;If LVP=0, MCLR pin function is port defined function; If LVP=1, RE3 pin fuction is MCL
  PWRTS = PWRT_OFF           ;PWRT is disable
  MVECEN = OFF               ;Interrupt contoller does not use vector table to prioritze interrupt
  IVT1WAY = ON               ;IVTLOCKED bit can be cleared and set only onc
  LPBOREN = ON               ;Low-Power BOR enable
  BOREN = ON                 ;Brown-out Reset enabled according to SBORE
  BORV = VBOR_1P9            ;Brown-out Reset Voltage (VBOR) set to 1.9
  ZCD = OFF                  ;ZCD module is disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCO
  PPS1WAY = OFF              ;PPSLOCKED bit can be set and cleared repeatedly (subject to the unlock sequence
  STVREN = ON                ;Stack full/underflow will cause Rese
  LVP = OFF                  ;HV on MCLR/VPP must be used for programmin
  XINST = OFF                ;Extended Instruction Set and Indexed Addressing Mode disable
  WDTCPS = WDTCPS_7          ;Divider ratio 1:409
  WDTE = OFF                 ;WDT Disabled; SWDTEN is ignore
  WDTCWS = WDTCWS_7          ;window always open (100%); software control; keyed access not require
  WDTCCS = SC                ;Software Contro
  BBSIZE = BBSIZE_512        ;Boot Block size is 512 word
  BBEN = OFF                 ;Boot block disable
  SAFEN = OFF                ;SAF disable
  DEBUG = OFF                ;Background Debugger disable
  WRTB = OFF                 ;Boot Block not Write protecte
  WRTC = OFF                 ;Configuration registers not Write protecte
  WRTD = OFF                 ;Data EEPROM not Write protecte
  WRTSAF = OFF               ;SAF not Write Protecte
  WRTAPP = OFF               ;Application Block not write protecte
  CP = OFF                   ;PFM and Data EEPROM code protection disable
Config_End

 '**** End of Fuse Configurator Settings ****
 '--------------------------------------------------------------------------------------------------

joesaliba

The problem seems to be from the PPS Wizard.

Seems that at least for INT0 I solved it, I posted here.

joesaliba

But still, the mystery or lack of knowledge for this chip are non stop.

I have disabled the INT0IE, and for false inputs, IOCIE.

But still, INT0IE still triggering the interrupt.

Although it seems to work, I would like to know why. Five long evenings into this and still playing around initial configuration.


trastikata

This is how the PPS works:

1. Outputs: From the table "PPS Output Selection Table" identify the code for the corresponding peripheral device and set the desired PPS pin (RxyPPS) to that code.

Example: PortA.1 - Output Source TMR0 - code 0x23 --> RA1PPS = 0x23

Example: PortA.4 - Output Source UART1 TX - code 0x10 --> RA4PPS = 0x10

Example: PortC.2 - Output Source UART2 TX - code 0x13 --> RC2PPS = 0x13

PPS_OUT.jpg


2. Inputs: From table "PPS Input Selection Table" look for the PPS Input Register name corresponding to the desired peripheral device. Now from table "Peripheral Input Selection Register" build the code for the corresponding pin:

Example: Peripheral Interrupt 0 - PPS Input Register INT0PPS - PortA 000 - Pin5 101 --> INT0PPS = %00000101 <==> INT0PPS = 0x05

Example: Peripheral UART1 Receive - PPS Input Register U1RXPPS - PortC 010 - Pin5 101 --> U1RXPPS = %00010101 <==> U1RXPPS = 0x15

Example: Peripheral UART2 Receive - PPS Input Register U2RXPPS - PortC 010 - Pin0 000 --> U2RXPPS = %00010000 <==> U2RXPPS = 0x10

PPS_IN_REG.jpg

PPS_IN_PIN.jpg

P.s. Check again if you have the correct register values, I think one of the registers in your code might have been wrong, or at least did not correspond to the comment against it.

trastikata

Change spare1 and spare2 from PortX.Y to LatX.Y

joesaliba

Thanks a lot for the detailed explanation, it makes things clearer.

I think I got the PPS correct: -

Proc InitPPS()
    PP_UnLock()
    INT0PPS = 0x05      ' INT0(RA5) Input to EXT_INT
    RA4PPS  = 0x10      ' TX1(RA4) Output from UART1
    RC2PPS  = 0x13      ' TX2(RC2) Output from UART2
    U1RXPPS = 0x15      ' RX1(RC5) Input to UART1
    U2RXPPS = 0x10      ' RX2(RC0) Input to UART2
    PP_Lock()
 EndProc
 

What it is continue to baffle me is why I turn OFF INT0IE and still to continue going into interrupt.

While it works as it should, I don't want that it will cause any problems during normal operations, although, this peripheral interrupt will be always ON during operation.

Thank you
Kind regards

Joe

trastikata

Quote from: joesaliba on Oct 13, 2024, 06:14 AMWhat it is continue to baffle me is why I turn OFF INT0IE and still to continue going into interrupt.

Hi Joe, can't say much without seeing the code.

top204

Below is a code listing template that uses an INT2 to trigger an interrupt when its dedicated pin is brought low, on a PIC18F05Q51 device.

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' A code listing template to fire an interrupt on an INT2, when a low is detected on the pin
' Written by Les Johnson for the Positron8 compiler
'
    Device = 18F05Q41                                   ' Tell the compiler what device to compile for
    Declare Xtal = 64                                   ' Tell the compiler what frequency the device is operating at (in MHz)
    On_Hardware_Interrupt GoTo ISR_Handler              ' Point to the interrupt handler routine
'
' Setup USART1
'
    Declare HRSOut1_Pin  = PORTC.4
    Declare HRSIn1_Pin   = PORTC.5
    Declare Hserial_Baud = 9600
'
' Create any pin defines here
'
    $define INT2_Demo_Pin PORTA.5                       ' Used for the input for an INT2 trigger

'------------------------------------------------------------------------------------------------
' Defines for general Interrupts on a 18F05Q41 device
'
$define IntGlobal_Enable() INTCON0bits_GIE = 1          ' Enable global interrupts
$define IntGlobal_Disable() INTCON0bits_GIE = 0         ' Disable global interrupts
$define IntPeriph_Enable() INTCON0bits_GIEL = 1         ' Enable peripheral interrupts
$define IntPeriph_Disable() INTCON0bits_GIEL = 0        ' Disable peripheral interrupts

'------------------------------------------------------------------------------------------------
' Defines for the INT2 peripheral on a 18F05Q41 device
'
$define INT2_Flag() PIR10bits_INT2IF                    ' The INT2 flag
$define INT2_FlagClear() INT2_Flag() = 0                ' Clear the INT2 interrupt flag
$define INT2_RisingEdgeSet()  INTCON0bits_INT2EDG = 1   ' Set INT2 for a rising edge trigger
$define INT2_FallingEdgeSet() INTCON0bits_INT2EDG = 0   ' Set INT2 for a falling edge trigger
$define INT2_Enable() PIE10bits_INT2IE = 1              ' Enable the INT2 interrupt
$define INT2_Disable() PIE10bits_INT2IE = 0             ' Disable the INT2 interrupt
'
' Create any global variables here
'
    Dim tINT2_Triggered As Bit                          ' Is set if an INT2 is triggered (must be reset in the main program)
    
'------------------------------------------------------------------------------------------------
' The main program starts here
' Wait for a low on the INT2 pin and transmit a message to a serial terminal if detected
'    
Main:
    Setup()                                             ' Setup the program and any peripherals

    Do                                                  ' Create a loop
        If tINT2_Triggered = 1 Then                     ' Has an INT2 triggered?
            HRSOut1Ln "INT2 Triggered"                  ' Yes. So transmit a message to a serial terminal
            tINT2_Triggered = 0                         ' Reset the bit flag
        EndIf
    Loop                                                ' Loop forever
   
'------------------------------------------------------------------------------------------------ 
' Setup the program and any peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
    DelayMS 10                                          ' A small delay to allow things to settle
    PPS_Unlock()                                        ' Unlock the PPS (this meta-macro is in the device's .def file)
    INT2PPS = Pin_A5                                    ' Set PPS so PORTA.5 is used for INT2

    PinMode INT2_Demo_Pin, Input_PullUp                 ' Set the INT2 pin as an input with the internal pull-up resistor enabled
    INT2_FlagClear()                                    ' Clear the INT2 interrupt flag
    INT2_FallingEdgeSet()                               ' Set INT2 for a Falling Edge, so a low on the pin will trigger it
    INT2_Enable()                                       ' Enable the INT2 interrupt
    tINT2_Triggered = 0                                 ' Reset the INT2 triggered flag
   
    IntPeriph_Enable()                                  ' Enable peripheral interrupts
    IntGlobal_Enable()                                  ' Enable global interrupts
EndProc

'-----------------------------------------------------------------------------------------------------------------------------
' Interrupt handler routine
' Input     : None
' Output    : Bit flag: tINT2_Triggered is 1 if an INT2 is triggered with a low on the pin
' Notes     : Interrupts on INT2 going low
'
ISR_Handler:
    Context Save                                        ' Save any compiler system variables and any SFRs used before the interrupt code runs
  
    If INT2_Flag() = 1 Then                             ' Is it an INT2 Interrupt?
       tINT2_Triggered = 1                              ' Yes. So set the bit flag: tINT2_Triggered (must be reset in the main program)
       INT2_FlagClear()                                 ' Clear the INT2 interrupt flag
    EndIf

    Context Restore                                     ' Restore any compiler system variables and SFRs, then exit the interrupt routine
   
'-------------------------------------------------------------------------------------------------
' Setup the config fuses for internal oscillator at 64MHz, with OSC pins as general purpose I/O.
' For a PIC18F05Q41 device
'
Config_Start
    FEXTOSC = Off                                       ' External Oscillator disabled
    RSTOSC = HFINTOSC_64MHZ                             ' HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1

    CLKOUTEN = Off                                      ' CLKOUT function is disabled
    PR1WAY = Off                                        ' PRLOCKED bit can be set and cleared repeatedly
    CSWEN = On                                          ' Writing to NOSC and NDIV is allowed
    FCMEN = On                                          ' Fail-Safe Clock Monitor enabled
    FCMENP = On                                         ' Fail-Safe Clock Monitor enabled
    FCMENS = On                                         ' Fail-Safe Clock Monitor enabled

    MCLRE = EXTMCLR                                     ' MCLR pin is MCLR
    PWRTS = PWRT_OFF                                    ' PWRT is disabled
    MVECEN = Off                                        ' Interrupt controller does not use vector table
    IVT1WAY = On                                        ' IVTLOCKED bit can be cleared and set only once
    LPBOREN = On                                        ' Low-Power BOR enabled
    BOREN = On                                          ' Brown-out Reset enabled according to SBOREN

    BORV = VBOR_1P9                                     ' Brown-out Reset Voltage (VBOR) set to 1.9V
    ZCD = Off                                           ' ZCD module is disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
    PPS1WAY = Off                                       ' PPSLOCKED bit can be set and cleared repeatedly (subject to the unlock sequence)
    STVREN = On                                         ' Stack full/underflow will cause Reset
    LVP = Off                                           ' HV on MCLR/VPP must be used for programming
    XINST = Off                                         ' Extended Instruction Set disabled

    WDTCPS = WDTCPS_17                                  ' WDT Period Divider ratio 1:4194304
    WDTE = Off                                          ' WDT disabled

    WDTCWS = WDTCWS_7                                   ' WDT window always open (100%); software control; keyed access not required
    WDTCCS = SC                                         ' WDT input clock Software Control

    BBSIZE = BBSIZE_512                                 ' Boot Block size is 512 words
    BBEN = Off                                          ' Boot block disabled
    SAFEN = Off                                         ' SAF disabled
    Debug = Off                                         ' Background Debugger disabled

    WRTB = Off                                          ' Boot Block not Write protected
    WRTC = Off                                          ' Configuration registers not Write protected
    WRTD = Off                                          ' Data EEPROM not Write protected
    WRTSAF = Off                                        ' SAF not Write Protected
    WRTAPP = Off                                        ' Application Block not write protected

    Cp = Off                                            ' PFM and Data EEPROM code protection disabled
Config_End

I have taken the general mechanism and $defines and setup from a project I did that used the INT2 pin as the Aux pin trigger from an E220 tranceiver, and it also used the PIC18F05Q41 device. To use an INT0 or INT1 will be a simple task of creating and changing the meta-macros that the code listing is using for INT2. The SFRs and bits are found in the device's datasheet, and looking in the device's .def file for the meta-macro names supported by the compiler. The compiler .def files can be found at: "C:\Program Files (x86)\ProtonIDE\PDS\Includes\Defs\"

The PPS_Unlock is already created in the device's .def file as a meta-macro.

See how the more logic code listing layout makes the code a lot easier to follow and read, and more importantly, change or add-to when required?

Dompie

@trastikata an excelent explanation in one message!!!!!

Johan

JohnB

#10
This is the code that the PPS Wizard produces which I assume is wrong

Proc InitPPS()
PPS_UnLock()
RA5PPS = 0x5    'INT0(RA5) Input to EXT_INT
RA4PPS = 0x10   'TX1(RA4) Output from UART1
U1RXPPS = 0x15  'RX1(RC5) Input to UART1
RC2PPS = 0x13   'TX2(RC2) Output from UART2
U2RXPPS = 0x10  'RX2(RC0) Input to UART2
PPS_Lock()
EndProc

I am assuming the PPS wizard is incorrect and that it should be INT0PPS not RA5PPS - I will look into why it is picking the wrong register whereas the other input registers are correct.

Edit: I have found the issue, I was defaulting to the wrong value when there is no RemapTo in the Microchip XML files.  Will issue an update with the next release of Positron Studio.  PM me if you need the update sooner.


JohnB

joesaliba

Thanks John.

joesaliba

Les,

I will try your code.

Regards

Joe

top204

#13
I've just tried the code template I posted, on a real PIC18F05Q41 device and it works well. However, remember, if you are using a button for the INTx trigger, it will generate multiple interrupt events because of switch bounce and while held down, but it will show that the INT is firing when the pin is brought low, and with a button it will fire again when it is released because of contact bounce.

What you can do is disable the INT when it fires in the interrupt using the INT2_Disable() macro, then re-enable it again when it is required in the main program using the INT2_Enable() macro, but first clearing the interrupt flag with the INT2_FlagClear() macro. This will help with debounce and multiple interrupt events, but not stop it completely with a button.

Below are the preprocessor meta-macros I have created for INT0 and INT1 on a PIC18F05Q41 device, that can be used to change the code to use them instead of INT2, but they all do the same thing and the device has PPS, so any one of them will work with the same pin:

'------------------------------------------------------------------------------------------------
' Defines for the INT0 peripheral on a PIC18F05Q41 device
'
$define INT0_Flag() PIR1bits_INT0IF                     ' The INT0 flag
$define INT0_FlagClear() INT0_Flag() = 0                ' Clear the INT0 interrupt flag
$define INT0_RisingEdgeSet()  INTCON0bits_INT0EDG = 1   ' Set INT0 for a rising edge trigger
$define INT0_FallingEdgeSet() INTCON0bits_INT0EDG = 0   ' Set INT0 for a falling edge trigger
$define INT0_Enable() PIE1bits_INT0IE = 1               ' Enable the INT0 interrupt
$define INT0_Disable() PIE1bits_INT0IE = 0              ' Disable the INT0 interrupt

'------------------------------------------------------------------------------------------------
' Defines for the INT1 peripheral on a PIC18F05Q41 device
'
$define INT1_Flag() PIR6bits_INT1IF                     ' The INT1 flag
$define INT1_FlagClear() INT1_Flag() = 0                ' Clear the INT1 interrupt flag
$define INT1_RisingEdgeSet()  INTCON0bits_INT1EDG = 1   ' Set INT1 for a rising edge trigger
$define INT1_FallingEdgeSet() INTCON0bits_INT1EDG = 0   ' Set INT1 for a falling edge trigger
$define INT1_Enable() PIE6bits_INT1IE = 1               ' Enable the INT1 interrupt
$define INT1_Disable() PIE6bits_INT1IE = 0              ' Disable the INT1 interrupt

Add these meta-macros above the existing INT2 meta-macros in the code listing, and then you have a choice of INT0, INT1 or INT2.

joesaliba

Thanks Les,

When You posted last post I had just finished adding other INT's as yours:)

Am I correct to say that INTCON0bits_GIEL refers to Low Priority Interrupts and not Peripheral interrupts?

With your example, the code is more clear to follow. It worked exactly like the code I wrote. I should begin writing code like yours.

I found out what is causing INT0 to trigger even if INT0 is Disabled.


I am using a Timer0 to interrupt when it overflows.

If I am setting the timer correctly for an overflow interrupt,

T0CON0 = %10010000     ' Postscaler is 1:1. Timer0 enabled and set for 16-bit mode
 T0CON1 = %01000010     ' Prescaler Rate Select 1:4 and Timer0 Clock Source Select Fosc/4

Then I set the Timer 0 interrupt bit to enable TMR0 interrupt: -

TMR0IE = 1             ' TMR0 Interrupt Enabled
Timer offset value for 100Hz is 25212.

It is the TMR0IE that is causing the INT0 to interrupt even if INT0 is disabled.

I want that INT0 will be always ON, so this is not a problem, but am afraid that TMR0IE will interfere with INT0.

I also tried using INT1 just to check if there is something related between Timer 0 and INT0.

Result? The same. If TMR0IE is set, then regardless of INT# if set or clear, INT will still trigger. Definitely, I am doing something wrong which I cannot find it.

Kind regards

Joe



trastikata

Quote from: joesaliba on Oct 14, 2024, 07:09 PMDefinitely, I am doing something wrong which I cannot find it.

In a PIC the interrupt flag is set regardless of whether the interrupt is enabled or not, therefore when the TMR0 fires the interrupt vector, the first thing being checked in your code is INT0IF.

Since it has been set, obviously, by the external pin, the code within the If INT0IF ... condition is being executed and jump to the exit, which will mess the TMR0 interrupt.

With multiple interrupts being dynamically enabled and disabled and single vector interrupt, it is not sufficient to check only the interrupt flag but you will have to check if the interrupt has been enabled as well. Simple And in the If statement will do ;) .

QuoteIf INT0IF = 1 And INT0IE = 1 Then
...



top204

#16
The GIEL bit of the INTCON0 SFR is rather confusing when read from the datasheet, because it refers to Low Prioriry Interrupts first, then mentions unmasked interrupts.

If the IPEN bit of the INTCON0 SFR is 0, the GIEL bit enables peripheral interrupts (as they used to be called) to trigger a global interrupt. i.e. Timer1, USARTs, INTs etc... And does not enable Low Prioriry interrupts.

So the GIEL manipulation in the code listing is to allow the INT peripheral to fire an interrupt.

Bit-6 of the INTCON or INTCON0 SFR used to be also named the PEIE bit, which was much clearer to understand if only high priority interrupts were used, because it enabled Peripheral Interrupts, but that bit name has now been removed from newer devices. Why??

Also, as trastikata stated, with some peripheral interrupts, it is better to check if the EN bit is also set before operating its code.

When it is required, I always use something like:

If Timer0_Enable() = 1 Then
    If Timer0_Flag() = 1 Then
        ' Do the Timer0 interrupt code here
    EndIf
EndIf


Where the Timer0_Flag and Timer0_Enable meta-macros have previously been defined. It also uses a direct comparison method and does not bring the comparison stack into play, so saving a tiny bit of time and code space.

joesaliba

Thank you so much Les and Trastikata.

I did not know that if INT# is disabled, the flag is still set. That makes more sense now. I was looking on the web to see if someone had similar problem, and now it clarifies why I have seen so much interrupts examples that uses the method both of you described, i.e.: -

If INT0IF = 1 And INT0IE = 1 Then

I can finally continue with my project.

Kind regards

Joe

top204

You have misunderstood Joe.

With an INTx peripheral, the flag will not set if the INTx peripheral is not enabled.

That is why it is not always required to test the EN and the Flag within an interrupt, it is mainly required with timers.

For example... With a Timer it will set its flag when the timer overflows, and if an interrupt routine is used that has a place for the Timer, but the Timer is disabled in the main program, it will still perform the code for it when something else triggers an interrupt and it sees the flag set.


joesaliba

Thanks Les. Now I have the full picture.

Apologies if it took me so long to understand it.

Regards

Joe