Symbols Code for PIC18 PORTB Interrupt management

Discussion on projects that are created by users and posted on mikroElektronika website.
Post Reply
Author
Message
Megahurts
Posts: 900
Joined: 01 Oct 2009 22:48
Location: Rocky Mountains, USA.

Symbols Code for PIC18 PORTB Interrupt management

#1 Post by Megahurts » 22 Oct 2010 03:15

Hi everyone,

Here is the zipped package of my interrupt symbol controls as a MB project plus this one includes a remark section "Controls quick list" for easy print out and look-up of the symbol controls in both file download and CODE LISTING window below.

All files in Zip archive are enclosed in a single folder for easy extraction and project file grouping.

Use MB project file as a starting template for your project code or copy/paste selection into your existing project code at proper locations or create as a module or library include file.

* The CODE LISTING below contains Important updated edits to this original ZIP file package. Please copy/paste it into MB project file and save it. Any future updates will be reflected there.

* Updated full MB Pro Project Template files, with successful compiled files Zip Package as of: 23/10/2010
FILE PACKAGE DOWNLOAD LINK
INTERRUPT_SYMBOLS.zip
MB Pro V4.1 compiler version
(24.07 KiB) Downloaded 319 times

USAGE:
I would like to share some code I've done as an example for managing the PIC18 PORTB interrupts by using MB's "SYMBOL" feature. This helped me manage some complex interrupt handling on a recent project and hope it can help others as well.

Basically, I've assigned an alias to the most common interrupt SFR bit manipulations that one needs to do in order to implement PORTB interrupt routines in your project code.

These control aliases contain functions for Reading (test or check bit), Clearing (disable or flag bit) and Setting (enable or flag bit) for Hard Ware (H/W) SFR Bits and both Hard Ware and Soft Ware (S/W) FLAGS.

There are NO aliases to set any H/W Flag registers as not needed, at least I haven't thought of any reason to have them yet (If you do, please post reason why. I'd be curious for usage reason).

Three (3) variables are defined also and needed for this code: PORTB_BUFFER [Byte] for holding last state of inputs, and FLAGSB [Byte] for using Bits 4,5,6,7 as Flags for which pin changed with the RBIE Interrupt.
FLAGSB Bits 0,1,2 are used for S/W flagging external interrupts on RB0-(INT0), RB1-(INT1) and RB2-(INT2).
FLAGSB Bit 3 is used for a S/W Flag RBCHG_FLAG now, in case your coding practice for Interrupt Service Routines (ISR) needs a buffered state holder flag outside of the ISR.

Depending on your coding of the ISR, due to your usage purpose of these H/W IRQ's, any of the S/W Buffered Flags may not require manipulation control code usage, but full Bit controls are defined for them in CODE LISTING.

Another 'Temp' Byte variable TEMP_BUFFER, is used to read PORTB and hold its current state to compare with the last state PORTB_BUFFER variable on a Bit by Bit basis to determine which pin changed states. Then update PORTB_BUFFER after checks so it holds new pin last states for next interrupt event.
See the example code in the Interrupt sub-procedure I've included for checking which pin changed and updating the PORTB_BUFFER Bits.

The same principle can be used on all of the PIC18's various peripheral Hardware interrupt sources also.

This Method can be applied to ANY PIC family chips registers Hard Ware bit Controls and Flags too.
This Method can also help you control your own S/W Flag Bits or switches and used as easy Output PORT-Pin Digital controls.

If your PIC Chip version features Output Port LATx H/W Buffers, they should be used in any 'SetBit()' and 'ClearBit()' constructs instead of manipulating a ports H/W output latch register buffer. See the MiKroeBasic Help file section 'Read Modify Write Problem' in 'PIC SPECIFICS' Chapter for more information about this.


These Defined controls compile as in-line-functions, so don't count against the stack levels usage also.
The MB compiler should exclude any Symbols defined but not used (called) in your code, so final code size only increases by usage in code.

Only PIC18 or higher level Chips can use HIGH/LOW Priority interrupts, so remove Priority control symbols for use with lower level PIC Chips like PIC16's.

This code uses SFR register Label and Bit define Definitions for a PIC18F4620 40-Pin device. Controls should migrate properly with any Hard Ware register re-locations as long as label usages remain the same between different Chip classes and versions.
Check the Data Sheet for your Chip Version if problems in using.


