本帖最后由 正点原子运营 于 2024-5-13 11:08 编辑
1)实验平台:正点原子 M144Z-M3 STM32F103最小系统板
2) 章节摘自【正点原子】M144Z-M3最小系统板使用指南——STM32F103版
3)购买链接:https://detail.tmall.com/item.htm?&id=609293737870
4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boar ... _mini_sysboard.html
5)正点原子官方B站:https://space.bilibili.com/394620890
6)正点原子STM32技术交流QQ群:725095144
本章将介绍使用STM32F103驱动SRAM进行SRAM的数据读写。通过本章的学习,读者将学习到EMMC中SMC的使用。 本章分为如下几个小节: 44.1 硬件设计 44.2 程序设计 44.3 下载验证
44.1 硬件设计 44.1.1 例程功能 1. 程序运行后,可通过按下KEY0和KEY_UP按键,分别进行SRAM的容量和数据测试,测试结果将在LCD上显示 2. 可通过USMART对外部SRAM进行数据读写的测试操作 3. LED0闪烁,指示程序正在运行
44.1.2 硬件资源 1. LED LED0 -PB5 2. 按键 WKUP - PA0 KEY0 - PE4 3. USART1(PA9、PA10连接至板载USB转串口芯片上) 4. 正点原子 2.8/3.5/4.3/7/10寸TFTLCD模块(仅限MCU屏,16位8080并口驱动) 5. 外部SRAM(FSMC驱动)
44.1.3 原理图 本章实验使用了一个板载的SRAM芯片,该SRAM芯片通过MCU的FSMC接口与MCU进行连接,该SRAM与MCU的连接原理图,如下图所示: 44.2 程序设计 44.2.1 HAL库的FSMC驱动 本章实验通过FSMC驱动SRAM芯片,通过FSMC可以将外部SRAM芯片的数据访问映射成一段内存空间,通过访问这段内存空间,即可访问SRAM芯片中的数据,因此需要对FSMC做相应的配置,FSMC的配置方式,请读者查看第25.2.1小节中HAL库的FSMC驱动中相关的内容。
44.2.2 SRAM驱动 本章实验的SRAM驱动主要负责向应用层提供SRAM的初始化函数,因为SRAM在初始化后,SRAM将被映射为一段内存空间,对SRAM的访问操作就是访问这段内存空间。本章实验中,SRAM的驱动代码包括sram.c和sram.h两个文件。 由于SRAM需要使用大量的GPIO引脚,因此对于GPIO的相关定义,请读者自行查看sram.c和sram.h这两个文件。 SRAM驱动中,SRAM的初始化函数,如下所示: - /**
- *@brief 初始化外部SRAM
- *@param 无
- *@retval 无
- */
- void sram_init(void)
- {
- GPIO_InitTypeDef GPIO_Initure;
- FSMC_NORSRAM_TimingTypeDef fsmc_readwritetim;
-
- SRAM_CS_GPIO_CLK_ENABLE();
- SRAM_WR_GPIO_CLK_ENABLE();
- SRAM_RD_GPIO_CLK_ENABLE();
- __HAL_RCC_FSMC_CLK_ENABLE();
- __HAL_RCC_GPIOD_CLK_ENABLE();
- __HAL_RCC_GPIOE_CLK_ENABLE();
- __HAL_RCC_GPIOF_CLK_ENABLE();
- __HAL_RCC_GPIOG_CLK_ENABLE();
-
- GPIO_Initure.Pin =SRAM_CS_GPIO_PIN;
- GPIO_Initure.Mode =GPIO_MODE_AF_PP;
- GPIO_Initure.Pull = GPIO_PULLUP;
- GPIO_Initure.Speed =GPIO_SPEED_FREQ_HIGH;
- HAL_GPIO_Init(SRAM_CS_GPIO_PORT, &GPIO_Initure);
-
- GPIO_Initure.Pin =SRAM_WR_GPIO_PIN;
- HAL_GPIO_Init(SRAM_WR_GPIO_PORT, &GPIO_Initure);
-
- GPIO_Initure.Pin =SRAM_RD_GPIO_PIN;
- HAL_GPIO_Init(SRAM_RD_GPIO_PORT, &GPIO_Initure);
-
- /* PD0,1,4,5,8~15 */
- GPIO_Initure.Pin =GPIO_PIN_0 |
- GPIO_PIN_1 |
- GPIO_PIN_8 |
- GPIO_PIN_9 |
- GPIO_PIN_10 |
- GPIO_PIN_11 |
- GPIO_PIN_12 |
- GPIO_PIN_13 |
- GPIO_PIN_14 |
- GPIO_PIN_15;
- GPIO_Initure.Mode =GPIO_MODE_AF_PP;
- GPIO_Initure.Pull = GPIO_PULLUP;
- GPIO_Initure.Speed =GPIO_SPEED_FREQ_HIGH;
- HAL_GPIO_Init(GPIOD, &GPIO_Initure);
-
- /* PE0,1,7~15 */
- GPIO_Initure.Pin =GPIO_PIN_0 |
- GPIO_PIN_1 |
- 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_Initure);
-
- /* PF0~5,12~15 */
- GPIO_Initure.Pin =GPIO_PIN_0 |
- GPIO_PIN_1 |
- GPIO_PIN_2 |
- GPIO_PIN_3 |
- GPIO_PIN_4 |
- GPIO_PIN_5 |
- GPIO_PIN_12 |
- GPIO_PIN_13 |
- GPIO_PIN_14 |
- GPIO_PIN_15;
- HAL_GPIO_Init(GPIOF, &GPIO_Initure);
-
- /* PG0~5,10 */
- GPIO_Initure.Pin = GPIO_PIN_0 |
- GPIO_PIN_1 |
- GPIO_PIN_2 |
- GPIO_PIN_3 |
- GPIO_PIN_4 |
- GPIO_PIN_5;
- HAL_GPIO_Init(GPIOG, &GPIO_Initure);
-
- g_sram_handler.Instance =FSMC_NORSRAM_DEVICE;
- g_sram_handler.Extended =FSMC_NORSRAM_EXTENDED_DEVICE;
-
- g_sram_handler.Init.NSBank = (SRAM_FSMC_NEX == 1) ? FSMC_NORSRAM_BANK1 : \
- (SRAM_FSMC_NEX == 2) ? FSMC_NORSRAM_BANK2 : \
- (SRAM_FSMC_NEX == 3) ? FSMC_NORSRAM_BANK3 :
- FSMC_NORSRAM_BANK4;
- g_sram_handler.Init.DataAddressMux=FSMC_DATA_ADDRESS_MUX_DISABLE;
- g_sram_handler.Init.MemoryType =FSMC_MEMORY_TYPE_SRAM;
- g_sram_handler.Init.MemoryDataWidth=FSMC_NORSRAM_MEM_BUS_WIDTH_16;
- g_sram_handler.Init.BurstAccessMode=FSMC_BURST_ACCESS_MODE_DISABLE;
- g_sram_handler.Init.WaitSignalPolarity=FSMC_WAIT_SIGNAL_POLARITY_LOW;
- g_sram_handler.Init.WaitSignalActive=FSMC_WAIT_TIMING_BEFORE_WS;
- g_sram_handler.Init.WriteOperation=FSMC_WRITE_OPERATION_ENABLE;
- g_sram_handler.Init.WaitSignal =FSMC_WAIT_SIGNAL_DISABLE;
- g_sram_handler.Init.ExtendedMode =FSMC_EXTENDED_MODE_DISABLE;
- g_sram_handler.Init.AsynchronousWait=FSMC_ASYNCHRONOUS_WAIT_DISABLE;
- g_sram_handler.Init.WriteBurst =FSMC_WRITE_BURST_DISABLE;
- /* FMC读时序控制寄存器 */
- fsmc_readwritetim.AddressSetupTime = 0x00;
- fsmc_readwritetim.AddressHoldTime = 0x00;
- fsmc_readwritetim.DataSetupTime = 0x01;
- fsmc_readwritetim.BusTurnAroundDuration = 0X00;
- fsmc_readwritetim.AccessMode = FSMC_ACCESS_MODE_A;
- HAL_SRAM_Init(&g_sram_handler, &fsmc_readwritetim, &fsmc_readwritetim);
- }
复制代码从原理图中可以看到,SRAM芯片的CE引脚连接到了PG10引脚(FSMC_NE3信号),因此在进行SRAM初始化后,SRAM映射的内存基地址为0x68000000,访问SRAM中存储的数据仅需访问0x68000000加上数据偏移后的地址即可。
44.2.3 实验应用代码 本章实验的应用代码,如下所示: - /* 定义测试数组
- * 起始地址为SRAM_BASE_ADDR
- */
- uint32_t g_test_buffer[250000]__attribute__((at(SRAM_BASE_ADDR)));
- int main(void)
- {
- uint8_t key;
- uint8_t i = 0;
- uint32_t ts = 0;
-
- HAL_Init(); /* 初始化HAL库 */
- sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
- delay_init(72); /* 延时初始化 */
- usart_init(115200); /* 串口初始化为115200 */
- usmart_dev.init(72); /* 初始化USMART */
- led_init(); /* 初始化LED */
- lcd_init(); /* 初始化LCD */
- key_init(); /* 初始化按键 */
- sram_init(); /* SRAM初始化 */
-
- lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
- lcd_show_string(30, 70, 200, 16, 16, "SRAM TEST", RED);
- lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
- lcd_show_string(30, 110, 200, 16, 16, "KEY0:TestSram", RED);
- lcd_show_string(30, 130, 200, 16, 16, "KEY_UP:TESTData", RED);
-
- for (ts = 0; ts < 250000; ts++)
- {
- g_test_buffer[ts] = ts; /* 预存测试数据 */
- }
-
- while (1)
- {
- key = key_scan(0); /* 不支持连按 */
-
- if (key == KEY0_PRES)
- {
- fsmc_sram_test(30, 150); /* 测试SRAM容量 */
- }
- else if (key == WKUP_PRES) /* 打印预存测试数据 */
- {
- for (ts = 0; ts < 250000; ts++)
- {
- lcd_show_xnum(30, 170, g_test_buffer[ts], 6, 16, 0, BLUE);
- }
- }
- else
- {
- delay_ms(10);
- }
-
- i++;
-
- if (i == 20)
- {
- i = 0;
- LED0_TOGGLE();
- }
- }
- }
复制代码可以看到,应用代码中定义了一个起始地址为SRAM_BASE_ADDR的数组,SRAM_BASE_ADDR是在sram.h文件中的一个宏定义,该宏定义用于表示SRAM进行映射后的内存起始地址,因此访问数组g_test_buffer就能访问SRAM中的数据。 在完成SRAM初始化后,便往SRAM中填充数据,随后便不断地检测按键输入,若检测到KEY_UP按键被按下,则将SRAM中的数据逐一地读出,然后在LCD上进行显示,这实际是测试了SRAM的读操作,若检测到KEY0按键被按下,则调用函数smc_sram_test()对SRAM进行读写测试,该函数如下所示: - /**
- *@brief 外部内存测试(最大支持1M字节内存测试)
- *@param 无
- *@retval 无
- */
- voidfsmc_sram_test(uint16_t x, uint16_t y)
- {
- uint32_t i = 0;
- uint8_t temp = 0;
- uint8_t sval = 0; /* 在地址0读到的数据 */
-
- lcd_show_string(x, y, 239, y + 16, 16, "Ex Memory Test: 0KB", BLUE);
-
- /* 每隔4K字节,写入一个数据,总共写入256个数据,刚好是1M字节 */
- for (i = 0; i < 1024 * 1024; i += 4096)
- {
- sram_write(&temp, i, 1);
- temp++;
- }
-
- /* 依次读出之前写入的数据,进行校验 */
- for (i = 0; i < 1024 * 1024; i += 4096)
- {
- sram_read(&temp, i, 1);
-
- if (i == 0)
- {
- sval = temp;
- }
- else if (temp <= sval)
- {
- break; /* 后面读出的数据一定要比第一次读到的数据大 */
- }
- /* 显示内存容量 */
- lcd_show_xnum(x+15*8, y, (uint16_t)(temp - sval + 1) * 4, 4, 16, 0, BLUE);
- }
- }
复制代码可以看到,函数smc_sram_test()就是往SRAM中写入数据,然后再读出校验,一次来进行SRAM的读写测试。
44.3 下载验证 在完成编译和烧录操作后,可以看到LCD上显示了本实验的实验信息,此时按下KEY_0按键对SRAM进行读写测试,便可以看到LCD上提示了测试外部SRAM的容量结果,如果一切正常,将提示“Ex MemoryTest:1024KB”,其中1024KB也就是开发板板载SRAM的实际容量(1M字节),接着按下KEY_UP按键对SRAM进行读测试,可以看到LCD上不断地刷新显示一串数字,这便是从SRAM中读出的在SRAM初始化后被写入SRAM的250000个数据(0~249999)。 |