Keil compiler & 8051 simulator

Do you have a question? Post it now! No Registration Necessary

Translate This Thread From English to

Threaded View
Hello, All!

    I'm studying the 8051 microcontroller and exploring now sample code I've
found. I'm using:
    - Keil C compiler v6.21
    - assembler compiler v6.20c
    - simulation DLL v2.20b

    There sre some items I can't understand. Anyway, the code I included to
this message, is doing the following:

    1) initialize Timer 2
    2) calculate the number of timer increments
    3) define 16-bit reload value
    4) split reload 16-bit value onto two 8-bit values....
    etc.

........
#define TICK_MS 30
#define OSC_FREQ (12000000UL)
#define OSC_PER_INST (12)

void Init_Timer2(const tByte TICK_MS)
   {
   tLong Inc, Reload_long;
   tWord Reload_16;
   tByte Reload_08H, Reload_08L;

   // Timer 2 is configured as a 16-bit timer,
   // which is automatically reloaded when it overflows
   T2CON   = 0x04;   // Load Timer 2 control register

   // Number of timer increments required (max 65536)
   Inc = ((tLong)TICK_MS * (OSC_FREQ/1000)) / (tLong)OSC_PER_INST;

   // 16-bit reload value
   Reload_16 = (tWord) (65536UL - Inc);
//   Reload_long = (tLong) (65536UL - Inc);

   // 8-bit reload values (High & Low)
   Reload_08H = (tByte)(Reload_16 / 256);
   Reload_08L = (tByte)(Reload_16 % 256);

   // Used for manually checking timing (in simulator)
   //P2 = Reload_08H;
   //P3 = Reload_08L;

   TH2     = Reload_08H;   // Load Timer 2 high byte
   RCAP2H  = Reload_08H;   // Load Timer 2 reload capt. reg. high byte
   TL2     = Reload_08L;   // Load Timer 2 low byte
   RCAP2L  = Reload_08L;   // Load Timer 2 reload capt. reg. low byte

   // Timer 2 interrupt is enabled, and ISR will be called
   // whenever the timer overflows.
   ET2     = 1;

   // Start Timer 2 running
   TR2   = 1;

   EA = 1;            // Globally enable interrupts
   }

    When I'm doing tracing of the code, I find that the value of  Reload_16
is set to 0x00D0 (in hex), but it should be:

   Inc =  ( 30 * (12000000/1000) ) / 12 = 30000, that's OK, clear...
    Reload_16 =  65536-30000  = 35536,  0x8AD0 in hex

    But how?

    And then Reload_08H and Reload_08L appeared to be: 0xD0 and 0xD0,  so I
still don't understand....

    I'm sorry if my question is too silly, so please direct me onto some
useful resource. Thanks in advance!

With best regards, Roman Mashak.  E-mail: snipped-for-privacy@tusur.ru



Re: Keil compiler & 8051 simulator
Because 65536 = 0x010000 = to big for an int. So effectively you are
subtracting from zero.

Try 65535.

Phil W


Quoted text here. Click to load it
I've
to
Reload_16
I



Re: Keil compiler & 8051 simulator
Hello, Phil!
You wrote  on Tue, 11 May 2004 15:21:51 +1000:

 PW> Try 65535.

    I tried... In this case Reload_16=0x00CF, that's 207. So, it's not the
reason, I guess.

 PW> Phil W

 ??>> Hello, All!
 ??>>
 ??>>     I'm studying the 8051 microcontroller and exploring now sample
 ??>> code
 PW> I've
 ??>> found. I'm using:

With best regards, Roman Mashak.  E-mail: snipped-for-privacy@tusur.ru



Re: Keil compiler & 8051 simulator

Quoted text here. Click to load it

How is tWord defined?  If it is unsigned char, you would get rhe results
  you specify.  Otherwise, watch the execution in the simulator and find
out.

Thad