CODE LISTING: Last Edited: Sat Oct 23, 2010 12:51 pm

Code: Select all

program Interrupt_Symbols

' Declarations section 
' Version Edit Date: 23/10/2010
'
' THIS UPDATE HAS IMPORTANT CHANGES IN ANY REMARK THAT STARTS LIKE THIS:  '*
'
' MegaHurts VulKan LogiK PIC 18 GLOBAL AND HI/LO-PRIORITY INTERRUPT MANAGEMENT
'===========================Vulkan_Logik===================================
' Define symbols for Global-Interrupt-Enable/Disable control and State Flag.
' (Or Hi-level Interrupt enable control)

' Global Mode versions
Symbol GLOBAL_ENABLED = SetBit(INTCON, GIE_bit)     ' Enables all IRQs
Symbol GLOBAL_DISABLED = ClearBit(INTCON, GIE_bit)  ' Disable all IRQs
Symbol GLOBAL_IRQ = TestBit(INTCON, GIE_bit)        '* Checks GIE State

' Hi-Priority Mode versions
Symbol HI_IRQ_ENABLED = SetBit(INTCON, GIE_bit)     ' Enables HI Priority IRQs
Symbol HI_IRQ_DISABLED = ClearBit(INTCON, GIE_bit)  ' Disable HI Priority IRQs
Symbol HI_IRQ = TestBit(INTCON, GIE_bit)            '* Checks GIE State

' PIC PERIPHERAL AND LO-PRIORITY INTERRUPT MANAGEMENT
'===========================Vulkan_Logik===================================
' Define symbols for Interrupt-Enable/Disable Control
' (Or lo-level Interrupt enable control) unmasked Peripheral interrupts

' Periphial Mode versions
Symbol PERIPH_ENABLED = SetBit(INTCON, PEIE_bit)    ' Enables all PERIPH IRQs
Symbol PERIPH_DISABLED = ClearBit(INTCON, PEIE_bit) ' Disable all PERIPH IRQs
Symbol PERIPH_IRQ = TestBit(INTCON, PEIE_bit)       '* Checks PEIE State

' LO-Priority Mode versions
Symbol LO_IRQ_ENABLED = SetBit(INTCON, PEIE_bit)    ' Enables LO Priority IRQs
Symbol LO_IRQ_DISABLED = ClearBit(INTCON, PEIE_bit) ' Disable LO Priority IRQs
Symbol LO_IRQ = TestBit(INTCON, PEIE_bit)           '* Checks PEIE State

' PIC INTERRUPT PRIORITY MODE ENABLE Bit (RCON.IPEN) MANAGEMENT
'===========================Vulkan_Logik===================================

Symbol PRIORITY_ENABLED = SetBit(RCON, IPEN_bit)   ' Enables IRQ Priority Mode
Symbol PRIORITY_DISABLED = ClearBit(RCON, IPEN_bit)' Disable IRQ Priority Mode
Symbol IRQ_PRI = TestBit(RCON, IPEN_bit)           ' Check IRQ Priority state

'* PIC PORT-B INTERNAL PULL-UPS Bit (INTCON2.RBPU) MANAGEMENT
'===========================Vulkan_Logik===================================

Symbol PULLUPB_ENABLED = SetBit(INTCON2, RBPU_bit)    '* Enables Port-B Pull-Ups
Symbol PULLUPB_DISABLED = ClearBit(INTCON2, RBPU_bit) '* Disable Port-B Pull-Ups
Symbol PULLUP_B = TestBit(INTCON2, RBPU_bit)         ' Checks set state
'* added 'B' designator to enable/disable labels so easy to add other Port's internal pull-up controls. Follow this
' same scheme but change PORT Letter in aliases to match Port being controlled.

' PIC PORT-B PINS RB4, RB5, RB6, RB7 IRQ-ON-CHANGE MANAGEMENT
'===========================Vulkan_Logik===================================
' Define symbols for Interrupt-on-change Enable/Disable Control
' RB4:5:6:7

'* Define symbol control to load TEMP_BUFFER with PORT-B Pins current state.
'* Loads PortB input-pins current state into TEMP_BUFFER
Symbol Set_BUFFER = TEMP_BUFFER = PORTB  '*

