通过调用读、写程序存储器,MAXQ 器件提供特殊的固定用途 ROM 函数。然而,在 MAXQ 微控制器上无法直接存取储存在程序存储器中的数据。固定用途 ROM 函数起始地址集成在 IAR Embedded Workbench®,以存取储存的数据。本应用笔记介绍如何利用 IAR 嵌入式工作台工具分配和存取 MAXQ 微控制器上的闪存和 SRAM 存储器。

 

引言
MAXQ 架构是一种基于标准 Harvard 结构、功能强大的单周期 RISC 微控制器,程序和数据存储总线相互独立。这种组织形式要求每个存储器具有专用总线(图 1),所以可同时读取指令和操作数。由于不存在单条数据总线的冲突问题,MAXQ 指令的执行时间仅需要单个周期。

 

图 1. Harvard 结构


每个 MAXQ 器件采用以下存储器类型:

 

  • 闪存
  • SRAM
  • 固定用途 ROM


MAXQ 器件也可从闪存、固定用途 ROM 或 SRAM 执行程序代码。从某个存储器段执行程序代码时,其它两个存储器段可作为数据存储器(更多详细信息,请参阅从闪存执行程序和执行固定用途 ROM 函数部分)。这是因为程序和数据存储器总线不能同时存取同一存储器段。
有人可能认为采用 Harvard 结构的 MAXQ 微控制器也不能在非易失闪存中储存数据。然而,MAXQ 器件内嵌固定用途 ROM 函数,允许读、写非易失闪存数据。


从闪存执行程序
MAXQ 器件中,从闪存执行应用程序时,数据存储器为 SRAM (读和写)和固定用途 ROM (只读)。从闪存执行代码时,数据存储器映射请参见表 1,存储器映射参见图 2。


SRAM 数据存储器在存储器映射中位于地址 0x0000 至 0x07FF (字节寻址模式下)或地址 0x0000 至 0x03FF (字寻址模式下)。


固定用途 ROM 在存储器映射中位于地址 0x8000 至 0x9FFFh (字节模式)或地址 0x8000 至 0x8FFF (字寻址模式下)。


表 1. 从闪存执行应用代码时的数据存储器映射
 

 

 

图 2. 从闪存执行应用代码时的存储器映射


执行固定用途 ROM 函数
执行固定用途 ROM 函数时,数据存储器为 SRAM (读和写)和闪存(读和写)。从闪存执行应用程序且变量或数据对象位于闪存时,可通过固定用途 ROM 函数读或写这些变量或数据对象。通过跳转至执行固定用途 ROM 函数,即可将闪存作为数据进行存取。从固定用途 ROM 执行代码时,数据存储器映射请参见表 2,存储器映射参见图 3。


SRAM 数据存储器在存储器映射中位于地址 0x0000 至 0x07FF (字节寻址模式下)或地址 0x0000 至 0x03FF (字寻址模式下)。


字节寻址模式下,CDA0 = 0 时,闪存的低半部分在存储器映射中位于地址 0x8000 至 0xFFFFh;CDA0 = 1 时,闪存的高半部分在存储器映射中位于地址 0x8000 至 0xFFFFh。字寻址模式下,闪存在存储器映射中位于地址 0x8000 至 0xFFFF。


表 2. 执行固定用途 ROM 函数时的数据存储器映射
 

 

图 3. 执行固定用途 ROM 函数时的存储器映射


闪存和 SRAM 中的存储器分配
IAR 嵌入式工作台 IDE 用于编程基于 MAXQ 核的微控制器。IAR™ C 编译器(用于 MAXQ 微控制器)提供用于定义闪存或 SRAM 位置中数据对象或变量的选项。编译器具有特殊关键词 pragma location 和 pragma required;通过使用关键词,可将存储器分配给绝对地址的数据对象或变量。必须用 IAR 关键词 __no_init 或 const (标准 C 关键词)声明这些变量或数据对象。请参见下文中 __no_init、const、pragma location 和 pragma required 的关键词说明。


关键词说明


pragma location

 

#pragma location 用于定义绝对地址的单个全局或静态变量或数据对象。变量或数据对象必须声明为 __no_init 或 const。这对于必须位于固定地址的个体数据对象非常有用,例如变量、带有外部或内部接口的数据对象或增加的硬件表项。


pragma required

 

#pragma required 确保链接输出中包括某个符号所需的另一个符号。该指令必须放在紧邻第二个符号的前边。如果符号在应用中不可见,使用该指令。例如,如果仅通过某个变量所在的段对其进行间接引用,必须使用#pragma required。


__no_init

 

正常情况下,应用程序启动时,IAR 运行时环境将全部全局和静态变量初始化为 0。IAR C 编译器支持声明不初始化的变量,使用 __no_init 类型限定符。声明为 __no_init 的变量在启动时被禁止。不可能为 __no_init 对象赋予初始值。


例如:__no_init char MaximChar @ 0x0200;


本例中,声明为 __no_init 的变量被放在默认数据存储器(SRAM)的一个绝对地址。


