CH32V003 Can't printf floating point values, is there a .h include to support? - Page 1
Forum section: electronics / general

author: rka
author_rank: Newbie
timestamp: June 09, 2024, 07:22:34 pm
content: Hello all,I've just recently gotten a CH32V003 EVT board running on WCH's Moun River IDE. One of the things I wanted to do initially was to try some timings, and so to ensure I could do floating point for my math I added a simple float printf to the GPIO routine in the EXAM section.float foo = 22.15;printf("FOO is: %2.2 \n\r", foo);This results in:FOO is: << No value returnedOn one hand I think that the CH32V003 is a small controller and wouldn't support floating point.On the other hand, I wondered whether I'd missed a step and left out a .h include file for example.After a lot of queries on Google and looking through the RM, I'm not finding any hints one way or another.Mavens -- Any ideas?rka

author: rka
author_rank: Newbie
timestamp: June 09, 2024, 07:25:01 pm
content: Correction,float foo = 22.15;printf("FOO is: %2.2f \n\r", foo);

author: ataradov
author_rank: Super Contributor
timestamp: June 09, 2024, 08:30:06 pm
content: This depends on the C library used in the compiler, there is no way to fix this with a single .h include. No idea what stock WCH toolchain uses, but generally it is not viable to have floating point printf() on a 16 KB MCU. On ARM full printf() with floating point support is about 20 KB.

author: amwales
author_rank: Regular Contributor
timestamp: June 09, 2024, 09:29:26 pm
content: I have mounriver intalled but there doesnt appear to be any source for the libraries so its impossible to tell why they work the way they do unless you can find some documentation. You should be able to accomplish what you are after with something like this, assuming %d worksprintf("%d.%d\n", (int)foo, (int)((foo - (int)foo)*100));

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 09, 2024, 09:38:11 pm
content: floating point support is usually disabled by default when using GCC with newlib (nano), which is likely what you have here.One way of enabling it is to pass the "-u _printf_float" option to the linker. If you're using some IDE, look at compiler/linker options and see if there is any such option available.As ataradov, it's not recommended when you have very little memory available though, it takes a lot of it.

author: brucehoult
author_rank: Super Contributor
timestamp: June 10, 2024, 07:33:02 am
content: I tried the following stupid little program (bonus points if you know the result without actually running it):Code:#include <stdio.h>int main(){float total=0,last=0,sign=4,cnt=1;do {last = total;total = total + sign/cnt;sign = -sign;cnt += 2;//printf("%d: %f\n", (int)cnt, total);} while (total != last);return 100*total;}Compiled with generic RISC-V gcc 14 newlib toolchain, not whatever is in MounRiver...ISAtextdatarv32gc54761416rv32ic117401416rv32ic800161872Uncomment printfrv32ic13936120Uncomment printf, nano.specrv32ic7988124nano.specSo soft float costs just over 6k (library, plus longer code to marshal arguments, call the functions etc). That's a chunk of a 16k flash but not a killer.printf with fp support? Forget it. Blows the flash out by 5x.printf fits ok with Newlib Nano ... and it runs with trying to print the float, but simply ignores it. Not useful if you actually wanted to printf a float. But if your own code is small then printf for integers and strings can be ok on the 003.I don't have my toolchain configured with rv32ec libs

author: AVI-crak
author_rank: Regular Contributor
timestamp: June 10, 2024, 09:07:12 am
content: intended purpose - macro printo();printo("text", double, float, uint(8-16-32-64)_t, int(8-16-32-64)_t )printing without specifying the type of the variable,up to 9 variables and constants at a time,has no external dependencies,all functions are thread independent,minimum weight +140 bytes, complete set 1684 bytes,maximum speed 20~470 ticks,does not use division and floating point,optimized for ARMhttps://github.com/AVI-crak/Rtos_cortex/tree/master/printo

author: langwadt
author_rank: Super Contributor
timestamp: June 10, 2024, 12:14:41 pm
content: Quote from: brucehoult on June 10, 2024, 07:33:02 amtried this?https://github.com/mpaland/printf

