Menu

Using PPS when PPSTool unavailable.

Help
mkstevo
2019-01-21
2019-01-21
  • mkstevo

    mkstevo - 2019-01-21

    As I've written before, I use a Mac for my GCB programming. At the moment the PPS Tool isn't available for the Mac. I recently ordered some PIC16F18877 processors for work as part of a potentially large project and today decided to have a look at them, and try and start to use them. A simple program I'd written for the 16F1825 which used interrupts, a serial LCD module and the millis() function by Chris Roper was loaded into my editor and compiled.

    Millis() returned an error message that TMR0 did not work correctly with this processor as Chris has stated, so all references to millis() were removed, and the program re-compiled.
    Success!
    Well, no!
    Although the program compiled perfectly well now, nothing appeared to work. The serial LCD refused to display anything and the button and buzzer did nothing either. Hmm. Why?

    I looked at the datasheet and could see that the Serial TX function is assigned by PPS. As the Mac can't use the PPS tool, I fired up a VirtualPC and installed the PC build of GCB onto it and ran the PPS tool which gave me this:

        'Generated by PIC PPS Tool for Great Cow Basic
        'PPS Tool version: 0.0.5.25
        'PinManager data: v1.75
        'Generated for 16f18877
        '
        'Template comment at the start of the config file
        '
        #startup InitPPS, 85
        #define PPSToolPart 16f18877
    
        Sub InitPPS
            UNLOCKPPS
    
                'Module: EUSART
                RC6PPS = 0x0010    'TX > RC6
    
            LOCKPPS
        End Sub
        'Template comment at the end of the config file
    

    Adding that into my code gave me a working Serial LCD. {Well it did once I counted the pins correctly and plugged the serial connection into the right pin...}

    Next to look at the Interrupt.

    Again the datasheet suggested this could be adjusted using PPS, so I went back to the VirtualPC and the PPS tool gave me this:

        'Generated by PIC PPS Tool for Great Cow Basic
        'PPS Tool version: 0.0.5.25
        'PinManager data: v1.75
        'Generated for 16f18877
        '
        'Template comment at the start of the config file
        '
        #startup InitPPS, 85
        #define PPSToolPart 16f18877
    
        Sub InitPPS
            UNLOCKPPS
    
                'Module: EUSART
                RC6PPS = 0x0010    'TX > RC6
                'Module: EXT_INT
                INTPPS = 0x0002    'RA2 > INT
    
            LOCKPPS
        End Sub
        'Template comment at the end of the config file
    

    Now my interrupt worked too, along with the buzzer.

    Looking at the generated PPS code I wondered how I could 'decode' the datasheet, into PPS code without needing to use the PPS tool I don't have easy access to.

    For the 16F18877 the relevant pages in the manual are 241, 243 and 246. Page 241 lists the names of the input PPS funtions, page 243 lists the pin 'values' that need to be assigned to the function. For the external interrupt, the constant given on page 241 is INTPPS. The value for PortA.2 is given on page 243 as 0x02. In order to set the PPS for an external interrupt on PortA.2 the required code would be:

    INTPPS = 0x02
    

    Just as given by the PPS tool.

    Moving on to the Serial TX, page 246 tells us that the output pins for PPS are set using the command:
    RxyPPS where the 'xy' is replaced by the pin notation of the required pin. So for pin PortC.6 this gives the command of: RC6PPS ('xy' being replaced by 'C6'). The instruction value for Serial TX is shown as 0x10 making the the code for Serial TX on PortC.6:

    RC6PPS = 0x10
    

    Again, just as produced by the PPS tool.

    Editing my code to read:

    'Uses 16F18877, Serial LCD, PPS function mapping and interrupts for a button.
    
    'The interrupt triggers on a rising then falling edge to enable 
    'counting of buttons only when a button is pressed and released.
    
    'The button state is stored at startup to allow for buttons that
    'may idle high or low automatically.
    
    #Chip 16F18877, 32
    #Option explicit
    #Config CP=On
    
    #Include "Simple_Serial_LCD.h"
    'Simple_Serial_LCD.h provides a simple interface to an
    'attached serial LCD display. The ports used for the
    'serial interface should be defined in program code
    'for portability.
    
     #startup InitPPS, 85 
     'Set a startup routine with a high priority of 85.
     'Comms routines have a priority of 90, so setting this below that 
     'ensures PPS is set before any comms routine is attempted.
     '80 is the highest priority, 100 is 'normal' priority.
     #define PPSToolPart 16f18877
    
     Sub InitPPS
        UnlockPPS       'Unlock PPS to allow changes
        RC6PPS = 0x10   'Assign PortC.6 to Serial TX
    
        INTPPS = 0x02   'Assign External Interrupt to PortA.2
        LockPPS         'Lock PPS to prevent changes
    End Sub
    
    '*******************************************************************
    '*******************************************************************
    '*******************************************************************
    
    
    ' Define the USART port
    #Define USART_BAUD_RATE 9600
    #Define USART_BLOCKING
    #Define SerOutPort portC.6 'Pin  25
    #Define Button     PortA.2 'Pin  4
    #Define Beeper     PortC.3 'Pin  18  'This connects directly to a 12V Piezo buzzer
                                         'the fact that a 12V buzzer is driven from a 5V pin
                                         'does not matter. It is loud enough to hear!
    
    Dim         TimeCount       As Long
    Dim         BeepCount       As Byte
    Dim         Pressed         As Bit
    
    
    Dim         Reset_Trigger   As Bit
    Dim         Trigger         As Bit
    
    
    'Set pin directions
    Dir SerOutPort  Out         'Pin  25
    Dir Beeper      Out         'Pin  18
    Dir Button      In          'Pin  4
    
    Let Reset_Trigger = 0
    Let Trigger       = 0
    Let TimeCount         = 0
    
    Initialise
    Test
    
    Sub Test
    
    
        Do
    
            SerLocate(0,0)
            HSerPrint TimeCount
    
            If Trigger = 1 Then
                SerLocate(1,0)
                HSerPrint TimeCount
                HSerPrint "                "
                Let Trigger = 0
                DoBip(1,25)
            End If
    
            If Reset_Trigger = 1 Then
                SerLocate(1,11)
                HSerPrint TimeCount
                HSerPrint"    "
                Let Reset_Trigger = 0
                DoBip(1,25)
            End If
    
            TimeCount++
    
        Loop
    
    End Sub
    
    Sub Initialise
    
        Do
            If Button = Pressed Then
                Let Pressed = !Button
                Let TimeCount = 0
            End If
            Wait 5 mS
            TimeCount++
        Loop Until TimeCount > 125 'Get the idle state of the button pin
        Let TimeCount = 0
    
    'For the serial LCD to initialise, there must be a few
    'milliseconds of delay before using the serial LCD.
    'This is provided by the button test above.
    'Otherwise, add some delay here.
    
        ClearScreen
        SerLocate(0,0)
        HSerPrint " Hello 16F18877 "
        SerLocate(1,0)
        HSerPrint "& Fast Interrupt"
    
        '**********************************************************************
        'Interrupt setup
        '**********************************************************************
    
        'Option_Reg for rising/falling edge
        'INTEDG
    
        'INTEDG = 1 'Rising Edge
        'INTEDG = 0 'Falling Edge
    
        Let INTEDG = Pressed      'Interrupt on switch pressed state
    
        'INTE = 1 'Interrupt on Edge enabled
        'INTE = 0 'Interrupt on Edge disabled
    
        'INTF = 1 'Edge Interrupt happened
        'INTF = 0 'No Edge Interrupt
    
        'INTE = 1 'Interrupt on Edge enabled
        'INTE = 0 'Interrupt on Edge disabled
    
        Let INTE   = 1 'Interrupt on Edge enabled
        Let INTF   = 0 'Clear any interrupts
    
        On Interrupt ExtInt0 Call Interrupt_Sub
        '**********************************************************************
        'Interrupt setup
        '**********************************************************************
        Wait 250 mS
        ClearScreen
    
    End Sub
    
    Sub Interrupt_Sub
    
        If INTF = 1 Then
            If Button = Pressed Then             'Button pressed
                Wait 10 mS
                If Button = Pressed Then         'Still pressed
                    Let Trigger  = 1
                    Let INTEDG = !Pressed
                End If
            End If
            If Button <> Pressed Then             'Button released
                Wait 10 mS
                If Button <> Pressed Then         'Still released
                    Let Reset_Trigger = 1
                    Let INTEDG = Pressed
                End If
            End If
            'Let INTF   = 0 'Clear interrupt
        End If
    
    End Sub
    
    Sub DoBip(In NumberOfBips As Byte, LengthOfBips As Word)
        For BeepCount = 1 To NumberOfBips
            SoundBeep(1) 'Beep on
            Wait LengthOfBips mS
            SoundBeep(0) 'Beep off
            Wait LengthOfBips mS
        Next
    End Sub
    
    Sub SoundBeep(In Sound As Bit)
        Let Beeper = Sound
        'Turn on or off the beeper
    End Sub
    

    Gave me fully working code.

    I don't imagine this comes close to describing the complexities of the PPS function assignments, in almost all cases I would recommend that if you have access to the PPS tool, that it is used, if you don't however, this may give some insight into how to generate working code for setting those functions.

    In my case the '#Define PPSToolPart 16F18877' assignment seemed not to be required, as I was unsure of it's significance, I left it in for the sake of completeness. The PPS tool sets a StartUp Function to set the PPS assignments as soon as the processor starts. I copied this method to ensure the PPS functions are set before anything else executes.

    The datasheet implies (if I read it correctly) that the Serial TX function defaults to PortC.6 during power on reset. For me, this didn't seem to be the case. Perhaps I didn't read that bit correctly?

     

    Last edit: mkstevo 2019-01-21
  • Chris Roper

    Chris Roper - 2019-01-21

    Hi mkstevo ,

    I have a new version of millis that should support your part.
    I have not released it yet as I am still testing and documenting but I attach it here for you to try.

    Cheers
    Chris

     
    • mkstevo

      mkstevo - 2019-01-21

      I have just tested that using the 'new' millis(), and it does work just as it did on the 16F1825. Many thanks for the updated version.

       

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.