38.1 初学者重要提示
学习本章节前,务必优先学习第37章,需要对FMC的基础知识和HAL库的几个常用API有个认识。
为什么要做IO扩展,不是已经用了208脚的F429BIT6吗?因为开发板使用了32位SDRAM和RGB888硬件接口,消耗IO巨大,所以必须得扩展了。
扩展的32路高速IO非常实用,且使用简单,只需初始下FMC,32路IO就可以随意使用了。当前的扩展方式只支持高速输出。
FMC总线扩展32路高速IO理解成GPIO的ODR寄存器就很简单了,其实就是一个东西。FMC扩展IO是对地址0x60001000的32bit数据空间的0和1的操作。GPIOA的ODR寄存器是对地址 0x40000000 + 0x18020000 + 0x14 空间的操作。但只能操作16个引脚。
使用总线的优势就在这里了,相当于在GPIOA到GPIOK的基础上,又扩展出GPIOL和GPIOM。
#define PERIPH_BASE ((uint32_t)0x40000000)
#define D3_AHB1PERIPH_BASE (PERIPH_BASE + 0x18020000)
#define GPIOA_BASE (D3_AHB1PERIPH_BASE + 0x0000)
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
typedef struct
{
__IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */
__IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */
__IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */
__IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */
__IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */
__IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */
__IO uint16_t BSRRL; /*!< GPIO port bit set/reset low register, Address offset: 0x18 */
__IO uint16_t BSRRH; /*!< GPIO port bit set/reset high register, Address offset: 0x1A */
__IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */
__IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
} GPIO_TypeDef;
38.2 FMC扩展IO硬件设计
扩展IO涉及到的知识点稍多,下面逐一为大家做个说明。
38.2.1 第1步,先来看FMC的块区分配
注,这个知识点在前面第37章的2.3小节有详细说明。
FMC总线可操作的地址范围0x60000000到0xDFFFFFFF,具体的框图如下:
从上面的框图可以看出,NOR/PSRAM/SRAM块区有4个片选NE1,NE2,NE3和NE4,但由于引脚复用,部分片选对应的引脚要用于其他功能,而且要控制的总线外设较多,导致片选不够用。因此需要增加译码器。
38.2.2 第2步,增加译码器及其地址计算
有了前面的认识之后再来看下面的译码器电路:
SN74LVC1G139APWR是双2-4线地址译码器,也就是带了两个译码器。原理图上仅用了一个。下面是139的真值表和引脚功能:
通过上面的原理图和真值表就比较好理解了,真值表的输出是由片选FMC_NE2和地址线FMC_A10、FMC_A11控制。
FMC_NE1 输出低电平:
FMC_A11(B),FMC_A10(A) = 00时,1Y0输出的低电平,选择的是OLED。
FMC_A11(B),FMC_A10(A) = 01时,1Y1输出的低电平,选择的是74HC574。
FMC_A11(B),FMC_A10(A) = 10时,1Y2输出的低电平,选择的是DM9000。
FMC_A11(B),FMC_A10(A) = 11时,1Y3输出的低电平,选择的是AD7606。
然后我们再计算译码器的地址,注意,这里地址的计算都是按照FMC的32bit访问模式计算的,因为我们的V6程序中是将NE1对应的FMC配置为32bit模式了。
具体FMC的32bit访问模式,16bit访问模式和8bit访问模式的区别在第37章的2.4小节有详细讲解。
32bit模式下,我们计算A10和A11的时候,实际上需要按HADDR12和HADDR13计算的。
如果来算NE1 + HADDR12 + HADDR13的四种组合地址就是如下:
NE2 + HADDR13 + HADDR12 = 0x64000000 + 0<<13 + 0<<12 = 0x64000000
NE2 + HADDR13 + HADDR12 = 0x64000000 + 0<<13 + 1<<12 = 0x64001000
NE2 + HADDR13 + HADDR12 = 0x64000000 + 1<<13 + 0<<12 = 0x64002000
NE2 + HADDR13 + HADDR12 = 0x64000000 + 1<<13 + 1<<12 = 0x64003000
这样一来,原理图里面给的地址就对应上了。同理如果配置为16位模式和8位模式,大家应该也都会计算了。
38.2.3 第3步,FMC的IO扩展部分
先来看下IO扩展的原理图实现,如果不太了解FMC的通信时序和数字逻辑芯片的使用,可能会比较懵,下面逐一为大家说明。
有了这个原理图,首先要做的就是了解74HC574和SN74HC32的功能。
74HC574是一款8位三态D触发器,起到锁存的功能,上升沿触发,对应的真值表如下(L表示低电平,H表示高电平,Z表示高阻):
SN74HC02是一款2输入或非门,一个芯片带了四组或非门,对应的真值表如下(L表示低电平,H表示高电平):
有了这个认识后,我们再来看FMC的配置,V6开发板的BSP驱动包里面专门做了一个IO扩展的FMC配置,即文件bsp_fmc_io.c,配置方式是FMC_AccessMode_A,这种模式对应的写时序是:
那么问题来了,我们要实现的功能是通过FMC输出的数据要锁存在扩展IO的输出端,否则FMC时序信号消失了,扩展IO的输出数据也消失了,就起不到控制作用了。所以就用到74HC574的锁存功能,而锁存的实现需要一个上升沿触发,这个上升沿就是通过74HC32输出的。
再结合上面FMC写时序图,在NE片选为低电平,NWE写使能信号为高电平期间,即地址建立时间段ADDSET内,74HC32是输出的高电平。
进入到DATAST数据建立阶段,在NE片选为低电平,NWE写使能信号也为低电平时,74HC32输出低电平。等NEW上升沿的时候,正好是实现1个上升沿的变化。
38.2.4 第4步,举例扩展IO驱动LED应用
进行到这里,再回过头来看LED驱动就比较好理解了。操作LED的亮灭就是操作FMC的数据引脚D8,D9,D10和D11。
对地址0x64001000发送数据就可以了,但是如何对这个地址发送数据呢? 反映到C语言的实现上就是通过固定地址的指针变量(跟我们操作寄存器是一样的),即
#define HC574_PORT *(uint32_t *)0x64001000
如果要点亮LED1(低电平点亮),就是 HC574_PORT = 0x0000 0000。
如果要熄灭LED1就是HC574_PORT = 0x0000 0100,即操作FMC_D8的高低电平即可。
38.3 FMC扩展IO驱动设计
下面将程序设计中的相关问题逐一为大家做个说明。
38.3.1 FMC扩展IO所涉及到的GPIO配置
这里仅需把用到的GPIO时钟、FMC时钟、GPIO引脚和复用配置好即可:
/*
*********************************************************************************************************
* 函 数 名: HC574_ConfigGPIO
* 功能说明: 配置GPIO,FMC管脚设置为复用功能
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static void HC574_ConfigGPIO(void)
{
/*
安富莱STM32-V6开发板接线方法:4片74HC574挂在FMC 32位总线上。1个地址端口可以扩展出32个IO
PD0/FMC_D2
PD1/FMC_D3
PD4/FMC_NOE ---- 读控制信号,OE = Output Enable , N 表示低有效
PD5/FMC_NWE -XX- 写控制信号,AD7606 只有读,无写信号
PD8/FMC_D13
PD9/FMC_D14
PD10/FMC_D15
PD14/FMC_D0
PD15/FMC_D1
PE7/FMC_D4
PE8/FMC_D5
PE9/FMC_D6
PE10/FMC_D7
PE11/FMC_D8
PE12/FMC_D9
PE13/FMC_D10
PE14/FMC_D11
PE15/FMC_D12
PG0/FMC_A10 --- 和主片选FMC_NE2一起译码
PG1/FMC_A11 --- 和主片选FMC_NE2一起译码
PG9/FMC_NE2 --- 主片选(OLED, 74HC574, DM9000, AD7606)
+-------------------+------------------+
+ 32-bits Mode: D31-D16 +
+-------------------+------------------+
| PH8 <-> FMC_D16 | PI0 <-> FMC_D24 |
| PH9 <-> FMC_D17 | PI1 <-> FMC_D25 |
| PH10 <-> FMC_D18 | PI2 <-> FMC_D26 |
| PH11 <-> FMC_D19 | PI3 <-> FMC_D27 |
| PH12 <-> FMC_D20 | PI6 <-> FMC_D28 |
| PH13 <-> FMC_D21 | PI7 <-> FMC_D29 |
| PH14 <-> FMC_D22 | PI9 <-> FMC_D30 |
| PH15 <-> FMC_D23 | PI10 <-> FMC_D31 |
+------------------+-------------------+
*/
GPIO_InitTypeDef gpio_init_structure;
/* 使能 GPIO时钟 */
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOI_CLK_ENABLE();
/* 使能FMC时钟 */
__HAL_RCC_FMC_CLK_ENABLE();
/* 设置 GPIOD 相关的IO为复用推挽输出 */
gpio_init_structure.Mode = GPIO_MODE_AF_PP;
gpio_init_structure.Pull = GPIO_PULLUP;
gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
gpio_init_structure.Alternate = GPIO_AF12_FMC;
/* 配置GPIOD */
gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5 |
GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_14 |
GPIO_PIN_15;
HAL_GPIO_Init(GPIOD, &gpio_init_structure);
/* 配置GPIOE */
gpio_init_structure.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 |
GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |
GPIO_PIN_15;
HAL_GPIO_Init(GPIOE, &gpio_init_structure);
/* 配置GPIOG */
gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_9;
HAL_GPIO_Init(GPIOG, &gpio_init_structure);
/* 配置GPIOH */
gpio_init_structure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12
| GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
HAL_GPIO_Init(GPIOH, &gpio_init_structure);
/* 配置GPIOI */
gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_6
| GPIO_PIN_7 | GPIO_PIN_9 | GPIO_PIN_10;
HAL_GPIO_Init(GPIOI, &gpio_init_structure);
}
38.3.2 FMC扩展IO时钟源选择
STM32F429的FMC是采用的HCLK时钟,位于AHB总线上。比如主频设置的是168MHz,那么FMC时钟也是168MHz。
38.3.3 时序配置(重要)
这里要补充两个重要的知识点,74HC574的CP端接收到上升沿触发到Qn输出的时间参数:
通过时序图和对应的参数要了解到以下几点:
tpd传输延迟在这里等效于tPHL和tPLH。
V6开发板的74HC574有三片是3.3V供电,另外一片是5V供电。参数表格里面没有给3.3V供电时的参数,也没有最小值。
了解了74HC574,再来看SN74HC32:
通过时序图和对应的参数要了解到以下几点:
tpd传输延迟在这里等效于tPHL和tPLH。
tt过渡时间等效于tr上升沿时间和tf下降沿时间。
对应74HC574和74HC02的时序参数有个了解后,继续往下看:
当写使能信号NWE出现上升降沿后,74HC32非门就会输出一个上升沿,然后触发74HC574做锁存。此时我们要考虑到一个重要的知识点,就是使用的数字逻辑芯片有个传输延迟问题,也就是要我们要保证74HC02的tpd传输延迟时间 + 74HC02的tr传输延迟时间 + 74HC574的tpd传输延迟时间的这段时间内,数据总线上要有数据,而这种模式下,NEW上升沿后,仅有1个HCLK时钟周期了,所以只能加大两个连续读数据的时间间隔和地址建立时间(其实是下一次的地址建立时间,可以和两个连续读的时间段放在一起)。实际测试FMC频率在168MHz的情况下,3-6个FMC时钟周期就已经可正常使用。
上一篇:第39章 STM32F429的FMC总线应用之SDRAM
下一篇:第37章 STM32F429的FMC总线基础知识和HAL库API
设计资源 培训 开发板 精华推荐
- #第八届立创电赛#桌面小时钟
- 使用 Analog Devices 的 ADP3336 的参考设计
- IS31IO7326-QFLS4-EB,基于 IS31IO7326 去抖 8x8 按键扫描控制器的评估板
- CP2102N串口板
- LT3091EDE 2 端子电流源的典型应用
- LTC3607IMSE 5V/2.5V、2.25MHz 降压稳压器的典型应用电路
- AM1D-0515D-RZ ±15V 1 瓦 DC/DC 转换器的典型应用
- 具有低漂移满量程微调的 LT1021DCN8-7 CMOS DAC 基准的典型应用
- 使用 Analog Devices 的 LTC3130EUDC 的参考设计
- OP213FPZ 5V Only 18-Bit Stereo Op-Amp DAC 的典型应用
- 报名有礼:【TI C2000在实时控制系统中的新特性】网络直播诚邀您参与!
- 免费测评乐鑫ESP32-C3-DevKitM-1
- 有奖直播|物联网时代的典型应用
- 年末福利!2019 TI 工业应用精选课程汇总,抢楼赢好礼
- 【已结束】 Qorvo、村田、NI直播【UWB最新技术、方案、市场、应用解析】(13:30开始入场)
- 有奖下载:邂逅大师——福禄克全新专家级红外热像仪
- 有奖直播:英飞凌针对电动工具的高功率、高效率以及高可靠性解决方案
- 【有奖问答】MOSFET,选型我在行!
- 有奖直播:基于GaN 的高频(1.2MHz)高效率 1.6kW 高密度临界模式 (CrM) 图腾柱功率因数校正 (PFC)转换器的应用介绍