author: brucehoult
author_rank: Super Contributor
timestamp: June 10, 2024, 12:19:50 pm
content: Quote from: AVI-crak on June 10, 2024, 09:07:12 amThat might be "optimised for Arm", but other than one optional use of inline asm it's all plain C code that compiles out of the box for RV32 (but not RV64 due to assumptions of the size of long/long long).Seems to pass almost all tests ootb.Code:bruce@i9:~/programs/Rtos_cortex/printo$ riscv64-unknown-elf-gcc -O -march=rv32imc -mabi=ilp32 test.c printo.c -o testbruce@i9:~/programs/Rtos_cortex/printo$ ./test23:24:35inf float = inf-inf float = -infnan float = NaN-nan float = -NaN0 float =-0 float = -1.11111111111d = 1.111111111110000049-1.0f = -1.000000000000000000-1uL = -2.3283062981.5f = 1.500000000000000000-1uL = 1.499999880790710449I suspect maybe a non-portable assumption about struct bitfield packing rules. Dunno. But it's very close.Code:#include <stdio.h>#include "printo.h"void M_print(char *text){puts(text);}int main(){print_float(355./113);return 0;}Output:Code:3.141592979431152344That's 7 accurate digits, then junk.The float_char() ("convert float to string") function is 116 bytes of code, and it tail-calls floating_char() which is 244 bytes. Floating_char() calls 64 bit multiply (174 bytes) and shift (40 bytes) utility functions which I'm not convinced are better than gcc would simply do for you if you just wrote the C code. And it calls a couple of character out functions.

author: rka
author_rank: Newbie
timestamp: June 10, 2024, 01:57:01 pm
content: All,Thank you all for your in-depth responses to my little question.I must admit that they have been very instructive for this CH32V Newbie.Most of my time spent fooling with these SOC things has been mostly using larger devices (ESP32, STM32, NXP, etc.) in which RAM isn't such a big limiter. Also, that work has been done with Arduino and PlatformIO, which has a larger legacy community base and is far more mature.As I've played with this device I've gravitated towards approaches that I'm familiar with, hence my question. However, after reading the responses I a little in awe at the "virtuousity" of the replies (I'm not trying to flatter anyone, it's just a great example of real serious technical analysis to my eye).I'll try a couple of the suggestions to go a couple steps further in appreciating the problem at hand. Thanks again.rks

author: AVI-crak
author_rank: Regular Contributor
timestamp: June 10, 2024, 02:31:08 pm
content: The calculation method differs from the standard printf().All sacrifices for the sake of speed - my project worked in real time.

author: HwAoRrDk
author_rank: Super Contributor
timestamp: June 10, 2024, 03:17:48 pm
content: Quote from: langwadt on June 10, 2024, 12:14:41 pmThis is what I use with CH32V with good success, much smaller than newlib implementation. When compiled withPRINTF_DISABLE_SUPPORT_FLOAT,PRINTF_DISABLE_SUPPORT_EXPONENTIAL, andPRINTF_DISABLE_SUPPORT_LONG_LONGit occupies only approx. 2kB. Can't comment on its floating point support, or how that changes the size, as I've never used it.

author: brucehoult
author_rank: Super Contributor
timestamp: June 10, 2024, 03:24:05 pm
content: Quote from: AVI-crak on June 10, 2024, 02:31:08 pmI'd suggest a utility function to allow printing only the first N digits of the generated string. And use N = 7 for float.What do you think is happening with -1.0f - 1UL? It's just completely wrong. That's bf7fffff (I assume by "-1UL" you mean "towards zero") being printed as c01502f8 should be. Those aren't even similar in any way.

author: ejeffrey
author_rank: Super Contributor
timestamp: June 10, 2024, 05:02:46 pm
content: You need to include the printf float routines. As an alternative to linker command line options it should work to add the following to one of your source files:asm(".global _printf_float");

author: AVI-crak
author_rank: Regular Contributor
timestamp: June 11, 2024, 03:55:26 am
content: /// determine the number of characters for numbers (6-20)#define OUT_TXT_SIZE_FLOATING 17 <-----------------#define DEL_ZERO 0Quote from: brucehoult on June 10, 2024, 03:24:05 pmFixed the test a little bit.

