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.
Sorry for the missing words. I posted it fastly, not checking the spelling so thoroughly.
The bootloader is mapped into the addressable memory at 0xF800. 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 0xF7FF? easy to see in the .map file
Erik
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, would it?
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 blank), but - it does not set the BLJB anymore (which we use for a certain reason) and - it does not initialise the UART for immediate communication and reprogramming, 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 )
@Hans-Bernhard 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.
@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.