Unsigned long int to ASCII conversion  - failed

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Unsigned long int to ASCII conversion  - failed

Jump to solution
3,941 Views
gooral
Contributor I

Hi,

 

I'm playing with small project based on JM60 and developed in CW 10.1.

 

Rough description:

uC reads four 8-bit registers from peripherial (HCTL-2032 Quadrature-decoder/counter) connected to rotary encoder and display result on LCD.

 

To this point everything works fine. I can observe register contetnt on LCD  in four groups eg. 255-255-255-255 (B4-B3-B2-B1)

 

Now I'm trying to convert this 8-bit groups to unsigned long int (eg 0xFF FF FF FF) and then to ASCII using :

 

 

unsigned long int result_unsigned_int;

char out_ASCII[11];

 

result_unsigned_int=(BYTE4*0x1000000)+(BYTE3*0x10000)+(BYTE2*0x100)+BYTE1;

sprintf(out, "%lu", result);

WriteStringToLCD(out);

 

 

It works in ordinary c complier on PC but it doesn't in CW - something stucks nothing happens

 

Can you tell me why? (Is there some restricions in sprintf in CW)

 

PS

Of  course I use same WriteStringToLCD() to display other inforation and it works fine....

 

Regards

Labels (1)
Tags (1)
0 Kudos
1 Solution
1,611 Views
CompilerGuru
NXP Employee
NXP Employee

What do you mean with stuch? Does sprintf not return? if that is the case I would try to increase the stack space.

 

There are different versions in different libraries provided, some support floating point, some not. But all of the

versions do support printing long. Especially the floating point versions need quite a bit of stack space.

 

Daniel

View solution in original post

0 Kudos
12 Replies
1,611 Views
Lundin
Senior Contributor IV

Why would you use sprintf() in an embedded application?

 

void gpfunc_getDecStr (uint8* str, uint8 len, uint32 val)
{
  uint8 i;
 
  for(i=1; i<=len; i++)
  {
    str[len-i] = (uint8) ((val % 10UL) + '0');
    val/=10;
  }
 
  str[i-1] = '\0';
}

 

That simple snippet takes 76 bytes on my S12. Personally, I have no particular urge to blow several kb of flash and RAM to do the very same thing with sprintf(), in a much slower fashion.

0 Kudos
1,611 Views
gooral
Contributor I

Lundin    I've just started uC and C programming so sprintf was first choose (easiest).

Your code shows me a different point of view and of coures it works fine!

Beauty of C....

 

Thanks!

0 Kudos
1,612 Views
CompilerGuru
NXP Employee
NXP Employee

What do you mean with stuch? Does sprintf not return? if that is the case I would try to increase the stack space.

 

There are different versions in different libraries provided, some support floating point, some not. But all of the

versions do support printing long. Especially the floating point versions need quite a bit of stack space.

 

Daniel

0 Kudos
1,611 Views
kef
Specialist I

gooral,

 

Are BYTE_X variables long integers? If not, then result

 

result_unsigned_int=(BYTE4*0x1000000)+(BYTE3*0x100​00)+(BYTE2*0x100)+BYTE1;

 

^^ is always not higher than 0xFFFF on C target machines with 16-bits int's. You need to convert at least BYTE_4 and BYTE_3 or those two >0xFFFF multiplier constants  to long, else it won't work when int is 16 bits wide.

0 Kudos
1,611 Views
CompilerGuru
NXP Employee
NXP Employee

It might not be the most efficient way to code it, but I think that the original code should work.

BYTE3/BYTE4 do not need to be longs because they are multiplied with long constants, so the multiplication gets performed with enough bits anyhow.

 

Hmm on a second thought the BYTE2*0x100 summand is problematic.  The issue is that multiplication result tyoe is probably an signed int (probably, as it depends on the not given type of BYTE2), not of type unsigned int (or long, unsigned long).

And if it is int, then it gets sign extended to a long...

 

To fix that, use 0x100u or else the highest bit of BYTE2 may count as -2^^16...

 

I tipically write it with shifts, and then an explicit cast to (unsigned) long is necessart when shifting by 16 or more bits.

 

Anyhow I guess the issue in the end is too little stack space allocated.

 

Daniel

 

BTW: It's also a bit uncommon that a variable called result_unsigned_int has a type of unsigned long :smileyhappy:.

0 Kudos
1,611 Views
kef
Specialist I

Compilerguru,

 

