Embedded system development environment construction

The embedded system development environment mainly includes:

  • Integrated development tools
  • Cross compiler
  • Batch file
  • makefile
  • Link Script
  • Debugging tools
  • download tool
  • Other tools (Offline Tools)
  • Emulator
  • Version control tool

Next, explain the above tools separately:

1. Integrated development tools

Generally CPU manufacturers will provide an integrated development environment (IDE) for the CPU, but in practical applications, most embedded project development companies will still use their own development environment. One is the special requirements of some functions of the project, and the other is that not all CPU models have corresponding IDE.

2、 Cross-Tools

Cross-Tools includes:

  • Cross-Assembler
  • Cross-Compiler
  • Cross-Library
  • Cross-Linker
  • dump tool (information about converting executable files into assembly language code)
  • Debugging tool (GNU gdb)

Taking the C compiler gcc in GNU Tool-Chain as an example, the following are some compiling options:

  • -Werror: Turn all warning messages into error messages. Once a warning message is generated, no target file is generated.
  • -S: Output assembly language code when compiling.
  • -C: Only object files are generated during compilation
  • -E: Only perform preprocessing without generating object files
  • -D: Define macro constants at compile time
  • -O, -O2, -O3: Optimization level.
  • -g: add debugging information when compiling, so that it can be debugged with GDB

Take the C linker Linker in GNU Tool-Chain as an example. Here are some options:

  • -T: Develop link script file
  • -Map: Generate a map file when connecting, which contains the address information of all symbols in the program.

GNU tool chain can support many different CPUs, and users can set the configuration according to their needs. For example, arm-elf-gcc is a C compiler that generates ARM machine code in elf format, and 68K-coff-ld is a linker that generates 68000 machine code in COFF format.

3、Make

make is a program tool for automatic compilation. As long as the makefile is used to describe in detail what tool (such as cross-compiler) to use for which file ( .c, .obj, ...) what to do (to produce unoptimized object files) ), make will also check whether these files are out of date. If they are out of date, they will only recompile the files that need to be compiled (make will compare the dependencies and dates between files to determine whether a file needs to be recompiled). The usual batch Processing program (for example, .bat program under windows), after some files are updated, all files need to be recompiled.

"Programming with GNU Software/GNU Programming"

"Managing Project with make/make project development tool"

The above two books have detailed instructions on the use of make.

(1) Important concepts in makefile

  • Target: The name of the file you want to generate.
  • Dependency: Define whether there is a dependency between two files.
  • Prerequisite (required files): Some files that can create a target. A target is usually created by multiple files.
  • UP to Date (new version): Assuming that a file is newer than the file it depends on, it means that the file has a new version.

The basic syntax of makefile:

#文件名:sample.mak
Target:Dependency list
    command1
    command2

The command to execute the above makefile is:, make -f sample.makif no makefile is specified with -f, make will look for a file named "makefile" in the current directory. In addition, if target is not specified, make will use the first target file name in the makefile as the target name.

(2) Examples of makefile

  • The following example is an example of macro definition in makefile:
#File Name  :   DEFINE.MAK
#
#定义其它makefile中会用到的宏,思想和C语言的#define一样
#
!IFNDEF _DEFINE_MAK
_DEFINE_MAK = DEFINED
#
#定义项目相关文件所在的磁盘机编号
#
PRJ_DRIVER  =   Y:
#
#定义项目工具所在目录
#
PRJ_TOOLS_ROOT  =   $(PRJ_DRIVER)\Tools
#
#定义编译器所在目录
#
GNU_CC  =   $(GNU33_ROOT)\kcc33
GNU_LK  =   $(GNU33_ROOT)\ld
GNU_AR  =   $(GNU33_ROOT)\ar
#
#定义项目程序所在目录
#
SRC_ROOT    =   $(PRJ_DRIVER)\Project2020
SRC_INC     =   $(SRC_ROOT)\include
#
#当编译时传入-DXXX参数,其效果如同在程序中写了#define XXX
#
PRJ_CONFIG  =   -DPRJ_2020 -DCPU_ARM9 -DLCD_160X160
#
#定义执行C compiler时的参数
#
?CFLAGS= -c -gstabs -mlong-calls -fno-builtin -mgda=0 -mdp=1 -O3 
        -I$(GNU_INCLUDE)
        -I$(SRC_INC)
        -I$(PRJ_CONFIG)
