eric2013 发表于 2021-11-13 14:54:23

IAR9.X printf串口底层重定向方法,否则提示Linker Error: "no definition for __write"



IAR9不能使用fputc了,实现如下:



添加如下代码:

/*******************
*
* Copyright 1998-2017 IAR Systems AB.
*
* This is a template implementation of the "__write" function used by
* the standard library.Replace it with a system-specific
* implementation.
*
* The "__write" function should output "size" number of bytes from
* "buffer" in some application-specific way.It should return the
* number of characters written, or _LLIO_ERROR on failure.
*
* If "buffer" is zero then __write should perform flushing of
* internal buffers, if any.In this case "handle" can be -1 to
* indicate that all handles should be flushed.
*
* The template implementation below assumes that the application
* provides the function "MyLowLevelPutchar".It should return the
* character written, or -1 on failure.
*
********************/

#include <LowLevelIOInterface.h>

#pragma module_name = "?__write"

int MyLowLevelPutchar(int x)
{
comSendChar(COM1, x);

return x;

}

/*
* If the __write implementation uses internal buffering, uncomment
* the following line to ensure that we are called with "buffer" as 0
* (i.e. flush) when the application terminates.
*/

size_t __write(int handle, const unsigned char * buffer, size_t size)
{
/* Remove the #if #endif pair to enable the implementation */
#if 1

size_t nChars = 0;

if (buffer == 0)
{
    /*
   * This means that we should flush internal buffers.Since we
   * don't we just return.(Remember, "handle" == -1 means that all
   * handles should be flushed.)
   */
    return 0;
}

/* This template only writes to "standard out" and "standard err",
   * for all other file handles it returns failure. */
if (handle != _LLIO_STDOUT && handle != _LLIO_STDERR)
{
    return _LLIO_ERROR;
}

for (/* Empty */; size != 0; --size)
{
    if (MyLowLevelPutchar(*buffer++) < 0)
    {
      return _LLIO_ERROR;
    }

    ++nChars;
}

return nChars;

#else

/* Always return error code when implementation is disabled. */
return _LLIO_ERROR;

#endif

}



xiaominghan 发表于 2021-11-14 11:36:33

666,感谢楼主分享

重庆破锅 发表于 2021-11-14 12:28:24

之前我把msp430,stm8,arm安装在一起了,花了一天时间,安装在一起可以不用切换iar就可以打开任意工程,安装最新的,可能msp430、stm8环境会失效。

eric2013 发表于 2021-11-15 01:32:48

重庆破锅 发表于 2021-11-14 12:28
之前我把msp430,stm8,arm安装在一起了,花了一天时间,安装在一起可以不用切换iar就可以打开任意工程,安 ...

IAR有必要搞个多合一就方便了。

neomissing 发表于 2021-11-15 09:35:41

重庆破锅 发表于 2021-11-14 12:28
之前我把msp430,stm8,arm安装在一起了,花了一天时间,安装在一起可以不用切换iar就可以打开任意工程,安 ...

同一个版本的是可以,不同版本的需要安装不同路径即可,因为共用的iar基础不一样,不能兼容

lyhawk2007 发表于 2022-4-19 08:15:37

Error: no definition for "__dwrite"        
我按照你给的代码 添加到IAR里面,然后编译提示如上错误,               

eric2013 发表于 2022-4-19 09:03:44

lyhawk2007 发表于 2022-4-19 08:15
Error: no definition for "__dwrite"        
我按照 ...

你现在的具体版本多少,我这个是在9.20.1上测试的。

lyhawk2007 发表于 2022-4-19 09:07:36

问题解决了

dsfeng 发表于 2022-6-6 13:51:55

你好,请问这个代码是放在哪里都行吗

dsfeng 发表于 2022-6-6 14:01:11

你好,请问,这个代码放在哪里都行吗

eric2013 发表于 2022-6-6 15:20:20

dsfeng 发表于 2022-6-6 14:01
你好,请问,这个代码放在哪里都行吗

对,这个是个弱定义,这里是做了个重定向。

freeman0323 发表于 2022-6-18 10:25:18

你好 想问一下为啥我会提示未COM1 为定义?

eric2013 发表于 2022-6-19 10:18:12

freeman0323 发表于 2022-6-18 10:25
你好 想问一下为啥我会提示未COM1 为定义?

这个是我们自己的bsp_uart_fifo.c驱动定义的,你可以换成自己的函数。

hpdell 发表于 2022-7-17 19:11:01

eric2013 发表于 2022-6-19 10:18
这个是我们自己的bsp_uart_fifo.c驱动定义的,你可以换成自己的函数。

感觉这个 iar-arm v9.3xx 版本的是比之前的版本强悍了不少,不过目前还是有点不足之处,就是使用

#if   1

#else

#endif

这里定义时,不被编译的部分代码不会变色显示,要是能够吧这个解决了就比较完美了喔 :lol

