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