Re: Keil compiler & 8051 simulator
Hello, Thad!
You wrote  on Mon, 10 May 2004 23:41:19 -0600:

 ??>> Timer 2 control register    // Number of timer increments required
 ??>> (max 65536)   Inc = ((tLong)TICK_MS * (OSC_FREQ/1000)) /
 ??>> (tLong)OSC_PER_INST;    // 16-bit reload value   Reload_16 = (tWord)
 ??>> (65536UL - Inc); //   Reload_long = (tLong) (65536UL - Inc);

 TS> How is tWord defined?  If it is unsigned char, you would get rhe
 TS> results you specify.  Otherwise, watch the execution in the simulator
 TS> and find out.
    tWord is defined as 'unsigned int'.

With best regards, Roman Mashak.  E-mail: snipped-for-privacy@tusur.ru



Re: Keil compiler & 8051 simulator

Quoted text here. Click to load it


This should not even compile

Quoted text here. Click to load it

I would suspect what the simulator is showing you did you actually inspect
T2H and T2L ? The variables you are looking at are likely to be assigned to
registers and/or optimised away completely. Try turning off all compiler
optimisation.


Re: Keil compiler & 8051 simulator
Hello, nospam!
You wrote  on Tue, 11 May 2004 14:22:18 +0100:

 ??>> void Init_Timer2(const tByte TICK_MS)

 n> This should not even compile
    Nevertheless it did...
 ??>>    When I'm doing tracing of the code, I find that the value of
 ??>> Reload_16 is set to 0x00D0 (in hex), but it should be:   Inc =  ( 30 *
 ??>> (12000000/1000) ) / 12 = 30000, that's OK, clear...   Reload_16 =
 ??>> 65536-30000  = 35536,  0x8AD0 in hex    But how?    And then
 ??>> Reload_08H and Reload_08L appeared to be: 0xD0 and 0xD0,  so I still
 ??>> don't understand....

   Now I changed code a little using the advice from this conference. I
assigned variables Inc and Reload_16 as 'static':

   static tLong Inc, Reload_long;
   static tWord Reload_16;
   staic tByte Reload_08H, Reload_08L;

    And I changed to  65536 to 65535  ->   Reload_16 = (tWord) (65535UL -
Inc);

    Reload_08H = (tByte)(Reload_16 / 256);
   Reload_08L = (tByte)(Reload_16 % 256);

    In this case I got the following:

    'Inc' is calculated correctly,  'Reload_16'  also....
    Reload_08H got 0x8A (OK), Reload_08L is 0xCF - why?  If we make '%'
operation (35535 % 256) - it should take division remainder, i.e. 80.

    And now is the most intersting: TH2 and TL2. TH2 is assigned correctly,
i.e. 0x8A, but TL2 is 0xD1 now, so it was increased with 2, why?

    Thank you for any help!

With best regards, Roman Mashak.  E-mail: snipped-for-privacy@tusur.ru



Re: Keil compiler & 8051 simulator
One of the things you should do is look at the atual instructions that the
compiler generates to see why it does certain things. You have a simulator so
you should be able to single step and see exactly what is going on. You don't
seem to be doing that and just guessing at what the compiler has done.

Re: Keil compiler & 8051 simulator

Quoted text here. Click to load it
....

Why are you not just simply getting the low byte by anding with 0xFF ?

It may just by that the modulus function is not correctly linked in.
Use a simpler method as modulus '%' is nearly always some form of
library function, which can need all sorts of extra code loaded.

