(solved) MPLABX PIC16F54 Timer Prescaler not working as expected (new title)

Thread Starter

Travm

Joined Aug 16, 2016
345
Here's the code, but this is more of a question.
My code seems to execute ok on the actual hardware, but when running on the simulator, it appears that setting the TMR0 prescaler has no effect on the TMR0 counter. I've tried setting OPTION = 000000, and it seems that TMR0 increments at the same rate when stepping through the program in the debugger (simulator) as it does when OPTION = 000111. Also setting a watch on OPTION seems to show it as 0x00 regardless of setting as well.

Is this a bug in the simulator? Or am I doing this wrong?
Code:
 /*
* File:   Main1.c
* Author: Travis
*
* Created on May 18, 2020, 1:30 PM
*/
// CONFIG
#pragma config OSC = XT         // Oscillator selection bits
#pragma config WDT = OFF         // Watchdog timer enable bit
#pragma config CP = OFF         // Code protection bit

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

#define _XTAL_ 4000000
#include <xc.h>
#include <stdlib.h>
#include <stdio.h>



const char (seg7set[11]) = {
    0b00001000, //0
    0b01101011, //1
    0b01001000, //2
    0b01000001, //3
    0b00100011, //4
    0b00010001, //5
    0b00010000, //6
    0b01001011, //7
    0b00000000, //8
    0b00000001, //9
    0b01111111, //clear
};
const char (timer_m_values[8]) = {
    3,
    4,
    5,
    6,
    7,
    8,
    9,
    10
};
    /*********************************************************
     * Global Variables
     * variables for clocks
    **********************************************************/
   
    int dotflash;
    char previousclk = 0;
    char ansel = 0;
   
    /*********************************************************/
    /*Function for advancing timer based clocks*/
    void advanceclocks (void){
          if (previousclk > TMR0) //advance item clocks here
        {
            dotflash++;
            ansel++;
        }
        else
        {
            previousclk = TMR0;
        }
    }

   
void main(void) {
    TRISA = 0b1010; //RA3 gets tri-stated to turn off AN1 and AN2,
                    //RA1 must be high imp. its connected straight to ground
    OPTION = 000111;  //Options - Prescaler set at 1:256
    TRISB = 0b00000000; //All PortB Pins are I/O
   

    char pba = 0b10000000;  //PortB Anode  This must be toggled to enable/disable the anode in port B (adds with portbset)
    char time_s = 0;  // timer
    char digit = 0;  // for setting each digit

    RA3=1; //Anode 1 and 2 - tristate this pin to turn off
    //PORTAbits.RA3=1;  //this is here from previous attempts at troubleshooting, does the same as above.
    RB7=1; //Anode 3 start on Anode 3, or the if statement flow doesnt work

    while(1) {      
        //clocks
        advanceclocks() ;
           
        if (dotflash==4000)  //4000 cycles is approx 1s
        {
            if (RA0==1) RA0=0;
            else if (RA0==0) RA0=1;
            dotflash=0;
        }
       
        if (ansel>15)  // This is the display multiplexor
        {
            if (RB7==1)
            {
                //clear the display
                RB7=0;
                pba=0b00000000;
                TRISA = 0b0010;
                RA3=1;
            //activate display
            }
            else if (RA3==1)
            {
                //clear the display
            RA3=0;
            //activate display
            }
            else if (RA3==0)
            {
                TRISA = 0b1010;
                RB7=1;
                pba=0b10000000;
        //activate display
            }
           ansel=0;
        }
// end of display multiplexor
       
       if (RA1==0)
       {
           PORTB = seg7set[0]+pba;
       }
       else
       {
        PORTB = seg7set[3]+pba;  
       }    
    }
    return;
}
 
Last edited:

Thread Starter

Travm

Joined Aug 16, 2016
345
Correction, the code does not work as expected..... changing prescaler has no effect. must be doing something wrong.
edit;
So i figured out that I wasn't telling the compiler that my OPTION register should be in binary; so now I have OPTION = 0b000111,
but there is still something not right with my code. Not sure it applies to the original question.
 
Last edited:

Thread Starter

Travm

Joined Aug 16, 2016
345
So it looks like I can't get the prescaler to work properly on my PIC16F54;
I've tried;
OPTION = 0b00000111;
OPTION = 0x07
OPTION = 0b000111;

and the 0b000000 equivalent for each of the above.
No matter what I do it doesnt seem to affect the period of TMR0. Otherwise the code seems to work. Any thoughts?
 
I haven't worked with this one yet, but it looks the the prescale may not be available for timer mode. In section 7.0 just above figure 7-1 on the left says "In timer mode the timer0 module will increment every instruction cycle (without prescaler)".

The prescaler isn't mentioned until the next section about counter mode. It may be just the way I'm looking at it, but I have found hidden details like this a few other times. if you can run it in counter mode for a test it may be worth a shot.
 