#
#定义执行linker时的参数
#
LDFLAGS= -T main.lds -Map $(TARGET).map -N
#...
#...
!ENDIF
  • The following example is a more complex example:
#
#在makefile中,也可以和include一样,包含其它makefile
#
!IF "$(_DEFINE_MAK)" == ""
!INCLUDE DEFINE.MAK
!ENDIF
#
#定义各模块包含的object file,每个object都是一个target
#
MODEL1_OBJS = m1_001.obj m1_002.obj m1_003.obj
MODEL2_OBJS = m2_001.obj m2_002.obj
#
# 项目中所有需要的object file
#
OBJS    = $(MODEL1_OBJS) $(MODEL2_OBJS)
#
#定义会用到的库函数
#
LIBS = $(GNU_LIB)\libgcc.a
#
#第一个target产生最终可执行文件main.elf,
#和main.elf有依赖关系的target有:所有的object file,main.mak,Link Script
#"$@"表示target本身,即main.elf
#
main.elf : $(OBJS) main.mak main.lds
    $(GNU_LK) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
#
# $* 表示target名称去掉扩展名
# $@ 表示target本身
# $< 表示XXX.c
#
m1_001.obj : $(SRC_ROOT)\m1\m1_001.c $(SRC_INC)\m1.h
    $(GNU_CC) $@ $(CFLAGS) $*.c

m1_002.obj : $(SRC_ROOT)\m1\m2_001.c $(SRC_INC)\m1.h
    $(GNU_CC) $@ $(CFLAGS) $*.c

...
  • When you need to process several files with the same extension repeatedly, you can usually use make's preset compilation rules. For example, when you need to compile all targets with the extension .obj under the same rules, you can use the following statement:
?.c.obj:;$(GNU_CC) $@ $(CFLAGS) $<

Syntax description of preset compilation rules:

  • .c.obj:; This line of directory is used to standardize the target as the .obj file, and rely on the preset compilation rules for the .c file

  • Macros can still be used when setting precompilation rules

(3) Target of non-file name

clean:
    del $(OBJS)
    del main.elf
    del main.bin

There is only target in the above makefile statement and no dependency, which means that the target will definitely execute the del command below. Generally used to execute before recompiling all files.

This non-file name target can also be used as a dependency of other targets, which is used to execute a series of instructions first when a target is to be made:

build_all : clean
    ...
    ...

(4) Version control

Before the system is officially released, the program code will definitely contain many lines of code for debugging. But in practice, due to the limited storage resources of the embedded system, it is impossible to burn the program containing the debugging code into the board as the final code. Therefore, when designing, two versions (debug version and release version) are generally designed. Of course, when the program is developed, we cannot manually delete these debugging codes one by one. At this time, the idea of ​​conditional compilation in C language can be used, see the following analysis:

Debug version batch file: make_debug.bat

REM ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
REM Make_debug.bat
REM~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

REM 设定Windows/DOS的系统环境变量
REM
set BUILD_MODE = Debug

REM make我们的程序
REM
make target

Release batch file: make_release.bat

REM ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
REM Make_release.bat
REM~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

set BUILD_MODE = Release
make target

makefile:

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#makefile
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
!IF "$(BUILD_MODE)" == "Debug"
# 如果BUILD_MODE等于“Debug”,则设定编译时期的参数CFLAGS_DEBUG = __DEBUG_VERSION
# 反之,则设定编译时期的参数为空
#
CFLAGS_DEBUG = -D__DEBUG_VERSION
!ENDIF

target:
    gcc $(CFLAGS_DEBUG) xxx.c
#-D参数用来在编译时期设定宏变量“__DEBUG_VERSION”

4、Link Script

