Re: [arm-gnu] output of sprintf with double-input
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [arm-gnu] output of sprintf with double-input



Hi,

i found a solution for this problem. In fact it was not sprintf specific, it was related to variadic functions. Just in case someone encounters this problem, here is my solution:

----------------------
1.) new hello.ld
----------------------
ENTRY(ResetISR)

MEMORY
{
   FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000
   SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00010000
}
SECTIONS
{
   .text :
   {
       _text = .;
       KEEP(*(.isr_vector))
       *(.text*)
       *(.rodata .rodata.* .gnu.linkonce.r.*)
       . = ALIGN(4);
       __init_array_start = .;
       KEEP (*(SORT(.init_array.*)))
       KEEP (*(.init_array))
       __init_array_end = .;
       _etext = .;
   } > FLASH
   .ARM.exidx :
   {
       *(.ARM.exidx* .gnu.linkonce.armexidx.*)
   } >FLASH
   .data : ALIGN(8)
   {
       _data = .;
       *(vtable)
       *(.data*)
       _edata = .;
   } > SRAM AT> FLASH
   .bss :
   {
       _bss = .;
       *(.bss*)
       *(COMMON)
       _ebss = .;
       . = ALIGN (8);
       _end = .;
   } > SRAM
}
PROVIDE(_lmadata = LOADADDR (.data));
PROVIDE(_heap = _end);
PROVIDE(_eheap = ALIGN(ORIGIN(SRAM) + LENGTH(SRAM) - 8, 8));

----------------------
2.) small change in startup_gcc.c
----------------------
void ResetISR(void)
{
   unsigned long *pulSrc, *pulDest;
   // Copy the data segment initializers from flash to SRAM.
   pulSrc = &_lmadata;
   for(pulDest = &_data; pulDest < &_edata; )
   {
       *pulDest++ = *pulSrc++;
   }
// Zero fill the bss segment. This is done with inline assembly since this
   // will clear the value of pulDest if it is not kept in a register.
   __asm("    ldr     r0, =_bss\n"
         "    ldr     r1, =_ebss\n"
         "    mov     r2, #0\n"
         "    .thumb_func\n"
         "zero_loop:\n"
         "        cmp     r0, r1\n"
         "        it      lt\n"
         "        strlt   r2, [r0], #4\n"
         "        blt     zero_loop");

   // Call the application's entry point.
   main();
}


3.) replace the arm-none-eabi-ld call with:
arm-none-eabi-gcc -Xlinker -Map="hello.map" -mcpu=cortex-m3 -mthumb -T hello.ld -Xlinker --gc-sections -o gcc/hello.axf gcc/hello.o gcc/syscalls.o gcc/rit128x96x4.o gcc/startup_gcc.o ../driverlib/gcc/libdriver.a





Hi,

i have observed a problem with sprintf and double on a ARM Cortex-M3-based microcontroller (the Stellaris LM3S8962 Evaluation Kit) using "Sourcery G++ Lite 2009q1-161".
In short: the modified Hello-World-Example from Stellaris
int main(void)
{
   char s[32];
   double d = 1.2;
   // Set the clocking to run directly from the crystal.
SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_8MHZ);
   // Initialize the OLED display.
   RIT128x96x4Init(1000000);
   RIT128x96x4StringDraw("Hello World!", 0, 0, 15);
   sprintf(s, "%d", (int)d);
   RIT128x96x4StringDraw(s, 0, 10, 15);
   sprintf(s, "%f", d);
   RIT128x96x4StringDraw(s, 0, 20, 15);
   sprintf(s, "%e", d);
   RIT128x96x4StringDraw(s, 0, 30, 15);
   while(1) {
   }
} produces the following output:
Hello World!
1
0.000000
1.397369e-76

Is someone successfully using sprintf with double on a cortex-m3 hardware?

Any suggestions what i am doing wrong?

