UBOOT//DDR内存原理及时序

本文介绍了UBOOT在2012.10版本中的启动流程,涉及V210启动机制、GPIO输入输出电路分析以及DDR2内存的初始化代码。在启动过程中,CPU先运行IROM,然后加载BL1到内存中,最后运行OS。GPIO讲解了上拉电阻和推挽级输出的工作原理。在DDR2内存部分,解释了其基本原理和读写时序,并分析了内存初始化的四个步骤,包括物理层配置、PHY和DLL初始化、内存控制器设置以及device芯片初始化。此外,讨论了内存地址排列的两种模式:顺序模式和交叉模式。
部署运行你感兴趣的模型镜像

这里使用的是2012.10版本的uboot ,来看一下如何将uboot 改为自己开发板可以使用的

第四阶段22课开始UBOOT完全理解课程

Uboot的异常向量表,V210的启动机制原理

在这里插入图片描述
上图是启动uboot的一段汇编指令,其中ldr pc,XXX //表示把XX寄存器中的地址值给pc指针
在这里插入图片描述
CPU启动过程,首先运行IROM(里面主要是配置时钟,看门狗等),然后把flash/SD卡中的头4K代码(BL1)放到CPU里运行,然后将flash/SD卡中剩下的内容加载到SDRAM中运行,然后通过调节指针最终运行OS

不同板子启动步骤不一样,有的是将BL1与BL2都放到CPU中运行

pv210中的UBOOT版本会先把一个叫做 uboot_spl 的很小的文件放到片内sram中运行,然后再将后面的uboot放到sdram中

cpsr寄存器设置,
用mrs 取出来 cpsr中的数,然后用bic orr两个指令来清零和置一,然后在把取出来的数放回去

cash 高速缓存,会缓存某些数据,然后在运行代码时会去cash 里面找是否有这个数据,如果没有这个数据再去内存找

GPIO输入输出电路分析

上拉电阻: 一般外面的输入设备都是用一个三极管或者MOS管,用开集或开漏的方式。 发射极接地,基级接通,三极管导通给到引脚低电平。三极管不导通的时候给到的单片机的电平就是上拉电阻上接的电平,这种设计可以将输入电平的大小交给外围设计者去做,上拉电阻可以接1.8 3 或5V 任意的VCC

推挽级输出:使用一对互补的NPN加PNP
在这里插入图片描述
当基极为高电平,上边的管子导通,输出为高电平,基极为低电平,下边的pnp导通,输出为低电平

大小端模式

小端:低位放到低地址
在内存中表示没问题(内存低地址在下高地址在上),但是在硬盘中 表示出来就是 相反的
比如 ea000014 硬盘中是从低位到高位,然后形成一个扇区,因此在硬盘中显示为14 00 00 ea 为什么14反过来不是41呢, 因为一个数字用4位二进制表示,14是一个字节表示,字节是不能反过来的。因为一个地址对应的一个字节。

小端用硬盘里打开就不太符合我们的阅读习惯,因此有了大端模式

大端:高位放到低地址
与小端相反 给、

编译,链接、汇编

预编译:precompile 展开头文件和宏定义
编译:conpile main.c变成main.s
汇编 assembly main.s变成main.o
链接:link 把各个.o 文件拼接起来,把实际的地址值都装进去,变成一个不带后缀的main文件(ELF文件)此文件可以在linux中运行了,但是不能再板子上运行,因为有乱七八糟的调试文件等,不是纯净的二进制文件

生成二进制文件 objdump 把main(把无用的文件剥离)变成main.bin
上面5个步骤统称为宏观的编译

linux中如何复制
从A文件复制到B文件
1、打开A文件, 输入一个任起的变量名(要单个字符 )ABCD或者0-9的数字 然后输入行数在输入一个yy, 从光标出开始N行
例如 “a3yy 从当前光标行数开始的三行
2、打开B 输入刚刚的变量名然后+p
“ap

