S3C2440 Hardware Part 3: MMU

Publisher:冷漠之心Latest update time:2016-12-01 Source: eefocusKeywords:s3c2440 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

MMU: Memory Management Unit. Function:

(1) The mapping of virtual address to physical address makes each process have the same address space.

(2) Check memory access permissions (implemented by the hardware itself). Protect the memory used by each process from being destroyed by other processes.

 

In a 32-bit CPU, the virtual memory address is 0~0xFFFF_FFFF.

Cache: A high-speed cache memory between the main memory and the CPU.

 

Detailed code explanation: (refer to Brother Wei Dongshan's code)

(1) head.S

 

@****************************************************************************
@ File: head.S
@ Function: Set up SDRAM, copy the second part of the code to SDRAM, set up the page table, start the MMU,
@ then jump to SDRAM to continue execution
@******************************************************************** 

.text
.global _start
_start:
    ldr sp, =4096 @ Set the stack pointer. The following are all C functions. You need to set the stack before calling them
    bl disable_watch_dog @ Turn off WATCHDOG, otherwise the CPU will restart continuously
    bl memsetup @ Set up the memory controller to use SDRAM
    bl copy_2th_to_sdram @ Copy the second part of the code to SDRAM
    bl create_page_table @ Set up the page table
    bl mmu_init @ Start the MMU
    ldr sp, =0xB4000000 @ Reset the stack pointer to point to the top of SDRAM (using virtual address)
    ldr pc, =0xB0004000 @ Jump to SDRAM and continue to execute the second part of the code
halt_loop:
    b halt_loop

(2)init.c

/*
 * init.c: do some initialization and run in Steppingstone
 * It belongs to the first part of the program with head.S. At this time, MMU is not enabled and physical addresses are used
 */ 

/* WATCHDOG register*/
#define WTCON (*(volatile unsigned long *)0x53000000)
/* Memory controller register starting address*/
#define MEM_CTL_BASE 0x48000000


/*
 * Turn off WATCHDOG, otherwise the CPU will restart continuously
 */
void disable_watch_dog(void)
{
    WTCON = 0; // Turning off WATCHDOG is very simple, just write 0 to this register

}

/*
 * Set up the memory controller to use SDRAM
 */
void memsetup(void)
{
    /* Values ​​of SDRAM 13 registers*/
    unsigned long const mem_cfg_val[]={ 0x22011110, //BWSCON

                                            0x00000700, //BANKCON0

                                            0x00000700, //BANKCON1

                                            0x00000700, //BANKCON2

                                            0x00000700, //BANKCON3 

                                            0x00000700, //BANKCON4

                                            0x00000700, //BANKCON5

                                            0x00018005, //BANKCON6

                                            0x00018005, //BANKCON7

                                            0x0 08C07A3, //REFRESH

                                            0x000000B1, //BANKSIZE

                                            0x00000030, //MRSRB6

                                            0x00000030, //MRSRB7

                                    };
    int i = 0;
    volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;
    for(; i < 13; i++)
        p[i] = mem_cfg_val[i];
}

/*
 * Copy the second part of the code to SDRAM
 */
void copy_2th_to_sdram(void)
{
    unsigned int *pdwSrc = (unsigned int *)2048;
    unsigned int *pdwDest = (unsigned int *)0x30004000;
    
    while (pdwSrc < (unsigned int *)4096)
    {
        *pdwDest = *pdwSrc;
        pdwDest++;
        pdwSrc++;
    }
}

/*
 * Set up the page table
 */
void create_page_table(void)
{

/* 
 * Some macro definitions for segment descriptors
 */ 
#define MMU_FULL_ACCESS (3 << 10) /* Access rights*/
#define MMU_DOMAIN (0 << 5) /* Which domain does it belong to*/
#define MMU_SPECIAL (1 << 4) /* must be 1 */
#define MMU_CACHEABLE (1 << 3) /* cacheable */
#define MMU_BUFFERABLE (1 << 2) /* bufferable */
#define MMU_SECTION (2) /* indicates this is a segment descriptor */
#define MMU_SECDESC (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | \
                             MMU_SECTION)
#define MMU_SECDESC_WB (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | \
                             MMU_CACHEABLE | MMU_BUFFERABLE | MMU_SECTION)
