2

I have already spent several nights debugging gated timer on PIC18F26K80. I use MPLAB v4.15 and XC8 v2.32. I want to run a long period timer, so I chose Timer 3 gated by Timer 4. I've read Microchip's documentation and tried to find answers anywhere, but I cannot understand:

  1. Why it doesn't set TMR3IF flag (and doesn't fire appropriate interruption) using Fosc/4 as a clock source of Timer 3 (so I use Fosc with prescale 1:4 - it works, but... why Fosc/4 doesn't?)
  2. Why TMR3IF flag fires in TMR3 state 0x0001? It should fire from 0xFFFF to 0x0000 and with PR4 = 0x63 there is no need to step over 0x0000 so fast.

So these 2 points are the most important points, there are some other miracles, but, if you could, help me with these.

/* 
 * Test file for Gated timer
 */
// PIC18F26K80 Configuration Bit Settings
// 'C' source line config statements
// CONFIG1L
#pragma config RETEN = OFF      // VREG Sleep Enable bit (Ultra low-power regulator is Disabled (Controlled by REGSLP bit))
#pragma config INTOSCSEL = HIGH // LF-INTOSC Low-power Enable bit (LF-INTOSC in High-power mode during Sleep)
#pragma config SOSCSEL = DIG   // SOSC Power Selection and mode Configuration bits (High Power SOSC circuit selected)
#pragma config XINST = OFF      // Extended Instruction Set (Disabled)

// CONFIG1H
#pragma config FOSC = INTIO2    // Oscillator (Internal RC oscillator)
#pragma config PLLCFG = OFF     // PLL x4 Enable bit (Disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor (Disabled)
#pragma config IESO = OFF       // Internal External Oscillator Switch Over Mode (Disabled)

// CONFIG2L
#pragma config PWRTEN = OFF     // Power Up Timer (Disabled)
#pragma config BOREN = SBORDIS  // Brown Out Detect (Enabled in hardware, SBOREN disabled)
#pragma config BORV = 3         // Brown-out Reset Voltage bits (1.8V)
#pragma config BORPWR = ZPBORMV // BORMV Power level (ZPBORMV instead of BORMV is selected)

// CONFIG2H
#pragma config WDTEN = SWDTDIS  // Watchdog Timer (WDT enabled in hardware; SWDTEN bit disabled)
#pragma config WDTPS = 1048576  // Watchdog Postscaler (1:1048576)

// CONFIG3H
#pragma config CANMX = PORTB    // ECAN Mux bit (ECAN TX and RX pins are located on RB2 and RB3, respectively)
#pragma config MSSPMSK = MSK7   // MSSP address masking (7 Bit address masking mode)
#pragma config MCLRE = ON       // Master Clear Enable (MCLR Enabled, RE3 Disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Overflow Reset (Enabled)
#pragma config BBSIZ = BB2K     // Boot Block Size (2K word Boot Block size)

// CONFIG5L
#pragma config CP0 = OFF        // Code Protect 00800-03FFF (Disabled)
#pragma config CP1 = OFF        // Code Protect 04000-07FFF (Disabled)
#pragma config CP2 = OFF        // Code Protect 08000-0BFFF (Disabled)
#pragma config CP3 = OFF        // Code Protect 0C000-0FFFF (Disabled)

// CONFIG5H
#pragma config CPB = OFF        // Code Protect Boot (Disabled)
#pragma config CPD = OFF        // Data EE Read Protect (Disabled)

// CONFIG6L
#pragma config WRT0 = OFF       // Table Write Protect 00800-03FFF (Disabled)
#pragma config WRT1 = OFF       // Table Write Protect 04000-07FFF (Disabled)
#pragma config WRT2 = OFF       // Table Write Protect 08000-0BFFF (Disabled)
#pragma config WRT3 = OFF       // Table Write Protect 0C000-0FFFF (Disabled)

// CONFIG6H
#pragma config WRTC = OFF       // Config. Write Protect (Disabled)
#pragma config WRTB = OFF       // Table Write Protect Boot (Disabled)
#pragma config WRTD = OFF       // Data EE Write Protect (Disabled)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protect 00800-03FFF (Disabled)
#pragma config EBTR1 = OFF      // Table Read Protect 04000-07FFF (Disabled)
#pragma config EBTR2 = OFF      // Table Read Protect 08000-0BFFF (Disabled)
#pragma config EBTR3 = OFF      // Table Read Protect 0C000-0FFFF (Disabled)

// CONFIG7H
#pragma config EBTRB = OFF      // Table Read Protect Boot (Disabled)


// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>
#include <stdint.h>

uint8_t tmr3Lprev = 0x00u;

void interrupt ISR(void){
    
        if(TMR3IF){
            if(TMR3L == 0x00u){  //after TMR3IF fires, TMR3L should be 0 (if PR4 is > cca 0x20)
                asm("BTG LATA, 2, 0"); //toggles with an output
            }else{
                LATAbits.LATA6 = 1;  // a failure flag
            }
            asm("BTG LATA, 1, 0"); //toggles with an output
            TMR3IF = 0;
        }
    
        if(TMR4IF){
            if(TMR3L == ++tmr3Lprev){  //TMR3L should increment on every T4 rollover
                asm("BTG LATA, 0, 0"); //toggles with an output
            }else{
                LATAbits.LATA5 = 1;  // a failure flag
            }
            TMR4IF = 0;
        }
        
    return;
}



void main(void) {
    
    //Clock setting (clock for system and all modules)
    OSCCONbits.IRCF = 0b111;
    OSCTUNEbits.PLLEN = 1; //turn on 4x Phase Lock Loop = 64MHz Clock
    
     //sets ports to output
    TRISA = 0x00; //A vse prepnout na vystup
    LATA = 0x00;

    //Timer4 initialization
    T4CONbits.T4OUTPS = 0;    //postscale, I don't know why, but doesen't effect length of T4 rollover
    T4CONbits.T4CKPS1 = 1;    //I dont know why, but T4CKPS = 0x11 doesnt set T4CKPS1 
    PR4 = 0x63;               //loop periode
    T4CONbits.TMR4ON = 1;     //1 = Timer 4 Enabled

    //Timer3 initialization
    T3CONbits.TMR3CS = 0b01;  //Clock source, 1 = system clock = Fosc; 0 = instruction clock = Fosc/4
    T3CONbits.T3CKPS = 0b10;  // 0b11 = 1:8 Prescale value; 0b10 = 1:4 Prescale value; 0b01 = 1:2 Prescale value; 0b00 = 1:1 Prescale value
    T3CONbits.SOSCEN = 0;
    T3CONbits.RD16   = 1;     //16bits wide register
    T3CONbits.TMR3ON = 1;     //1 = Timer 3 Enabled
    
    T3GCONbits.TMR3GE = 1; //Timer 3 is gated
    T3GCONbits.T3GPOL = 1; //high/low level of timer4 enables Timer3
    T3GCONbits.T3GTM = 0;  //Toggle mode disabled
    T3GCONbits.T3GSPM = 0; //Single pulse mode disabled
    T3GCONbits.T3GSS = 0x01; //TMR4 as a source

    WRITETIMER3(0x0000ul);
    TMR4 = 0x00;
    

    //interrupts handling
    PIE2bits.TMR3IE = 1;
    PIE4bits.TMR4IE = 1;
    INTCONbits.GIE = 1;
    INTCONbits.PEIE = 1;  
    
    //the infinite loop
    while(1){
  
    }
}
  • Why do you think that *Fosc/4* clock source wouldn't work? Have you tried setting `TMR3CS` bits to `0b00`? If you did it, how did you find out that the *Fosc/4* mode doesn't work? – Kozmotronik Jul 13 '22 at 08:51
  • I did it. It works fine when Timer 3 is not gated (_TMR3GE = 0_). But I need it to be gated by Timer 4 and in this case it just doesn't work correctly - yes, TMR3L and TMR3H registers are incrementing, but it just doesn't set TMR3IF flag and absolutely doesn't fire appropriate interruption (I will edit my question to be more clear, thanks for feedback). – OndraCER552 Jul 13 '22 at 09:43
  • I will explain you the cause of TMR3IF interrupt delay soon. Keep watching... – Kozmotronik Jul 13 '22 at 10:18
  • Great! I am excited! – OndraCER552 Jul 13 '22 at 10:43
  • Are you aware of that the T3 gating with T4 will give you only one intstruction cycle wide pulse to the gate of T3? – Kozmotronik Jul 14 '22 at 08:50
  • I think I misunderstood your qestions. How do you test these conditions? In the MPLAB simulator or in a real hardware? – Kozmotronik Jul 14 '22 at 08:51
  • @Kozmotronik: _Are you aware of that the T3 gating with T4 will give you only one intstruction cycle wide pulse to the gate of T3?_ : YES, there shouldn't be any problem - I wont 1 increment when TMR4 rolls over. I tested it on real HW. – OndraCER552 Jul 14 '22 at 09:27
  • hi. I have tried to reproduce your problem in the MPLAB simulator. But in simulator gated timer functions don't work well. I need a real hw so I'm gonna test it with a PIC18F46K22. – Kozmotronik Jul 15 '22 at 07:40
  • @Kozmotronik: Yes, simulator works absolutely different. Thanks for your time. But as I realized on a different forum, there is an errata about gate controle of Timer1/3 https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/Errata/PIC18F66K80-Silicon-Errata-Data-Sheet-Clarification-80000519P.pdf – OndraCER552 Jul 15 '22 at 18:24
  • Well done! I did not expect that the Microchip would make hardware mistakes like that. Microchip should have added this erratas in the microcontroller's datasheet. Well it seems that further debugging make no sense because the error is in the hardware. – Kozmotronik Jul 16 '22 at 12:45
  • Yes, unfortunately, seems there is a hardware bug. So I chose an alternative solution (I use TMR4IF ISR and check TMR3 if it is 0 - there are some more instruction, but works OK). Thanks for your time! – OndraCER552 Jul 16 '22 at 18:05
  • Hi @OndraCER552 hope you do well. Can you please answer your question with your findings and your workaround on this matter and accept your answer as solved? This would be very helpful for other developers working with similar controllers. Please consider doing it. – Kozmotronik Sep 22 '22 at 11:16

1 Answers1

1

I have spent plenty of time solving this problem (even there: https://www.microchip.com/forums/m1211315.aspx) and my conclusion is, that it is most probably a HW bug. So Timers 1 and 3 with gated control (from Timer 2/4) works properly as a timer (their registers TMR1/3H/L increment well), but they fail in triggering interrupts and setting appropriate PIR flags. So my resolution for another applications is:

  1. let's use Timers 1/3 as counters of TMR2/4 rollovers (and make a 24bit wide timer), it works well and is useful;
  2. but do not use any (including CCP) ISR function (or PIR values) rising from Timer 1/3 with gated control from Timer 2/4. I simply use ISR rising from Timer 2/4 and test Timer 1/3 state by SW.