I am new to the world of STM32F103. I have a demo code for STM32F103 and I am using arm-none-eabi to compile it.
I tried what I could find on Google, but nothing worked so far. I have already spent three days on the problem.
Anyone can give me a demo code for printf which works well?
Part of my makefile:
CFLAG = -mcpu=$(CPU) -mthumb -Wall -fdump-rtl-expand -specs=nano.specs --specs=rdimon.specs -Wl,--start-group -lgcc -lc -lm -lrdimon -Wl,--end-group
LDFLAG = -mcpu=$(CPU) -T ./stm32_flash.ld -specs=nano.specs --specs=rdimon.specs -Wl,--start-group -lgcc -lc -lm -lrdimon -Wl,--end-group
Writing an own printf
implementation is an option, and probably the most recommended option according to me. Get some inspiration from the standard library implementation and write your own version, only to cater your requirements. In general, what you have to do is, first retarget a putc
function to send char s through your serial interface. Then override the printf
method by using the putc
custom implementation. Perhaps, a very simple approach is sending the string character-wise by recursive calls for putc
function.
Last but not least, you can find some lightweight printf
implementations. The code size and the set of features offered by these lightweight implementations lie in between the custom written printf
function and the stock standard printf
function (aka the beast). I have recently tried this Tiny Printf and very pleased with its performance on an ARM core in terms of memory footprint and the number of execution cycles required.
-PS
Copied from my own writings sometime back.
Link: How to retarget printf() on an STM32F10x?
Try hijacking the _write function like so:
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
int _write(int file, char *ptr, int len)
{
switch (file)
{
case STDOUT_FILENO: /*stdout*/
// Send the string somewhere
break;
case STDERR_FILENO: /* stderr */
// Send the string somewhere
break;
default:
return -1;
}
return len;
}
The original printf will go through this function (depending on what libs you use of course).
Look there. This is printf
from glib
. But you have microcontroller. So you sould write own printf
, where vfprintf
will return result into buffer and next you will send data from buffer to UART. Kind of
void printf( const char * format, ... )
{
char buffer[256];
va_list args;
va_start (args, format);
vsprintf (buffer,format, args);
send_via_USART1 (buffer);
va_end (args);
}
Also you can write own vsprintf
. Standart vsprintf
is very heavy. Usually little part of vsprintf
features is used.
By including the following linker flags:
LDFLAGS += --specs=rdimon.specs -lc -lrdimon
it looks like you are trying to use what is called semihosting. You are telling the linker to include system call libraries.
Semihosting is a mechanism that enables code running on an ARM target to communicate and use the Input/Output facilities on a host computer that is running a debugger.
Examples of these facilities include keyboard input, screen output, and disk I/O. For example, you can use this mechanism to enable functions in the C library, such as printf() and scanf(), to use the screen and keyboard of the host instead of having a screen and keyboard on the target system.
Since you are using openSource tools for your STM32 development (Makefile and arm-none-eabi), I am assuming you are also using openOCD to program your microcontroller. openOCD requires you to enable semihosting as well using the following command:
arm semihosting enable
You can at the command to your openOCD script making sure you terminate the configuration stage and enter the run stage with the 'init' command. Below is an example of an openOCD script (adapted for STM32F103):
source [find target/stm32f1x.cfg]
init
arm semihosting enable
Other solutions mentioned here where your retarget the fputc()
function to a UART interface will also work and might. Semihosting will work on all recent ARM Cortex-M but will require some compiler & debugger configuration (see above). Retargeting the fputc()
function to a UART interface will work with any compiler but you will have to check your pin configurations for every board.