9.2 Bare Metal Code

The first step will be to configure the microcontroller to disable the Watchdog Timer (WDT) and to enable Low-Voltage Programming (LVP).

#pragma config WDTE = OFF   /*disable Watchdog*/
#pragma config LVP = ON  /* Low voltage programming enabled, RE3 pin is MCLR */

The following constants need to be defined:

#define Timer2Period    0x2F        /* TMR2 Period is 100ms */
#define Timer4Period    0xF1        /* TMR4 Period is 500ms */

The CLK_Initialize function initializes the HFINTOSC internal oscillator:

static void CLK_Initialize(void)
{
    /* set HFINTOSC Oscillator */  
    OSCCON1 = 0x60;
    /* set HFFRQ to 1 MHz */
    OSCFRQ = 0x00;
}

The PPS_Initialize function has the role to configure the RC7 peripheral select as input for TMR4:

static void PPS_Initialize(void)
{
    /* Set RC7 as input for TMR4 (T4IN) */
    T4INPPS = 0x17;
}

PORT_Initialize has the role to configure the RC7, input channel, and RE0 output for LED0 pins:

static PORT_Initialize(void)
{
    /* Set RC7 pin as digital */
    ANSELC = 0x7F;
    /* Set RE0 pin as output */
    TRISE = 0x06;
    /* Enable weak pull-up on pin RC7 */
    WPUC = 0x80;
}

The TMR2_Initialize function sets the clock source and the registers needed to generate an 100 ms period:

static void TMR2_Initialize(void)
{
    /* TMR2 Clock source, LFINTOSC (00100) has 31 kHz */
    T2CLKCON = 0x04;
    /* T2PSYNC Not Synchronized; T2MODE Starts at T2ON = 1 and TMR2_ers = 0; T2CKPOL Rising Edge */
    T2HLT = 0x02; 
    /* TMR2 external reset is TMR4_postscaled */ 
    T2RST = 0x02;
    /* TMR2 ON on; T2 CKPS Prescaler 1:64; T2 OUTPS Postscaler 1:1 
       Minimum timer period is 31 kHz/64 = 2.064516 ms  */
    T2CON = 0xE0;
    /* Set TMR2 period, PR2 to 100ms */
    T2PR = Timer2Period;
    /* Clear the TMR2 interrupt flag */
    PIR4bits.TMR2IF = 0;
    /* Enabling TMR2 interrupt */
    PIE4bits.TMR2IE = 1;
}

The TMR4_Initialize function sets the clock source and the registers needed to generate an 500 ms period:

static void TMR4_Initialize(void)
{
    /* TMR4 Clock source, LFINTOSC (00100) has 31 kHz */
    T4CLKCON = 0x04;
    /* TMR4 in OneShot mode, Starts at TMR4_ers=0 and resets on TMR4_ers=1 */
    T4HLT = 0x17;
    /* TMR4 External reset signal selected by T4INPPS pin  */
    T4RST = 0;
    /* TMR4 ON on; T4 CKPS Prescaler 1:64; T4 OUTPS Postscaler 1:1 
       Minimum timer period is 31 kHz/64 = 2.064516 ms  */ 
    T4CON = 0xE0;
    /* Set TMR4 period, PR4 to 500ms */
    T4PR = Timer4Period;
    /* Clear the TMR4 interrupt flag */
    PIR4bits.TMR4IF = 0;
}

The following initialization function will safely enable the Global and Peripherals interrupts, after all modules have been initialized with proper settings:

static void INTERRUPT_Initialize(void)
{
    INTCONbits.GIE  = 1;          /* Enable Global Interrupts */
    INTCONbits.PEIE = 1;          /* Enable Peripheral Interrupts */    
}

The next function handles the interrupts (in this case there is only one interrupt), checks the status of the TMR2 Interrupt flag, and then calls the TMR2_Interrupt function.

static void __interrupt() INTERRUPT_InterruptManager(void)
{
    if (INTCONbits.PEIE == 1)
    {
        if (PIE4bits.TMR2IE == 1 && PIR4bits.TMR2IF == 1)
        {
            TMR2_Interrupt();
        } 
    }
}

The TMR2_Interrupt clears the Interrupt flag and toggles the LED0 (this will happen with Timer2 Period frequency).

static void TMR2_Interrupt(void)
{
    /* Clear the TMR2 interrupt flag */
    PIR4bits.TMR2IF = 0;
    /* Toggle LED0 at the Timer2Period frequency */
    LATEbits.LATE0 = ~LATEbits.LATE0;
}

The void main function contains only the initialization functions:

void main(void)
{
    /* Initialize the device */
    CLK_Initialize();             /* Oscillator Initialize function */
    PPS_Initialize();             /* Peripheral select Initialize function */
    PORT_Initialize();            /* Port Initialize function */
    TMR2_Initialize();            /* TMR2 Initialize function */
    TMR4_Initialize();            /* TMR4 Initialize function */
    INTERRUPT_Initialize();       /* Interrupt Initialize function */
    
    while (1)
    {
        ;/* Add your application code */
    }
}

If the RC7 pin is pulled to GND for more than the Timer4 Period (500 ms), TMR4 will trigger TMR2 to stop and act as a one-shot Reset.