Follow+Star public number, don’t miss wonderful content
Arrangement | strongerHuang
WeChat Public Number | Embedded Column
Embedded Column
1
Currently, embedded development in China is mainly divided into embedded low-level development and embedded application development. The low-level embedded development is generally called driver development or BSP development, and sometimes referred to as Linux kernel development, which sounds very impressive.
On the other hand, embedded application development generally involves simpler business logic, which is often overlooked by many, so employers feel there is no need to hire architect-level personnel.
Embedded Column
2
Of course, it cannot be said that it is completely necessary, but at least for most projects, a software architecture design is needed, and the benefits are numerous, here are some:
Embedded Column
3
The embedded systems I want to mention here are more inclined towards microcontrollers, and I will explain layered design with a case study. Using MCU + IAR as an example, I will discuss separating low-level software from application software.
One approach: Generate a static library for the low-level software to provide to the application. However, this raises a problem: if the static library changes, it must be recompiled and then provided to the application, which also needs to be recompiled, making this a cumbersome handling method.
Another approach: The low-level software and application software are two independent bin files, tentatively named libdev.bin and app.bin. Non-operating system embedded systems do not have dynamic libraries like .so, but we can consider the executable file of the low-level software as app’s .so.
These two bin files are configured through icf, mapped to different flash spaces, and allocated different RAM spaces. Clearly, the relationship between these two bin files is that app.bin will call the implementation of libdev.bin.
But they are independent bin files, how do we link them? This requires a function table to tell app.bin where to call the function implementations inside libdev.bin. To achieve this function table, a unified function interface is needed for easy management. This function table can be implemented using a static library .a (libdev.a). The function of libdev.a is to map all libdev interface functions, so when app calls a certain interface function, it can jump to the implementation inside libdev.bin.
Specific design ideas:
1. The function table is implemented using a structure, with structure elements being function pointers.
struct libdev_ops{ int (*dev_PortOpen)(int PortNum, char *PortParm);};
2. Inside libdev.bin, assign values to the function pointers within the structure.
void libdev_ops_init(struct libdev_ops *ops){ ops->dev_PortOpen = dev_PortOpen; // Assign the function address to the corresponding function pointer}
3. When the program starts, it first enters libdev.bin, then jumps to app.bin. A jump address function is needed (inside libdev.a).
struct libdev_ops ops;void call_app(int addr){ int (*startup)(struct libdev_ops *ops); startup = (int(*)(struct libdev_ops *))(addr); libdev_ops_init(&ops); startup(&ops);}
4. Repackage all functions as follows:
int dev_PortOpen(int PortNum, char *PortPara){ return ops->dev_PortOpen(PortNum, PortPara);}
5. Implement the function that requires a jump address for libdev.bin (inside app.bin).
void common_startup(struct libdev_ops *libdev_ops){ ...... ops = libdev_ops; dev_printf = ops->printf; // printf is a variable argument function, cannot be assigned in step 2, so it is initialized in the static library. main(); // Jump to app's main}
6. Modify the startup address of the app.bin program, modify IAR configuration.
Enter options — linker — library — check override default program entry, and enter common_startup after Entry symbol.
7. Since there are two .bin programs, it is necessary to configure the icf file, and the addr in call_app(addr) is the address of the common_startup function inside app.bin. Therefore, you need to compile app.bin and check the address of common_startup in the output file’s app.map (since this function is the first to execute, its address is the starting address configured in icf).
8. Then you can normally call the dev_PortOpen function in the application if you include the header file for it.
Since libdev.bin and app.bin run simultaneously (the libdev function called by app.bin is implemented inside libdev.bin), RAM and ROM must be divided into two parts and must not overlap.
Reference: https://blog.51cto.com/kenotu/1614390
Reply in the background『Embedded Software Design and Development』to read more related articles.
Click “Read the original” for more shares, welcome to share, collect, like, and see.