Keil compiler & 8051 simulator

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

Reply to
Roman Mashak
Loading thread data ...

Because 65536 = 0x010000 = to big for an int. So effectively you are subtracting from zero.

Try 65535.

Phil W

I've

to

Reload_16

I
Reply to
Phil W

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

Reply to
Thad Smith

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

??>> 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

Reply to
Roman Mashak

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

Reply to
Roman Mashak

This should not even compile

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.

Reply to
nospam

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);

Reply to
Not Really Me

"Roman Mashak" wrote in news:c7pdht$17ja$ snipped-for-privacy@mpeks.tomsk.su:

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.

Reply to
Mark A. Odell

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

Reply to
Roman Mashak

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

Reply to
Roman Mashak

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.

Reply to
Gary Kato

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		| paul@pcserv.demon.co.uk
        Main Site
              GNU H8 & mailing list info.
             For those web sites you hate.
Reply to
Paul Carpenter

....

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		| paul@pcserv.demon.co.uk
        Main Site
              GNU H8 & mailing list info.
             For those web sites you hate.
Reply to
Paul Carpenter

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

Reply to
Roman Mashak

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

Reply to
Roman Mashak

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.

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

--
Hans-Bernhard Broeker (broeker@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.
Reply to
Hans-Bernhard Broeker

35535 is 0x8ACF so the 0xCF is correct

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.

Reply to
nospam

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

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		| paul@pcserv.demon.co.uk
        Main Site
              GNU H8 & mailing list info.
             For those web sites you hate.
Reply to
Paul Carpenter

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.