author: brucehoult
author_rank: Super Contributor
timestamp: June 11, 2024, 04:49:07 am
content: Quote from: AVI-crak on June 11, 2024, 03:55:26 amomg that's got to be the least convenient way ever to get an update. wget doesn't really interact with eevblog attachment URLs very well. Just "git pull" would have been far simpler.Anyway, I'm seeing a ton of weird whitespace/indentation changes, which don't matter. And replacing 'printf("\n ...' with 'printf("\n\r ...' everywhere ... whyyyy? What is that supposed to do? Any system that needs CRLF line endings is supposed to expand \n to CRLF so on Windows or something that should produce CRLFCR which is redundant. On Linux and Mac it just screws everything up.More importantly, I'm not seeing anything fixed.All of the following outputs are similarly weird:-2.328306298 -1f -1uL2.328306437 1e+8f2.328306250 1e+8f -1uL2.328306437 1e+10f2.328306198 1e+8f -1uL2.328306298 1.0000000149e-1f -1uL2.328306303 1.00000001335e-10f -1uL2.328306437 9.999999999d2.328306363 test.fl 9.99999968266e-23fAll other results look ok.

author: westfw
author_rank: Super Contributor
timestamp: June 11, 2024, 08:19:42 am
content: QuoteThere's asoftware floating point library for Cortex-M0that fits in about 1k.I'm not familiar enough with either architecture to tell whether it's conceptually portable to RISC-V.

author: brucehoult
author_rank: Super Contributor
timestamp: June 11, 2024, 09:19:46 am
content: Quote from: westfw on June 11, 2024, 08:19:42 amYou can do it very small if the results are not required to be accurate to the last bit, support Nans, infinities, denorms etc. The FP library used by AVR Arduino is a great example.On the other extreme is Apple's SANE implementation of full IEEE 754 math (or 8087/68881 compatible anyway) for the 6502https://apple.fandom.com/wiki/Standard_Apple_Numerics_Environment

author: AVI-crak
author_rank: Regular Contributor
timestamp: June 11, 2024, 09:35:16 am
content: I don't have a CH32V003. The test runs on CH32V307VCT6, stm32f030f4, STM32F746BG - no errors./// determine the number of characters for numbers (6-20)#define OUT_TXT_SIZE_FLOATING 17 <----------------- исправить на 17#define DEL_ZERO 0Code:void _write_o(char *buf){while(*buf != 0){#if(DEBUG == DEBUG_UART1)while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);USART_SendData(USART1, *buf++);#elif(DEBUG == DEBUG_UART2)while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);USART_SendData(USART2, *buf++);#elif(DEBUG == DEBUG_UART3)while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);USART_SendData(USART3, *buf++);#endif}}

author: brucehoult
author_rank: Super Contributor
timestamp: June 11, 2024, 11:13:13 am
content: Quote from: AVI-crak on June 11, 2024, 09:35:16 amI don't either -- or at least I'm not using it for this.I'm running on QEMU (via bimfmt_misc) after building with standard GCC. Both are a simple package install away on all major OSes: HomeBREW on Mac , apt get on Debian-based including Windows WSL. If you're running Fedora or Arch or Alpine or something then I'm sure you know your own package management system. actually I'd recommend docker on Mac

author: AVI-crak
author_rank: Regular Contributor
timestamp: June 11, 2024, 06:54:02 pm
content: brucehoult - It works for me...

author: cnich
author_rank: Newbie
timestamp: June 12, 2024, 01:36:11 pm
content: https://github.com/charlesnicholson/nanoprintfis a single .h file implementation of printf that supports float/double and is designed with tiny systems in mind; perhaps it might help you?

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 12, 2024, 10:13:38 pm
content: Quote from: cnich on June 12, 2024, 01:36:11 pmI have used nanoprintf. Fun fact, compared to using printf from newlib nano, it actually took more code size (tested on a RISCV, GCC with -02).