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.
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.
OK, sorry. It's the Device tab.
And no, I DIDN'T DO IT BEFORE you claimed it wasn't possible.
"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
Note that lots of people on this forum "simply don't get the time
from their boss to help others avoid inventing the wheel".
Getting help may be very important to the one who wants/needs
help. But what incentive is there to give that help? Using what
resources? What boss wants people to spend time helping? Especially
if there is a commercial advantage of being alone having the
knowledge about the wheel?
You don't have to be rude. Thanks for your help.
I think I need to elaborate why I have gotten rude:
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.
I think it is not difficult to find the right page. Because I read
the entire thing before I ever got the idea to waste other people's
time on my problems. I haven't read everything in detail (i.e. I
skimmed a lot of parts), but still I looked over everything and have
a firm idea of what I can find in there.
This is the standard I ask anyone else to meet. Otherwise you are
just a parasite. People invested a lot of time into creating that
documentation and you're spitting into their faces.
When someone posts something that can be found in the manual in
reply to a question I asked, I'm deeply insulted. Because it means
people think I am that kind of person.
Now would be a good idea to calm down a bit.
Doh, I could have found out myself this time. You're right. Problem
now is, I can only select the LX51 linker if I have selected a device
and in UV4, the Atmel AT89C51CC03 is not listed anymore. None of
89ers is listed. I can also not select a different CPU database.
But in File->Database it lists a much bigger database with that
Atmel MCU included. Even I go to Project->New project, it only
shows me the short list with only Atmel SAM devices.
In UV4 I can right-click the target and select target options, where
I can not switch the target device. So I exported the UV4 project to
a UV3 project and opened it in UV3. There I can select the
AT98C51CC03 from the generic CPU database AND activate the LX51.
OK, next step: compiling. Using the BL51, all works fine (without
the new linker command). Using LX51 with the linker command, I get
warnings (L48), but these can be ignored. The post-processor from
Hitex obviously denies the output from the LX51, so we could not
debug the code. But at least I got a hex file and, looking at the map
file, see the bootloader jump code at 0x2000.
I tested the code - works. It now sets BLJB and jumps to
bootloader (instantly accessible with FLIP).
Many thanks for all your help!
Well, the solution was here, on Keil's website, not in the
documents that come with UV.
The BL51 solution still does not work, but is given by Keil for UV4
and BL51. So I'm in doubt whether I was wrong or them.
See, Dominic, as I said above: you can read as much as you want
and they could have spent a lot of time writing such documents - all
doesn't matter if the information is wrong.
My job is to write technical documentation for the power supplies
we produce. People often phone us about things that is all written in
the documents, but they don't read. Sometimes I want to shout Please read the manual!
But we don't do, of course. Being lazy is in the nature of man.
Asking people who know is easier than learning all yourself. Else we
all would be highly trained specialists and that wouldn't work