I'm encountering difficulties printing both 64-bit integers and double precision floating point values in the same application. Some background. MCU is MK22DX128VLF5 on a board of my own design. I'm using MCUXpresso 10.3.1 in a no-host configuration. I've written my own _read() and _write() functions to interface to a UART which communicates to the outside world at 1 Mb/s through an external serial/USB translator. Both I/O support functions are re-used from a similar design and have been thoroughly proven in use. Code size is not an issue as my application code is approximately 90% complete and, with Newlib selected only about 60% of available flash is needed and much less than 50% of available RAM.
Using the Quick Settings link, I've first selected SoftABI floating point since the MCU has no hardware floating point unit. If I then select NewlibNano (nohost) in the Library/Header category, the following statement executes as expected:
printf("x = %f\n", x);
where x is a declared as a double precision value equal to 2.71828. On the other hand, the statement
printf("i = %lu\n", i);
where i is declared as uint64_t cast as an unsigned long int equal to 0x100000001 displays as "i = lu".
If instead I select Newlib (nohost) in the Library/Header category, the second printf() call shown above will render the expected value, however when the first printf() shown is encountered the hard fault handler is inevitably invoked.
I've spent a number of hours reading through the MCUXpresso IDE User's Guide to be sure I understand what libraries are available and how they are intended to be used, inspecting library paths and compiler options, etc., but so far have been unable to find a way to build an applications which can render both data types correctly using printf(). It's understandable to me that NewlibNano doesn't support 64-bit integers, but I don't understand why it's not working with double precision floats. My code is needed to control an instrument which needs to go into service soon, and this is the final hurdle to leap before that can happen. Any suggestions are appreciated.
Actually, I did have "%llu" in my code to display a 64-bit unsigned. And as I noted, 64-bit values are displayed correctly if my application is linked with Newlib, but not NewlibNano. I've isolated an example into a separate function this morning:
#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include <MK22F12810.h>
int cmd_test(int argc, char *argv[]) {
uint64_t i = 0xfedcba9876543210;
double x = 355.0 / 113.0;
printf("i = %llu (0x%llx)\n", (unsigned long long int) i, (unsigned long long int) i);
printf("x = %f\n", x);
return 0;
}
Results, if linked with NewlibNano (nohost):
QTG-1.0 > test
i = lu (0xlx)
x = 3.141593
If I highlight the project name, then select QuickSettings>> -> Set library/header type -> Newlib (nohost), execution terminates at the semihost hardfault exception handler when the second printf() is encountered. In my application code, I've isolated this fault to that statement by commenting it out. And, if I comment the second printf() out of my example linked with Newlib, I see this result:
QTG-1.0 > test
i = 18364758544493064720 (0xfedcba9876543210)
Compiler/linker outputs for the two cases follow.
QuickSettings>> -> Set library/header type -> NewlibNano (nohost)
Building file: ../source/cmd_test.c
Invoking: MCU C Compiler
arm-none-eabi-gcc -DFSL_RTOS_BM -DSDK_OS_BAREMETAL -DCPU_MK22FN128VDC10 -DCPU_MK
22FN128VDC10_cm4 -D__MCUXPRESSO -D__USE_CMSIS -DDEBUG -D__NEWLIB__ -I/usr/local/
mcuxpressoide/arm-none-eabi/include/ -I"/home/username/MCUXpresso/QTG/source" -I
"/home/username/MCUXpresso/QTG/device" -I"/home/username/MCUXpresso/QTG/CMSIS" -
O0 -fno-common -g3 -Wall -c -ffunction-sections -fdata-sections -ffreestanding -
fno-builtin -fsingle-precision-constant -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloa
t-abi=softfp -mthumb -D__NEWLIB__ -MMD -MP -MF"source/cmd_test.d" -MT"source/cmd
_test.o" -MT"source/cmd_test.d" -o "source/cmd_test.o" "../source/cmd_test.c"
Finished building: ../source/cmd_test.c
Building target: QTG.axf
Invoking: MCU Linker
arm-none-eabi-gcc -nostdlib -Xlinker -Map="QTG.map" -Xlinker --gc-sections -Xlin
ker -print-memory-usage -Xlinker --sort-section=alignment -mcpu=cortex-m4 -mfpu=
fpv4-sp-d16 -mfloat-abi=softfp -mthumb -T "QTG_Debug.ld" -u _printf_float -o "QT
G.axf" ./startup/startup_mk22f12810.o ./source/FTM0_IRQHandler.o ./source/FTM2
_IRQHandler.o ./source/PIT0_IRQHandler.o ./source/PIT1_IRQHandler.o ./source/PIT
2_IRQHandler.o ./source/PIT3_IRQHandler.o ./source/QTG.o ./source/UARTGPS_RX_TX_
IRQHandler.o ./source/UARTUSB_RX_TX_IRQHandler.o ./source/advance_time_date.o ./
source/atolx.o ./source/calculate_crc.o ./source/cli.o ./source/cmd_baud.o ./sou
rce/cmd_cal.o ./source/cmd_date.o ./source/cmd_geo.o ./source/cmd_help.o ./sourc
e/cmd_nmea.o ./source/cmd_pinstress.o ./source/cmd_strobe.o ./source/cmd_sysrese
t.o ./source/cmd_tbcmp.o ./source/cmd_test.o ./source/crc_n.o ./source/delay.o .
/source/enqueue_char.o ./source/getchar.o ./source/global_constants.o ./source/g
lobal_variables.o ./source/inpstr.o ./source/parse_cmd_line.o ./source/parse_nme
a.o ./source/qtg.o ./source/queue_full.o ./source/semihost_hardfault.o ./source/
sysclk_start.o ./source/uart_rw.o ./device/system_MK22F12810.o ./board/board.o
./board/clock_config.o ./board/peripherals.o ./board/pin_mux.o
Memory region Used Size Region Size %age Used
PROGRAM_FLASH: 45352 B 128 KB 34.60%
SRAM_UPPER: 4024 B 16 KB 24.56%
SRAM_LOWER: 0 GB 8 KB 0.00%
Finished building target: QTG.axf
QuickSettings>> -> Set library/header type -> Newlib (nohost)
Building file: ../source/cmd_test.c
Invoking: MCU C Compiler
arm-none-eabi-gcc -DFSL_RTOS_BM -DSDK_OS_BAREMETAL -DCPU_MK22FN128VDC10 -DCPU_MK22FN128VDC10_cm4 -D__MCUXPRESSO -D__USE_CMSIS -DDEBUG -D__NEWLIB__ -I/usr/local/mcuxpressoide/arm-none-eabi/include/ -I"/home/username/MCUXpresso/QTG/source" -I"/home/username/MCUXpresso/QTG/device" -I"/home/username/MCUXpresso/QTG/CMSIS" -O0 -fno-common -g3 -Wall -c -ffunction-sections -fdata-sections -ffreestanding -fno-builtin -fsingle-precision-constant -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mthumb -D__NEWLIB__ -MMD -MP -MF"source/cmd_test.d" -MT"source/cmd_test.o" -MT"source/cmd_test.d" -o "source/cmd_test.o" "../source/cmd_test.c"
Finished building: ../source/cmd_test.c
Building target: QTG.axf
Invoking: MCU Linker
arm-none-eabi-gcc -nostdlib -Xlinker -Map="QTG.map" -Xlinker --gc-sections -Xlinker -print-memory-usage -Xlinker --sort-section=alignment -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mthumb -T "QTG_Debug.ld" -o "QTG.axf" ./startup/startup_mk22f12810.o ./source/FTM0_IRQHandler.o ./source/FTM2_IRQHandler.o ./source/PIT0_IRQHandler.o ./source/PIT1_IRQHandler.o ./source/PIT2_IRQHandler.o ./source/PIT3_IRQHandler.o ./source/QTG.o ./source/UARTGPS_RX_TX_IRQHandler.o ./source/UARTUSB_RX_TX_IRQHandler.o ./source/advance_time_date.o ./source/atolx.o ./source/calculate_crc.o ./source/cli.o ./source/cmd_baud.o ./source/cmd_cal.o ./source/cmd_date.o ./source/cmd_geo.o ./source/cmd_help.o ./source/cmd_nmea.o ./source/cmd_pinstress.o ./source/cmd_strobe.o ./source/cmd_sysreset.o ./source/cmd_tbcmp.o ./source/cmd_test.o ./source/crc_n.o ./source/delay.o ./source/enqueue_char.o ./source/getchar.o ./source/global_constants.o ./source/global_variables.o ./source/inpstr.o ./source/parse_cmd_line.o ./source/parse_nmea.o ./source/qtg.o ./source/queue_full.o ./source/semihost_hardfault.o ./source/sysclk_start.o ./source/uart_rw.o ./device/system_MK22F12810.o ./board/board.o ./board/clock_config.o ./board/peripherals.o ./board/pin_mux.o
Memory region Used Size Region Size %age Used
PROGRAM_FLASH: 59660 B 128 KB 45.52%
SRAM_UPPER: 6112 B 16 KB 37.30%
SRAM_LOWER: 0 GB 8 KB 0.00%
Finished building target: QTG.axf
Looks like Newlib Nano does not support formatting of 64-bit types.
Question #219065 : Questions : GNU Arm Embedded Toolchain
I guess if they did, it would no longer be ‘nano’.
Lack of support for 64-bit integers in NewlibNano is not a serious problem because I have plenty of code space available for Newlib. What I don't understand is that I'm getting hard faults when linked with Newlib when attempting to print floating point values. In Properties -> C/C++ Build -> Settings -> MCU Linker -> Managed Linker Script, the Enable printf float and Enable scanf float are grayed-out when Newlib (nohost) is selected, so I don't think I'm misconfiguring anything there.
Is there something specific that needs to be configured when an application is linked with Newlib in order to support printf() and floating point types?
The 'enable printf/scanf' options are grayed out because the are turned on by default in newlib, and you cannot turn it off.
If you get a hardfault with using floating point, this is most likely if a) the printf arguments are wrong or b) you don't have enough stack space allocated (keep in mind that printf and its other family members need a lot of stack space).
Erich
Stack space may indeed be the issue. My prototype board was committed yesterday to running a test fixture and will be unavailable for several weeks, however I've commenced assembly of two more boards and should be able to test with a larger stack allocation soon. Will post a follow-up once I again have hardware that can host my code.
check the new MCUXpresso IDE v11: it has has a cool new view to check the stack usage both for FreeRTOS and bare metal applications: New NXP MCUXpresso Eclipse IDE v11.0 | MCU on Eclipse
Erich
To display a long long (64 bit) you need to use %llu (%lu is just a 32 bit value).
Can you provide a a simple copiable example that shows the double failure?