--
Paul Carpenter        | snipped-for-privacy@pcserv.demon.co.uk
<http://www.pcserv.demon.co.uk/ Main Site
We've slightly trimmed the long signature. Click to see the full one.
Re: Keil compiler & 8051 simulator
Hello, Paul!
You wrote  on Wed, 12 May 2004 06:49:09 +0000 (UTC):

 ??>>    'Inc' is calculated correctly,  'Reload_16'  also....
 ??>>    Reload_08H got 0x8A (OK), Reload_08L is 0xCF - why?  If we make '%'
 ??>> operation (35535 % 256) - it should take division remainder, i.e. 80.

 PC> Why are you not just simply getting the low byte by anding with 0xFF ?

 PC> It may just by that the modulus function is not correctly linked in.
 PC> Use a simpler method as modulus '%' is nearly always some form of
 PC> library function, which can need all sorts of extra code loaded.

    As I said before, I'm studying this microcontroller, so I would like to
understand this code, and find the error!
    By the way, this source code was provided in the book by Michael J. Pont
"Embedded C".

With best regards, Roman Mashak.  E-mail: snipped-for-privacy@tusur.ru



Re: Keil compiler & 8051 simulator

Quoted text here. Click to load it
 
35535 is 0x8ACF so the 0xCF is correct

Quoted text here. Click to load it

Without checking the timer documentation and modes I am not sure but make
sure the timer is stopped before you configure it and configured in the
right mode before you start it. It is the function of the timer in some
modes to increment TL2 so the value you load may be incremented by the
timer hardware before you inspect it.


Re: Keil compiler & 8051 simulator
Quoted text here. Click to load it

Try this change.  It may not be the "correct" solution, but it seems to
work:

void Init_Timer2( const tByte tick)
   {
   static   tLong Inc, Reload_long;
   static   tWord Reload_16;
   tByte Reload_08H, Reload_08L;


   // Timer 2 is configured as a 16-bit timer,
   // which is automatically reloaded when it overflows
   T2CON   = 0x04;   // Load Timer 2 control register

   // Number of timer increments required (max 65536)
   Inc = ((tLong)TICK_MS * (OSC_FREQ/1000)) / (tLong)OSC_PER_INST;

   // 16-bit reload value
   Reload_long = (tLong) (65536UL - Inc);
   Reload_16 = (tWord) Reload_long;

   // 8-bit reload values (High & Low)
   Reload_08H = (tByte)(Reload_16 / 256);
   Reload_08L = (tByte)(Reload_16 % 256);



Re: Keil compiler & 8051 simulator
Hello, Not!
You wrote  on Tue, 11 May 2004 10:00:44 -0600:

 NRM> Try this change.  It may not be the "correct" solution, but it seems
 NRM> to work:

 NRM> void Init_Timer2( const tByte tick)
 NRM>    {
 NRM>    static   tLong Inc, Reload_long;
 NRM>    static   tWord Reload_16;
 NRM>    tByte Reload_08H, Reload_08L;

 NRM>    // Timer 2 is configured as a 16-bit timer,
 NRM>    // which is automatically reloaded when it overflows
 NRM>    T2CON   = 0x04;   // Load Timer 2 control register

 NRM>    // Number of timer increments required (max 65536)
 NRM>    Inc = ((tLong)TICK_MS * (OSC_FREQ/1000)) / (tLong)OSC_PER_INST;

 NRM>    // 16-bit reload value
 NRM>    Reload_long = (tLong) (65536UL - Inc);
 NRM>    Reload_16 = (tWord) Reload_long;

    Thank you very much! It's really worked out.
    It seems compiler cannot make type casting correctly and assign 'tLong'
value to 'tWord' variable ?

With best regards, Roman Mashak.  E-mail: snipped-for-privacy@tusur.ru



Re: Keil compiler & 8051 simulator
Quoted text here. Click to load it

Have you checked whether you have something set in the compiler to say
an 'int' is 32 bit?

Try using tWord defined as an unsigned short?

After that check the assembly code and what registers are actually being
changed at each instruction. That is what the simulator is for debugging
the code.

--
Paul Carpenter        | snipped-for-privacy@pcserv.demon.co.uk
<http://www.pcserv.demon.co.uk/ Main Site
We've slightly trimmed the long signature. Click to see the full one.
Re: Keil compiler & 8051 simulator
Hello, Paul!
You wrote  on Wed, 12 May 2004 06:49:08 +0000 (UTC):

 ??>>    Thank you very much! It's really worked out.
 ??>>    It seems compiler cannot make type casting correctly and assign
 ??>> 'tLong' value to 'tWord' variable ?

 PC> Have you checked whether you have something set in the compiler to say
 PC> an 'int' is 32 bit?
    It's all fine...
 PC> Try using tWord defined as an unsigned short?

    Yes, I tried, but nothing changed.... They all have the same width - 32
bits.

 PC> After that check the assembly code and what registers are actually
 PC> being changed at each instruction. That is what the simulator is for
 PC> debugging the code.

 I was fighting with assembler debugger for some time :) and what I've
found. All code is correctly processed, except this part :

   TH2     = Reload_08H;            -> MOV   TH2(0xCD), 0x12
   RCAP2H  = Reload_08H;        -> MOV   RCAP2H(0xCB), 0x12
   TL2     = Reload_08L;              ->  MOV  TL2(0xCC), 0x13
   RCAP2L  = Reload_08L;          ->  MOV  RCAP2L(0xCA),  0x13

So, TH2 is correctly setup (0x8A), RCAP2H also, BUT TL2 is incorrectly setup
(0xD1 instead of 0xCF), while RCAP2L is fine! It seems to me that timer is
getting increasing, but it's not turned on at this time, because line TR2 is
beneath.....

Moreover, the memory window is showing absolutely correct values calculated
during the program.

What else can you recommend?

With best regards, Roman Mashak.  E-mail: snipped-for-privacy@tusur.ru



Re: Keil compiler & 8051 simulator

Quoted text here. Click to load it


Most certainly not.  On an 8051 compiler, both int and short will
almost invariably be 16-bit data types.  You don't want to use 32 bit
types any more than you absolutely have to, on such a small CPU.

Quoted text here. Click to load it

I'm still not convinced.  Show actual assembly output from the listing
file please.

--
Hans-Bernhard Broeker ( snipped-for-privacy@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.

Re: Keil compiler & 8051 simulator
On Thursday, in article
Quoted text here. Click to load it

All compilers have options, I never said it was the problem, but
'may be his problem', which is slightly different.

Quoted text here. Click to load it

He claimed in an earlier post that he was getting 32bit values (probably
finger trouble or simulator operation issue), however there are always
possibilities of misconfiguring compilation.

It is not 'incorrect' for GCC in general to do this as on some processors
some registers can be accessed as 32 bit and 32 bit operations exist for them
as well. Hence for some applications it is a choice, whether it is a
good choice is not a matter I would want to debate. For this processor
I would never remotely suggest it should be used, but some people assume
more bits is always better.

--
Paul Carpenter        | snipped-for-privacy@pcserv.demon.co.uk
<http://www.pcserv.demon.co.uk/ Main Site
We've slightly trimmed the long signature. Click to see the full one.
Re: Keil compiler & 8051 simulator

Quoted text here. Click to load it

This is how I remember doing it. First, let the pre-processor do the math,
not the CPU. E.g.

/* 1000 T2 ticks is my example timer interval, the minus sign
** makes it all work for incrementing timers.
*/
#define NUM_TICKS     -1000
#define T2_RELOAD_HI  (NUM_TICKS >> 8)
#define T2_RELOAD_LO  (NUM_TICKS & 0xFF00)

...

/* Be sure T2 is stopped. Load T2 up to run at NUM_TICKS
** interval.
*/
RCAP2H = T2_RELOAD_HI;   // Useless comment removed
RCAP2L = T2_RELOAD_LO;   // Useless comment removed
T2H    = T2_RELOAD_HI;   // Useless comment removed
T2L    = T2_RELOAD_LO;   // Useless comment removed

/* Start T2
*/

I seem to remember something about need to write to TL2 first or last,
maybe I'm thinking of something else.

Site Timeline