电脑蓝屏显示0xc 000014怎么解决,电脑蓝屏0xc000014c怎么处理

首页 > 实用技巧 > 作者:YD1662023-11-05 22:42:06

FCLK与Fin的倍数通过MPLLCON寄存器设置,三者之间有以下关系: MPLL(FCLK) = (2 * m * Fin)/(p*2^s) 其中:m = MDIV 8, p = PDIV 2, s = SDIV   PLL配置寄存器如图:

电脑蓝屏显示0xc 000014怎么解决,电脑蓝屏0xc000014c怎么处理(5)

当设置完MPLL之后,就会自动进入LockTime变频锁定期间,LOCKTIME之后,MPLL输出稳定时钟频率。 FCLK、HCLK、PCLK的设置比例如图:

电脑蓝屏显示0xc 000014怎么解决,电脑蓝屏0xc000014c怎么处理(6)

电脑蓝屏显示0xc 000014怎么解决,电脑蓝屏0xc000014c怎么处理(7)

如果HDIV设置为非0,CPU的总线模式要进行改变,默认情况下FCLK = HCLK,CPU工作在fast bus mode快速总线模式下,HDIV设置为非0后, FCLK与HCLK不再相等,要将CPU改为asynchronous bus mod异步总线模式,可以通过下面的嵌入汇编代码实现:

__asm__( "mrc p15, 0, r1, c1, c0, 0\n" /* 读出控制寄存器 */ "orr r1, r1, #0xc0000000\n" /* 设置为“asynchronous bus mode” */ "mcr p15, 0, r1, c1, c0, 0\n" /* 写入控制寄存器 */ );为加载 Bootloader的第二阶段代码准备RAM空间(初始化内存空间)

lowlevel_init中设置相应BANK地址,主要用来设置SDRAM。内存是被映射在了0x30000000-0x40000000的位置,即bank6与bank7。那么在内存时序设置的时候,主要关心的,就是bank6与bank7。当然,bank0也是需要关注的,因为它是启动时,启动程序存放的位置。但是bank0是由OM[1:0],即板子上的那几个小开关中的两个来控制的,所以这里程序上是不用管它的。

SMRDATA: .long 0x22011110 //BWSCON .long 0x00000700 //BANKCON0 .long 0x00000700 //BANKCON1 .long 0x00000700 //BANKCON2 .long 0x00000700 //BANKCON3 .long 0x00000740 //BANKCON4 .long 0x00000700 //BANKCON5 .long 0x00018005 //BANKCON6 .long 0x00018005 //BANKCON7 .long 0x008C04F4 // REFRESH .long 0x000000B1 //BANKSIZE .long 0x00000030 //MRSRB6 .long 0x00000030 //MRSRB7

接下来设置栈地址指向NAND,准备初始化NANDFLASH。

ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)//等于0x30000f80 bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ bl nand_init_ll

初始化NANDFLASH,其中包括设置时序NFCONF,(参考芯片手册和2440手册设置nandflsh的启动时序)。TACLS表示的建立所用的时间,TWRPH0表示nWE写控制信号的持续时间,TWRPH1表示数据生效所用的时间,什么时候可以读数据。 最后就是使能NFCONT NAND Flash控制器,初始化ECC, 禁止片选。到这里,NANDFlash的初始化就完成了。下面就可以进行重定位了。

