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

本章教程为大家讲解利用STM32H7的FMC总线扩展出32路高速IO,且使用简单,实际项目中也比较有实用价值。

48.1 初学者重要提示

48.2 FMC扩展IO硬件设计

48.3 FMC扩展IO驱动设计

48.4 FMC扩展IO板级支持包(bsp_fmc_io.c)

48.5 FMC扩展IO驱动移植和使用

48.6 实验例程设计框架

48.7 实验例程说明(MDK)

48.8 实验例程说明(IAR)

48.9 总结

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)typedefstruct{

__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的通信时序和数字逻辑芯片的使用,可能会比较懵,下面逐一为大家说明。

有了这个原理图,首先要做的就是了解74HC574和SN74HC02的功能。

74HC574是一款8位三态D触发器,起到锁存的功能,上升沿触发,对应的真值表如下(L表示低电平,H表示高电平,Z表示高阻):

SN74HC02是一款2输入或非门,一个芯片带了四组或非门,对应的真值表如下(L表示低电平,H表示高电平):

有了这个认识后,我们再来看FMC的配置,V7开发板的BSP驱动包里面专门做了一个IO扩展的FMC配置,即文件bsp_fmc_io.c,配置方式是FMC_AccessMode_A,这种模式对应的写时序是:

那么问题来了,我们要实现的功能是通过FMC输出的数据要锁存在扩展IO的输出端,否则FMC时序信号消失了,扩展IO的输出数据也消失了,就起不到控制作用了。所以就用到74HC574的锁存功能,而锁存的实现需要一个上升沿触发,这个上升沿就是通过74HC02输出的。

再结合上面FMC写时序图,在NE片选为低电平,NWE写使能信号为高电平期间,即地址建立时间段ADDSET内,74HC02是输出的低电平。

进入到DATAST数据建立阶段,在NE片选为低电平,NWE写使能信号也为低电平时,74HC02输出高电平,正好是实现1个上升沿的变化,将数据总线上的数据锁存到74HC574的输出端了。这里隐含了一个知识点,数据还没有完全建立起来就锁存是不是会有问题。在下面的3.3小节配置具体时序参数时再为大家说明。

48.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的高低电平即可。

48.3 FMC扩展IO驱动设计

下面将程序设计中的相关问题逐一为大家做个说明。

48.3.1 FMC扩展IO所涉及到的GPIO配置

这里仅需把用到的GPIO时钟、FMC时钟、GPIO引脚和复用配置好即可:

/**********************************************************************************************************

* 函 数 名: 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下降沿时间。

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

对应74HC574和74HC02的时序参数有个了解后,再来看本章2.3小节末尾的问题:

当写使能信号NWE出现下降沿后,74H02或非门就会输出一个上升沿,然后触发74HC574做锁存。此时我们要考虑到一个重要的知识点,就是使用的数字逻辑芯片有个传输延迟问题,也就是要我们要保证74HC02的tpd传输延迟时间 + 74HC02的tr传输延迟时间 + 74HC574的tpd传输延迟时间的这段时间内,数据总线上要有数据,所以保证DATAST数据建立时间够大就行。实际测试FMC频率在200MHz的情况下,2-3个FMC时钟周期就已经可以正常使用。

有了这些认识后,再来看FMC的时序配置就比较好理解了:

1. /*2. ******************************************************************************************************

3. * 函 数 名: HC574_ConfigFMC

4. * 功能说明: 配置FMC并口访问时序

5. * 形 参: 无

6. * 返 回 值: 无

7. ******************************************************************************************************

8.*/

9. static void HC574_ConfigFMC(void)10. {11. SRAM_HandleTypeDef hsram = {0};12. FMC_NORSRAM_TimingTypeDef SRAM_Timing = {0};13.14. hsram.Instance =FMC_NORSRAM_DEVICE;15. hsram.Extended =FMC_NORSRAM_EXTENDED_DEVICE;16.17. /*FMC使用的HCLK3,主频200MHz,1个FMC时钟周期就是5ns*/

18. /*SRAM 总线时序配置 4-1-2-1-2-2 不稳定,5-2-2-1-2-2 稳定*/

19. SRAM_Timing.AddressSetupTime = 5; /*5*5ns=25ns,地址建立时间,范围0 -15个FMC时钟周期个数*/

20. SRAM_Timing.AddressHoldTime = 2; /*地址保持时间,配置为模式A时,用不到此参数 范围1 -15个时

21. 钟周期个数*/

22. SRAM_Timing.DataSetupTime = 2; /*2*5ns=10ns,数据保持时间,范围1 -255个时钟周期个数*/

23. SRAM_Timing.BusTurnAroundDuration = 1; /*此配置用不到这个参数*/

24. SRAM_Timing.CLKDivision = 2; /*此配置用不到这个参数*/

25. SRAM_Timing.DataLatency = 2; /*此配置用不到这个参数*/

26. SRAM_Timing.AccessMode = FMC_ACCESS_MODE_A; /*配置为模式A*/

27.28. hsram.Init.NSBank = FMC_NORSRAM_BANK1; /*使用的BANK1,即使用的片选FMC_NE1*/

29. hsram.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE; /*禁止地址数据复用*/

30. hsram.Init.MemoryType = FMC_MEMORY_TYPE_SRAM; /*存储器类型SRAM*/

31. hsram.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_32; /*32位总线宽度*/

32. hsram.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE; /*关闭突发模式*/

33. hsram.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW; /*用于设置等待信号的极性,关闭突

34. 发模式,此参数无效*/

35. hsram.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS; /*关闭突发模式,此参数无效*/

36. hsram.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE; /*用于使能或者禁止写保护*/

37. hsram.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE; /*关闭突发模式,此参数无效*/

38. hsram.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE; /*禁止扩展模式*/

39. hsram.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE; /*用于异步传输期间,使能或者禁止

40. 等待信号,这里选择关闭*/

41. hsram.Init.WriteBurst = FMC_WRITE_BURST_DISABLE; /*禁止写突发*/

42. hsram.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY; /*仅同步模式才做时钟输出*/

43. hsram.Init.WriteFifo = FMC_WRITE_FIFO_ENABLE; /*使能写FIFO*/

44.45. /*初始化SRAM控制器*/

46. if (HAL_SRAM_Init(&hsram, &SRAM_Timing, &SRAM_Timing) !=HAL_OK)47. {48. /*初始化错误*/

49. Error_Handler(__FILE__, __LINE__);50. }51. }

这里把几个关键的地方阐释下:

第11 - 12行,对作为局部变量的HAL库结构体做初始化,防止不确定值配置时出问题。

第19行,地址建立时间,对于FMC的IO扩展来说,这个地方取值0都可以,因为主要还是ADDST数据建立时间起作用。但是考虑到扩展IO外接了多个控制设备,这里取值5个FMC时钟周期,大家可以根据实际情况做减小出来。

第20行,地址保持时间,对于FMC模式A来说,此参数用不到。

第22行,数据建立时间,实际测试2个FMC时钟周期就可以正常使用,大家可以根据情况加大此数值。

第23 – 25行,当前配置用不到这三个参数。

第28行,使用的BANK1,即使用的片选FMC_NE1。

第31行,由于是扩展的32路IO,所以这里要配置为32位带宽。

48.3.4 MPU配置

实际测试发现,使能FMC_NE1所管理的存储区的Cache功能后,会出现扩展IO的NE片选和NWE信号输出2次的问题。经过各种Cache方式配置、FMC带宽配置、操作FMC时的数据位宽设置,发现禁止了Cache功能就正常了,也就是说,设置FMC_NE1所管理的存储区MPU属性为Device或者Strongly Ordered即可。

/*配置FMC扩展IO的MPU属性为Device或者Strongly Ordered*/MPU_InitStruct.Enable=MPU_REGION_ENABLE;

MPU_InitStruct.BaseAddress= 0x60000000;

MPU_InitStruct.Size=ARM_MPU_REGION_SIZE_64KB;

MPU_InitStruct.AccessPermission=MPU_REGION_FULL_ACCESS;

MPU_InitStruct.IsBufferable=MPU_ACCESS_BUFFERABLE;

MPU_InitStruct.IsCacheable=MPU_ACCESS_NOT_CACHEABLE;

MPU_InitStruct.IsShareable=MPU_ACCESS_NOT_SHAREABLE;

MPU_InitStruct.Number=MPU_REGION_NUMBER1;

MPU_InitStruct.TypeExtField=MPU_TEX_LEVEL0;

MPU_InitStruct.SubRegionDisable= 0x00;

MPU_InitStruct.DisableExec=MPU_INSTRUCTION_ACCESS_ENABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);

