找回密码
 立即注册
首页 业界区 安全 【EXMC】简介

【EXMC】简介

科元料 3 天前
1.EXMC概述

  外部存储器控制器(External Memery Controller,EXMC),主要用来访问各种存储器,通过配置寄存器,EXMC可以把单片机内的AMBA协议转化为外部存储器,如SRAM、NOR Flash、PC Card等存储器芯片所专用的协议。芯片厂商一般在引脚较多封装的芯片型号中才会有EXMC外设,因为需要额外的引脚用于EXMC的寻址和标志位。
  EXMC是GD32的叫法,STM32芯片一般将此外设称为FSMC,两者是同一外设。通俗地说,通过设置EXMC外设,可以让你的程序像访问单片机内的SRAM那样读写外部的存储空间,仅用几行代码即可完成外部存储器的读写,而无需细究芯片通信的时序,就像下面一样。
  1. // 代码示例
  2. // 配置完EXMC后,仅需几行代码即可完成外部存储器的读写
  3. #define  EXSRAM_BASE  0X60000000
  4. #define  EX_SRAM_BUFFER_SIZE  1024
  5. static u8   s_arrExSRAM[EX_SRAM_BUFFER_SIZE] __attribute__((at((u32)EXSRAM_BASE)));   // 缓冲区首地址重定向
  6. s_arrExSRAM[byte_cnt]=0xff;     // 将外部SRAM中的第byte_cnt字节写0xff
  7. Temp=s_arrExSRAM[byte_cnt];    // 读外部SRAM的第byte_cnt字节
复制代码
  EXMC直接与AHB总线相连,这意味着 内核可以直接通过AHB与EXMC进行交互,如下图所示。取指令、传数据等操作都是通过AHB总线实现,我们所写的代码的赋值读取等操作,实际是内核借由AHB总线(还要经过MPU)完成的。所以在上面的代码示例中,我们实际是通过AHB总线访问了EXMC地址范围内的某一地址,而配置好的EXMC则自动帮我们生成了读写时序去访问外部存储器芯片中的对应地址中的数据
1.png

  通过配置EXMC,外部存储器的存储空间将被映射到EXMC的地址范围内,EXMC的地址与外部存储器地址存在一定对应关系,外部存储器将如同单片机内部存储器的扩展,变成了挂载在单片机内部存储空间上的一部分。从结果来看,我们可以直接通过AHB对外部存储器进行读写。
2.EXMC工作原理

2.1地址映射

  针对不同类型的外部存储器,EXMC划分了不同的地址范围用于与不同类型的外部存储器进行通信,其中分为bank和region,它们的关系如下图所示。我们代码示例中将缓冲区的起始地址重定向到0x60000000(bank0中region0的起始地址),就是为了使代码中的地址和EXMC为SRAM设置的地址范围对应。
2.png
3.png

  EXMC与外部地址存储器的地址映射描述如下(用户手册577页原文)
  1.  如果外部存储器的数据宽度是 8 位按字节对齐,EXMC 内部将 HADDR[25:0]与
  2. EXMC_A[25:0]相连,然后 EXMC_A[25:0]与外部存储器的地址线相连;
  3.  如果外部存储器的数据宽度是 16 位按半字对齐,就需要将 HADDR 的字节
  4. 地址转化为半字地址之后再连接外存储器, EXMC内部将 HADDR[25:1]与
  5. EXMC_A[24:0]相连, 然后EXMC_A[24:0]与外部存储器的地址线相连。
复制代码
  这里的HADDR指AHB总线的地址总线,EXMC_A实际指单片机的引脚的复用,部分对应引脚关系如下图。而正是因为HADDR与EXMC_A的相连,外部存储器的存储空间才会被映射到EXMC的地址范围内。当程序代码中通过AHB总线访问EXMC某一Region中某一地址时,单片机也通过引脚访问着单片机外的存储器芯片中的对应地址
4.png

  这里很多人不理解的一点是,为什么外部存储器数据宽度为16bit时,HADDR要错开一位,将ADDR[25:1]与EXMC_A[24:0]相连。首先要知道AHB总线协议的地址是字节地址,即每地址对应1字节数据。当外部存储器数据宽度为16bit时,该芯片的地址为半字地址,一地址对应半字(两个字节)。AHB当然也能按照半字对齐进行数据读取,这样的话,地址总线HADDR的LSB永远为0,因为地址递增差额是2。这已经很好解释了为何将ADDR[25:1]与EXMC_A[24:0]相连:(1)HADDR[25:1]与EXMC_A[24:0]都是1递增的半字地址;(2)即使数据宽度为16bit,外部存储器的每一字节存储空间仍然一一映射到了EXMC的地址范围内,你可以通过地址总线ADDR[25:0]实现对单个字节的访问。
  如果还要问为什么地址总线取址时,只用到了第[25]位,更高位不用?那请好好阅读数据手册关于bank0的地址划分,并开动你的小脑瓜,答案显而易见。
