I'm trying to use the updater_F02x.c file and project to load my firmware and reset to run it. But the part I'm using is c8051f120.h. I understand the 02 code should work with the 120.
I understand to place the code at a specific memory address you use these parameters during link:
I want to place this updater code very high
in memory, about 4k below 128k, which would be bank 3, addr EFFF. How do I place it at bank 3, addr EFFF. Do I simply forget about the banks and specify the address as if there were no banks, as so?
I'm new at this kind of thing and would appreciate a response that takes this into consideration.
BTW, I am using the Cygnal IDE and it crashes like very 10 minutes. Very annoying!
The classic 8051 archtiecture (used in the Cygnal parts) is limited to 64KB address space. The address extension for the Cygnal
devices is done with code banking. See also: http://www.keil.com/support/docs/2441.htm
Therefore you need to use the LX51 SEGEMNTS directive with the Bx: address prefix or the BL51 directive BANK0 .. BANK31 to locate specific segments into code banks. More information can be found in the Ax51 Assembler/Utilities User's Guide (A51.PDF), Chapter 9.
I read it. I tried the BANKx thing. I can put main() in say BANK3. But I want the WHOLE program, not just segments. How do I get the entire thing up there? I am using BL51.
By the way, the purpose is to put the entire boot loader really high in memory (BANK3). My firmware will go in BANK0 and run normally. When it receives the command to update, it will start executing the bootloader code in BANK3 via a function pointer. After the bootloader receives the code and flashes it to BANK0, it resets the board to start executing the new code.
I've never done this before but I understand that is how it's done?
It kinda sounds like you don't really need code banking so much as you need a flip-flop with a reset. That way, after reset, you program starts executing code in one ROM, you twiddle a bit and switch to the other ROM.
I think you should really write two applications: a boot and a download application. You can then put the boot application to BANK3 by using a PROM programmer.
Thank you. I am using the Cygnal IDE to download the firmware into the 8051 code space. I have figured out how to download segments (ie. like main()) into bank3 using the BL51 linker, but cannot figure out how to get the entire program in bank3. The CODE linker parameter doesn't seem to support memory this high.
Can someone give me the BL51 command line to put my entire bootloader program in bank3?
Does not work.
Did you consider to write two applications?
Yes, I have two projects. Project 1 is the main firmware app which is small enough to fit in bank 0 entirely. It connects to a Win32 app via the serial port.
Project 2 is the bootloader code, that should live in bank 3.
The Win32 app will give project 1 the command to upgrade. When the firmware receives this command, it will execute the firmware in bank 3 (the bootloader code) via a function pointer.
The bootloader code will receive the new firmware via the serial port from the Win32 app. It will write the received code to flash at bank 0, overwriting the original project 1. When all code is received, it will reset the board causing the new project 1 to start executing.
Anyway, that's the idea. I do not know if that is the way these things are supposed to happen, but that is what I envision. I've read a lot of application notes I've collected from the Keil website and the Cygnal website, but still cannot figure out how to do what I want. Maybe the way I'm thinking about doing it is not the correct way.
How does one normally do this?
You could make the two projects into one initially, and set it up as a standard bank switch application. Go to the Cygnal web site and fetch their AN030 - Code Banking Using the Keil 8051 Tools. With this you can get an application going.
I do want to question the wisdom of putting the boot loader code up high. Usually it is put low so it can run and manage FLASH pointers in a manual way without having to deal with the stuff imposed by a code running in another bank.
What I normally do is just simply put the updater code right in the application. It is usually just a source file or two. I force the link order to put the start up code and the updater down at the base of the program space. Then I program the end of the updater module with an "eye-ball string" that is designed to be ORG'ed so that its ending is just below a FLASH page size boundary. The updater application that runs on the PC is capable of reading the program to be sent to the 8051, and finding the eye-ball string in it. It also talks to the updater module in the 8051 and reads out the program image in the 8051 to validate the eye-ball strings for equivalence. (If you use unique eye-ball strings for each projectyou can ensusre that the updater function on the PC doesn not try to send the wrong firmware update to the product). (Note also that Microsoft has a utility called GUIDGEN that is a cool thing that can make very unigue ID strings for you. It is part of VC++).
When the updater program runs it is designed to not allow the code area in FLASH pages below the eye-ball string end to be erased and re-programmed. (You may have to make special provisions for the interrupt vectors but that is no different problem that the common debug type monitor deal with,
As I understand your design there could be one more problem. If during download will be a reset or a power off situation. Your loader program have erased the flash at bank0 including all vectors of the vector table. How can your system restart then? How can it connect to your win32 ap? and how can it call the function pointer to your loader programm?
I would suggest to hold the loader programm in the default bank0 and the application in another memory bank which can be mapped instead of bank0 after the loader programm have checked if the application is correctly stored on the flash.
with best regards
Ignoring code banking for now since both my bootloader code and the application code both fit into the Common area ...
I am doing this in C. I removed the ISR's from my application code and made them into normal functions (I will call them ISR-stubs). I put the ISR's in the bootloader code. The ISR's in the bootloader code has the locations of the application codes ISR-stubs hardcoded. Each ISR in the bootloader code executes the ISR-stubs in the application code via a function pointer.
Someone suggested I get rid of main() in the application code because the compiler/linker adds in the startup code and the startup code is not necessary because it's already included with the bootloader code at 0000H. However, the linker spewed many 'address space overflow' errors because without a main(), the linker cannot perform overlaying of DATA variables. Any thoughts on this?
The CODE memory for the bootloader code and application code cannot overlap. So the application code is located at 0C00H, above the bootloader code. I put in a function called EntryPoint() that does nothing but call main(). EntryPoint() is located at 0C00H, so it jumps right to main instead of executing the STARTUP code.
The DATA memory for the bootloader code and application code cannot overlap. So the bootloader DATA is located at 0064H.
This all seems to work. The problem I am now having is how can I upgrade and modify the application code such that all DATA is located below 0064H and the ISR-stubs are always at the address locations the bootloader code has them hardcoded to? I mean, when I update the application code surely I may need to add more variables which will increase the DATA memory. Then I'll have to update the bootloader code. But that defeats the entire purpose, doesn't it?
Did I do this wrong? Any ideas?
Here is the linker command for my application code:
RS(255) PL(68) PW(78) CO(0C00H, ?PR?ENTRYPOINT?MAIN(0C00H))
Here is the linker command for my bootloader code:
DA(64H) RS(256) PL(1000) PW(132)
Here are the ISR's in the bootloader code calling the ISR_stubs in the application code:
// function pointers to jump to application code
static void (*f_main)();
static void (*f_isr)();
void UART_RX_ISR() interrupt 4
f_isr = (void code*)0x6BFA;
void Timer0_ISR() interrupt 1
f_isr= (void code*)0x2F60;
void timer2_ISR() interrupt 5
f_isr = (void code*)0x74FF;
void ASDC0_ISR() interrupt 15
f_isr = (void code*)0x3A7C;
void main (void)
// disable watchdog
WDTCN = 0xde;
WDTCN = 0xad;
// disable interrupts
EA = 0;
// launch the application code
f_main = (void code*)0x0C00;
View all questions in Keil forum