MPU配置中直接从FMC_NE1的首地址开始配置,设置了64KB空间的属性。将FMC_NE1通过译码器所管理的所有设备地址全部设置为此配置:

48.3.5 操作数据位宽注意事项

在bsp_fmc_io.c文件开头有个宏定义#define  HC574_PORT  *(uint32_t *)0x60001000。特别注意,这里是要操作地址0x60001000上的32位数据空间,即做了一个强制转换uint32_t *,要跟FMC配置时设置的位宽一致。这样做的原因,在第47章的2.6小节有说明。

48.4 FMC扩展IO板级支持包(bsp_fmc_io.c)

驱动文件bsp_fmc_io.c提供了如下几个函数供用户调用:

bsp_InitExtIO

HC574_SetPin

HC574_TogglePin

HC574_GetPin

48.4.1 函数bsp_InitExtIO

函数原型:

/**********************************************************************************************************

* 函 数 名: bsp_InitExtIO

* 功能说明: 配置扩展IO相关的GPIO. 上电只能执行一次。

* 形 参: 无

* 返 回 值: 无

**********************************************************************************************************/

void bsp_InitExtIO(void)

{

HC574_ConfigGPIO();

HC574_ConfigFMC();/*将开发板一些片选,LED口设置为高*/g_HC574= (NRF24L01_CE | VS1053_XDCS | LED1 | LED2 | LED3 |LED4);

HC574_PORT= g_HC574; /*写硬件端口,更改IO状态*/}

函数描述:

此函数用于初始化FMC扩展IO所用到的GPIO和FMC的参数配置。

使用举例:

作为初始化函数,直接在在bsp.c文件的bsp_Init函数里面调用即可。

48.4.2 函数HC574_SetPin

函数原型:

/**********************************************************************************************************

* 函 数 名: HC574_SetPin

* 功能说明: 设置74HC574端口值

* 形 参: _pin : 管脚号, 0-31; 只能选1个,不能多选

* _value : 设定的值,0或1

* 返 回 值: 无

**********************************************************************************************************/

voidHC574_SetPin(uint32_t _pin, uint8_t _value)