不知道是哪里可以设置吗??

lushuhao2012 发表于 2022-7-25 17:50:29

说白了就是把原来小写的printf改成大写就好了,小写是打印到iar自带的终端,大写打印到串口:)

风来吴山 发表于 2022-7-26 08:59:52

https://github.com/mpaland/printf
printf库

ihavedone 发表于 2022-7-27 12:10:47

按照楼主方法实现了重定向,但有个问题: __write 函数的参数 size 永远都是 1。

我写了个串口驱动,可以一次发送多个字节,也做了互斥支持多线程。
如果__write 函数的参数 size 永远都是 1 的话,那做的互斥就没用了,因为每发送完一个字节就会释放互斥量。
并且每次发送一个字节效率也很低。


这个问题大佬有解决方法吗?

eric2013 发表于 2022-7-29 09:28:29

ihavedone 发表于 2022-7-27 12:10
按照楼主方法实现了重定向,但有个问题: __write 函数的参数 size 永远都是 1。

我写了个串口驱动, ...
这就跟fputc差不多了。

做互斥在这里做效率太低,重新封装个printf做互斥好很多,比如这样:

/*
*********************************************************************************************************
*      函 数 名: App_Printf
*      功能说明: 线程安全的printf方式                                          
*      形    参: 同printf的参数。
*             在C中,当无法列出传递函数的所有实参的类型和数目时,可以用省略号指定参数表
*      返 回 值: 无
*********************************************************************************************************
*/
staticvoidApp_Printf(const char *fmt, ...)
{
    charbuf_str; /* 特别注意,如果printf的变量较多,注意此局部变量的大小是否够用 */
    va_list   v_args;


    va_start(v_args, fmt);
   (void)vsnprintf((char       *)&buf_str,
                   (size_t      ) sizeof(buf_str),
                   (char const *) fmt,
                                  v_args);
    va_end(v_args);

      /* 互斥操作 */
    tx_mutex_get(&AppPrintfSemp, TX_WAIT_FOREVER);

    printf("%s", buf_str);

    tx_mutex_put(&AppPrintfSemp);                                       
}

ihavedone 发表于 2022-7-29 16:39:28

eric2013 发表于 2022-7-29 09:28
这就跟fputc差不多了。

做互斥在这里做效率太低,重新封装个printf做互斥好很多,比如这样:


这个改发用于自己的代码还好,但如果是移植了第三方软件包,其中用到 printf 函数的话,就会麻烦点。
所以最好还是能直接用 printf ,但我找了几天,MDK 下实现的 _sys_write 函数就可以实现一次输出多个字节。
IAR 下怎么搞都不行,每次一个,放弃了。
:lol

接下来还要重定向文件操作,别也是一个一个字节来的,那就搞不成器了。。

eric2013 发表于 2022-7-29 16:48:41

ihavedone 发表于 2022-7-29 16:39
这个改发用于自己的代码还好,但如果是移植了第三方软件包,其中用到 printf 函数的话,就会麻烦点。
所 ...
这个担心是多余的。

第三方库基本都不会直接调用printf的,都会做个重定向的#define LOGXXXprintf,凡是第3方库直接倒腾printf的都是骚操作。必须让他们"整改"。

ihavedone 发表于 2022-8-4 21:30:28

eric2013 发表于 2022-7-29 16:48
这个担心是多余的。

第三方库基本都不会直接调用printf的,都会做个重定向的#define LOGXXXprintf, ...

我发现了问题所在,一定要加这句
#pragma module_name = "?__write"

不加的话,printf 进这个 __write 函数时,size 参数总是 1,每次只能打印一个字节。

eric2013 发表于 2022-8-5 09:46:15

ihavedone 发表于 2022-8-4 21:30
我发现了问题所在,一定要加这句
#pragma module_name = "?__write"


你前面是不是把这个看成乱码给删了。。



ihavedone 发表于 2022-9-3 16:22:33

本帖最后由 ihavedone 于 2022-9-3 16:31 编辑

eric2013 发表于 2022-8-5 09:46
你前面是不是把这个看成乱码给删了。。
今天使用发现了这个重定向的另一个问题,printf 长度最大只能输出 80 个字节。后面的自动就没了。。
之前一直没输出过这么长,大佬那边能超过这个限制吗?
使用 printf 时进入 重定向的 write 函数,size 参数最大只有 80(0x50)
但是使用 文件操作 fwrite 时,进入重定向的 write 函数,size 参数就可以超过 80.。。 很奇怪

并且用 printf 打印常量字符串,最终到重定向的 write 函数中时,字符串参数的地址 在 0x20000000 开始的内存区(H743芯片)。
但是常量字符串应该是保存在代码区 0x08000000 开始的位置才对。
感觉是 printf 函数内部进行了内容复制。

eric2013 发表于 2022-9-3 17:12:41

