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

LPC2138, but with a GCC compiled from sources (I’m a Linux user :))

Try reading this thread, if you haven’t already viewtopic.php?t=5390&postdays=0&postord … s&start=15

I feel it won’t work :slight_smile: Maybe you could just send me makefile, startup and linker scripts from a simple project, where sprintf() works with float, please?

Here’s part of my “template” project, that’s what I use as a starting point when I write a new application. Sorry, it’s in C++ because I couldn’t find the one in C but it doesn’t make much difference, it just requires a little longer startup and linker script script.

Here’s the crt0.s (Linker script)

/* Mode bits and Interrupt (I & F) flags in PSRs (program status registers) */
.set  MODE_USR, 0x10  /* User Mode                      */
.set  MODE_FIQ, 0x11  /* FIQ Fast Interrupt Mode        */
.set  MODE_IRQ, 0x12  /* IRQ Interrupt Mode             */
.set  MODE_SVC, 0x13  /* Supervisor Call Interrupt Mode */
.set  MODE_ABT, 0x17  /* Abort (memory fault) Mode      */
.set  MODE_UND, 0x1B  /* Undefined Instructions Mode    */
.set  MODE_SYS, 0x1F  /* System Mode                    */
.set  I_BIT, 0x80     /* if I bit set, IRQ is disabled  */
.set  F_BIT, 0x40     /* if F bit set, FIQ is disabled  */

.text
.arm

.global _startup
.func   _startup

_startup:

/* Interrupt vectors */