Symbol RBCHG_ENABLED = SetBit(INTCON, RBIE)      ' Enables Interrupts
Symbol RBCHG_DISABLED = ClearBit(INTCON, RBIE)   ' Disable Interrupts
Symbol RBCHG_IRQ = TestBit(INTCON, RBIE_bit)     '* RBIE IRQ Control State

' Controls for setting RBIE Interrupt Priority
Symbol RBCHG_HIPRI = SetBit(INTCON2, RBIP_bit)   ' Port Change IRQ HIGH
Symbol RBCHG_LOPRI = ClearBit(INTCON2, RBIP_bit) ' Port Change IRQ LOW
Symbol RBCHG_Pri = TestBit(INTCON2, RBIP_bit)    ' Checks Priority State

' Define symbol for PORTB pin change FLAG (Must be cleared AFTER read PORTB)
' 1 = one of the 4 pins (RB4:7) has changed state.

Symbol RBCHG_FLAG = TestBit(FLAGSB, B3)          '* Check S/W Flag Register
'* (B3 unused as NO PORTB H/W IRQ source to Buffer)
Symbol _RBCHG_FLAG = TestBit(INTCON, RBIF_bit)   '* Check H/W Flag Register
Symbol ClrHW_RBCHG = ClearBit(INTCON, RBIF_bit)  '* Clears H/W IRQ BPIN_CHG_FLAG
Symbol Clear_RBCHG = ClearBit(FLAGSB, B3)        '* Clears S/W RBCHG_FLAG
Symbol Set_RBCHG = SetBit(FLAGSB, B3)            '* Sets S/W RBCHG_FLAG

' Controls for RB4:7 S/W Flags
' Change the INTRB4, INTRB5, INTRB6, INTRB7 in the Symbol names
' to whatever you need for better clarity or use as is.

Symbol Set_INTRB4 = SetBit(FLAGSB, B4)     ' sets S/W Buffered flag
Symbol IRQ_INTRB4 = TestBit(FLAGSB, B4)    ' Check Flag for RB4 Pin state change
Symbol Clear_INTRB4 = ClearBit(FLAGSB, B4) ' Clears S/W Buffered Flag

Symbol Set_INTRB5 = SetBit(FLAGSB, B5)     ' sets S/W Buffered Flag
Symbol IRQ_INTRB5 = TestBit(FLAGSB, B5)    ' Check Flag for RB5 Pin state change
Symbol Clear_INTRB5 = ClearBit(FLAGSB, B5) ' Clears S/W Buffered Flag

Symbol Set_INTRB6 = SetBit(FLAGSB, B6)     ' sets S/W Buffered Flag
Symbol IRQ_INTRB6 = TestBit(FLAGSB, B6)    ' Check Flag for RB6 Pin state change
Symbol Clear_INTRB6 = ClearBit(FLAGSB, B6) ' Clears S/W Buffered Flag

Symbol Set_INTRB7 = SetBit(FLAGSB, B7)     ' sets S/W Buffered Flag
Symbol IRQ_INTRB7 = TestBit(FLAGSB, B7)    ' Check Flag for RB7 Pin state change
Symbol Clear_INTRB7 = ClearBit(FLAGSB, B7) ' Clears S/W Buffered Flag

' PIC PORT-B EXTERNAL INT0, INT1, INT2 INPUTS MANAGEMENT
'===========================Vulkan_Logik===================================
' Define symbols for controlling Interrupt INT0 -(RB0) functions
' Change the "INT0" in each Symbol name to what ever function your hardware
' is set to monitor.

Symbol INT0_ENABLED = SetBit(INTCON, INT0IE_bit)    ' Enables INT0 interrupts
Symbol INT0_DISABLED = ClearBit(INTCON, INT0IE_bit) ' Disables INT0 interrupts
Symbol INT0_IRQ = TestBit(INTCON, INT0IE_bit)       ' Checks state of H/W INT0

' Define  controls to set Active Edge Logic detection IRQ trigger
Symbol INT0_TRIG_HI = SetBit(INTCON2, INTEDG0_bit)   ' Set Active HIGH Logic
Symbol INT0_TRIG_LO = ClearBit(INTCON2, INTEDG0_bit) ' Set Active LOW Logic
Symbol INT0_TRIG = TestBit(INTCON2, INTEDG0_bit)     ' Checks set state