{if (_value == 0)

{

g_HC574&= (~_pin);

}else{

g_HC574|=_pin;

}

HC574_PORT=g_HC574;

}

函数描述:

此函数用于设置扩展IO的输出状态。调用此函数前,要保证调用了函数bsp_InitExtIO进行了初始化。

函数参数:

第1个参数是扩展IO的引脚,支持的形参如下,每次仅支持调用下面1个,不支持多个IO一起操作。

#define GPIO_PIN_0 ((uint16_t)0x0001) /* Pin 0 selected */

#define GPIO_PIN_1 ((uint16_t)0x0002) /* Pin 1 selected */

#define GPIO_PIN_2 ((uint16_t)0x0004) /* Pin 2 selected */

#define GPIO_PIN_3 ((uint16_t)0x0008) /* Pin 3 selected */

#define GPIO_PIN_4 ((uint16_t)0x0010) /* Pin 4 selected */

#define GPIO_PIN_5 ((uint16_t)0x0020) /* Pin 5 selected */

#define GPIO_PIN_6 ((uint16_t)0x0040) /* Pin 6 selected */

#define GPIO_PIN_7 ((uint16_t)0x0080) /* Pin 7 selected */

#define GPIO_PIN_8 ((uint16_t)0x0100) /* Pin 8 selected */

#define GPIO_PIN_9 ((uint16_t)0x0200) /* Pin 9 selected */

#define GPIO_PIN_10 ((uint16_t)0x0400) /* Pin 10 selected */

#define GPIO_PIN_11 ((uint16_t)0x0800) /* Pin 11 selected */

#define GPIO_PIN_12 ((uint16_t)0x1000) /* Pin 12 selected */

#define GPIO_PIN_13 ((uint16_t)0x2000) /* Pin 13 selected */

#define GPIO_PIN_14 ((uint16_t)0x4000) /* Pin 14 selected */

#define GPIO_PIN_15 ((uint16_t)0x8000) /* Pin 15 selected */

#define GPIO_PIN_16 ((uint32_t)0x00010000) /* Pin 16 selected */

#define GPIO_PIN_17 ((uint32_t)0x00020000) /* Pin 17 selected */

#define GPIO_PIN_18 ((uint32_t)0x00040000) /* Pin 18 selected */

#define GPIO_PIN_19 ((uint32_t)0x00080000) /* Pin 19 selected */

#define GPIO_PIN_20 ((uint32_t)0x00100000) /* Pin 20 selected */

#define GPIO_PIN_21 ((uint32_t)0x00200000) /* Pin 21 selected */

#define GPIO_PIN_22 ((uint32_t)0x00400000) /* Pin 22 selected */

#define GPIO_PIN_23 ((uint32_t)0x00800000) /* Pin 23 selected */

#define GPIO_PIN_24 ((uint32_t)0x01000000) /* Pin 24 selected */

#define GPIO_PIN_25 ((uint32_t)0x02000000) /* Pin 25 selected */

#define GPIO_PIN_26 ((uint32_t)0x04000000) /* Pin 26 selected */

#define GPIO_PIN_27 ((uint32_t)0x08000000) /* Pin 27 selected */

#define GPIO_PIN_28 ((uint32_t)0x10000000) /* Pin 28 selected */

#define GPIO_PIN_29 ((uint32_t)0x20000000) /* Pin 29 selected */

#define GPIO_PIN_30 ((uint32_t)0x40000000) /* Pin 30 selected */

#define GPIO_PIN_31 ((uint32_t)0x80000000) /* Pin 31 selected */

第2个参数用于设置指定扩展IO的高低电平,0表示输出低电平,1表示输出高电平。

使用举例:

比如设置扩展IO引脚GPIO_PIN_23为高电平:HC574_SetPin(GPIO_PIN_23, 1)。

48.4.3 函数HC574_TogglePin

函数原型:

/**********************************************************************************************************

* 函 数 名: HC574_TogglePin

* 功能说明: 饭庄74HC574端口值

* 形 参: _pin : 管脚号, 0-31; 只能选1个,不能多选

* 返 回 值: 无

**********************************************************************************************************/

voidHC574_TogglePin(uint32_t _pin)

{if (g_HC574 &_pin)

{

g_HC574&= (~_pin);

}else{

g_HC574|=_pin;

}

HC574_PORT=g_HC574;

}

函数描述:

此函数用于FMC扩展IO的翻转。调用此函数前,要保证调用了函数bsp_InitExtIO进行了初始化。

函数参数:

第1个参数是扩展IO的引脚,支持的形参如下,每次仅支持调用下面1个,不支持多个IO一起操作。

#define GPIO_PIN_0 ((uint16_t)0x0001) /* Pin 0 selected */

#define GPIO_PIN_1 ((uint16_t)0x0002) /* Pin 1 selected */

#define GPIO_PIN_2 ((uint16_t)0x0004) /* Pin 2 selected */

#define GPIO_PIN_3 ((uint16_t)0x0008) /* Pin 3 selected */

#define GPIO_PIN_4 ((uint16_t)0x0010) /* Pin 4 selected */

#define GPIO_PIN_5 ((uint16_t)0x0020) /* Pin 5 selected */

#define GPIO_PIN_6 ((uint16_t)0x0040) /* Pin 6 selected */

#define GPIO_PIN_7 ((uint16_t)0x0080) /* Pin 7 selected */

