STM32 HAL: используем printf

В сгенерированный кубом код нужно добавить следующий кусок в main.c:

#include  <errno.h>
#include  <sys/unistd.h> // STDOUT_FILENO, STDERR_FILENO

int _write(int file, char *data, int len)
{
   if ((file != STDOUT_FILENO) && (file != STDERR_FILENO))
   {   
      errno = EBADF;
      return -1; 
   }   

   // arbitrary timeout 1000
   HAL_StatusTypeDef status =
      HAL_UART_Transmit(&huart1, (uint8_t*)data, len, 1000);

   // return # of bytes written - as best we can tell
   return (status == HAL_OK ? len : 0); 
}

Я добавляю после /* USER CODE BEGIN 4 */. UART должен быть предварительно настроен. Да, это блокирующий код, но пока что он меня устраивает.

STM32: OpenOCD semihosting

Небольшая заметка для себя, чтобы не гуглить заново в следующий раз.

  • В Makefile меняем параметры линкера: вместо -specs=nano.specs пишем -specs=rdimon.specs, вместо -lnosys пишем -lrdimon. Мне также пришлось добавить -Wl,—no-wchar-size-warning, т. к. размерность wchar где-то не совпала.
  • В коде до main объявляем функцию extern void initialise_monitor_handles(void) и вызываем её в начале main. Важный момент — при отсутствии принимающей стороны на хосте этот вызов приведёт к HardFault, т. е. система сможет работать только под отладчиком.
  • Запускаем OpenOCD с командой arm semihosting enable и в его выводе увидим сообщения от printf. Ещё один важный момент — вывод будет в отладочных сообщениях, по telnet его не видно.
  • Для младших контроллеров может стать проблемой увеличение размера прошивки. В STM32F030 пришлось уменьшить размер Min_Heap_Size в LD-скрипте.