1-15 GD32ARM存储器

前言:


项目过程中对相关知识回顾,仅供学习参考......


目录

前言:

[1.0 简介](#1.0 简介)

[2.0 芯片内部结构](#2.0 芯片内部结构)

[3.0 SRAM存储器的时序](#3.0 SRAM存储器的时序)

[4.0 SRAM芯片时序](#4.0 SRAM芯片时序)

[5.0 EXMC 存储器映射](#5.0 EXMC 存储器映射)

[6.0 EXMC控制SRAM时序](#6.0 EXMC控制SRAM时序)

[7.0 FLASH空间布局](#7.0 FLASH空间布局)

[8.0 RAM区域](#8.0 RAM区域)

[9.0 程序实现](#9.0 程序实现)

9.0.1原理图

[9.0.2 宏定义外部存储器](#9.0.2 宏定义外部存储器)

[9.0.3 RCU使能GPIO时钟](#9.0.3 RCU使能GPIO时钟)

[9.0.4 初始化地址总线](#9.0.4 初始化地址总线)

[9.0.5 初始化数据总线](#9.0.5 初始化数据总线)

[9.0.6 初始化控制总线](#9.0.6 初始化控制总线)

[9.0.7 控制块函数](#9.0.7 控制块函数)

[9.0.8 补充知识点](#9.0.8 补充知识点)

[9.0.9 完整程序](#9.0.9 完整程序)

后记:


1.0 简介


ARM(Advanced RISC Machine)架构的存储器系统是其设计中的关键部分,它不仅影响着处理器的性能,还决定了系统的整体效率和功耗。以下是关于ARM存储器的一些基本概念和特性介绍:


2.0 芯片内部结构


注:芯片的内部结构包含矩阵存储器,地址译码器,控制电路,每个控制电流都包含对应的功能


注:以上对应引脚的地址,给出特定的功能,这里的数据线有16根,也就是数据的位数是16位的那么:**也可以称16根数据线,所以它的访问数据宽度为16位,2个字节,**19根地址线一共可以表示0~111 1111 11111111 1111地址范围,2^19=2^9x1024=512K个16位数据宽度的存储单元,所以能访问512Kx16bits大小的空间:为了能够细粒度到访问16位宽度的高8位或低8位,又使用UB或LB线控制。


3.0 SRAM存储器的时序


读写时序的流程如下:

1.0 主机使用地址信号线发出要访问的存储器目标地址

2.0 控制片选信号CS1使能存储器芯片

3.0 若是要进行读操作,则控制读使能信号OE表示要读数据

4.0 若进行写操作则控制写使能信号WE表示要写数据

5.0 使用掩码信号LB与UB指示要访问目标地址的高、低字节部分

6.0 若是读取过程,存储器会通过数据线向主机输出目标数据

7.0 若是写入过程,主要使用数据线向存储器传输目标数据


4.0 SRAM芯片时序




5.0 EXMC 存储器映射

单片机通过地址来访问寄存器、RAM、FLASH,ARM寻址范围4GB,分为多个块:

EXMC外设可以用来驱动外部扩展的存储器,包括SRAM、NOR FLASH以及NAND FLSAH类型的存储器,但不能驱动如DRAM这种动态的存储器。


EXMC地址区域又分成了4个Bank,每个Bank占256M字节空间,并分配了地址范围及适用驱动的存储器类型如NOR FLASH及SRAM存储器只能使用Bank1的地址来访问和驱动。

注:这里每个EXMC分为四个块,整个EXMC的总大小是1G,而分为四个区域每个区域的大小是256MB, 然后每个blank块分别用于存储不同外部存储器的数据。


在NOR及SRAM区域又分成了4个小块,每个小块有相应的控制引脚(EXMC NE[3:0])可以作为芯片片选信号如访问0x68000000-0x6BFFFFFF地址空间时,会访问到的Region2区域,相应的EXMC NE2信号线会输出低电平控制信号。


存储器映射EXMC对应引脚图:

注:一般情况下一个地址对应的大小就是一个字节,比如我们想往外部存储器写数据10,也就是往D0里面写数据10,这个时候通过系统总线HA0给一个地址,然后地址给EXMC存储器映射,也就是给到我们MCU对外引出的引脚,然后引脚在连接到对应的外部设备,然后将数据存储到外部设备中。


注:如果我们存储的数据不是8位的而是16位的会比较的难处理,因为系统总线默认是8位的,这个时候从外部过来就需要往左移动一位,相当于数MA0连接到HA1这个引脚,然后再使用掩码信号访问来解决是访问的高8位还是低8位。


6.0 EXMC控制SRAM时序


当要访问某个指向外部存储器地址时,EXMC会根据配置控制信号线产生时序访问存储器,上图

中是访问外部SRAM时的读时序。

该时序由一个存储器操作期由地址建立周期(ADDSET)、数据建立周期(DATAST)以及2个HCLK周期组成。在地址建立周期中,地址线发出要访问的地址,数据掩码信号线指示出要读取地址的高、低字节部分,片选信号使能存储器芯片;

地址建立周期结束后读使能信号线发出读使能信号,接着存储器通过数据信号线把目标数据

传输给EXMC,EXMC再交给内核。


写时序

写时序类似,区别是它的一个存储器操作周期仅由地址建立周期(ADDSET)和数据建立周期(DATAST)组成,且在数据建立周期期间写使能信号线发出写信号,接着EXMC将数据通过

数据线传输到存储器中。


7.0 FLASH空间布局


最终烧写到单片机flash中的文件大小:Code+RO +RW,Program Size:Code=276 RO-data=992 RW-data=4Zl-data=1028。


8.0 RAM区域


9.0 程序实现

9.0.1原理图
9.0.2 宏定义外部存储器

注:这个位置表示存储器的存储位置,表示哪一个外部存储器块,和存储器块中的哪一个位置

cpp 复制代码
/**
 * @brief  宏定义缓冲区
 * @param  无参数
 * @return 无返回值
 * @author tao.Huang
 */
#define BANK0_REGON3_ADDR ((uint32_t)0x6C000000)    // bank0 regon3起始地址
#define EXMC_SRAM_BUFFER_SIZE (1 * 1024 * 1024)     // 外部SRAM缓冲区大小,1M字节
#define EXMC_SRAM_BEGIN_ADDR (BANK0_REGON3_ADDR)    // 存储器映射起始地址
#define EXMC_SRAM_END_ADDR (BANK0_REGON3_ADDR + EXMC_SRAM_BUFFER_SIZE - 1)  // 0x6c100000 - 1

注:分为每一个块,然后每一个块占用的存储空间大小是256M


9.0.3 RCU使能GPIO时钟
cpp 复制代码
    rcu_periph_clock_enable(RCU_GPIOD); // 使能GPIOD的时钟
    rcu_periph_clock_enable(RCU_GPIOE); // 使能GPIOE的时钟
    rcu_periph_clock_enable(RCU_GPIOF); // 使能GPIOF的时钟
    rcu_periph_clock_enable(RCU_GPIOG); // 使能GPIOG的时钟

注:下面的引脚表示的是端口对应的引脚定义图


9.0.4 初始化地址总线
cpp 复制代码
    /* 地址总线 */
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_0);  // A0
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_1);  // A1
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_2);  // A2
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_3);  // A3
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_4);  // A4
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_5);  // A5
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_12); // A6
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_13); // A7
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_14); // A8
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_15); // A9
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_0);  // A10
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_1);  // A11
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_2);  // A12
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_3);  // A13
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_4);  // A14
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_5);  // A15
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_11); // A16
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_12); // A17
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_13); // A18