#define GPIO_PIN_8 ((uint16_t)0x0100) /* Pin 8 selected */

#define GPIO_PIN_9 ((uint16_t)0x0200) /* Pin 9 selected */

#define GPIO_PIN_10 ((uint16_t)0x0400) /* Pin 10 selected */

#define GPIO_PIN_11 ((uint16_t)0x0800) /* Pin 11 selected */

#define GPIO_PIN_12 ((uint16_t)0x1000) /* Pin 12 selected */

#define GPIO_PIN_13 ((uint16_t)0x2000) /* Pin 13 selected */

#define GPIO_PIN_14 ((uint16_t)0x4000) /* Pin 14 selected */

#define GPIO_PIN_15 ((uint16_t)0x8000) /* Pin 15 selected */

#define GPIO_PIN_16 ((uint32_t)0x00010000) /* Pin 16 selected */

#define GPIO_PIN_17 ((uint32_t)0x00020000) /* Pin 17 selected */

#define GPIO_PIN_18 ((uint32_t)0x00040000) /* Pin 18 selected */

#define GPIO_PIN_19 ((uint32_t)0x00080000) /* Pin 19 selected */

#define GPIO_PIN_20 ((uint32_t)0x00100000) /* Pin 20 selected */

#define GPIO_PIN_21 ((uint32_t)0x00200000) /* Pin 21 selected */

#define GPIO_PIN_22 ((uint32_t)0x00400000) /* Pin 22 selected */

#define GPIO_PIN_23 ((uint32_t)0x00800000) /* Pin 23 selected */

#define GPIO_PIN_24 ((uint32_t)0x01000000) /* Pin 24 selected */

#define GPIO_PIN_25 ((uint32_t)0x02000000) /* Pin 25 selected */

#define GPIO_PIN_26 ((uint32_t)0x04000000) /* Pin 26 selected */

#define GPIO_PIN_27 ((uint32_t)0x08000000) /* Pin 27 selected */

#define GPIO_PIN_28 ((uint32_t)0x10000000) /* Pin 28 selected */

#define GPIO_PIN_29 ((uint32_t)0x20000000) /* Pin 29 selected */

#define GPIO_PIN_30 ((uint32_t)0x40000000) /* Pin 30 selected */

#define GPIO_PIN_31 ((uint32_t)0x80000000) /* Pin 31 selected */

使用举例:

比如翻转扩展IO引脚GPIO_PIN_23为高电平:HC574_TogglePin(GPIO_PIN_23)。

48.4.4 函数HC574_GetPin

函数原型:

/**********************************************************************************************************

* 函 数 名: HC574_GetPin

* 功能说明: 判断指定的管脚输出是1还是0

* 形 参: _pin : 管脚号, 0-31; 只能选1个,不能多选

* 返 回 值: 0或1

**********************************************************************************************************/uint8_t HC574_GetPin(uint32_t _pin)

{if (g_HC574 &_pin)

{return 1;

}else{return 0;

}

}

函数描述:

此函数用于读取FMC扩展IO的状态。调用此函数前,要保证调用了函数bsp_InitExtIO进行了初始化。

函数参数:

第1个参数是扩展IO的引脚,支持的形参如下,每次仅支持调用下面1个,不支持多个IO一起操作。

#define GPIO_PIN_0 ((uint16_t)0x0001) /* Pin 0 selected */

#define GPIO_PIN_1 ((uint16_t)0x0002) /* Pin 1 selected */

#define GPIO_PIN_2 ((uint16_t)0x0004) /* Pin 2 selected */

#define GPIO_PIN_3 ((uint16_t)0x0008) /* Pin 3 selected */

#define GPIO_PIN_4 ((uint16_t)0x0010) /* Pin 4 selected */

#define GPIO_PIN_5 ((uint16_t)0x0020) /* Pin 5 selected */

#define GPIO_PIN_6 ((uint16_t)0x0040) /* Pin 6 selected */

#define GPIO_PIN_7 ((uint16_t)0x0080) /* Pin 7 selected */

#define GPIO_PIN_8 ((uint16_t)0x0100) /* Pin 8 selected */

#define GPIO_PIN_9 ((uint16_t)0x0200) /* Pin 9 selected */

#define GPIO_PIN_10 ((uint16_t)0x0400) /* Pin 10 selected */

#define GPIO_PIN_11 ((uint16_t)0x0800) /* Pin 11 selected */

#define GPIO_PIN_12 ((uint16_t)0x1000) /* Pin 12 selected */

#define GPIO_PIN_13 ((uint16_t)0x2000) /* Pin 13 selected */

#define GPIO_PIN_14 ((uint16_t)0x4000) /* Pin 14 selected */

#define GPIO_PIN_15 ((uint16_t)0x8000) /* Pin 15 selected */

#define GPIO_PIN_16 ((uint32_t)0x00010000) /* Pin 16 selected */

#define GPIO_PIN_17 ((uint32_t)0x00020000) /* Pin 17 selected */

#define GPIO_PIN_18 ((uint32_t)0x00040000) /* Pin 18 selected */

#define GPIO_PIN_19 ((uint32_t)0x00080000) /* Pin 19 selected */

#define GPIO_PIN_20 ((uint32_t)0x00100000) /* Pin 20 selected */

#define GPIO_PIN_21 ((uint32_t)0x00200000) /* Pin 21 selected */

#define GPIO_PIN_22 ((uint32_t)0x00400000) /* Pin 22 selected */