Thread Starter

Travm

Joined Aug 16, 2016
345
I wasn't sure if I had tested that, but thought I had. Setting it to "counter mode" causes the timer to not function (T0CKI pin is tied to gnd w/ 20k resistor).

I guess i'll have to breadboard a simple little set-up to see if thats the case. Going to be very annoyed if thats what they meant by that. Looking at the functional block diagrams it doesn't appear to be the case though.
 

sagor

Joined Mar 10, 2019
479
In the PIC16F5x datasheet, it clearly states there is a prescaler. How it is set may be an issue... Maybe re-check which clock it is set for.
The Timer0 module has the following features:
• 8-bit Timer/Counter register, TMR0
- Readable and writable
• 8-bit software programmable prescaler
• Internal or external clock select
- Edge select for external clock
Try OPTION register = 0, which gives 1:2 ratio based on internal clock. Then, you can change prescaler up to 0b00000111. Using internal clock, it seems only the lower 3 bits of OPTION register are relevant as long as bit 5 = 0
Remember when running any kind of debugging, the timer may be running while the code is paused, or other wierd symptoms.
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,551
EDITED: You are not specifying the radix for the OPTION value and the compiler is defaulting to OCTAL 111 = 49h as shown in the first instance of the disassembly listing below. Your specification for OPTION and again with a proper constant is shown:
Code:
78:                // **** INCOMPLETE SPECIFICATION GENERATES INVALID VALUE FOR OPTION
79:                OPTION = 000111;  //Options - Prescaler set at 1:256
0102  0C49     MOVLW 0x49
0103  0002     OPTION
80:     
81:                //****  USING COMPLETE VALUES AND SPECIFIED RADIX GENERATES CORRECT CODE
82:                OPTION = 0b00000111;
0104  0C07     MOVLW 0x7
0105  0002     OPTION
XC8 Ver 2.32 Free Mode
MPLABX 5.45
YMMV

EDIT: This is a good reason to always specify the radix in your constants in the source code. OCTAL is traditionally the default radix for C. It is also preferable to specify complete 8 bit values to help avoid justification errors. Never use a command line compiler switch to specify a new default radix - it's too easy to miss when coming back to the project after an absence.
Just my .02

EDIT2: FWIW, the sim indicates that the prescaler is working after the correct value is written to OPTION
 
Last edited:

Thread Starter

Travm

Joined Aug 16, 2016
345
EDITED: You are not specifying the radix for the OPTION value and the compiler is defaulting to OCTAL 111 = 49h as shown in the first instance of the disassembly listing below. Your specification for OPTION and again with a proper constant is shown:
Code:
78:                // **** INCOMPLETE SPECIFICATION GENERATES INVALID VALUE FOR OPTION
79:                OPTION = 000111;  //Options - Prescaler set at 1:256
0102  0C49     MOVLW 0x49
0103  0002     OPTION
80:     
81:                //****  USING COMPLETE VALUES AND SPECIFIED RADIX GENERATES CORRECT CODE
82:                OPTION = 0b00000111;
0104  0C07     MOVLW 0x7
0105  0002     OPTION
XC8 Ver 2.32 Free Mode
MPLABX 5.45
YMMV

EDIT: This is a good reason to always specify the radix in your constants in the source code. OCTAL is traditionally the default radix for C. It is also preferable to specify complete 8 bit values to help avoid justification errors. Never use a command line compiler switch to specify a new default radix - it's too easy to miss when coming back to the project after an absence.
Just my .02
In post 3 is that not noted as something I've tried?

Although your post reminds me I can look at the compiler generated assembly code can't I? There may be some more hints in there, even if I don't read it well.
 

Thread Starter

Travm

Joined Aug 16, 2016
345
Figured it out; stupid me.
So;
Code:
currentclk=TMR0 ;
        if (previousclk > currentclk) //advance item clocks here
        {
                dotflash++;
                ansel++;
        }
        else
        {
            previousclk = currentclk;
        }
This is basically what I had originally (slightly different, but the problem was still there). What would happen is eventually (likely within the first second) previousclk would get set to 255, and since I didn't have anything resetting it, currentclk would never get set higher, and the item clocks would start advancing at full device speed (way too fast) instead of waiting for what should be a TMR0 rollover. New code works, and I learned 2 or 3 new things just from this thread (would have never thought to look at the compiler ASM files).

Code:
currentclk=TMR0 ;
        if (previousclk > currentclk) //advance item clocks here
        {
                dotflash++;
                ansel++;
                previousclk = 0;
        }
        else
        {
            previousclk = currentclk;
        }
This fixed it;

Much thanks @JohnInTX for clearing up that I was barking up the wrong tree on the prescaler (even though initially it was wrong too). And everyone else that took the time to read and offer assistance.
 
Top