4.2 Bare Metal Code
The necessary code and functions to implement the presented example are analyzed in this section.
The first step will be to configure the microcontroller to disable the Watchdog Timer and to enable the Low-Voltage Programming (LVP).
#pragma config WDTE = OFF /* WDT operating mode → WDT Disabled */ #pragma config LVP = ON /* Low-voltage programming enabled, RE3 pin is MCLR */
As described in the example functionality, the following peripherals must be initialized: Timer2, Timer4, CLC1, the I/O PORT and PPS.
The internal oscillator has to be set to the desired value (in this case to 64 MHz), using the following function:
static void CLK_init(void) { OSCCON1bits.NOSC = 6; /* HFINTOSC oscillator */ OSCFRQ = 0x08; /* HFFRQ 64_MHz; */ }
To enable the output driver in the desired I/O pins (RA2), the following function is used:
static void PORT_init(void) { TRISAbits.TRISA2 = 0; /*PORT RA2 output driver enabled*/ }
For Timer2 to use FOSC/4 as clock source and generate a pulse every 4.096 ms (frequency = 24.41 Hz), the prescaller must also be added to 1:128 and postcaller to 1:2. The following function is used:
static void TMR2_init(void) { T2CLKCONbits.CS = 1; /* Timer2 clock source is FOSC/4 */ T2PR = 0xFF; /* Load period values */ T2CONbits.CKPS = 7; /* Set prescaller to 1:128 */ T2CONbits.OUTPS = 1; /* Set postcaller to 1:2 */ T2CONbits.ON = 1; /* Enable Timer2 */ }
For Timer4 to use FOSC/4 as clock source and generate a pulse every 4.08 ms (frequency = 24.51 Hz), the prescaller must also be added to 1:128 and postcaller to 1:2. The following function is used:
static void TMR4_init(void) { T4CLKCONbits.CS = 1; /* Timer4 clock source is FOSC/4 */ T4PR = 0xFE; /* Load period values */ T4CONbits.CKPS = 7; /* Set prescaller to 1:128 */ T4CONbits.OUTPS = 1; /* Set postcaller to 1:2 */ T4CONbits.ON = 1; /* Enable Timer4 */ }
CLC1 is configured in the SR Latch mode and uses TMR2 and TMR4 as inputs. The following function is used:
static void CLC1_init(void) { CLC1POL = 0x00; /* Clear the output polarity register */ CLC1SEL0 = 0x13; /* Configure TMR2_OUT as input for first OR gate */ CLC1SEL1 = 0x13; /* Configure TMR2_OUT as input for second OR gate */ CLC1SEL2 = 0x15; /* Configure TMR4_OUT as input for third OR gate */ CLC1SEL3 = 0x15; /* Configure TMR4_OUT as input for fourth OR gate */ /* All four inputs are not inverted*/ CLC1GLS0 = 0x02; CLC1GLS1 = 0x08; CLC1GLS2 = 0x20; CLC1GLS3 = 0x80; CLC1CONbits.EN = 1; /* CLC1 enabled; */ CLC1CONbits.MODE = 3; /* Mode SR latch */ }
To measure the internal peripheral signals with the oscilloscope, the following link must be made:
Internal CIP Signal | Microcontroller Pin |
---|---|
CLC1_OUT | RA2 |
This is done in the following function:
static void PPS_init(void) { RA2PPS = 0x18; /*Configure RA2 for CLC1 output*/ }