Use ads1.2 for embedded software development (below)

Source: Internet
Author: User
Stack and heap placement
The scatterloading Mechanism provides a method to specify the code and static data layout. The following describes how to place the application stack and heap.
* _ User_initial_stackheap redirection
The Application Stack and heap are established during the C library function initialization process. You can rewrite the corresponding subroutine to change the location of the stack and heap. In the library function of ads, that is, the _ user_initial_stackheap () function.
_ User_initial_stackheap () can be implemented using C or assembly. It must return the following parameters:
R0: heap base address;
R1: Stack base address;
R2: Maximum heap length (if needed );
R3: Stack length limit value.
When using the distributed load function, you must re-call _ user_initial_stackheap (); otherwise, the connector reports an error:
Error: l6218e: Undefined symbol image $ Zi $ limit (Referred From sys_stackheap.o)

*Memory Model
ADS provides two real-time storage models. The default value is one-region. The application stack and heap are located in the same storage block and grow in the opposite direction. When allocating a memory space in the heap area, you need to check the stack pointer. Another scenario is that the stack and heap use two separate storage areas. For RAM with extremely high speed, you can choose to use it only for stacks. To use this two-region model, you need to import the use_two_region_memory symbol. To use heap, you need to check the length limit of heap.
By default, the growth of stacks is not checked for both models. You can use the-APCs/swst compiler option for software stack check during program compilation. If the two-region model is used, a stack limit value must be specified when _ user_initial_stackheap is executed.

 


Figure 9 redirection _ user_initial_stackheap ()


Figure 10 basic initialization process


Figure 11 ROM/Ram redirection and ing


Table 1

System reset and initialization
In the current situation, it is generally assumed that the program is executed from the initialization entry _ main of the C library function. In fact, all embedded programs must perform system-level initialization during startup. This topic is discussed here.
Initialization Process
Figure 10 shows the basic initialization process of an ARM-based embedded system. We can see that a reset processing module reset handler is added before _ main, Which is started immediately when the system is powered on and reset. The new code block marked as $ sub $ main is executed before the main program.
The reset processing module reset handler is usually a small piece of assembly code that is executed during system reset. It completes at least the stack initialization of all processor modes used in the application. For a kernel containing a local memory system (such as an ARM Kernel containing a cache), the configuration must also be completed during the initialization process. After the system initialization is completed, the program usually jumps to _ main to start the initialization process of the C library function.
The system initialization process generally includes other content, such as interrupt enabling and so on, which are mostly executed after the initialization of the C library function is complete. $ Sub $ main () to complete this function.
Vector table)
All arm systems have an interrupt vector table. When an exception occurs, the vector table must be called. Generally, the vector table must be at 0.


Table 2


Table 3


Table 4


Table 5


Table 6


Table 7


Table 8


Table 9


Table 10

Memory Configuration
*ROM/Ram redirection
When the system is started, non-volatile memory is required to ensure that the correct startup code exists at address 0.
A simple method is to allocate an address starting with 0 x to Rom. The disadvantage is that the ROM Access speed is much slower than that of Ram. When the execution interrupt response needs to jump from the interrupt to the table, the system performance will be compromised. At the same time, the vector table content in the ROM cannot be dynamically modified by the user program.
Another feasible solution 11 is shown. Rom is located at the beginning of address 0x1000, but is mapped to address 0x0000 by the memory controller when the system is reset. In this way, after the system starts, the Rom is displayed at address 0x0000. The system executes the boot code in this ROM and the boot code jumps to the real rom address, and let the memory controller remove the address ing to Rom. At this time, the memory at the address 0x0000 is restored to ram. The code in _ main copies the vector table to Ram at 0x0000, so that the table can be correctly responded to exceptions.
Table 1 provides an example of ROM/Ram redirection and ing in arm assembly. It is based on ARM's integrator platform and applies to all platforms similar to Rom/Ram redirection methods. The first command redirects from the ROM ing address (0x00000) to the real address. The instruct_2 address is the actual Rom address (0x180004 ). Then, the ROM address ing is removed by setting the corresponding control registers on the integrator platform. The code is executed once the system is started. All operations on address redirection/ ing must be completed before the C-library function initialization.