9.0.5 初始化数据总线
cpp 复制代码
    /* 数据总线 */
	gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_14); //D0
	gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_15); //D1
	gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_0 ); //D2
	gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_1 ); //D3
	gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_7 ); //D4
	gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_8 ); //D5
	gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_9 ); //D6
	gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_10); //D7
	gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_11); //D8
	gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_12); //D9
	gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_13); //D10
	gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_14); //D11
	gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_15); //D12
	gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_8 ); //D13
	gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_9 ); //D14
	gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_10); //D15
9.0.6 初始化控制总线
cpp 复制代码
    /* 控制信号 */
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_9);  // EXMC_NE1
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_4);  // EXMC_NOE
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_5);  // EXMC_NWE
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_12); // EXMC_NE3
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_0);  // EXMC_NBL0
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_1);  // EXMC_NBL1

cpp 复制代码
/**
 * @brief  外部存储器映射GPIO初始化
 * @param  void
 * @return 无返回值
 * @author tao.Huang
 */
static void Config_Exmc_Gpio(void)
{
    rcu_periph_clock_enable(RCU_GPIOD); // 使能GPIOD的时钟
    rcu_periph_clock_enable(RCU_GPIOE); // 使能GPIOE的时钟
    rcu_periph_clock_enable(RCU_GPIOF); // 使能GPIOF的时钟
    rcu_periph_clock_enable(RCU_GPIOG); // 使能GPIOG的时钟

    /* 地址总线 */
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_0);  // A0
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_1);  // A1
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_2);  // A2
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_3);  // A3
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_4);  // A4
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_5);  // A5
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_12); // A6
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_13); // A7
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_14); // A8
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_15); // A9
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_0);  // A10
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_1);  // A11
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_2);  // A12
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_3);  // A13
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_4);  // A14
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_5);  // A15
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_11); // A16
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_12); // A17
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_13); // A18

    /* 数据总线 */
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_14); // D0
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_15); // D1
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_0);  // D2
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_1);  // D3
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_7);  // D4
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_8);  // D5
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_9);  // D6
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_10); // D7
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_11); // D8
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_12); // D9
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_13); // D10
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_14); // D11
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_15); // D12
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_8);  // D13
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_9);  // D14
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_10); // D15

    /* 控制信号 */
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_9);  // EXMC_NE1
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_4);  // EXMC_NOE
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_5);  // EXMC_NWE
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_12); // EXMC_NE3
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_0);  // EXMC_NBL0
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_1);  // EXMC_NBL1
}

