STM32之TFTLCD指针深度讲解

这篇文章对应于stm32的FSMC外接LCD控制器章节。

限于知识程度有限,出错在所难免,还请指正!
(学习嵌入式已经过去一年了,再次回来修补这篇文章,2021-1-19,_

//TFTLCD信息结构体
typedef struct
{
	vu16 LCD_REG;    //地址
	vu16 LCD_RAM;    //数据
} LCD_TypeDef;	
    
#define LCD_BASE        ((u32)(0x6C000000 | 0x0000007E))
#define TFTLCD 			((LCD_TypeDef *) LCD_BASE)            //强制转换成 (LCD_TypeDef *)指针类型

TFTLCD->LCD_REG=regval; 	指针指向 0x6C00 007E
TFTLCD->LCD_RAM=data;		指针指向 0x6C00 0080

1、怎么决定发送的是数据还是命令?
先来说最容易理解的一种情况,假设说某个芯片IC有一个D/C管脚(D:数据;C:命令),连接到了单片机I/O口上,我们可以通过控制I/O输出高低电平,来决定发送的是数据还是命令。

现在我们的 stm32 的 FSMC 控制器要挂载外接存储器(在这里我们使用的是 TFTLCD 屏,可以看做是外接存储器),如下图所示(只截取一部分)。PF12 ( FSMC_A6 )要复用成地址线,因此不能通过 I/O 口拉高拉低决定发送数据还是命令,但是我们可以通过FSMC_A6这一根地址线是0还是1(注意这不是高低电平),决定发送的数据还是命令。这里的解释有点模糊,请继续往下看。
stm32电路图和程序
2、先来思考一个问题: 内核(cpu)是怎么和外设"交流"的 ,或者说怎么操作寄存器的?

在这里插入图片描述
先解释几个概念:

1、什么是总线?
我知道的总线可以分为地址总线、数据总线、控制总线。以下解释对于stm32来说,具体能分几个,我也不知道,但是不会妨碍我们的理解。上图中的内核也可以看做cpu核心。

地址总线:很明显地址总线是用来寻址的。那些GPIO寄存器,I2C控制器,SPI控制器等等,cpu要想修改控制它们的内容,必须先通过地址总线寻址到它们。

数据总线:当cpu寻址到目的地之后,怎么把数据写进去或读出来,那就要靠这个数据总线。

控制总线:控制总线目的是来控制是读操作还是写操作。

相关知识
32位单片机的"32"到底代表什么意思?答:32代表ALU,算术逻辑单元的宽度。通俗来讲就是,cpu做加减法时,加数或减数的最大宽度。大多数情况下,地址总线、数据总线的宽度都是32位的,这样对称性好,但有些单片机的地址总线和数据总线的宽度是不同的,例如51单片机。这里地址总线是32位,那么它的寻址空间就是 0x00000000-0xFFFFFFFF 刚好4个G。

2、什么是存储器映射?
和存储器映射相对的就是IO端口映射,不过对于stm32,好像都是存储器映射。具体IO端口映射是什么,大家自行百度吧,感觉以后用到的很少。那什么是存储器映射?说白一点,就是我们(cpu)访问一个控制器就像访问一个内存一样,直接把这些外设看做是一个内存来进行访问。

下面进入正题----->
先举个例子,当我们调用这一条程序时,GPIOA->MODER=xxxx,内核(cpu)怎么把数据 xxxx 写入GPIOA的MODER寄存器的?
这里,内核首先发出"疑问"了,MODER寄存器是谁?在哪?我怎么把xxxx数据写进MODER寄存器?最明显的是,内核和寄存器不是绕开寻址,直接通过数据总线和寄存器交互的。如果是直接进行数据交换,那还要映射,总线干啥,对吧。其实GPIOA->MODER 已经提供了一个地址(在后面有讲解),(这条指令会被翻译成机器码,当cpu执行这条指令的时候,其实它已经知道要修改哪个地址了,相当于寻址吧,我暂时这样去理解),这时候内核拿着这个地址通过总线去外设空间(寻址空间)上去找,说白了,内核要对某一个寄存器(外设)操作,前提得先找到要读写的位置,然后通过数据总线读写。寻址流程见上图
讲完这个好像跟 TFTLCD 指针也没啥关系呀,别着急,继续看下一个问题-------->

3、HADDR[27:0]地址线 和 FSMC_A[24:0]地址线有什么关系?
STM32F4xx中文参考手册 1194/1284
HADDR[27:0]是什么? 答:我认为,HADDR 是 AHB 内部地址线,但也会参与对外部存储器的寻址,(因为此时我们的TFTLCD就相当于一个外部存储器,挂接在FSMC控制器下面。cpu要操作TFTLCD,但是它能"看到"的只是FSMC,当cpu对FSMC控制时,我们也可以看做是cpu在操作TFTLCD)。

下面来解释HADDR[27:0]这28根线的作用----------->

HADDR 27位和26位用于选择4个存储区域之一的.
我们定义的 TFTLCD指针是指向0X6C00007E这个地址的, 从下图看是存储在HADDR[25:0]里面,(cpu要操作FSMC控制器,它首先要寻址到这个控制器,那么要寻址的地址我们可以认为存储在HADDR[25:0]当中)。因为HADDR[25:0]包含外部存储器地址, 之后是要被传到FSMC_A[24:0]的,(说传到FSMC_A[24:0]不太形象,我们可以认为HADDR[25:1]和FSMC_A[24:0]这25根线是直接相连接的,注意此时还是用来寻址的)如下图所示:

画的有点乱,先大致看下最左边的红框,再从右边往下看,注意提示。
在这里插入图片描述

再把代码贴过来:

//TFTLCD信息结构体
typedef struct
{
	vu16 LCD_REG;    //地址
	vu16 LCD_RAM;    //数据
} LCD_TypeDef;	
    
#define LCD_BASE        ((u32)(0x6C000000 | 0x0000007E))
#define TFTLCD 			((LCD_TypeDef *) LCD_BASE)            //强制转换成 (LCD_TypeDef *)指针类型

TFTLCD->LCD_REG=regval; 	指针指向 0x6C00 007E
TFTLCD->LCD_RAM=data;		指针指向 0x6C00 0080

这两个结构体变量是16位(两个字节)的变量,当TFTLCD从指向LCD_REG 转到指向 LCD_RAM的时候,0x6C00007E 变成了 0x6C000080 ,HADDR[25:0]的第7位 由0变成了1,FSMC_A[24:0]的第6位也由 0 变成了 1,就可以决定发的是数据还是命令了,16位的变量(两个字节)目的就在于此,实在是女少口阿。

为什么是HADDR[25:0]这26根数据线呢,不是25根,24根呢?
存储区域地址边界相减,0X6FFF FFFF – 0X6C00 0000 =0X3F FFFF 换成二进制刚好是26个1。

4、结构体成员为什么只有地址有用?我们通过调用这两句话TFTLCD->LCD_REG=regval;TFTLCD->LCD_RAM=data;数据是怎么被传出去的?
在这里插入图片描述
通过这两张图,我们会发现跟最开始定义的TFTLCD结构体和TFTLCD指针简直一模一样,下面慢慢分析。
这里,我打开的是F4的keil工程,根据实际情况分析。。。
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE) 0x4002 0000 (自己对着芯片手册算一下 哈哈)
在这里插入图片描述
我们看第 4 个问题的第一张图片,定义了GPIO的寄存器结构体,MODER成员相对于此结构体起始地址偏移量是 0,通过手册我们也可得到对应寄存器相对的偏移值。(注意这里定义的结构体,只是一个声明,没有分配内存,定义变量时才会分配内存。)所以,GPIOA 这个指针(地址)刚好就指向了MODER寄存器,(因为MODER寄存器的地址 = GPIOA + 0)。
只要有了GPIOA这个基地址 , 在加上偏移量,(MODER的偏移量是 0 字节,OTYPER寄存器的偏移量是 4 字节,依次类推)就能偏移到对应寄存器。GPIOA->MODER=xxxx ;这条语句左边就是一个寄存器(内存)的地址,所以此操作就是直接向指针指向的寄存器赋值。
再次重申,这里只是定义了一个结构体 GPIO_TypeDef,并没有定义变量,也没有开辟空间,这个结构体只是告诉编译器,定义变量时,按照我结构体里成员布局来分配内存。所以GPIOA 指向谁,指向的那个成员只是提供一个偏移。
类比GPIOA指针,TFTLCD指针也是同样的道理,给TFTLCD指针指向的区域赋值,只要数据到了这个区域(0x6C00 0000 - 0x6FFF FFFF),剩下的事情就是FSMC的了。细细想来,通过指针指向不成的成员就相当于直接指向内存中的地址,直接向这个地址赋值就可以了。这样一下结构体成员(LCD_REG、LCD_RAM,都是两个字节)只有地址有用,这两个成员的大小决定寻址地址从0x6C00007E变成0x6C000080的时候,FSMC_A6会发生变化,来控制发送数据还是命令。

5、为什么HADDR的最后一根地址线舍弃了?
STM32F4xx中文参考手册1195 / 1284
上面图片中说的按字寻址,准确来说应该是2个字节,或者半字,通过左边的16位,我们也可认为是2个字节。(我习惯认为一个字是4个字节)。
因为我们的LCD屏是2个字节2个字节寻址的,而我们的地址总线是一个字节一个字节寻址的,只有一次两个字节的方式寻址才能正常操作TFTLCD,寻址宽度不同所以要舍弃一根,详细解释见下面两个链接:
感谢下面两个链接的大佬,哈哈哈。。。

1、]已失效](http://bbs.100ask.org/forum.php?mod=viewthread&tid=11544&extra=page=1&page=1)
2、STM32 FSMC HADDR和FSMC_A对应的问题

  • 9
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值