#define GPIO_PIN_23 ((uint32_t)0x00800000) /* Pin 23 selected */

#define GPIO_PIN_24 ((uint32_t)0x01000000) /* Pin 24 selected */

#define GPIO_PIN_25 ((uint32_t)0x02000000) /* Pin 25 selected */

#define GPIO_PIN_26 ((uint32_t)0x04000000) /* Pin 26 selected */

#define GPIO_PIN_27 ((uint32_t)0x08000000) /* Pin 27 selected */

#define GPIO_PIN_28 ((uint32_t)0x10000000) /* Pin 28 selected */

#define GPIO_PIN_29 ((uint32_t)0x20000000) /* Pin 29 selected */

#define GPIO_PIN_30 ((uint32_t)0x40000000) /* Pin 30 selected */

#define GPIO_PIN_31 ((uint32_t)0x80000000) /* Pin 31 selected */

返回值,返回0表示低电平,返回1表示高电平。

使用举例:

比如获取扩展IO的GPIO_PIN_23高低电平状态,调用函数HC574_GetPin(GPIO_PIN_23)获取即可。

48.5 FMC扩展IO驱动移植和使用

扩展IO的移植比较方便:

第1步:复制bsp_fmc_io.c和bsp_fmc_io.h到自己的工程目录,并添加到工程里面。

第2步:这几个驱动文件主要用到HAL库的GPIO和FMC驱动文件,简单省事些可以添加所有HAL库.C源文件进来。

第3步,应用方法看本章节配套例子即可,另外就是根据自己的需要做配置修改。

48.6 实验例程设计框架

通过程序设计框架,让大家先对配套例程有一个全面的认识,然后再理解细节,本次实验例程的设计框架如下:

第1阶段,上电启动阶段:

这部分在第14章进行了详细说明。

第2阶段,进入main函数:

第1步,硬件初始化,主要是MPU,Cache,HAL库,系统时钟,滴答定时器,LED和串口。

第2步,按键应用程序设计部分。定时器中断服务程序里面实现翻转FMC扩展引脚20和23。

48.7 实验例程说明(MDK)

配套例子:

V7-027-FMC总线扩展32路高速IO

实验目的:

学习FMC总线扩展32路高速IO。

实验内容:

系统上电后驱动了1个软件定时器,每100ms翻转一次LED2。

启动1个TIM6周期性中断,频率10KHz,在中断服务程序里面翻转FMC扩展引脚20和23。

实验操作:

K1按键按下,开启TIM6的周期性中断。

K2按键按下,关闭TIM6的周期性中断。

FMC扩展引脚20和23的位置:

上电后串口打印的信息:

波特率 115200,数据位 8,奇偶校验位无,停止位 1

程序设计:

系统栈大小分配:

RAM空间用的DTCM:

硬件外设初始化

硬件外设的初始化是在 bsp.c 文件实现:

/**********************************************************************************************************

* 函 数 名: bsp_Init

* 功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次

* 形 参:无

* 返 回 值: 无

**********************************************************************************************************/

void bsp_Init(void)

{/*配置MPU*/MPU_Config();/*使能L1 Cache*/CPU_CACHE_Enable();/*STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:

- 调用函数HAL_InitTick,初始化滴答时钟中断1ms。

- 设置NVIV优先级分组为4。*/HAL_Init();/*配置系统时钟到400MHz

- 切换使用HSE。

- 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。*/SystemClock_Config();/*Event Recorder:

- 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。

- 默认不开启,如果要使能此选项,务必看V7开发板用户手册第xx章*/

#if Enable_EventRecorder == 1

/*初始化EventRecorder并开启*/EventRecorderInitialize(EventRecordAll,1U);

EventRecorderStart();#endifbsp_InitKey();/*按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描*/bsp_InitTimer();/*初始化滴答定时器*/bsp_InitUart();/*初始化串口*/bsp_InitExtIO();/*初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行*/bsp_InitLed();/*初始化LED*/}

MPU配置和Cache配置:

数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM)和FMC的扩展IO区。

/**********************************************************************************************************

* 函 数 名: MPU_Config

* 功能说明: 配置MPU

* 形 参: 无

* 返 回 值: 无

**********************************************************************************************************/

static void MPU_Config( void)

{

MPU_Region_InitTypeDef MPU_InitStruct;/*禁止 MPU*/HAL_MPU_Disable();/*配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate*/MPU_InitStruct.Enable=MPU_REGION_ENABLE;

MPU_InitStruct.BaseAddress= 0x24000000;

MPU_InitStruct.Size=MPU_REGION_SIZE_512KB;

MPU_InitStruct.AccessPermission=MPU_REGION_FULL_ACCESS;

MPU_InitStruct.IsBufferable=MPU_ACCESS_BUFFERABLE;

MPU_InitStruct.IsCacheable=MPU_ACCESS_CACHEABLE;

MPU_InitStruct.IsShareable=MPU_ACCESS_NOT_SHAREABLE;

MPU_InitStruct.Number=MPU_REGION_NUMBER0;

MPU_InitStruct.TypeExtField=MPU_TEX_LEVEL1;

MPU_InitStruct.SubRegionDisable= 0x00;

MPU_InitStruct.DisableExec=MPU_INSTRUCTION_ACCESS_ENABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);/*配置FMC扩展IO的MPU属性为Device或者Strongly Ordered*/MPU_InitStruct.Enable=MPU_REGION_ENABLE;