9.0.7 控制块函数

注:以下的是程序的原码,结构体定义中包含的参数,值有使能或者是失能

cpp 复制代码
/* EXMC NOR/SRAM timing initialize struct */
typedef struct
{
    uint32_t asyn_access_mode;                                          /*!< asynchronous access mode */
    uint32_t syn_data_latency;                                          /*!< configure the data latency */
    uint32_t syn_clk_division;                                          /*!< configure the clock divide ratio */
    uint32_t bus_latency;                                               /*!< configure the bus latency */
    uint32_t asyn_data_setuptime;                                       /*!< configure the data setup time,asynchronous access mode valid */
    uint32_t asyn_address_holdtime;                                     /*!< configure the address hold time,asynchronous access mode valid */
    uint32_t asyn_address_setuptime;                                    /*!< configure the data setup time,asynchronous access mode valid */
}exmc_norsram_timing_parameter_struct;
------------------|----------------|----------------

/* EXMC NOR/SRAM initialize struct */
typedef struct
{
    uint32_t norsram_region;                                            /*!< select the region of EXMC NOR/SRAM bank */
    uint32_t write_mode;                                                /*!< the write mode, synchronous mode or asynchronous mode */
    uint32_t extended_mode;                                             /*!< enable or disable the extended mode */
    uint32_t asyn_wait;                                                 /*!< enable or disable the asynchronous wait function */
    uint32_t nwait_signal;                                              /*!< enable or disable the NWAIT signal while in synchronous bust mode */
    uint32_t memory_write;                                              /*!< enable or disable the write operation */
    uint32_t nwait_config;                                              /*!< NWAIT signal configuration */
    uint32_t wrap_burst_mode;                                           /*!< enable or disable the wrap burst mode */
    uint32_t nwait_polarity;                                            /*!< specifies the polarity of NWAIT signal from memory */
    uint32_t burst_mode;                                                /*!< enable or disable the burst mode */
    uint32_t databus_width;                                             /*!< specifies the databus width of external memory */
    uint32_t memory_type;                                               /*!< specifies the type of external memory */
    uint32_t address_data_mux;                                          /*!< specifies whether the data bus and address bus are multiplexed */
    exmc_norsram_timing_parameter_struct* read_write_timing;            /*!< timing parameters for read and write if the extended mode is not used or the timing 
                                                                             parameters for read if the extended mode is used */
    exmc_norsram_timing_parameter_struct* write_timing;                 /*!< timing parameters for write when the extended mode is used */
}exmc_norsram_parameter_struct;

cpp 复制代码
/**
 * @brief  外部存储器映射控制
 * @param  void
 * @return 无返回值
 * @author tao.Huang
 */
