[LPC2148][C] sprintf() doesn't work with double/float

Hi,

For a few days I’m a fresh user of an LPC2148 testboard. I’ve got some programming experience on AVR, but I’m new to ARM. I’ve got a problem with an sprintf() function. Everything works fine with a code:

int a=2;
char buf[16];
sprintf(buf, "A: %d", a);
LCDWrite(buf);

I’ve got a “A: 2” on a LCD. But when I try to use double/float variables:

double a=2;
char buf[16];
sprintf(buf, "A: %0.2lf", a);
LCDWrite(buf);

there’s nothing on a LCD, program seems to halt (no intruction is being made after sprintf()). Can anyone help me?

These are my syscalls.c i startup.s files:

#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include "uart.h"

#undef errno
extern int errno;

caddr_t _sbrk(int incr)
{
   extern char _end;      /* Defined by the linker */
   extern char _ram_end;
   static char *heap_end;
   char *prev_heap_end;

   if(heap_end == 0)
   {
      heap_end = &_end;
   }
   prev_heap_end = heap_end;
   if(heap_end + incr > (char*)&_ram_end)
   {
      errno = ENOMEM;
      return (caddr_t) -1;
   }


   heap_end += incr;
   return (caddr_t) prev_heap_end;
}

int _isatty(int fd)
{
  return 1;
}

int _lseek(int fd, off_t pos, int whence)
{
  return 0;
}

int _close(int file) {
return -1;
}

int _read(int fd, void *buffer, unsigned int count)
{
return(0);
}

int _fstat(int file, struct stat *st) {
st->st_mode = S_IFCHR;
return 0;
}

int open(const char *name, int flags, int mode) {
return -1;
}

int
_write(int file, char *ptr, int len) {
	int todo;
	for (todo = 0; todo < len; todo++) {
		UART_PutChar((*ptr++));
	}
	return len;
}
/* *************************************************************************************************************** 
   crt.s                  STARTUP  ASSEMBLY  CODE 
                        ----------------------- 

   Module includes the interrupt vectors and start-up code. 
  *************************************************************************************************************** */ 

/* Stack Sizes */ 
.set  UND_STACK_SIZE, 0x00000200     
.set  ABT_STACK_SIZE, 0x00000200      
.set  FIQ_STACK_SIZE, 0x00000200      
.set  IRQ_STACK_SIZE, 0x00000200    
.set  SVC_STACK_SIZE, 0x00000200    
#.set _MEMMAP,      0xE01FC040 

/* Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs (program status registers) */ 
.set  MODE_USR, 0x10                  /* Normal User Mode                               */ 
.set  MODE_FIQ, 0x11                  /* FIQ Processing Fast Interrupts Mode                   */ 
.set  MODE_IRQ, 0x12                  /* IRQ Processing Standard Interrupts Mode                */ 
.set  MODE_SVC, 0x13                  /* Supervisor Processing Software Interrupts Mode          */ 
.set  MODE_ABT, 0x17                  /* Abort Processing memory Faults Mode                   */ 
.set  MODE_UND, 0x1B                  /* Undefined Processing Undefined Instructions Mode       */ 
.set  MODE_SYS, 0x1F                  /* System Running Priviledged Operating System Tasks  Mode   */ 

.set  I_BIT, 0x80                     /* when I bit is set, IRQ is disabled (program status registers) */
.set  F_BIT, 0x40                     /* when F bit is set, FIQ is disabled (program status registers) */


.text 
.arm 

.global   Reset_Handler 
.global _startup 
.func   _startup 

_startup: 