' Define INT0 Flag management
Symbol INT0_FLAG = TestBit(FLAGSB, B0)               '* Checks S/W Flag state
Symbol _INT0_FLAG = TestBit(INTCON, INT0IF_bit)      '* Checks H/W FLAG SFR
' 1 = Interrupt happened, 0 = No Event. (Clear H/W Flag before enabling)

Symbol Clear_INT0 = ClearBit(FLAGSB, B0)             '* Clears S/W INT0 Flag
Symbol ClrHW_INT0 = ClearBit(INTCON, INT0IF_bit)     '* Clears H/W INT0 Flag
Symbol Set_INT0 = SetBit(FLAGSB, B0)                 '* Sets S/W INT0 Flag

'  PIC interrupt management ( RB1: INT1)
'===========================Vulkan_Logik===================================
' Define symbols for RB1-Ext. INT1 IRQ Enable/Disable control.
' Change the "INT1" in each Symbol name to what ever function your hardware
' is set to monitor.

Symbol INT1_ENABLED = SetBit(INTCON3, INT1IE_bit)      ' INT1 IRQ Enabled
Symbol INT1_DISABLED = ClearBit(INTCON3, INT1IE_bit)   ' INT0 IRQ Disabled
Symbol INT1_IRQ = TestBit(INTCON3, INT1IE_bit)         ' Check H/W set state

' Define controls to set Active Edge Logic detection IRQ trigger
Symbol INT1_TRIG_HI = SetBit(INTCON2,  INTEDG1)        ' Ext. IRQ Trig Low->Hi
Symbol INT1_TRIG_LO = Clearbit(INTCON2, INTEDG1)       ' Ext. IRQ Trig Hi->Low
Symbol INT1_TRIG = TestBit(INTCON2, INTEDG1)           ' Check H/W set State

' Define controls for setting RB1-ext. INT1 IRQ Priority HIGH/LOW
Symbol INT1_HIPRI = SetBit(INTCON3, INT1IP_bit)        ' Set to HIGH Priority
Symbol INT1_LOPRI = ClearBit(INTCON3, INT1IP_bit)      ' Set to LOW Priority
Symbol INT1_Pri = TestBit(INTCON3, INT1IP_bit)         ' Check H/W set state

' Define symbol for External-INT1 FLAG. (RB1)
Symbol INT1_FLAG  = TestBit(FLAGSB, B1)            '* Test for S/W Flag IRQ INT1
Symbol _INT1_FLAG = TestBit(INTCON3, INT1IF_bit)   '* Test H/W Flag Register
' 1 = Interrupt happened, 0 = No Event. (Clear H/W Flag before enabling)

Symbol ClrHW_INT1 = ClearBit(INTCON3, INT1IF_bit)  '* Clears H/W IRQ _INT1_FLAG
Symbol Clear_INT1 = ClearBit(FLAGSB, B1)           '* Clears S/W Flag
Symbol Set_INT1 = SetBit(FLAGSB, B1)               '* Set S/W Flag

' PIC INTERRUPT MANAGEMENT ( RB2 )
'===========================Vulkan_Logik===================================
' Define symbols for External INT2 Enable/Disable control.
' Change the "INT2" in each Symbol name to what ever function your hardware
' is set to monitor.

Symbol INT2_ENABLED = SetBit(INTCON3, INT2IE_bit)    ' Enables INT2 IRQ
Symbol INT2_DISABLED = ClearBit(INTCON3, INT2IE_bit) ' Disable INT2 IRQ
Symbol INT2_IRQ = TestBit(INTCON3, INT2IE_bit)       ' checks set state

' Define controls to set Active Edge Logic detection IRQ trigger
Symbol INT2_TRIG_HI  = SetBit(INTCON2, INTEDG2)    ' Ext. IRQ trig on Low->Hi.
Symbol INT2_TRIG_LO = ClearBit(INTCON2, INTEDG2)   ' Ext. IRQ Trig on Hi->Low
Symbol INT2_Trig = TestBit(INTCON2, INTEDG2)       ' Check state of Active Logic

' Define controls for setting RB2-ext. INT2 IRQ Priority
Symbol INT2_HIPRI = SetBit(INTCON3, INT2IP)        ' Set to HIGH IRQ Priority
Symbol INT2_LOPRI = ClearBit(INTCON3, INT2IP)      ' Set to LOW IRQ Priority
Symbol INT2_PRI = TestBit(INTCON3, INT2IP)         ' check state IRQ Priority

