Keil MDK : 标准IO函数重定向相关

本文详细介绍了如何使用MDK-ARM配置目标依赖库,以避免链接器选择使用semihosting的库函数。通过复制并编辑RETARGET.C模板文件,可以适配字符I/O函数如printf()和scanf(),确保在新的执行环境中正确实现输入输出功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Library Retarget File

Semihosting is not supported by MDK-ARM. Use the retargeting functionality of MDK-ARM instead. To prevent the linker from selecting libraries functions that use semihosting, MDK-ARM includes retarget files that redefine low-level I/O routines.

RETARGET.C template file, located in the folder ..\ARM\Startup, implements the functionality required to adapt character I/O functions such as printf() and scanf().

  1. Copy the RETARGET.C template to the project folder.
  2. Include the copied file to the project (described in Create Source File).
  3. Edit the file and make your changes. You may use the following code as a template and adapt it to your needs.
    /*----------------------------------------------------------------------------
     * Name:    Retarget.c
     * Purpose: 'Retarget' layer for target-dependent low level functions
     * Note(s):
     *----------------------------------------------------------------------------
     * This file is part of the µVision/ARM development tools.
     * This software may only be used under the terms of a valid, current,
     * end user licence from KEIL for a compatible version of KEIL software
     * development tools. Nothing else gives you the right to use this software.
     *
     * This software is supplied "AS IS" without warranties of any kind.
     *
     * Copyright (c) 2009 Keil - An ARM Company. All rights reserved.
     *----------------------------------------------------------------------------*/
    
    #include <stdio.h>
    #include <rt_misc.h>
    
    #pragma import(__use_no_semihosting_swi)
    
    
    extern int sendchar (int c);
    extern int getkey   (void);
    
    
    struct __FILE { int handle; /* Add whatever you need here */ };
    FILE __stdout;
    FILE __stdin;
    
    
    int fputc(int c, FILE *f) {
      return (sendchar(c));
    }
    
    
    int fgetc(FILE *f) {
      return (getkey());
    }
    
    
    int ferror(FILE *f) {
      /* Your implementation of ferror */
      return EOF;
    }
    
    
    void _ttywrch(int c) {
      sendchar(c);
    }
    
    
    void _sys_exit(int return_code) {
    label:  goto label;  /* endless loop */
    }
    

 Note

Tailoring the C library to a new execution environment

1.41 Tailoring the C library to a new execution environment

Tailoring the C library to a new execution environment involves re-implementing functions to produce an application for a new execution environment, for example, embedded in ROM or used with an RTOS.

Functions whose names start with a single or double underscore are used as part of the low-level implementation. You can re-implement some of these functions. Additional information on these library functions is available in the  rt_heap.hrt_locale.hrt_misc.h, and  rt_sys.h include files and the rt_memory.s assembler file.

Redefining target-dependent system I/O functions in the C library

1.78 Redefining target-dependent system I/O functions in the C library

The default target-dependent I/O functions use semihosting. If any of these functions are redefined, then they must all be redefined.

The following example shows you how to redefine the required functions this, for a device that supports writing but not reading.

Retargeting the system I/O functions

FILEHANDLE _sys_open(const char *name, int openmode)
{
  return 1; /* everything goes to the same output */
}
int _sys_close(FILEHANDLE fh)
{
  return 0;
}
int _sys_write(FILEHANDLE fh, const unsigned char *buf,
               unsigned len, int mode)
{
  your_device_write(buf, len);
  return 0;
}
int _sys_read(FILEHANDLE fh, unsigned char *buf,
              unsigned len, int mode)
{
  return -1; /* not supported */
}
void _ttywrch(int ch)
{
  char c = ch;
  your_device_write(&c, 1);
}
int _sys_istty(FILEHANDLE fh)
{
  return 0; /* buffered output */
}
int _sys_seek(FILEHANDLE fh, long pos)
{
  return -1; /* not supported */
}
long _sys_flen(FILEHANDLE fh)
{
  return -1; /* not supported */
}
rt_sys.h defines the type  FILEHANDLE. The value of  FILEHANDLE is returned by  _sys_open() and identifies an open file on the host system.
If the system I/O functions are redefined, both normal character I/O and wide character I/O work. That is, you are not required to do anything extra with these functions for wide character I/O to work.