_vectors:	ldr     pc, Reset_Addr
			ldr     pc, Undef_Addr
			ldr     pc, SWI_Addr
			ldr     pc, PAbt_Addr
			ldr     pc, DAbt_Addr
			nop                      /* Reserved for ISP checksum                    */
			ldr     pc, [pc,#-0xFF0] /* Jump to VIC (vectored interrupt controller)  */
			ldr     pc, FIQ_Addr

Reset_Addr: .word   Reset_Handler  /* defined below            */
Undef_Addr: .word   UNDEF_Routine  /* defined in main.cpp      */
SWI_Addr:   .word   SWI_Routine	   /* defined in main.cpp      */
PAbt_Addr:  .word   UNDEF_Routine  /* defined in main.cpp      */
DAbt_Addr:  .word   UNDEF_Routine  /* defined in main.cpp      */
FIQ_Addr:   .word   FIQ_Routine    /* defined in main.cpp      */
            .word   0              /* rounds the vector addresses to 64 bytes */


/* Reset Handler */

Reset_Handler:  
			/* Setup a stack for each mode */
    		msr		CPSR_c, #MODE_UND|I_BIT|F_BIT  /* Undefined Instruction Mode (IRQ Off, FIQ Off) */
    		ldr		sp, =_und_stack_top

    		msr		CPSR_c, #MODE_ABT|I_BIT|F_BIT  /* Abort Mode (IRQ Off, FIQ Off) */
            ldr     sp, =_abt_stack_top

    		msr		CPSR_c, #MODE_FIQ|I_BIT|F_BIT  /* FIQ Mode (IRQ Off, FIQ Off) */
		    ldr     sp, =_fiq_stack_top

    		msr		CPSR_c, #MODE_IRQ|I_BIT|F_BIT  /* IRQ Mode (IRQ Off, FIQ Off) */
            ldr     sp, =_irq_stack_top

    		msr		CPSR_c, #MODE_SVC|I_BIT|F_BIT  /* Supervisor Mode (IRQ Off, FIQ Off) */
            ldr     sp, =_svc_stack_top

    		msr		CPSR_c, #MODE_SYS|I_BIT|F_BIT  /* System mode (IRQ Off, FIQ Off) */
    		ldr		sp, =_sys_stack_top

			/* copy .data section from FLASH to RAM */
			ldr		r1, =_etext
			ldr		r2, =_data
			ldr		r3, =_edata
1:        	cmp		r2, r3
			ldrlo	r0, [r1], #4
			strlo	r0, [r2], #4
			blo		1b
			/* clear .bss section */
			mov		r0, #0
			ldr		r1, =_bss_start
			ldr		r2, =_bss_end
2:			cmp		r1, r2
			strlo	r0, [r1], #4
			blo		2b
			/* fill stack with watermark 0xbbbbbbbb */
			ldr		r0, =0xbbbbbbbb
			ldr		r1, =_stack_start
			ldr		r2,	=_stack_end
3:			cmp		r1, r2
			strlo	r0, [r1], #4
			blo		3b
			/* call static constructors. Supports both eabi and elf binary formats */
			ldr		r0, =__preinit_array_start
			ldr		r1, =__preinit_array_end
			bl		_call_constructors
			ldr		r0, =_ctor_start
			ldr		r1, =_ctor_end
			bl		_call_constructors
			ldr		r0, =__init_array_start
			ldr		r1, =__init_array_end
			bl		_call_constructors
			/* enter main(). the lr (return address) is set to 0x00000000, so if main returns,
			it will jump to the reset vector, rebooting the system */
			ldr		lr, =0
			b		main

.endfunc

.func	_call_constructors
_call_constructors:
			stmfd	sp!, {lr}
4:			cmp		r0,r1
			beq		5f
			ldr		r2, [r0], #4
			stmfd	sp!, {r0-r1}
			mov		lr, pc
			bx		r2
			ldmfd	sp!, {r0-r1}
			b		4b
5:			ldmfd	sp!, {pc}
.endfunc
	
.end

The linker script LPC2138_rom.ld

/* stack sizes, used by startup assembler code, can be modified if needed */
_und_stack_size = 0x00000000;  /* stack for "UND" is 0, this means it shares the stack with "ABT" */
_abt_stack_size = 0x00000000;  /* stack for "ABT" is 0, this means it shares the stack with "FIQ" */
_fiq_stack_size = 0x00000020;  /* stack for "FIQ"         32 bytes */
_irq_stack_size = 0x00000200;  /* stack for "IRQ"        256 bytes */
_svc_stack_size = 0x00000020;  /* stack for "SVC"         32 bytes */
_sys_stack_size = 0x00003800;  /* stack for "SYS"        14K bytes */

/* end of the stack */
_stack_end = 0x40007EE0;       /* end of available ram */

/* calculate the stacks and the end of the heap, used to check heap overflow */
_und_stack_top = _stack_end;
_abt_stack_top = _und_stack_top - _und_stack_size;
_fiq_stack_top = _abt_stack_top - _abt_stack_size;
_irq_stack_top = _fiq_stack_top - _fiq_stack_size;
_svc_stack_top = _irq_stack_top - _irq_stack_size;
_sys_stack_top = _svc_stack_top - _svc_stack_size;
_stack_start   = _sys_stack_top - _sys_stack_size;
_heap_end      = _stack_start;

/* identify the Entry Point  */
ENTRY(_startup)

/* specify the LPC2138 memory areas  */
MEMORY
{
 flash(rx) 			: ORIGIN = 0,          LENGTH = 500K  /* FLASH (512K-12K for bootloader)  */	
 ram_vectors		: ORIGIN = 0x40000000, LENGTH = 64    /* interrupt vectors (if remapped)  */
 ram(wx)			: ORIGIN = 0x40000040, LENGTH = 32416 /* free RAM area                    */
}

/* now define the output sections  */
SECTIONS 
{
 . = 0;								/* set location counter to address zero */
	
 .startup :
 {
		*crt0.o (.text)
 } >flash							/* startup code goes in flash @ addr 0x00000000 */
 
 .text :							/* collect all sections that go into FLASH after startup */ 
 {
		*(.text)					/* all .text    sections (code)                     */
        *(.text.*)					/* all .text.*  sections (for C++)                  */
		*(.gnu.linkonce.t.*)        /* not so sure it's necessary                       */
        *(.gcc_except_table)		/* all .gcc_except_table    sections (for C++)      */
        *(.gcc_except_table.*)		/* all .gcc_except_table.*  sections (for C++)      */
		*(.rodata)					/* all .rodata  sections (constants, strings, etc.) */
		*(.rodata*)					/* all .rodata* sections (constants, strings, etc.) */
		*(.glue_7)					/* all .glue_7  sections (no idea what these are)   */
		*(.glue_7t)					/* all .glue_7t sections (no idea what these are)   */
		*(.gnu.linkonce.r.*)        /* not so sure it's necessary                       */
		
		. = ALIGN(4);
		
		_ctor_start = .;			/* Static constructors and destructors under elf    */
        KEEP (*(.ctors))
        KEEP (*(SORT(.ctors.*)))
		_ctor_end = .;
        KEEP (*(.dtors))
        KEEP (*(SORT(.dtors.*)))
		*(.init)					/* Static constructors and destructors under eabi   */
		*(.fini)
		PROVIDE_HIDDEN (__preinit_array_start = .);
        KEEP (*(.preinit_array))
        PROVIDE_HIDDEN (__preinit_array_end = .);
        PROVIDE_HIDDEN (__init_array_start = .);
        KEEP (*(SORT(.init_array.*)))
        KEEP (*(.init_array))
        PROVIDE_HIDDEN (__init_array_end = .);
        PROVIDE_HIDDEN (__fini_array_start = .);
        KEEP (*(.fini_array))
        KEEP (*(SORT(.fini_array.*)))
        PROVIDE_HIDDEN (__fini_array_end = .);
		
		_etext = .;					/* global symbol _etext after the last code byte    */
 } >flash						    /* put everything into flash                        */

 .data :							/* collect all initialized .data sections that go into RAM  */ 
 {
		_data = .;					/* global symbol marking the start of .data section */
		*(.data)					/* all .data   sections                             */
        *(.data.*)					/* all .data.* sections (for C++)                   */
		*(.gnu.linkonce.d.*)        /* not so sure it's necessary                       */
		_edata = .;					/* global symbol marking the end of .data section   */
 } >ram AT >flash					/* put everything into ram, load LMA copy in flash  */
 
 . = ALIGN(4);						/* advance location counter to the next 32-bit boundary */

 .bss :								/* collect all uninitialized .bss sections that go into RAM  */
 {
		_bss_start = .;				/* global symbol marking the start of .bss section  */
		*(.bss)						/* all .bss   sections                              */
        *(.bss.*)					/* all .bss.* sections (for C++)                    */
		*(.gnu.linkonce.b.*)        /* not so sure it's necessary                       */
 } >ram								/* put everything in ram                            */

 . = ALIGN(4);						/* advance location counter to the next 32-bit boundary */
 _bss_end = . ;						/* define a global symbol marking the end of the .bss section */
 _end = .;							/* define a global symbol marking the end of application RAM  */
 PROVIDE(end = .);
}

Here’s the syscalls.cpp file

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <reent.h>
#include <sys/stat.h>
/* Low level serial port tx functions */
#include "system.h"

/**
new operator. Redefined not to throw exceptions. 
*/
void *operator new(size_t size)
{
    return malloc(size);
}

void *operator new[](size_t size)
{
    return malloc(size);
}

/**
delete operator. Redefined not to throw exceptions.
*/
void operator delete(void *p)
{
    free(p);
}

void operator delete[](void *p)
{
    free(p);
}

#ifdef __cplusplus
extern "C" {
#endif

#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2

/**
Required by C++ standard library. FIXME: understand better what it does
*/
void *__dso_handle;

/**
_exit, restarts the system
*/
void _exit(int n)
{
    uart0_tx_str("\r\n***Exit called\r\n");
    while(!uart0_fifo_empty());//Wait until all data sent
    system_reboot();
    for(;;) /*lock*/;
}

/**
_sbrk_r, malloc calls it to increase the heap size
*/
void *_sbrk_r(struct _reent *ptr, ptrdiff_t incr)
{
    //This is the absolute start of the heap
    extern char _end asm("_end"); //defined in the linker script
    //This is the absolute end of the heap
    extern char _heap_end asm("_heap_end"); //defined in the linker script
    //This holds the current end of the heap (static)
    static char *cur_heap_end=NULL;
    //This holds the previous end of the heap
    char *prev_heap_end;

    //Check if it's first time called
    if(cur_heap_end==NULL) cur_heap_end=&_end;

    prev_heap_end=cur_heap_end;
    if((cur_heap_end+incr)>&_heap_end)
    {
        //bad, heap overflow
        uart0_tx_str("\r\n***Heap overflow\r\n");
        _exit(1);
    }
    cur_heap_end+=incr;
    return (caddr_t)prev_heap_end;
}

/**
__malloc_lock, no need to lock malloc
*/
void __malloc_lock()
{
    //Do nothing
}

/**
__malloc_unlock, no need to lock malloc
*/
void __malloc_unlock()
{
    //Do nothing
}

/**
_open_r, unimplemented
*/
int _open_r(struct _reent *ptr, const char *file, int flags, int mode)
{
    return -1;
}

/**
_close_r, unimplemented
*/
int _close_r(struct _reent *ptr, int fd)
{
    return 0;
}

/**
_write (for C++ library)
*/
int _write(int fd, const void *buf, size_t cnt)
{
    if(fd==STDOUT_FILENO)
    {
        size_t i;
        char *tmp=(char *)buf;
        for(i=0;i<cnt;i++) uart0_tx(*tmp++);
    } else {
        uart0_tx_str("Error: _write\r\n");
        cnt = -1;
    }
    return cnt;
}

/**
_write_r, FIXME: partially implemented
*/
int _write_r(struct _reent *ptr, int fd, const void *buf, size_t cnt)
{
    return _write(fd,buf,cnt);
}

/**
_read (for C++ library)
*/
int _read(int fd, void *buf, size_t cnt)
{
    //iprintf("read: buf %d\r\n",(int)cnt);//To check read buffer size
    char *buffer=(char*)buf;
    if(fd==STDIN_FILENO)
    {
        unsigned int i;
        for(i=0;i<cnt;i++)
        {
            buffer[i]=uart0_rx();//FIXME: cpu busy wait, wastes power
            if(buffer[i]=='\r')
            {
                buffer[i]='\n';
                uart0_tx_str("\r\n");//Echo
                return i+1;
            } else uart0_tx(buffer[i]);//Echo
        }
        return i;
    } else {
        uart0_tx_str("Error: _read\r\n");
        return -1;
    }
}

/**
_read_r, unimplemented
*/
int _read_r(struct _reent *ptr, int fd, void *buf, size_t cnt)
{
    return _read(fd,buf,cnt);
}

/**
_lseek (for C++ library)
*/
off_t _lseek(int fd, off_t pos, int whence)
{
    return -1;
}

/**
_lseek_r, unimplemented
*/
off_t _lseek_r(struct _reent *ptr, int fd, off_t pos, int whence)
{
    return -1;
}

/**
_stat_r, unimplemented
*/
int _stat_r(struct _reent *ptr, const char *file, struct stat *pstat)
{
    return 0;
}

/**
_fstat (for C++ library)
*/
int _fstat(int fd, struct stat *pstat)
{
    if(fd==STDOUT_FILENO)
    {
        memset(pstat,0,sizeof(*pstat));//FIXME: sizeof(*pstat) is the size of the pointer??
        pstat->st_mode=S_IFCHR;
        pstat->st_blksize=1024;
        return 0;
    } else {
        return -1;
    }
}

/**
_fstat_r, FIXME: partially implemented
*/
int _fstat_r(struct _reent *ptr, int fd, struct stat *pstat)
{
    return _fstat(fd,pstat);
}

/**
isatty, returns 1 if fd is associated with a terminal
*/
int isatty(int fd)
{
    switch(fd)
    {
        case STDIN_FILENO:
        case STDOUT_FILENO:
        case STDERR_FILENO:
            return 1;
        default:
            return 0;
    }
}

/**
_isatty, required by codesourcery gcc
*/
int _isatty(int fd)
{
    return isatty(fd);
}

/*--------------------------------------------
These functions are required by the C and C++
standard library, but will not be implemented
--------------------------------------------*/

/**
_fork_r, unimplemented
*/
int _fork_r(struct _reent *ptr)
{
    return -1;
}

/**
_wait_r, unimpemented
*/
int _wait_r(struct _reent *ptr, int *status)
{
    return -1;
}

/**
_link_r, unimpemented
*/
int _link_r(struct _reent *ptr, const char *f_old, const char *f_new)
{
    return -1;
}

/**
_unlink_r, unimplemented
*/
int _unlink_r(struct _reent *ptr, const char *file)
{
    return -1;
}

/**
_kill, unimplemented (don't even know if function signature is correct)
*/
int _kill(int pid, int sig)
{
    return -1;
}

/**
_getpid, unimplemented  (don't even know if function signature is correct)
*/
int _getpid()
{
    return -1;
}

#ifdef __cplusplus
}
#endif

And finally the main.cpp

I’ve tested right now and it prints the correct result, so sprintf works as expected.

#include "system.h"
#include <cstdio>

using namespace std;

int main()
{
    init();

    double d=-12.3456;
    char line[16];
    sprintf(line,"%8.4f\r\n",d);
    puts(line);

    shutdown();
}

Last notes: the files system.h and system.cpp referenced by the code I’ve posted is a collection of functions for handling pll, serial port, and other things.

The linker script might cause troubles with codesourcery since it’s designed for arm-ELF-gcc, while codesourcery is arm-none-EABI-gcc, so that’s a different ABI.

I’ve just deleted new and delete from syscalls.c, put my LCD libs and it all compiled properly. However, still hangs… :-/

Bug in codesourcery’s release?

Try upgrading to the latest release, or if it is already the last, try downgrading to a previous one, and contact them telling they might have a bug…