Embedded software development using ADS1.2 (bottom)

Source: Internet
Author: User
Tags requires reset
Placing Stacks and heap
The scatterloading mechanism provides a way to specify code and static data layout. Here's how to place the stack and heap for your application.
* _user_initial_stackheap Redirection
The stack and heap of the application are built up during the initialization of the C library function. You can change the position of the stack and heap by redirecting the corresponding subroutine, in the Ads library function, the _user_initial_stackheap () function.
_user_initial_stackheap () can be implemented in C or assembly, and it must return the following parameters:
R0:heap base Site;
R1: Stack base address;
R2:heap length limit value (if required);
R3: Stack length limit value.
When the user uses the distributed loading function, the _user_initial_stackheap () must be called again, or the connector will error:
Error:L6218E:Undefined symbol image$ $ZI $ $Limit (referred from SYS_STACKHEAP.O)


* memory model
ADS provides two real-time memory models. The default is One-region, where the stack and heap of the application are in the same memory block, used to grow against each other, and the stack pointer needs to be checked when allocating a piece of memory space in the heap. Another scenario is that the stack and heap use two separate memory areas. For extremely fast RAM, you can choose to use it only as a stack. In order to use this two-region model, the user needs to import the symbol use_two_region_memory,heap using the length limit value that needs to be checked for the heap.
For both of these models, the stack is not checked for growth by default. Users can use the-APCS/SWST compiler option to perform software stack checks at program compile time. If you use the Two-region model, you must specify a stack limit value when you execute _user_initial_stackheap.


Figure 9 redirect _user_initial_stackheap ()


Figure 10 Basic initialization process


Figure one Rom/ram redirection and mapping


Table 1

System Reset and initialization
At present, the general assumption is that the program starts execution from the initialization entry _main of the C library function. In fact, all embedded programs perform some system-level initialization at startup. The content of this aspect is discussed here.
Initialization process
The basic initialization of an arm-based embedded system is shown in Figure 10. As you can see, a reset processing module, reset handler, is added prior to _main, which starts immediately when the system is reset. New blocks of code identified as $sub$ $main executed before entering the main program.
Reset processing Module The reset handler is usually a small piece of assembly code that executes when the system is reset. It completes the stack initialization of at least all the processor patterns used in the application. For kernels that contain a local memory system (such as the arm kernel with the cache), the configuration must also be done during this initialization. When the system initialization is complete, the program usually jumps to _main and begins the initialization of the C library function.
The system initialization process typically includes additional content, interrupt enable, and most of these are scheduled to be executed after the initialization of the C library function is completed. $sub $ $main () to complete this part of the function.
Vector Tables (vectors table)
All arm systems have a single interrupt vector table. The vector table must be called when an exception is required to be processed. The vector table is typically located at 0 addresses.


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 starts, non-volatile memory is required to ensure that the correct startup code exists at 0 addresses.
An easy way to do this is to assign a piece of address that the system 0x0000 begins to ROM. The disadvantage is that because ROM accesses more slowly than RAM, when the interrupt response needs to jump from the interrupt vector table, the system performance is lost, and the contents of the vector table in ROM cannot be modified dynamically by the user program.
Another possible scenario is shown in Figure 11. The ROM is located at the beginning of address 0x1000, but is mapped to the 0x0000 address by the memory controller when the system is reset. So when the system starts, the address 0x0000 see is ROM, the system executes the boot code in this ROM, the boot code jumps to the address of the real ROM, and lets the memory controller remove the address mapping of the ROM. The memory at the 0x0000 address is then restored back to ram. The code in the __main copy the vector table to ram in 0x0000 so that the exception can be correctly responded to.
Table 1 is an example of performing rom/ram redirection and mapping in arm assembler. It is based on ARM's integrator platform, which applies to all platforms similar to the Rom/ram redirection approach. The first instruction completes the jump from the mapped address (0x00000) of the ROM to the real address. The address designator instruct_2 is the real address of the ROM (0x180004). The address mapping of the ROM is then removed by setting the appropriate control register on the Integrator platform. The code is executed as soon as the system is started. All operations on address redirection/mapping must be completed before the C library function is initialized.


