C8051F12X中多bank的分区跳转处理
时间:09-21
来源:互联网
点击:
在8051核单片机庞大的家族中,C8051F系列作为其中的后起之秀,是目前功能最全、速度最快的8051衍生单片机之一,正得到越来越广泛的应用。它集成了嵌入式系统的许多先进技术,有丰富的模拟和数字资源.是一个完全意义上的SoC产品。
C805IF12X作为该系列中的高端部分,具有最快100MIPS的峰值速度,集成了最多的片上资源。其128 KB的片上Flash和8 KB的片上RAM足以满足绝大多数应用的需求。使用C8051F12X,只需外加为数不多的驱动和接口,就可构成较大型的完整系统。只是其中128 KB的Flash存储器不可避免地要处理bank分区问题。
幸运的是Keil C51开发环境对C8051F系列有良好的支持,包括一般的跨bank分区的程序跳转和调用。作为数据存储器使用时,Flash的分区读写完全是编程者要考虑的事情,与开发环境无关。本文只针对特殊的强制转移和μC/OS—II在多bank分区中的移植问题展开讨论。
1 C8051F12X在Keil C51中的多bank分区转移机制
Keil C51的连接定位器支持分组连接,允许生成代码长度大于64 KB的8051目标程序_1_。一般的8051系统只提供16根地址线,需要附加地址线来实现代码分组切换,而编译器产生bank切换代码时受到配置文件L51_BANK.A51的支持,所以用户必须根据自己的硬件结构来修改这个配置文件。
C8051F12X系列不用考虑硬件部分,也不存在地址线的扩展问题,因为128 KB的4个bank区全部都在CPU内部,所以作为常规跨bank的跳转和调用,不需要处理L51_BANK.A51配置文件。但在特殊情况下就必须考虑该问题,否则程序将无法工作。下面以C8051F120为例先讨论代码的透明分组切换过程。
C805IF120在Keil C51的项目配置中被划分为4个bank,每个32 KB。公共bank地址从0"0x7fff,其余bank从0x8000h"0xffff。在对应的配置文件L51_BANK.A51中,涉及到特殊功能寄存器PSBANK(SFR地址:0B1H)、SWITCHn宏、B_BANKn、?B_SWITCHn分组信息保存和切换代码,以及?B_CURENTBANK变量。
PSBANK为C8051F120内的特殊功能寄存器,128KB Flash的分bank访问就是通过它来实现的。要想转移到新的bank中去,必须赋予PSBANK正确的值,然后再转向bank区内地址即可。
SWITCHn宏共有4个,分别是SwITCH0、SWITCH1、SWITCH2和SWITCH3,对应切换到4个bank中。其中SWITCH0对应的语句为:
MOV PSBANK.#00h ;把00h用1Ih、22h和33h替换;就是其他三个宏它将插入到?B_SWITCHn代码中,用来切换新的bank和恢复到原来的bank。
所有4组?B_BANKn和?B_SWITCHn代码也都是用宏实现的,对应4个bank处理。它们汇集在?BANK?SWITCH代码段中,整个bank切换及恢复机制非常巧妙,可以实现任意bank之间函数的相互调用及嵌套。下面以bank3区中的main函数调用bank1区的Delay_noOS()延时函数为例说明该机制。
void main(void){
MCUInit(); //初始化CPU
Delay_n00s(10); //延时lO ms
Lcmlnition();
bank3中被调用的函数Delay_noOS(10)对应的汇编语句为:
LCALL C:5049
公共段(即Common段,对应bank0)中C:5049处的汇编语句如下:
MOV dptr,#Delay_noOS
AJMP B_BANK1
这里的B_BANK1就是宏?B_BANK&N中N为1的例程。现在进入问题的核心:全部的跨bank区程序切换及恢复过程依靠公共段中?BANK?SWITCH代码段里的以下汇编代码实现,对应的N为0、1、2和3。?BANK?SWITCH SEGMENT CODE PAGE
;
?B_BANK&N:
PUSH ?B_CURRENTBANK (1)
MOV A,#HIGH?BANK?SWITCH (2)
PUSH ACC (3)
PUSH DPL (4)
PUSH DPH (5)
?B_SWITCH&N:
MOV ?B_CURRENTBANK,#LOW? B_SWITCH&N
(6)
SWITCH&N (7)
RET (8)
:
Delay_noOS(10)函数的返回地址,即函数LcmIni-tion()的入口地址(也在bank3中),其高低位字节表示为ADDH和ADDL。程序进入main()后的?B_CURRENTBANK变量初值是?B_SWITCH3的低8位,其意义稍后叙述。AJMP B_BANK1后程序执行?B_BANK1和?B_SWITCH1的(1)~(8),执行到(5)时的堆栈结构如图1所示。
继续执行?B_SWITCH1到(7)时,PSBANK变为指向bank1,?B_CURRENTBANK变为?B_SWITCH1的低8位。执行(8)后,从堆栈结构可以看出,堆栈弹出①作为新的PC值,程序进入Delay_noOS(10)函数,延时功能完成后,函数最后一条RET指令开始返回。这是Keil C51处理bank机制的关键,此时的返回地址为堆栈中的②,此地址即?B_SWITCH&H代码的入口,这里对应main()函数所在的bank3分组,也就是?B_SWITCH3的人口。
因为所有?B_SWITCH&N的高8位地址,即?BANK?SWITCH代码段的高8位都一样,由语句(2)中的操作符HIGH?BANK?SWITCH确定;低8位保存在已经压栈的?B_CURRENTBANK变量中,此时堆栈中的?B_CURRENTBANK压栈值是?B_SWITCH3的低8位,这样②的地址就是?B_SWITCH3。
程序继续执行?B_SWITCH3,在执行?B_SWITCH3的(6)语句之前,?B_CURRENTBANK还是前面执行?B_SWITCH1时的值,即?B_SWITCH1的低8位。执行语句(6)后,?B_CURRENTBANK恢复为?B_SWITCH3的低8位,为返回main函数做准备。然后PSBANK置为33h,即指向bank3,接着执行RET语句,堆栈③成为RET的返回地址,程序回到了main()中Delay_noOS(10)的下一条语句继续执行,?B_CURRENTBANK也已恢复。
这个调用过程中,用了6个堆栈字节,3条RET指令,关键内容就是?B_CURRENTBANK变量,它保存了可以恢复调用前bank环境代码的地址低位。从被调用函数返回 到这个地址后,就能恢复调用前的bank环境,即赋予PSBANK正确的值。
不采用直接保存PSBANK值然后再恢复,而是用压栈的方式保存了相关地址(语句(1)~(3)),是为了实现跨bank区的嵌套调用。例如,在Delay_noOS(10)函数中,如果再次跨bank去调用新函数,会再次重复上述过程,堆栈从②往上再长6个字节。Delay_noOS(10)函数之前执行?B_SWITCHI产生的?B_CURRENTBANK值(?B_SWITCHI的低8位)也会进栈,为调用完新函数后返回到bank1继续执行Delay_noOS(10)提供保证。
C805IF12X作为该系列中的高端部分,具有最快100MIPS的峰值速度,集成了最多的片上资源。其128 KB的片上Flash和8 KB的片上RAM足以满足绝大多数应用的需求。使用C8051F12X,只需外加为数不多的驱动和接口,就可构成较大型的完整系统。只是其中128 KB的Flash存储器不可避免地要处理bank分区问题。
幸运的是Keil C51开发环境对C8051F系列有良好的支持,包括一般的跨bank分区的程序跳转和调用。作为数据存储器使用时,Flash的分区读写完全是编程者要考虑的事情,与开发环境无关。本文只针对特殊的强制转移和μC/OS—II在多bank分区中的移植问题展开讨论。
1 C8051F12X在Keil C51中的多bank分区转移机制
Keil C51的连接定位器支持分组连接,允许生成代码长度大于64 KB的8051目标程序_1_。一般的8051系统只提供16根地址线,需要附加地址线来实现代码分组切换,而编译器产生bank切换代码时受到配置文件L51_BANK.A51的支持,所以用户必须根据自己的硬件结构来修改这个配置文件。
C8051F12X系列不用考虑硬件部分,也不存在地址线的扩展问题,因为128 KB的4个bank区全部都在CPU内部,所以作为常规跨bank的跳转和调用,不需要处理L51_BANK.A51配置文件。但在特殊情况下就必须考虑该问题,否则程序将无法工作。下面以C8051F120为例先讨论代码的透明分组切换过程。
C805IF120在Keil C51的项目配置中被划分为4个bank,每个32 KB。公共bank地址从0"0x7fff,其余bank从0x8000h"0xffff。在对应的配置文件L51_BANK.A51中,涉及到特殊功能寄存器PSBANK(SFR地址:0B1H)、SWITCHn宏、B_BANKn、?B_SWITCHn分组信息保存和切换代码,以及?B_CURENTBANK变量。
PSBANK为C8051F120内的特殊功能寄存器,128KB Flash的分bank访问就是通过它来实现的。要想转移到新的bank中去,必须赋予PSBANK正确的值,然后再转向bank区内地址即可。
SWITCHn宏共有4个,分别是SwITCH0、SWITCH1、SWITCH2和SWITCH3,对应切换到4个bank中。其中SWITCH0对应的语句为:
MOV PSBANK.#00h ;把00h用1Ih、22h和33h替换;就是其他三个宏它将插入到?B_SWITCHn代码中,用来切换新的bank和恢复到原来的bank。
所有4组?B_BANKn和?B_SWITCHn代码也都是用宏实现的,对应4个bank处理。它们汇集在?BANK?SWITCH代码段中,整个bank切换及恢复机制非常巧妙,可以实现任意bank之间函数的相互调用及嵌套。下面以bank3区中的main函数调用bank1区的Delay_noOS()延时函数为例说明该机制。
void main(void){
MCUInit(); //初始化CPU
Delay_n00s(10); //延时lO ms
Lcmlnition();
bank3中被调用的函数Delay_noOS(10)对应的汇编语句为:
LCALL C:5049
公共段(即Common段,对应bank0)中C:5049处的汇编语句如下:
MOV dptr,#Delay_noOS
AJMP B_BANK1
这里的B_BANK1就是宏?B_BANK&N中N为1的例程。现在进入问题的核心:全部的跨bank区程序切换及恢复过程依靠公共段中?BANK?SWITCH代码段里的以下汇编代码实现,对应的N为0、1、2和3。?BANK?SWITCH SEGMENT CODE PAGE
;
?B_BANK&N:
PUSH ?B_CURRENTBANK (1)
MOV A,#HIGH?BANK?SWITCH (2)
PUSH ACC (3)
PUSH DPL (4)
PUSH DPH (5)
?B_SWITCH&N:
MOV ?B_CURRENTBANK,#LOW? B_SWITCH&N
(6)
SWITCH&N (7)
RET (8)
:
Delay_noOS(10)函数的返回地址,即函数LcmIni-tion()的入口地址(也在bank3中),其高低位字节表示为ADDH和ADDL。程序进入main()后的?B_CURRENTBANK变量初值是?B_SWITCH3的低8位,其意义稍后叙述。AJMP B_BANK1后程序执行?B_BANK1和?B_SWITCH1的(1)~(8),执行到(5)时的堆栈结构如图1所示。
继续执行?B_SWITCH1到(7)时,PSBANK变为指向bank1,?B_CURRENTBANK变为?B_SWITCH1的低8位。执行(8)后,从堆栈结构可以看出,堆栈弹出①作为新的PC值,程序进入Delay_noOS(10)函数,延时功能完成后,函数最后一条RET指令开始返回。这是Keil C51处理bank机制的关键,此时的返回地址为堆栈中的②,此地址即?B_SWITCH&H代码的入口,这里对应main()函数所在的bank3分组,也就是?B_SWITCH3的人口。
因为所有?B_SWITCH&N的高8位地址,即?BANK?SWITCH代码段的高8位都一样,由语句(2)中的操作符HIGH?BANK?SWITCH确定;低8位保存在已经压栈的?B_CURRENTBANK变量中,此时堆栈中的?B_CURRENTBANK压栈值是?B_SWITCH3的低8位,这样②的地址就是?B_SWITCH3。
程序继续执行?B_SWITCH3,在执行?B_SWITCH3的(6)语句之前,?B_CURRENTBANK还是前面执行?B_SWITCH1时的值,即?B_SWITCH1的低8位。执行语句(6)后,?B_CURRENTBANK恢复为?B_SWITCH3的低8位,为返回main函数做准备。然后PSBANK置为33h,即指向bank3,接着执行RET语句,堆栈③成为RET的返回地址,程序回到了main()中Delay_noOS(10)的下一条语句继续执行,?B_CURRENTBANK也已恢复。
这个调用过程中,用了6个堆栈字节,3条RET指令,关键内容就是?B_CURRENTBANK变量,它保存了可以恢复调用前bank环境代码的地址低位。从被调用函数返回 到这个地址后,就能恢复调用前的bank环境,即赋予PSBANK正确的值。
不采用直接保存PSBANK值然后再恢复,而是用压栈的方式保存了相关地址(语句(1)~(3)),是为了实现跨bank区的嵌套调用。例如,在Delay_noOS(10)函数中,如果再次跨bank去调用新函数,会再次重复上述过程,堆栈从②往上再长6个字节。Delay_noOS(10)函数之前执行?B_SWITCHI产生的?B_CURRENTBANK值(?B_SWITCHI的低8位)也会进栈,为调用完新函数后返回到bank1继续执行Delay_noOS(10)提供保证。
单片机 嵌入式 SoC MIPS Keil MCU C语言 相关文章:
- 单片机智能频率信号装置(11-25)
- 单片机在医学信号检测仪中的应用(02-07)
- 单片机应用编程技巧(02-25)
- DSP与单片机通信的多种方案设计(03-08)
- 单片机与PC机串行通信的实现方法 (02-25)
- 单片机与PC通信的简化接口 (05-11)