cancel
Showing results for 
Search instead for 
Did you mean: 

How to use printf() to output to UART

gerhard
Associate II

I have been using printf() to output to UART for many years on a STM32L052

All these projects still compile and printf() to UART, no problem.

I started a NEW project with CubeMX, but now printf() does NOT print to UART.

I use the same int fputc(int ch, FILE *f) as in ALL the other projects, but still no UART output. (Plese see attached code)

I looked at other solutions, but they seem to be doing similar int fputc(int ch, FILE *f)

Any help appreciated

12 REPLIES 12
TDK
Guru

Does HAL_UART_Transmit work if it's used directly within the main program?

If you put a breakpoint within fputc, does it get hit?

If you feel a post has answered your question, please click "Accept as Solution".
gerhard
Associate II

TDK,

YES - HAL_UART_Transmit(&huart1, (uint8_t *)message, string_lenght, 100);

NO - Does NOT break at fputc

gerhard
Associate II

TDK,

The app actually crashes at my printf("\r\nmyString\r\n");

Regards

Printf uses the heap by default. Could be an issue there. Look into what “crash�? means. Debug the code, find out where the cpu is at.
If you feel a post has answered your question, please click "Accept as Solution".
Paul1
Lead

Possibly:

STM32 provides two versions of libs used for for printf = with/without floating point.

Check your compile settings, maybe running out of memory due to overhead for floating point.

Try setting your projects compile options for "no floating point"

Paul

gerhard
Associate II

Paul,

I am still struggling to make it work.

If I put breakpoints, and step over, the app does NOT crash.

printf() still has NO output, but is does not crash, and the rest of the app continues.

If I remove the breakpoints, the app crashes, and I cannot figure out where / why.

Also., I am using IAR, and cannot find where the compile setting is for floating point.

I only see the FPU option under General Options > 32Bit, but FPU is grayed out

Regards

Rehards

Paul1
Lead

Qualifier: We're not using IAR or the exact STM32 you are, but we are using many different STM32, with both UART and VCP for terminal diagnostics by printf, and UART for data communications.

Attached is a screen capture from our STM32 troubleshooting, it has several points that may help.

  • STM32_printf_troubleshooting_20220428PR.png
  • (We build these inhouse wiki's because of two things: (a) I have an ever changing team of student co-op engineers (b) I have a rotten memory).

One more:

  • Ensure you have your compiler warnings and errors turned up on bust (turn off only as needed). Missing simple warnings like like an int for a long or a float for a double can wreak havoc when a printf is trying to deciphers its stacked data list.
  • To separate checks on generated code from your own code: I do all my code in cpp files, even when only C-code. C++ checking is much stronger and catches more bugs, and I can set cpp compiler warnings separate from the c compiler warnings used for MX generated files.
  •  

Paul

Paul1
Lead

Also:

As TDK said check your heap.

I have no idea how IAR determines the heap size.

Quick test: make the heap as big as possible (and still compile).

Careful that increasing heap isn't hiding an actual bug!!

Recall my note about bad memory above? Just had a brain fart...

I've seen crashes like you mention when code references data in stacked/alloc'd variables that have been released (like temp internal variable in a function). Typically happens with pointers or alloc'd, but may happen in other scenarios. Somewhere a pointer is set, but the thing pointed to was a temporary stacked variable. Later you printf that item. Depending what has happened to stack or heap that data may or may not still be there. Enabling debugger changes how the memory is affected and may allow your code to survive longer, but not reliably.

Soln: tedious, but trace through your code tell you find the "released/orphaned" data and change how you handle that data.

Warn: The fault may not actually be in current printf, it could be in preceding code that uses the orphaned data and leaves stack corrupted so later code fails upon a "return".

Tracing/Debugging: What I do to catch these is just put a whole bunch of printf+waitempty in my code (I make a macro for the pair as I may be putting 20-50 of these in at a time). Basically it is a printf, followed by a function that loops till the UART is empty. That way you know that printf completed properly and any crash is truly for later code, or in code that called this code. I put the printf+waitempty between most every line, removing later as I determine it is before/after a particular printf+waitempty and crashing at a different printf+waitempty.

Paul

// The standard printf will consume too many resources. here is a light alternative:

// called xprintf)

static int inited = 0;
static char tmp[16];
static SemaphoreHandle_t BinSemHandle;
 
// This will do int, hex, str, float (%d %x %s %f) [pasted from working code]
 
int xprintf(const char *str, ...)
{
 
   if(!inited) 
   {
      inited = 1;
      BinSemHandle = xSemaphoreCreateBinary(); xSemaphoreGive(BinSemHandle);
   }
 
  // So one can call it forn different threads (tasks)
   xSemaphoreTake(BinSemHandle, portMAX_DELAY);
   va_list ap;
   va_start(ap, str);
 
   int len = strlen(str);
   for(int aa = 0; aa < len; aa++)
   {
      char chh = str[aa];
      if(chh == '%')
      {
         if(str[aa+1] == 'd')
            {
            int vvv = va_arg(ap, int);
            itoa(vvv, tmp, 10);
            HAL_UART_Transmit(&huart2, (uint8_t *)tmp, strlen(tmp), HAL_MAX_DELAY);
            }
         else if(str[aa+1] == 'x')
            {
            int vvv = va_arg(ap, int);
            itoa(vvv, tmp, 16);
            HAL_UART_Transmit(&huart2, (uint8_t *)tmp, strlen(tmp), HAL_MAX_DELAY);
            }
         else if(str[aa+1] == 'f')
            {
            double vvv = va_arg(ap, double);
            gcvt(vvv, 4, tmp);
            HAL_UART_Transmit(&huart2, (uint8_t *)tmp, strlen(tmp), HAL_MAX_DELAY);
            }
         else if(str[aa+1] == 's')
            {
            char *sss = va_arg(ap, char*);
            HAL_UART_Transmit(&huart2, (uint8_t *)sss, strlen(sss), HAL_MAX_DELAY);
            }
         else
            {
            HAL_UART_Transmit(&huart2, (uint8_t *)str[aa+1], 1, HAL_MAX_DELAY);
            }
         aa++;
      }
      else
      {
         HAL_UART_Transmit(&huart2, (uint8_t *)&str[aa], 1, HAL_MAX_DELAY);
      }
   }
   xSemaphoreGive(BinSemHandle);
   return len;
}