MPU_InitStruct.BaseAddress= 0x60000000;

MPU_InitStruct.Size=ARM_MPU_REGION_SIZE_64KB;

MPU_InitStruct.AccessPermission=MPU_REGION_FULL_ACCESS;

MPU_InitStruct.IsBufferable=MPU_ACCESS_BUFFERABLE;

MPU_InitStruct.IsCacheable=MPU_ACCESS_NOT_CACHEABLE;

MPU_InitStruct.IsShareable=MPU_ACCESS_NOT_SHAREABLE;

MPU_InitStruct.Number=MPU_REGION_NUMBER1;

MPU_InitStruct.TypeExtField=MPU_TEX_LEVEL0;

MPU_InitStruct.SubRegionDisable= 0x00;

MPU_InitStruct.DisableExec=MPU_INSTRUCTION_ACCESS_ENABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);/*使能 MPU*/HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

}/**********************************************************************************************************

* 函 数 名: CPU_CACHE_Enable

* 功能说明: 使能L1 Cache

* 形 参: 无

* 返 回 值: 无

**********************************************************************************************************/

static void CPU_CACHE_Enable(void)

{/*使能 I-Cache*/SCB_EnableICache();/*使能 D-Cache*/SCB_EnableDCache();

}

主功能:

主程序实现如下操作:

K1按键按下,开启TIM6的周期性中断。

K2按键按下,关闭TIM6的周期性中断。

/**********************************************************************************************************

* 函 数 名: main

* 功能说明: c程序入口

* 形 参: 无

* 返 回 值: 错误代码(无需处理)

**********************************************************************************************************/

int main(void)

{

uint8_t ucKeyCode;/*按键代码*/bsp_Init();/*硬件初始化*/PrintfLogo();/*打印例程名称和版本等信息*/PrintfHelp();/*打印操作提示*/bsp_StartAutoTimer(0, 100); /*启动1个100ms的自动重装的定时器*/bsp_SetTIMforInt(TIM6,10000, 2, 0); /*设置为10KHz频率定时器中断*/

/*进入主程序循环体*/

while (1)

{

bsp_Idle();/*这个函数在bsp.c文件。用户可以修改这个函数实现CPU休眠和喂狗*/

/*判断定时器超时时间*/

if (bsp_CheckTimer(0))

{/*每隔100ms 进来一次*/bsp_LedToggle(2);

}/*按键滤波和检测由后台systick中断服务程序实现,我们只需要调用bsp_GetKey读取键值即可。*/ucKeyCode= bsp_GetKey(); /*读取键值, 无键按下时返回 KEY_NONE = 0*/

if (ucKeyCode !=KEY_NONE)

{switch(ucKeyCode)

{case KEY_DOWN_K1: /*K1键按下,开启TIM6的周期性中断*/TIM6->DIER |=TIM_IT_UPDATE;break;case KEY_DOWN_K2: /*K2键按下,关闭TIM6的周期性中断*/TIM6->DIER &= ~TIM_IT_UPDATE;break;default:/*其它的键值不处理*/

break;

}

}

}

}

定时器6中断服务程序:

/**********************************************************************************************************

* 函 数 名: TIM6_DAC_IRQHandler

* 功能说明: TIM6定时中断服务程序

* 返 回 值: 无

**********************************************************************************************************/

void TIM6_DAC_IRQHandler(void)

{if((TIM6->SR & TIM_FLAG_UPDATE) !=RESET)

{/*清除更新标志*/TIM6->SR = ~TIM_FLAG_UPDATE;/*翻转FMC扩展引脚20和23脚*/HC574_TogglePin(GPIO_PIN_23);

HC574_TogglePin(GPIO_PIN_20);

}

}

48.8 实验例程说明(IAR)

配套例子:

V7-027-FMC总线扩展32路高速IO

实验目的:

学习FMC总线扩展32路高速IO。

实验内容:

系统上电后驱动了1个软件定时器,每100ms翻转一次LED2。

启动1个TIM6周期性中断,频率10KHz,在中断服务程序里面翻转FMC扩展引脚20和23。

实验操作:

K1按键按下,开启TIM6的周期性中断。

K2按键按下,关闭TIM6的周期性中断。

FMC扩展引脚20和23的位置:

上电后串口打印的信息:

波特率 115200,数据位 8,奇偶校验位无,停止位 1

程序设计:

系统栈大小分配:

RAM空间用的DTCM:

硬件外设初始化

硬件外设的初始化是在 bsp.c 文件实现:

/**********************************************************************************************************

* 函 数 名: bsp_Init

* 功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次

* 形 参:无

* 返 回 值: 无

**********************************************************************************************************/

void bsp_Init(void)

{/*配置MPU*/MPU_Config();/*使能L1 Cache*/CPU_CACHE_Enable();/*STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:

- 调用函数HAL_InitTick,初始化滴答时钟中断1ms。

- 设置NVIV优先级分组为4。*/HAL_Init();/*配置系统时钟到400MHz

- 切换使用HSE。

- 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。*/SystemClock_Config();/*Event Recorder:

- 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。

- 默认不开启,如果要使能此选项,务必看V7开发板用户手册第xx章*/

#if Enable_EventRecorder == 1

/*初始化EventRecorder并开启*/EventRecorderInitialize(EventRecordAll,1U);

EventRecorderStart();#endifbsp_InitKey();/*按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描*/bsp_InitTimer();/*初始化滴答定时器*/bsp_InitUart();/*初始化串口*/bsp_InitExtIO();/*初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行*/bsp_InitLed();/*初始化LED*/}

MPU配置和Cache配置:

数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM)和FMC的扩展IO区。

