Scatter-loading for ARM

Publisher:心动代码Latest update time:2016-06-21 Source: eefocusKeywords:ARM Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere
For those who have just learned ARM, if they analyze its startup code, they often do not understand the meaning of the following variables: |Image$$RO$$Limit|, |Image$$RW$$Base|, |Image$$ZI$$Base|.

First of all, I would like to state that the debugging software I use is ADS1.2. After we have written the program, we need to compile and link it. Select the MAKE button in ADS1.2, and an Errors and Warnings dialog box will appear. The results of the compilation and linking will be displayed in this column. If there are no errors, you should be able to see Image component sizes at the end of the file, followed by the number of bytes of each item, Code, RO Data, RW Data, ZI Data, and Debug, and finally a statistical data of them:

Code 163632, RO Data 20939, RW Data 53, ZI Data 17028

Tatal RO size (Code+ RO Data) 184571 (180.25kB)

Tatal RW size(RW Data+ ZI Data) 17081(16.68 kB)

Tatal ROM size(Code+ RO Data+ RW Data) 184624(180.30 kB)

The number of bytes following this is based on the user's different programs. The following will use the above data as an example to explain the calculation of those variables.

In the Debug Settings of ADS, there is a column called Linker/ARM Linker. In the output option, there is an RO base option. There should be an address below it. In my case, it is 0x0c100000. The RW base address behind it is 0x0c200000. Then in the Options option, there is Image entry point, which is the entry address of the initial program. In my case, it is 0x0c100000.

With the above information, we can fully understand how these variables come from:

|Image$$RO$$Base| = Image entry point = 0x0c100000 ; indicates the starting address where the program code is stored

|Image$$RO$$Limit|=Program code starting address+code length+1=0x0c100000+Statal RO size+1

= 0x0c100000 + 184571 + 1 = 0x0c100000 +0x2D0FB + 1

= 0x0c12d0fc

|Image$$RW$$Base| = 0x0c200000 ; specified by RW base address

|Image$$RW$$Limit| = |Image$$RW$$Base| + RW Data 53 = 0x0c200000+0x37 (multiples of 4, 0 to 55, a total of 56 units)

=0x0c200037

|Image$$ZI$$Base| = |Image$$RW$$Limit| + 1 =0x0c200038

|Image$$ZI$$Limit| = |Image$$ZI$$Base| + ZI Data 17028

                            =0x0c200038 + 0x4284

                            =0x0c2042bc

It can also be calculated from:

|Image$$ZI$$Limit| = |Image$$RW$$Base| +TatalRWsize(RWData+ZIData) 17081

                            =0x0c200000+0x42b9+3 (must be a multiple of 4)

                            =0x0c2042bc

 

Original address http://blog.csdn.net/yyt7529/archive/2009/06/05/4245604.aspx

 

For simple applications, you do not need to write a .scf file. Instead, select "Simple" on the "Output" page. Then fill in the starting addresses of "RO Base" and "RW Base". On the "Lay Out" page, fill in Object/Symble: Startup.o, Section: Start. Write the startup file: Startup.s.

 

In the "Option" page, fill in the starting address in "Image Entry Point".

-------------------------------------------------- ----------------------------------

 

The structure of Scatter-Load Description File:

 

The "+RW" in the ".scf" file corresponds to the "READWRITE" in the ".s" source file.

"+ZI" in the ".scf" file corresponds to "NOINIT" in the ".s" source file.

"+RO" in the ".scf" file corresponds to "READONLY" in the ".s" source file.

 

In the ".s" source file there is:

AREA area_name CODE/DATA,READONLY/NOINIT/READWRITE

END

 

 

".scf" example

 

Contents Notes

ROM_LOAD 0x80000000

