本帖最后由 luobeihai 于 2023-6-8 00:07 编辑
#申请原创# @21小跑堂
1. APM32F4xx SMC 简介SMC,全称是 Static Memory Controller ,即静态存储控制器。该外设用于驱动静态存储设备,比如 SRAM、PSRAM、NandFlash、NorFlash、PCCard 。APM32F4xx SMC 内部有四个存储块,每个存储块都对应控制不同类型的存储器,通过配置 SMC 控制寄存器选择不同的存储器类型;任一时刻只能访问一个外部设备;每个存储块都可以单独配置,SMC 控制时序可编程以适用不同的外部存储设备。 1.1 SMC 结构框图SMC 主要有五个部分组成:AHB 总线接口、配置寄存器、NORFlash 控制器、NANDFlash/PC 卡控制器和外部设备接口信号,具体情况如下图: 1.2 SMC 的地址映射使用 APM32F4xx SMC 外设外接存储器扩展存储空间时,外部的存储器存储空间会映射到 MCU 的内存存储空间,而且不同的外部存储设备对应不同的地址空间,如下表所示: 可以看到,SMC 把内部 1GB 的存储空间划分为了 4 个 256MB 的存储块,每个存储块有各自的地址空间以及适用的存储器类型,存储块 1 用于控制 NOR/PSRAM 存储器,而存储块 2、3、4 用于控制 NAND 闪存和 PC 卡。 此外,对于每个存储块的内部,又划分为 4 块 64MB 同等大小的区域,每个小块都有对应的控制引脚用于连接外部存储器的片选信号,从而决定外部存储器具体连接到的是哪个 64MB 的存储区域。比如对于存储块 1 ,有对应的控制信号线 SMC_NE[4 : 1] ,用于选择存储块 1 内部的 4 个 64MB 的地址空间,具体地址分配如下:
2. SRAM 简介
2.1 SRAM 存储结构SRAM(Static Random Access Memory)是一种静态随机存取存储器,它是一种主要用于 CPU 内部的高速缓存(Cache)或者集成在 MCU 内部作为数据存储器。SRAM 的所谓的“静态”,指的就是只要保持在通电状态,存储在其内部的数据就可以一直保存,一般是和 DRAM ,即动态存储器相比较而言的。 SRAM 的存储单元结构以锁存器来存储数据,存储单元电路如下: 2.2 APM32F4xx SMC 与 SRAM 的信号连接尽管市面上有各种不同厂商、不同型号的 SRAM 芯片,但是 SRAM 芯片的引脚信号基本都是一致的,有地址线、数据线、控制线三种类型。下面以常见的 SRAM 芯片型号 IS62WV12816 ,给出该 SRAM 芯片与 APM32 SMC 外设的信号引脚连接关系:
对于数据位宽为 8bit 的 SRAM 型号,高位数据线 D8-D15 可以不用连接。 3. APM32F4xx SMC 外设初始化参数说明通过 APM32 SMC 驱动外部 SRAM 芯片时,需要配置 SMC 的时序寄存器以及控制寄存器,但是 APM32F4xx 的固件库中,对 SMC 相关的操作已经封装好了,有两个结构体是比较重要的,分别是时序结构体和初始化配置结构体,下面对这些结构体成员变量作一些解释及配置说明。 3.1 时序结构体时序结构体的代码如下: /**
* [url=home.php?mod=space&uid=247401]@brief[/url] Timing parameters for NOR/SRAM Banks
*/
typedef struct
{
uint8_t addressSetupTime; /*!< Set address setup time */
uint8_t addressHodeTime; /*!< Set address-hold setup time */
uint8_t dataSetupTime; /*!< Set data setup time */
uint8_t busTurnaroundTime; /*!< Set bus turnaround time */
uint8_t clockDivision; /*!< Set clock divide radio */
uint8_t dataLatency; /*!< Set data latency */
SMC_ACCESS_MODE_T accessMode; /*!< Set access mode */
} SMC_NORSRAMTimingConfig_T;
该结构体的成员都是 NorFlash/SRAM 读写过程中与时间相关的各项参数,对这些结构体成员说明如下: (1) addressSetupTime :本成员用于设置地址建立时间,可设置为 0-15 个 HCLK 时钟周期数。APM32F4xx 的 HCLK 时钟频率是168MHz,那么一个 HCLK 时钟周期就是 1/168 微秒。 (2) addressHodeTime :本成员用于设置地址保持时间,同样也可以设置为 0-15 个 HCLK 时钟周期数。 (3) dataSetupTime :本成员用于设置数据建立时间,可设置为 0-15 个 HCLK 时钟周期数。 (4) busTurnaroundTime :本成员用于设置总线转换周期,只适用于总线复用模式的 NorFlash 存储器。 (5) clockDivision :本成员用于配置时钟分频系数,可以把 HCLK 时钟作为输入源,配置为 0-16 分频,用于需要时钟同步的存储器。 (6) dataLatency :本成员设置数据保持时间,用于配置在读取第一个数据前等待的存储器周期数目,可设置为 0-15 个时钟周期。该成员仅适用于同步突发模式的 NorFlash 操作。 (7) accessMode :本成员配置访问存储器的模式,可配置为 A/B/C/D 模式,不同的模式下 SMC 输出的时序不同。对应 SRAM 来说,一般使用模式 A 即可。 对于时序结构体所有与时间相关的参数,单位都是 HCLK 个时钟周期,APM32F4xx 的 HCLK 时钟为 168MHz ,那么 1 个 HCLK 时钟周期就是 1/168 us ,即约等于 6ns. 3.2 初始化配置结构体初始化配置结构体的代码如下: /**
* [url=home.php?mod=space&uid=247401]@brief[/url] SMC NOR/SRAM Config structure
*/
typedef struct
{
SMC_BANK1_NORSRAM_T bank; /*!< NORSRAM bank selection */
SMC_DATA_ADDRESS_MUX_T dataAddressMux; /*!< Data address bus multiplexing selection */
SMC_MEMORY_TYPE_T memoryType; /*!< Memory type selection */
SMC_MEMORY_DATA_WIDTH_T memoryDataWidth; /*!< Data width selection */
SMC_BURST_ACCESS_MODE_T burstAcceesMode; /*!< Set burst access mode */
SMC_ASYNCHRONOUS_WAIT_T asynchronousWait; /*!< Set asynchronous wait */
SMC_WAIT_SIGNAL_POLARITY_T waitSignalPolarity; /*!< Set wait signal polarity */
SMC_WRAP_MODE_T wrapMode; /*!< Set wrapped burst mode */
SMC_WAIT_SIGNAL_ACTIVE_T waitSignalActive; /*!< Set wait timing */
SMC_WRITE_OPERATION_T writeOperation; /*!< Set write operation */
SMC_WAITE_SIGNAL_T waiteSignal; /*!< Set wait signal */
SMC_EXTENDEN_MODE_T extendedMode; /*!< Set extended mode */
SMC_WRITE_BURST_T writeBurst; /*!< Set write burst */
SMC_NORSRAMTimingConfig_T* readWriteTimingStruct; /*!< Read and write timing */
SMC_NORSRAMTimingConfig_T* writeTimingStruct; /*!< Write timing */
} SMC_NORSRAMConfig_T;
该结构体主要是在配置 SMC 初始化时所需要的参数,最底层的代码其实就是配置 SMC 的片选控制、片选时序、写时序这 3 个寄存器,下面简单介绍下这些结构体成员: (1) bank:选择 SRAM 类型的哪个存储区域,该参数需要根据片选引脚的连接不同进行选择,前面也有介绍不同的片选信号对应的是哪个存储区域。 (2) dataAddressMux :用于设置地址线与数据线是否进行复用。对于 NorFlash 存储器类型,地址线与数据线是可以分时复用的,这样可以减少 GPIO 引脚的使用,该参数仅对 NorFlash 有效。 (3) memoryType :配置存储器类型,可以配置的存储器类型有:SRAM、PSRAM、NorFlash。 (4) memoryDataWidth :配置控制存储器的数据位宽,可恶意配置为 8 位或者 16 位。 (5) burstAcceesMode :本成员用于配置是否使用突发访问模式。突发访问模式是指发送一个地址后连续访问多个数据,非突发模式下每访问一个数据都需要输入一个地址。该成员只对同步模式下才有效。 (6) asynchronousWait :用于配置是否使能同步等待信号,对于同步类型的 NorFlash 或者 PSRAM 存储器,可以使用 SMC_NWAIT 引脚插入等待状态。 (7) waitSignalPolarity :该成员用于配置等待信号极性,可设置要求等待的信号是高电平还是低电平。 (8) wrapMode :配置是否使能非对齐突发模式,仅在突发模式下才有效。 (9) waitSignalActive :用于配置等待信号是在等待之前有效还是等待期间有效,只在突发模式下有效。 (10) writeOperation :用于配置是否开启写使能,如果禁止写使能,那么 SMC 外设对存储器只能进行读操作,写操作此时是禁止的。 (11) waiteSignal :该成员用于设置是否使能 NWAIT 信号插入等待状态,只对突发模式下有效。 (12) extendedMode :该成员用于设置是否使能扩展模式,在扩展模式下,读写时序可以分别配置不同的时序寄存器,即读写时序可以不一样;而在费扩展模式下,读写时序的配置都是一样的。 (13) writeBurst :用于配置是否使能写突发操作,只在突发模式下有效。 (14) readWriteTimingStruct :读写时序结构体。在不使用扩展模式时,该成员可同时配置读写时序;在扩展模式下,只配置读时序。 (15) writeTimingStruct:写时序结构体,在扩展模式时,可以配置写时序;在非扩展模式下,配置无效。 3.3 APM32F4xx SMC 控制 SRAM 时序计算APM32F4xx SMC 要控制外部 SRAM 存储器,必须要正确配置时序结构体中的两个时序参数:地址建立时间和数据建立时间,其他的时序参数没有用到,设置为 0 即可。 下面以 SRAM 芯片型号 IS62WV12816 为例,介绍 APM32F4xx SMC 控制 SRAM 芯片的时序计算。根据 IS62WV12816 芯片手册,其关键的时序参数如下: 写时序参数要求:
读时序参数要求:
APM32F4xx SMC 控制外部 SRAM 的读写时序有多种不同的模式,下面展示的是模式 A 的读写时序,如下图所示: SMC 写 SRAM 时序: SMC 读 SRAM 时序: 根据 IS62WV12816 芯片的时间参数要求,以及 SMC 读写 SRAM 的时序图,可以得到 IS62WV12816 芯片的时间参数计算公式如下: tWC = ADDSET + DATASET + 1 >= 55ns tPWE = DATASET >= 40ns tRC = ADDSET + DATASET >= 55ns 对时序结构体进行赋值的 ADDSET 和 DATASET 参数,它的单位都是 1 个 HCLK 周期,而 APM32F4xx 的 HCLK 时钟频率是 168MHz ,那么 1 个 HCLK 周期就是 1/168 us = 6ns . 根据前面的 IS62WV12816 关键的时间参数表格可知,地址建立时间是 0 ,所以时序结构体的 ADDSET 参数赋值为 0 即可;然后根据上面的三条表达式,为了同时满足读写时序的要求,可得出 DATASET 参数赋值为 10 ,这样就可以满足 SRAM 读写的时间要求了。
4. APM32F4xx SMC 读写外部SRAM例程
4.1 硬件设计外部 SRAM 芯片使用的是 IS62WV12816 型号,SRAM 芯片和 APM32F4xx 连接的原理图如下: 可以看到,SRAM 芯片有很多的信号线需要与 APM32F4xx 的相连,其中 SRAM 芯片的大部分信号线都是与 MCU 连接固定的引脚的,只有片选引脚可以让我们选择连接 SMC_NE1 - NE4,而片选引脚的连接不同,会映射到 MCU 不同的地址空间。 上面的原理图片选引脚连接的是 SMC_NE1 ,那么 SRAM 的存储空间会被映射到 MCU 内部的 0x60000000 ~ 0x63FFFFFF 这一片地址空间上。对于 IS62WV12816 型号,其内存大小是 256KB ,那么当 MCU 访问 0x60000000 开始的 256KB 的内存空间时,SMC 外设会根据初始化的配置,产生相应的访问时序,从而实现外部 SRAM 的读写操作。 4.2 软件设计要通过 APM32F4xx SMC 实现外部 SRAM 存储器的访问,只要配置使用到的 SMC 外设相关的 GPIO 引脚以及配置好 SMC 的时序结构体和初始化结构体即可。代码实现流程图如下: 4.2.1 SMC GPIO引脚配置对 SMC 外设所使用到的 GPIO 引脚,全部都配置为复用功能输出模式,具体代码如下: static void SMC_SRAM_GPIOConfig(void)
{
GPIO_Config_T gpioConfig;
/**
+--------------------+--------------------+
| PD0 <-> SMC_D2 | PE0 <-> SMC_NBL1 |
| PD1 <-> SMC_D3 | PE1 <-> SMC_NBL0 |
| PD4 <-> SMC_NOE | PE7 <-> SMC_D4 |
| PD5 <-> SMC_NWE | PE8 <-> SMC_D5 |
| PD7 <-> SMC_NE1 | PE9 <-> SMC_D6 |
| PD8 <-> SMC_D13 | PE10 <-> SMC_D7 |
| PD9 <-> SMC_D14 | PE11 <-> SMC_D8 |
| PD10 <-> SMC_D15 | PE12 <-> SMC_D9 |
| PD11 <-> SMC_A16 | PE13 <-> SMC_D10 |
| PD12 <-> SMC_A17 | PE14 <-> SMC_D11 |
| PD13 <-> SMC_A18 | PE15 <-> SMC_D12 |
| PD14 <-> SMC_D0 | |
| PD15 <-> SMC_D1 | |
+--------------------+--------------------+
| PF0 <-> SMC_A0 | PG0 <-> SMC_A10 |
| PF1 <-> SMC_A1 | PG1 <-> SMC_A11 |
| PF2 <-> SMC_A2 | PG2 <-> SMC_A12 |
| PF3 <-> SMC_A3 | PG3 <-> SMC_A13 |
| PF4 <-> SMC_A4 | PG4 <-> SMC_A14 |
| PF5 <-> SMC_A5 | PG5 <-> SMC_A15 |
| PF12 <-> SMC_A6 | |
| PF13 <-> SMC_A7 | |
| PF14 <-> SMC_A8 | |
| PF15 <-> SMC_A9 | |
+--------------------+--------------------+
*/
/* Enable GPIO Clock */
RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOD | RCM_AHB1_PERIPH_GPIOE | \
RCM_AHB1_PERIPH_GPIOF | RCM_AHB1_PERIPH_GPIOG);
/* SMC SRAM GPIO Config */
gpioConfig.speed = GPIO_SPEED_100MHz;
gpioConfig.mode = GPIO_MODE_AF;
gpioConfig.otype = GPIO_OTYPE_PP;
gpioConfig.pupd = GPIO_PUPD_UP;
gpioConfig.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_11 | GPIO_PIN_12 | \
GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
GPIO_Config(GPIOD, &gpioConfig);
GPIO_ConfigPinAF(GPIOD, GPIO_PIN_SOURCE_0, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOD, GPIO_PIN_SOURCE_1, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOD, GPIO_PIN_SOURCE_4, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOD, GPIO_PIN_SOURCE_5, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOD, GPIO_PIN_SOURCE_7, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOD, GPIO_PIN_SOURCE_8, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOD, GPIO_PIN_SOURCE_9, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOD, GPIO_PIN_SOURCE_10, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOD, GPIO_PIN_SOURCE_11, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOD, GPIO_PIN_SOURCE_12, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOD, GPIO_PIN_SOURCE_13, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOD, GPIO_PIN_SOURCE_14, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOD, GPIO_PIN_SOURCE_15, GPIO_AF_FSMC);
gpioConfig.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;
GPIO_Config(GPIOE, &gpioConfig);
GPIO_ConfigPinAF(GPIOE, GPIO_PIN_SOURCE_0, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOE, GPIO_PIN_SOURCE_1, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOE, GPIO_PIN_SOURCE_7, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOE, GPIO_PIN_SOURCE_8, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOE, GPIO_PIN_SOURCE_9, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOE, GPIO_PIN_SOURCE_10, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOE, GPIO_PIN_SOURCE_11, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOE, GPIO_PIN_SOURCE_12, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOE, GPIO_PIN_SOURCE_13, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOE, GPIO_PIN_SOURCE_14, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOE, GPIO_PIN_SOURCE_15, GPIO_AF_FSMC);
gpioConfig.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;
GPIO_Config(GPIOF, &gpioConfig);
GPIO_ConfigPinAF(GPIOF, GPIO_PIN_SOURCE_0, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOF, GPIO_PIN_SOURCE_1, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOF, GPIO_PIN_SOURCE_2, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOF, GPIO_PIN_SOURCE_3, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOF, GPIO_PIN_SOURCE_4, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOF, GPIO_PIN_SOURCE_5, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOF, GPIO_PIN_SOURCE_12, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOF, GPIO_PIN_SOURCE_13, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOF, GPIO_PIN_SOURCE_14, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOF, GPIO_PIN_SOURCE_15, GPIO_AF_FSMC);
gpioConfig.pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | \
GPIO_PIN_5;
GPIO_Config(GPIOG, &gpioConfig);
GPIO_ConfigPinAF(GPIOG, GPIO_PIN_SOURCE_0, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOG, GPIO_PIN_SOURCE_1, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOG, GPIO_PIN_SOURCE_2, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOG, GPIO_PIN_SOURCE_3, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOG, GPIO_PIN_SOURCE_4, GPIO_AF_FSMC);
GPIO_ConfigPinAF(GPIOG, GPIO_PIN_SOURCE_5, GPIO_AF_FSMC);
}
4.2.2 SMC 初始化配置APM32F4xx 固件库已经对 SMC 外设对时序控制以及初始化配置相关的参数封装在时序结构体和初始化配置结构体了,SMC 外设的初始化配置,主要就是对这两个结构体成员变量进行赋值,最后调用固件库函数提供的初始化配置函数实现 SMC 外设的初始化配置,具体代码如下: void SMC_SRAM_Init(void)
{
SMC_NORSRAMConfig_T SMC_NORSRAM_ConfigStruct;
SMC_NORSRAMTimingConfig_T readWriteTimingStruct;
/* SMC SRAM GPIO Config */
SMC_SRAM_GPIOConfig();
/* Enable SMC Clock */
RCM_EnableAHB3PeriphClock(RCM_AHB3_PERIPH_EMMC);
/* SMC SRAM Timing Config */
readWriteTimingStruct.addressSetupTime = 0x00;
readWriteTimingStruct.addressHodeTime = 0x00;
readWriteTimingStruct.dataSetupTime = 0x0A;
readWriteTimingStruct.busTurnaroundTime = 0x00;
readWriteTimingStruct.clockDivision = 0x00;
readWriteTimingStruct.dataLatency = 0x00;
readWriteTimingStruct.accessMode = SMC_ACCESS_MODE_A;
/* SMC SRAM Init Config */
SMC_NORSRAM_ConfigStruct.bank = SMC_BANK1_NORSRAM_1;
SMC_NORSRAM_ConfigStruct.dataAddressMux = SMC_DATA_ADDRESS_MUX_DISABLE;
SMC_NORSRAM_ConfigStruct.memoryType = SMC_MEMORY_TYPE_SRAM;
SMC_NORSRAM_ConfigStruct.memoryDataWidth = SMC_MEMORY_DATA_WIDTH_16BIT;
SMC_NORSRAM_ConfigStruct.burstAcceesMode = SMC_BURST_ACCESS_MODE_DISABLE;
SMC_NORSRAM_ConfigStruct.asynchronousWait = SMC_ASYNCHRONOUS_WAIT_DISABLE;
SMC_NORSRAM_ConfigStruct.waitSignalPolarity = SMC_WAIT_SIGNAL_POLARITY_LOW;
SMC_NORSRAM_ConfigStruct.wrapMode = SMC_WRAP_MODE_DISABLE;
SMC_NORSRAM_ConfigStruct.waitSignalActive = SMC_WAIT_SIGNAL_ACTIVE_BEFORE_WAIT_STATE;
SMC_NORSRAM_ConfigStruct.writeOperation = SMC_WRITE_OPERATION_ENABLE;
SMC_NORSRAM_ConfigStruct.waiteSignal = SMC_WAITE_SIGNAL_DISABLE;
SMC_NORSRAM_ConfigStruct.extendedMode = SMC_EXTENDEN_MODE_DISABLE;
SMC_NORSRAM_ConfigStruct.writeBurst = SMC_WRITE_BURST_DISABLE;
SMC_NORSRAM_ConfigStruct.readWriteTimingStruct = &readWriteTimingStruct;
SMC_NORSRAM_ConfigStruct.writeTimingStruct = &readWriteTimingStruct;
SMC_ConfigNORSRAM(&SMC_NORSRAM_ConfigStruct);
}
对于时序结构体 SMC_NORSRAMTimingConfig_T 相关的参数配置,需要根据 SRAM 的芯片手册提供的时间参数要求,计算出对应结构体成员的值,从而对各成员参数进行合理配置,本例程所使用的 SRAM 芯片型号是 IS62WV12816 。 4.2.3 SMC 访问外部 SRAM 存储器通过原理图可以确定,外部 SRAM 芯片的片选引脚连接到的是 SMC_NE1 引脚,那么外部 SRAM 的存储空间会映射到 MCU 内部的 0x60000000 ~ 0x63FFFFFF 范围内的地址空间。对于本例程所使用的 IS62WV12816 型号,其存储空间大小是 256KB ,所以我们访问外部 SRAM 的起始地址是 0x60000000 ,结束地址是 0x60040000 。 只要初始化了 SMC 外设之后,对外部 SRAM 的读写访问就是对内存的读写操作。而对于 C 语言的话,通过指针就可以实现对特定内存地址进行读写操作,例如: 对 SRAM 的 0x6000000 地址,读取 1 个字节数据: uint8_t data = *(uint8_t *)0x6000000;
对 SRAM 的 0x6000000 地址,写入 1 个字节数据: *(uint8_t *)0x6000000 = (uint8_t)0x55;
如果我们想要定义变量在指定的内存地址上,可以使用编译器提供的扩展关键字来修饰变量,比如对于 ARM-CC 编译器变量定义如下: uint8_t data[256 * 1024] __attribute__((at(0x60000000)));
下面是对外部 SRAM 读写操作的函数封装: void SMC_SRAM_WriteBufferWord(uint32_t address, const uint32_t *pdata, uint32_t len)
{
uint32_t i = 0;
for (i = 0; i < len / 4; i++)
{
*(__IO uint32_t *)(SRAM_START_ADDR + address) = pdata[i];
address += 4;
}
}
void SMC_SRAM_ReadBufferWord(uint32_t address, uint32_t *pdata, uint32_t len)
{
uint32_t i = 0;
for (i = 0; i < len / 4; i++)
{
pdata[i] = *(__IO uint32_t *)(SRAM_START_ADDR + address);
address += 4;
}
}
5. 基于外部SRAM存储器的应用案例后续计划补充基于SRAM存储器的应用案例,待定。 上述关于APM32F4 SMC SRAM的代码附件也上传了,以供大家参考。
|
厉害,学习
关于APM32F4的SMC介绍及该芯片下的使用方法,其中SMC的结构介绍清晰有条理,操作方法及函数和结构体等定义做了详细介绍,文章整体结构清晰,但是缺少实操结果验证,望以后的文章可以写的更好,加油!