IMX6ULL笔记
一,裸机篇
- 硬件启动方式选择
- 启动方式选择
LED灯实验,是从SD卡读取bin文件并启动,说明6UL支持从SD卡启动。6ULL支持多种启动方式。
6ULL是怎么支持从多种外置flash启动程序的
- 启动方式选择
BOOT_MODE0和BOOT_MODE1,这两个是两个IO来控制的。选择从USB启动还是内部BOOT启动。如果要烧写系统到开发置存储中。烧写完成设置从内部BOOT启动,然后从相应的外置版中可以选择从USB下载,下载到SD卡,EMMC,NADN等外存储中启动。
- 启动设备的选择
前提是设置MODE1和MODE0是从内部BOOT启动的,也就是MODE1=1,MODE=0。
支持的设备有:
NOR Flash,oneNAND,NAND Flash,QSPI Flash,SD/EMMC,EEPROM。我们常用的就是NAND,SD,EMMC甚至QSPI Flash
如何选择启动设备:
通过BOOT_CFG来选择,有BOOT_CFG1,2,3,4,每个8位。BOOT_CFG是由LCD_DATA0~23来设置的。
二,LED实验(C语言版)
1.C语言运行环境搭建
一,设置处理器模式
设置6ULL处于SVC模式下。设置CPSR寄存器的bit4-0,也就是M[4:0]为10011 = 0x13。读写状态寄存器需要用到MRS和MSR指令。MRS将CPSR寄存器数据读出到通用寄存器里面,MSR指令将通用寄存器的值写到CPSR寄存器里面去。
- 设置SP指针
SP可以指向内部RAM,也可以指向DDR,我们将其指向DDR。SP设置范围为:512MB的范围0x8000 0000~0x9000 0000。栈大小,0x20 0000 = 2MB。处理器栈增长方式,对于A7而言是向下增长。设置SP指向0x8020 0000.
- 跳转到C语言
使用b指令,跳转到C语言函数,比如main函数
三,LED实验(汇编语言版本)
- MX6ULL IO初始化
- 使能时钟 CCGR0~CCGR6这7个寄存器控制着MX6ULL所有外设时钟的使能,为了简单,设置CCGR0~CCGR6这7个寄存器全部为0xFFFF FFFF ,相当于使能所有外设的时钟。
- IO复用,寄存器IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03的bit3:0设置为0101=5 .这样GPIO1_IO03就复用为GPIO
- 将寄存器IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03是设置GPIO1_IO03的电气属性,包括压摆率,速度,驱动能力,开漏输出,上下拉等。
- 配置GPIO功能,设置输入/输出。设置GPIO1_GDIR寄存器bit3为1,也就是设置为输出模式。设置GPIO1_DR寄存器的bit3,为1表示输出高电平,为0设置为低电平。
- 链接脚本
- 链接脚本描述了要链接的文件,以及链接顺序,和链接首地址
- STM32寄存器结构体详解
- 对于STM32而言,使用一个结构体将一个外设的所有寄存器都放到一起,可以把结构体抽象看成一个外设
2.在计算机程序中,BSS段(Block Started by Symbol)是一个用于存储未初始化全局变量和静态变量的内存区域。它是程序内存布局的一部分,通常由链接器分配,并在运行时由操作系统初始化。
2.修改驱动
1.添加清除bss段代码
2.添加寄存器结构体
在结构体中添加寄存器的时候一定要注意地址的连续性,如果不连续的话要添加占位
- 官方SDK移植
- 新建cc.h文件
SDK包里面会用到很多数据类型,所以我们需要在cc.h里面定义一些常用的数据类型。
- 移植文件
需要移植的文件fsl_common.h,fsl_iomuxc.h, MCIMX6Y2.h
设备为MCIMX6Y2
- IO函数
IOMUXC_SetPinMux(uint32_t muxRegister, 0x020E0068U
uint32_t muxMode, 0x5U
uint32_t inputRegister, 0x00000000U
uint32_t inputDaisy, 0x0U
uint32_t configRegister, 0x020E02F4U
uint32_t inputOnfield) 0
IOMUXC_GPIO1_IO03_GPIO1_IO03 0x020E0068U, 0x5U, 0x00000000U, 0x0U, 0x020E02F4U
void IOMUXC_SetPinConfig(
uint32_t muxRegister, 0x020E0068U
uint32_t muxMode, 0x5U
uint32_t inputRegister, 0x00000000U
uint32_t inputDaisy, 0x0U
uint32_t configRegister, 0x020E02F4U
uint32_t configValue) 0x10b0
IOMUXC_SetPinConfig 这个函数是把configValue的值写入地址为0x020E02F4U的寄存器中
- BSP工程管理原理
- BSP工程管理的目的是为了模块化整理代码,同一个属性的文件存放在同一个目录里面
- 新建所需的文件夹,将同一属性的文件放到相应的文件夹中。
- 修改clk , led,delay驱动,创建对应的驱动文件,放置到对应的文件夹中。
- 根据编写的新驱动文件,修改main.c文件内容
- 设置VSCODE头文件路径。先创建.vscode目录,然后打开C/C++配置器,会在 .vscode目录下生成一个c_cpp_properties.json文件
- makefile指定头文件路径,需要 -I。编译源码的时候需要指定头文件路径。比如bsp/clk/bsp_clk.h 变为 -I bsp/clk/bsp_clk.h
- 通过一堆的变量,将要编译的原材料准备好了
八,BEEP实验
1.BEEP控制IO为SNVS_TAMPER1,当输出低电平的时候蜂鸣器响,输出高电平蜂鸣器不响
1.配置步骤
1.初始化SNVS_TAMPER1这个IO复用为GPIO
2.设置SNVS_TAMPER1这个IO的电气属性
3.配置GPIO
4.控制GPIO输出高低电平
九,按键输入实验
1.硬件原理图分析
按键KEY0链接到了UART1_CTS的引脚上。当默认情况下UART1_CTS为高电平,当按下KEY0以后,UART1_CTS引脚为低电平。
- 配置步骤
- 设置UART1_CTS复用为GPIO1_IO18
- 设置电气属性
- 配置GPIO为输入模式
- 读取按键值,也就是GPIO1_IO18的高低电平
- 时钟树
一,硬件原理图分析
1.32.768khz的晶振,供给RTC使用。
2.在6U的T16和T17这两个IO接了一个24MHZ的晶振。
二,IMX6U系统时钟分析
1.7路PLL为了方便生成时钟,6ul从24M晶振生出了7路PLL,这7路PLL中有的又生出来了PFD。
2.要初始化的PLL和PFD:PLL1,PLL2,以及PLL2_FDP0~PLL2_FDP3 ,PLL3以及PLL3_PFD0~PLL3_PFD3
3.一般按照时钟树里面的值进行设置。
十一,MX6U系统时钟配置
1.系统主频的配置
1.要设置ARM内核主频为528MHZ可以设置CACRR寄存器的ARM_PODF位为2分频,然后设置PLL1 = 1056MHZ即可。CACRR的bit3~0为ARM_PODF位,可设置0~7,分别对应1~8分频。应该设置CACRR寄存器的ARM_PODF=1。
2.设置PLL1=1056MHZ。PLL1=pll1_sw_clk。pll1_sw_clk有两路可以选择,分别为pll1_main_clk,和step_clk,通过CCSR寄存器的pll1_sw_clk_sel (bit2)位来选择。为0的时候选择pll1_man_clk,为1的时候选择step_clk。
3.在修改PLL1的时候,也就是在修改系统时钟的时候需要给6ULL一个临时的时钟,也就是step_clk。在修改PLL1的 时候需要将pll1_sw_clk切换到step_clk上。
4.设置step_clk。step_clk也有两路来源,有CCSR的step_sel位(bit8)来设置,为0的时候设置step_clk为osc=24MHZ。为1的时候不重要。
5.时钟切换成功以后就可以修改PLL的值。
6.通过CCM_ANALOG_PLL_ARM寄存器的DIV_SELECT位(bit0~6)来设置PLL1的频率。公式为:
Output = fref(外部晶振)*DIV_SEL/2 1056 = 24*DIV_SEL/2=>DIV_SEL=88
设置CCM_ANALOG_PLL_ARM寄存器的DIV_SELECT位等于88即可。这时PLL1 = 1056MHZ。
还要设置CCM_ANALOG_PLL_ARM寄存器的ENABLE位(bit13)为1,也就是使能输出。
- 在切换为回PLL1之前,设置CACRR寄存器的ARM_PODF=1。
2.各个PLL时钟的配置
PLL2,PLL3。PLL2(system pll)固定为528MHZ,PLL3(usb pll)固定为480MHZ。
- 初始化PLL2_PFD0~PLL2_PFD3.寄存器CCM_ANALOG_PFD_528用于设置4路PFD的时钟。比如PFD0=528*18/PFD0_FRAC。设置PFD0_FRAC位即可。比如PLL2_PFD0 = 352MHZ=528*18/PFD0_FRAC .所以PFD0_FRAC=27.
- 初始化PLL3_PFD0~PLL3_PFD3.
- 其他外设时钟源配置
AHB_CLK_ROOT,PERCLK_CLK_ROOT,IPG_CLK_ROOT
因为PERCLK_CLK_ROOT,IPG_CLK_ROOT要用到AHB_CLK_ROOT,所以要初始化AHB_CLK_ROOT
- AHB_CLK_ROOT的初始化:
AHB_CLK_ROOT = 132MHZ
设置CBCMR寄存器的PRE_PERIPH_CLK_SEL位(bit18:19)为1。 设置CBCDR寄存器的PERIPH_CLK_SEL位为0,来选择PLL2_PFD2作为时钟源。设置CBCDR寄存器的AHB_PODF位(bit 10:12)为2。
注意:在更新这个AHB_PODF的值的时候应该先关闭时钟输出,否则可能会出现没有时钟输出的情况。
- PERCLK_CLK_ROOT = IPG_CLK_ROOT = 66MHZ的初始化:
- 设置CBCDR寄存器的IPG_PODF位(bit 8:9)为1,也就是2分频。
- 设置CSCMR1寄存器的PERCLK_CLK_SEL位为0,表示PERCLK的时钟源为IPG。
- IMX6ULL中断
1.STM中断
- STM32中断向量偏移:
一般ARM从0x0000 0000地址开始执行,对于STM32我们设置连接首地址为0x8000 000。
如果代码一定要从0x8000 000开始运行,那么需要告诉一下soc内核。也就是设置中断向量偏移。设置SCB的VTOR寄存器为新的中断向量起始地址即可。
- STM32NVIC中断控制器
NVIC就是中断管理机构,使能和关闭指定的中断,设置中断优先级
- STM32中断服务函数的编写
中断服务函数就是中断要做的事情。
- IMX6ULL中断
- Cortex-A中断向量表
- Cortex-A中断向量表有8个中断,其中重点关注IRQ。Cortex-A的中断向量表需要用户自己去定义。
- 中断向量偏移
裸机例程都是从0x8780 0000开始,因此要设置中断向量偏移
- GIC中断控制器
和NVIC一样,GIC用于管理Cortex-A的中断,GIC提供了开关中断,然后是设置中断优先级。
- IMX6U中断号
为了区分不同的中断,引入了中断号
ID0~ID15:这 16 个 ID 分配给 SGI。
ID16~ID31:这 16 个 ID 分配给 PPI。
ID32~ID1019:这 988 个 ID 分配给 SPI,像 GPIO 中断、串口中断等这些外部中断 ,至于具体到某个 ID 对应哪个中断那就由半导体厂商根据实际情况去定义了。
6ULL支持128个中断
- 中断服务函数的编写
一个是IRQ中断服务函数的编写,另一个就是在IRQ中断函数里面去查找并运行的具体的外设中断服务函数。
- 中断实验编写
- 编写按键中断例程:
KEY0使用UART1_CTS这个IO,编写UART1_CTS的中断代码
- 修改start.s:为了添加中断向量表,编写中断服务函数和IRQ中断服务函数。
- 编写复位中断服务函数,内容如下:
0.关闭I,D Cache 和MMU
-
-
- 设置处理器9种工作模式下对应的SP指针。要使用中断那么必须设置IRQ模式下的SP指针。索性直接设置所有模式下的SP指针。
- 清除BSS段
- 跳转的C函数,也就是main函数
-
- CP15协处理器
MRC: 将 CP15 协处理器中的寄存器数据读到 ARM 寄存器中。
MCR: 将 ARM 寄存器的数据写入到 CP15 协处理器寄存器中。
MCR指令格式:MCR{cond} p15, <opc1>, <Rt>, <CRn>, <CRm>, <opc2>
MRC p15,0,r0,c0,c0,0 读取ID寄存器到r0寄存器中
现在要关闭I,D Cache 和 MMU,打开Cortex-A7参考手册到105页找到SCTLR寄存器,也就是系统控制寄存器,此寄存器bit0用于打开和关闭MMU,bit1对齐控制位,bit2控制D Cache的打开和关闭。bit11用于控制分支预测,bit12用于控制I Cache。
中断向量偏移设置:
将新的中断向量表首地址写入到CP15协处理器的VBAR寄存器。
MCR{cond} p15, <opc1>, <Rt>, <CRn>, <CRm>, <opc2>
MRC p15,0,r0,c12,c0,0 这行指令将寄存器VBAR的值写入到r0寄存器中。
MCR p15,0,r0,c12,c0,0 这行指令将r0中新的向量偏移地址写入VBAR寄存器中。
IRQ中断服务函数
mcr p15,4,r1,c15,c0,0 读取CP15的CBAR寄存器。CBAR寄存器保存了GIC控制器的寄存器组首地址。GIC寄存器组偏移0x1000~0x1ffff为GIC的分发器,0x2000~0x3fff为CPU接口端。意味着我们可以访问GIC控制器了
代码中,r1寄存器保存着GIC控制器的CPU接口端的基地址,
读取cpu接口端的GICC_IAR寄存器的值保存到R0寄存器里面。
可以从GICC_IAR寄存器的0~9位来读取中断号。我们读取中断ID的目的就是为了得到对应的中断处理函数。
system_irqhandler就是具体的中断处理函数,此函数有一个参数为GICC_IAR寄存器的值
system_irqhandler处理完具体的中断以后,需要将对应的中断ID的值写入到GICC_BOIR寄存器里面。
6ULL GPIO中断设置
- 我们要设置GPIO的中断触发方式,也就是GPIO_ICR1或ICR2寄存器。触发方式有低电平,高电平,上升沿和下降沿。对于本例程来说设置UART1_CTS这个IO为下降沿触发。
- 使能GPIO对应的中断,设置GPIO_IMR寄存器。
- 处理完中断以后,需要清除中断标志位,也就是清除GPIO_ISR寄存器相对应的位,GPIO_ISR寄存器是写1清零
- GIC配置:
- 使能相应的中断ID。GPIO1_IO18对应的中断ID为67+32 = 99。
- 设置中断优先级
- 注册GPIO1_IO18的中断处理函数
IMX6ULL 处理器的中断系统是基于 ARM Cortex-A7 内核的 GIC (Generic Interrupt Controller) 设计的,其中断号分配和使用机制导致了这种现象。
原因解析:
中断源数量与中断号的关系:
-
- IMX6ULL 支持 128 个硬件中断源,这些中断源通常对应于外设、系统功能等。
- 中断号的范围是为了兼容 Cortex-A 系列的标准设计,实际中断号并不仅限于硬件中断源的数量。
中断号偏移:
-
- ARM GIC 的设计中,前 32 个中断号(0-31) 是保留给 内部中断(如软件中断和定时器中断) 的。
- 硬件中断源的中断号从 32 开始,依次编号至硬件中断源的数量上限(IMX6ULL 的 128 个硬件中断对应中断号 32-159)。
总中断号数量:
-
- 前 32 个是 GIC 的内部中断号。
- 加上 128 个硬件中断源,最终中断号范围为 0-159,总计 160 个中断号。
总结
IMX6ULL 的 GIC 中断控制器分配了 160 个中断号,其中:
- 0-31:内部中断号(如软件中断)。
- 32-159:硬件中断号,对应于 128 个外设或硬件模块。
这种设计是 ARM GIC 的通用特性,并非 IMX6ULL 独有。通过将内部和外部中断分开,可以更清晰地管理中断优先级和中断处理逻辑。
- EPIT定时器实验
- EPIT简介
- EPIT是32位的一个向下计数器。
- EPIT的时钟源可以选择,我们选择ipg_clk = 66MHZ。
- 可以对时钟源进行分频,12位的分频器,0~4095分别代表1~4096分频
- 开启定时器后,计数寄存器每个时钟减1,如果和比较寄存器里面的值相等的话就会触发中断
- EPIT有两种工作模式:
- Set-add-forget 另外一个是 free-running
- 6ULL有两个EPIT定时器
- EPIT—CR寄存器用来配置EPIT
- 实验原理简介
- EPIT_CR bit0 为1使能EPIT,bit1为1设置计数器的初始值为加载寄存器的值,bit2为1使能比较中断,bit3为1设置定时器工作在set-and-forget模式下,bit15~4设置分频值,bit25~24设置时钟源的选择,我们设置为1,那么EPIT的时钟源就为ipg_clk=66MHZ
- EPIT_SR寄存器,只有bit0有效表示中断状态,写1清零。当OCIF为1时表示中断发生,为0的时候表示中断未发生。我们处理完定时器中断以后一定要清除中断标志位。
- EPIT_LR寄存器设置计数器的加载值,计数器每次计时到0以后就会读取LR寄存器的值,重新开始计时。
- EPIT_CMPR比较计时器,当计数器的值和CMPR的值相等以后,就会产生比较中断。
- 使用EPIT实现500ms周期的定时器。我们在EPIT中断服务函数里面让LED灯亮灭。
- 定时器按键消抖实验
- 定时器按键消抖简介
-
- 当按键按下以后,进入到中断服务函数中,开始一个定时器,定时周期为10ms,只有在最后一个抖动信号开启的定时器才能完全的执行完一个周期。当定时器产生周期以后就在中断函数里做具体的处理,比如开关蜂鸣器。
-
- GPT定时器原理
- GPT定时器简介:
-
- 以前的延时函数就采用空指令执行来实现,延时肯定不准确。当我们修改了6ULL的主频以后,采用空指令的延时函数就不准了。因此我们需要高精度的延时函数,而且不随着主频的变化而改变。
- STM32使用SYSTICK这个硬件定时器来实现高精度的延时。因此我们可以在6U里面使用一个硬件定时起来实现高精度的延时。
- 我们使用6U的GPT定时器来实现高精度的延时
- GPT定时器是一个32位的向上计数器。
- GPT定时器有捕获的功能
- GPT定时器支持比较输出或中断功能
- GPT具有12位的分频器
- GPT时钟源可以选择,我们选择使用ipg_clk = 66MHZ作为GPT的时钟源。
- GPT_CR寄存器,bit0为GPT使能位,为0的时候关闭GPT,为1的时候打开GPT。bit1确定GPT定时器的初始值,为0的时候表示GPT定时器计数器默认值为上次关闭的遗留的值,为1的话表示计数值GPT定时器计数器默认值为0。bit6~8为时钟源的选择,设置为1,表示GPT时钟源为ipg_clk = 66MHZ。bit9设置GPT定时器的工作模式,为0的时候工作在restart模式,为1的时候工作在free-run模式。bit15软件复位
- GPT_PR寄存器的bit11~0为分频值,可设置0~4095,表示1~4096分频
-
-
-
- GPT_SR寄存器的bit5表示溢出发生,bit4和bit3分别为输入通道2和1的 捕获中断标志位。bit2~0也就是OF3~OF1为比较中断。
- GPT_IR寄存器,也就是中断使能寄存器。
- GPT定时器有两种工作模式,restart和free-run。
- Restart模式下:
- 定时器计数值和比较寄存器OCR的值相等的话定时器就会重新从0开始计时。注意:只有比较通道1才有此功能。
- Restart模式下:
-
- frre-run模式:
- 所有三个输出比较通道都适用。从0开始一直加到0xffffffff,然后重新从0开始。
- 串口实验
1.6ULL串口UART原理
1.6ULL的UART_URXD寄存器保存这串口接受到的数据,UART_UTXD寄存器为发送数据寄存器,如果需要通过串口发送数据,只需要将数据写入到UART_UTXD寄存器里面。
- UART_UCR1~UCR4都是串口的控制寄存器,UART_UCR1的bit0是UART的使能位,为1的时候使能UART,bit14为自动检测波特率使能位,为1的时候使能波特率自动检测。
- UART_UCR2的bit0为软件复位位,为0的时候复位UART。bit1使能UART的接受,我们要配置为1.bit2为发送使能,要设置为1。bit5设置数据位,0的话表示7位数据位,1的话表示8位数据位。bit6设置停止位,0的话表示1位停止位,1的话表示2位停止位。bit7为奇偶校验位,为0的时候为偶校验,为1的时候为奇校验。bit8为校验使能位,为0的时候关闭校验。
- UART_UCR3的bit2,必须为1。
- UART_UFCR寄存器的bit9~7设置分频值,UART的时钟源=PLL3/6=480/6=80。CSCDR1寄存器UART_CLK_SEL位设置UART的时钟源,为0的时候UART时钟源为80MHZ,为1的时候UART时钟源为24MHZ。CSCDR1寄存器的UART_CLK_PODF位控制分频,一般设置为1分频,因此UART_CLK_ROOT= 80MHZ。
- UART_UFCR,UART_UBIR,UART_UBMI这三个寄存器决定了串口的波特率
- UART_USR2寄存器的bit0表示是否有数据可以读取,bit0为1的时候表示有数据可以读取,bit3表示是否发送完成,为1的时候表示发送完成。
2.实验程序编写
1.UART1_TXD使用的IO为UART1_TX_DATA,UART1_RXD使用的IO为UART1_RX_DATA
2.putc和puts在编译的时候会报错,要在Makefile中添加-fno-builtin
3.SecuCRT打开以后串口接受到乱码,因为Linux默认用UTF-8编码,因此我们需要设置SecuCRT的编码模式为UTF-8
4.我们移植的printf不支持浮点计算和输出!!!!
- DDR3内存简介
- SRAM
一开始是芯片内部RAM,后面因为应用需求外扩RAM,比如STM32F103/407开发外扩1MBSRAM。
IS62WV51216,这是一个16位宽的1MB的SRAM。
-
- SDRAM
- SDRAM需要时钟线,常见的频率就是100MHZ,133MHZ,166MHZ,200MHZ
- SDRAM
- DDR3时间参数
- 传输速度:DDR3 1600 DDR3 1866 DDR4 3200 单位MT/S
- tRCD:行到列的延时
- CL参数:
- tRC参数
- tRAS参数
IMX6U MMDC控制器
- 多模支持DDR3/DDR3L LPDDR2 x16位
- MMDC最高支持DDR3频率是400MHZ,也就是800MT/S的传输速率
- MMDC提供的DDR3连接信号。6ULL给DDR提供了专用的IO
DDR时钟配置:
- DDR使用时钟源为MMDC_CLK_ROOT = PLL2_PFD2 = 396MHZ。在前面例程我们已经设置为396MHZ。
- CBCMR寄存器的PRE_PERIPH2_CLK_SEL这个位来选择,也就是bit21,22,设置pre_periph2时钟源,设置为01,也就是PLL2_PFD2作为pre_periph2时钟源。
- CBCDR寄存器的PERIPH2_CLK_SEL这个位来选择MMDR的时钟源,也就是bit26,设置为0的时候选择PLL2作为时钟源。
- CBCDR寄存器的FABRIC_MMDC_PODF这个位来设置预分频的值,因为不进行分频,也就是把bit5~3设置为000。最终MMDC_CLK_ROOT = 396MHZ。
- DDR3L初始化与测试
- ddr_stress_test配置文件:
excel配置文件,excel配置好以后realvuew.inc会同步的更新。
-
- .inc文件
- ddr_stress_tester工具需要用到.inc文件。
- 测试
- ddr_stress_tester通过USB口 将.inc中的配置信息下载到开发板里面。直接进行超频测试的话测试失败。
- 做校准
- .inc文件
Write leveling calibration
MMDC_MPWLDECTRL0 ch0 (0x021b080c) = 0x00000000
MMDC_MPWLDECTRL1 ch0 (0x021b0810) = 0x000B000B
Read DQS Gating calibration
MPDGCTRL0 PHY0 (0x021b083c) = 0x013C013C
MPDGCTRL1 PHY0 (0x021b0840) = 0x00000000
Read calibration
MPRDDLCTL PHY0 (0x021b0848) = 0x40403038
Write calibration
MPWRDLCTL PHY0 (0x021b0850) = 0x40403830
二十,RGB显示原理简介
- 像素点:
- 像素点就相当于一个“小灯”,不管是液晶屏,还是手机,平板,RGBLCD屏幕他都是由一个个彩色的小灯构成。彩色点阵屏每个像素点有三个小灯,蓝色,红色,绿色和蓝色,也就叫做RGB。RGB就是光的三原色
- 分辨率
- 要想显示文字,图片,视频等等就需要和多个像素点,分辨率说的就是像素点的个数,1080p,720p,2k,4k,8k。1080p = 1920*1080.表示一行有1920个像素点,一列有1080个像素点。显示器有尺寸!24寸.尺寸不变的情况下,分辨率越高,显示效果越精细。4k = 3840*2160相当于4个1080P
- 像素格式
- 如何将RGB三种颜色进行量化,每种颜色用8bit表示,RGB就需要888共24bit。
可以描述出2^24=16M种颜色。现在流行10bit,HDR10,支持HDR效果的10bit面板,RGB10 10 10也就是可以描绘出2^30 = 1G中颜色。
-
- 在RGB的基础上加上8bit的ALPHA通道,也就是透明通道,ARGB888 = 32位。
- LCD屏幕接口
- RGB格式的屏幕,一般叫做RGB接口屏。
- 屏幕接口有:MIPI,LVDS,MCU,RGB接口。
- 屏幕ID:使用ID可以识别不同的屏幕,在RGBLCD屏幕上对R7,G7,B7焊接上拉或下拉电阻,实现不同的ID。
- LCD时间参数
- 水平:HSYNC水平同步信号,行同步信号,当出现HSYNC信号的时候表示新的一行开始显示,HSYNC信号要维持一段时间,这个时间叫做HSPW,HSYNC信号完成以后,需要一段时间延时,这段时间叫做HBP。一行像素显示完成以后,到HSYNC下一行信号的产生之间有个延时,叫做HFP。因此真正显示一行的时间为HSPW + HBP + WIDTH(屏幕水平像素点个数,比如1024CLK)+HFP
- 垂直:VSYNC垂直同步信号,帧同步信号,当出现VSYNC信号的时候表示新的一帧开始显示。VSYNC信号,持续一段时间为VSPW。VSYNC信号完成以后需要一段时间,叫做VBP。VBP信号结束以后,就是要显示函数,比如600行。所有的行显示完成以后,要有一段延时,叫做VFP。一帧的时间为(VSPW+VBP+HEIGHT(600)+VFP)* (HSPW + HBP + WIDTH(屏幕水平像素点个数,比如1024CLK)+HFP)。
- 显存
- 显存:显示存储空间,采用ARGB888=32bit=4B。这4个字节的数据表示一个像素点的信息,必须得存起来。定义一个数组来存储像素点的数据
二十一,6ULL LCDIF控制器接口原理
- 使用DOTCLK接口,也就是VSYNC,HSYNC,ENABLE(DE)和DOTCLK(PLCK)
- LCDIF_CTRL寄存器的bit0必须置1 ,bit1设置数据格式24位全部有效,设置为0。bit5设置LCDIF接口工作在主机模式下,必须置1。bit9:8设置输入像素格式为24bit,设置为3。bit11:10设置数据传输宽度为24bit写3。bit13:12设置数据交换,不需要交换设置为0.bit15:14设置输入数据交换,不交换设置为0。bit17置1,LCDIF工作在DOTCLK模式下。bit19必须置1,因为工作在DOTCLK模式下。bit31是复位功能必须置0。
- LCDIF_CRTL1寄存器的bit19:16设置为0x7,相当为24位的格式。
- LCDIF_TRANSFER_COUNT寄存器的bit15:0是LCD一行屏幕的像素数,bit31:16是LCD一共有多少行。
- LCDIF_VDCTRL0寄存器bit17:0为VSPW参数,bit20设置VSYNC信号的宽度单位,设置为1。bit21设置为1。bit24设置ENABLE信号极性,为0的时候为低电平,为1时为高电平,设置为1.bit25设置CLK信号极性,设置为0。bit26设置HSYNC信号极性,设置0,低电平有效,bit27设置VSYNC信号极性,设置为0,低电平有效。bit28设置为1,开启ENABLE信号。bit29设置为0,VSYNC输出
- LCDIF_VDCTRL1寄存器为两个VSYNC信号之间的长度,那就是VSPW+VBP+HEIGH+VFP。
- LCDIF_VDCTRL2寄存器bit17:0是两个HSYNC信号之间的长度,那就是HSPW + HBP + WIDTH(屏幕水平像素点个数,比如1024CLK)+HFP。bit31:18为HSYNC信号的宽度,也就是HSPW。
- LCDIF_VDCTRL3寄存器:bit15:0是VBP+VSPW。bit27:16为HBP+HSPW
- LCDIF_VDCTRL4寄存器bit17:0是一行有多少个像素点,bit18设置为1。
- LCDIF_CUR_BUF寄存器LCD当前缓存,显存首地址。
- LCDIF_NEXT_BUF寄存器LCD下一帧数据首地址。
- LCD IO初始化
LCD像素时钟的设置
- LCD需要一个CLK信号,这个时钟信号是6ULL的CLK引脚发送给RGB LCD的。
- LCDIF_CLK_ROOT就是6ULL的像素时钟。我们设置PLL5(video PLL)为LCD的时钟源。
- PLL5_CLK = Fref*(DIV_SELECT)=24*DIV_SELECT。DIV_SELECT就是CCM_ANALOG_PLL_VIDEO bit6~0也就是DIV_SELECT位。可选范围27~54.
- 设置PLL_VIDEO寄存器的bit 20:19为2表示1分频
- CCM_ANALOG_MISC2n寄存器的VIDEO_DIV bit31:30设置为0,表示1分频。
- 我们不使用小数分频器,因此CCM_ANALOG_PLL_VIDEO_NUM寄存器(分子) = 0;再设置CCM_ANALOG_PLL_VIDEO_DENOM寄存器也等于0,也就是不使用小数分频器
- CCM_CSCDR2寄存器的bit 17:15 设置LCDIF1_PRE_CLK_SEL,来选择LCDIF_CLK_ROOT的时钟源,设置为2,表示LCDIF时钟源为PLL5。bit 14:12为LCDIF1_PRED位,设置前一级分频,可以设置 0~7分别对应1~8分频。
- CCM_CBCMR寄存器的bit 25:23为LCDIF1_PODF来设置第二级分频,也是0~7,分别对应1~8分频。
- CCM_CSCDR2寄存器的bit 11:9为LCDIF1_CLK_SEL位来设置LCDIF_CLK_ROOT的时钟源,设置为0.
LCD驱动程序编写
- 初始化LCD之前,先读取屏幕ID。
RTC原理详解
1.6U内部自带了一个SRTC外设,6U和6ULL的RTC内容在SNVS章节,6U的RTC 分为LP和HP。LP叫做SRTC,HP叫做RTC但是HP的RTC掉电以后数据就丢失了, 即使用了纽扣电池也没用。所以必须要使用LP,也就是SRTC。
- RTC分为SNVS_LP和SNVS_HP
- 如果做产品,建议使用外置RTC芯片,PCF8563。
- RTC类似定时器,外接32.768KHZ的晶振,然后开始计时。
- RTC使用两个寄存器保存计数值
- RTC使用,打开RTC,RTC就开始工作,我们要做的就是不断的读取RTC计数寄存器,获取时间值,或者向RTC计数器写入时间值,也就是调整时间。
- SNVS_HPCOMR寄存器的bit31置1,表示所有的软件都可以访问SNVS所有的寄存器。bit8也是和安全有关的设置为1。
- SNVS_LPCR寄存器bit0置1开启SRTC。
- SNVS_LPSRTCMR寄存器的bit15:0为RTC计数寄存器,每1秒数据加1
- SNVS_LPSRTCLR是低32为RTC计数器,与LPSRCMR共同组成SRTC计数器,每一秒加1。
- 6U的RTC默认从1970年1月1日0时0点0分0秒
时间乱码的问题
- 问题:当我们按照6U的参考手册编写代码,读取SRTC的LPSRTCMR和LPSRTCLP获取时间值的时候,发现按照手册的说法,时间是错误的。
- 手册上写的LPSRTCMR是SRTC的高15位。LPSRTCLR寄存器是SRTC的低32位,也就是SRTC是47位的。
- 问题解决方法:LPSRTCMR作为SRTC计数器的高15位,但是LPSRTCLR寄存器的bit31:15作为SRTC计数器的低17位。相当于SRTC的计数器是个32位的,不是47位的。
IIC协议
- ALPHA开发板上有一个AP3216C,这是一个IIC接口的器件,这是一个环境光传感器。AP321C连接到了I2C1上。
- I2C1_SCL:使用的是UART4_TXD引脚,复用为ALT2
- I2C1_SDA:使用的是UART4_RXD引脚,复用为ALT2
- I2C分为SCL和SDA,这两个必须接上拉电阻,到VCC,比如3.3V,一般是4.7K上拉电阻
- I2C总线支持多从机,通过从机地址来区分访问那个从机。
- 6ULL的I2C频率标准模式100kbit,快速模式400kbit/S。
- 时钟源选择perclk_clk_root = ipg_clk_root = 66MHZ。
- IFDR寄存器设置I2C频率,bit5:0设置分频值,假若我们现在需要100kbit的速率,那么66000000/100000 = 660;经过查找IC位设置为0X38或0X15的时候,为640分频,66000000/640=103.125kbit
- I2CR寄存器bit7为IIC使能位,置1使能I2C。bit5为主从模式选择位,为0表示从模式,为1表示主模式。bit4为发送/接受设置位。为0的时候是接受,为1的时候是发送。
- I2SR寄存器bit7为传输完成,为0表示正在发送,为1表示发送完成。bit5表示为IIC忙闲位,为0的时候IIC总线空闲,为1的时候IIC总线忙。bit0是读确认位,也就是ACK信号。
- IICDR寄存器,数据寄存器
AP3216C简介
- AP3216C是一个三合一的环境光传感器,ALS(环境光)+PS(接近传感器)+IRLED(是红外LED灯),IIC接口,最高400kbit/S的频率。
- 环境光,ALS是16位输出。
- 接近传感器是10位输出,IR也是10位寄存器。
- AP3216C的从机地址为0X1E。
- 0X0A是IR Data low。bit7为0的时候表示IR和PS数据有效,为1的时候IR和PS数据无效。bit1:0是IR的低2位。
- 0X0B是IR Data height。bit 7:0是高字节。与0X0A一起组成10bit的寄存器。
- 0X0C和0X0D分别为ALS的低8位和高8位
- 0x0E是PS的bit3:0是低四位数据,0X0F的bit5:0是高6位数据。
- 0X00是系统配置寄存器,bit2:0设置AP3216C开启那些传感器。需要设置为011,也就是0x3,表示开启ALS+PS+IR。
SPI协议详解
- SPI相比I2C最大的优势有两点,一个是速度快,最高可以达到几十M,甚至是上百MHz,第二个是SPI是一个全双工的。
- SPI接口和IIC一样,一个SPI接口可以连接多个SPI外设,SPI通过CS引脚/数据线,片选引脚来选择和那个SPI外设通信。SPI通信前先将指定的SPI外设对应的CS引脚拉低,来选择和那个设备进行通信。
- ALPHA开发板上连接了一个ECSPI3接口连接了一个6轴传感器,引脚如下:ECSPI3_SCLK : UART2_RX,ECSPI3_MOSI:UART2_CTS,ECSPI3_MISO:UART_RTS,ECSPI3_SS0:UART2_TXD。6ULL一个SPI主接口有4个硬件片选,分别为SS0~SS3。
- 根据CPOL和CPHA可以设置4种工作模式,一般使用CPOL = 0,CPHA = 0
SPI接口
1.6ULL的SPI接口叫做ECSPI,支持全双工,主从可配置。
2.4个硬件片选信号,可以使用软件片选,这样一个SPI接口所能连接的外设就无限制了。
3.RXDATA寄存器为接收到的数据,TXDATA寄存器为发送数据寄存器。
- CONREG寄存器为配置寄存器,bit 0置1使能SPI。bit 3置1表示当向TXFIFO写入数据以后马上开启SPI突发访问,也就是发送数据。bit 7:4设置SPI通道主从模式,bit 7为通道3,bit 4为通道0,使用到了SS0,也就是通道0,因此要设置bit4为1.bit 19:18为通道选择,设置为00,我们使用到SS0,也就是通道0.bit 31:20设置突发访问长度,我们设置为7,也就是8bit。
- CONFIGREG寄存器的bit 0为PHA,设置为0,表示从串行时钟的第一个跳变沿来采集数据。bit 7 :4设置为0,设置空闲为低电平。bit 8设置为0。bit 12 设置为0。bit16设置为0,表示空闲的时候数据线为高,bit20设置为0,表示空闲的时候为低
- STATREG寄存器bit 0 表示TXFIFO为空,我们在发送数据之前,要等待TXFIFO为空,也就是等待bit 0为1. bit 3 表示RXFIFO是否有数据,为1的时候表示RXFIFO至少有一个字的数据。我们在接受数据的时候要等待bit 3 为1.
- PERIODREG寄存器,bit 0~14设置wait states时间,设置为0x2000。bit15 设置wait states的时钟源为SPI CLK,将此位设置为0.bit21:16表示片选信号的延时,可设置0~63,这里设置为0.
- SPI时钟设置:SPI时钟源最终来源于pll3_sw_clk = 480MHz/8 = 60MHz.设置CSCDR2寄存器的ECSPI_CLK_SEL位设置为0,也就是ECSPI时钟源为60MHz。ECSPI_CLK_PODF位设置位0,表示1分频,因此最终进入ECSPI的时钟源为60MHz
- ECSPI模块还需要对时钟进行两级分频 由ECSPI_CONREG寄存器设置,bit 15:12设置前级分频,可以设置0~0x0f,表示1~16分频。bit 11:8设置二级分频,设置2^n分频,n = 0~15。
ICM20608简介
- 陀螺仪和加速度都是16为ADC。
- 通信接口为IIC或SPI,IIC最大到400kHZ,SPI最大到8MHz
- ICM20608G的WHO_AM_I寄存器地址为0x75,默认值为0XAF。ICM20608D的WHO_AM_I寄存器地址为0x75,默认值为0XAE。
- 0x3b~0x48是传感器的数据寄存器。