{ ;Name of Load Region, Start Address for Load Region and Maximum size of Load Region (omitted)

  ROM_EXEC 0x80000000 0x20000

{ ; Off-chip storage area, starting from 0x80000000, up to 0x20000 bytes.

  Startup.o(Vector,+First); The Vector segment of the Startup module is placed at the front. Note 1

  *(+RO); All code and read-only data in all other modules are placed here.

  }  

  IRAM 0x40000000 0x00004000

{ ; On-chip RAM area, starting from 0x40000000, up to 0x4000 bytes

  Startup.o(MyStacks,+first); specifies that MyStacks in Startup.o is placed first.

  Startup.o(+RW,+ZI); Other +RW/+ZI sections in Startup.o. Note 1

  os_cpu_a.o(+RW,+ZI)  

  }  

  STACKS 0x40004000 UNINIT

{ ; The top of the on-chip 16K RAM stores segments that do not need to be initialized by the "C library".

  Stack.o(+ZI) Note 2

  }  

  ERAM 0x80040000

{  

  *(+RW,+ZI)  

  }  

  HEAP +0 UNINIT

{; "+0" means continuing from the end of the previous section "ERAM" and continuing to arrange the storage area.

  Heap.o(+ZI) Note 3

  }  

}    

 

The following is a sample of the source files referenced in the scf file: "Startup.s"

code 32

area Vectors,CODE,READONLY

entry

...

end Note 1: A segment named "Vectors" will be generated in "Startup.o", and the segment attribute is "READONLY"

"Stack.s"

area Stacks, DATA, NOINIT

export StackUsr

StackUsr SPACE 1

end Note 2: A segment named "Stacks" will be generated in "Stack.o" with the attribute "NOINIT", which corresponds to "+ZI" in the scf file. This segment does not need to be initialized or can be initialized to "0".

"Heap.s"

area Heap,DATA,NOINIT

export bottom_of_heap

bottom_of_heap SPACE 1

end Note 3: The segment named "Heap" in "Heap.o".

 

 

It is best to add a Maximum parameter to each Region in the Scatter file. In this way, when compiling, if the actual space used is larger than the Maximum Size, there will be an Error: 16220E: Excution region xxx size (xxx bytes) exceeds limit (xx bytes). If the address is repeated, there will be an Error: 16221E: Excution region xxx overlaps with excution region xxx. There may not be an Error when the first address of the previous Region + Maximum > the first address of the next Region. An Error will only occur when an allocated memory is overlapped.

 

Region's "UNINIT" and other parameters should be placed before the "Maximum size" parameter.

 

In a region, RAM is not allocated in the order listed. To make variables used in assembly have fixed positions, you can put ".o" generated by all assembly files in the same region. For example:

IRAM1 0x40000000

{

startup.o(+RW,+ZI)

ASMSourceCode1.o(+RW,+ZI)

ASMSourceCode2.o(+RW,+ZI)

}

IRAM2 +0

{

CSourceCode1.o(+RW,+ZI)

CSourceCode2.o(+RW,+ZI)

}

In this way, the addresses of variables defined in all assemblies are relatively concentrated.

If there is only one assembly file such as startup.s, it can also be like this:

IRAM 0x40002000 0x1000

{

startup.o (Mystack,+first)

*(+RW,+ZI)

}

Use a "+first" to force Mystack in startup.s to be placed at position 0x40002000.

 

Select "Image map" in "Edit -> DebugRel Settings...->ARM Linker". After compiling, detailed memory allocation will be displayed in the Error & Warnings window. If you specify an output file name in "List file name", the list will be directly saved in the specified file for multiple studies.

 

 

-------------------------------------------------- ----------------------------------

 

About JTAG interface:

P1.20/TRACESYNC should be pulled up with a resistor to disable the TRACE function. PINSEL2 must be initialized at the beginning of the program.

 JTAG

 Note

 

  1,2/VDD3.3V  

P1.31/nTRST, input 3/nTRST, output There are pull-up resistors in EasyJTAG.

P1.28/TDI, input 5/TDI, output There is a pull-up resistor in EasyJTAG.

P1.30/TMS, input 7/TMS, output There is a pull-up resistor in EasyJTAG.

P1.29/TCK, input/output 9/TCK, input/output There is a pull-up resistor in EasyJTAG.

P1.26/RTCK, input 11/RTCK, output P1.26 is connected to an external pull-down resistor.

P1.26 has an internal pull-up resistor, so the pin will be high when measured. However, during reset, its pull-up resistor does not work, only the external pull-down resistor works, P1.26 = 0V, so after power-on, D3~D0 of PINSEL2 will be 0x04 (B0100), and JTAG is valid.

