当前位置:   article > 正文

【正点原子STM32连载】 第四十四章 外部SRAM实验 摘自【正点原子】APM32E103最小系统板使用指南

【正点原子STM32连载】 第四十四章 外部SRAM实验 摘自【正点原子】APM32E103最小系统板使用指南

1)实验平台:正点原子APM32E103最小系统板
2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420
3)全套实验源码+手册+视频下载地址: http://www.openedv.com/docs/boards/xiaoxitongban

第四十四章 外部SRAM实验

本章将介绍使用APM32E103驱动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 硬件资源
  4. LED
    LED0 - PB5
  5. 按键
    KEY0 - PE4
    KEY_UP - PA0
  6. USART1(PA9、PA10连接至板载USB转串口芯片上)
  7. 正点原子 2.8/3.5/4.3/7/10寸TFTLCD模块(仅限MCU屏,16位8080并口驱动)
  8. 外部SRAM(SMC驱动)
    44.1.3 原理图
    本章实验使用了一个板载的SRAM芯片,该SRAM芯片通过MCU的SMC接口与MCU进行连接,该SRAM与MCU的连接原理图,如下图所示:
    在这里插入图片描述

图44.1.3.1 SRAM与MCU的连接原理图
44.2 程序设计
44.2.1 Geehy标准库的SMC驱动
本章实验通过SMC驱动SRAM芯片,通过SMC可以将外部SRAM芯片的数据访问映射成一段内存空间,通过访问这段内存空间,即可访问SRAM芯片中的数据,因此需要对SMC做相应的配置,SMC的配置方式,请读者查看第25.2.1小节中Geehy标准库的SMC驱动中相关的内容。
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_Config_T gpio_init_struct;
    SMC_NORSRAMConfig_T smc_norsram_init_struct;
    SMC_NORSRAMTimingConfig_T smc_timing_struct;
    
    /* 使能时钟 */
    RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_SMC);	/* 使能SMC时钟 */
    SRAM_WR_GPIO_CLK_ENABLE();						/* 使能SMC_NWE引脚端口时钟 */
    SRAM_RD_GPIO_CLK_ENABLE();						/* 使能SMC_NOE引脚端口时钟 */
SRAM_CS_GPIO_CLK_ENABLE();						/* 使能SMC_NE3引脚端口时钟 */
/* 使能SMC_D0/1/2/3/13/14/15、SMC_A16/17/18引脚端口时钟 */
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOD);
/* 使能SMC_D4/5/6/7/8/9/10/11/12、SMC_NBL0/1引脚端口时钟 */
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOE);
	/* 使能SMC_A0/1/2/3/4/5/6/7/8/9引脚端口时钟 */
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOF);
/* 使能SMC_A10/11/12/13/14/15引脚端口时钟 */
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOG);
    
    /* 配置SMC_NWE引脚 */
gpio_init_struct.pin = SRAM_WR_GPIO_PIN;
/* 高速 */
gpio_init_struct.speed = GPIO_SPEED_50MHz;
/* 复用功能推挽输出模式 */
gpio_init_struct.mode = GPIO_MODE_AF_PP; 
/* 配置SMC_NOE引脚 */
    GPIO_Config(SRAM_WR_GPIO_PORT, &gpio_init_struct);
    /* SMC_NOE引脚 */
    gpio_init_struct.pin = SRAM_RD_GPIO_PIN;                                       	/* 配置SMC_NEx引脚 */
    GPIO_Config(SRAM_RD_GPIO_PORT, &gpio_init_struct);
    /* SMC_NEx引脚 */
    gpio_init_struct.pin = SRAM_CS_GPIO_PIN;                                                	/* 配置SMC_NEx引脚 */
		GPIO_Config(SRAM_CS_GPIO_PORT, &gpio_init_struct);
    
    /* 配置SMC_NBLn引脚省略 */
    /* 地址建立时间 */
smc_timing_struct.addressSetupTime = 0x02;
/* 地址保持时间 */
smc_timing_struct.addressHodeTime = 0x00;
/* 数据建立时间 */
smc_timing_struct.dataSetupTime = 0x02;
/* 访问模式 */
smc_timing_struct.accessMode = SMC_ACCESS_MODE_A;
/* 根据配置选择SMC_NE1~4 */
    smc_norsram_init_struct.bank = (SRAM_SMC_NEX == 1) ? SMC_BANK1_NORSRAM_1 :
                                   (SRAM_SMC_NEX == 2) ? SMC_BANK1_NORSRAM_2 :
                                   (SRAM_SMC_NEX == 3) ? SMC_BANK1_NORSRAM_3 :
                                                         SMC_BANK1_NORSRAM_4;
	/* 禁止数据、地址总线复用 */
smc_norsram_init_struct.dataAddressMux = SMC_DATA_ADDRESS_MUX_DISABLE;
/* SRAM类型 */
smc_norsram_init_struct.memoryType = SMC_MEMORY_TYPE_SRAM;
	/* 16位数据宽度 */