static void Config_Bank0_Region3(void)
{
    exmc_norsram_parameter_struct sramInitStruct;
    exmc_norsram_timing_parameter_struct sramTimingInitStruct;
    exmc_norsram_struct_para_init(&sramInitStruct);

    // 外部读写时序
    sramTimingInitStruct.asyn_access_mode = EXMC_ACCESS_MODE_A; //模式A,异步访问SRAM
    sramTimingInitStruct.asyn_address_setuptime = 0;            // 异步访问地址建立时间
    sramTimingInitStruct.asyn_address_holdtime  = 0;            // 异步访问地址保持时间
    sramTimingInitStruct.asyn_data_setuptime    = 0;            // 异步访问数据建立时间
    sramTimingInitStruct.bus_latency 			= 0;            // 异步/同步访问总线延迟时间
    sramTimingInitStruct.syn_clk_division = 0;                  // 同步访问时钟分频系数(从HCLK中分频)
    sramTimingInitStruct.syn_data_latency = 0;                  // 同步访问中获得第1个数据所需要的等待延迟

    /* Region3配置 */
    sramInitStruct.norsram_region = EXMC_BANK0_NORSRAM_REGION3; // Region3
    sramInitStruct.address_data_mux = DISABLE;                  // 禁用地址、数据总线多路复用
    sramInitStruct.memory_type = EXMC_MEMORY_TYPE_SRAM;         // 储存器类型为SRAM
    sramInitStruct.databus_width = EXMC_NOR_DATABUS_WIDTH_16B;  // 数据宽度16位
    sramInitStruct.burst_mode = DISABLE;                        // 禁用突发访问
    sramInitStruct.nwait_config = EXMC_NWAIT_CONFIG_BEFORE;     // 等待输入配置
    sramInitStruct.nwait_polarity = EXMC_NWAIT_POLARITY_LOW;    // 等待输入信号低电平有效
    sramInitStruct.wrap_burst_mode = DISABLE;                   // 禁用包突发访问
    sramInitStruct.asyn_wait = DISABLE;                         // 禁用异步等待
    sramInitStruct.extended_mode = DISABLE;                     // 禁用扩展模式
    sramInitStruct.memory_write = ENABLE;                       // 使能写入外部存储器
    sramInitStruct.nwait_signal = DISABLE;                      // 禁用等待输入信号
    sramInitStruct.write_mode = EXMC_ASYN_WRITE;                // 写入模式为异步写入
    sramInitStruct.read_write_timing = &sramTimingInitStruct;   // 读写时序配置

    /* 初始化Region3 */
    exmc_norsram_init(&sramInitStruct);

    /* 使能Region3 */
    exmc_norsram_enable(EXMC_BANK0_NORSRAM_REGION3);
}

注:以上是外部存储器映射控制代码程序


9.0.8 SRAM初始化函数

cpp 复制代码
/**
 * @brief  SRAM初始化函数
 * @param  void
 * @return 无返回值
 * @author tao.Huang
 */
void ExSramDrvInit(void)
{
    Config_Exmc_Gpio();
    Config_Bank0_Region3();
}

9.0.8 补充知识点

格式 `0x%02X` 是一种常见的格式化字符串,用于在编程语言中将数值(通常是整数)转换为十六进制表示形式。具体来说:

  • **`0x`**:这是十六进制数的前缀,表明后面跟随的是一个以16为基数的数字。这个前缀是C语言及其衍生语言(如C++、Java等)中约定俗成的表示方法。

  • **`%02X`**:这部分是格式说明符,用来告诉编译器或解释器如何格式化输出:

  • **`%`**:表示接下来是一个格式化的指令。

  • **`02`**:指定了最小宽度为2个字符。如果转换后的值不足两位,则用前导零填充,确保输出总是两个字符宽。

  • **`X`**:表示将整数转换为大写的十六进制表示。如果是小写的 `x`,则会使用小写字母a-f来表示10到15的值;而大写的 `X` 则会使用A-F。

示例

假设你有一个整数值 `15`,当你使用 `printf("0x%02X", 15);` 或者类似的语句时,它将会输出 `0x0F`。同样地,对于整数值 `255`,使用相同的格式化字符串将会输出 `0xFF`。

这种格式化方式常用于调试信息输出、日志记录或者需要明确展示数值的二进制或十六进制表示的情况下,尤其是在嵌入式系统开发、驱动程序编写或其他低级编程任务中。

如果你有具体的编程语言或上下文,请提供更多信息,这样我可以给出更针对性的帮助。


注:全局变量初始化后的位置是放在flash中的,一个是RW区域一个是RO区域,这些数据初始化时是保存在flash的内存空间中的,当程序运行起来后这些数据是保存在内存当中的data段中

这个阶段是在.S汇编启动文件中完成的,先是调用Systeminit文件然后再调用main函数

所以执行的顺序如下所示:

将SRAM硬件初始化放到_main之前,放到SystemInit.c接口函数中调用