*Local Memory Configuration
Many arm processors have on-chip memory systems, such as cache and tightly coupled memory (TCM), Memory Management Unit (MMU), and memory Protection Unit (MPU ). These devices must be correctly configured during system initialization and have special requirements.
As we can see from the previous article, the C library function initialization code in _ main is responsible for the memory system settings when the program is running. Therefore, the entire memory system must complete initialization before _ main. For example, MMU or MPU must complete configuration in reset handler.
The initialization of tightly coupled memory (TCM) must also be completed before _ main (usually before MMU/MPU), because the general program needs to scatter the code and data into TCM. Note that when TCM is enabled, it no longer accesses the memory blocked by TCM.
For cache consistency issues, if the cache is enabled before _ main, when _ main is used to copy code and data from the loading area to the execution area (because commands and data are essentially treated as data processing during the copy process ), the command appears in the data buffer. To avoid this problem, you can enable the cache after the C library function Initialization is complete.
*Scatter loading and memory configuration
Whether configured through ROM/Ram redirection or MMU, if the Storage Distribution of the system at startup and runtime is inconsistent, the definition in the scatterloading file must be based on the memory distribution after system redirection.
The preceding ROM/Ram redirection is used as an example:
Load_rom 0x10000 0x8000
{
Exe_rom 0x10000 0x8000
{
Reset_handler.o (+ RO, + first)
...
}
Ram 0x0000 0X4000
{
Vectors. O (+ RO, + first)
...
}
}
The load_rom in the load area is placed at 0x10000, representing the address for Loading Code and data after redirection.

Stack Initialization
A stack pointer must be defined for all the processor modes that may be used in the program.
In Table 2, the stack is located in the address identified by stack_base. This symbol can be a direct address in the memory system, or it can be defined in another assembly file, which is defined by the scatter file. Table 2 code allocates a 256-byte stack for each FIQ and IRQ modes. You can allocate a stack for other modes in the same way. The simplest way is to enter the corresponding mode and specify the corresponding value for the SP register. To use the software stack check, you must specify a stack length limit value.
The value of the stack pointer and stack restriction will be automatically passed to the initialization code _ user_initial_stackheap of the c library function as a parameter. These values should not be modified in _ user_initial_stackheap.
Hardware initialization $ sub $ main ()
In general, all system initialization code should be separated from the main application, but there are several exceptions, such as cache and interrupt enabling, which must be executed after the C library function initialization.
Table 3 code shows how to use $ sub and $ supper. The connector replaces the Call Main () function with call $ sub $ main (), completes cache and interrupt enabling, and finally jumps to main ().

Execution Mode considerations
It is very important to select a processor Execution Mode for the main application, depending on the system initialization code.
Many functions used during the startup process, such as MMU/MPU configuration and interrupt enabling can only be performed in privileged mode. If you need to run your own applications in privileged mode, you only need to change to the corresponding mode before exiting the initialization process. There is no other problem.
If user mode is used, you must ensure that all functions executed in privileged mode are completed before entering user mode. Because the system mode and user mode use the same register group, reset handler should exit from system mode, and _ user_initial_stackheap completes Application Stack initialization in system mode. In this way, after the processor enters the user mode, all the stack spaces have been correctly set.

Further consideration of memory Layout
Allocate hardware addresses in the scatter File
Although code and data layout can be described in a scatter file, the peripheral registers, stacks, and heap configurations in the target hardware are still directly set in the program source code using the hardware address. If you define all the information related to the memory address in the scatter file to avoid referencing absolute hardware address in the source file, it is of great benefit to program engineering management.
* Define the target peripheral address in the scatter File
Generally, the address of the peripheral register is defined in the program file or header file. You can also declare a structure type pointing to the peripheral register. The structure address is located in the scatter file.
For example, the target timer has two 32-bit registers, which can be mapped with table 4. To place the structure on the specified memory address, create a new execution zone (see table 5 ). The scatter file locates the timer_regs structure in the address 0x40000000.
Note that the content of these registers does not need to be cleared during the startup process. Changing the register content may affect the system status. Adding the uninit attribute to the execution area can prevent the Zi data from being cleared during initialization.
Allocate stacks and heap in the scatter File
In many cases, using scatter files to define the stack and heap addresses brings some benefits, mainly including: all memory allocation information is concentrated in one file; you only need to reconnect the stack address and heap address without re-compiling.
* Explicitly place symbols
In the ads1.2 environment, this is the simplest method. Two symbols stack_base and heap_base are referenced in the previous article. These two symbols are created in the assembly module and located in the respective execution areas of the scatter file (see table 6 ).
In table 7, the heap base address is located on 0x20000, And the stack base address is located on 0x40000. Now the location of heap and stack can be easily edited.
* Use the symbols produced by the connector
In this method, you must specify the heap and stack length in the target file. This weakens the two advantages described at the beginning of this section.
First, define the heap and stack length in the Assembly source program. The keyword space is used to retain a piece of memory space, and noint can prevent the zeroing operation (see table 8 ). Note that the address label is not required in the source file.
Then these parts can be located in the corresponding execution zone of the scatter file (see table 9 ). The symbols generated by the connector point to the base address and length limit of each execution zone. These symbols can be used by the redirection code called by _ user_initial_stackheap. Using DCD in Code to define more meaningful names for these values can enhance code readability (see table 10 ).
The file locates the heap base address in 0x15000, And the stack address in 0X4000. The heap and stack locations can be easily changed by editing the address of the corresponding execution zone. ■

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.