{"id":589,"date":"2015-02-25T18:17:13","date_gmt":"2015-02-25T17:17:13","guid":{"rendered":"http:\/\/www.verelec.nl\/?page_id=589"},"modified":"2015-02-25T18:17:13","modified_gmt":"2015-02-25T17:17:13","slug":"getting-printf-to-work","status":"publish","type":"page","link":"https:\/\/www.verelec.nl\/?page_id=589","title":{"rendered":"Getting printf to work"},"content":{"rendered":"<p>Being spoiled by the fact that printf is supported on many platforms, it took some time to get this working. But it works. I copied a file called syscalls.c and incorporate it into my projects. this file will give an error from EM::Blocks compiler as <strong>_eBSS<\/strong> is not found by the linker. Both errors can be found in _sbrk(). I modified it a bit (borrowed from another source) and now it works. This is the code:<\/p>\n<p>[code language=&#8221;cpp&#8221;]<br \/>\n\/*<br \/>\n * newlib_stubs.c<br \/>\n *<br \/>\n *  Created on: 2 Nov 2010<br \/>\n *      Author: nanoage.co.uk<br \/>\n *\/<br \/>\n#include &lt;errno.h&gt;<br \/>\n#include &lt;sys\/stat.h&gt;<br \/>\n#include &lt;sys\/times.h&gt;<br \/>\n#include &lt;sys\/unistd.h&gt;<br \/>\n#include &quot;stm32f10x_usart.h&quot;<\/p>\n<p>#ifndef STDOUT_USART<br \/>\n#define STDOUT_USART 1<br \/>\n#endif<\/p>\n<p>#ifndef STDERR_USART<br \/>\n#define STDERR_USART 1<br \/>\n#endif<\/p>\n<p>#ifndef STDIN_USART<br \/>\n#define STDIN_USART 1<br \/>\n#endif<\/p>\n<p>#undef errno<br \/>\nextern int errno;<\/p>\n<p>\/*<br \/>\n environ<br \/>\n A pointer to a list of environment variables and their values.<br \/>\n For a minimal environment, this empty list is adequate:<br \/>\n *\/<br \/>\nchar *__env[1] = { 0 };<br \/>\nchar **environ = __env;<\/p>\n<p>int _write(int file, char *ptr, int len);<\/p>\n<p>void _exit(int status)<br \/>\n{<br \/>\n    _write(1, &quot;exit&quot;, 4);<br \/>\n    while (1) {<br \/>\n        ;<br \/>\n    }<br \/>\n}<\/p>\n<p>int _close(int file)<br \/>\n{<br \/>\n    return -1;<br \/>\n}<br \/>\n\/*<br \/>\n execve<br \/>\n Transfer control to a new process. Minimal implementation (for a system without processes):<br \/>\n *\/<br \/>\nint _execve(char *name, char **argv, char **env)<br \/>\n{<br \/>\n    errno = ENOMEM;<br \/>\n    return -1;<br \/>\n}<br \/>\n\/*<br \/>\n fork<br \/>\n Create a new process. Minimal implementation (for a system without processes):<br \/>\n *\/<\/p>\n<p>int _fork()<br \/>\n{<br \/>\n    errno = EAGAIN;<br \/>\n    return -1;<br \/>\n}<br \/>\n\/*<br \/>\n fstat<br \/>\n Status of an open file. For consistency with other minimal implementations in these examples,<br \/>\n all files are regarded as character special devices.<br \/>\n The `sys\/stat.h&#8217; header file required is distributed in the `include&#8217; subdirectory for this C library.<br \/>\n *\/<br \/>\nint _fstat(int file, struct stat *st)<br \/>\n{<br \/>\n    st-&gt;st_mode = S_IFCHR;<br \/>\n    return 0;<br \/>\n}<\/p>\n<p>\/*<br \/>\n getpid<br \/>\n Process-ID; this is sometimes used to generate strings unlikely to conflict with other processes. Minimal implementation, for a system without processes:<br \/>\n *\/<\/p>\n<p>int _getpid()<br \/>\n{<br \/>\n    return 1;<br \/>\n}<\/p>\n<p>\/*<br \/>\n isatty<br \/>\n Query whether output stream is a terminal. For consistency with the other minimal implementations,<br \/>\n *\/<br \/>\nint _isatty(int file)<br \/>\n{<br \/>\n    switch (file) {<br \/>\n    case STDOUT_FILENO:<br \/>\n    case STDERR_FILENO:<br \/>\n    case STDIN_FILENO:<br \/>\n        return 1;<br \/>\n    default:<br \/>\n        \/\/errno = ENOTTY;<br \/>\n        errno = EBADF;<br \/>\n        return 0;<br \/>\n    }<br \/>\n}<\/p>\n<p>\/*<br \/>\n kill<br \/>\n Send a signal. Minimal implementation:<br \/>\n *\/<br \/>\nint _kill(int pid, int sig)<br \/>\n{<br \/>\n    errno = EINVAL;<br \/>\n    return (-1);<br \/>\n}<\/p>\n<p>\/*<br \/>\n link<br \/>\n Establish a new name for an existing file. Minimal implementation:<br \/>\n *\/<\/p>\n<p>int _link(char *old, char *new)<br \/>\n{<br \/>\n    errno = EMLINK;<br \/>\n    return -1;<br \/>\n}<\/p>\n<p>\/*<br \/>\n lseek<br \/>\n Set position in a file. Minimal implementation:<br \/>\n *\/<br \/>\nint _lseek(int file, int ptr, int dir)<br \/>\n{<br \/>\n    return 0;<br \/>\n}<\/p>\n<p>\/*<br \/>\n sbrk<br \/>\n Increase program data space.<br \/>\n Malloc and related functions depend on this<br \/>\n *\/<br \/>\ncaddr_t _sbrk(int incr)<br \/>\n{<br \/>\n    extern char end asm(&quot;end&quot;); \/\/ Defined by the linker<br \/>\n    static char *heap_end;<br \/>\n    char *prev_heap_end;<\/p>\n<p>    if (heap_end == 0) {<br \/>\n        heap_end = &amp;end;<br \/>\n    }<br \/>\n    prev_heap_end = heap_end;<\/p>\n<p>    char * stack = (char*) __get_MSP();<br \/>\n    if (heap_end + incr &gt;  stack) {<br \/>\n        _write (STDERR_FILENO, &quot;Heap and stack collision\\n&quot;, 25);<br \/>\n        errno = ENOMEM;<br \/>\n        return  (caddr_t) -1;<br \/>\n        \/\/abort ();<br \/>\n    }<\/p>\n<p>    heap_end += incr;<br \/>\n    return (caddr_t) prev_heap_end;<\/p>\n<p>}<\/p>\n<p>\/*<br \/>\n read<br \/>\n Read a character to a file. `libc&#8217; subroutines will use this system routine for input from all files, including stdin<br \/>\n Returns -1 on error or blocks until the number of characters have been read.<br \/>\n *\/<\/p>\n<p>int _read(int file, char *ptr, int len)<br \/>\n{<br \/>\n    int n;<br \/>\n    int num = 0;<br \/>\n    switch (file) {<br \/>\n    case STDIN_FILENO:<br \/>\n        for (n = 0; n &lt; len; n++) {<br \/>\n#if   STDIN_USART == 1<br \/>\n            while ((USART1-&gt;SR &amp; USART_FLAG_RXNE) == (uint16_t)RESET) {}<br \/>\n            char c = (char)(USART1-&gt;DR &amp; (uint16_t)0x01FF);<br \/>\n#elif STDIN_USART == 2<br \/>\n            while ((USART2-&gt;SR &amp; USART_FLAG_RXNE) == (uint16_t) RESET) {}<br \/>\n            char c = (char) (USART2-&gt;DR &amp; (uint16_t) 0x01FF);<br \/>\n#elif STDIN_USART == 3<br \/>\n            while ((USART3-&gt;SR &amp; USART_FLAG_RXNE) == (uint16_t)RESET) {}<br \/>\n            char c = (char)(USART3-&gt;DR &amp; (uint16_t)0x01FF);<br \/>\n#endif<br \/>\n            *ptr++ = c;<br \/>\n            num++;<br \/>\n        }<br \/>\n        break;<br \/>\n    default:<br \/>\n        errno = EBADF;<br \/>\n        return -1;<br \/>\n    }<br \/>\n    return num;<br \/>\n}<\/p>\n<p>\/*<br \/>\n stat<br \/>\n Status of a file (by name). Minimal implementation:<br \/>\n int    _EXFUN(stat,( const char *__path, struct stat *__sbuf ));<br \/>\n *\/<\/p>\n<p>int _stat(const char *filepath, struct stat *st)<br \/>\n{<br \/>\n    st-&gt;st_mode = S_IFCHR;<br \/>\n    return 0;<br \/>\n}<\/p>\n<p>\/*<br \/>\n times<br \/>\n Timing information for current process. Minimal implementation:<br \/>\n *\/<\/p>\n<p>clock_t _times(struct tms *buf)<br \/>\n{<br \/>\n    return -1;<br \/>\n}<\/p>\n<p>\/*<br \/>\n unlink<br \/>\n Remove a file&#8217;s directory entry. Minimal implementation:<br \/>\n *\/<br \/>\nint _unlink(char *name)<br \/>\n{<br \/>\n    errno = ENOENT;<br \/>\n    return -1;<br \/>\n}<\/p>\n<p>\/*<br \/>\n wait<br \/>\n Wait for a child process. Minimal implementation:<br \/>\n *\/<br \/>\nint _wait(int *status)<br \/>\n{<br \/>\n    errno = ECHILD;<br \/>\n    return -1;<br \/>\n}<\/p>\n<p>\/*<br \/>\n write<br \/>\n Write a character to a file. `libc&#8217; subroutines will use this system routine for output to all files, including stdout<br \/>\n Returns -1 on error or number of bytes sent<br \/>\n *\/<br \/>\nint _write(int file, char *ptr, int len)<br \/>\n{<br \/>\n    int n;<br \/>\n    switch (file) {<br \/>\n    case STDOUT_FILENO: \/*stdout*\/<br \/>\n        for (n = 0; n &lt; len; n++) {<br \/>\n#if STDOUT_USART == 1<br \/>\n            while ((USART1-&gt;SR &amp; USART_FLAG_TC) == (uint16_t)RESET) {}<br \/>\n            USART1-&gt;DR = (*ptr++ &amp; (uint16_t)0x01FF);<br \/>\n#elif  STDOUT_USART == 2<br \/>\n            while ((USART2-&gt;SR &amp; USART_FLAG_TC) == (uint16_t) RESET) {<br \/>\n            }<br \/>\n            USART2-&gt;DR = (*ptr++ &amp; (uint16_t) 0x01FF);<br \/>\n#elif  STDOUT_USART == 3<br \/>\n            while ((USART3-&gt;SR &amp; USART_FLAG_TC) == (uint16_t)RESET) {}<br \/>\n            USART3-&gt;DR = (*ptr++ &amp; (uint16_t)0x01FF);<br \/>\n#endif<br \/>\n        }<br \/>\n        break;<br \/>\n    case STDERR_FILENO: \/* stderr *\/<br \/>\n        for (n = 0; n &lt; len; n++) {<br \/>\n#if STDERR_USART == 1<br \/>\n            while ((USART1-&gt;SR &amp; USART_FLAG_TC) == (uint16_t)RESET) {}<br \/>\n            USART1-&gt;DR = (*ptr++ &amp; (uint16_t)0x01FF);<br \/>\n#elif  STDERR_USART == 2<br \/>\n            while ((USART2-&gt;SR &amp; USART_FLAG_TC) == (uint16_t) RESET) {<br \/>\n            }<br \/>\n            USART2-&gt;DR = (*ptr++ &amp; (uint16_t) 0x01FF);<br \/>\n#elif  STDERR_USART == 3<br \/>\n            while ((USART3-&gt;SR &amp; USART_FLAG_TC) == (uint16_t)RESET) {}<br \/>\n            USART3-&gt;DR = (*ptr++ &amp; (uint16_t)0x01FF);<br \/>\n#endif<br \/>\n        }<br \/>\n        break;<br \/>\n    default:<br \/>\n        errno = EBADF;<br \/>\n        return -1;<br \/>\n    }<br \/>\n    return len;<br \/>\n}<\/p>\n<p>\/**<br \/>\n * @brief initialize usart1<br \/>\n * @name usart1_init<br \/>\n * initializes the UART1 port<br \/>\n *\/<br \/>\nvoid usart1_init(){<br \/>\n    GPIO_InitTypeDef \t\tGPIO_InitStructure;\t\t\t\/\/ create a GPIO init structure<br \/>\n    USART_InitTypeDef \t\tUSART_InitStructure;\t\t\/\/ create a USART init structure<br \/>\n    USART_ClockInitTypeDef  USART_ClockInitStructure;\t\/\/ create a CLOCK init structure<br \/>\n    \/\/<br \/>\n    \/\/ since we are connecting an on-chip peripheral (USART) to the IO pin, we must<br \/>\n    \/\/ configure it to enable alternate IO functions (AFIO). But we must enable the clock first<br \/>\n    \/\/ thus to enable USART1 we must:<br \/>\n    \/\/ &#8211; enable the peripheral<br \/>\n    \/\/ &#8211; enable GPIOA as our pins are connected to GPIOA<br \/>\n    \/\/ &#8211; enable alternate IO functions to connect USART1 to GPIOA<br \/>\n    \/\/<br \/>\n    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);<br \/>\n    \/\/<br \/>\n    \/\/Configure USART1 Tx (PA.09) as alternate function push-pull<br \/>\n    \/\/<br \/>\n    GPIO_InitStructure.GPIO_Pin \t= GPIO_Pin_9;<br \/>\n    GPIO_InitStructure.GPIO_Mode \t= GPIO_Mode_AF_PP;<br \/>\n    GPIO_InitStructure.GPIO_Speed \t= GPIO_Speed_50MHz;<br \/>\n    GPIO_Init(GPIOA, &amp;GPIO_InitStructure);<br \/>\n    \/\/<br \/>\n    \/\/Configure USART1 Rx (PA.10) as input floating<br \/>\n    \/\/<br \/>\n    GPIO_InitStructure.GPIO_Pin \t= GPIO_Pin_10;<br \/>\n    GPIO_InitStructure.GPIO_Mode \t= GPIO_Mode_IN_FLOATING;<br \/>\n    GPIO_Init(GPIOA, &amp;GPIO_InitStructure);<br \/>\n    \/\/<br \/>\n    \/\/ initialize USART Clock<br \/>\n    \/\/<br \/>\n    USART_ClockStructInit(&amp;USART_ClockInitStructure);<br \/>\n    USART_ClockInit(USART1, &amp;USART_ClockInitStructure);<br \/>\n    \/\/<br \/>\n    \/\/ set defaults in USART init structure<br \/>\n    \/\/<br \/>\n    USART_StructInit(&amp;USART_InitStructure);<br \/>\n    \/\/<br \/>\n    \/\/ Configure USART1 basic and asynchronous parameters<br \/>\n    \/\/<br \/>\n    USART_InitStructure.USART_BaudRate=921600;\t\t\t\t\/\/ just change the baud rate in this case<br \/>\n    \/\/<br \/>\n    \/\/ initialize the USART<br \/>\n    \/\/<br \/>\n    USART_Init(USART1, &amp;USART_InitStructure);<br \/>\n    \/\/<br \/>\n    \/\/Enable USART1<br \/>\n    \/\/<br \/>\n    USART_Cmd(USART1, ENABLE);<br \/>\n}<br \/>\n\/** @brief Delay function<br \/>\n * @name Delay(volatile uint32_t ncCount)<br \/>\n * @param nCount delay number of counts. Very unclear what actually<br \/>\n * @return none<br \/>\n *<br \/>\n *\/<br \/>\nvoid Delay(volatile uint32_t nCount)<br \/>\n{<br \/>\n    for (; nCount != 0; nCount&#8211;);<br \/>\n}<\/p>\n<p>[\/code]<\/p>\n<p>I added 2 extra functions for my purpose and experimenting. Just put the code in a file and add the file (.c) to the project. Now printf will work outputting stdin, stdout and stderr to the serial monitor or terminal program. Now we are not there yet. floating point is usually omitted from a standard binary. A simple parameter in the linker will solve this:<\/p>\n<ul>\n<li>go to project build options<\/li>\n<li>select either Release \/ Debug<\/li>\n<li>Select linker settings tab<\/li>\n<li>select other options<\/li>\n<li>add <strong>-u _printf_float<\/strong><\/li>\n<li>clock OK etc&#8230; and done<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Being spoiled by the fact that printf is supported on many platforms, it took some time to get this working. But it works. I copied a file called syscalls.c and incorporate it into my projects. this file will give an &hellip; <a href=\"https:\/\/www.verelec.nl\/?page_id=589\">Lees verder <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"open","ping_status":"open","template":"","meta":{"footnotes":""},"_links":{"self":[{"href":"https:\/\/www.verelec.nl\/index.php?rest_route=\/wp\/v2\/pages\/589"}],"collection":[{"href":"https:\/\/www.verelec.nl\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.verelec.nl\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.verelec.nl\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.verelec.nl\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=589"}],"version-history":[{"count":2,"href":"https:\/\/www.verelec.nl\/index.php?rest_route=\/wp\/v2\/pages\/589\/revisions"}],"predecessor-version":[{"id":591,"href":"https:\/\/www.verelec.nl\/index.php?rest_route=\/wp\/v2\/pages\/589\/revisions\/591"}],"wp:attachment":[{"href":"https:\/\/www.verelec.nl\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=589"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}