I believe many engineers will often see the macro definitions as shown in the figure below when reading the RT thread related source code. According to the naming of macro definitions, these macro definitions seem to be some declaration work for some initialization functions.
As shown in the figure above, through tracing the source code, we can find that these inits_ XXX_ The macro definition of export calls init in the end_ The macro definition of export is to place the initialization function in the user-defined RTI_ FN symbol segment, the source code in the rtdef. H header file, as shown in the figure below.
What’s the use of putting initialization functions in custom symbol segments? The answer is that these initialization functions can be called implicitly in this way, without manually adding the function to the initialization process of RT thread.
What is implicit call? Implicit call means that when we add a system component or external device to the engineering code, the component or device needs to be initialized. For this initialization function, we don’t need to add calls directly to the main function or RT thread startup function, which can avoid modifying the RT thread startup code.
Let’s take a look at the calling process of RT thread’s startup function, and pay attention to the contents in the red box, as shown in the figure below.
In the startup function, there are two functions: RT_ components_ board_ Init() and RT_ components_ Init () is specifically used to handle automatic initialization. The prototypes and comments of these two functions are shown in the figure below.
As can be seen from the above function prototype, these two functions are used to continuously traverse the initialization functions in the symbol segment through the for loop, obtain the pointers of these initialization functions, and then call them to achieve the purpose of device or component initialization.
rt_ components_ board_ Init() function is executed first, this function is used to initialize the chip related hardware, this function will traverse with init_ BOARD_ List of functions declared by export (FN).
rt_ components_ Init() function is called and executed in the main thread after the system is started. This function is used to initialize other init functions_ XXX_ The list of functions declared by export (FN).
At present, the macro definition interface in RT thread kernel is used to realize the automatic initialization function, as shown in the figure below.
To sum up, the automatic initialization process of RT thread can be summarized as the following steps as shown in the figure.
Why can initialization function be called automatically after adding symbol segment? What is the symbol segment? What are the benefits of using this method?
To add a function to a symbol segment is to use the MDK compiler__ attribute__(( Section (x)), which is used to declare functions. When the compiler links the functions declared by section keyword, it will automatically collect these functions and put them into a centralized area. Check the following. Map file.
As shown in the red box above, RT_ hw_ pin_ Init and RT_ hw_ usart_ Init uses init_ BOARD_ Export (FN), so they are stored in the interval where the orange vertical line is located. Use RT_ components_ board_ Init() function can traverse this interval.
As shown in the blue box and green box above, they use init_ COMPONENT_ Export (FN) and init_ APP_ Functions declared by export (FN), which are stored in the interval where the red vertical line is located, use RT_ components_ Init() function can traverse this interval.
From the above analysis, it can be seen that the advantage of using symbol segment to store initialization function is that when I need to add an initialization function, I don’t need to change the RT thread startup code any more. I can directly add the initialization function to the corresponding symbol segment through the section keyword.
Thank you for reading!
Link to the original text:https://club.rt-thread.org/as…