1. 简介
MCS-51是8根数据线,16根地址线,所以MCS-51最大只能访问64KB(216)的地址。很多较复杂的C51代码,其整个代码生成Bin文件可能大小64KB。针对这种情况,Keil C51提出了Code Banking机制来解决这个问题。
2. 基本原理
MCS-51内核的代码执行机制已经固定死了,代码运行的地址范围只能在0-64KB之间。一般情况下,我们编译生成的Bin文件,其代码执行地址和代码存储地址是一致。MCU执行到哪个地址,直接去ROM上取相应地址的内容然后执行即可。
MCU要访问超过64KB的地址范围,肯定需要增加地址线。增加4根地址线,则能够访问到2MB的地址范围。由于MCS-51只能执行64K范围的代码,Keil C51编译器相应也只会生成64K地址范围内的代码。
C51是采用分离编译,即单个文件独立编译,最后再链接成一个Bin文件。在链接的过程中,会有一个地址重定位的过程,会将每个obj文件中的代码映射成64K中的一个绝对地址。Keil链接器在链接时,可以将指定的多个Obj文件中的代码地址重定位到相同同地址空间去。如ObjA和ObB指定地址重定位到相同的地址范围内,并且各自的CodeSize为40KB。这样A.c和B.c的代码不能同时在MCU上执行,但是分两次加载,就可以在分别MCU上执行了。
MCS-51默认ROM片外存储器为64KB,存放A.bin。MCS-51再外接1个64KB的外置存储器ROM存放B.bin。什么时候读取ROMA,什么时候读取ROMB呢?还需要1个Pin用来选择。执行A.C中的函数时,选择读取ROMA,执行B.C中的函数时,选择读取ROMB。那么如何知道A.C中的函数会读取ROMA,B.C中的函数会读取ROMB呢?这是因为编译器会将A.C中的函数全部标记0,将B.C中的函数全部标记1。这个标记正好对应上面选择ROM的Pin。
3. Keil的实现
像Reset Vector、Interrupt Vectors、Interrupt Service Routines以及负责几个相同地址模块切换的代码,都是必须固定位置,不能随意变动,可能导致系统出问题。所以Keil C51提出了一个Common Area的概念,存放上述代码。然后针对重定位到相同地址的代码,则被称为Bank Area。
3.1. 具体设置
Bank Area,选择指定有多少个相同地址范围的代码。
指定文件所属Bank号。
可以将多个文件指定为相同Bank号,未指定Bank号的文件默认为Common Area。BX51链接器最多支持32个Bank号,LX51链接器最多支持64个Bank号。
Bank分配基本原则。
Common Bank因为是不需要重复加载的,所以效率最高。那些追求效率的代码,都可骗我在Common Bank中。如:Reset Vector、Interrupt Vector、Interruption Service Routines、String constants、Bank Switching Routines、Inter-Bank Jump Tables等等。
Bank0放置一上电就需要调用,并且调用不是非常频率的代码。
其他调用不频繁的代码放在其他Bank。
添加Bank调用代码,默认使用系统提供的(在KeilC51LIBL51_BANK.A51)。
B_NBANKS与前面配置的Bank数相同,B_MODE是Bank_Switching的方式。
; For BL51 the maximum value for ?B_NBANKS is 32
; For LX51 the maximum value for ?B_NBANKS is 64
?B_NBANKS EQU 4 ; Define maximum Number of Banks
; ; following values are allowed: 2, 4, 8, 16, 32, 64
; ; for BL51 the maximum value for ?B_NBANKS is 32
; ; for LX51 the maximum value for ?B_NBANKS is 64
;
; ; <0=> 8051 Port ; <1=> XDATA Port ; <4=> User-provided bank switch code ?B_MODE EQU 0 ; 0 for Bank-Switching via 8051 Port ; ; 1 for Bank-Switching via XDATA Port ; ; 4 for user-provided bank switch code 3.2. 链接器 Keil C51支持2种链接器,分别为BL51和LX51。 3.2.1. BL51链接器 BL51默认生成的Hex文件为Hex80,并且当前工程设置多少个Bank,则生成多少个Hex文件,每个Bank和相同的Common组成一个文件,如下图。每个Hex文件可以用Hex2Bin.exe转换成Bin文件。 3.2.2. LX51链接器 BL51是较早的链接器,LX51是在BL51基础上进行扩展的链接器,功能更强大,优化性能更好。一般情况下建议使用LX51。LX51会将多个Bank合并生成一个Hex文件。这个Hex文件中的代码地址空间是超过64KB的,Hex80格式不支持超过64KB的地址空间。针对这种情况,一种新的Hex描述格式产生了——Hex386。Hex386不仅支持多超过64KB地址范围,还支持指定偏移存储。 BL51链接器生成的Bin文件,如果Bank Area有多余空间,会以0填充。而LX51生成的Bin文件,如果Bank Rrea有多余空间,则会优先以Common代码填充。Offset默认为0,如果指定了,则将生成的代码放在Bin文件相应的偏移。下图为偏移为0。 3.3. Bank Switching方式 3.3.1. 8051Port MSC-51操作64KROM的结构如下: 我们完全可以依据上述接口,连接多个ROM。然后通过P口来选通。 L51_BANK.A51中有下述代码,即指定P1口用来控制选择哪个ROM,也即代码执行到Bank1时,P1=1;执行到Bank2时,P1=2,依次类推。更详细的切换流程,可以查看汇编代码。 IF ?B_MODE = 0; ;----------------------------------------------------------------------------- ; if ?BANK?MODE is 0 define the following values ; For Bank-Switching via 8051 Port define Port Address / Bits ; ; ; This is only used if ?B_MODE is 0 ; P1 DATA 90H ; I/O Port Address ; ?B_PORT EQU P1 ; default is P1 ; ; Default is Bit 2 ?B_FIRSTBIT EQU 2 ; default is Bit 2 ; ;----------------------------------------------------------------------------- ENDIF; 3.3.2. XData Port 查看L51_BANK.A51代码,变量B_XDATAPORT是参与切换的标识,默认设置为0xFFFF,可以根据需要修改。 IF ?B_MODE = 1; ;----------------------------------------------------------------------------- ; if ?BANK?MODE is 1 define the following values ; For Bank-Switching via XDATA Port define XDATA Port Address / Bits ; ; ; This is only used if ?B_MODE is 1 ; ?B_XDATAPORT EQU 0FFFFH ; default is XDATA Port Address 0FFFFH ; ; Default is Bit 0 ?B_FIRSTBIT EQU 0 ; default is Bit 0 ; ;----------------------------------------------------------------------------- ENDIF; 配合分布外部存储器,如下图。PSD813F2可以0FFFFH地址为控制位,来分别切换不同的Bank对应不同的存储空间,达到和8051Port类似的效果。标准的ROM成本较高,使用此种方式,可以更方便地支持更多的Bank,成本也低。PSD813F2更详细的配置可以参考PSD813F2的DataSheet。 3.3.3. user-provided 以上两种方式,明显是8051Port更容易。所以用户定义也是基于这种方式。很多基于MSC-51内核的MCU,并未完整引出P1口,不能正确的使用方法1,此时可以自定义。见L51_BANK.A51代码。 P1 DATA 90H ; I/O Port Addresses P3 DATA 0B0H ; SWITCH0 MACRO ; Switch to Memory Bank #0 CLR P1.5 ; Clear Port 1 Bit 5 CLR P3.3 ; Clear Port 3 Bit 3 ENDM ; SWITCH1 MACRO ; Switch to Memory Bank #1 SETB P1.5 ; Set Port 1 Bit 5 CLR P3.3 ; Clear Port 3 Bit 3 ENDM ; SWITCH2 MACRO ; Switch to Memory Bank #2 CLR P1.5 ; Clear Port 1 Bit 5 SETB P3.3 ; Set Port 3 Bit 3 ENDM ; SWITCH3 MACRO ; Switch to Memory Bank #3 SETB P1.5 ; Set Port 1 Bit 5 SETB P3.3 ; Set Port 3 Bit 3 ENDM 默认是以P1.5和P3.3两个Pin为例。需要匹配相应的外置电路,见下图。编译器编译Bank1的函数,会在前面插入SWITCH1指令,相当于Bank1对应的EPROM。编译器编译Bank2的函数,会在前面插入SWITCH2指令,相当于Bank2对应的EPROM。更多详细信息,可以在Keil中仿真调试查看。 3.3.4. 注意 使用user-provided时,因为复位时,系统保持之前的状态,不会自动切换到Bank0,需要修改切换代码,见STARTUP.A51代码的最后,将if 0改为if 1。 ; This code is required if you use L51_BANK.A51 with Banking Mode 4 ; ; #if 0 ; Initialize bank mechanism to code bank 0 when using L51_BANK.A51 with Banking Mode 4. EXTRN CODE (?B_SWITCH0) CALL ?B_SWITCH0 ; init bank mechanism to code bank 0 #endif 3.4. 自定义外部存储器 除了MSC-51直接总线支持的的ROM外部存储器外,还有一些设备可以作为外部存储器存储bin文件。如EEPROM、NorFlash,这两种设置,MSC-51一般没有直接提供总线访问,也就是说直接连接到MSC-51上,然后直接利用Keil提供的Bank Switching方法。那么针对这种情况,我们有办法吗?可以的。我们可以完全不用Keil提供的Switch方法,完全自己构建Switch方法。如在执行Bank0中的FunA时,接下来需要执行Bank1中的函数B,那么在执行FunB之前,先让代码运行至Common Bank中的SwitchFun。SwitchFun负责将Bank1中的Bin文件加载SRAM中覆盖原有的Bank0的代码。详见下面的伪代码。 // Common.c void SwitchFun(int nOldBankNo, int nNewBankNo, PFun pFun) { LoadBinToSRAM(nNewBankNo); pFun(); LoadBinToSRAM(nNewBankNo); } // Bank0.c void FunA() { // Call FunB of bank1 SwitchFun(0, 1, FunB); // Do some stuff } // Bank1.c void FunB() { // Do some stuff } LoadBinToSRAM完成加载指定Bank的Bin覆盖到指定的SRAM。 此种方法主要是利用Keil的Code Banking功能将指定文件生成相同的执行代码地址,加载切换的过程换成自己实现。这里依然要利用L51_BANK.A51文件,否则无法使用Bank功能。然后用user-provided模式,为了防止触发Keil提供的切换功能自动设置了相应的Pin,我们可以修改L51_BANK.A51中B_MODE = 4时时的代码,注释对相关Pin的设置。当我们调用Bank0的函数时,系统可能会调用SWITCHO函数,然后会设置对应的2个Pin,这会带来不可控影响。 P1 DATA 90H ; I/O Port Addresses P3 DATA 0B0H ; SWITCH0 MACRO ; Switch to Memory Bank #0 ; CLR P1.5 ; Clear Port 1 Bit 5 ; CLR P3.3 ; Clear Port 3 Bit 3 ENDM ; SWITCH1 MACRO ; Switch to Memory Bank #1 ; SETB P1.5 ; Set Port 1 Bit 5 ; CLR P3.3 ; Clear Port 3 Bit 3 Select Bank 0 for L51_BANK.A51 Mode 4
上一篇:C51中的函数指针
下一篇:C51和MDK的ROM大小及变量绝对地址初始化
推荐阅读最新更新时间:2024-11-09 10:31
设计资源 培训 开发板 精华推荐
- AD9736-EB,使用 AD9736、14 位、1.2 GSPS 串行电压输出数模转换器的评估板
- LT2940IDD 宽输入范围 10W PWM 热源的典型应用电路
- M24SR-DISCO-PREM,用于 M24SR 系列动态 NFC/RFID 标签的探索套件
- LT1021CCN8-5 电压基准作为超线性铂金温度传感器的典型应用
- 具有关断低压差线性稳压器的 LT3007ITS8-1.8 3.3V、20mA 电源的典型应用电路
- IRU3033奔腾双电源应用的典型应用
- OP213FSZ-REEL7假接地发生器的典型应用
- FAN251040GEVB:FAN251040GEVB,具有 PMBUS 的 40A 同步降压稳压器
- wireless-sd
- FAH4840 线性谐振驱动器 (LRA) 触觉驱动器的典型应用电路
- 有奖活动|TE无线连接,释放物联网无限潜能!
- Littelfuse【智能家居的电路保护方案】在线研讨会 11月22日10点 强势登场!预报名、参与研讨会赢好礼!
- 直播已结束【英飞凌全新Wi-Fi6单芯片SoC助力物联网产品的快速开发】(9:30入场)
- 三人行必有我师——EEworld网友原创教程隆重登场!
- 极简主义,足不出户,看东芝在线展会,安心答题送好礼!
- 赛灵思网络通信专题有奖问答
- 英飞凌ADAS解决方案,确保您每一次安全出行 参与赢好礼!
- 你评论,我送礼!《玩转TI MSP430 Launchpad》TI社区与EEWORLD联合首发!
- 似兰斯馨,一个老电子工程师的点滴足迹
- 直播已结束| STM32 Summit全球在线大会