硬汉嵌入式论坛

 找回密码
 立即注册
查看: 7097|回复: 45
收起左侧

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

  [复制链接]

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
发表于 2021-11-13 14:54:23 | 显示全部楼层 |阅读模式


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

1.png

添加如下代码:

  1. /*******************
  2. *
  3. * Copyright 1998-2017 IAR Systems AB.
  4. *
  5. * This is a template implementation of the "__write" function used by
  6. * the standard library.  Replace it with a system-specific
  7. * implementation.
  8. *
  9. * The "__write" function should output "size" number of bytes from
  10. * "buffer" in some application-specific way.  It should return the
  11. * number of characters written, or _LLIO_ERROR on failure.
  12. *
  13. * If "buffer" is zero then __write should perform flushing of
  14. * internal buffers, if any.  In this case "handle" can be -1 to
  15. * indicate that all handles should be flushed.
  16. *
  17. * The template implementation below assumes that the application
  18. * provides the function "MyLowLevelPutchar".  It should return the
  19. * character written, or -1 on failure.
  20. *
  21. ********************/

  22. #include <LowLevelIOInterface.h>

  23. #pragma module_name = "?__write"

  24. int MyLowLevelPutchar(int x)
  25. {
  26.   comSendChar(COM1, x);
  27.   
  28.   return x;

  29. }

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

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

  39.   size_t nChars = 0;

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

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

  55.   for (/* Empty */; size != 0; --size)
  56.   {
  57.     if (MyLowLevelPutchar(*buffer++) < 0)
  58.     {
  59.       return _LLIO_ERROR;
  60.     }

  61.     ++nChars;
  62.   }

  63.   return nChars;

  64. #else

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

  67. #endif

  68. }
复制代码




回复

使用道具 举报

0

主题

4

回帖

4

积分

新手上路

积分
4
发表于 2021-11-14 11:36:33 | 显示全部楼层
666,感谢楼主分享
回复

使用道具 举报

0

主题

7

回帖

7

积分

新手上路

积分
7
发表于 2021-11-14 12:28:24 | 显示全部楼层
之前我把msp430,stm8,arm安装在一起了,花了一天时间,安装在一起可以不用切换iar就可以打开任意工程,安装最新的,可能msp430、stm8环境会失效。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2021-11-15 01:32:48 | 显示全部楼层
重庆破锅 发表于 2021-11-14 12:28
之前我把msp430,stm8,arm安装在一起了,花了一天时间,安装在一起可以不用切换iar就可以打开任意工程,安 ...

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

使用道具 举报

1

主题

73

回帖

76

积分

初级会员

积分
76
发表于 2021-11-15 09:35:41 | 显示全部楼层
重庆破锅 发表于 2021-11-14 12:28
之前我把msp430,stm8,arm安装在一起了,花了一天时间,安装在一起可以不用切换iar就可以打开任意工程,安 ...

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

使用道具 举报

3

主题

22

回帖

31

积分

新手上路

积分
31
发表于 2022-4-19 08:15:37 | 显示全部楼层
Error[Li005]: no definition for "__dwrite" [referenced from xxwritebuffered.o(dl7M_tlf.a)]       
我按照你给的代码 添加到IAR里面,然后编译提示如上错误,               
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2022-4-19 09:03:44 | 显示全部楼层
lyhawk2007 发表于 2022-4-19 08:15
Error[Li005]: no definition for "__dwrite" [referenced from xxwritebuffered.o(dl7M_tlf.a)]       
我按照 ...

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

使用道具 举报

3

主题

22

回帖

31

积分

新手上路

积分
31
发表于 2022-4-19 09:07:36 | 显示全部楼层
问题解决了
回复

使用道具 举报

0

主题

8

回帖

8

积分

新手上路

积分
8
发表于 2022-6-6 13:51:55 | 显示全部楼层
你好,请问这个代码是放在哪里都行吗
回复

使用道具 举报

0

主题

8

回帖

8

积分

新手上路

