Interpretation of ARM2440ddr.h file

Publisher:cwm6269310Latest update time:2015-01-15 Source: 51heiKeywords:ARM2440 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere
After the board is powered on, it will start executing from here, mainly completing basic initialization, judging whether to start from NOR or NAND, and then moving the program to SDRAM. After the transfer is successful, it will jump to the main function for execution.
 
Let's start looking at its specific code now!
 
The functions of GET and INCLUDE are the same, both of which are to import some compiled files.
 
 GET option.inc
 GET memcfg.inc
 GET 2440addr.inc
 
Define SDRAM to work in Reflesh mode. SDRAM has two refresh modes: selfreflesh and autoreflesh. The latter is set during its use.
 
 BIT_SELFREFRESH EQU (1<<22)
 
The following is the assignment of constants corresponding to the ARM processor mode register. The ARM processor has a CPSR register, and its last five bits determine which mode the processor is in. It can be seen that the definition of constants will not exceed the last 5 bits.
 
USERMODE    EQU  0x10
FIQMODE     EQU  0x11
IRQMODE     EQU  0x12
SVCMODE     EQU  0x13
ABORTMODE   EQU  0x17
UNDEFMODE   EQU  0x1b
MODEMASK    EQU  0x1f
NOINT       EQU  0xc0
Stacks for each exception mode
 
UserStack EQU (_STACK_BASEADDRESS-0x3800) ;0x33ff4800 ~
SVCStack EQU (_STACK_BASEADDRESS-0x2800) ;0x33ff5800 ~
UndefStack EQU (_STACK_BASEADDRESS-0x2400) ;0x33ff5c00 ~
AbortStack EQU (_STACK_BASEADDRESS-0x2000) ;0x33ff6000 ~
IRQStack EQU (_STACK_BASEADDRESS-0x1000) ;0x33ff7000 ~
FIQStack EQU (_STACK_BASEADDRESS-0x0) ;0x33ff8000 ~
This section unifies the working state of arm and the corresponding software compilation method (the 16-bit compilation environment uses tasm.exe to compile). The working state of arm processor is divided into two types: 32-bit, arm executes word-aligned arm instruction set; 16-bit, arm executes half-word-aligned Thumb instruction set. Different working states have different compilation methods. So the following program is to determine the working mode of arm to determine its compilation method.
 
 GBLL THUMBCODE //Define THUMBCODE This variable GBLL declares a global logic variable and initializes it to {FALSE}
 [{CONFIG} = 16//"[" means "if", "|" means "else", "]" means "endif", CONFIG is an internal variable defined in ADS compilation.
THUMBCODE SETL {TRUE}
     CODE32
   |
THUMBCODE SETL {FALSE}
    ]//If ARM is in 16-bit working state, set the global variable THUMBCODE to true.
 
   MACRO//This is the keyword for macro definition
 MOV_PC_LR //The function is to return from the subroutine
   [ THUMBCODE
     bx lr //When the target program is Thumb, use BX to jump back and switch the mode.
   |
     mov pc,lr //The target program is ARM instruction set, just assign lr to pc.
   ]
 MEND //End mark of macro definition.
 
   MACRO
 MOVEQ_PC_LR //This is a subroutine return with an "equal" condition. Similar to what is mentioned above.
   [ THUMBCODE
        bxeq lr
   |
     moveq pc,lr
   ]
 MEND
 
The handlexxx HANDLER handlexxx under the macro definition will be expanded into the following program segment. This program mainly transmits the entry address of the interrupt service program to the pc. The program uses 34 words to store the entry address of the interrupt service program. Each word space will have a label starting with handlerxxx.
 
 MACRO
$HandlerLabel HANDLER $HandleLabel
 
