ARM bare metal - detailed explanation of SD card brush startup principle

Posted by flash-genie on Wed, 05 Jan 2022 09:35:47 +0100

1. Difference between internal memory and external memory:

Memory: RAM(random access memory, characterized by arbitrary byte reading and writing, power loss).

External memory: ROM (read only memory, similar to Flash SD card, which is used to store things. It is not lost when power is off, and can not be accessed by random address. It can only be accessed in blocks).

2.SD card programming interface

The SD card is physically connected with the outside world by 9 pins, including 2 ground, 1 power supply and 6 signal wires.

3.SD protocol and SPI protocol

The SD card needs to be accessed according to a certain interface protocol (timing).

->SPI protocol:

SD card supports SPI protocol, which is a communication protocol widely used in single chip microcomputer. It is not specially invented for SD card. SPI protocol is relatively slow compared with SD protocol.

->SD protocol:

SD protocol is specially used to communicate with SD card. SD protocol requires SD controller in SoC. When running at high rate, the dominant frequency of SoC shall not be too low.

4.SD/MMC controller

In addition to the storage unit Flash, there is also an SD card management module in the SD card. When our SoC communicates with the SD card, we send commands, clocks, data and other information to the SD card management module through the 9-pin pin SD protocol / SPI protocol, and then return information from the SD card to the SoC for interaction. When working, each task (such as initializing SD card, reading a block, writing, erasing, etc.) needs a certain timing to complete.

5. Detailed explanation of SD card startup of s5pv210


First, after the CPU is powered on, first read the preset code (BL0) from the internal IROM, and first do some basic initialization (CPU clock, turn off the watchdog ···); then (BL0) will judge the startup mode we selected, and then read the first part of the startup code (BL1, size 16KB) from the corresponding external memory to the internal SRAM.
Second: run the BL1 (16KB) just read in the previous step, and then execute it. BL1 is responsible for initializing NandFlash, and then read BL2 to IRAM (the remaining 80KB) and run it.
Third: run BL2 from IRAM, BL2 initializes DRAM, then reads the OS into DRAM, then starts the OS, and the startup process ends.

The 210 has a built-in 96KB SRAM (called iRAM) and a built-in 64KB NorFlash (called iROM).

6.SD card startup process (when the bin file is less than 16KB and greater than 16KB)

The first case of startup: the entire image size is less than 16KB. At this time, it is equivalent to that my entire image is directly loaded and executed by steppingstone as BL1.

The second case of startup: the entire image size is greater than 16KB. (as long as it is larger than 16KB, even 17KB or 700MB is the same) at this time, the whole image should be divided into two parts: the first part is 16KB and the second part is the remaining size. Then, the first part starts as BL1, which is responsible for initializing DRAM and loading the second part into DRAM for execution (uboot does this).

7. Call device copy function with function pointer

Samsung has built some codes to initialize the external SD card / NandFlash in advance in iROM, and built-in codes to read various SD cards / NandFlash in iROM. BL0 reads BL1 in the external SD card / NandFlash by calling these device copy function s.

->Macro definition method.

// The first method: macro definition
#define CopySDMMCtoMem(z,a,b,c,e) (((bool(*)(int, unsigned int, unsigned short, unsigned int*, bool))(*((unsigned int *)0xD0037F98)))(z,a,b,c,e))

->Function pointer.

typedef unsigned int bool;
// The second method: call by function pointer
typedef bool(*pCopySDMMC2Mem)(int, unsigned int, unsigned short, unsigned int*, bool);


// In actual use
pCopySDMMC2Mem p1 = (pCopySDMMC2Mem)0xD0037F98;
p1(x, x, x, x, x);		// First call method
(*p1)(x, x, x, x, x);	// The second calling method
*p1(x, x, x, x, x);		// Error, because p1 combines with () first, not * first.

8. SD card startup practice of s5pv210

Our code is divided into two parts: the first part BL1 is less than or equal to 16KB, and the second part is of any size. After the iROM code is executed, BL1 will be automatically read from SD card and executed in SRAM; BL1 is responsible for initializing DDR during execution, then manually copy BL2 from SD card to the correct position in DDR, and then BL1 jumps far to BL2 to execute BL2

->Process BL1 first

To be completed in BL1: close the watchdog, set the stack, open iCache, initialize DDR, copy BL2 from SD card to a specific location in DDR, and jump to execute BL2

start.s:

sd_relocate.c:

- > reprocess BL2

Enter BL2 folder:

start.S:

.global _start					// Handle_ Change the start link attribute to external so that other files can see it_ Start
_start:

	ldr pc, =main				// ldr instruction to realize long jump
	
	
// The last loop of the assembly cannot be lost
	b .

 led.c: Simply used to test SD card startup

#define GPJ0CON		0xE0200240
#define GPJ0DAT		0xE0200244

#define rGPJ0CON	*((volatile unsigned int *)GPJ0CON)
#define rGPJ0DAT	*((volatile unsigned int *)GPJ0DAT)

void delay(void);

void led1(void)
{
	rGPJ0CON = 0x11111111;
	rGPJ0DAT = ((0<<3) | (1<<4) | (1<<5));
}

void led2(void)
{
	rGPJ0CON = 0x11111111;
	rGPJ0DAT = ((0<<3) | (0<<4) | (1<<5));
}

void led3(void)
{
	rGPJ0CON = 0x11111111;
	rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5));
}

// This function is to achieve the led flashing effect
void main(void)
{
	// led initialization, that is, set GPJ0CON to output mode
	//volatile unsigned int *p = (unsigned int *)GPJ0CON;
	//volatile unsigned int *p1 = (unsigned int *)GPJ0DAT;
	rGPJ0CON = 0x11111111;
	
	while (1)
	{
		// led on
		rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5));
		// delayed
		delay();
		// led off
		rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));
		// delayed
		delay();
	}
}


void delay(void)
{
	volatile unsigned int i = 900000;		// volatile tells the compiler not to optimize so that it can really reduce
	while (i--);							// To consume time and realize delay
}