ihavedone 发表于 2022-9-3 16:22
今天使用发现了这个重定向的另一个问题,printf 长度最大只能输出 80 个字节。后面的自动就没了。。
之 ...
输出100多个字符,没问题。



eric2013 发表于 2022-9-3 17:30:08

ihavedone 发表于 2022-9-3 16:22
今天使用发现了这个重定向的另一个问题,printf 长度最大只能输出 80 个字节。后面的自动就没了。。
之 ...
然后我们LUA小程序读取对应地址内容,没问题,也是在内部Flash里面。



ihavedone 发表于 2022-9-4 01:08:24

eric2013 发表于 2022-9-3 17:30
然后我们LUA小程序读取对应地址内容,没问题,也是在内部Flash里面。

第一个你这边能输出超过 80 个字符,我这里还要看看原因是什么。
第二个你查看 0x80004434 的地址,是表示这个字符串的原始位置是这里。但是经过 printf 调用后,最终传递到重定向的那个 write 函数的地址是否仍然是这个地址,或者是 printf 内部把这个字符串复制到了另外的地址,比如 0x20000000 那段,然后把复制后的字符串传递给了 write。这个从第二个实验看不出来。

eric2013 发表于 2022-9-4 01:49:03

ihavedone 发表于 2022-9-4 01:08
第一个你这边能输出超过 80 个字符,我这里还要看看原因是什么。
第二个你查看 0x80004434 的地址,是表 ...

1、这个不知道怎么回事了。
2、有可能,有时间我再看下。

ihavedone 发表于 2022-9-5 15:31:09

eric2013 发表于 2022-9-4 01:49
1、这个不知道怎么回事了。
2、有可能,有时间我再看下。

问题解决,原因如下:

eric2013 发表于 2022-9-5 15:44:39

ihavedone 发表于 2022-9-5 15:31
问题解决,原因如下:
应该是你的IAR设置问题,我这里没有进入过buffer = 0



快乐寄存器 发表于 2023-3-2 10:51:15

妙啊,学到了

0error 发表于 2023-3-28 21:45:16

你好,我的提示Fatal Error: cannot open source file "LowLevelIOInterface.h"是为什么呢

eric2013 发表于 2023-3-29 00:38:48

0error 发表于 2023-3-28 21:45
你好,我的提示Fatal Error: cannot open source file "LowLevelIOInterface.h"是为什么呢

这个是iar的系统文件,你下载我这个例子,使用iar9.x编译是否正常

https://www.armbbs.cn/forum.php?mod=viewthread&tid=118149

xmetoo 发表于 2023-4-21 16:28:36

感谢分享,但是还有个什么半主机模式的?

eric2013 发表于 2023-4-22 12:23:25

xmetoo 发表于 2023-4-21 16:28
感谢分享,但是还有个什么半主机模式的?

对,输出非常慢,非常卡

IAR自带的Terminal I/O不错,可以通过半主模式输出打印数据
https://www.armbbs.cn/forum.php?mod=viewthread&tid=89459&fromuid=58
(出处: 硬汉嵌入式论坛)

yunqi 发表于 2023-4-23 15:08:36

ihavedone 发表于 2022-9-3 16:22
今天使用发现了这个重定向的另一个问题,printf 长度最大只能输出 80 个字节。后面的自动就没了。。
之 ...

你打printf(“\n”)
试试,这个是Flush操作。

与长歌 发表于 2023-8-2 10:38:57

lyhawk2007 发表于 2022-4-19 08:15
Error: no definition for "__dwrite"        
我按照 ...

大佬,这个问题最后你是怎么解决的呀

Aaron_EE 发表于 2023-9-7 17:34:37

请教一个问题,我把串口驱动移植到STM32L051上,如果使用你这个方法使用printf函数,还是没有输出,串口正常的,使用comSendbuf输出正常的

eric2013 发表于 2023-9-7 17:37:56

Aaron_EE 发表于 2023-9-7 17:34
请教一个问题,我把串口驱动移植到STM32L051上,如果使用你这个方法使用printf函数,还是没有输出,串口正 ...

正常进入到MyLowLevelPutchar函数里面没

Aaron_EE 发表于 2023-9-8 13:59:11

eric2013 发表于 2023-9-7 17:37
正常进入到MyLowLevelPutchar函数里面没

谢谢eric大佬,问题解决了,现在遇到一个可笑的问题,使用STM32L051内部HSI,我开一个串口波特率还是很准的,开2个串口,波特率完全对不上了

eric2013 发表于 2023-9-8 14:05:50

Aaron_EE 发表于 2023-9-8 13:59
谢谢eric大佬,问题解决了,现在遇到一个可笑的问题,使用STM32L051内部HSI,我开一个串口波特率还是很准 ...

单独仅开另一个串口是否正常。
页: [1] 2
查看完整版本: IAR9.X printf串口底层重定向方法,否则提示Linker Error: "no definition for __write"