yes, it's not the case using Codewarrior S12(X), that  char * 0x10000  or short * 0x10000 are chopped to 16bits. I'm not sure if this should be the same using other compilers. I believed that constant isn't long without L suffix, even if it is more than 0xFFFF. Is it? In all compilers? You must be right, I should consult C specs.

 

 

So what result from above should give for char BYTE4..1 set to 0xF4,0xF3..0xF1?

 

a).BYTEn are unsigned char's:

 

byte4 * 0x1000000 should give 0xF4000000, of course if constant is treated as long.

byte3 * 0x10000 , should give 0x00F30000

byte2 * 0x100 gives int = 0xF200, which is then sign extended to long givinh 0xFFFFF200

byte1 directly converted to long gives 0x000000F1.

The sum should be 0xF4F2F2F1

 

b) BYTEn are signed char's:

 

byte4 * 0x1000000 should give 0xF4000000

byte3 * 0x10000 , should give 0xFFF30000

byte2 * 0x100 gives int = 0xF200, which is then sign extended to long givinh 0xFFFFF200

byte1 directly converted to long gives 0xFFFFFFF1.

The sum should be 0xF3F2F1F1

 

0 Kudos
1,611 Views
gooral
Contributor I

Thanks for discussion!

 

I spent last exening and half of night to solve this - without results....

 

To avoid a possible problems with  result claculation (mentioned abow - BYTEx are unsigned char so it works fine). I tried to convert a direct declared variable result_insigned_int=0xFFFFFFFF and convert it using sprintf(out,"%lu",result_unsigned int)

 

out is declared as:

char out[11];

 

Maybe it is something with stack size as CompilerGuru wrote...digging in stack settings will be difficult for me - I'm begginer :smileysad:

Could you try to run this simple code on your 8-bit uC(my is JM60):

 

unsigned long int in=0xFFFFFFFF;

char out[11];

sprintf(out,"%lu",in);

 

What you get in out? As I wrote abow it works in simulation mode but stucks in BDM.....

 

0 Kudos
1,611 Views
gooral
Contributor I

Hi,

 

Looks like the solution has been found!

I've followed ComplierGuru suggestion and I've changed Stack size in Project.prm from 0x80 to 0x100 and now it works perfect.

 

I wondering why old stack size wasn't enough. I don't use interrupts and any complicated calculations aren't performed in my project...

 

Thanks for advise! Another usefull lesson....

0 Kudos
1,611 Views
gooral
Contributor I

One more Thanks for CompilerGuru...  BYTEs multiplication must be done by 0x100u otherwise Byte is extended as signed....

0 Kudos
1,611 Views
Jim_P
Contributor III

Are  you sure that you are passing the right variable,   Result is not defined  - - above and does not contain the result of the putting of the 4 bytes together - - - - FYI, I tend to define a union  and then place the bytes directly - - faster code. 

 

Jim P

0 Kudos
1,611 Views
gooral
Contributor I

You have right, but this is only my mistake in listing - of course should be:

 

result_unsigned_int=(BYTE4*0x1000000)+(BYTE3*0x10000)+(BYTE2*0x100)+BYTE1;

sprintf(out, "%lu", result_unsigned_int);

 

I also try to simulate in CW and it works fine - out gets correct values.

 

I try to debug via BDM - I set breakpoint after sprintf and - variable result_unsigned_int has correct value but out doesn't change (has its initial value). When debugger starts process sprints it stuck......

 

My code obviously isn't optimal I know that :smileyhappy:

Bytes in union..., I'll try to implement this......

 

 

Something like itoa() for unsigned long int would be usefull (I'm using _itoa to convert decoder register values to ascii before displaing on LCD

0 Kudos
1,611 Views
Jim_P
Contributor III

Out is not defined, I assume same mistake

 

I am old hat type of programmer before standard lib's came about - - - - I have never liked the overhead of the printf, format, or sprintf - - - -

 

I have a routine that takes a nibble and outputs the hex code

this is called by the rountine to output a byte (twice)

the byte routine is called twice by the routine that outputs a 16 bit  - - - etc.

 

routines are called out_nibble, out_byte, out_int - - and of course can simply add out_long

and in my case output directly to the serial output ring buffer for being sent out over a RS232 link to the program on the PC for debug and check out.

 

Out_byte does a left shift for the top bits.

Out_Int has the value passed as a union so it simply calls Out_byte with upper and then lower byte.

 

Thus do not have to fight the lib functions - - - and get the data sent where I want it to be faster.

 

Jim P

0 Kudos