【STM32H7教程】第48章 STM32H7的FMC总线应用之是32路高速IO扩展

2023-04-07  

48.1 初学者重要提示

学习本章节前,务必优先学习第47章,需要对FMC的基础知识和HAL库的几个常用API有个认识。

为什么要做IO扩展,不是已经用了240脚的H743XIH6吗?因为开发板使用了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;

48.2 FMC扩展IO硬件设计

扩展IO涉及到的知识点稍多,下面逐一为大家做个说明。


48.2.1 第1步,先来看FMC的块区分配

注,这个知识点在前面第47章的2.3小节有详细说明。


FMC总线可操作的地址范围0x60000000到0xDFFFFFFF,具体的框图如下:

从上面的框图可以看出,NOR/PSRAM/SRAM块区有4个片选NE1,NE2,NE3和NE4,但由于引脚复用,部分片选对应的引脚要用于其他功能,而且要控制的总线外设较多,导致片选不够用。因此需要增加译码器。

48.2.2 第2步,增加译码器及其地址计算

有了前面的认识之后再来看下面的译码器电路:

SN74LVC1G139APWR是双2-4线地址译码器,也就是带了两个译码器。原理图上仅用了一个。下面是139的真值表和引脚功能:

通过上面的原理图和真值表就比较好理解了,真值表的输出是由片选FMC_NE1和地址线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访问模式计算的,因为我们的V7程序中是将NE1对应的FMC配置为32bit模式了。

具体FMC的32bit访问模式,16bit访问模式和8bit访问模式的区别在第47章的2.4小节有详细讲解。

32bit模式下,我们计算A10和A11的时候,实际上需要按HADDR12和HADDR13计算的。

如果来算NE1 + HADDR12 + HADDR13的四种组合地址就是如下:

NE1 + HADDR13 + HADDR12 = 0x6000000 + 0<<13 + 0<<12 = 0x60000000

NE1 + HADDR13 + HADDR12 = 0x6000000 + 0<<13 + 1<<12 = 0x60001000

NE1 + HADDR13 + HADDR12 = 0x6000000 + 1<<13 + 0<<12 = 0x60002000

NE1 + HADDR13 + HADDR12 = 0x6000000 + 1<<13 + 1<<12 = 0x60003000

这样一来,原理图里面给的地址就对应上了。同理如果配置为16位模式和8位模式,大家应该也都会计算了。

48.2.3 第3步,FMC的IO扩展部分

先来看下IO扩展的原理图实现,如果不太了解FMC的通信时序和数字逻辑芯片的使用,可能会比较懵,下面逐一为大家说明。

48.2 FMC扩展IO硬件设计

扩展IO涉及到的知识点稍多,下面逐一为大家做个说明。

48.2.1 第1步,先来看FMC的块区分配

注,这个知识点在前面第47章的2.3小节有详细说明。

FMC总线可操作的地址范围0x60000000到0xDFFFFFFF,具体的框图如下:

从上面的框图可以看出,NOR/PSRAM/SRAM块区有4个片选NE1,NE2,NE3和NE4,但由于引脚复用,部分片选对应的引脚要用于其他功能,而且要控制的总线外设较多,导致片选不够用。因此需要增加译码器。

48.2.2 第2步,增加译码器及其地址计算

有了前面的认识之后再来看下面的译码器电路:

SN74LVC1G139APWR是双2-4线地址译码器,也就是带了两个译码器。原理图上仅用了一个。下面是139的真值表和引脚功能:

通过上面的原理图和真值表就比较好理解了,真值表的输出是由片选FMC_NE1和地址线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访问模式计算的,因为我们的V7程序中是将NE1对应的FMC配置为32bit模式了。

具体FMC的32bit访问模式,16bit访问模式和8bit访问模式的区别在第47章的2.4小节有详细讲解。

32bit模式下,我们计算A10和A11的时候,实际上需要按HADDR12和HADDR13计算的。

如果来算NE1 + HADDR12 + HADDR13的四种组合地址就是如下:

NE1 + HADDR13 + HADDR12 = 0x6000000 + 0<<13 + 0<<12 = 0x60000000

NE1 + HADDR13 + HADDR12 = 0x6000000 + 0<<13 + 1<<12 = 0x60001000

NE1 + HADDR13 + HADDR12 = 0x6000000 + 1<<13 + 0<<12 = 0x60002000

NE1 + HADDR13 + HADDR12 = 0x6000000 + 1<<13 + 1<<12 = 0x60003000

这样一来,原理图里面给的地址就对应上了。同理如果配置为16位模式和8位模式,大家应该也都会计算了。

48.2.3 第3步,FMC的IO扩展部分

先来看下IO扩展的原理图实现,如果不太了解FMC的通信时序和数字逻辑芯片的使用,可能会比较懵,下面逐一为大家说明。

/*

*********************************************************************************************************

*    函 数 名: HC574_ConfigGPIO

*    功能说明: 配置GPIO,FMC管脚设置为复用功能

*    形    参:  无

*    返 回 值: 无

*********************************************************************************************************

*/

static void HC574_ConfigGPIO(void)

{

/*

    安富莱STM32-H7开发板接线方法: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一起译码

    XX --- PG9/FMC_NE2        --- 主片选(OLED, 74HC574, DM9000, AD7606)    

     --- PD7/FMC_NE1        --- 主片选(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_7 |

                                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;

    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);

}

48.3.2 FMC扩展IO时钟源选择

使用FMC可以选择如下几种时钟源HCLK3,PLL1Q,PLL2R和PER_CK:

我们这里直接使用HCLK3,配置STM32H7的主频为400MHz的时候,HCLK3输出的200MHz,这个速度是FMC支持的最高时钟,正好用于这里:

48.3.3 时序配置(重要)

这里要补充两个重要的知识点,74HC574的CP端接收到上升沿触发到Qn输出的时间参数:

通过时序图和对应的参数要了解到以下几点:

  • tpd传输延迟在这里等效于tPHL和tPLH。

  • V7开发板的74HC574有三片是3.3V供电,另外一片是5V供电。参数表格里面没有给3.3V供电时的参数,也没有最小值。

了解了74HC574,再来看SN74HC02:

通过时序图和对应的参数要了解到以下几点:

  • tpd传输延迟在这里等效于tPHL和tPLH。

  • tt过渡时间等效于tr上升沿时间和tf下降沿时间。

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。