2

I am using MPLAB X IDE version 5.43 to develop an embedded project for a PIC18F8722 microcontroller.

It has a timer TMR0 which can be configured to be 32 bits.

I had lots of statements:

TMR0L = 0;
TMR0H = 0;

that I wanted to simplify (i.e., replace) to:

TMR0 = 0;

The 3 identifiers above are defined through macro constants in the included file #include <pic18f8722.h> as shown in this snippet:

// Register: TMR0
#define TMR0 TMR0
extern volatile unsigned short          TMR0                __at(0xFD6);
#ifndef _LIB_BUILD
asm("TMR0 equ 0FD6h");
#endif

// Register: TMR0L
#define TMR0L TMR0L
extern volatile unsigned char           TMR0L               __at(0xFD6);
#ifndef _LIB_BUILD
asm("TMR0L equ 0FD6h");
#endif

// Register: TMR0H
#define TMR0H TMR0H
extern volatile unsigned char           TMR0H               __at(0xFD7);
#ifndef _LIB_BUILD
asm("TMR0H equ 0FD7h");
#endif

However, the above substitution in my code (TMR0L=0 and TMR0H=0 with TMR0=0) surprisingly DOES NOT work, i.e., the functions using TMR0 stop doing their job and give errors.

Did anybody ever notice such bizarre, strange behavior and, above all, could explain WHY it is happening?

6
  • Please don't make us to have to guess the problems. You're putting more suspense to your question than useful information like error messages. Try adding any relevant error messages and a reproducible example if possible. Commented Oct 16 at 6:11
  • @Kozmotronik Even if I can understand your feeling, try to look at my question from other perspective, which is always beneficial. It is a matter of compromise: how much time you, me and others can dedicate to this issue? Functions that stop working when I do the substitution are several, so complex that explain it thoroughly could take a long time, because I'd have to give enough context, global variables and definitions, etc. After all, everything is working fine if I don't do any constant substitution. (follows in next comment pls, a matter of text limits, not related with "suspense") Commented Oct 16 at 9:25
  • (...from the last comment) So my scope was: IF someone already experienced such a problem perhaps he had been able to tell me the reason quickly without investing too much time and I could've quickly learnt something new. I think this is within the scope of Stack Overflow. I've spent many hours in the issue trying to understand it but I failed. I can only spend little more time to follow it up, otherwise I'll keep my functioning code as it is. So sorry if the question is not appropriate, but I hope you can understand the reasons... Commented Oct 16 at 9:32
  • Hey Guille, thanks for the context. I totally get your time is valuable—mine too! I really want to help you solve this fast, but debugging without a Minimal, Reproducible Example (MWE) and the exact error message is impossible; it's just a guess. If you can simplify one failing function and show us the code plus the error output, we'll nail the bug instantly. That's the quickest way for us both. Can you share that little example? Commented Oct 17 at 19:09
  • I ran a simple simulation and everything looks OK. See this demo video: youtu.be/iFrWmlQIPt0. As far as I know, the XC8 compiler is smart enough to convert the 16-bit load operation (i.e. TMR0 = 500) into the appropriate assembly code to load the value in 8-bit chunks (i.e. movlw 0xF4 movwf TMR0L movlw 1 movwf TMR0H). This issue might be specific to your application. That's why an additional context would be helpful to catch this bug. By the way, you use XC8 compiler, don't you? You see, we have to guess everything :D. Commented Oct 17 at 19:19

1 Answer 1

2

First, take a look at section 12.1 of the PIC18F8722 datasheet!

TMR0H is not the actual high byte of Timer0 in 16-bit mode; it is actually a buffered version of the real high byte of Timer0 which is not directly readable nor writable TMR0H is updated with the contents of the high byte of Timer0 during a read/write of TMR0L. This provides the ability to read all 16 bits of Timer0 without having to verify that the read of the high and low byte were valid, due to a rollover between successive reads of the high and low byte.

So it is important the order how to write to registers. First write the high part of 16 bit value in to TMR0H register and then low part to TMR0L.

Sign up to request clarification or add additional context in comments.

3 Comments

So you are suggesting that writing (TMR0H = 0; TMR0L = 0;) or (TMR0L = 0; TMR0H = 0;) could not have the same effect of (TMR0 = 0;) because the order of writing? And in that case, in an statement TMR0 = 0, which would be the order of writing, or, in other words, TMR0 high byte (the "real" one) would be updated or not???
Exactly, it is allowed to read and write in to TMR0 when timer is running. So,TMR0 16 bit value is updated atomic in one MCPU cycle, when TMR0L is written. TMR0H is temporary register, when you read TMR0L also the content of TMR0H is updated from TMR0 high byte. You must check how compiler compile TMR0 = 0. If TMR0H is written last then you must to do your own function.
It is clear that the order of writing TMR0H and TMR0L matters. What is not absolutely clear (at least for me) is what the compiler XC8 v3.10 is doing when I do TMR0 = 0; but at this point I'll safely keep in my code TMR0H=0 and then TMR0L=0. Other research on TMR0 will be for future, thanks for your comments...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.