void nand_init_ll(void) { #define TACLS 0 #define TWRPH0 1 #define TWRPH1 0 /* 设置时序 */ NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4); /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */ NFCONT = (1<<4)|(1<<1)|(1<<0); }Bootloader的第二阶段代码到SDRAM空间中(重定位)

首先判断是NOR启动还是NAND启动,如果是NAND启动就直接拷贝数据。拷贝代码之前,要传递给拷贝函数三个参数,源,目的,长度。读取NAND的话要参考芯片手册的NAND读取数据的时序,选中NAND,发出读命令,发出地址,发出读命令,判断状态,读取数据,取消选中等。

bl copy_code_to_sdram bl clear_bss //清除bss段(参考自制uboot章节)

void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len) { int i = 0; /* 如果是NOR启动 */ if (isBootFromNorFlash()) { while (i < len) { dest[i] = src[i]; i ; } } else { //nand_init(); nand_read_ll((unsigned int)src, dest, len); } } void clear_bss(void) { extern int __bss_start, __bss_end__; int *p = &__bss_start; for (; p < &__bss_end__; p ) *p = 0; }

最后要清除bss。bss段不占用空间,都是未初始化的全局变量或者已经初始化为零的变量,本来就是零,直接清零就好。不清零的话未初始化的变量可能会存在未知的数值。

设置好栈

设置栈跳转到SDRAM执行。

ldr pc,=call_board_init_f //绝对跳转,跳到SDRAM上执行跳转到第二阶段代码的C入口点

跳转到SDRAM执行剩下的程序。

call_board_init_f: .globl base_sp base_sp: .long 0 ldr r0,=0x00000000 bl board_init_f /*unsigned int id 的值存在r0中,正好给board_init_r使用*/ ldr r1, =_TEXT_BASE /*重新设置栈到之前的位置 指向原来addr_sp = 128;*/ ldr sp,base_sp /*调用第二阶段代码*/ bl board_init_rBootloader第二阶段的功能初始化本阶段要使用到的硬件设备

为了方便开发,至少要初始化一个串口以便程序员与 Bootloader进行交互。

检测系统内存映射( memory map)

所谓检测内存映射,就是确定板上使用了多少内存、它们的地址空间是什么。由于嵌入式开发中 Bootloader多是针对某类板子进行编写,所以可以根据板子的情况直接设置,不需要考虑可以适用于各类情况的复杂算法。

将内核映象和根文件系统映象从 Flash上读到SDRAM空间中

Flash上的内核映象有可能是经过压缩的,在读到SDRAM之后,还需要进行解压。当然,对于有自解压功能的内核,不需要 Bootloader来解压。将根文件系统映象复制到SDRAM中,这不是必需的。这取决于是什么类型的根文件系统以及内核访问它的方法。

将内核存放在适当的位置后,直接跳到它的入口点即可调用内核。调用内核之前,下列条件要满足: (1)CPU寄存器的设置   R0=0(规定)。   R1=机器类型ID;对于ARM结构的CPU,其机器类型ID可以参见 linux/arch/arm tools/ mach-types   R2=启动参数标记列表在RAM中起始基地址(下面会详细介绍如何传递参数)。 (2)CPU工作模式   必须禁止中断(IRQ和FIQ,uboot启动是一个完整的过程,没有必要也不能被打断)   CPU必须为SVC模式(为什么呢?主要是像异常模式、用户模式都不合适。具体深入的原因自己可以查下资料)。 (3) Cache和MMU的设置   MMU必须关闭。   指令 Cache可以打开也可以关闭。   数据 Cache必须关闭。

为内核设置启动参数

Bootloader与内核的交互是单向的, Bootloader将各类参数传给内核。由于它们不能同时行,传递办法只有一个:Bootloader将参数放在某个约定的地方之后,再启动内核,内核启动后从这个地方获得参数

除了约定好参数存放的地址外,还要规定参数的结构。Linu2.4x以后的内核都期望以标记列表( tagged_list)的形式来传递启动参数。标记,就是一种数据结构;标记列表,就是挨着存放的多个标记。标记列表以标记 ATAG CORE开始,以标记 ATAG NONE结束。

标记的数据结构为tag,它由一个 tag_header结构和一个联合(union)组成。 tag_ header结构表小标记的类型及长度,比如是表示内存还是表示命令行参数等。对于不同类型的标记使用不同的联合(union),比如表示内存时使用 tag_mem32,表示命令行时使用 tag_cmdline。

bootloader与内核约定的参数地址,设置内存的起始地址和大小,指定根文件系统在那个分区,系统启动后执行的第一个程序linuxrc,控制台ttySAC0等。

调用内核

调用内核就是uboot启动的最后一步了。到这里就uboot就完成了他的使命。

uboot启动内核详解

下面我们来展开说下uboot具体是如何调用内核的,引导内核启动的。

uboot与Linux内核之间的参数传递

我们知道,uboot启动后已经完成了基本的硬件初始化(如:内存、串口等),接下来它的主要任务就是加载Linux内核到开发板的内存,然后跳转到Linux内核所在的地址运行。

具体是如何跳转呢?做法很简单,直接修改PC寄存器的值为Linux内核所在的地址,这样CPU就会从Linux内核所在的地址去取指令,从而执行内核代码。

在前面我们已经知道,在跳转到内核以前,uboot需要做好以下三件事情:

(1) CPU寄存器的设置   R0=0。   R1=机器类型ID;对于ARM结构的CPU,其机器类型ID可以参见 linux/arch/arm tools/ mach-types   R2=启动参数标记列表在RAM中起始基地址。 (2) CPU工作模式   必须禁止中断(IRQs和FIQs)   CPU必须为SVC模式 (3) Cache和MMU的设置   MMU必须关闭   指令 Cache可以打开也可以关闭   数据 Cache必须关闭

其中上面第一步CPU寄存器的设置中,就是通过R0,R1,R2三个参数给内核传递参数的。(ATPCS规则可以参考)

为什么要给内核传递参数呢?

在此之前,uboot已经完成了硬件的初始化,可以说已经”适应了“这块开发板。然而,内核并不是对于所有的开发板都能完美适配的(如果适配了,可想而知这个内核有多庞大,又或者有新技术发明了,可以完美的适配各种开发板),此时对于开发板的环境一无所知。所以,要想启动Linux内核,uboot必须要给内核传递一些必要的信息来告诉内核当前所处的环境

如何给内核传递参数?

因此,uboot就把机器ID通过R1传递给内核,Linux内核运行的时候首先就从R1中读取机器ID来判断是否支持当前机器。这个机器ID实际上就是开发板CPU的ID,每个厂家生产出一款CPU的时候都会给它指定一个唯一的ID,大家可以到uboot源码的arch\arm\include\asm\mach-type.h文件中去查看。

电脑蓝屏显示0xc 000014怎么解决,电脑蓝屏0xc000014c怎么处理(8)

上一页123下一页

栏目热文

文档排行

本站推荐

Copyright © 2018 - 2021 www.yd166.com., All Rights Reserved.