积分
8
发表于 2022-6-6 14:01:11 | 显示全部楼层
你好,请问,这个代码放在哪里都行吗
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2022-6-6 15:20:20 | 显示全部楼层
dsfeng 发表于 2022-6-6 14:01
你好,请问,这个代码放在哪里都行吗

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

使用道具 举报

0

主题

1

回帖

1

积分

新手上路

积分
1
发表于 2022-6-18 10:25:18 | 显示全部楼层
你好 想问一下为啥我会提示未COM1 为定义?
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2022-6-19 10:18:12 | 显示全部楼层
freeman0323 发表于 2022-6-18 10:25
你好 想问一下为啥我会提示未COM1 为定义?

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

使用道具 举报

609

主题

3047

回帖

4894

积分

至尊会员

积分
4894
发表于 2022-7-17 19:11:01 | 显示全部楼层
eric2013 发表于 2022-6-19 10:18
这个是我们自己的bsp_uart_fifo.c驱动定义的,你可以换成自己的函数。

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

#if   1

#else

#endif

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

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

使用道具 举报

0

主题

1

回帖

1

积分

新手上路

积分
1
发表于 2022-7-25 17:50:29 | 显示全部楼层
说白了就是把原来小写的printf改成大写就好了,小写是打印到iar自带的终端,大写打印到串口
回复

使用道具 举报

3

主题

110

回帖

119

积分

初级会员

积分
119
发表于 2022-7-26 08:59:52 | 显示全部楼层
回复

使用道具 举报

58

主题

267

回帖

446

积分

高级会员

积分
446
发表于 2022-7-27 12:10:47 | 显示全部楼层
按照楼主方法实现了重定向,但有个问题: __write 函数的参数 size 永远都是 1。  

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


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

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2022-7-29 09:28:29 | 显示全部楼层
ihavedone 发表于 2022-7-27 12:10
按照楼主方法实现了重定向,但有个问题: __write 函数的参数 size 永远都是 1。  

我写了个串口驱动, ...

这就跟fputc差不多了。

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

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


    va_start(v_args, fmt);
   (void)vsnprintf((char       *)&buf_str[0],
                   (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);                                         
}
回复

使用道具 举报

58

主题

267

回帖

446

积分

高级会员

积分
446
发表于 2022-7-29 16:39:28 | 显示全部楼层
eric2013 发表于 2022-7-29 09:28
这就跟fputc差不多了。

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

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


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

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2022-7-29 16:48:41 | 显示全部楼层
ihavedone 发表于 2022-7-29 16:39
这个改发用于自己的代码还好,但如果是移植了第三方软件包,其中用到 printf 函数的话,就会麻烦点。
所 ...

这个担心是多余的。

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

使用道具 举报

58

主题

267

回帖

446

积分

高级会员

积分
446
发表于 2022-8-4 21:30:28 | 显示全部楼层
eric2013 发表于 2022-7-29 16:48
这个担心是多余的。

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

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

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

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2022-8-5 09:46:15 | 显示全部楼层
ihavedone 发表于 2022-8-4 21:30
我发现了问题所在,一定要加这句
#pragma module_name = "?__write"

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


回复

使用道具 举报

58

主题

267

回帖

446

积分

高级会员

积分
446
发表于 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 函数内部进行了内容复制。

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2022-9-3 17:12:41 | 显示全部楼层
ihavedone 发表于 2022-9-3 16:22
今天使用发现了这个重定向的另一个问题,printf 长度最大只能输出 80 个字节。后面的自动就没了。。
之 ...

输出100多个字符,没问题。
image.png


回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2022-9-3 17:30:08 | 显示全部楼层
ihavedone 发表于 2022-9-3 16:22
今天使用发现了这个重定向的另一个问题,printf 长度最大只能输出 80 个字节。后面的自动就没了。。
之 ...

然后我们LUA小程序读取对应地址内容,没问题,也是在内部Flash里面。


image.png
回复

使用道具 举报

58

主题

267

回帖

446

积分

高级会员

