英文:
How to properly retarget STM32 fprintf to multiple destinations (uarts)?
问题
我正在尝试使用fprintf(或printf)将输出发送到多个目标(UARTS),使用GCC编译器。
覆盖_write_r仅适用于stderr:
int _write_r(void *reent, int fd, char *ptr, size_t len) // stderr
{
__asm volatile ("nop");
__asm volatile ("nop");
return _write((FILE*)fd, ptr, len);
//return 0;
}
fprintf(stdout, "Error reading file"); // 正常工作!
但是尝试以下操作没有效果,根本不会调用_write_r():
fprintf((FILE *)USART1, "Error reading file 2");
所以基本上我计划使用switch/case根据不同的目标进行输出。
ST社区上有一些示例,但它们使用__io_putchar(int ch),这样就无法在不同目标之间切换。
有什么想法吗?
谢谢!
英文:
I am trying to use fprintf (or printf) to multiple destinations (UARTS) using GCC
Overriding _write_r works only for stderr:
int _write_r(void *reent, int fd, char *ptr, size_t len) // stderr
{
__asm volatile ("nop");
__asm volatile ("nop");
return _write((FILE*)fd, ptr, len);
//return 0;
}
fprintf (stdout, "Error reading file" ) ; // works!
But trying this is not working, _write_r() is not called at all.
fprintf ((FILE *)USART1, "Error reading file 2" ) ;
So basically I plan to use a switch/case depending on destinations.
Some examples are available on ST community, but are using __io_putchar(int ch) which leaves no possibility to switch between destinations.
Any idea?
Thank you!
答案1
得分: 1
使用 fopencookie
函数打开具有自定义回调的流。您可以创建类似以下方式的 fopenusart
函数:
#define _GNU_SOURCE
#include <stdio.h>
static ssize_t usart_read(void *cookie, char *buf, size_t size) {
UART_HandleTypeDef *usart = cookie;
HAL_StatusTypeDef s = HAL_UART_Transmit(usart, buf, size);
return s == HAL_OK ? size : -1;
}
// 等等。
static const cookie_io_functions_t usart_functions = {
.read = usart_read,
// 等等。
};
FILE *fopenusart(UART_HandleTypeDef *usart, const char *mode) {
return fopencookie(usart, mode, usart_functions);
}
英文:
Use fopencookie
to open your own stream with custom callbacks. You could create your like fopenusart
built on top like the following:
#define _GNU_SOURCE
#include <stdio.h>
static ssize_t usart_read(void *cookie, char *buf, size_t size) {
UART_HandleTypeDef *usart = cookie;
HAL_StatusTypeDef s = HAL_UART_Transmit(usart, buf, size);
return s == HAL_OK ? size : -1;
}
// etc.
static const cookie_io_functions_t usart_functions = {
.read = usart_read,
// etc.
};
FILE *fopenusart(UART_HandleTypeDef *usart, const char *mode) {
return fopencookie(usart, mode, usart_functions);
}
答案2
得分: 0
抱歉回复自己的问题,但我发现现有的方法对于STM32 Cortex M0平台来说过于复杂。标准NANO库仍然占用4K,没有提到重定向实现。
我只是想要一个通用的printf()函数,能够在运行时重定向到USARTs、RAM、LCD或所有其他设备。
最简单的方法是采用一个简单(小型)的printf实现,首次谷歌搜索我找到了这个
https://github.com/heartoftechnology/embedded-printf
将原型修改为:
void embedded_printf(void *stream, const char *format, ...)
将putchar()修改为以下内容(也接受stream参数):
void embedded_putChar(void *stream, uint8_t c)
设计putchar()如下:
void embedded_putChar(void *stream, uint8_t c) {
switch ((uint32_t)(stream))
{
default:
break;
case (uint32_t)USART2:
// 对于USART2的putc()
break;
}
}
就是这样。
英文:
Sorry to reply my own question, but all that I found is a way too complicated for a STM32 Cortex M0 platform. Standard NANO library still occupies 4K, no mention redirect implementation.
I simply wanted a common printf() function able to redirect to USARTs, RAM, LCD or ALL other devices at runtime.
The easiest way to do it was to take a simple (tiny) printf implementation, at first google search I found this one
https://github.com/heartoftechnology/embedded-printf
Modify the prototype to this
void embedded_printf(void *stream, const char *format, ...)
Modify the putchar() to this (to accept stream also)
void embedded_putChar(void *stream, uint8_t c)
Design the putchar() like this
void embedded_putChar(void *stream, uint8_t c) {
switch ((uint32_t)(stream))
{
default:
break;
case (uint32_t)USART2:
// putc() for USART2
break;
}
}
And that's all.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论