smc_norsram_init_struct.memoryDataWidth = SMC_MEMORY_DATA_WIDTH_16BIT;
/* 禁止突发访问 */
smc_norsram_init_struct.burstAcceesMode = SMC_BURST_ACCESS_MODE_DISABLE;
/* 禁止异步传输期间的等待信号 */
smc_norsram_init_struct.asynchronousWait = SMC_ASYNCHRONOUS_WAIT_DISABLE;
/* 配置等待信号极性,仅在突发访问模式下有效 */
smc_norsram_init_struct.waitSignalPolarity = SMC_WAIT_SIGNAL_POLARITY_LOW;
/* 禁止非对齐的突发访问 */
smc_norsram_init_struct.wrapMode = SMC_WRAP_MODE_DISABLE;
/* 配置等待时序 */
	smc_norsram_init_struct.waitSignalActive = 	SMC_WAIT_SIGNAL_ACTIVE_BEFORE_WAIT_STATE;
/* 使能写存储器 */
smc_norsram_init_struct.writeOperation = SMC_WRITE_OPERATION_ENABLE;
/* 禁止等待信号 */
smc_norsram_init_struct.waiteSignal = SMC_WAITE_SIGNAL_DISABLE;
/* 禁止扩展模式 */
smc_norsram_init_struct.extendedMode = SMC_EXTENDEN_MODE_DISABLE;
/* 禁止突发写 */
smc_norsram_init_struct.writeBurst = SMC_WRITE_BURST_DISABLE;
/* 读时序 */
smc_norsram_init_struct.readWriteTimingStruct = &smc_timing_struct;
/* 写时序 */
smc_norsram_init_struct.writeTimingStruct = NULL;
/* 配置SMC */
SMC_ConfigNORSRAM(&smc_norsram_init_struct);
/* 根据配置使能存储块1区域块1~4 */
    SMC_EnableNORSRAM((SRAM_SMC_NEX == 1) ? SMC_BANK1_NORSRAM_1 :
                      (SRAM_SMC_NEX == 2) ? SMC_BANK1_NORSRAM_2 :
                      (SRAM_SMC_NEX == 3) ? SMC_BANK1_NORSRAM_3 :
                                            SMC_BANK1_NORSRAM_4);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90

从原理图中可以看到,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)
{
    uint32_t ts;
    uint8_t t = 0;
    uint8_t key;
    
    NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_4);  /* 设置中断优先级分组为组4 */
    sys_apm32_clock_init(15);                         /* 配置系统时钟 */
    delay_init(120);                                  /* 初始化延时功能 */
    usart_init(115200);                               /* 初始化串口 */
    usmart_dev.init(120);                             /* 初始化USMART */
    led_init();                                       /* 初始化LED */
    key_init();                                       /* 初始化按键 */
    lcd_init();                                       /* 初始化LCD */
    sram_init();                                      /* 初始化外部SRAM */
    
    lcd_show_string(30, 50, 200, 16, 16, "APM32", 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:Test SRAM", RED);
    lcd_show_string(30, 130, 200, 16, 16, "KEY_UP:Test Data", RED);
    
    for (ts=0; ts<250000; ts++)                       /* 创建测试数据 */
    {
        g_test_buffer[ts] = ts;
    }
    
    while (1)
    {
        t++;
        key = key_scan(0);
        
        if (key == KEY0_PRES)                         /* 测试外部SRAM容量 */
        {
            smc_sram_test(30, 150);
        }
        else if (key == WKUP_PRES)
        {
            for (ts=0; ts<250000; ts++)
            {
/* 显示测试数据 */
                lcd_show_xnum(30, 170, g_test_buffer[ts], 6, 16, 0, BLUE);  
            }
        }
        
        if (t == 20)
        {
            LED0_TOGGLE();
            t = 0;
        }
        
        delay_ms(10);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

可以看到,应用代码中定义了一个起始地址为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       测试外部SRAM容量
 * @note        最大支持1MB容量的SRAM
 * @param       x: LCD上显示提示信息的起始X坐标
 * @param       y: LCD上显示提示信息的起始Y坐标
 * @retval      无
 */
static void smc_sram_test(uint16_t x, uint16_t y)
{
    uint32_t i;
    uint8_t temp;
    uint8_t sval;
    
    lcd_show_string(x, y, 239, y + 16, 16, "Ex Memory Test:   0KB", BLUE);
    
    /* 每间隔4KB写入一个数据,总共写入256个数据,刚好为1MB */
    for (temp=0, i=0; i<(1 * 1024 * 1024); i+=4096)
    {
        sram_write(&temp, i, 1);
        temp++;
    }
   
    /* 读出写入的数据进行校验 */
    for (i=0; i<(1 * 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);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

可以看到,函数smc_sram_test()就是往SRAM中写入数据,然后再读出校验,一次来进行SRAM的读写测试。
44.3 下载验证
在完成编译和烧录操作后,可以看到LCD上显示了本实验的实验信息,此时按下KEY_0按键对SRAM进行读写测试,便可以看到LCD上提示了测试外部SRAM的容量结果,如果一切正常,将提示“Ex Memory Test:1024KB”,其中1024KB也就是开发板板载SRAM的实际容量(1M字节),接着按下KEY_UP按键对SRAM进行读测试,可以看到LCD上不断地刷新显示一串数字,这便是从SRAM中读出的在SRAM初始化后被写入SRAM的250000个数据(0~249999)。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/172523
推荐阅读
相关标签
  

闽ICP备14008679号