#define MMU_SECTION_SIZE 0x00100000

    unsigned long virtuladdr, physicaladdr;
    unsigned long *mmu_tlb_base = (unsigned long *)0x30000000;
    
    /*
     * The starting physical address of Steppingstone is 0, and the starting running address of the first part of the program is also 0.
     * In order to still run the first part of the program after turning on the MMU,
     * map the virtual addresses of 0 to 1M to the same physical address
     */
    virtuladdr = 0;
    physicaladdr = 0;
    *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \
                                            MMU_SECDESC_WB;

    /*
     * 0x56000000 is the starting physical address of the GPIO register.
     * The physical addresses of the two registers GPBCON and GPBDAT are 0x56000010 and 0x56000014.
     * In order to operate GPBCON and GPBDAT at addresses 0xA0000010 and 0xA0000014 in the second part of the program,
     * map the 1M virtual address space starting from 0xA0000000 to the 1M physical address space starting from 0x56000000
     */
    virtuladdr = 0xA0000000;
    physicaladdr = 0x56000000;
    *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \
                                            MMU_SECDESC;

    /*
     * The physical address range of SDRAM is 0x30000000~0x33FFFFFF,
     * Map the virtual address 0xB0000000~0xB3FFFFFF to the physical address 0x30000000~0x33FFFFFF,
     * a total of 64M, involving 64 segment descriptors
     */
    virtuladdr = 0xB0000000;
    physicaladdr = 0x30000000;
    while (virtuladdr < 0xB4000000)
    {
        *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \
                                                MMU_SECDESC_WB;
        virtuladdr += 0x100000;
        physicaladdr += 0x100000;
    }
}

/*
 * Start MMU
 */
void mmu_init(void)
{
    unsigned long ttb = 0x30000000;

__asm__(
    "mov r0, #0\n"
    "mcr p15, 0, r0, c7, c7, 0\n" /* invalidate ICaches and DCaches */
    
    "mcr p15, 0, r0, c7, c10, 4\n" /* drain write buffer on v4 */
    "mcr p15, 0, r0, c8, c7, 0\n" /* invalidate instruction and data TLB */
    
    "mov r4, %0\n" /* r4 = page table base address */
    "mcr p15, 0, r4, c2, c0, 0\n" /* set page table base register */
    
    "mvn r0, #0\n" 
    "mcr p15, 0, r0, c3, c0, 0\n" /* Set the domain access control register to 0xFFFFFFFF,
                                         * without performing permission check 
                                         */ 
    /* 
     * For the control register, first read its value, modify the bits of interest based on this,
     * and then write
     */
    "mrc p15, 0, r0, c1, c0, 0\n" /* Read the value of the control register*/
    
    /* The lower 16 bits of the control register mean: .RVI ..RS B... .CAM
     * R : Indicates the algorithm used when swapping out entries in the cache,
     0x00000000;      1 = High addresses = 0xFFFF0000      * I : 0 = Disable ICaches; 1 = Enable ICaches      * R, S : Used together with the descriptor in the page table to determine memory access permissions
     *      B : 0 = CPU is little endian; 1 = CPU is big endian      * C : 0 = Disable DCaches; 1 = Enable DCaches      * A : 0 = Do not perform address alignment check on data access; 1 = Perform address alignment check on data access      * M : 0 = Disable MMU; 1 = Enable MMU      */     /*       * Clear unneeded bits first, and reset them if needed later       */                                         /* .RVI ..RS B... .CAM */      "bic r0, r0, #0x3000\n" /* ..11 .... .... .... Clear V, I bits */     "bic r0, r0, #0x0300\n" /* .... ..11 .... .... Clear R, S bits */     "bic r0, r0, #0x0087\n" /* .... .... 1... .111 Clear B/C/A/M */     /*      * Set required bits      */     "orr r0, r0, #0x0002\n" /* .... .... .... ..1. Enable alignment check */     "orr r0, r0, #0x0004\n" /* .... .... .... .1.. Enable DCaches */     "orr r0, r0, #0x1000\n" /* ...1 .... .... .... Enable ICaches */     "orr r0, r0, #0x0001\n" /* .... .... .... ...1 Enable MMU */     "mcr p15, 0, r0, c1, c0, 0\n" /* Write the modified value to the control register */     : /* No output */     : "r" (ttb) ); }








    















    





(3) leds.c

/*
 * leds.c: Turn on 4 LEDs in a loop
 * This belongs to the second part of the program. At this time, MMU is turned on and virtual addresses are used
 */ 

#define GPFCON (*(volatile unsigned long *)0xA0000010) // Physical address 0x56000050

#define GPFDAT (*(volatile unsigned long *)0xA0000014) // Physical address 0x56000054



#define GPF0_out (1<<(0*2))
#define GPF1_out (1<<(1*2))
#define GPF2_out (1<<(2*2))
#define GPF3_out (1<<(3*2))

/*
 * There is a reason why the wait function is added with "static inline".
 * This allows the wait to be embedded in main when compiling leds.c, and there is only one function, main, in the compiled result.
 * So when linking, the address of the main function is the runtime loading address specified by the link file.
 * In the link file mmu.lds, the runtime loading address of leds.o is specified as 0xB4004000.
 * In this way, "ldr pc, =0xB4004000" in head.S jumps to execute the main function.
 */
