1.先给出源代码和书中指南截图
//LCD地址结构体
typedef struct
{
vu16 LCD_REG;
vu16 LCD_RAM;
} LCD_TypeDef;
//使用NOR/SRAM的 Bank1.sector4,地址位HADDR[27,26]=11 A10作为数据命令区分线
//注意设置时STM32内部会右移一位对其!
#define LCD_BASE ((u32)(0x6C000000 | 0x000007FE))
#define LCD ((LCD_TypeDef *) LCD_BASE)
2.地址偏移量解释
很多人都对这个0x6C000000和0x000007FE很不理解,百度了一堆也没人能解释清楚,包括他们自己的视频课和论坛解释也是让很多人云里雾里。
首先这个0x6C000000,为啥不是0x6C或者0x6C00或者0x6C0000,少个0少几个0不行吗?答案是:绝对不可以。因为STM32单片机是32位的,所以地址都是32位的,我们知道0x前缀开始的都是十六进制的,那么0x6C000000就是个十六进制数,转换成二进制就是
0110 | 1100 | 0000 | 0000 | 0000 | 0000 | 0000 | 0000 |
那么这个0x6C000000数字是从哪来的呢?因为TFT屏幕用了STM32的FSMC接口的存储块1的第四个区(Bank1->Sector4),这个要去看STM32的中文参考手册的FSMC部分P326页,我直接贴图
我们可以看到存储块1的起始地址是:0x6000 0000,结束地址是:6FFF FFFF。这个存储块1又被分为4个区,每个区是64MB,我们知道1MB=1024KB=1024*1024bit,所以呢,64MB=67,108,864bit,那么bit是二进制的,我们把它换算成十六进制数就是0x400 0000,所以第一个区的起始地址就是:0x6000 0000+0x400 0000=0x6400 0000。以此类推就可以得到二三四区的起始地址:如下表所示。
BANK1的区 | 地址范围 |
第一个区 | 0X6000,0000~0x63FF FFFF |
第二个区 | 0X6400,0000~0x67FF,FFFF |
第三个区 | 0X6800,0000~6BFF,FFFF |
第四个区 | 0X6C00,0000~6FFF,FFFF |
所以我们的地址就是0x6C00 0000。
接下来再说0x7FE怎么来的,这个问题也困扰了我好久,为啥不是别的数字呢,0x400为啥不行?0x800为啥不行?。这个我通过Chatgpt找到了答案,题外话:Chatgpt真的好用,比百度强多了,百度全是广告,翻了半天都没有想要的答案,尤其最近搞了个什么萝卜无人驾驶出租车,就想着跟底层老百姓去抢饭碗,人工智能我觉得更应该用到地质矿山勘测、动植物保护、洪涝灾害、海洋探测等等一些工作危险区域,代替人去执行工作,而不是用它来压榨普通百姓。
把A10作为命令/数据的区分,这个A10指的是FMSC_A[24:0]这里的第11位(因为是从0开始的),而且STM32中文参考手册里关于FMSC明确说了FMSC_A[24:0]的A0必须对应HDDR[25:1]的A[0],
那么0x7FE对应的二进制数字就是
0111 | 1111 | 1110 |
从右往左数分别是A0->A1->...A11,所以A10是1,那么A0如果不是0是1呢,行不行?答案是不行,因为STM32要满足16位对齐,如果A0是1,这个二进制数字就不能被16整除了,所以必须是0而且这个结构体里的变量类型都是2字节的,结构体里的变量地址都是自增的,也就是第二个变量的地址是第一个变量的地址加上2个字节。如果你把地址只让A10是1,A0是0,那么就是0x400,如果把它作为第一个变量的地址,那么第二个变量的地址就是:0x400+2=0x402,会发现第11位也就是A10还是1,根本就没变,那就达不到作为数据/命令区分了,因为数据的时候要A10是0,命令的时候A10是1.所以必须为0x7FE。因为0x7FE+2=0x800,此时A10就是0了。
3.关于字节计算的错误
正点原子的书籍中紧接着又给了一个结构体的代码
这个表述是错误的,这个结构体的字节数并不是10,而是14。虽然不影响最终结果,但是要明白结构体的内存计算。
想咨询更多关于嵌入式的技术问题请添加我私人微信