If P1.26 is connected to 3.3V and then reset, D3~D0 of PINSEL2 will be 0x00 and JTAG will be invalid.

P1.27/TDO, output 13/TDO, input There is a pull-up resistor in EasyJTAG.

nRESET, input 15/nRST, output There is a pull-up resistor in EasyJTAG.

  4,6,8,10,12,14,16,18,20/GND  

  17,19/NC  

 

 

The G18 control board uses LPC2114, and the program will not be loaded correctly every time Axd is run. The reasons are as follows:

 

One time, there was already an Axd running, so when I opened the second Axd, the program would not be loaded correctly.

Another time I recompiled it and it was fine.

The above two times are not strange, but the following are strange:

In "Config Target -> Config -> Easy JTag Setup", randomly click the options in "Halt Mode" twice, then click "OK" all the way, and "Reload the last Image?" will appear, click "Yes". Sometimes the correct program will be loaded, but sometimes it will not be successful. To check whether it has been successfully loaded, just press "Ctrl-D" to display the Disassembly window, and you can see whether the program in the chip is correct.

Select "Reload Images" in "Option -> Config Interface -> Session File -> Session file Options". Every time you start Axd, you will be prompted with "The processor ARM_1 already has image(s) loaded. Continue the operation will replace the currently loaded images(s).... Do you wish to continue?" Select "Yes". Sometimes the program can be loaded successfully.

Of course, in "Easy JTag Setup -> Aux Option" check "Erase Flash when need".

The fixed program has a statement to disable the JTag debug port (a statement to operate PINSEL2). When it fails to connect, I use LPC2000 Flash Utility to erase the Flash. It works occasionally.

Note that when using LPC2000 Flash Utility, you must reset the circuit first, then click "OK".

 

Of course, the most fundamental solution is to set the computer parallel port to "EPP" mode. All other places can be set to "Default".

 

 

 

-------------------------------------------------- ----------------------------------

 

 

Valid user codes:

ARM uses "the sum of all 32-bit data in the vector table is 0" as the condition for valid user code. This only applies when using on-chip program memory. There is no such limitation for off-chip program memory.

 

C language programs usually require a section of assembly code for initialization, usually stored as "Startup.s", which usually implements the following tasks:

1. Make a good interrupt vector table

2. Initialize the external bus controller/stack/target board basic modules.

3. "__user_inital_stackheap" for library functions.

4. Infinite loop "__rt_div0: B __rt_div0" when the divisor is zero.

5. Support encryption function statements.

6. Define stack space: AREA MyStacks, DATA, NOINIT, ALIGN = 2

To define the starting address of the stack: IrqStackSpace SPACE ...

And the head of the stack: StackIrq DCD IrqStackSpace + Length*4. Because the stack grows downwards.

 

The initialization program related to the target board can be placed in a file named "Target.c".

1. Define interrupt processing entry: void IRQ_Exception(void), void FIQ_Exception(void), void Timer0_Exception(void).

2. Initialize the vector interrupt controller.

3. remap, system clock, real-time clock, memory acceleration.

 

 

 

-------------------------------------------------- ----------------------------------

 

 

Delay in C language:

__asm{

nop;

nop;}

That's it.

 

Note for C compilers: The priority of "==" is indeed higher than that of "&", so for anything involving logic, use "()" to confirm the priority to avoid low-level errors.

 

 

 

-------------------------------------------------- ----------------------------------

 

 

Operation of timer:

void Timer0Init(uint8 VICSlot, uint32 fdiv)

{

T0PR = 0; //Prescaling = 0

T0PC = 0; //Prescalar Counter

T0TC = 0; //T0 Counter

T0MR0 = Fpclk / fdiv; //Counting cycle

T0MCR = 0x03; //When the count reaches T0MR0, the interrupt is set, the counter is reset and continues to run.

T0CCR = 0x00; //No capture mode

T0TR = 0xffffffff; // Clear interrupt

T0TCR = 0x01; //Run

 

if(VICSlot <= 15){

    *((uint32*)(&VICVectAddr0 + VICSlot)) = (uint32)Timer0_Exception;

    *((uint32*)(&VICVectCntl0 + VICSlot)) = 0x20 | 0x04;

    VICIntEnable = 1 << 0x04;

}

}

 

 