In the process of making executable files, all program files must be compiled into object files first, and the next step is to link all object files and library files into executable files through the linker linker. How to link and which address to connect to is specified by the link script file with the extension .ld.

In the case of an operating system, different programs have their own address spaces and do not interfere with each other. Such programs are all executed in RAM (memory), and all programs only need to be connected from the same starting address. However, embedded programs often do not have an operating system. The system and the program are usually in the same address space, and there is often no hard disk. The program can only be executed in ROM or flash. But data can only be addressed in RAM, so when connecting, tell the linker where the program segment should be addressed (the starting address of the ROM) and where the data segment should be addressed (the starting address of the RAM) .

(1) The structure of the program section

  • text segment : the code segment, the content of the text segment will not change during execution, it can be executed directly in ROM without loading into memory.
  • Read-only-data (rodata) section : Variables and strings defined as const will be classified into the rodata section. , Which is also executed directly in ROM.
  • Data section : Global variables with initial values ​​are placed in this section. During the connection period, these initial values ​​must be added to the executable file, but must be addressed to the RAM address; during the execution period, these variables are stored in the ROM, but must be loaded into the RAM before they can be used, because they The value of is variable. Therefore, the data segment will be added to the ROM, but it must be addressed to the RAM.
  • Bss section : Global variables without initial values ​​will be classified into the bss section. Because there is no initial value, it does not need to be added to the program, as long as it is addressed to RAM when connecting. There was no problem of loading during execution, but after the machine RESET, the system actively cleared the entire bss segment.

(2) The content of the link script

Memory usage during execution:

Memory usage during execution

  • LMA(Load Memory Address)与VMA(Virtual Memory Address)

Data will be placed in ROM, but must be loaded into RAM during execution. The address in ROM (the final storage address) is called LMA, and the address in RAM (runtime) is VMA.

Try to write a link script with the following connection requirements:

  • There is a ROM in the system, its starting address is 0xC00000, and another RAM, its starting address is 0.
  • The executable file contains text, rodata, and data segments. The text and rodata segments can be executed in ROM, so they are addressed to 0xC00000, and rodata follows text.
  • Because the bss segment has no initial value, it will not occupy executable space or ROM space, and it will be addressed to the starting address of RAM 0.
  • The data section is more complicated, its content must also be included in the executable file, and it must be loaded into RAM during execution. So the VMA of data is in RAM, following the bss segment, and the LVA is following the rodata segment.

Expansion : When you want a program to be executed at a faster speed, you only need to put its LMA in ROM, and VMA will address it to RAM, and load it from ROM to RAM before execution.

Storage structure during execution

/*********************************************************
Link Script sample
存储器地址配置:ROM起始地址(0xC00000),RAM起始地址(0)
输出ARM9机器码,可执行文件格式为elf32
**********************************************************/

OUTPUT_FORMAT("elf32-arm9")
OUTPUT_ARCH(arm9)
SEARCH_DIR(.);