积分
446
发表于 2022-9-4 01:08:24 | 显示全部楼层
eric2013 发表于 2022-9-3 17:30
然后我们LUA小程序读取对应地址内容,没问题,也是在内部Flash里面。

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

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2022-9-4 01:49:03 | 显示全部楼层
ihavedone 发表于 2022-9-4 01:08
第一个你这边能输出超过 80 个字符,我这里还要看看原因是什么。
第二个你查看 0x80004434 的地址,是表 ...

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

使用道具 举报

58

主题

267

回帖

446

积分

高级会员

积分
446
发表于 2022-9-5 15:31:09 | 显示全部楼层
eric2013 发表于 2022-9-4 01:49
1、这个不知道怎么回事了。
2、有可能,有时间我再看下。

问题解决,原因如下:
C967F620-9607-46a1-92B3-7F24E278BA86.png
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2022-9-5 15:44:39 | 显示全部楼层
ihavedone 发表于 2022-9-5 15:31
问题解决,原因如下:

应该是你的IAR设置问题,我这里没有进入过buffer = 0
image.png


回复

使用道具 举报

0

主题

5

回帖

5

积分

新手上路

积分
5
发表于 2023-3-2 10:51:15 | 显示全部楼层
妙啊,学到了
回复

使用道具 举报

0

主题

1

回帖

1

积分

新手上路

积分
1
发表于 2023-3-28 21:45:16 | 显示全部楼层
你好,我的提示Fatal Error[Pe1696]: cannot open source file "LowLevelIOInterface.h"是为什么呢
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 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
回复

使用道具 举报

1

主题

9

回帖

12

积分

新手上路

积分
12
发表于 2023-4-21 16:28:36 | 显示全部楼层
感谢分享,但是还有个什么半主机模式的?
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2023-4-22 12:23:25 | 显示全部楼层
xmetoo 发表于 2023-4-21 16:28
感谢分享,但是还有个什么半主机模式的?

对,输出非常慢,非常卡

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

使用道具 举报

8

主题

157

回帖

181

积分

初级会员

积分
181
发表于 2023-4-23 15:08:36 | 显示全部楼层
ihavedone 发表于 2022-9-3 16:22
今天使用发现了这个重定向的另一个问题,printf 长度最大只能输出 80 个字节。后面的自动就没了。。
之 ...

你打
[C] 纯文本查看 复制代码
printf(“\n”)

试试,这个是Flush操作。
回复

使用道具 举报

0

主题

1

回帖

1

积分

新手上路

积分
1
发表于 2023-8-2 10:38:57 | 显示全部楼层
lyhawk2007 发表于 2022-4-19 08:15
Error[Li005]: no definition for "__dwrite" [referenced from xxwritebuffered.o(dl7M_tlf.a)]       
我按照 ...

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

使用道具 举报

0

主题

7

回帖

7

积分

新手上路

积分
7
发表于 2023-9-7 17:34:37 | 显示全部楼层
请教一个问题,我把串口驱动移植到STM32L051上,如果使用你这个方法使用printf函数,还是没有输出,串口正常的,使用comSendbuf输出正常的
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2023-9-7 17:37:56 | 显示全部楼层
Aaron_EE 发表于 2023-9-7 17:34
请教一个问题,我把串口驱动移植到STM32L051上,如果使用你这个方法使用printf函数,还是没有输出,串口正 ...

正常进入到MyLowLevelPutchar函数里面没
回复

使用道具 举报

0

主题

7

回帖

7

积分

新手上路

积分
7
发表于 2023-9-8 13:59:11 | 显示全部楼层
eric2013 发表于 2023-9-7 17:37
正常进入到MyLowLevelPutchar函数里面没

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

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2023-9-8 14:05:50 | 显示全部楼层
Aaron_EE 发表于 2023-9-8 13:59
谢谢eric大佬,问题解决了,现在遇到一个可笑的问题,使用STM32L051内部HSI,我开一个串口波特率还是很准 ...

单独仅开另一个串口是否正常。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-4-28 14:47 , Processed in 0.387617 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表