Notice:

1. In "*((uint32*)(&VICVectAddr0 + VICSlot)) = ...", &VICVectAddr0 is used as the base address and VICSlot is used as the offset. Since (uint32*) has been used to declare that this is a pointer to uint32, each change in the offset means that the address has changed by 4 bytes. When the base address and the offset are added, the system automatically multiplies VICSlot by 4. If you write "... + 4 * VICSlot" in the program, it is wrong.

2. Be sure to use "Fpclk / fdiv" to set the delay to 1/fdiv seconds. This parameter cannot be in uS. If "Fpclk * us / 1000000" is used, multiplication overflow will occur during calculation, which is difficult to avoid and there is no warning, so it cannot be used.

 

 

 

-------------------------------------------------- ----------------------------------

 

 

Setting the I2C duty cycle:

I2SCLH = (Fpclk / fi2c + 1) / 2;

I2SCLL = (Fpclk / fi2c) / 2;

Wonderful! No matter "Fpclk / fi2c" is odd or even, the unilateral "Fpclk / fi2c + 1" makes the total I2C cycle "Fpclk / fi2c = I2SCLH + I2SCLL" methodically error-free.

 

I2C must work in interrupt mode. Because: "When the "SI" flag is reset, no serial interrupt is requested, and there is no stretching of the serial clock on the SCL line."

 

I2C information is at http://www.semiconductors.philips.com/acrobat/various/8xC552_562OVERVIEW_2.pdf.

 

 

 

-------------------------------------------------- ----------------------------------

 

 

Macro application:

 

In the process of setting up on-chip peripherals such as I2C, UART, T0, T1, SPI, some setting values ​​need to be calculated based on Fpclk. I hate using ARM to do division, so I use macros to implement it, and the division can be completed at compile time.

 

First, the initialization routines for all on-chip peripherals are named "void _xxxInit();". The reason for adding an "_" before the formal function name is to distinguish it from the macro so as not to write the function by mistake. Because the macro name is the same as the function name, it is just all capitalized and there is no "_" in front of it. For example:

 

#define TIMER0INIT(VICSlot,ms) _Timer0Init(VICSlot,Fpclk/100*ms/10);

 

void _Timer0Init(uint8 VICSlot,uint32 ClockCycle);

In the function, just set "T0MR0 = ClockCycle".

 

Note that the expression in the macro cannot be written as "Fpclk*ms/1000". If it is written like this, when mS is too large, for example, mS=1000, Fpclk*mS=(11059200/4)*1000=0xA4CB8000, the compiler will consider it an overflow (it regards the calculation result as a signed number). As long as an overflow warning appears, the setting is incorrect.

You should also not do division first to prevent loss of precision, which will result in the calculation result being "0" and causing the timer to die.

In short, calculation accuracy must be guaranteed, and overflow warnings must not appear.

 

 

 

-------------------------------------------------- ----------------------------------

 

 

Regarding the stack settings used by the C compiler:

1. There is a sentence in Startup.s:

MSR CPSR_C,#0x5f //System mode

LDR SP, =UsrStack //User stack

2. In the Scatter file, there is

STACKS 0x40004000 UNINT

{

    UsrStack.o(+ZI)

}

3. In UsrStack.s there is

AREA Stacks, DATA, NOINT

EXPORT UsrStack

UsrStack SPACE 1

END

Define a UsrStack, the size doesn't matter, put it at the top of the available physical memory. When the C compiler compiles a subroutine call, it pushes the registers to be protected onto the stack, such as:

stmfd r13!,{r3-r7,r14}

Among them, the alias of r13 is SP.

This is a full descending stack, that is, the data in the unit pointed to by SP is valid, and when pushing data into the stack, SP is decremented before storing the data.

Keywords:ARM Reference address:Scatter-loading for ARM

Previous article:The driver module in arm is loaded and called by the application
Next article:ARM scatter-loading files

Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号