SECTIONS
{
    /*****************************************
    定义text段,起始地址(VMA)从0xC00000开始,
    若没有指定LMA,表示LMA起始地址同VMA。
    *****************************************/
    .text 0xC00000:
    {
    /* 定义变量__START_text,句号.表示当前的VMA,即0xC00000 */
    __START_text = . ;

    /* *(.text)表示将当前目录中所有的.text段加入到这个段*/
    *(.text);

    /* 定义变量__END_text,目前VMA应该是0xC00000加上所有.text段的size总和 */
    __END_text = . ;
    }

     /*****************************************
    定义rodata段,起始地址(VMA)从__END_text开始(跟在text段之后),
    若没有指定LMA,表示LMA起始地址同VMA。
    *****************************************/
    .rodata __END_text :
    {
    __START_rodata = . ;
    *(.rodata);
    __END_rodata = . ;
    }

     /*****************************************
    定义bss段,起始地址(VMA)从0开始,
    若没有指定LMA,表示LMA起始地址同VMA。
    *****************************************/
    .bss 0x00000000:
    {
        __START_bss = .;
        *(.bss);
        __END_bss = .;
    }

     /* 定义可在程序中使用的变量__SIZE_BSS,表示bss段的大小。*/
    __SIZE_BSS = __END_bss - __START_bss;

    /*****************************************
    定义data段,其LMA应该在ROM,而VMA在RAM。
    所以,VMA跟在bss段后面,LMA跟在rodata段之后
    *****************************************/
    .data __END_bss : AT(__END_rodata)
    {
        __START_data = .;
        *(.data);
        __END_data = .;
    }

    /*定义变量__START_data_LMA,表示data段的起始地址*/
    __START_DATA_LMA =  LOADADDR(.data);

     /* 定义可在程序中使用的变量__SIZE_DATA,表示data段的大小。*/
    __SIZE_DATA = __END_data - __START_data;

    /***********************************************
    speed_up模块的VMA和LMA都是跟在data段之后,
    它会被加到可执行文件中,但执行时要载入到RAM才能执行
    **************************************************/
    .text_speed_up __END_data : AT(__START_data_LMA + SIZEOF(.data))
    {
    __START_text_speed_up = .;
      speed_up_main.o(.text);
      speed_up_main.o(.rodata);
      speed_up_main.o(.data);
    __END_text_speed_up = .;
    /* 为便于说明,假设该模块没有bss段*/
    }
    __START_text_speed_up_LMA = LOADADDR(.text_speed_up);
    __SIZE_TEXT_SPEED_UP = __END_text_speed_up - __START_text_speed_up;
}

The code for transferring a program module (speed_up) to a faster memory for execution is as follows:

extern unsigned char * __START_text_speed_up;
extern unsigned char * __START_text_speed_up_LMA;
extern int __SIZE_TEXT_SPEED_UP;

void copy_data_section(void)
{
    //一个字节一个字节的传输(性能较差)
    int i;
    unsigned char *dest = __START_text_speed_up;
    unsigned char *src = __START_text_speed_up_LMA;
    for(i=0; i<__SIZE_TEXT_SPEED_UP; i++)
        dest[i] = src[i]
}

The code assigned to 0 for the bss segment is:

extern unsigned char * __START_bss;
extern int __SIZE_BSS;

void clear_bss_section(void)
{
    int i;
    unsigned char * dest = __START_bss;
    for(i=0; i<__SIZE_BSS;i++)
        dest[i] = 0;
}

(3) Map File or Symbol Table

In addition to generating executable files after linking, it is usually required to generate a map file (-m parameter of GNU linker'ld'), which is used to record every Symbol in the project (all functions in the program, library functions, global variables and linker) The automatically generated variable of the start and end address of each section) the corresponding relationship between the LMA and VMA. The following information can be obtained through the map file:

  • Whether the addressing of each section of the program is correct;
  • The size of each section of the program; namely the usage of ROM and RAM;
  • The address of each symbol in the program;
  • The order of each symbol in the memory
  • Storage usage of each program file

When the connection is completed, before downloading the executable file to the actual storage, you generally need to check the map file to make sure that the starting address and size of each section meet your own assumptions. The following figure is a partial screenshot of a map file:

Map file screenshot

5、ROM Maker

The executable file has various formats (ELF, COFF, HEX, S-Record, EXE, etc.), but the binary file that needs to be burned into the board ROM is the binary file, so when the executable file is obtained, it needs to be converted by ROM Maker Only binary files can be programmed. Of course, because embedded systems usually do not have a hard disk, files other than executable binary files must also be converted into a total single binary file (Image File) together with them. This process is called make ROM. The specific process is shown in the figure below:

The process of making the final Image File

In addition to the binary executable file, the files that are added to the Image File are usually pictures (JPG files, etc.). The common practice is to convert the picture file into a constant C array by bytes and give it a name , In the program, you can use these data by directly operating the memory, thus avoiding the use of the file system, but the scalability is not strong and the update is troublesome. Therefore, when there are a lot of these image files, it is more convenient to use a file system to manage them.

In fact, we generally develop a tool to convert all files in a directory into a C array program, and at the same time, a .h header file will be generated, which contains all the C array declarations representing data mining and each array's Size, you can use these arrays as long as you include the .h file when you use it.

  • File system image

