I seek to find help here, because we across a problem we don't
seem to be able to solve. But perhaps has an idea...
Following: for a power supply we sell we use AT89C51CC03 as main
controller. It has 64k flash.
The bootloader is mapped into the addressable memory at 0xF800. In
order to be able to update the microcontroller firmware (i.e. ISP),
we used to send a command from outside, which let our code jump to
the bootloader by API calls.
With the time, the code grew. Some versions earlier, jumping into
bootloader worked fine. It means, we just sent the command, the
controller jumped into bootloader, initialised the UART (which is
connect to USB, making a VCOM port on the PC side) and we could then
instantly access the Atmel chip via FLIP. In some newer versions, the
code grew bigger and now has 63.2k, making its end address being
around 0xFD30. We didn't realize so far, because we usually only test
the code itself, but not if the update still works. And now, neither
jumping to bootloader nor setting the BLJB via API calls works
Did we cross a magic border? A border which is at 0xF7FF?
I read the UART bootloader documentation and the AT89C51CC03
manual, I found no hint about that using up all of the 64k flash
memory could result in such a problem. But it seems, it's exactly
caused by now having code with end address >0xF7FF.
Question now is: how to access the bootloader and how to update
the firmware without forcing the chip to bootloader with PSEN?
Thanks for any advice.
Sorry for the missing words. I posted it fastly, not checking the
spelling so thoroughly.
The bootloader is mapped into the addressable memory at
I know of no use for a non-addressable memory, do you mean flash?
Did we cross a magic border? A border which is at
easy to see in the .map file
Did we cross a magic border? A border which is at
I'll risk pointing out the painfully obvious: your
bootloader lies north of that not-so-magic border. Where in
your code is the jump-to-bootloader routine (and all its helper
functions)? It wouldn't happen to be sitting in the bootloader area,
OK, in other words: this is about the 64k flash memory, also
called CODE range. I know that the bootloader is only mapped at
0xF800, not programmed there in the same memory space.
But, it is pretty obvious that when compiling code which size is
>0xF7FF, the code still starts the bootloader (LCD display goes
- it does not set the BLJB anymore (which we use for a certain
- it does not initialise the UART for immediate communication and
so the possibility to reprogram the chip in ISP is lost atm.
The code to set BLJB and start the bootloader is still the same in
all the versions.
The start code is quite cryptic for me:
*((const void(code*)(void)) 0xF800 )
A very good thought! Looking at the memory model, it says that the
CODE space from 0xF800 is not accessible anymore once the ENBOOT bit
in AUXR is set. This bit is set by our code directly before starting
the bootloader. So it may be fixed by putting the jump code
definitely somewhere below 0xF800, I guess.
I'm using a different 64k 8052 core, too. We can still reach the
boot loader through banking. Our µC has 16 banks, in one of
them we can access the boot loader, another bank has the internal
flash. We can add external flash to the remaining banks and address
1Mb of flash overall.
I expect your µC probably has a banking mechanism, too.
So if your boot loader is in a true ROM and wasn't just some code
in the flash, you should still be able to access it.
Here it's different. The bootloader is not im ROM, it's in flash.
With the 64k flash version of the 8051, it is located at address
0x10000 for programming. Means, the Atmel bootloader could be
replaced by a custom one or by another Atmel bootloder, for example
the CAN bootloader. Since the code cannot access the address 0x10000,
setting a bit in AUXR register maps the bootloader space into code
space from 0xF8000 which seems to make code between 0xF800 and 0xFFFF
Also, we don't use banking. The memory ranges are defined. DATA,
IDATA, XDATA, PDATA and CODE.
64k flash (CODE), 2k RAM (XDATA, PDATA, DATA, IDATA) is all we
The thing with the inaccessible bootloader hasn't happen before,
since the code always was smaller than end address 0xF7FF.
As said before, I need to find a way to put the bootloader jump
code definitely into CODE space below 0xF800.
OK, I see. I cannot tell you how to rescue existing installations.
But you can prevent this from happening in the future:
Just add this to your code somewhere:
const ubyte code loader_mem[0x200] _at_ 0xF800;
This will block your linker from putting anything there. I've done
this to protect the data flash of the XC878 (which I can write to at
runtime with some arcane timing voodoo and the spare 0xA5 op-code),
so the linker doesn't put any code into it (a theoretical possibility
only, my code sizes don't go much beyond 20k so far).
However it looks like you need the space. So your alternative
would be to define a custom segment in a safe place for the function
that calls the bootloader and only setting AUXR there. Of course that
function may not call any other function outside of your safe
You can define custom segments in the linker configuration, open
it and just press the help button. The online help works quite well
in those dialogues. I think the manual also has an example how to put
a specific function into a custom segment.
Thanks for your help, but I guess you mean something
The API code for jumping to the bootloader switches the ENBOOT bit in
AUXR to one and then only executes the jump code to start the
bootloader. This fails, because the compiled code may be at an
address higher than 0xF7FF or lower. If higher, the code is not
accessible anymore after mapping the bootloader to 0xF800-0xFFFF.
So I actually need to place the whole function void
__api_start_bootloader (void) to a certain code memory position. But
I'm still on finding out how. The _at_ directive does not help
As I said create a custom segment and put the
__api_start_bootloader() function into it.
That's problematic. The Keil documentation of compiler and linker
explains WHAT you can do, but not HOW. The linker can link code to a
certain address, but there is no linker file.
The compiler created .obj files and the linker links them. But these
are not editable, nor can they be loaded into uVision. Here in the
forum are only threads about linking variables to certain
I can create code segments in the target dialog (BL51 Locate), but
that's all. I would like to assign a C file or just a function to a
specific code segment, but there's no way. There are also no compiler
directives for that.
Use the LX51 linker. Add the following to User Segments:
It locates the function run() in the file main.c at code memory
Took me the better part of 15 minutes to find out and
Sorry for being, but I don't know how to do that. The same thing
for the BL51 is described here: http://www.keil.com/support/man/docs/bl51/bl51_code.htm
But it does not make sense to me to run the linker on it's own,
because it would only link 1 object file. So there must be list of
object files which is used by uVision to control the linker. This
seems to be the *.lnp file. But this one is created by uVision. So if
I edit it for BL51, the next time compiling the code would erase my
The LNP file looks like this
TO "96230019_PS_PSI8000_T_321" REGFILE (.\96230019_PS_PSI8000_T_321.ORC)
CODE( 0X0000-0XFFFF )
XDATA( 0X0000-0X07FF,0X1000-0X1FFE )
and I could create a linker control file (*.lin) in the target
dialogue, which then contains the last four lines of the LNP file,
but not all the object files. It also looks like the linker
directives can not be applied here.
I will continue tomorrow. Thanks for any help until now.
You need to relax a moment and actually look at all the
tools you're using, and their documentation. Not just that of the
As you've found out already, in uVision project, it's uVision that
controls the linker. And of course there are changes you can make to
how it does that. And guess what, the BL51 manual even tells you
where in uVision you're meant to control which BL51 directive. That's
what each directive's description has that "uVision" entry for.
Select the Target tab
Check LX51 instead of BL51
Select the LX51 Locate tab
Add the following line to User Segments:
function is the name of the function you want to place in the
module is the name of the C module, e.g. MAIN for main.c
And afterword I suggest you learn a bit about the tool you're
using. Fiddle with all the options, learn what they mean.
I didn't do this ever before and I needed 5 minutes to figure the
principles out and less then 10 minutes to apply them.
You came along quite competent in your first post and I thought
you just needed a nudge into the right direction. Instead I did all
the work for you, just to disprove that ridiculous claim that
µVision doesn't let you do this.
You don't have to be rude. Thanks for your help.
I don't know everything, else I wouldn't ask. The Keil documentation
does not tell HOW, only WHERE and WHAT. If you need only 5 minutes, I
need more. Since you have done it before, it's very appreciated you
tell it here. Finding out myself can take a lot of time and we don't
want to invent the wheel again. Programming is only a side job for
me, I simply don't get the time from my boss to learn all the stuff
about Keil's tools. Stuff which I most probably need only once in my
About your guide:
1. I have the latest version of uVision 4 (at least there is no
2. There is no way to switch to a different linker in the target tab.
3. In the other tabs I can also not set a different linker
4. This finally tells exactly how: http://www.keil.com/support/docs/359.htm.
But if I follow "For the BL51 Linker/Locater enter the following code
segment with the address under BL51 Locate - Code" and put
?pr?__api_start_bootloader?api_cc03u_flash_201 (C:0x2000) in that tab
into the section CODE, as told, I get fatal error 206 when compiling.
See, my problem is not understanding, but if the documentation
does not match the tools, I'm lost.
Besides: the uVision F1 help is a CHM (uv4.chm) file that is
called from the help menu. Since it is quite big, it's not to easy to
find the right page. In the target dialog, there is a HELP button.
Clicking this just tells me, it couldn't find uv4.hlp. Looking into
the Keil installation of uVision, it's not there. It seems, in this
UV versions this help is not included anymore.
View all questions in Keil forum