const

 

const 关键词意味着对象为只读。这类限定符用于表示直接或通过指针存取的数据对象,不可写。当 const 随关键词#pragma location 和#pragma required 一起使用时,IAR 分配#pragma location 定义的位置的存储器。这对于配置从外部接口进行存取的参数非常有用。这样的闪存数据只能由固定用途 ROM 函数读或写。


IAR 默认存储器模型中,不可存取绝对地址的常量。利用选项 Place constants in CODE (在 IAR Project  Option  General Option  Target window)使其可存取,如图 4 所示。

 

图 4. IAR 项目选项窗口



例 1

const int FLASH_DATA0;


//FLASH_DATA0 is initialized to 0x0000 and linker will allocate memory address.


例 2

#pragma location = 0xA000


const int FLASH_DATA1 = 0x1234;


#pragma required = FLASH_DATA1


本例中,存储器分配为闪存地址 0xA000,初始化为 0x1234。


例 3

#pragma location = 0xA002


__no_init const int FLASH_DATA2 //Memory is allocated at the address 0xA002 (byte address)


#pragma required = FLASH_DATA2


本例中,存储器分配为闪存地址 0xA002,不初始化。


上例中,有三个声明为常量的对象,第一个初始化为 0,第二个初始化为规定值,第三个不初始化。全部三个变量均在闪存中。


关键词举例
例 1

下例中,FLASH_CONFIG 为 FlashMemoryMap 结构变量。利用关键词#pragma location 和#pragma required 显式定义该结构变量的开始地址为“CONFIG_FLASH” (0xEE00)。


//Structure for Memory Map


typedef struct


{


  unsigned char SYSTEM_CONFIG;                //Address 0x00


  unsigned char TEMP_CONFIG;                  //Address 0x01


  unsigned char SLAVE_ADDR_A0;                //Address 0x02  


  unsigned char NULL_A0_3;                    //Address 0x03


  signed   int  INTERNAL_TEMP_THRES;          //Address 0x04-5


  signed   int  EXTERNAL_TEMP_THRES;          //Address 0x06-7


  signed   int  DS75_TEMP_THRES;              //Address 0x08-9


}FlashMemoryMap;

 

#define CONFIG_FLASH = 0xEE00 //Flash Address

 

#pragma location = CONFIG_FLASH   


const FlashMemoryMap FLASH_CONFIG =  //Initialize data objects variable


                            {


                              0x00,           // SYSTEM_CONFIG


                              0xFE,           // TEMP_CONFIG


                              0xA0,           // SLAVE_ADDR_A0


                              0x00,           // NULL_A0_3


                              0x3200,         // INTERNAL_TEMP_THRES


                              0x4200,         // EXTERNAL_TEMP_THRES


                              0x5200          // DS75_TEMP_THRES


                           };


#pragma required = FLASH_CONFIG


为了在 IAR 嵌入式工作台 IDE 中查看存储器分配和初始化,进入 View  Memory。在显示的编辑框中,在 Go to 框中键入 0xEE00,然后从下拉框中选择 Code,如图 5 所示。

 

图 5. 存储器分配


例 2

下例中,在地址 0x0116 创建 DATA SRAMMemoryMap 结构变量(DATA_MONITOR),该变量将被初始化(使用 __no_init 类型限定符)。
typedef struct


{


  //Read Only  


  signed int    INTERNAL_TEMP;                //Address = OFFSET + 0x00-1


  signed int    EXTERNAL_TEMP;                //Address  = OFFSET + 0x02-3


  signed int    DS75_TEMP;                    //Address  = OFFSET + 0x04-5


  signed int    VOLTAGE0;                     //Address  = OFFSET + 0x06-7


  signed int    VOLTAGE1;                     //Address  = OFFSET + 0x08-9


}SRAMMemoryMap;

 

#define CONFIG_SRAM 0x0116                    //SRAM Address 0x0116

 

#pragma location = CONFIG_SRAM


__no_init SRAMMemoryMap DATA_MONITOR; 


#pragma required = DATA_MONITOR


在 IAR 中调试时,为了查看该结构变量的内容,选择变量,点击右键,然后选择 Add to Watch 选项,参见图 6。

 

图 6. IAR 查看窗口


在 Intel® HEX 文件中查看分配的存储器
可在 IAR 嵌入式工作台生成的 Intel HEX 文件中查看在代码存储器中为数据对象分配的存储器。请参见图 7 中的高亮部分。本例中,为数据对象分配的存储器为闪存中 0xEE00 至 0xEE15。

 

图 7. 释放模式下 IAR 生成的 HEX 文件



示例代码

提供的示例代码中包含演示如何在闪存和 SRAM 中为变量分配存储器的文件,并演示如何读、写闪存中的变量。提供的文件有:
main.c 演示读、写闪存。


memory.h 演示在闪存和 SRAM 中创建数据对象及初始化。该文件使用 __no_init、const、pragma location 和 pragma required 关键词。


flash-c.zip 包括闪存读、写函数(C 函数)。