In fact, the file system is just an interface for accessing data. It is a set of abstract data types that implement operations such as data storage, hierarchical organization, access, and acquisition. It is possible where the file system is stored and what format it uses. If the system has no requirement for writing files, the file system can still be stored in ROM.

In an embedded system, if there is no need to write data, I generally use an index table to record the file name and its first address and file size in the memory. For the convenience of searching, the index table is generally located at the highest address.

File system for embedded system

6、Offline Tools

Tools that are used in the development phase and must be developed and executed on the PC are called offline tools. These tools can be divided into 6 categories:

  • Program Generator (Program General)

    • System configuration setting tool: A tool that runs on the PC and is used to select the system configuration (certain function switches, LCD resolution, etc.), and automatically generate a .h file or make-file.
    • Resource Manager: The string, graphic or data file to be added to the system is resource. For example, the small graphic file used for the UI interface must be converted to a C array and added to the program, and other programs correspond to the array through the resource ID. This tool allows us to automatically export the .h file that contains all resource ID definitions and the .c file that contains the C array of these resource contents just by editing the resource file name.
  • Data Maker: General embedded systems cannot use databases such as mySQL, and must be designed according to the characteristics of the application.
    • File System: Strictly speaking, a file system is also a database, but its unit is a file rather than a record.
    • Database: The so-called database basically contains data files and multiple levels of index tables. Under the premise of limited CPU computing power, the design of database format and compression algorithm is particularly important.
    • Product built-in files: For example, some files that cannot be deleted by users, such as some MP3 built-in music or e-book built-in books, must be distinguished from user-editable files, which involves multiple file storage areas or multiple file systems.
    • Product information or default factory settings: For some frequently changing information (manufacturer, date, etc.), we tend to not write it in the program, but store the information in file or database, so that the system is running Just get the information in it.
  • Image Maker: Its function is to make an image to be burned into the memory at the end. The image contains not only the program, but also product information, FIle System image, Database, etc.

Application of offline tool in embedded system development

  • Download tool: In addition to using a burner to write the image into the memory, it is also necessary to provide a download tool for partial download, because sometimes it only updates some programs or some files in the file system.
  • Mass production tool: Some information of the manufacturer (manufacturer name, batch number, date, etc.) can only be determined before burning. At this time, a tool needs to be provided to the manufacturer to write this information to a specific location in the image before proceeding to memory burning.
  • Emulator
  • Other tools

7. Download and execute

Strictly speaking, the so-called ROM cannot be burned. Before mass production, it is necessary to entrust a professional Mask-ROM manufacturer to perform one-time burning according to the image file we provide. In the development stage, we have to choose other repeatable alternatives, such as NOR-flash, EPROM or EEPROM. There are generally several ways to write data:

  • First use ICE to download to RAM for execution and test.
  • Burner: First put the chip of the memory on the socket of the burner, and then use the PC to operate the burning program provided by the manufacturer, select the image file and execute the burning. (The memory of the board in the development stage is first designed to be connected to the board through a socket, we only need to put the burned IC on the socket and clamp it)
  • ROM-Emulator: This tool is to emulate EPROM/EEPROM, one end of which is connected to the socket of the board, and the other end is connected to the PC. Through the program provided by the manufacturer, the image file can be downloaded to the memory of the ROM emulator, and the machine is connected to the emulator just like a real ROM.
  • Update program: If the actual board can be connected to the PC through some way (USB, RS232, network cable) and transmit data, we can develop an update program module to receive the content of the image file on the PC side and write it into the NOR flash. In this way, the function of updating the program version on the machine is completed.

8. Version control

Whether it is an embedded system or a general software project, as long as it involves multi-person collaborative development, version control must be done. When software development reaches a certain milestone or has a major breakthrough, the administrator can give the current version a name, we call it Label or tag, and anyone can download all programs at a certain time point from the version control server.

When the system needs to develop a new function, you can establish a branch and develop on that branch. After success, merge with the master branch.

Guess you like

Origin blog.51cto.com/14592069/2556459