Redefining low-level library functions to enable direct use of high-level library functions in the C library

1.74 Redefining low-level library functions to enable direct use of high-level library functions in the C library

If you define your own version of __FILE, your own fputc() and ferror() functions, and the __stdout object, you can use all of the printf() family, fwrite()fputs()puts() and the C++ object std::cout unchanged from the library.

These examples show you how to do this. However, consider modifying the system I/O functions instead of these low-level library functions if you require real file handling.
You are not required to re-implement every function shown in these examples. Only re-implement the functions that are used in your application.

Retargeting printf()

#include <stdio.h>
struct __FILE
{
  int handle;
  /* Whatever you require here. If the only file you are using is */
  /* standard output using printf() for debugging, no file handling */
  /* is required. */
};
/* FILE is typedef’d in stdio.h. */
FILE __stdout;
int fputc(int ch, FILE *f) 
{
  /* Your implementation of fputc(). */
  return ch;
}
int ferror(FILE *f)
{
  /* Your implementation of ferror(). */
  return 0;
}
void test(void)
{
  printf("Hello world\n");
}

Note

Be aware of endianness with  fputc()fputc() takes an  int parameter, but contains only a character. Whether the character is in the first or the last byte of the integer variable depends on the endianness. The following code sample avoids problems with endianness:
extern void sendchar(char *ch);
int fputc(int ch, FILE *f)
{
  /* example: write a character to an LCD */
  char tempch = ch; // temp char avoids endianness issue
  sendchar(&tempch);
  return ch;
}

Retargeting cout

File 1: Re-implement any functions that require re-implementation.
#include <stdio.h>
namespace std {
  struct __FILE
  {
    int handle;
    /* Whatever you require here. If the only file you are using is */
    /* standard output using printf() for debugging, no file handling */
    /* is required. */
  };
  FILE __stdout;
  FILE __stdin;
  FILE __stderr;
  int fgetc(FILE *f)
  {
    /* Your implementation of fgetc(). */
    return 0;
  };
  int fputc(int c, FILE *stream)
  {
    /* Your implementation of fputc(). */
  }
  int ferror(FILE *stream)
  {
    /* Your implementation of ferror(). */
  }
  long int ftell(FILE *stream)
  {
    /* Your implementation of ftell(). */
  }
  int fclose(FILE *f)
  {
    /* Your implementation of fclose(). */
    return 0;
  }
  int fseek(FILE *f, long nPos, int nMode)
  {
    /* Your implementation of fseek(). */
    return 0;
  }
  int fflush(FILE *f)
  {
    /* Your implementation of fflush(). */    
    return 0;
  }
}
File 2: Print "Hello world" using your re-implemented functions.
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
  cout << "Hello world\n";
  return 0;
}
By default,  fread() and  fwrite() call fast block input/output functions that are part of the ARM stream implementation. If you define your own  __FILE structure instead of using the ARM stream implementation, fread() and  fwrite() call  fgetc() instead of calling the block input/output functions.

What is semihosting?

Semihosting is a mechanism that enables code running on an ARM target to communicate and use the Input/Output facilities on a host computer that is running a debugger.

Examples of these facilities include keyboard input, screen output, and disk I/O. For example, you can use this mechanism to enable functions in the C library, such as printf() and scanf(), to use the screen and keyboard of the host instead of having a screen and keyboard on the target system.

This is useful because development hardware often does not have all the input and output facilities of the final system. Semihosting enables the host computer to provide these facilities.

Semihosting is implemented by a set of defined software instructions, for example, SVCs, that generate exceptions from program control. The application invokes the appropriate semihosting call and the debug agent then handles the exception. The debug agent provides the required communication with the host.

The semihosting interface is common across all debug agents provided by ARM. Semihosted operations work when you are debugging applications on your development platform, as shown in the following figure:

Figure 6. Semihosting overview


In many cases, semihosting is invoked by code within library functions. The application can also invoke the semihosting operation directly.

Note

ARM processors prior to ARMv7 use the SVC instructions, formerly known as SWI instructions, to make semihosting calls. However, if you are compiling for an ARMv6-M or ARMv7-M, for example a Cortex-M1 or Cortex-M3 processor, semihosting is implemented using the BKPT instruction.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值