Hello!
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 anymore.
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.
@Dominic: 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 inaccessible.
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 use. 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 segment.
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 different. 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 here.
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 addresses. 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:
?PR?RUN?MAIN(C:0x1337)
It locates the function run() in the file main.c at code memory address 0x1337.
Took me the better part of 15 minutes to find out and test.
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 modification. The LNP file looks like this
"EA_Timer_201.obj", "EA_UmrProz_201.obj", "EA_UmrZeit_201.obj", "STARTUP.obj" TO "96230019_PS_PSI8000_T_321" REGFILE (.\96230019_PS_PSI8000_T_321.ORC) RAMSIZE(256) 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 linker itself.
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.
Project/Options Select the Target tab Check LX51 instead of BL51 Select the LX51 Locate tab Add the following line to User Segments:
?PR?function?module (C:0x2000)
function is the name of the function you want to place in the code space module is the name of the C module, e.g. MAIN for main.c Click OK Hit F7
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 life.
About your guide: 1. I have the latest version of uVision 4 (at least there is no update available). 2. There is no way to switch to a different linker in the target tab. postimage.org/.../ 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. postimage.org/.../
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 Keil's tools"
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.
@Dominic: 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 either.