* local memory configuration
Many arm processors have on-chip memory systems such as cache and tightly coupled memory (TCM), Memory Management Unit (MMU), or memory protection Unit (MPU). These devices are configured correctly during system initialization and have special requirements to consider.
from the previous article, the C library function initialization code in _main is responsible for the memory system setup when the program is running. Therefore, the entire memory system itself must be initialized before __main, such as the MMU or MPU must be configured in reset handler. The initialization of the
tightly coupled memory (TCM) must also be done before _main (usually before Mmu/mpu), because the general program needs to distribute the code and data into TCM. It is important to note that when TCM is enabled, it no longer accesses the memory that is blocked by TCM.
about the cache consistency issue, if the cache is enabled before _main, then when the _main inside the code and data copy from the load zone to the execution area (since both the instruction and the data are treated essentially as data during the copy process), the instruction appears in the data buffer. The way to avoid this problem is to enable the cache after the C library function initialization is complete.
* Scatter loading and memory configuration
either through Rom/ram redirection or MMU configuration, if the system does not have a consistent storage distribution at startup and runtime, The definition in the Scatterloading file will be based on the memory distribution after the system redirection.
above article Rom/ram redirection 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 Area Load_rom is placed at 0x10000, which represents the load address of code and data after redirection.

Initialization of the stack
The processor pattern that may be used in the program requires a stack pointer to be defined.
In table 2, the stack is in the address identified by the stack_base. This symbol can be a direct address in the memory system, or it can be defined in another assembly file, defined by the scatter file. Table 2 Code allocates a 256-byte stack for each of the FIQ and IRQ modes, and the user can also allocate stacks for other schemas in the same way. The simplest approach is to enter the appropriate mode and then specify the corresponding value for the SP register. If you want to use a software stack check, you must also specify a stack length limit value.
The values of the stack pointer and stack limit are automatically passed as parameters to the initialization code __USER_INITIAL_STACKHEAP of the C library function, and 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 enable, which need to be executed after the C library function is initialized.
The table 3 code shows how to use $sub and $supper. The connector replaces the function called Main () with the call $sub$ $main (), completes the cache and interrupts, and eventually jumps to main ().


Execution Mode considerations
It is important to choose a processor execution mode for the main application, depending on the initialization code of the system.
Many of the features used during the boot process, such as MMU/MPU configuration, interrupt enable, and so on, can only be performed in privileged-level mode. If you need to run your own application in privileged polar mode, you can simply change to the appropriate schema before exiting the initialization process without any other problems.
If you use user mode, you must ensure that all features that can only be performed in privileged mode are completed before you can enter user mode. Because the system mode and user mode use the same register group, the reset handler should exit from System mode and _user_initial_stackheap the application stack initialization in system mode. This allows all stack space to be set correctly after the processor enters user mode.

further consideration of the memory layout
assigning hardware addresses in the scatter file
Although the distributed layout of code and data can be described in a scatter file, the peripheral registers in the target hardware, the stack and heap configurations, are still directly in the program source code with the hardware address set. If all the memory address related information is defined in the scatter file, to avoid referencing the absolute hardware address in the source file, there is great benefit to the engineering management of the program.
* Define the target peripheral address in the scatter file
The address of the peripheral register is usually defined in the program file or header file, or a struct type is pointed to the peripheral register, and the address of the structure is located in the scatter file.
For example, there are 2 32-bit registers on the target timer, which can be mapped using the table 4来. To place the structure above the specified memory address, create a new execution area (see table 5). The scatter file then locates the TIMER_REGS structure in the address 0x40000000.
Note that the contents of these registers do not need to be zeroed during startup, and changing the contents of the registers may affect the system state. Adding the UnInit property on the execution area prevents the Zi data from being zeroed out during initialization.
Allocating stacks and heap in the scatter file
In many cases, the use of the scatter file to define the stack and heap addresses has some benefits, mainly: All memory allocation information is concentrated in a single file; changing the stack and heap addresses is just a good way to reconnect, no recompilation is required.
* Explicitly place symbols
In the ADS1.2 environment, this is the simplest method. In the preceding article, 2 symbols stack_base and heap_base are referenced, and these 2 symbols are created in the Assembler module and positioned in the respective execution area of the scatter file (see table 6).
In the table 7 file, the heap base address is located on the 0x20000 and the stack base address is 0x40000. The heap and stack locations can now be easily edited.
* Use connectors to generate symbols
This approach requires specifying the length of the heap and stack in the destination file. This has somewhat weakened the two advantages described at the beginning of this section.
The length of the heap and stack is defined first in the assembler source program. The keyword space is used to preserve a memory space, and Noint can block 0 operations (see table 8). Note that the address label is not required in the source file here.
These sections can then be positioned in the corresponding execution area of the scatter file (see table 9). The symbols produced by the connector point to the base address and length limits of each execution area, which can be used by the redirect code called by the _user_initial_stackheap. Using DCD in your code to define more meaningful names for these values can enhance the readability of your code (see table 10).
The file locates the heap base site at 0x15000 and the stack address is located in 0x4000. The location of the heap and stack can be easily changed by editing the address of the corresponding execution area.

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.