9.0.9 完整程序

cpp 复制代码
头文件

#ifndef _EXSRAM_DRV_H_
#define _EXSRAM_DRV_H_

#include <stdint.h>
#include <stdlib.h>

void ExSramDrvInit(void);
void ExSramDrvTest(void);

#endif


-------------------|-----------------|-----------

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include "gd32f30x.h"

/**
 * @brief  宏定义缓冲区
 * @param  无参数
 * @return 无返回值
 * @author tao.Huang
 */
#define BANK0_REGON3_ADDR ((uint32_t)0x6C000000)                           // bank0 regon3起始地址
#define EXMC_SRAM_BUFFER_SIZE (1 * 1024 * 1024)                            // 外部SRAM缓冲区大小,1M字节
#define EXMC_SRAM_BEGIN_ADDR (BANK0_REGON3_ADDR)                           // 存储器映射起始地址
#define EXMC_SRAM_END_ADDR (BANK0_REGON3_ADDR + EXMC_SRAM_BUFFER_SIZE - 1) // 0x6c100000 - 1

/**
 * @brief  外部存储器映射GPIO初始化
 * @param  void
 * @return 无返回值
 * @author tao.Huang
 */
static void Config_Exmc_Gpio(void)
{
    rcu_periph_clock_enable(RCU_GPIOD); // 使能GPIOD的时钟
    rcu_periph_clock_enable(RCU_GPIOE); // 使能GPIOE的时钟
    rcu_periph_clock_enable(RCU_GPIOF); // 使能GPIOF的时钟
    rcu_periph_clock_enable(RCU_GPIOG); // 使能GPIOG的时钟

	rcu_periph_clock_enable(RCU_EXMC);	// 使能EXMC时钟
	
    /* 地址总线 */
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_0);  // A0
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_1);  // A1
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_2);  // A2
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_3);  // A3
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_4);  // A4
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_5);  // A5
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_12); // A6
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_13); // A7
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_14); // A8
    gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_15); // A9
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_0);  // A10
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_1);  // A11
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_2);  // A12
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_3);  // A13
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_4);  // A14
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_5);  // A15
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_11); // A16
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_12); // A17
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_13); // A18

    /* 数据总线 */
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_14); // D0
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_15); // D1
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_0);  // D2
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_1);  // D3
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_7);  // D4
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_8);  // D5
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_9);  // D6
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_10); // D7
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_11); // D8
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_12); // D9
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_13); // D10
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_14); // D11
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_15); // D12
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_8);  // D13
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_9);  // D14
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_10); // D15

    /* 控制信号 */
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_9);  // EXMC_NE1
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_4);  // EXMC_NOE
    gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_5);  // EXMC_NWE
    gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_12); // EXMC_NE3
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_0);  // EXMC_NBL0
    gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_1);  // EXMC_NBL1
}

/**
 * @brief  外部存储器映射控制
 * @param  void
 * @return 无返回值
 * @author tao.Huang
 */
static void Config_Bank0_Region3(void)
{
    exmc_norsram_parameter_struct sramInitStruct;
    exmc_norsram_timing_parameter_struct sramTimingInitStruct;
    exmc_norsram_struct_para_init(&sramInitStruct);

    // 外部读写时序
    sramTimingInitStruct.asyn_access_mode = EXMC_ACCESS_MODE_A; // 模式A,异步访问SRAM
    sramTimingInitStruct.asyn_address_setuptime = 0;            // 异步访问地址建立时间
    sramTimingInitStruct.asyn_address_holdtime = 0;             // 异步访问地址保持时间
    sramTimingInitStruct.asyn_data_setuptime = 0;               // 异步访问数据建立时间
    sramTimingInitStruct.bus_latency = 0;                       // 异步/同步访问总线延迟时间
    sramTimingInitStruct.syn_clk_division = 0;                  // 同步访问时钟分频系数(从HCLK中分频)
    sramTimingInitStruct.syn_data_latency = 0;                  // 同步访问中获得第1个数据所需要的等待延迟

    /* Region3配置 */
    sramInitStruct.norsram_region = EXMC_BANK0_NORSRAM_REGION3; // Region3
    sramInitStruct.address_data_mux = DISABLE;                  // 禁用地址、数据总线多路复用
    sramInitStruct.memory_type = EXMC_MEMORY_TYPE_SRAM;         // 储存器类型为SRAM
    sramInitStruct.databus_width = EXMC_NOR_DATABUS_WIDTH_16B;  // 数据宽度16位
    sramInitStruct.burst_mode = DISABLE;                        // 禁用突发访问
    sramInitStruct.nwait_config = EXMC_NWAIT_CONFIG_BEFORE;     // 等待输入配置
    sramInitStruct.nwait_polarity = EXMC_NWAIT_POLARITY_LOW;    // 等待输入信号低电平有效
    sramInitStruct.wrap_burst_mode = DISABLE;                   // 禁用包突发访问
    sramInitStruct.asyn_wait = DISABLE;                         // 禁用异步等待
    sramInitStruct.extended_mode = DISABLE;                     // 禁用扩展模式
    sramInitStruct.memory_write = ENABLE;                       // 使能写入外部存储器
    sramInitStruct.nwait_signal = DISABLE;                      // 禁用等待输入信号
    sramInitStruct.write_mode = EXMC_ASYN_WRITE;                // 写入模式为异步写入
    sramInitStruct.read_write_timing = &sramTimingInitStruct;   // 读写时序配置

    /* 初始化Region3 */
    exmc_norsram_init(&sramInitStruct);

    /* 使能Region3 */
    exmc_norsram_enable(EXMC_BANK0_NORSRAM_REGION3);
}