# Exception Vectors 
_vectors:       ldr     PC, Reset_Addr          
                ldr     PC, Undef_Addr 
                ldr     PC, SWI_Addr 
                ldr     PC, PAbt_Addr 
                ldr     PC, DAbt_Addr 
                nop                     /* Reserved Vector (holds Philips ISP checksum) */ 
                ldr     PC, [PC,#-0xFF0]   /* see page 71 of "Insiders Guide to the Philips ARM7-Based Microcontrollers" by Trevor Martin  */ 
                ldr     PC, FIQ_Addr 

Reset_Addr:     .word   Reset_Handler      /* defined in this module below  */ 
Undef_Addr:     .word   UNDEF_Routine      /* defined in main.c  */ 
SWI_Addr:       .word   SWI_Routine         /* defined in main.c  */ 
PAbt_Addr:      .word   UNDEF_Routine      /* defined in main.c  */ 
DAbt_Addr:      .word   UNDEF_Routine      /* defined in main.c  */ 
IRQ_Addr:       .word   IRQ_Routine         /* defined in main.c  */ 
FIQ_Addr:       .word   FIQ_Routine         /* defined in main.c  */ 
                .word   0               /* rounds the vectors and ISR addresses to 64 bytes total  */ 

Reset_Handler:  
            /* Setup a stack for each mode - note that this only sets up a usable stack 
            for User mode.   Also each mode is setup with interrupts initially disabled. */ 
               
             ldr   r0, =_stack_end 
             msr   CPSR_c, #MODE_UND|I_BIT|F_BIT    /* Undefined Instruction Mode  */ 
             mov   sp, r0 
             sub   r0, r0, #UND_STACK_SIZE 
             msr   CPSR_c, #MODE_ABT|I_BIT|F_BIT    /* Abort Mode */ 
             mov   sp, r0 
             sub   r0, r0, #ABT_STACK_SIZE 
             msr   CPSR_c, #MODE_FIQ|I_BIT|F_BIT    /* FIQ Mode */ 
             mov   sp, r0    
               sub   r0, r0, #FIQ_STACK_SIZE 
             msr   CPSR_c, #MODE_IRQ|I_BIT|F_BIT    /* IRQ Mode */ 
             mov   sp, r0 
             sub   r0, r0, #IRQ_STACK_SIZE 
             msr   CPSR_c, #MODE_SVC|I_BIT|F_BIT    /* Supervisor Mode */ 
             mov   sp, r0 
             sub   r0, r0, #SVC_STACK_SIZE 
             msr   CPSR_c, #MODE_SYS|I_BIT|F_BIT    /* User Mode */ 
             mov   sp, r0 

            /* copy .data section (Copy from ROM to RAM) */ 
                ldr     R1, =_text_end
                ldr     R2, =_data_start
                ldr     R3, =_data_end
1:              cmp     R2, R3 
                ldrlo   R0, [R1], #4 
                strlo   R0, [R2], #4 
                blo     1b 

            /* Clear .bss section (Zero init)  */ 
                mov     R0, #0 
                ldr     R1, =_bss_start 
                ldr     R2, =_bss_end 
2:            cmp     R1, R2 
                strlo   R0, [R1], #4 
                blo     2b 

            /* Enter the C code  */ 
                b       main 

.endfunc 
.end

Kulesz

Looks like a buffer overflow, if you specify %0.21f you need at least a 22 character string (one for the \0), but your string is char buf[16];

Anyway the format string does not seem correct, because %X.Y means print X character of which Y after the decimal point, so setting X to zero might mean “print nothing” depending on the libc implementation.

Title of this thread is incorrect?

inventore123:
if you specify %0.21f you need at least a 22 character string (one for the \0), but your string is char buf[16];

It is not 21f, but 2lf (it's "L" there), for "long float". I've also tried %lf, %f and it does't work too.

Why title is incorrect?

Ok, so no buffer overflow, but the zero length problem remains. Try something like %4.2f which should print 4 characters of which 2 after decimal point (something like 0.00)

Still nothing, program hangs with “%lf”, “%f”, “%4.3f”, “%4.3lf” etc. The same with printf and so on. I’m using Codesurcery and Eclipse IDE. Maybe it needs to enable floating point operations somehow?

Maybe crazy but try:

double a;

a=2.0;

Compiler maybe trying to place the integer 2 into a float?

Still nothing… It must be some kind of memory/stack problem. Float operations (adding, dividing, trigonometric etc.) works ok. But malloc(), strtok() functions doesn’t work.

Correct project settings for compiler and linker? To pick up the float version of library code for printf, vprintf et al? Often, the library used is minus support for floats, e.g., IAR has like 4 libraries of increasing size and completeness. Chosen via the IDE project settings.

Looked up all project options in Eclipse and didn’t find anything connected with versions of printf etc.

Interesting thing is that the program hangs also on:

int *a=(int)malloc(4*sizeof(int))

but works on:

int *a=(int)malloc(3*sizeof(int))

Printf/sprintf in newlib DO use malloc, so if malloc is broken, printf is broken too.

Sprintf() works, but only with integers (%d). Printf() doesn’t work anyway.

I’ve got syscalls.c from: http://yagarto.de/download/yagarto/syscalls.c

kulesz:
Looked up all project options in Eclipse and didn’t find anything connected with versions of printf etc.

Interesting thing is that the program hangs also on:

int *a=(int)malloc(4*sizeof(int))

but works on:

int *a=(int)malloc(3*sizeof(int))

It’s likely there - a linker option for which library to use. It’s in all the GCCs I’ve ever seen. I doubt malloc() is broken.

It can be, but I didn’t see it :slight_smile: Maybe it can be set in the makefile somehow?

kulesz:
It can be, but I didn’t see it :slight_smile: Maybe it can be set in the makefile somehow?

I use GCC for AVRs, but not ARM. So search the forums and read-up on linker and library. Or post the question politely as a newbie, in the Yahoo forums on ARM or on the less popular http://forums.arm.com/index.php?showforum=3

Another day of searching and still nothing. Maybe someone has a working example of project with codesourcery and sprintf (with floats)?

did you post into those other forums?

sprintf with floats works for me.

I think that your _sbrk_r is broken, that’s why malloc doesn’t work

Yes, I posted to Yahoo and Embedded Related.

inventore123:
sprintf with floats works for me.

I think that your _sbrk_r is broken, that’s why malloc doesn’t work

Inventore123, are you using the Codesourcery toolchain? And what kind of uC?