freescale S12X微控制器 模拟EEPROM 快速上手指南

来源:互联网 发布:淘宝封口棒视频 编辑:程序博客网 时间:2024/05/18 03:03

嵌入式开发中常有存储一些下电后不丢失的数据的需求,RAM访问起来很方便,但是下电后数据会丢失,而MC9S12XE提供了D-Flash和EEPROM用于存储非易失性数据。之前一直只是知道这个东西,但是一直都是看着prm中的这个地址范围干瞪眼,不知道怎么用,正好官方文档上有讲这个,赶快下下来学习学习。

翻译的资料是公开的,在这里下载https://www.nxp.com/products/microcontrollers-and-processors/additional-processors-and-mcus/8-16-bit-mcus/16-bit-s12-and-s12x-mcus/ultra-reliable-s12xe-high-performance-automotive-and-industrial-microcontrollers:S12XE?tab=Documentation_Tab,我想应该不会有什么版权问题,如涉及版权问题,请联系我删除文章。另感谢NXP提供的学习资料。


在用TBDML调试这个工程的时候你可能会发现(起码我是这样的),memory窗口中的EEPROM区域并没有在被修改后刷新,右键refresh也没用,但实际上重新Load代码时确会发现里头的值其实是更改过了。

这个问题困扰了我一会,然后机智的我就发现了原因。

这是由于调试器默认只加载一次全局地址和本地地址中的EEPROM这段地址范围,而不在暂停时重新读取。所以每次重新加载代码时就能看到之前的更改,而运行过程中却看不到。
解决方法如下:

如图,菜单栏TBDML HCS12 ->Debugging Memory Map

在弹出的Debugging Memory Map窗口中,先在列表框中找到并选择 global eeprom 那一行,然后点击 Modify/Detail 按钮。

然后勾上refresh memory when halt就行了(点OK什么的总不用再说了吧。),这样这段地址范围就会在每次程序暂停时都被重新读取了。然后就可以按照这篇教程中讲的观察到EEPRAM的变化了。


Emulated EEPROM Quick Start Guide

by: Matthew Grant
16-Bit Applications
Freescale Semiconductor

