C8051 F12X中多bank的分区跳转问题处理
BANK?SWITCH确定;低8位保存在已经压栈的?B_CURRENTBANK变量中,此时堆栈中的?B_CURRENTBANK压栈值是?B_SWITCH3的低8位,这样②的地址就是?B_SWITCH3。
程序继续执行?B_SWITCH3,在执行?B_SWITCH3的(6)语句之前,?B_CURRENTBANK还是前面执行?B_SWITCHl时的值,即?B_SWITCHl的低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位)也会进栈,为调用完新函数后返回到bankl继续执行Delay_noOS(10)提供保证。
2 无操作系统bank分区间的强制跳转
通过上面的分析得知,如果要处理跨bank区的跳转、调用和返回,关键是能正确处理好PSBANK中的内容。当程序没有操作系统用于任务切换,而又需要强制退出某一函数进入到另一函数的某一地址时,比如说在中断发生后,结束原来的工作转入到另一工作去,就需要处理好PSBANK。
如果不考虑bank,可以在转入新地址之前执行一段代码,保存该地址处的环境变量[2],包括堆栈指针sP和需要的入口地址。然后在中断返回之前,恢复此环境变量,执行中断返回指令进入该新地址。这个思路和C51库函数setjump和longjump比较相近,但比它们灵活,因为环境变量可以自己处理。
考虑bank后的情况稍微复杂些,环境变量中需增加bank的处理信息,那么只处理PSBANK行不行呢?
如果仅保存和恢复PSBANK,则很简单,在保存环境变量的程序中加入:
JMPEnv[envl][3]=PSBANK;
在恢复环境变量的程序中加入:
PSBANK=JMPEnv[envl][3];
这里环境变量是二维数组JMPEnv,envl代表一个环境变量,即一个返回点。第二维是变量中的参数个数。因此可以保存多个环境变量以供使用。
初看起来这样处理是没有问题的,可实际上不行。因为进入返回点后,虽然PSBANK正确了,但是?B_CUR-RENTBANK可能已经被修改,不能和返回点程序的bank区匹配,如果再次出现跨bank调用的话将不能正确返回。
处理方法是有点技巧的,因为C语言不支持汇编变量?B_CURRENTBANK的写法,所以在L51_bank.A51中要加上声明:
PUBLIC BLCURRENTBANK
和伪指令:
B_CURRENTBANK EQU ?B_CURRENTBANK
这样就可以在C程序中使用B_CURRENTBANK
了,先声明B_CURRENTBANK:
extern Uchar data B_CURRENTBANK;
然后在保存环境变量程序中加入:
JMPEnv[envl][3]=PSBANK;
JMPEnv[envl][4]=B_CURRENTBANK;
恢复环境变量程序中加入:
PSBANK=JMPEnv[envl][3];
B_CURRENTBANK=JMPEnv[envl][4];
这样恢复环境变量进入到新程序后,也将恢复该程序对应的正确?B_cuRRENTBANK值,问题得到解决。
3 no/0S-ll移植中的bank分区处理
μC/OS-II的51版本已经很成熟,但是所有移植版本均未处理bank问题,需要增加该内容,否则不能在包括C8051F12X系列及其他多bank程序中使用。
如前所述,Keil C51提供对跨bank调用的透明切换支持,但在使用操作系统时,这种透明切换机制还需要提供对任务切换的支持。因为任务的切换,程序可能需要到别的代码分组中去运行,而此时PSBANK和?B_CUR-RENTBANK还停留在原来代码分组中的状态,将导致程序崩溃。显然,无论由于什么情况导致的任务切换完成之前,都需要保存和恢复PSBANK和?B_CURRENT-BANK的值。解决的办法是在每次任务切换前将PS-BANK和?B_CURRENTBANK压入用户任务栈。
按照μC/OS-II的要求,在任务创建时,任务栈必须初始化成像运行中的任务刚刚发生过中断一样嘲。?B_CURRENTBANK的初始值取决于该任务所在分组对应的切换代码段的低8位地址。所以,任务堆栈的初始化函数OSTaskStkInit需要加入一个参数INT8U bank,指明该任务位于哪个代码分组中。又由于任务堆栈的初始化函数是被任务创建函数OSTaskCreate调用的,所以该函数
问题 处理 分区 bank F12X 中多 C8051 相关文章:
- 信号完整性中的反射问题原理(12-02)
- F频段干扰问题的几种解决方案(09-23)
- 电磁兼容技术及应用实例详解:工控机的抗扰问题(08-14)
- 智慧城市建设需直面“三个问题”(12-16)
- 选择软件定义网络SDN须注意的12个问题(07-03)
- 关于WLAN解决方案的10个问题(02-04)