$HandlerLabel
 sub sp,sp,#4 // Reserve space first to store the jump address.
 
 stmfd sp!,{r0} //Push the working register into the stack.
 ldr     r0,=$HandleLabel
 ldr r0,[r0] //The function of these two sentences is to put the entry address of the interrupt program in the intermediate variable r0 first.
 
 str r0,[sp,#4]//Push the entry address of the interrupt service program into the stack.     
 ldmfd sp!,{r0,pc}//Finally, the interrupt program entry address in the stack is popped to the pc register, so that the corresponding interrupt service program can be executed.    
 MEND
 
S3C2440 has two interrupt modes: one with an interrupt vector table and one without. The one with a table has better real-time performance. When an external interrupt 0 occurs, the program automatically jumps to address 0x20. The instruction at address 0x20 is "ldr pc, = HandlerEINT0", so the program jumps to HandlerEINT0 to execute this macro operation, which is to assign the external interrupt address to PC.
 
An arm program is composed of three segments: R0, RW, and ZI. R0 is the code segment, RW is an initialized global variable, and ZI is an uninitialized global variable. BOOTLOADER needs to copy the RW segment to RAM and clear the ZI segment.
 
The compiler uses the following segments to record the start and end addresses of each segment:
|Image$$RO$$Base| ; RO segment start address|Image$$RO$$Limit| ; RO segment end address plus 1|Image$$RW$$Base| ; RW segment start address
 
|Image$$RW$$Limit| ; RW segment end address plus 1|Image$$ZI$$Base| ; ZI segment start address|Image$$ZI$$Limit| ; ZI segment end address plus 1
 
The values ​​of these labels are determined by the compiler settings, such as the settings of ro-base and rw-base in the compiler software, for example, ro-base=0xc000000 rw-base=0xc5f0000. Here, the IMPORT pseudo-instruction (same as extren in C language) is used to introduce |Image$$RO$$Base|, |Image$$RO$$Limit|... and other weird variables are generated by the compiler. The three segments RO, RW, and ZI are all stored in Flash, but the addresses of RW and ZI in Flash are definitely not the locations where the variables are stored when the program is running. Therefore, when our program is initialized, RW and ZI in Flash should be copied to the corresponding locations in RAM. These variables are set by RO Base and RW Base set in the project settings of ADS, and are finally imported into the program by the compilation script and linker.
 
IMPORT |Image$$RO$$Base|
 
IMPORT |Image$$RO$$Limit|
 
IMPORT |Image$$RW$$Base|
 
IMPORT |Image$$ZI$$Base|
 
IMPORT |Image$$ZI$$Limit|
 
Introduce two variables of external variable mmu fast bus mode and synchronous bus mode
 
IMPORT MMU_SetAsyncBusMode
IMPORT MMU_SetFastBusMode
 
The main function we are familiar with
 
IMPORT  Main
 
Function to copy image from Nandflash to SDRAM
 
IMPORT  RdNF2SDRAM
 
Define the arm assembly program segment, the segment name is init segment, which is a read-only segment
 
       AREA    Init,CODE,READONLY
 
       ENTRY
 
       EXPORT __ENTRY //Export __ENTRY label
__ENTRY
ResetEntry
 
ASSERT :DEF:ENDIAN_CHANGE//Judge whether the mode change has been defined (ASSERT is a pseudo instruction, :DEF:lable judges whether the label has been defined)
 
[ ENDIAN_CHANGE
  ASSERT :DEF:ENTRY_BUS_WIDTH//Judge whether the bus width is defined
 
  [ENTRY_BUS_WIDTH=32//If the memory is 32-bit bus width
   b ChangeBigEndian     ;DCD 0xea000007
  ]
 
  [ENTRY_BUS_WIDTH=16 //If the memory is 16-bit bus width
   andeq r14,r7,r0,lsl #20   ;DCD 0x0007ea00
  ]
 
  [ENTRY_BUS_WIDTH=8//If the memory is 8-bit bus width
   streq r0,[r0,-r10,ror #1] ;DCD 0x070000ea
  ]
 
|//If the bus width is not defined, jump directly to the reset interrupt
  b ResetHandler // Jump instruction executed by the program
 
]
 
 b HandlerUndef ;handler for Undefined mode
 b HandlerSWI ;handler for SWI interrupt
 b HandlerPabort ;handler for PAbort
 b HandlerDabort ;handler for DAbort
 b .  ;reserved
 b HandlerIRQ ;handler for IRQ interrupt
 b HandlerFIQ ;handler for FIQ interrupt
 
;@0x20
 b EnterPWDN ; Must be @0x20. //Enter powerdown mode
 
The above 8 jump instructions are 8 exception interrupt processing vectors, which must be arranged in sequence. As far as I know, each time an exception occurs, the hardware will look up the table by itself.
 
HandlerFIQ HANDLER HandleFIQ
HandlerIRQ HANDLER HandleIRQ
HandlerUndef HANDLER HandlerUndef
HandlerSWI HANDLER HandleSWI
HandlerDabort TRADE HandlerDabort
HandlerPassport TRADE HandlerPassport
 
The following program is very important, it is the program to implement the second table lookup. ARM classifies all interrupts as an IRQ and a FIRQ interrupt exception. In order to know the specific interrupt, we can jump to the interrupt service routine corresponding to the interrupt.
 
IsrIRQ
 sub sp,sp,#4 //Retain the value of the pc register
 stmfd sp!,{r8-r9}//Push r8 r9 into the stack
 
 ldr r9,=INTOFFSET//Load the address of interrupt offset INTOFFSET into r9
 ldr r9,[r9]//Get the value in INTOFFSET unit to r9
 ldr r8,=HandleEINT0 //The entry address of the vector table is assigned to r8
 add r8,r8,r9,lsl #2//Find the address of the specific interrupt vector
 ldr r8,[r8]//The entry address of the interrupt service routine stored in the interrupt vector is assigned to r8
 str r8,[sp,#8]//Push into the stack
 ldmfd sp!,{r8-r9,pc}//Stack pops up and jumps to the corresponding interrupt service routine
 
 
 
 LTORG//Declaration text pool
 
After the board is powered on, the program executes b ResetHandler at 0x00
 
ResetHandler
 ldr r0,=WTCON //turn off the watchdog  
 ldr r1,=0x0
 str r1,[r0]
 
 
 
 ldr r0,=INTMSK
 ldr r1,=0xffffffff //Disable all interrupts
 str r1,[r0]
 
 ldr r0,=INTSUBMSK
 ldr r1,=0x7fff //Disable all sub-interrupts
 
 str r1,[r0]
 
 
 
 [ {FALSE}
  ;rGPFDAT = (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4);
  ; Led_Display
  ldr r0,=GPBCON
  ldr r1,=0x155500
  str r1,[r0]//Make GPB10~GPB4 the output port and GPB3~GPB0 the input port
  ldr r0,=GPBDAT
  ldr r1,=0x0
  str r1,[r0]//Make GPB10~GPB4 output low level, GPB3~GPB0 input low level
 ]
 
It can be found from the data sheet that when the output is 1, the LED is off, and vice versa.
 
LOCKTIME is the lock time counter of the pll. To reduce the lock time of the pll, adjust the LOCKTIME register.
 
 ldr r0,=LOCKTIME
 ldr r1,=0xffffff //After assigning this value, the locktime values ​​of UPLL and MPLL will be set. You can ask Samsung why this value is set. I don't know much about it.
 str r1,[r0]
At this point, you may not understand it very well. Let me explain it in detail here. This involves the knowledge of the clock module of arm9. arm9 has a clock control logic, which can generate the FCLK clock of the CPU, the HCLK clock of the AHB bus peripheral interface device, and the PCLK clock of the APB bus peripheral interface device. arm9 has two phase-locked loops PLL, one for FCLK, HCLK, and HCLK. One for the USB module. We call these two PLLs MPLL and UPLL respectively. After the system is reset, the PLL operates according to the default configuration. Since it is considered to be in an unstable state at this time, the external clock is used as the output of the FCLK clock. Only when the corresponding value is set to the PLLCON register, the PLL will run according to the frequency set by the software. At this time, the output of the PLL is used as FCLK. For FCLK, there are two different clocks as inputs in succession, so there is an adaptation time. The setting of this time is the constant we set in the LOCKTIME register here.
 
[PLL_ON_START//Set the CLKDIVN value to be valid after the PLL lock time.
 
  ldr r0,=CLKDIVN
 
  ldr r1,=CLKDIV_VAL  ; 0=1:1:1, 1=1:1:2, 2=1:2:2, 3=1:2:4, 4=1:4:4, 5=1:4:8, 6=1:3:3, 7=1:3:6.
  str r1,[r0]
 
It can be seen that the ratio of FCLK, PCLK and HCLK is set. The required ratio can be obtained by simply operating CLKDIVN.
 
  [CLKDIV_VAL>1 //If Fclk:Hclk is not 1:1, execute the following
 
    mrc p15,0,r0,c1,c0,0
    orr r0,r0,#0xc0000000;R1_nF:OR:R1_iA
    mcr p15,0,r0,c1,c0,0
   |
    mrc p15,0,r0,c1,c0,0
    bic r0,r0,#0xc0000000;R1_iA:OR:R1_nF
    mcr p15,0,r0,c1,c0,0
  ] 
 
It can be seen here that if the ratio of FCLK:HCLK is not 1:1, it is necessary to switch to asynchronous bus mode. On the contrary, if it is this ratio, it is necessary to switch to fast bus mode.
 
  ldr r0,=UPLLCON //Configure UPLL
  ldr r1,=((U_MDIV<<12)+(U_PDIV<<4)+U_SDIV)//Here is the very familiar PMS, Fin = 12.0MHz, UCLK = 48MHz
  str r1,[r0]
  nop ; Caution: After UPLL setting, at least 7-clocks delay must be inserted for setting hardware be completed.
  nop
  nop
  nop
  nop
  nop
  nop
  ldr r0,=MPLLCON //Configure MPLL
  ldr r1,=((M_MDIV<<12)+(M_PDIV<<4)+M_SDIV) ;Fin = 12.0MHz, FCLK = 400MHz
  str r1,[r0]
 ]
 
 ldr r1,=GSTATUS2
 ldr r0,[r1]
 tst r0,#0x2
 
To determine whether the device is awakened from sleep mode, the detection of GSTATUS2[2] can determine whether the device is awakened from sleep mode.
 
bne WAKEUP_SLEEP // Jump if yes.
 
EXPORT StartPointAfterSleepWakeUp //Define an external StartPointAfterSleepWakeUp
 
StartPointAfterSleepWakeUp
 
    adrl r0, SMRDATA 
    ldr r1,=BWSCON 
    add r2, r0, #52 
 
0
    ldr r3, [r0], #4
    str r3, [r1], #4
    cmp r2, r0
    bne %B0
 
The purpose of this code is to set up the storage controller. There is a SMRDATA data area behind the code, with r0 used to define its start address and r2 used to define its end address. r3 represents the 13 storage controllers. The code is obvious, it is to assign the memory data to the 13 storage controllers.
 
 ldr r0,=GPFCON
 ldr r1,=0x0
 str r1,[r0]//set GPF as input function
 ldr r0,=GPFUP
 ldr r1,=0xff
 str r1,[r0]//Disable pull-up resistor
 
 ldr r1,=GPFDAT
 ldr r0,[r1]
 bic r0,r0,#(0x1e<<1) //bic is the bitwise AND of r0 and #(0x1e<<1).
 tst r0,#0x1//Here is to test whether the last bit is 0. If it is 0, it means a key is pressed.
 bne %F1 //When key 0 is not pressed, jump.
This code detects whether EINT0 is pressed.
 
 ldr r0,=GPFCON
 ldr r1,=0x55aa
 str r1,[r0]//GPF7~GPF4 are set as output, GPF3~GPF0 are set as EINT0~EINT3
 
 ldr r0,=GPFDAT
 ldr r1,=0x0
 str r1,[r0] //Obviously, GPF7~GPF4 are set to control the LED lights, and all low level lights are on. It serves as an indication.
 
 mov r1,#0
 move r2, #0
 move r3, #0
 mov r4,#0
 move r5, #0
 mov r6,#0
 mov r7,#0
 rice r8, #0
 
 
 
 ldr r9,=0x4000000   ;64MB
 ldr r0,=0x30000000
 
 
 
 stmia r0!,{r1-r8}
 subs r9,r9,#32
 bne %B0
 
It is obvious that the program uses registers r1~r8 to clear all the memory from 0x30000000 to 0x34000000.
 
1
 
 bl InitStacks // Initialize stack
 
 
 ldr r0, =BWSCON
 ldr r0, [r0]
 ands r0, r0, #6 //OM[1:0] != 0, boot from NOR FLash or memory, no need to read NAND FLASH
 bne copy_proc_beg //No need to boot from NAND FLASH, just jump here
 
 adr r0, ResetEntry//OM[1:0] == 0, boot from NAND FLash 
 cmp r0, #0//Compare whether the entry address is at 0, if not, use the emulator   
 bne copy_proc_beg // The emulator does not need to be started in NAND FLASH
 
nand_boot_beg
 [ {TRUE}
  bl RdNF2SDRAM
 ]
 
  ldr pc, =copy_proc_beg
 
Let's take a look at how RdNF2SDRAM works. The function of this code is to read the program from NAND into RAM.
 
 void RdNF2SDRAM( )
{
  U32 i;
  U32 start_addr = 0x0;
  unsigned char * to = (unsigned char *)0x30000000;
  U32 size = 0x100000; //It can be calculated that the size is 8M.
  rNF_Init(); //Let's take a closer look at this function.
 
  as follows:
 
         static void rNF_Init(void)
{
 rNFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0); //TACLS=1,TWRPH0=4,TWRPH1=0 initialize ECC, set CLE&ALE duration, set TWRPH0 and TWRPH1 duration.
 rNFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0);//Before reading and writing NANDFLASH, the settings of bits 6, 5, and 4 ensure that ECC can be used; clear bit 13 to allow writing, erasing, and reading the contents of the area 0x4E000038~0x4E00003C; since we do not impose any restrictions on the reading and writing of this range, we do not need to set an interrupt to notify the system that the area in this range has been read or written, that is, bit 10 is cleared; RnB indicates whether the memory is currently busy. When bit 9 is set to 1, it means that an interrupt can be used to notify the CPU of the current memory status, and bit 8 is set to indicate whether it is a rising edge trigger or a falling edge trigger.
 
 rNFSTAT = 0;
 rNF_Reset();
}
 
Let's take a look at the specific code of rNF_Reset(). The code is as follows:
 
static void rNF_Reset()
{
 NF_CE_L();
 NF_CLEAR_RB();
 NF_CMD(CMD_RESET); 
 NF_DETECT_RB();
 NF_CE_H();
}
 
The code looks annoying, but it's not. It's just a bunch of macro definitions. Let me translate it directly. The translation is as follows:
 
rNFCONT &= ~(1<<1); // Bit 1 is cleared to indicate chip select is enabled, so the chip can work.
 
rNFSTAT |= (1<<2); // Clear bit 2. There is no need to determine whether the chip is busy.
 
rNFCMD  = (CMD_RESET);//其中CMD_RESET=0xff。
 
while(!(rNFSTAT&(1<<2))); //When RnB changes from low level to high level, it will jump out of this loop. It is waiting for the NANDFLASH operation to be completed.
 
rNFCONT |= (1<<1); //Stop the chip from working.
 
In this way, the initialization of NANDFLASH is finally completed. Now we return to RdNF2SDRAM and continue the analysis.
 
switch(rNF_ReadID()) Let's analyze this function. The code is as follows:
 
static char rNF_ReadID()
{
 char pMID;
 char pDID;
 char nBuff;
 char n4thcycle;
 int i;
 
 
 NF_nFCE_L(); //Enable the chip to work   
 NF_CLEAR_RB(); //Clear bit 2 of NFSTAT to determine whether the film has completed the work.
 NF_CMD(CMD_READID); //Send the read ID command to NFCMD.
 NF_ADDR(0x0); //Send address to NFADDR
 for ( i = 0; i < 100; i++ );
 
 pMID = NF_RDDATA8();
 pDID = NF_RDDATA8();
 
 nBuff     = NF_RDDATA8();
 n4thcycle = NF_RDDATA8();
 NF_nFCE_H();
 
 
 return (pDID);
}//Why does pDID have other values ​​in the final return? I don't quite understand. Let's return to the main program and have a look.
 
switch(rNF_ReadID())
 {
  case 0x76:
   for(i = (start_addr >> 9); size > 0; ) // In this case, the size of a page is considered to be 512 bytes
   {
    rSB_ReadPage(i, to);
    size -= 512;
    to += 512;
    i ++;
   }
   break;
  case 0xf1:
  case 0xda:
  case 0xdc:
  case 0xd3:
   for(i = (start_addr >> 11); size > 0; ) // In this case, 2048 bytes are considered as one page
   {
    rLB_ReadPage(i, to);
    size -= 2048;
    to += 2048;
    i ++;
   }
   break;
 }
}  
 
In fact, the contents of the second page of NANDFLASH are stored in a pointer array, and the starting address of this pointer array is 0x30000000. This is the to[i] array we will see below. The following two functions have the same function, but the difference is how big a page is, 512 or 2048.
 
static void rSB_ReadPage(U32 addr, unsigned char * to)
{
 U32 i;
 
 rNF_Reset();
 
 //  Enable the chip
 NF_nFCE_L();
 NF_CLEAR_RB();
 
 // Issue Read command
 NF_CMD(CMD_READ);
 
 //  Set up address
 NF_ADDR(0x00);
 NF_ADDR((addr) & 0xff);
 NF_ADDR((addr >> 8) & 0xff);
 NF_ADDR((addr >> 16) & 0xff);
 
 
 NF_DETECT_RB();  // wait tR(max 12us)
 
 for (i = 0; i < 512; i++)
 {
  to[i] =  NF_RDDATA8();
 }
 
 NF_nFCE_H();
 
}
static void rLB_ReadPage(U32 addr, unsigned char * to)
{
 U32 i;
 
 rNF_Reset();
 
 //  Enable the chip
 NF_nFCE_L();  
 NF_CLEAR_RB();
 
 // Issue Read command
 NF_CMD(CMD_READ);
 
 //  Set up address
 NF_ADDR(0x00);
 NF_ADDR(0x00);
 NF_ADDR((addr) & 0xff);
 NF_ADDR((addr >> 8) & 0xff);
 NF_ADDR((addr >> 16) & 0xff);
 
 NF_CMD(CMD_READ3);
 
 NF_DETECT_RB();  // wait tR(max 12us)
 
 for (i = 0; i < 2048; i++)
 {
  to[i] =  NF_RDDATA8();
 }
 
 NF_nFCE_H();
 
}
 
It can be seen that they are all reset at the beginning. The difference lies in how the incoming address is converted and then paid to the NFADDR register each time. The specific method depends on the NAND data manual.
 
 Let's go back to the 2440init.s program, and then there is the following sentence:
 
ldr pc, =copy_proc_beg
 
We have seen the label copy_proc_beg appear many times before. The function of the code below this label is to copy the contents of nand flash to ram.
 
copy_proc_beg
 adr r0, ResetEntry
 ldr r2, BaseOfROM
 cmp r0, r2 // compare the two
 ldreq r0, TopOfROM //If they are the same, assign the end position of R0 to r0, which is also the starting position of RW.
 beq InitRam //If they are the same, jump to the position of this label.
 
 ldr r3, TopOfROM//The following code is for the copy method when the code is in NOR FLASH.
 ldmia r0!, {r4-r7}
 stmia r2!, {r4-r7}
 cmp r2, r3
 bcc %B0 //The function of these codes is to move the contents of ResetEntry to BaseOfROM (the starting position of R0, which is declared later).
 
 sub r2, r2, r3
 sub r0, r0, r2 //Here, the position of ResetEntry is moved down to prepare for the subsequent data copy.  
  
InitRam 
 ldr r2, BaseOfBSS
 ldr r3, BaseOfZero 
0
 cmp r2, r3
 ldrcc r1, [r0], #4
 strcc r1, [r2], #4
 bcc %B0 //It can be seen that this section copies the data defined in ResetEntry to the RW segment.
 
 mov r0, #0
 ldr r3, EndOfBSS
 cmp r2, r3
 strcc r0, [r2], #4
 bcc %B1 //If there is extra space left after copying the data, fill it with 0
 
 ldr pc, =%F2  ;goto compiler address
2
 
 ldr r0,=HandleIRQ 
 ldr r1,=IsrIRQ 
 str r1,[r0]//These three statements clearly show that the storage unit of the HandleIRQ interrupt vector is assigned the address of the IsrIRQ label, so that when an IRQ interrupt occurs, it will go directly to the secondary table to confirm which specific interrupt occurred.
 
 
 
    [ :LNOT:THUMBCODE
   bl Main //At this point, we see that we have entered the MAIN function.
   b .
    ]
 
    [ THUMBCODE  ;for start-up code for Thumb mode
   orr lr,pc,#1
   bx lr
   CODE16
   bl Main //You can see that the above code indicates that if arm is in THUMBCODE instruction mode, the mode will be switched.
 
   b .
  CODE32
    ]
 
So far, we have analyzed the startup code of 2440init.s. If there are any errors, please point them out! Thank you!
Keywords:ARM2440 Reference address:Interpretation of ARM2440ddr.h file

Previous article:Design of a three-component measuring instrument for the ocean environment geomagnetic field based on ARM
Next article:Design of electronic let-off and take-up system based on ARM7 and CAN bus

Recommended ReadingLatest update time:2024-11-16 13:45

DDR Test--SDRAM Clock Analysis Case
Last weekend, I received a call from a friend, asking me what items should be tested if there is a problem with the memory? For this very common question, I habitually answered him to measure the memory clock and read and write timing first, and then ended the call. After a while, my friend called me again and told
[Test Measurement]
DDR Test--SDRAM Clock Analysis Case
Dedicated Driver Monitoring System ASIC with Image Signal Processor and DDR3 Memory
OmniVision Technologies, a world-leading developer of digital imaging solutions, released the OAX8000 before CES today. This AI-powered automotive ASIC is optimized for entry-level standalone driver monitoring systems (DMS). The OAX8000 uses a chip stacking architecture to provide on-chip DDR3 SDRAM memory (1GB) for t
[Mobile phone portable]
Dedicated Driver Monitoring System ASIC with Image Signal Processor and DDR3 Memory
Teledyne e2v's 8 GB DDR4 memory goes into space
Teledyne e2v’s new 8 GB DDR4 memory advances edge computing in space Ultra-compact elastic dynamic memory advances cutting-edge space programs and space-based communications, observation and science satellites 8 GB DDR4 Engineering Samples (EM) now available, Flight Films (FM) to be released in 2
[Embedded]
Teledyne e2v's 8 GB DDR4 memory goes into space
Crucial DDR5 4800MHz 16GX2 memory review: performance improved by over 60%
With the release of Intel Core 12th generation desktop processors, the Z690 chipset is the first to support the latest DDR5 memory. The new DDR5 memory frequency starts from 4800MHz and supports the latest XMP 3.0 technology, which can be overclocked with one click. For high-end enthusiasts, installing DDR5 memory i
[Embedded]
Crucial DDR5 4800MHz 16GX2 memory review: performance improved by over 60%
DDR Test Series 4 - Talking about DDR3
Introduction to DDR3 DDR3 (double-data-rate three synchronous dynamic random access memory) is a high-bandwidth parallel data bus used in the field of computers and electronic products. DDR3 is developed on the basis of DDR2, and its data transmission speed is twice that of DDR2. At the same time, the DDR3 standard ca
[Test Measurement]
DDR Test Series 4 - Talking about DDR3
Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
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号