'* Define symbol for External-INT2 FLAG. (RB2)
Symbol INT2_FLAG = TestBit(FLAGSB, B2)             '* Test for S/W Flag IRQ INT2
Symbol _INT2_FLAG = TestBit(INTCON3, INT2IF_bit)   '* Check H/W Flag Register
' 1 = Interrupt happened, 0 = No Event. (Clear H/W Flag before enabling)

Symbol Clear_INT2 = ClearBit(FLAGSB, B2)           '* Clears S/W INT2 Flag
Symbol ClrHW_INT2 = ClearBit(INTCON3, INT2IF_bit)  '* Clears INT H/W _INT2 Flag
Symbol Set_INT2 = SetBit(FLAGSB, B2)               '* Set S/W INT2 IRQ Flag
'---------------------------------------------------------------------------------------------------------------

' Constants declarations go here.

'______________________________________________________________________________________
'                 DEFINE PROGRAM VARIABLES SECTION
'======================================================================

dim PORTB_BUFFER as Byte        ' variable for holding PORTB last state
    FLAGSB       as Byte        ' variable for IRQ Flags (individual bit usage)
    TEMP_BUFFER  as Byte        ' Temp variable for reading PORTB

' your project program variable defines go here.

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


'_____________________________________________________________________________________
'                   IRQ CONTROLS QUICK LIST
'
' Mhz Vulkan_Logik PIC CONTROLS FOR GLOBAL AND HI/LO-PRIORITY IRQ MANAGEMENT
'=============================Vulkan_Logik=================================

'____enable___________disable_________test_________________________________
' PRIORITY_ENABLED PRIORITY_DISABLED IRQ_PRI
'                                             INTERRUPT PRIORITY DISABLED
' GLOBAL_ENABLED   GLOBAL_DISABLED   GLOBAL_IRQ
' PERIPH_ENABLED   PERIPH_DISABLED   PERIPH_IRQ
'                                             INTERRUPT PRIORITY ENABLED
' HI_IRQ_ENABLED   HI_IRQ_DISABLED   HI_IRQ
' LO_IRQ_ENABLED   LO_IRQ_DISABLED   LO_IRQ
'
'===========================Vulkan_Logik===================================

'PIC PORT-B: RB4-RB7 (RBIE) IRQ-ON-CHANGE MANAGEMENT
'===========================Vulkan_Logik===================================
'____enable___________disable_________test____________flag set & clr_______
' PULLUPB_ENABLED   PULLUPB_DISABLED   PULLUP_B
' RBCHG_ENABLED    RBCHG_DISABLED    RBCHG_IRQ        Set_RBCHG    (S/W Flag)
' RBCHG_HIPRI      RBCHG_LOPRI       RBCHG_Pri
'                                   _RBCHG_FLAG (H/W) ClrHW_RBCHG  (H/W Flag)
'                                    RBCHG_FLAG (S/W) Clear_RBCHG  (S/W Flag)
'     Set_BUFFER    '* Loads TEMP_BUFFER with PORTB's current input-pins states
'
'  S/W BUFFERED FLAGS FOR PORT-B INTERRUPT-ON-CHANGE MANAGEMENT
'_pin___set flag_________test flag________clear flag_______________________
' RB4   Set_INTRB4       IRQ_INTRB4       Clear_INTRB4
' RB5   Set_INTRB5       IRQ_INTRB5       Clear_INTRB5
' RB6   Set_INTRB6       IRQ_INTRB6       Clear_INTRB6
' RB7   Set_INTRB7       IRQ_INTRB7       Clear_INTRB7
'
' PIC PORT-B: RB0-RB2 EXTERNAL INTERRUPTS MANAGEMENT
'===========================Vulkan_Logik=======================
'____enable___________disable_________test____________flag set & clr_______