文件链接
.o文件一般包含三个段
第一个是.text 代码 段 第二个是.data已经初始化的全局变量 第三个是.bss段未被初始化,系统自动设为零的变量

lds文件
每一个链接过程都由链接脚本(linker script, 一般以lds作为文件的后缀名)控制. 链接脚本主要用于规定如何把输入文件内的section放入输出文件内, 并控制输出文件内各部分在程序地址空间内的布局.
链接器把一个或多个输入文件合成一个输出文件.
输入文件: 目标文件或链接脚本文件.
输出文件: 目标文件或可执行文件.

书写格式

SECTIONS
{
		. = 0X0;   // 点=  第一句语句在哪个位置开始 一般是0x0,具体看芯片,如果的有芯片sram起始地址不是0x0就改成相应的地址
		.text :{
						mystart.o     /说明mystart.o的text段要放在最前面
						*(.text)                                              //星号代表后面所有文件
					}
	.data :{
					*(.data)          //data段没有什么要求,直接就都放在一起
			}
	.bss_start = .;            bss段在别的文件里可能会用到。所以要先声明一下
	.bss :{
				*(.bss)
			}
	.bss_end = .;          使用start和end声明 链接时会给外一个标号,在代码里可以用的
}

然后用
arm-linux-ld -Tmyboot.lds -o myboot mystart.o mylowlevel_init.o
来生成文件

makefile
书写格式是
目标: 依赖
命令
因为makefile只会执行第一个,因此要做一个伪目标all,然后在一次完成它的依赖文件
例如:
all : main.o build.o
gcc -o mian mian.o build.o
main.o:mian.c
gcc -c main.c
build.o:build.c
gcc -c build.c‘

这样就可以执行所有的命令了。
如果
all : main.o build.o clear
gcc -o mian mian.o build.o
main.o:mian.c
gcc -c main.c
build.o:build.c
gcc -c build.c
clear:
rm main.o build.o
这样运行makefile会发现两个文件并没有被删除,因为all里面的clear并没有任何依赖,所以一开始就直接执行了。要在clear前面加上一个.phony做成伪命令

如果依赖文件更新时间比目标晚,才会执行命令

自动化变量
$@ 所有的目标集合
$< 所有的依赖文件中的第一个文件,模式匹配中则是所有的依赖文件
$^ 所有依赖文件的集合
模式匹配

%.o 当前目录下所有的.o文件
%.s 当前目录下所有的.s文件

makefile中最好用:= 不要用= 因为makefile 会去一直寻找到底在回来赋值
如A=B B=C makefile执行时看到A=B不会立即赋值,而是找B的关系,将B=C执行完在执行A=B
:=可以直接赋值


cc:= gcc
下面就可以使用$(cc)来代替GCC

UART初始化与异步通信原理

同步通信SPI 一般在芯片内部用,因为需要引进一个时钟信号,因此不能远距离传输。
波特率是调制速率,模拟线路信号的速率,以波形每秒震荡次数来衡量,如果数据不压缩,波特率等于没秒钟传输的数据单位,bit/s。和比特率不同,因为传输时需要一个起始位和停止位,换算成字节应该是bps/10

数据位:7或8位(7位是因为当时多用于调制解调器,当时7位就可以表示一个ascll码)
校验位:奇偶校验位,每一字节外又额外增加了一位用来
停止位:可以是1位、1.5位、2位

DDR2 SDRAM 基本原理

Double Data Rate Synchronous Dynamic Random Access Memory

动态电容保持一个位用一个电容
静态内存则需要4个晶体管

在这里插入图片描述

内存里面一个单元是由一个MOS管和一个电容组成,
读出时,导通横向的wordline ,mos管导通,从bitline中读,如果是高电平则是1,低电平则是0
如果是写,就说从bitline中导入高电平或者低电平

从列中选出来保存在 sense amps 再存到 DATA BUFFFER 每次只能读取一个位。所以8个芯片叠在一起,每次输出的就是一个字节
在这里插入图片描述