/**********************************************************************************************************

* 函 数 名: MPU_Config

* 功能说明: 配置MPU

* 形 参: 无

* 返 回 值: 无

**********************************************************************************************************/

static void MPU_Config( void)

{

MPU_Region_InitTypeDef MPU_InitStruct;/*禁止 MPU*/HAL_MPU_Disable();/*配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate*/MPU_InitStruct.Enable=MPU_REGION_ENABLE;

MPU_InitStruct.BaseAddress= 0x24000000;

MPU_InitStruct.Size=MPU_REGION_SIZE_512KB;

MPU_InitStruct.AccessPermission=MPU_REGION_FULL_ACCESS;

MPU_InitStruct.IsBufferable=MPU_ACCESS_BUFFERABLE;

MPU_InitStruct.IsCacheable=MPU_ACCESS_CACHEABLE;

MPU_InitStruct.IsShareable=MPU_ACCESS_NOT_SHAREABLE;

MPU_InitStruct.Number=MPU_REGION_NUMBER0;

MPU_InitStruct.TypeExtField=MPU_TEX_LEVEL1;

MPU_InitStruct.SubRegionDisable= 0x00;

MPU_InitStruct.DisableExec=MPU_INSTRUCTION_ACCESS_ENABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);/*配置FMC扩展IO的MPU属性为Device或者Strongly Ordered*/MPU_InitStruct.Enable=MPU_REGION_ENABLE;

MPU_InitStruct.BaseAddress= 0x60000000;

MPU_InitStruct.Size=ARM_MPU_REGION_SIZE_64KB;

MPU_InitStruct.AccessPermission=MPU_REGION_FULL_ACCESS;

MPU_InitStruct.IsBufferable=MPU_ACCESS_BUFFERABLE;

MPU_InitStruct.IsCacheable=MPU_ACCESS_NOT_CACHEABLE;

MPU_InitStruct.IsShareable=MPU_ACCESS_NOT_SHAREABLE;

MPU_InitStruct.Number=MPU_REGION_NUMBER1;

MPU_InitStruct.TypeExtField=MPU_TEX_LEVEL0;

MPU_InitStruct.SubRegionDisable= 0x00;

MPU_InitStruct.DisableExec=MPU_INSTRUCTION_ACCESS_ENABLE;

HAL_MPU_ConfigRegion(&MPU_InitStruct);/*使能 MPU*/HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

}/**********************************************************************************************************

* 函 数 名: CPU_CACHE_Enable

* 功能说明: 使能L1 Cache

* 形 参: 无

* 返 回 值: 无

**********************************************************************************************************/

static void CPU_CACHE_Enable(void)

{/*使能 I-Cache*/SCB_EnableICache();/*使能 D-Cache*/SCB_EnableDCache();

}

主功能:

主程序实现如下操作:

K1按键按下,开启TIM6的周期性中断。

K2按键按下,关闭TIM6的周期性中断。

/**********************************************************************************************************

* 函 数 名: main

* 功能说明: c程序入口

* 形 参: 无

* 返 回 值: 错误代码(无需处理)

**********************************************************************************************************/

int main(void)

{

uint8_t ucKeyCode;/*按键代码*/bsp_Init();/*硬件初始化*/PrintfLogo();/*打印例程名称和版本等信息*/PrintfHelp();/*打印操作提示*/bsp_StartAutoTimer(0, 100); /*启动1个100ms的自动重装的定时器*/bsp_SetTIMforInt(TIM6,10000, 2, 0); /*设置为10KHz频率定时器中断*/

/*进入主程序循环体*/

while (1)

{

bsp_Idle();/*这个函数在bsp.c文件。用户可以修改这个函数实现CPU休眠和喂狗*/

/*判断定时器超时时间*/

if (bsp_CheckTimer(0))

{/*每隔100ms 进来一次*/bsp_LedToggle(2);

}/*按键滤波和检测由后台systick中断服务程序实现,我们只需要调用bsp_GetKey读取键值即可。*/ucKeyCode= bsp_GetKey(); /*读取键值, 无键按下时返回 KEY_NONE = 0*/

if (ucKeyCode !=KEY_NONE)

{switch(ucKeyCode)

{case KEY_DOWN_K1: /*K1键按下,开启TIM6的周期性中断*/TIM6->DIER |=TIM_IT_UPDATE;break;case KEY_DOWN_K2: /*K2键按下,关闭TIM6的周期性中断*/TIM6->DIER &= ~TIM_IT_UPDATE;break;default:/*其它的键值不处理*/

break;

}

}

}

}

定时器6中断服务程序:

/**********************************************************************************************************

* 函 数 名: TIM6_DAC_IRQHandler

* 功能说明: TIM6定时中断服务程序

* 返 回 值: 无

**********************************************************************************************************/

void TIM6_DAC_IRQHandler(void)

{if((TIM6->SR & TIM_FLAG_UPDATE) !=RESET)

{/*清除更新标志*/TIM6->SR = ~TIM_FLAG_UPDATE;/*翻转FMC扩展引脚20和23脚*/HC574_TogglePin(GPIO_PIN_23);

HC574_TogglePin(GPIO_PIN_20);

}

}

48.9 总结