' RB0-INT0 [ INT0IE ] (HIGH Priority Only)
' INT0_ENABLED     INT0_DISABLED     INT0_IRQ  (H/W)  Set_INT0   (S/W)
' INT0_TRIG_HI     INT0_TRIG_LO      INT0_TRIG
'                                    INT0_FLAG (S/W)  Clear_INT0 (S/W)
'                                   _INT0_FLAG (H/W)  ClrHW_INT0 (H/W)
'
' RB1-INT1 [ INT1IE ]
' INT1_ENABLED     INT1_DISABLED     INT1_IRQ (H/W)   Set_INT1   (S/W)
' INT1_TRIG_HI     INT1_TRIG_LO      INT1_TRIG
' INT1_HIPRI       INT1_LOPRI        INT1_Pri
'                                    INT1_FLAG (S/W)  Clear_INT1 (S/W)
'                                   _INT1_FLAG (H/W)  ClrHW_INT1 (H/W)
'
' RB2-INT2 [ INT2IE ]
' INT2_ENABLED     INT2_DISABLED     INT2_IRQ (H/W)   Set_INT2   (S/W)
' INT2_TRIG_HI     INT2_TRIG_LO      INT2_Trig
' INT2_HIPRI       INT2_LOPRI        INT2_Pri
'                                    INT2_FLAG (S/W)  Clear_INT2 (S/W)
'                                   _INT2_FLAG (H/W)  ClrHW_INT2 (H/W)
'
'--------------------------------------------------------------------------------------------------------
'________________________________________________________________________________
'                      GLOBAL OR HIGH PRIORITY ISR
' example interrupt routine: not complete or fully functional as is!!!
'==================================================================

sub procedure interrupt()

 ' other interrupt service code goes here

' test for portB IRQ on Change event: if so, which pins
if ( (_RBCHG_FLAG = 1) and (RBCHG_IRQ = 1) ) Then '* IMPORTANT CHANGE TO USING H/W FLAG HERE!
    Set_BUFFER                 '* Get current PORTB input-pins states
    if (TEMP_BUFFER.4 <> PORTB_BUFFER.4) Then
       Set_INTRB4                    ' set S/W Flag for INTRB4 Pin state change
       PORTB_BUFFER.4 = TEMP_BUFFER.4  ' update portB last state buffer bit
    end if
    if (TEMP_BUFFER.5 <> PORTB_BUFFER.5) Then
       Set_INTRB5                    ' set S/W Flag for INTRB5 Pin state change
       PORTB_BUFFER.5 = TEMP_BUFFER.5  ' update portB last state buffer bit
    end if
    if (TEMP_BUFFER.6 <> PORTB_BUFFER.6) Then
       Set_INTRB6                    ' set S/W Flag for INTRB6 Pin state change
       PORTB_BUFFER.6 = TEMP_BUFFER.6  ' update portB last state buffer bit
    end if
    if (TEMP_BUFFER.7 <> PORTB_BUFFER.7) Then
       Set_INTRB7                    ' set S/W Flag for INTRB7 Pin state change
       PORTB_BUFFER.7 = TEMP_BUFFER.7  ' update portB last state buffer bit
    end if
    ClrHW_RBCHG                        '* CLEAR HardWare FLAG RBIF
    Set_RBCHG                  '* Sets S/W RBIE Flag
end if

 ' other interrupt service code goes here

end sub

'_____________________________________________________________
'                           SUB FUNCTION DECLARATIONS SECTION
'==================================================

' your sub function codes go here.

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


'______________________________________________________________
'                             MAIN PROGRAM CODE SECTION
'====================================================

main:

'   Main program code goes here.


'---------------------------------------------------------------------------------
end.

Of course, you'll need to write code for separate HIGH and LOW Interrupt Service Routines if enabled.

Hope this is useful for everyone and if you use it and like/dislike, let me know, MHz. B^)
HW: easyPIC5|PICFlash2|easyBT|smartGSM|easyGSM|PICPLC16|mmWorkStation|FT800 Eve|PIC Clicker/2|
MMBs:PIC18F,PIC33EP,PIC32|CLICKs:DAC,ADC,GPS L10,Thermo,8x8B LED,Stepper,W/B OLED,9DOF,GPS3,tRF,Hall I|

SW: mP for PIC|mB for PIC-dsPIC-PIC32|Visual-TFT|

igeorge
Posts: 593
Joined: 28 Dec 2005 09:15

Re: Symbols Code for PIC18 PORTB Interrupt management

#2 Post by igeorge » 25 Apr 2014 14:54

Thank you Robert
Great tool for newbie like me
Experience is something you don't get until just after you need it

Post Reply

Return to “User Projects”