堆栈
SP 是用来记录堆栈地址的寄存器,SP 会指向堆栈的顶端。堆栈是一个先进后出的内存结构,µ’nSP™的堆栈结构是由高地址往低地址的方向来储存的。CPU 执行push、子程序呼叫call、以及进入中断服务子程序(ISR,Interrupt Service Routine) 时,会储存寄存器内容在堆栈里,这时SP 会递减以反映堆栈用量的增加。当CPU 执行pop、子程序返回ret、以及从ISR 返回reti 时,SP 会递增以反映堆栈用量的减少。
µ’nSP™堆栈的大小限制在2K 字的SRAM 内,即地址为0x000000~0x0007FF 的内存范围中。SPCE061A 系统复位后,SP 初始化为0x07FF,每执行push 指令一次,SP 指针减一。
闪存Flash
SPCE061A 是一个用闪存替代mask ROM 的MTP(multi-time-programmable)芯片,闪存可以进行多次的擦除与写入,可用来存储程序与数据。SPCE061A 具有32K 字(32K×16 位)闪存容量,这32K 字的内嵌闪存被划分为128 个页,每个页存储容量为256 个字。它们在CPU 正常运行状态下均可通过程序擦除或写入。全部32K 字闪存均可在ICE 工作方式下被写入或被擦除。为了安全起见,不对用户开放整体擦除功能。
用户必须通过向P_Flash_Ctrl (写) ($7555H)单元写入0xAAAA,来启用闪存的存取功能。然后,向P_Flash_Ctrl (写) ($7555H)单元写入0x5511,来擦除页的内容。写入0x5533,对闪存写入。这些指令不能被任何其它的操作打断,包括中断、ICE 的单步跟踪动作。这是因为闪存控制器必须保证闪存处于写入状态。如果其它的操作打乱了这个顺序,闪存的状态将发生改变,擦除页和写入的操作不能再继续进行。
此外,为保证数据的正确写入,用户必须在写入之前擦除页的内容。页大小为0x100。第一页地址范围:0x8000~0x80FF,最后一页的地址范围:0xFF00~0xFFFF。0xFC00~0xFFFF范围内的地址由系统保留,用户最好不要用本范围内的地址。
1 读取操作
在芯片上电后,闪存就处于读取状态,读取的操作与SRAM 相同。
2 擦除操作
在对闪存写入数据前,必须对闪存进行擦除操作。由于闪存采用分页的数组结构,使得各个存储页可以被独立地擦除。当用户向闪存控制接口发出页擦除命令以后,只要向某个地址写入任意的数据,对应到这个地址的的记忆页就被擦除。要保证擦除操作的正确完成,必须考虑以下几个参数:
1. 该闪存的内部分页结构。
2. 每个页分区的擦除时间。
3 写入操作
闪存芯片的写入操作是自动字节写入, 既可以循序写入,也可指定地址写入。闪存的地址空间为0x8000—0xFFFF,闪存控制接口的地址为0x7555 。第一页范围是[0x8000—0x80FF],最后一页范围是[0xFF00—0xFFFF]。
1. 擦除一页的流程是:先对命令用户接口地址0x7555 送出0xAAAA,然后再对命令用户接口地址0x7555 送出0x5511,再来对要擦除的记忆页地址写入任意数据,约20ms 即可完成擦除操作,之后就可以再进行其它操作。例如擦除第6 页[0x8500—0x85FF]流程如下:(1)0x7555 ←0xAAAA (2) 0x7555 ←0x5511(3)0x85XX←0xXXXX (其中X 为任意值)。
2. 写入一个字的流程是:先对命令用户接口地址0x7555 送出0xAAAA,然后再对命令用户接口地址0x7555 送出0x5533,再来对要写入字的地址写入数据,约40us 即可完成写入操作,之后就可以再进行其它操作。例如向0x8000记忆地址写入0xffff 流程如下:(1)0x7555 ←0xAAAA (2) 0x7555 ←0x5533 (3) 0x8000←0xFFFF
3. 连续写入多个字的流程是:先对命令用户接口地址0x7555 送出0xAAAA,然后再对命令用户接口地址0x7555 送出0x5544,再给要连续写入字的起始地址写入字数据,约40us 即可完成1 个字的写入操作。再对命令用户接口地址0x7555 送出0x5544,再对后续要写入的字地址写入字数据,等待40us,循环操作即可完成连续字的写入。
上面所提到延时等待是由硬件完成,不需要软件延时。
以上所介绍的闪存擦除及写入操作,一般用于执行中数据的储存。例如,当我们把一小段程序写入闪存后,假设程序代码占用的空间不大(例如5 字K 字),我们就可以在程序代码后面的空间(5K~32K)存储一些数据,这样就需要对这一段闪存空间(5K~32K)进行上述的写入或擦除操作。前提条件是,必须计算出程序代码所占用的空间。
[例2.4]:
//================================================================
//程序名称:FLASH.asm
//描述:擦除、写入1 个字、写入多个字子程序
//================================================================
.INCLUDE hardware.inc
.DEFINE C_FLASH_SIZE 0x8000 //定义flash 的空间为32K 字
.DEFINE C_FLASH_BLOCK_SIZE 0x0100 //定义共分为256 页
.DEFINE C_FLASH_MATCH 0xAAAA
.DEFINE C_FLASH_PAGE_ERASE 0x5511 //擦除一页控制字
.DEFINE C_FLASH_1WORD_PGM 0x5533 //写一个字的控制字
.DEFINE C_FLASH_SEQUENT_PGM 0x5544 //写多个字的控制字
.CODE
//================================================================
//函数 名称: F_FlashWrite1Word()
//描述:写一个字到FLASH 中
//传入参数:1、Flash 写入地址2、欲写入的数据
//无返回值
//================================================================
.public _F_FlashWrite1Word
.DEFINE P_Flash_Ctrl 0x7555
_F_FlashWrite1Word: .proc
PUSH BP TO [SP] //将BP 压入堆栈内
BP = SP + 1 //BP的值变为SP+1
R1 = C_FLASH_MATCH //先送AAAA
[P_Flash_Ctrl] = R1
R1 = C_FLASH_1WORD_PGM //再送5533
[P_Flash_Ctrl] = R1
R1 = [BP+3] //取Flash 写入地址
R2 = [BP+4] //取欲写入的字数据
[R1] = R2 //把数据写入内存单元中
POP BP FROM [SP] //出堆栈
RETF //子程序返回
.ENDP
//================================================================
//函数名称: F_FlashWrite()
//描述:连续写多个字
//传入参数:1、Flash 写入起始地址2、欲写入数据的起始地址3、写入的数量
//无返回值
//================================================================
.public _F_FlashWrite
_F_FlashWrite: .proc //子程序的开始
PUSH BP TO [SP] //将BP 压入堆栈内
BP = SP + 1 //BP的值变为SP+1
R1 = [BP+3] //取Flash 写入起始地址
R2 = [BP+4] //取欲写入数据的起始地址
R3 = [BP+5] //写N 个字
R4 = C_FLASH_MATCH //将AAAA 送到控制单元
[P_Flash_Ctrl] = R4
L_FlashWriteLoop:
R4 = C_FLASH_SEQUENT_PGM //把5544 送到控制单元
[P_Flash_Ctrl] = R4
R4 = [R2++] //继续下一个数的写入
[R1++] = R4
R3 -= 1 //计数减一
JNZ L_FlashWriteLoop //不为0 时继续进行写入操作
[P_Flash_Ctrl] = R3 //写入结束
POP BP FROM [SP] //出堆栈
RETF //子程序返回
.ENDP
//================================================================/
//
//函数名称: F_FlashErase()
//描述:擦除256 字节
//传入参数:1、擦除页的任一个地址
//================================================================
.public _F_FlashErase
_F_FlashErase: .proc //擦除一页的子程序
PUSH BP TO [SP] //将BP 压入堆栈内
BP = SP + 1
R1 = C_FLASH_MATCH //先将AAAA 送到控制单元
[P_Flash_Ctrl] = R1
R1 = C_FLASH_PAGE_ERASE //再将5511 送到控制单元
[P_Flash_Ctrl] = R1
R1 = [BP+3] //取擦除页的任一个地址
[R1] = R1 //写入任意值进行擦除
POP BP FROM [SP] //出堆栈
RETF //子程序返回
.ENDP