1)实验平台:正点原子stm32f103战舰开发板V4
2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420
3)全套实验源码+手册+视频下载地址: http://www.openedv.com/thread-340252-1-1.html##
本章将介绍使用APM32F407驱动SRAM进行SRAM的数据读写。通过本章的学习,读者将学习到EMMC中SMC的使用。
本章分为如下几个小节:
47.1 硬件设计
47.2 程序设计
47.3 下载验证
47.1.1 例程功能
图47.1.3.1 SRAM与MCU的连接原理图
47.2 程序设计
47.2.1 Geehy标准库的SMC驱动
本章实验通过SMC驱动SRAM芯片,通过SMC可以将外部SRAM芯片的数据访问映射成一段内存空间,通过访问这段内存空间,即可访问SRAM芯片中的数据,因此需要对SMC做相应的配置,SMC的配置方式,请读者查看第26.2.1小节中Geehy标准库的SMC驱动中相关的内容。
47.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)
{
SMC_NORSRAMConfig_T smc_norsram_init_struct;
SMC_NORSRAMTimingConfig_T smc_timing_struct;
/* 使能时钟 */
RCM->AHB3CLKEN_B.EMMCEN = ENABLE; /* 使能EMMC时钟 */
/* 省略GPIO引脚的配置代码 */
/* 配置SMC时序 */
smc_timing_struct.addressSetupTime = 0x02; /* 地址建立时间 */
smc_timing_struct.addressHodeTime = 0x00; /* 地址保持时间 */
smc_timing_struct.dataSetupTime = 0x08; /* 数据建立时间 */
smc_timing_struct.accessMode = SMC_ACCESS_MODE_A; /* 访问模式 */
/* 配置SMC */
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;
smc_norsram_init_struct.memoryType = SMC_MEMORY_TYPE_SRAM;
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_ConfigNORSRAM(&smc_norsram_init_struct);
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);
}
从原理图中可以看到,SRAM芯片的CE引脚连接到了PG10引脚(SMC_NE3信号),因此在进行SRAM初始化后,SRAM映射的内存基地址为0x68000000,访问SRAM中存储的数据仅需访问0x68000000加上数据偏移后的地址即可。
47.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_3); /* 设置中断优先级分组为组3 */
sys_apm32_clock_init(336, 8, 2, 7); /* 配置系统时钟 */
delay_init(168); /* 初始化延时功能 */
usart_init(115200); /* 初始化串口 */
usmart_dev.init(84); /* 初始化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);
}
}
可以看到,应用代码中定义了一个起始地址为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);
}
}
可以看到,函数smc_sram_test()就是往SRAM中写入数据,然后再读出校验,一次来进行SRAM的读写测试。
47.3 下载验证
在完成编译和烧录操作后,可以看到LCD上显示了本实验的实验信息,此时按下KEY_0按键对SRAM进行读写测试,便可以看到LCD上提示了测试外部SRAM的容量结果,如果一切正常,将提示“Ex Memory Test:1024KB”,其中1024KB也就是开发板板载SRAM的实际容量(1M字节),接着按下KEY_UP按键对SRAM进行读测试,可以看到LCD上不断地刷新显示一串数字,这便是从SRAM中读出的在SRAM初始化后被写入SRAM的250000个数据(0~249999)。