Problem with Timer0 rollover time -pic16f1503

Discussion in 'Embedded Systems and Microcontrollers' started by hunterage2000, Oct 5, 2016.

  1. hunterage2000

    Thread Starter Active Member

    May 2, 2010
    400
    0
    I tried the below code expecting a Timer rollover every 200us with:

    fosc/4 = 1MHz = 1us
    prescaler = 256
    TMR0 = 256 - 200 = 56

    but I'm getting 21.8us and even changing the prescaler to 2 it remains 21.8us. The code is wrong but I can't see where.

    Anyone see what could be the problem?

    Code (Text):
    1. #include <stdio.h>
    2. #include <pic16f1503.h>
    3. #include <stdlib.h>
    4. #include <xc.h>
    5. // CONFIG1
    6. #pragma config FOSC = INTOSC    // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin)
    7. #pragma config WDTE = OFF        // Watchdog Timer Enable (WDT enabled)
    8. #pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
    9. #pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
    10. #pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
    11. #pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
    12. #pragma config CLKOUTEN = ON    // Clock Out Enable (CLKOUT function is enabled on the CLKOUT pin)
    13.  
    14. // CONFIG2
    15. #pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
    16. #pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
    17. #pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
    18. #pragma config LPBOR = OFF      // Low-Power Brown Out Reset (Low-Power BOR is disabled)
    19. #pragma config LVP = ON      
    20. void delay(void);
    21.  
    22. void main()
    23. {
    24.     OSCCONbits.SCS = 0b10;
    25.     OSCCONbits.IRCF = 0b1101;
    26.     TRISCbits.TRISC3 = 0;
    27.     OPTION_REGbits.TMR0CS = 0;
    28.     OPTION_REGbits.PSA = 0;
    29.     OPTION_REGbits.PS = 0b000;
    30.  
    31.     while(1)
    32.     {
    33.         //LATCbits.LATC3 = 0;
    34.       LATCbits.LATC3 = !LATCbits.LATC3;
    35.        delay();
    36.     }
    37. }
    38.  
    39. void delay()
    40. {
    41.     TMR0 = 56;
    42.     INTCONbits.T0IE = 1;
    43.  
    44.     while (INTCONbits.T0IF == 0)
    45.     {
    46.         ;
    47.     }
    48. }
     
  2. dannyf

    Well-Known Member

    Sep 13, 2015
    1,806
    361
    Not enough time to execute your isr.
     
  3. AlbertHall

    Well-Known Member

    Jun 4, 2014
    1,940
    383
    Having the prescaler at 256 and a clock every 1uS means that the timer will increment once every 256uS.
     
  4. hunterage2000

    Thread Starter Active Member

    May 2, 2010
    400
    0
    you mean an interrupt?
     
  5. AlbertHall

    Well-Known Member

    Jun 4, 2014
    1,940
    383
    Having had a longer look:
    The TMR0 prescaler is actually set to 2:1, so TMR0 will increment every 2uS.
    In the delay routine you enable the TMR0 interrupt but there is no interrupt routine.
    In the delay routine you wait until TMR0IF is set but you never reset it so it will be set forever.

    To make it work as you want:
    Set PSA = 1 - prescaler not assigned to TMR0. The timer will increment every 1uS.
    In the delay routine after setting the TMR0 value, reset the TMR0IF flag.
     
  6. dannyf

    Well-Known Member

    Sep 13, 2015
    1,806
    361
    Don't enable t0ie.
     
  7. hunterage2000

    Thread Starter Active Member

    May 2, 2010
    400
    0
    Ok so now PSA = 1 and I have cleared the TMR0 flag. I ran it and the oscilloscope is measuring 220us. I tried 256 - 1 = 255 thinking this might make it 1us but it is 1ms. Any ideas why?
     
  8. AlbertHall

    Well-Known Member

    Jun 4, 2014
    1,940
    383
    The uC is executing one instruction in 1uS (jumps take 2uS) so you will not get correct results trying to get 1uS delay. You would get that from a single instruction with no time left to toggle a pin.

    The delay for an expected 200uS is longer than expected than expected because the uC is executing other instructions before/after the delay loop - return from delay; toggle the pin; call delay routine...

    To get it exact either make the delay shorter to allow for the overhead, or use the TMR0 interrupt.

    The delay you have is called a blocking delay because the uC can do nothing during the delay period. Depending on what you use the delay for this may not matter. One advantage of using the interrupt version is that the uC can do other stuff while waiting for the end of the delay period. In this case toggling a pin.
     
  9. dannyf

    Well-Known Member

    Sep 13, 2015
    1,806
    361
    the following generates 50us stops consistently:

    Code (Text):
    1.  
    2.         //alternative #2
    3.         IO_FLP(OUT_PORT, OUT);                //flip the output pin
    4.         tmr0_delay(OUT_DLY);                //waste time
    5.  
    OUT_DLY is defined as 50.
     
  10. AlbertHall

    Well-Known Member

    Jun 4, 2014
    1,940
    383
    BTW As you are apparently using XC8 then there is a built-in accurate delay routines.
    At the top of the program:
    #define _XTAL_FREQ 4000000 // Tells the delay routines what the clock frequency is.

    Then use __delay_us(constant_expression) or __delay_ms(constant_expression)
    Note they begin with a double underscore.
     
  11. ci139

    Member

    Jul 11, 2016
    341
    38
    unit tme2;

    interface uses windos,sysx;

    function GetLongTime: longint; function MakeTime(tm: longint): String;
    function GetSC: double;
    function GetOSTime: longint; function MakeOSTime(tm: longint): String;

    implementation var ctm : longint absolute 0:$46C; { timer value holder }

    function GetLongTime : longint; begin GetLongTime := ctm end;

    const SC:double=18.2064815;{ the min interval between timer ticks is ÷ 55ms }

    function MakeTime(tm: longint): String; var tst: string; dd,cr: longint;
    hh,mm,ss,cc,rr : longint; { ctm receives timer updates SC times per second }
    begin dd:=0; tm:=tm*3*3*3*2*2*2*5; { ++ ~ NEW ! ~ ! iNsAnE ~ ~ ~ }
    { when ctm reaches 1573040-1 then next update is resetting it back to zero }
    hh:=tm div 70786800; rr:=tm mod 70786800; { updateing and the date value }
    mm:=rr div 1179780; rr:=rr mod 1179780;
    ss:=rr div 19663; rr:=rr mod 19663; cc:=Round(100*rr/19663);
    if cc>99 then begin cr:=cc div 100; cc:=cc mod 100; ss:=ss+cr;
    if ss>59 then begin cr:=ss div 60; ss:=ss mod 60; mm:=mm+cr;
    if mm>59 then begin cr:=mm div 60; mm:=mm mod 60; hh:=hh+cr;
    if hh>23 then begin cr:=hh div 24; cc:=hh mod 24; dd:=dd+cr end end end end;
    tst := frm(dcs(hh),2) + ':';
    tst := tst + frm(dcs(mm),2) + ':';
    tst := tst + frm(dcs(ss),2) + '.';
    tst := tst + frm(dcs(cc),2); MakeTime:=tst end;

    function GetSC:double; begin GetSC:=SC end;

    function GetOSTime:longint; var hh,mm,ss,cc:word; rv,zt:longint;
    begin GetTime(hh,mm,ss,cc); rv:=0+hh; zt:=rv shl 6;
    rv:=0+mm; zt:=(zt or rv)shl 6; rv:=0+ss; zt:=(zt or rv)shl 7;
    rv:=0+cc; zt:=zt or rv; GetOSTime:=zt end;

    function MakeOSTime(tm : longint) : String;
    var hh,mm,ss,cc,zt: longint; ost: string;
    begin
    cc:=tm and $7F; tm:=tm shr 7; ss:=tm and $3F; tm:=tm shr 6;
    mm:=tm and $3F; tm:=tm shr 6; hh:=tm and $1F;
    ost:=frm(dcs(hh),2)+':'; ost:=ost+frm(dcs(mm),2)+':';
    ost:=ost+frm(dcs(ss),2)+'.'; ost:=ost+frm(dcs(cc),2); MakeOSTime:=ost end;

    begin SC:=1573040/24/3600 end.
     
  12. AlbertHall

    Well-Known Member

    Jun 4, 2014
    1,940
    383
    o_O
     
    hunterage2000 likes this.
  13. ci139

    Member

    Jul 11, 2016
    341
    38
    there's decades ago when such was done -- this likely resolved the issue (don't remember the details how it was tracked dn - was not so obvious at 1-st)

    the first result by googling for INTCONbits.T0IE OR INTCONbits.T0IF
    http://picguides.com/beginner/timers.php
     
    Last edited: Oct 7, 2016
  14. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,387
    1,605
    Is there some good reason you are not using Timer2 for this task?

    Once configured Timer2 is designed to give you regularly spaced events completely determined and regulated by hardware only.
     
Loading...