本章节就为大家讲解这么多,由于FMC总线可以扩展出32路高速IO且使用简单,所以实际项目中也比较有实用价值,望初学者熟练掌握。

stm32h7高速通信_【STM32H7教程】第48章 STM32H7的FMC总线应用之是32路高速IO扩展相关推荐

  1. stm32h7高速通信_【STM32H7教程】第75章 STM32H7的SPI总线应用之驱动DAC8501(双路输出,16bit分辨率,0-5V)...

    第75章       STM32H7的SPI总线应用之驱动DAC8501(双路输出,16bit分辨率,0-5V) 本章节为大家讲解标准SPI接线方式驱动模数转换器DAC8501,制作了中断和DMA两种 ...

  2. 0.96寸_OLED_屏幕_SSD1306_IIC通信_入门教程_指令详解_驱动介绍_笔记分享_初学者易懂

    目录 一.简介 1:总结 2:屏幕介绍 二.基本使用流程 1_介绍: 2_流程:(省略了应答) 三.指令集 1.基础指令 1:设置对比度(亮度)(81H + A[7:0]) 2:设置全屏全亮(A4H. ...

  3. 用python做一个上位机串口通信_【教程】简易Python上位机之LED控制

    电子爱好者应该不会对"上位机"这个词感到陌生,毕竟或多或少有过接触.但若是说到上位机的开发的话,大家就不一定熟悉了.很多电子爱好者完全没有接触过上位机的开发工作,他们真的没有相应的 ...

  4. 【STM32H7教程】第76章 STM32H7的FMC总线应用之驱动AD7606(8通道同步采样, 16bit, 正负10V)

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第76章       STM32H7的FMC总线应用之驱动AD ...

  5. 【STM32H7教程】第94章 STM32H7的SPI总线应用之双机通信(DMA方式)

    完整教程下载地址:链接 第94章       STM32H7的SPI总线应用之双机通信(DMA方式) 本章节为大家讲解SPI DMA方式双机通信. 目录 94.1 初学者重要提示 94.2 SPI D ...

  6. stm32h7关串口中断怎么弄_【STM32H7教程】第33章 STM32H7的定时器应用之TIM1-TIM17的中断实现...

    第33章       STM32H7的定时器应用之TIM1-TIM17的中断实现 本章教程为大家讲解定时器应用之TIM1 – TIM17所有定时器的周期性中断实现.实际项目中用到的地方较多,特别是周期 ...

  7. stm32h7内存分配_【STM32H7教程】第25章 STM32H7的TCM,SRAM等五塊內存基礎知識

    第25章       STM32H7的TCM,SRAM等五塊內存基礎知識 本章教程為大家介紹STM32H7帶的ITCM,DTCM,AXI SRAM,SRAM1,SRAM2,SRAM3,SRAM4和備份 ...

  8. stm32h7内存分配_【STM32H7教程】第9章 STM32H7重要知识点数据类型,变量和堆栈...

    第9章   STM32H7重要知识点数据类型,变量和堆栈 本章教程为大家介绍数据类型,变量和堆栈的相关知识. 9.1 初学者重要提示 9.2 数据类型 9.3 局部变量和全局变量 9.4 堆栈 9.5 ...

  9. stm32h7内存分配_【STM32H7教程】第26章 STM32H7的TCM,SRAM等五块内存的超方便使用方式...

    第26章       STM32H7的TCM,SRAM等五块内存的超方便使用方式 本章教程为大家分享一种快捷的DTCM,SRAM1,SRAM2,SRAM3和SRAM4的使用方式.MDK和IAR均支持这 ...

最新文章

  1. js在上传图片前判断大小
  2. 动态给组件添加背景,一半圆角
  3. python正则去除换行符,关于python:用于删除换行符的正则表达式
  4. C语言之数组探究(一):定义、大小、初始化、访问和三要素
  5. Ubuntu安装OpenTSDB
  6. PostgreSQL监控指标
  7. JS — 数组去重(4种方法)
  8. web安全day4--DHCP部署与安全
  9. 弹簧管压力表设计报告
  10. 小鹤双拼入门和小鹤音形的搜狗输入法配置方法
  11. LPVOID 指针 转 int
  12. 在用mybatis时报错java.lang.AbstractMethodError: com.mysql.jdbc.ServerPreparedState
  13. 微信小程序--引用外部字体(云开发实现)
  14. 互联网公司的裁员,能玩出多少种花样?
  15. 基于单片机的智能花盆
  16. OSChina 周四乱弹 ——潘金莲告西门庆
  17. win 10 hosts 文件位置
  18. C#如何获取本机网络ip地址
  19. 2019.04.12 Head First
  20. Salesforce低代码平台底层架构设计原理一:多租户与元数据驱动的概念

热门文章

  1. IOT语义互操作性之本体论
  2. Excel/Word 插入图表 InvokeMember设置图表类型
  3. 【C基础练习题】Week9:凯撒密码 | 按空格切分字符串 | 单词折半拆分
  4. kronecker delta函数
  5. 清华计算机录取通知书,清华送出第一批录取通知书,这些被刷屏的学霸,有怎样的成长密码...
  6. vue滑杆_Vue无限滑杆组件
  7. java 计算器 junit测试_Java Junit测试
  8. PHP自学教程之PHP语法基础
  9. 无线安全渗透测试套件WiFi-Pumpkin新版本发布
  10. Kubernetes 二进制安装详细步骤