static inline void wait(unsigned long dly)
{
    for(; dly > 0; dly--);
}

int main(void)
{
    unsigned long i = 0;
    
    // Set the four pins GPB5/6/7/8 corresponding to LED1-4 as outputs

    GPFCON = GPF0_out|GPF1_out|GPF2_out|GPF3_out; 

    while(1){
       for(i=0;i<4;i++){
             GPFDAT = ~(1<             wait(30000);
         }

    }

    return 0;
}

(4)mmu.lds

SECTIONS { 
  first 0x00000000 : { head.o init.o }
  second 0xB0004000 : AT(2048) { leds.o }

 


(5) Makefile

objs := head.o init.o leds.o

mmu.bin : $(objs)
    arm-linux-ld -Tmmu.lds -o mmu_elf $^
    arm-linux-objcopy -O binary -S mmu_elf $@
    arm-linux -objdump -D -m arm mmu_elf > mmu.dis
    
%.o:%.c
    arm-linux-gcc -Wall -O2 -c -o $@ $<

%.o:%.S
    arm-linux-gcc -Wall -O2 -c -o $@ $<

clean:
    rm -f mmu.bin mmu_elf mmu.dis *.o        
    



Keywords:s3c2440 Reference address:S3C2440 Hardware Part 3: MMU

Previous article:S3C2440 Hardware Part 4: NandFlash (1) Introduction
Next article:S3c2440 Hardware Part 2: SDRAM

Recommended ReadingLatest update time:2024-11-16 22:24

s3c2440 bare metal - nandflash programming - 2 - nand controller and access timing
How simple, nothing more than read, write and erase, like our nand data width 8bit, one cycle is more than enough. But the address is different, for example, this nandflash capacity is 256M = 2^28, then 28 data lines are needed to transmit in one cycle, but the data bus width of this nandflash is only 8bit, there ar
[Microcontroller]
Design of ECG monitor based on Linux and MCU
  As people's pace of life accelerates and the population gradually ages, heart disease has become one of the major diseases that endanger human health and life. The ECG monitoring system provides an effective means for the diagnosis and treatment of heart disease patients, and is of great significance to the preventi
[Microcontroller]
Design of ECG monitor based on Linux and MCU
Design of free swing plate control system based on S3C2440 and acceleration sensor
The focus of this design is to collect the angle information of each joint through the acceleration sensor MMA7455, and control the operation of the stepper motor according to the obtained angle value and task requirements, complete the adjustment of the attitude of the flat plate at the end of the free swing arm, and
[Microcontroller]
Design of free swing plate control system based on S3C2440 and acceleration sensor
S3C2440 FCLK, HCLK, PCLK configuration
The FLCK value of the official wince system of Samsung is 400MHz, the HCLK value is 100MHz, and the PCLK value is 50MHz. So how are these values ​​calculated? The general process is as follows: these values ​​are multiplied to the core frequency we need, such as 400MHz, based on the external crystal oscillator 12MHz
[Microcontroller]
S3C2440 FCLK, HCLK, PCLK configuration
S3C2440 bare metal ------- touch screen _ use timer to support long press
In the code we wrote earlier, the coordinates cannot be read when long pressing or sliding. Next, we use a timer to improve the code so that the coordinate values ​​can be read when long pressing or sliding. #include "../s3c2440_soc.h"   #define ADC_INT_BIT (10) #define TC_INT_BIT (9)   #define INT_ADC_TC (31)     /
[Microcontroller]
S3C2440 clock system
The default working main frequency of S3C2440 is 12MHz and 16.9344MHz, which is the frequency of our crystal oscillator. However, 12MHz crystal oscillator is more commonly used. Fin refers to the frequency of the crystal oscillator we connect. As we all know, the frequency of S3C2440 after power-on and normal operation
[Microcontroller]
S3C2440 clock system
ARM History 4 - LCD
    It has been 10 days since I last wrote about my journey. It was the National Day holiday, so I gave myself a few days off - I played some games, chess, etc.     In fact, it took a lot of time and brainpower to write the touch screen driver and understand the interrupt process in ARM. I will simply share the cond
[Microcontroller]
LCD display of ARM9 (S3C2440) - theoretical knowledge
      Today I would like to discuss the LCD display problem of S3C2440 with you. I hope you can give me more advice. If I say something wrong, I hope you can help me correct it in time so that I can increase my knowledge and not cause inconvenience to others' learning. Haha Let me first take a look at an article I f
[Microcontroller]
LCD display of ARM9 (S3C2440) - theoretical knowledge
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号