Search code examples
picrtcc

pic18F47J53 RTCC not starting


Using a PIC18F47J53, MPLAB x, XC8 (v2.31), I am trying to use the internal RTCC, but I cannot see it counting (the seconds). The register RTCVALL, is not changing after waiting a few seconds.

I would like to use the 8MHz internal oscillator for the main clock, and the internal INTRC for the RTCC. Maybe first someone can confirm is it possible to use those 2?

The code is fairly simple, just setting a "seconds" value in RTCVALL, wait a bit, read the same register and hoping to find it has changed.. but it hasn't.

I am posting the main part of the code. Other question, what is the RTCC pin is supposed to output? I have chosen the "seconds" as output, but if it is supposed to toggle high/low every seconds, where can I see in the datasheet the duty cycle? in my case the LED on RTCC pin stays solid high.

'''

// CONFIG1L
#pragma config WDTEN = OFF      // Watchdog Timer (Disabled - Controlled by SWDTEN bit)
#pragma config PLLDIV = 1       // PLL Prescaler Selection (No prescale (4 MHz oscillator input drives PLL directly))
#pragma config CFGPLLEN = OFF   // PLL Enable Configuration Bit (PLL Disabled)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset (Enabled)
#pragma config XINST = OFF      // Extended Instruction Set (Disabled)
// CONFIG1H
#pragma config CPUDIV = OSC1    // CPU System Clock Postscaler (No CPU system clock divide)
#pragma config CP0 = OFF        // Code Protect (Program memory is not code-protected)
// CONFIG2L
#pragma config OSC = INTOSC     // Oscillator (INTOSC)
#pragma config SOSCSEL = HIGH   // T1OSC/SOSC Power Selection Bits (High Power T1OSC/SOSC circuit selected)
#pragma config CLKOEC = ON      // EC Clock Out Enable Bit  (CLKO output enabled on the RA6 pin)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor (Enabled)
#pragma config IESO = ON        // Internal External Oscillator Switch Over Mode (Enabled)
// CONFIG2H
#pragma config WDTPS = 32768    // Watchdog Postscaler (1:32768)
// CONFIG3L
#pragma config DSWDTOSC = INTOSCREF// DSWDT Clock Select (DSWDT uses INTRC)
#pragma config RTCOSC = INTOSCREF       // RTCC Clock Select (INTRC)
#pragma config DSBOREN = ON     // Deep Sleep BOR (Enabled)
#pragma config DSWDTEN = ON     // Deep Sleep Watchdog Timer (Enabled)
#pragma config DSWDTPS = G2     // Deep Sleep Watchdog Postscaler (1:2,147,483,648 (25.7 days))
// CONFIG3H
#pragma config IOL1WAY = ON     // IOLOCK One-Way Set Enable bit (The IOLOCK bit (PPSCON<0>) can be set once)
#pragma config ADCSEL = BIT10   // ADC 10 or 12 Bit Select (10 - Bit ADC Enabled)
#pragma config MSSP7B_EN = MSK7 // MSSP address masking (7 Bit address masking mode)
// CONFIG4L
#pragma config WPFP = PAGE_127  // Write/Erase Protect Page Start/End Location (Write Protect Program Flash Page 127)
#pragma config WPCFG = OFF      // Write/Erase Protect Configuration Region  (Configuration Words page not erase/write-protected)
// CONFIG4H
#pragma config WPDIS = OFF      // Write Protect Disable bit (WPFP<6:0>/WPEND region ignored)
#pragma config WPEND = PAGE_WPFP// Write/Erase Protect Region Select bit (valid when WPDIS = 0) (Pages WPFP<6:0> through Configuration Words erase/write protected)
#pragma config LS48MHZ = SYS48X8// Low Speed USB mode with 48 MHz system clock bit (System clock at 48 MHz USB CLKEN divide-by is set to 8)

#define UINT_TO_BCD_ONES(x) ((x) % 10)
#define UINT_TO_BCD_TENS(x) (((x) % 100) / 10)
#define BCD_TO_UINT_TENS(x) ((x) >> 4)
#define BCD_TO_UINT_ONES(x) ((x) & 0x0F)

void main(void)
{
    // set to 8MHz internal oscillator
    OSCCON = 0x70;
    // not sure that is necessary but either 0 or 1 don't work
    OSCTUNEbits.INTSRC = 1;

    pic_uart1_init(UART_BDS_9600);
    __delay_ms(1000);

    uint8_t seconds = 0;

    // seconds RTCC output pin
    PADCFG1bits.RTSECSEL1 = 0;
    PADCFG1bits.RTSECSEL0 = 1;
    pic_rtc_set_alarm_output(ON);

    pic_rtc_enable(ON);
    pic_rtc_wr_enable(ON);
    pic_rtc_set_seconds(45);
    pic_rtc_wr_enable(OFF);

    // wait some time
    for (int i = 0; i < 12; i++){
        __delay_ms(1000);
        printf("-> RTCVALL = %d\n", RTCVALL);
        printf("-> RTCVALH = %d\n", RTCVALH);
    }

    pic_rtc_read_seconds(&seconds);
    pic_rtc_enable(OFF);

    printf("seconds = %d\n", seconds);
}

pic_status_t pic_rtc_enable(feature_status_t set_status)
{
    pic_rtc_wr_enable(ON);
    RTCCFGbits.RTCEN = set_status;
    pic_rtc_wr_enable(OFF);
    return PIC_SUCCESS;
}

pic_status_t pic_rtc_set_alarm_output(feature_status_t set_status)
{
    RTCCFGbits.RTCOE = set_status;
    return PIC_SUCCESS;
}

pic_status_t pic_rtc_wr_enable(feature_status_t set_status)
{
    INTCONbits.GIE = 0;
    EECON2 = 0x55;
    EECON2 = 0xAA;
    RTCCFGbits.RTCWREN = set_status;
    INTCONbits.GIE = 1;

    return PIC_SUCCESS;
}

pic_status_t pic_rtc_read_seconds(uint8_t *seconds)
{
    // point to minutes
    RTCCFGbits.RTCPTR1 = 0;
    RTCCFGbits.RTCPTR0 = 0;

    printf("RTCCFGbits.RTCPTR1 = %d\n", RTCCFGbits.RTCPTR1);
    printf("RTCCFGbits.RTCPTR0 = %d\n", RTCCFGbits.RTCPTR0);
    printf("RTCCFGbits.RTCWREN = %d\n", RTCCFGbits.RTCWREN);

    uint8_t buffer_rd_sec = RTCVALL;

    printf("buffer_rd_sec (BCD) = 0x%02x\n", buffer_rd_sec);

    *seconds = (uint8_t)((BCD_TO_UINT_TENS(buffer_rd_sec) * 10) + (BCD_TO_UINT_ONES(buffer_rd_sec)));

    return PIC_SUCCESS;
}

pic_status_t pic_rtc_set_seconds(uint8_t seconds)
{
    if (seconds > 59)
        return PIC_FAIL;

    // point to seconds
    RTCCFGbits.RTCPTR1 = 0;
    RTCCFGbits.RTCPTR0 = 0;

    printf("RTCCFGbits.RTCPTR1 = %d\n", RTCCFGbits.RTCPTR1);
    printf("RTCCFGbits.RTCPTR0 = %d\n", RTCCFGbits.RTCPTR0);
    printf("RTCCFGbits.RTCWREN = %d\n", RTCCFGbits.RTCWREN);

    uint8_t buf_ones = UINT_TO_BCD_ONES(seconds);
    printf("buf_ones = 0x%02x\n", buf_ones);

    uint8_t buf_tens = UINT_TO_BCD_TENS(seconds);
    printf("buf_tens = 0x%02x\n", buf_tens);

    uint8_t buffer = buf_tens << 4 | buf_ones;
    printf("buffer = 0x%02x\n", buffer);

    RTCVALL = buffer;

    return PIC_SUCCESS;
}

'''