译者注:译者博客(http://blog.csdn.net/lin_strong),转载请保留这条。此为官方文档AN3743,仅供学习交流使用,请勿用于商业用途。

介绍

模拟EEPROM

S12X系列微控制器(MCUs)家族的一些成员,如MC9S12XEP100,的地址映射图中有一块被标记为EEPROM的增强型内存区域。这个区域并不是传统意义上的EEPROM,而是一种由增强型flash模块(FTM)通过特殊的算法管理flash和RAM而模拟出来的EEPROM。由于FTM允许划分EEPROM资源以满足应用实际需求,这给用户提供了很大的灵活性。

目标

这篇应用笔记的目标是帮助用户快速上手使用模拟EEPROM(EEE)。它特别适合于那些很熟悉编程与调试器的使用,但是不熟悉EEE的人。这篇文档会通过一些简单的EEE相关的示例来教导用户。我们会忽略最底层的细节,这样就可以集中注意力在与EEE相关的高层概念。用户会需要一个S12XE MCU的开发板和一个调试器以调试例子代码。这篇文档展示了:

  • EEE组件在地址映射图的哪个位置
  • 三类配置的示例
  • FTM命令流
  • 在不同的配置下,缓存RAM中数据会有什么行为

还介绍了其他重要的主题。想要了解EEE的更多细节的话,请查阅freestyle应用笔记AN3490, “MC9S12XE的模拟EEPROM综述”,可以在 www.freescale.com上下载它。

S12X地址映射图中的S12XE EEE

图1展示了这个增强型EEPROM区域在S12XE本地和全局地址映射中的位置。这个图还标注了增强型EEPROM的 D-flash 和 缓存RAM 组件。

S12XE地址映射中的EEPROM区域
图 1.S12XE地址映射中的EEPROM区域

配置增强型EEPROM区域

由于FTM的灵活性,有三种配置EEE的方式:

全部作为D-Flash 和 缓存RAM:所有的缓存RAM和所有的D-flash扇区都被用作传统的RAM和flash。没有创建EEE分区,没有启用EEPROM模拟。

EEPROM区域被配置为D-flash和缓存RAM
图 2.EEPROM区域被配置为D-flash和缓存RAM

全部作为EEE:所有EEE资源被全部分区为EEE。这会使所有的缓存RAM被用作EEE RAM,所有的D-flash被用作EEE flash。一旦启用了EEE,FTM会通过往EEE flash中存储数据记录使得EEE RAM中的数据变为非易失的。FTM会自动地管理这些记录,用户不用干涉。在下次MCU重置之后,直到EEE flash中的数据记录全被恢复到EEE RAM中,FTM会阻止中央处理单元(CPU)执行指令。这种数据管理使得EEE RAM看起来就好像EEPROM,而且用户还可以在任意时刻修改其中的数据。

EEPROM区域被配置为EEE
图 3.EEPROM区域被配置为EEE

作为EEE、D-Flash 和 缓存RAM:这是一种混合配置。缓存RAM和D-flash的一部分分别被划分为EEE RAM和EEE flash。剩下的区块和扇区仍然作为缓存RAM和D-flash使用。放在EEE RAM中的数据会由FTM管理以支持EEE。

EEPROM区域被配置为EEE、D-flash和缓存RAM
图 4.EEPROM区域被配置为EEE、D-flash和缓存RAM

发起FTM命令

为了写、读或配置与FTM有关的地址区域,必须把命令装载入FTM并执行。这个过程涉及一个用来设置FTM命令参数并启动执行的特殊序列。以下代码片提取自一个函数,”LaunchFlashCommand”,它被用于设置和执行FTM命令。用户应该遵循特定的流程以降低发生模块错误的风险。图5展示了推荐的FTM命令执行流程。

FSTAT = 0x30; //Use store instruction to clear ACCERR, FPVIOL./**********SET UP THE FTM COMMAND AND PARAMETERS***********/FCCOBIX = 0; //Set CCOB index to 0 to begin command setup.FCCOBHI = ccob0high; //Write ccob0 high-byte command value.FCCOBLO = ccob0low; //Write ccob0 low-byte parameter, if used.if (params > 0) //Continue if more parameters to specify.{  FCCOBIX++;  FCCOB = ccob1; //Write next word parameter to CCOB1 buffer.  if (params > 1) //Continue if more parameters to specify.  {     FCCOBIX++;     FCCOB = ccob2; //Write next word parameter to CCOB2 buffer.     if (params > 2) //Continue if more parameters to specify.     {        FCCOBIX++;        FCCOB = ccob3; //Write next word parameter to CCOB3 buffer.        if (params > 3) //Continue if more parameters to specify.        {           FCCOBIX++;           FCCOB = ccob4; //Write next word parameter to CCOB4 buffer.           if (params > 4) //Continue if more parameters to specify.           {               FCCOBIX++;               FCCOB = ccob5; //Write next word parameter to CCOB5 buffer.               if (params > 5) //Continue if more parameters to specify.               {                  FCCOBIX++;                  FCCOB = ccob6; //Write next word parameter to CCOB6 buffer.                  if (params > 6) //Continue if more parameters to specify.                  {                     FCCOBIX++;                     FCCOB = ccob7; //Write next word parameter to CCOB7 buffer.                  }               }            }        }     }  }}/**********************************************************/FSTAT = 0x80; //Clear buffer-empty-flag to start FTM command.while (!FSTAT_CCIF); //Now wait for the FTM command to complete.status.fstat_var = FSTAT; //Copy FSTAT register state for later comparison.status.ferfstat_var = FERSTAT; //Copy FERSTAT register state for later comparison.return(status); //After FTM command completed, return status.

FTM命令执行流程图
图 5.FTM命令执行流程图

检查错误

每个FTM命令完成后都会置位CCIF标志位,检查flash状态寄存器也很重要。当遇到特定的错误时,FSTAT和FERSTAT寄存器中对应的错误标志位会被置位。如果探测到了错误,用户应该使用软件进行相应处理,然后清零错误标志位。当寄存器如FSTAT和FERSTAT有多个被置位的标志位时(标志位是通过写1来清零的),用户应该避免使用BSET指令来清零这些标志位。这可能导致无意间清零了寄存器中的其他标志位。如果可以的话,更推荐使用STAA或STAB指令。

EEEPROM Quick Start工程设置

包含这篇应用笔记示例代码的工程”EEEPROM Quick Start”可以从freescale的网站上下载。没有编译器的用户可以下载免费版本的CodeWarrior™ for the S12X。首先打开“EEEPROM_Quick_Start.mcp”工程文件。打开后,用户可以选择并打开“main.c”文件,其中包含了这篇应用笔记中引用的大部分代码。文件中按照这篇文档中对应的步骤放好了注释。

在尝试编译并加载工程之前,先要检查一些重要设置。首先,先根据你用来编程MCU的通讯设备选择一个target。

然后,必须定义一个合适的flash时钟分频值(FCLK_DIV)以保证FTM正常工作。在“main.c”中的时钟分频部分,用户应该取消合适的FCLK_DIV值前的注释,或者根据MCU板上振荡器的频率重新定义一个分频值。可以在S12XE flash block指南中找到一个查询表。在这个示例中,代码并没有使用 时钟生成器(CRG)模块,而是完全使用了外部振荡器。

//CLOCK DIVIDE SECTION//Uncomment the FCLK_DIV value according to the oscillator crystal.//These values are chosen from the MC9S12XE100 datasheet.//#define FCLK_DIV 0x1 // Flash clock divider for 2MHz crystal#define FCLK_DIV 0x3 // Flash clock divider for 4MHz crystal//#define FCLK_DIV 0x7 // Flash clock divider for 8MHz crystal//#define FCLK_DIV 0x9 // Flash clock divider for 10MHz crystal//#define FCLK_DIV 0x18 // Flash clock divider for 26MHz crystal

后面的代码片定义了分区EEPROM资源的参数。使用了宏来在编译工程之前定义EEE的大小。定义了要设置为EEE RAM的缓存RAM的数量,以及要保留为D-flash的flash数量。D-flash剩下的资源会被用作EEE flash。一旦定义好了,这些参数之后就会被用于FTM命令以完全分区和实现EEE。

可以改为其他设置。用户可以在一定数量限制和比例限制下调整这些参数,如AN3490中所述。

//EEE SIZE SECTION/**** SET THE SIZE OF THE EEE HERE ****/#define EEE_RAM 1 //Specify the # of EEE RAM sections for the FTM (Flash                  //module) to use as EEE. The valid range is 0-16 sections./**** CALCULATES AMOUNT OF DATA FLASH FOR GENERAL USE ****/#if(EEE_RAM == 1)   #define DFPART (128 - 12)#else   #define DFPART (128 - (8 * EEE_RAM))

当FTM使用了上面的参数,也就是1个区块的EEE RAM与12个扇区的EEE flash,创建了一个完全分区。剩下的区块和扇区就会分别用作缓存RAM和D-flash。尽管flash中实际存在着扇区这个物理分块,这里说的“区块(section)”只是对缓存RAM的想象分块。图6展示了对EEE 区域进行配置后的分块图。图中清晰地标识了缓存RAM区块。在这里,随着缓存RAM地址的增加,区块号是递减。当EEE被使能后,FTM会把新写入EEE RAM中数据的对应数据记录存储在EEE flash中。

示例配置:1 EEE RAM扇区 12 EEE Flash区块
图 6.示例配置:1 EEE RAM扇区 12 EEE Flash区块

为了使用这个示例,把代码编译并加载进S12XE MCU。如果使用的是CodeWarrior,则会出现调试器。图7是调试器的一张截屏,可以使用memory窗口和变量来观察EEPROM区域内的寄存器值和数据值。后面还有许多图以强调工程内的重要步骤。

调试器示例
图 7.调试器示例

访问EEPROM

为了在EEPROM区域内进行读写,可以让指针指向对应的地址。这是在主函数的开头完成的,如下面的代码以及图8中所示。在编程示例的不同阶段,文本字符串会被分别写入EEE RAM与缓存RAM的相邻区块1和2。这里使用相邻的区块是为了更方便在memory窗口内观察它们不同的行为。随着程序一步步的执行,应该能观察到每一步后文本字符串的行为。这能帮助用户理解拥有模拟特性的EEE RAM与普通的缓存RAM间的差异。

/******************************************************************************/voidmain(void){volatile char before[]="BEFORE"; //Chars to be written to the EEE and Buffer RAMvolatile char during[]=" DURING";//Chars to be written to the EEE and Buffer RAMvolatile char after[]=" AFTER";  //Chars to be written to the EEE and Buffer RAMsigned char dfPart, erPart;      //Holds EEE partition size of data Flash and buffer RAMchar * section1_ptr;             //Points to location within section1 of buffer RAMchar * section2_ptr;             //Points to location within section2 of buffer RAMvolatile ErrType status;   EnableInterrupts;   section1_ptr = (signed char *) 0x0F00;//Assign beginning address of section1 of                                         //EEE RAM to pointer.   section2_ptr = (signed char *) 0x0E00;//Assign beginning address of section2 of                                         //buffer RAM to pointer.

赋值地址给指针
图 8.赋值地址给指针

学习EEE Quick Start代码的步骤

这篇应用笔记的剩下部分按序讲了main函数内标注的十个步骤。每个步骤后面都有对应的代码。用户应该使用一个调试器来执行代码并观察调试器memory窗口内发生的变化。这有助于理解EEE的一些行为。

①将先前定义的FCLK_DIV值写入flash时钟分频寄存器(FCLKDIV)。在提交任何命令给FTM之前必须进行这一步。

/*********(1)SET UP THE FLASH CLOCK DIVIDE REGISTER********/while (!FSTAT_CCIF)                  //Wait for FTM to be ready{}FCLKDIV = FCLK_DIV;                  //Now write FCLKDIV before using the FTM.if(FCLKDIV != (FCLK_DIV | 0x80))     //Ensure the value is written.   ReportError(FDIV_NOT_SET);        //Report an error code./**********************************************************/

②在数据被修改之前,使用调试器的memory窗口分别看下EEE RAM和缓存RAM的区块1和2中的内容。

/****(2)CHECK BUFFER RAM CONTENTS FROM THE PREVIOUS RUN****///Before any FTM commands are executed, check the debugger memory//window and observe the contents of sections 1 (0xF00 to 0xFFF)//and 2 (0xE00 to 0xEFF) of the buffer RAM./**********************************************************/

③“LaunchFlashCommand”函数是用于接受参数并执行FTM命令的。在这一步,会执行一次完全分区命令,它会擦除并初始化EEE RAM和EEE flash。之后,调试器的memory窗口(图9)会显示所有EEE RAM(分区1)中的数据都处于擦除状态(0xFFFF)。相邻的缓存RAM区块中则是看上去随机的数据,它不由FTM管理。用户总是应该在FTM命令执行完后查看FSTAT和FERSTAT寄存器以检查命令是否出错。

/***********(3)PERFORM FULL PARTITION OF EEE RAM***********/#ifdef FORCE_PARTITON_FOR_DEBUG     //If defined, force EEE partition and eraser.   //Run LaunchFlashCommand to partition and erase the EEE in debug mode.   //Return the status of the FSTAT and FERSTAT Flash registers.   status = LaunchFlashCommand(2 ,FULL_PARTITION_D_FLASH, 0, DFPART, EEE_RAM, 0, 0, 0, 0, 0);   //Always check if any error bits are set.   ErrorCheck(status, accerr|fpviol|mgstat1|mgstat0, erserif|pgmerif|epviolif|ersvif1|ersvif0|dfdif|sfdif);#endif/**********************************************************/

EEPRAM被擦除之后的数据
图 9.EEPRAM被擦除之后的数据

④使用查询命令来检查分区。可以从FCCOBLO寄存器中回读参数。如果参数是对的,则说明EEE被正确的分区了。

/*****************(4)CHECK EEE PARTITIONING****************///Use flash command function to query the EEEPROM partitioning.//Return the status of the FSTAT and FERSTAT Flash registers.status = LaunchFlashCommand(0 ,EEPROM_QUERY, 0, 0, 0, 0, 0, 0, 0, 0); //Check the EEE status//Check if any error bits are set.ErrorCheck(status, (accerr|fpviol|mgstat1|mgstat0), (erserif|pgmerif|epviolif|ersvif1|ersvif0|dfdif|sfdif));FCCOBIX = 1;       //Set CCOB index to get Data flash partition result.dfPart = FCCOBLO;  //Copy Data flash partition result.FCCOBIX++;         //Set CCOB index to get EEE RAM partition result.erPart = FCCOBLO;  //Copy EEE RAM partition result.#ifdef FORCE_PARTITON_FOR_DEBUG  //If defined, check that the FTM properly allocated                                 //and erased the EEE sectors in buffer RAM.//Use query results to determine if D-Flash has been partitioned//for EEEPROM with erPart == EEE_RAM and dfPart == DFPART.if (EEE_RAM > 0){   if((erPart != EEE_RAM) || (dfPart != DFPART))      ReportError(PARTITION_MISMATCH);    //Full Partition was UNsuccessful}else if((erPart != -1) || (dfPart != -1)){   ReportError(PARTITION_MISMATCH);       //EEE_RAM might be out of range (0-16)}#endif/**********************************************************/

⑤这一步是为了说明:用户可以在使能EEE之前自由地读写EEE RAM。测试字符串“BEFORE”被写在区块的开头。为了比较,缓存RAM中的那个相邻的区块也写入了同个字符串。这种情况下,数据表现为易失的数据,如果这时下电重启的话,不管是缓存RAM中的数据还是EEE RAM中的数据都会丢失,这是由于FTM并没有为EEE RAM创建记录。在后面几步还会检查这些字符串。

/****(5)WRITE PATTERN TO EEE SECTIONS BEFORE EEE ENABLED***///Now write the character pattern, "BEFORE", to the beginning of the//1st and 2nd buffer RAM sections. The 1st 256byte section is partitioned//as EEE RAM. The 2nd and remaining sections are general user RAM.section1_ptr = copy_string(&before, section1_ptr);//Copy "BEFORE" to EEE RAMsection2_ptr = copy_string(&before, section2_ptr);//Copy "BEFORE" to user RAM/**********************************************************/

⑥这一步使能EEE。一旦被使能,EEE就会意识到,来自步骤⑤的,新数据已经被加入EEE RAM(区块1)中。FTM会生成新EEE RAM数据的记录并存储到EEE flash中。然而,写在缓存RAM(区块2)中的同样的数据不会被备份,因为这个区块不是EEE RAM。

/**************(6)ENABLE WRITES OF EEE RECORDS***************///This enables the FTM to take any revised data written to the EEE//partitioned section(s) of the buffer RAM and update the record(s)//in the EEE partitioned section(s) of data Flash.#ifdef ENABLE_EEE_RECORD_WRITING   if(erPart > 0)   {      //Use flash command function to enable the FTM to manage EEE data and records.      //Return the status of the FSTAT and FERSTAT Flash registers.      status = LaunchFlashCommand(0 ,ENABLE_EEPROM_EMULATION, 0, 0, 0, 0, 0, 0, 0, 0);      //Check if any error bits are set.      ErrorCheck(status, (accerr|fpviol|mgstat1|mgstat0),(erserif|pgmerif|epviolif|ersvif1|ersvif0|dfdif|sfdif));   }/**********************************************************/

⑦下面的指令则说明了:在EEE被使能后,用户还是可以任意读写EEE RAM。然而,FTM可能会拷贝写入EEE RAM的数据以用于存储并在EEE Flash中维护数据的记录。”DURING”是下一个要写入的文本字符串,它被放在之前的字符串的后面。应该能在调试器的memory窗口内看到这个文本字符串,如图10所示。

/****(7)WRITE PATTERN TO EEE SECTORS WHILE EEE ENABLE****///Now write the character pattern, "DURING", after the character string,//"BEFORE", which is at the beginning of the 1st and 2nd buffer RAM sections.//The 1st 256byte section is partitioned as EEE RAM. The 2nd and remaining//sections are general user RAM.section1_ptr++;                                   //Move to next character positionsection2_ptr++;                                   //Move to next character positionsection1_ptr = copy_string(&during, section1_ptr);//Copy "DURING" to EEE RAMsection2_ptr = copy_string(&during, section2_ptr);//Copy "DURING" to user RAM/**********************************************************/

执行步骤⑦后的结果
图 10.执行步骤⑦后的结果

⑧接下来,EEE会被禁用。但是,在禁用EEE之前,会先进行状态检查以确保FTM当前不在忙并且所有被修改过的EEE RAM数据对应的记录都已经被更新了。可以用ETAG寄存器来追踪还未被存储和更新的挂起的记录的数量。当ETAG读取为0时,所有的记录就都被更新完毕了。(译者注:还需要确定FTM存储控制器不在忙,才能确定所有数据都被更新完毕)

/**************(8)DISABLE WRITES OF EEE RECORDS**************/if(erPart > 0){   //Wait for FTM to store new EEE RAM data into EEE Flash.   while(FSTAT_MGBUSY || ETAG)   {      //Wait for FTM to finish writing data records to EEE Flash.   }   //Use to DISable the FTM from managing EEE data and records.   //Return the status of the FSTAT and FERSTAT Flash registers.   status = LaunchFlashCommand(0 ,DISABLE_EEPROM_EMULATION, 0, 0, 0, 0, 0, 0, 0, 0);   //Check if any error bits are set.   ErrorCheck(status, (accerr|fpviol|mgstat1|mgstat0), (erserif|pgmerif|epviolif|ersvif1|ersvif0|dfdif|sfdif));   }#endif/************************************************************/

⑨写最后一个字符串(“AFTER”)到EEE RAM和缓存RAM中。在调试器中观察字符串。memory窗口应该与图11看起来很像。

/*****(9)WRITE PATTERN TO EEE SECTORS AFTER EEE DISABLE****///Now write the character pattern, "AFTER", after the character string,//"DURING", which is at the beginning of the 1st and 2nd buffer RAM sections.//The 1st 256byte section is partitioned as EEE RAM. The 2nd and remaining//sections are general user RAM.section1_ptr++;                                  //Move to next character positionsection2_ptr++;                                  //Move to next character positionsection1_ptr = copy_string(&after, section1_ptr);//Copy "AFTER" to EEE RAMsection2_ptr = copy_string(&after, section2_ptr);//Copy "AFTER" to user RAM/**********************************************************/

执行步骤⑨后的结果
图 11.执行步骤⑨后的结果

⑩这一步不需要执行任何代码,只需要在内存窗口内进行观察。到现在,我们已经证明了,只要CPU在活跃状态,数据总是可以被写入缓存RAM或EEE RAM区块中。memory窗口应该会在EEE RAM和相邻的缓存RAM中显示这三个字符串 — “BEFORE”、”DURING”和”AFTER”。以下子步骤则揭示了缓存RAM与EEE RAM的差异。

a) 使用调试器进行一次重置。在重置之后,FTM会将以数据记录形式存储在EEE flash中的数据拷贝回EEE RAM中。这时,CPU如果企图在FTM完成拷贝过程之前访问EEE RAM,将会导致CPU暂停运行,直到拷贝过程完成。现在的memory窗口应该与图12类似。注意,EEE RAM中的文本字符串”AFTER”不见了。这是由于EEE flash中并没有这个字符串对应的记录。因此,FTM把这个地址的所有字符串都设为了擦除状态。反之,尽管缓存RAM是易失性存储器,但在相邻的缓存RAM区块中的所有三个字符串仍然在那里。这是因为MCU并没有经历下电重启(power cycled)。
重置之后的EEE RAM和缓存RAM
图 12.重置之后的EEE RAM和缓存RAM

b) 现在退出调试器应用程序。下电重启MCU以强制所有的缓存RAM和EEE RAM丢失数据。重新用调试器连接MCU;可以通过把同样的代码重新编程进MCU来做这件事。

c) 不执行任何代码,观察memory窗口,你会注意到缓存RAM中的所有三个字符串都消失了。消失的字符串证明了缓存RAM的易失性。而EEE RAM中则仍然存在”BEFORE”和”DURING”字符串,因为它们被FTM从EEE flash中恢复了。这个特性使得FTM能使用flash和RAM资源来模拟EEPROM。

总结

S12X flash模块的EEEPROM特性是最新的增强特性,它允许用户灵活地配置EEPROM区域内的存储行为。在完成这个示例后,用户就明白了以下知识点:

  • EEPROM区域的位置以及它的物理子部件:缓存RAM和D-flash
  • EEPROM区域的可选配置
  • FTM命令执行流
  • 总是在执行FTM命令后进行错误检查的必要性
  • 数据被写入缓存RAM和EEE RAM后会有什么表现
    • 在EEE使能之前
    • 当EEE使能时
    • 在EEE被禁用后
  • 当EEE被分区后,重置后如果CPU试图读写EEE RAM区域,那CPU会一直暂停直到FTM完成从EEE flash的数据记录中恢复所有记录到EEE RAM中的这个过程。

尽管这篇应用笔记强调了EEE的一些特性,还有许多细节没讲。请参考freestyle应用笔记AN3490, “MC9S12XE的模拟EEPROM综述”来更深入的了解EEE。

原创粉丝点击