I'm building on a ubuntu 8.04 Linux 32bit machine, with the following commands (the output of a verbose build can be found in the attached build_output_verbose.txt file): arm-none-eabi-gcc -mthumb -mcpu=cortex-m3 -Os -ffunction-sections -fdata-sections -MD -std=c99 -Wall -pedantic -DPART_LM3S8962 -c -I.. -Dgcc -o gcc/hello.o hello.c arm-none-eabi-gcc -mthumb -mcpu=cortex-m3 -Os -ffunction-sections -fdata-sections -MD -std=c99 -Wall -pedantic -DPART_LM3S8962 -c -I.. -Dgcc -o gcc/syscalls.o syscalls.c arm-none-eabi-gcc -mthumb -mcpu=cortex-m3 -Os -ffunction-sections -fdata-sections -MD -std=c99 -Wall -pedantic -DPART_LM3S8962 -c -I.. -Dgcc -o gcc/rit128x96x4.o rit128x96x4.c arm-none-eabi-gcc -mthumb -mcpu=cortex-m3 -Os -ffunction-sections -fdata-sections -MD -std=c99 -Wall -pedantic -DPART_LM3S8962 -c -I.. -Dgcc -o gcc/startup_gcc.o startup_gcc.c arm-none-eabi-ld -T hello.ld --entry ResetISR --gc-sections -o gcc/hello.axf gcc/hello.o gcc/syscalls.o gcc/rit128x96x4.o gcc/startup_gcc.o ../driverlib/gcc/libdriver.a /opt/CodeSourcery/Sourcery_Lite/bin/../lib/gcc/arm-none-eabi/4.3.3/../../../../arm-none-eabi/lib/thumb2/libc.a /opt/CodeSourcery/Sourcery_Lite/bin/../lib/gcc/arm-none-eabi/4.3.3/thumb2/libgcc.a

Files used for building:

----------------------
hello.c
----------------------
#include <stdio.h>
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/sysctl.h"
#include "drivers/rit128x96x4.h"

int main(void)
{
   char s[32];
   double d = 1.2;
   // Set the clocking to run directly from the crystal.
SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_8MHZ);
   // Initialize the OLED display.
   RIT128x96x4Init(1000000);
   RIT128x96x4StringDraw("Hello World!", 0, 0, 15);
   sprintf(s, "%d", (int)d);
   RIT128x96x4StringDraw(s, 0, 10, 15);
   sprintf(s, "%f", d);
   RIT128x96x4StringDraw(s, 0, 20, 15);
   sprintf(s, "%e", d);
   RIT128x96x4StringDraw(s, 0, 30, 15);
   while(1) {
   }
}

----------------------
hello.ld
----------------------
MEMORY
{
   FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000
   SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00010000
}

SECTIONS
{
   .text :
   {
       _text = .;
       KEEP(*(.isr_vector))
       *(.text*)
       *(.rodata*)
       _etext = .;
   } > FLASH
   .ARM.exidx :
   {
       *(.ARM.exidx* .gnu.linkonce.armexidx.*)
   } >FLASH
   _flash_data = ADDR(.text) + SIZEOF(.text) + SIZEOF(.ARM.exidx);
   .data : AT(_flash_data)
   {
       _data = .;
       *(vtable)
       *(.data*)
       _edata = .;
   } > SRAM
   .bss :
   {
       _bss = .;
       *(.bss*)
       *(COMMON)
       _ebss = .;
       . = ALIGN (8);
       _end = .;
   } > SRAM
}
PROVIDE(_heap = _end);
PROVIDE(_eheap = ALIGN(ORIGIN(SRAM) + LENGTH(SRAM) - 8 ,8));

----------------------
syscalls.c
----------------------
#include <sys/types.h>

extern unsigned long _heap;
extern unsigned long _eheap;

static caddr_t heap = NULL;

caddr_t _sbrk(int incr)
{
   caddr_t prevHeap;
   caddr_t nextHeap;

   if(heap == NULL) heap = (caddr_t) &_heap;

   prevHeap = heap;
   nextHeap = prevHeap + incr;

if(nextHeap >= (caddr_t) &_eheap) return (caddr_t) -1; // error - no more memory
   else {
       heap = nextHeap;
       return prevHeap;
   }
}