2.2时序生成

  除了地址映射外,EXMC的另一功能就是时序生成,其中EXMC_NOE等也是引脚的复用功能,用于配合完成EXMC要生成的通信时序,具体引脚对应功能请查阅用户手册的描述。根据你使用的存储器芯片,为EXMC配置不同的读写时序,即可像开头代码示例那样实现外部存储器的快速读写。可选的部分时序如下。这些时序通过一些参数(如地址建立时间、数据建立时间等)进行描述,具体可在时序控制寄存器中修改。实际应用的时候,应当根据外部存储器的通信时序,设置合适的参数来控制EXMC生成的时序模型与外部存储器的时序相匹配。
5.png
6.png

  这里给出时序设置的示例。
  1. static void ConfigBank0Region3(void)
  2. {  
  3.   exmc_norsram_parameter_struct        sram_init_struct;
  4.   exmc_norsram_timing_parameter_struct sram_timing_init_struct;
  5.   //使能EXMC时钟
  6.   rcu_periph_clock_enable(RCU_EXMC);
  7.   //外部SRAM读写时序
  8.   sram_timing_init_struct.asyn_access_mode = EXMC_ACCESS_MODE_A; //模式A,异步访问SRAM
  9.   sram_timing_init_struct.asyn_address_setuptime = 0; //异步访问地址建立时间
  10.   sram_timing_init_struct.asyn_address_holdtime  = 0; //异步访问地址保持时间
  11.   sram_timing_init_struct.asyn_data_setuptime    = 3; //异步访问数据建立时间
  12.   sram_timing_init_struct.bus_latency            = 0; //同步/异步访问总线延时时间
  13.   sram_timing_init_struct.syn_clk_division       = 0; //同步访问时钟分频系数(从HCLK中分频)
  14.   sram_timing_init_struct.syn_data_latency       = 0; //同步访问中获得第1个数据所需要的等待延迟
  15.   //Region3配置
  16.   sram_init_struct.norsram_region    = EXMC_BANK0_NORSRAM_REGION3; //Region3
  17.   sram_init_struct.address_data_mux  = DISABLE;                    //禁用地址、数据总线多路复用
  18.   sram_init_struct.memory_type       = EXMC_MEMORY_TYPE_SRAM;      //储存器类型为SRAM
  19.   sram_init_struct.databus_width     = EXMC_NOR_DATABUS_WIDTH_16B; //数据宽度16位
  20.   sram_init_struct.burst_mode        = DISABLE;                    //禁用突发访问
  21.   sram_init_struct.nwait_config      = EXMC_NWAIT_CONFIG_BEFORE;   //等待输入配置
  22.   sram_init_struct.nwait_polarity    = EXMC_NWAIT_POLARITY_LOW;    //等待输入信号低电平有效
  23.   sram_init_struct.wrap_burst_mode   = DISABLE;                    //禁用包突发访问
  24.   sram_init_struct.asyn_wait         = DISABLE;                    //禁用异步等待
  25.   sram_init_struct.extended_mode     = DISABLE;                    //禁用扩展模式
  26.   sram_init_struct.memory_write      = ENABLE;                     //使能写入外部存储器
  27.   sram_init_struct.nwait_signal      = DISABLE;                    //禁用等待输入信号
  28.   sram_init_struct.write_mode        = EXMC_ASYN_WRITE;            //写入模式为异步写入
  29.   sram_init_struct.read_write_timing = &sram_timing_init_struct;   //读时序配置
  30.   sram_init_struct.write_timing      = &sram_timing_init_struct;   //写时序配置
  31.   
  32.   //初始化Region3
  33.   exmc_norsram_init(&sram_init_struct);
  34.   
  35.   //使能Region3
  36.   exmc_norsram_enable(EXMC_BANK0_NORSRAM_REGION3);
  37. }
复制代码
3.总结

  配置EXMC,可以使HADDR与EXMC_A相连(根据外部存储器的数据宽度自动调整),从而将外部存储器的存储空间一一映射到EXMC的地址范围中。当我们通过代码访问EXMC范围内的某存储空间,EXMC会按我们的配置生成相应的读写时序,访问被映射的外部存储器中的存储空间。因此,地址选取、时序生成均由硬件帮我们完成,而我们只需像访问单片机内部SRAM的数据那样轻松快速地完成对外部存储器的访问。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册