In the past few nights, I have been tossing the bare metal SD card boot of S3C6410. I don't want to use UBOOT. I am a hardware developer and I am very interested in the bottom layer. I don't like the ones that are already written, so I have been trying it myself. In fact, I tried SD card boot a long time ago, that is, after ARM11 is powered on, it will copy the 8KB starting from the 9th KB from the bottom of the SD card (the offset of 0x2400B from the bottom) to the internal SRAM for execution. This is relatively simple, but the code size is only 8K, which cannot be played like STM32. Therefore, I consulted relevant information and learned that the boot method is L0 loading L1, and L1 loading L2. In short, after power-on, the L0 code solidified in the S3C6410 is started, and the external memory such as NAND and SD card is loaded. The memory is mapped or copied to the internal SRAM. The code copied from the SD card or flash is called L1, which is the user's boot code. On the computer, it is equivalent to the boot code and BIOS of the hard disk primary partition. It is used to initialize the external clock and peripherals and start the system. This part of the code is only 8KB, so the work completed is limited. Therefore, this code can be used to complete the initialization and copy the operating system or larger code to the memory. This part of the code is L2. Only after L1 initializes the memory can the memory be used. Before that, the memory is only 8KB, which is the internal SRAM. When starting from the SD card, it is mapped to 0x0c000000. From NAND, it can be 0 or 0x0c000000.
Currently only L1 is implemented, no uboot is needed, just need to burn to the specified location of SD card, and the development board needs to be selected as SD card boot.
The startup code completes the operations of turning off the watchdog, initializing the clock, SDRAM memory, stack, VIC, interrupt, etc. (The startup code comes from the Internet)
INCLUDE S3C6410.inc
PRESERVE8
AREA Init, CODE, READONLY
STACK_BASEADDRESS EQU 0x0c000400;0x52000000
SVCStack EQU (STACK_BASEADDRESS); Management mode
UndefStack EQU (STACK_BASEADDRESS - 0x300); instruction termination mode
AbortStack EQU (STACK_BASEADDRESS - 0x300); data access termination mode
IRQStack EQU (STACK_BASEADDRESS - 0x200); interrupt mode
FIQStack EQU (STACK_BASEADDRESS - 0x100); Fast interrupt mode
;---------------------------
; CPSR Mode Bit Definition
;---------------------------
Mode_USR EQU (0x10)
Mode_FIQ EQU (0x11)
Mode_IRQ EQU (0x12)
Mode_SVC EQU (0x13)
Mode_ABT EQU (0x17)
Mode_UND EQU (0x1B)
Mode_SYS EQU (0x1F)
Mode_MASK EQU (0x1F)
NOINT EQU (0xC0)
I_Bit EQU (0x80)
F_Bit EQU (0x40)
;Exception handling function
;------------------------------------------------- --------------------------------------------------
IMPORT main
EXPORT ResetHandler
ResetHandler
ldr r0, =0x70000013; Base Addresses: 0x70000000, Size: 256 MB (0x13)
mcr p15,0,r0,c15,c2,4 ; Tell the CPU the base address and address space of the peripheral registers. Important
; Set to SVC mode
MRS R0,CPSR
BIC R0,R0,#0x1F
ORR R0,R0,#0xD3
MSR CPSR_cxsf,R0
; Unknown mode stack
mrs r0,cpsr
bic r0,r0,#Mode_MASK
orr r1,r0,#Mode_UND|NOINT
msr cpsr_cxsf,r1 ;UndefMode
ldr sp,=UndefStack
;Exception mode stack
orr r1,r0,#Mode_ABT|NOINT
msr cpsr_cxsf,r1 ;AbortMode
ldr sp,=AbortStack
;Interrupt mode stack
orr r1,r0,#Mode_IRQ|NOINT
msr cpsr_cxsf,r1 ;IRQMode
ldr sp,=IRQStack
; Manage mode stack
bic r0,r0,#Mode_MASK|NOINT
orr r1,r0,#Mode_SVC
msr cpsr_cxsf,r1 ;SVCMode
ldr sp,=SVCStack
; Disable watchdog
LDR R0,=rWTCON
LDR R1,=0x0
STR R1,[R0]
; Disable cache and mmu
LDR R0,=0x0
MRC p15,0,R0,c1,c0,0
LDR R1,=0xFFFF
BIC R0,R0,R1
MCR p15,0,R0,c1,c0,0
; Disable all interrupts
LDR R0,=rVIC0INTENCLEAR
LDR R1,=0xFFFFFFFF
STR R1,[R0]
LDR R0,=rVIC1INTENCLEAR
LDR R1,=0xFFFFFFFF
STR R1,[R0]
;------------------------------------------------- --------------------------------------------------
; Set the clock source
LDR R0,=rOTHERS
LDR R1,[R0]
ORR R1,R1,#(1<<6)
LDR R0,=rCLK_SRC
LDR R1,=(1<<13)|7
STR R1,[R0]
LDR R0,=rCLK_SRC2
LDR R1,=0x0
STR R1,[R0]
; Set the clock division
LDR R0,=rCLK_DIV0
LDR R1,=0x01043310
STR R1,[R0]
LDR R0,=rCLK_DIV1
LDR R1,=0x0
STR R1,[R0]
LDR R0,=rCLK_DIV2
LDR R1,=3<<16
STR R1,[R0]
; Enable clock
LDR R0,=rHCLK_GATE
LDR R1,=0xFFFFFFFF
STR R1,[R0]
LDR R0,=rPCLK_GATE
STR R1,[R0]
LDR R0,=rSCLK_GATE
STR R1,[R0]
; Set the system clock
; Set APLL 532MHz
LDR R0,=rAPLL_LOCK
LDR R1,=0xFFFF
STR R1,[R0]
LDR R0,=rAPLL_CON
LDR R1,=(1<<31)|(266<<16)|(3<<8)|(1)
STR R1,[R0]
; Set MPLL 532MHz
LDR R0,=rMPLL_LOCK
LDR R1,=0xFFFF
STR R1,[R0]
LDR R0,=rMPLL_CON
LDR R1,=(1<<31)|(266<<16)|(3<<8)|(1)
STR R1,[R0]
; Set EPLL 96MHz
LDR R0,=rEPLL_LOCK
LDR R1,=0xFFFF
STR R1,[R0]
LDR R0,=rEPLL_CON0
LDR R1,=(1<<31)|(32<<16)|(1<<8)|(2)
STR R1,[R0]
LDR R0,=rEPLL_CON1
LDR R1,=0x0
STR R1,[R0]
;=================
;Select synchronous working mode
;=================
ldr r4, =rOTHERS
ldr r5, [r4]
bic r5, r5, #0xC0
orr r5, r5, #0x40 ; SyncReq = Async, SyncMUX = Sync
str r5, [r4]
_wait_for_async ; confirm that the work is in synchronous mode
ldr r5, [r4] ; Read OTHERS
and r5, r5, #0xF00 ; Wait SYNCMODEACK = 0x0
cmp r5, #0x0
bne _wait_for_async
ldr r4, =rOTHERS
ldr r5, [r4]
bic r5, r5, #0x40 ;SyncMUX = Async
str r5, [r4]
nop
nop
nop
nop
nop
;------------------------------------------------- --------------------------------------------------
; Set up DRAM
LDR R0,=0x7E00F120
LDR R1,=0xD
STR R1,[R0]
LDR R0,=rP1MEMCCMD
LDR R1,=0x4
STR R1,[R0]
LDR R0,=rP1REFRESH
LDR R1,=0x40D
STR R1,[R0]
LDR R0,=rP1CASLAT
LDR R1,=0x6
STR R1,[R0]
LDR R0,=rP1T_DQSS
LDR R1,=0x1
STR R1,[R0]
LDR R0,=rP1T_MRD
LDR R1,=0x2
STR R1,[R0]
LDR R0,=rP1T_RAS
LDR R1,=0x6
STR R1,[R0]
LDR R0,=rP1T_RC
LDR R1,=0xA
STR R1,[R0]
LDR R0,=rP1T_RCD
LDR R1,=0xB
STR R1,[R0]
LDR R0,=rP1T_RFC
LDR R1,=0x10B
STR R1,[R0]
LDR R0,=rP1T_RP
LDR R1,=0xB
STR R1,[R0]
LDR R0,=rP1T_RRD
LDR R1,=0x2
STR R1,[R0]
LDR R0,=rP1T_WR
LDR R1,=0x2
STR R1,[R0]
LDR R0,=rP1T_WTR
LDR R1,=0x2
STR R1,[R0]
LDR R0,=rP1T_XP
LDR R1,=0x2
STR R1,[R0]
LDR R0,=rP1T_XSR
LDR R1,=0x10
STR R1,[R0]
LDR R0,=rP1T_ESR
LDR R1,=0x10
STR R1,[R0]
LDR R0,=rP1MEMCFG
LDR R1,=0x1001A
STR R1,[R0]
LDR R0,=rP1MEMCFG2
LDR R1,=0xB45
STR R1,[R0]
LDR R0,=rP1_chip_0_cfg
LDR R1,=0x150F0
STR R1,[R0]
LDR R0,=rP1_user_cfg
LDR R1,=0x0
STR R1,[R0]
LDR R0,=rP1_DIRECTCMD
LDR R1,=0xC0000
STR R1,[R0]
LDR R0,=rP1_DIRECTCMD
LDR R1,=0x00000
STR R1,[R0]
LDR R0,=rP1_DIRECTCMD
LDR R1,=0x40000
STR R1,[R0]
STR R1,[R0]
LDR R0,=rP1_DIRECTCMD
LDR R1,=0xA0000
STR R1,[R0]
LDR R0,=rP1_DIRECTCMD
LDR R1,=0x80032
STR R1,[R0]
LDR R0,=rP1MEMCCMD
LDR R1,=0x0
STR R1,[R0]
LDR R0,=rP1MEMSTAT
DRAM_WAIT
LDR R1,[R0]
AND R1,R1,#0x3
CMP R1,#0x1
BNE DRAM_WAIT
;------------------------------------------------- --------------------------------------------------
; Set up the stack
;STACK_TOP EQU 0x52000000;0x0c000400
; LDR SP,=STACK_TOP
;------------------------------------------------- --------------------------------------------------
; Enable VIC
mrc p15,0,r0,c1,c0,0
orr r0,r0,#(1<<24)
mcr p15,0,r0,c1,c0,0
;------------------------------------------------- --------------------------------------------------
; Enable VFP
MRC p15, 0, r0, c1, c0, 2
ORR r0, r0, #0x00F00000
MCR p15, 0, r0, c1, c0, 2
MOV r1, #0
MCR p15, 0, r1, c7, c5, 4
MOV r0,#0x40000000
FMXR FPEXC, r0; FPEXC = r0
nop
nop
;------------------------------------------------- --------------------------------------------------
LDR R0,=rGPMCON
LDR R1,=0x11111
STR R1,[R0]
LDR R0,=rGPMPUD
LDR R1,=0x0
STR R1,[R0]
LDR R0,=rGPMDAT
LDR R1,=0
STR R1,[R0]
B main
END
//Main function
#include "system.h"
#include "uart.h"
#include "other.h"
#include "SDCARD.h"
//Simple delay
void Delay_Ms(u32 n)
{
u32 i;
while(n --)
{
for(i = 0;i < 0xfff;i ++)
{
nop;
}
}
}
// Jump to the specified location to execute
__asm jump()
{
LDR PC,=0x52000000;
}
//Key detection
bool Key_Test(void)
{
static u8 i = 0;
if((rGPNDAT & 0x3f) != 0x3f )
{
i++;
if(i > 10)
{
i = 0;
return TRUE;
}
}
return FALSE;
}
//Main function
int main(void)
{
u16 n = 0;
u32 cnt1 = 0, cnt2 = 0;
LED_Init(); //Initialize LED
UART0_Init(ENABLE,115200); //Initialize the serial port
UARTx_SetRxBuff(UART_CH0, (u8 *)0x52000000, 1024*1024*10); //Set the serial port receive buffer
rGPNCON = 0; //Initialize the button
UART0_SendString("SD BOOT started successfully!\r\n");
Delay_Ms(100);
//The button is not pressed to load the program from the SD card
if((rGPNDAT & 0x3f) == 0x3f)
{
Delay_Ms(10);
if((rGPNDAT & 0x3f) == 0x3f )
{
if(SD_Init() == SD_OK)
{
UART0_SendString("SD card initialization successful!\r\n");
if(SD_ReadMultiBlocks(1621032, (u32 *)0x52000000, 1000) == SD_OK)
{
UART0_SendString("Successfully read program from SD card, start execution from 0x52000000!\r\n");
jump(); //jump
}
else
{
UART0_SendString("Failed to read program from SD card!\r\n");
LED0_FLASH();
}
}
else
{
UART0_SendString("SD card initialization failed!\r\n");
}
}
}
while((rGPNDAT & 0x3f) != 0x3f); //Wait for the button to be released
Delay_Ms(100);
// Load the program from the serial port
UART0_SendString("Please send code from the serial port!\r\n");
while(1)
{
n++;
if(n == 300)
{
LED1_FLASH();
n = 0;
cnt1 = cnt2;
cnt2 = UARTx_GetRxCnt(UART_CH0);
if(cnt1!=cnt2)
{
LED2_FLASH();
}
else if(cnt2 == 0)
{
//UART0_SendString("Please send code from the serial port!\r\n");
LED3_FLASH();
}
}
if(Key_Test() == TRUE)
{
//Test to check memory
*((vu32 *)0x59000000) = 0xa55aaa55;
*((vu32 *)0x59000000)+=1;
if(*((vu32 *)0x59000000) == (0xa55aaa55+1))
{
UART0_SendString("Memory 0x59000000 is checked correctly!\r\n");
}
else
{
UART0_SendString("Memory 0x59000000 error!\r\n");
}
//Test to check memory
*((vu32 *)0x54000000) = 0xaa5aaa55;
*((vu32 *)0x54000000)-=1;
if(*((vu32 *)0x54000000) == (0xaa5aaa55-1))
{
UART0_SendString("Memory 0x54000000 is checked correctly!\r\n");
}
else
{
UART0_SendString("Memory 0x54000000 error!\r\n");
}
UART0_SendString("Sending completed, start execution from 0x52000000!\r\n");
jump(); //jump
}
Delay_Ms(1);
}
}
if(SD_ReadMultiBlocks(1621032, (u32 *)0x52000000, 1000)
When no key is pressed, a comparison program is loaded from the specified location of the SD card for execution, which can be an operating system or your own bare metal program.
1621032: The location of the program in the SD card. Note that it is the physical sector, not the logical sector. The physical sector is the sector address that the bare metal code you wrote can read, such as 1, 2, etc. The logical sector is the sector provided by the file system. The two locations are different, so pay attention.
0x52000000 The location where the program starts should be specified during compilation, usually in SDRAM.
1000: The number of sectors to be loaded. Each sector is 512B in size, so my program loads 512KB.
1. Download the program using the serial port
After you are ready, download the program from the serial port. Press and hold any button, except RESET, to use the serial port to download the program. The baud rate is 115200. I use the OK6410 development board, so the button detection is if((rGPNDAT & 0x3f) != 0x3f );
After startup, use the serial port to send bin
After sending, press any button (except reset) to start execution
You can see that the program has started to execute. At the beginning, I used the serial port to download the program. After a while, the CPU would die. I had to toss and turn for an afternoon. Finally, I found that the CPU main frequency was too high. It was initialized to 633MHZ, and the result was unstable. Now it is 533MHZ, which is more stable.
2. I have put the big program to be started in the specified location of the SD card. Just reset it and do not press any button to load it. Later, an interface will be made to choose which program to start, just like flashing the SD card of an Android phone, you can choose the startup program.
3. How to write the boot program to the SD card
Writing is relatively simple, see the picture below
First use a hexadecimal editor to open the disk, it must be a physical disk
Specify the offset to the last 0x2400B. Note: 4G and above cards are not at this position. Go to Baidu.
Note the options in the box
Open the SD_BOOT bin file, select all, and copy
Switch to the specified location of the SD card
Right click -> Edit -> Clipboard Data -> Write
Be sure to start writing at the specified sector, and don't forget to save after writing.
Another program that needs to be started can also use this tool to check its location
Pay attention to the physical sector number
Mainly because the file system cannot be added to the 8K code, if this code is started, there will be no restrictions, and interfaces and other things can be added. Later, the L2 code will be improved to achieve more convenient functions.
Attached is the project RVDS4.0 settings
L1 code settings
In order to reduce the code size, the optimization level should be set higher, and the lowest level can be used for normal testing.
L2 Code Engineering
Other location settings are the same
Attached project download location: http://download.csdn.net/detail/cp1300/6694183
I use RVDS4.0. If you want to download or use it, you can read my blog post, which details the installation and settings of RVDS4.0.
http://blog.csdn.net/cp1300/article/details/7772645 //Installation
http://blog.csdn.net/cp1300/article/details/7772809 //Create a project
http://blog.csdn.net/cp1300/article/details/8164042 //Debugging
http://blog.csdn.net/cp1300/article/details/8237076 //Debug patch
Previous article:STM32 CRC register operation
Next article:Mini2440 bare metal MMU experiment
Recommended ReadingLatest update time:2024-11-17 04:24
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- Rambus Launches Industry's First HBM 4 Controller IP: What Are the Technical Details Behind It?
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- Allegro Ali Dog Drawing Board. I haven't drawn on the drawing board for a long time.
- BMW Night Vision (Infrared Thermal Imaging) Camera Disassembly
- stm32 usb cdc communication
- [ATmega4809 Curiosity Nano Review] Unboxing
- How to burn MSBL format firmware
- Application of large color serial port screen in non-contact infrared thermometer
- The Hardships of Engineers——Comics | How to drive an engineer crazy?
- [RISC-V MCU CH32V103 Review] Reinterpretation of USB read and write functions
- When using the MINI USB connector to power the board, are D+D- short-circuited or floating?
- Single Voltage Reference vs. Dual Voltage Reference - II