----------------------
startup_gcc.c
----------------------
void ResetISR(void);
static void NmiSR(void);
static void FaultISR(void);
static void IntDefaultHandler(void);
extern int main(void);
static unsigned long pulStack[512];
__attribute__ ((section(".isr_vector")))
void (* const g_pfnVectors[])(void) =
{
   (void (*)(void))((unsigned long)pulStack + sizeof(pulStack)),
                                           // The initial stack pointer
   ResetISR,                               // The reset handler
   NmiSR,                                  // The NMI handler
   FaultISR,                               // The hard fault handler
   IntDefaultHandler,                      // The MPU fault handler
   IntDefaultHandler,                      // The bus fault handler
   IntDefaultHandler,                      // The usage fault handler
   0,                                      // Reserved
   0,                                      // Reserved
   0,                                      // Reserved
   0,                                      // Reserved
   IntDefaultHandler,                      // SVCall handler
   IntDefaultHandler,                      // Debug monitor handler
   0,                                      // Reserved
   IntDefaultHandler,                      // The PendSV handler
   IntDefaultHandler,                      // The SysTick handler
   IntDefaultHandler,                      // GPIO Port A
   IntDefaultHandler,                      // GPIO Port B
   IntDefaultHandler,                      // GPIO Port C
   IntDefaultHandler,                      // GPIO Port D
   IntDefaultHandler,                      // GPIO Port E
   IntDefaultHandler,                      // UART0 Rx and Tx
   IntDefaultHandler,                      // UART1 Rx and Tx
   IntDefaultHandler,                      // SSI0 Rx and Tx
   IntDefaultHandler,                      // I2C0 Master and Slave
   IntDefaultHandler,                      // PWM Fault
   IntDefaultHandler,                      // PWM Generator 0
   IntDefaultHandler,                      // PWM Generator 1
   IntDefaultHandler,                      // PWM Generator 2
   IntDefaultHandler,                      // Quadrature Encoder 0
   IntDefaultHandler,                      // ADC Sequence 0
   IntDefaultHandler,                      // ADC Sequence 1
   IntDefaultHandler,                      // ADC Sequence 2
   IntDefaultHandler,                      // ADC Sequence 3
   IntDefaultHandler,                      // Watchdog timer
   IntDefaultHandler,                      // Timer 0 subtimer A
   IntDefaultHandler,                      // Timer 0 subtimer B
   IntDefaultHandler,                      // Timer 1 subtimer A
   IntDefaultHandler,                      // Timer 1 subtimer B
   IntDefaultHandler,                      // Timer 2 subtimer A
   IntDefaultHandler,                      // Timer 2 subtimer B
   IntDefaultHandler,                      // Analog Comparator 0
   IntDefaultHandler,                      // Analog Comparator 1
   IntDefaultHandler,                      // Analog Comparator 2
IntDefaultHandler, // System Control (PLL, OSC, BO)
   IntDefaultHandler,                      // FLASH Control
   IntDefaultHandler,                      // GPIO Port F
   IntDefaultHandler,                      // GPIO Port G
   IntDefaultHandler,                      // GPIO Port H
   IntDefaultHandler,                      // UART2 Rx and Tx
   IntDefaultHandler,                      // SSI1 Rx and Tx
   IntDefaultHandler,                      // Timer 3 subtimer A
   IntDefaultHandler,                      // Timer 3 subtimer B
   IntDefaultHandler,                      // I2C1 Master and Slave
   IntDefaultHandler,                      // Quadrature Encoder 1
   IntDefaultHandler,                      // CAN0
   IntDefaultHandler,                      // CAN1
   IntDefaultHandler,                      // CAN2
   IntDefaultHandler,                      // Ethernet
   IntDefaultHandler                       // Hibernate
};

extern unsigned long _etext;
extern unsigned long _flash_data;
extern unsigned long _data;
extern unsigned long _edata;
extern unsigned long _bss;
extern unsigned long _ebss;

void ResetISR(void)
{
   unsigned long *pulSrc, *pulDest;
   // Copy the data segment initializers from flash to SRAM.
   pulSrc = &_flash_data;
   for(pulDest = &_data; pulDest < &_edata; )
   {
       *pulDest++ = *pulSrc++;
   }
// Zero fill the bss segment. This is done with inline assembly since this
   // will clear the value of pulDest if it is not kept in a register.
   __asm("    ldr     r0, =_bss\n"
         "    ldr     r1, =_ebss\n"
         "    mov     r2, #0\n"
         "    .thumb_func\n"
         "zero_loop:\n"
         "        cmp     r0, r1\n"
         "        it      lt\n"
         "        strlt   r2, [r0], #4\n"
         "        blt     zero_loop");

   // Call the application's entry point.
   main();
}

static void NmiSR(void) { while(1); }
static void FaultISR(void) { while(1); }
static void IntDefaultHandler(void) { while(1); }