/**
 * @brief  SRAM初始化函数
 * @param  void
 * @return 无返回值
 * @author tao.Huang
 */
void ExSramDrvInit(void)
{
    Config_Exmc_Gpio();
    Config_Bank0_Region3();
}

/**
 * @brief  宏定义存储空间
 * @param  MULL
 * @return 无返回值
 * @author tao.Huang
 */
#define BUFFER_SIZE 6
// static uint8_t g_buffer[BUFFER_SIZE] __attribute__((at(EX_SRAM_BEGIN_ADDR)));
// static uint8_t g_buffer[BUFFER_SIZE];
static uint8_t g_buffer[BUFFER_SIZE] = {
    0,
    1,
    2,
    3,
    4,
    5,
};

/**
 * @brief  测试函数
 * @param  MULL
 * @return 无返回值
 * @author tao.Huang
 */
void ExSramDrvTest(void)
{
    printf("********************************\n");
    printf("********外部SRAM测试开始********\n");
    printf("********************************\n");

    //	printf("ex sram writing...\r\n");
    //	for (uint16_t i = 0; i < BUFFER_SIZE; i++)
    //	{
    //        g_buffer[i] = i;
    //        printf("0x%02X ", i);
    //        if (15 == i % 16)
    //		{
    //            printf("\r\n");
    //        }
    //    }

    printf("ex sram reading...\r\n");
    for (uint16_t i = 0; i < BUFFER_SIZE; i++)
    {
        if (i != g_buffer[i])
        {
            printf("0x%02X ", g_buffer[i]);
            printf("\n\nex sram测试故障,请排查!\n\n");
            return;
        }
        printf("0x%02X ", g_buffer[i]);
        if (15 == i % 16)
        {
            printf("\r\n");
        }
    }

    printf("********************************\n");
    printf("********外部SRAM测试结束********\n");
    printf("********************************\n");
}

编译程序输出如下结果:

下载:

实际输出:

后记:

仅供学习参考 ...

相关推荐
jmlinux5 分钟前
STM32 HAL库 + LM2904运算放大器 + ADC + 4-20ma液位传感器:电路设计及代码实现
stm32·单片机·嵌入式硬件
嵌入式小强工作室9 分钟前
STM32内部flash分区
stm32·单片机·嵌入式硬件
毒丐37 分钟前
FreeBSD安装教程
c语言·c++
--Ekko--38 分钟前
嵌入式入门Day32
c语言·进程
析木不会编程1 小时前
【小白51单片机专用教程】protues仿真流水灯
单片机·嵌入式硬件·51单片机
9毫米的幻想1 小时前
【Linux系统】—— 软件下载
linux·运维·服务器·c语言·c++
m0_370565221 小时前
stm32 rtc 详解
stm32·单片机·实时音视频
羊小猪~~2 小时前
C/C++语言基础--C++STL库之仿函数、函数对象、bind、function简介
java·c语言·开发语言·数据结构·c++·visualstudio·stl
嵌入式大圣2 小时前
单片机TCP无线数据透传
单片机·嵌入式硬件·tcp/ip
堇舟2 小时前
第一章 从C到C++相关知识点
c语言·开发语言·c++