Thanks for having a look and help


Solution

  • I got it working, looks like it wasn't the understanding of the PIC the problem, but the XC8 compiler instead.. I thought the RTCWREN bit had to be checked before enable the RTCEN

    pic_status_t pic_rtc_enable(feature_status_t set_status)
    {
        while(!RTCCFGbits.RTCWREN); // wait for the bit to be set
        RTCCFGbits.RTCEN = set_status;
        return PIC_SUCCESS;
    }
    

    and found that the bit wasn't set at all, resulting the rest of the code been ignored. so I looked into my pic_rtc_wr_enable function and I am very puzzled why the parameter set_status is making the block!

    it is an enum,

    typedef enum {
        OFF = 0,
        ON = 1,
    } feature_status_t;
    

    but if you replace the code with

    pic_status_t pic_rtc_wr_enable(feature_status_t set_status)
    {
        if (set_status == 1) {
    
            INTCONbits.GIE = 0;
            EECON2 = 0x55;
            EECON2 = 0xAA;
            RTCCFGbits.RTCWREN = 1;
            INTCONbits.GIE = 1;
        }
    
        return PIC_SUCCESS;
    }
    

    then it works perfectly fine.

    So why XC8 doesn't substitute my enum ON with its int value of 1 for the bit assignment? despite it works in the check? Any ideas?

    For the RTCC pin, got it working too now, and it looks like the pin out is pulsing every seconds (in my case), and duty cycle is 50%.