8个叠在一起叫做一个bank
在这里插入图片描述

一片内存条一般有两个rank 也就是通道

一个device 可以输出8位(取决于BANk,每次只输出1个bank),4个组成一个rank就可以一次输出32位数据
但是他们地址总线是统一的,因此,一个地址可以从四块device中取出数据。

比如 内存是1Gbit 可以组织成32Mbit(寻址范围为32Mbit) * 4I/O(4 个位同时输入输出.4个array组成一个bank)*8bank(8bank组成一个device)

读写操作的时序

在这里插入图片描述

先拉低行地址的控制信号,行然后锁存解析,然后再把列地址的地址锁存信号拉低 然后分析列地址,因为把行列地址分开传输因此,用了14根地址线就可以

因为行列地址分开,可寻址范围为 2的14次方乘2的14次方乘2的平方(因为是用了4块芯片device组成的rank)可寻址范围为2的30次方一个G

DDR的时序
读过程
在这里插入图片描述
写过程
在这里插入图片描述
tcwd 命令发布到总线上输出数据间隔的时间
row acc 行激活
行激活之后才是别的命令,是读是写,下面是一些重要参数
t_refi average periodic refresh interval 平均刷新间隔
t_rfc refresh cycle time 刷新周期时间 每完成一次行刷新所需时间,一般一次是刷新两个行
t_rrd row activation to row activation delay 行激活到行激活延迟(这个bank和下个bank行激活命令之间的间隔)
t_rp row orecharge (预充电时间)行预充电时间
t_rcd row to column command delay 行激活到真正的输入列命令的延迟时间(激活bank后等待的时间,等待完成才能发布列写入命令,但是可以提前放入指令)
t_rc row cycle 行激活到完成的时间 行的整个完整的循环 (t_ras+t_rp)
t_ras row access strone 从行命令执行完再到数据从bank读完之后在冲回到电容的一整个过程 (行执行的过程)
t_wtr write to read delay time 写到读命令的延迟时间
t_wr write recovery time 写命令恢复时间 (即将数据存到电容里的时间)
t_rtp read to precharge 读后预充电 从AL过后必须大于RTP个时钟周期才能进行预充电
t_cl(t_cas) colmn access strobe latency 列命令写入后的延迟,之后才会真正从总线输出数据
t_faw four active window 四个运行窗口(因为bank太耗电,一次最多激活4个) 如果已经打开了4个bank想打开第五个bank时所需要间隔的时间
t_al added latency to column access 附加延迟在输入列命令前
t_rl(读延迟) t_rl = t_al(附件延迟)+t_cl(列延迟)
t_wl (写延迟) t_wl = t_rl -1

t_burst 输出数据的位数 就是BL

post技术,可以提前发布指令从到寄存器中,然后到合适的时间在传到内存中
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
附加延迟结束可以再加一个读命令。

在这里插入图片描述

refresh 刷新命令
每过一段时间会打开行对里面的电容进行充电来保存数据,否则数据会丢失。
刷新时序
在这里插入图片描述

DDR2初始化代码分析

因为某种原因,原版代码只是支持256M内存(可能因为我看的视频太久远)
大概分为4个步骤
1、对物理层的配置,管脚驱动输出强度
2、初始化PHY (memory controller的物理层)和DLL(延时锁环)
3、初始化内存控制器(包括一些芯片的时序,预充电的规则等)
4、初始化device芯片

有的芯片手册会告诉你内存需要配置什么

关于内存地址排列顺序
在这里插入图片描述
第一种是先按宽度(几个I/O线)然后在列,行,bank 顺序模式
第二种是先按宽度(几个I/O线)然后在列,bank,行 交叉模式
区别就是,地址0开始,都是从第一行一次排,当这一行用完第一种是在下一行地址继续,而第二种会在下一个bank的第一行地址继续
这个位决定了你可用内存为多少(可寻址范围)因为之前的初始化程序定的是256M所以这一位如果设置不正确,就无法跑满内存
在这里插入图片描述

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值