Topic : Address Space Overflow too early

Forum : ST7/STM8

Original Post
Post Information Post
June 21, 2011 - 7:40pm
Guest

Hi,

I am working on a custom CAN bootloader for the STM8S208RB.

When I build the code normally, everything is fine. The program runs from 0x8080 to about 0xA000. When I use the CODE(0xXXXX) linker option, everything still builds correctly and runs. So if I use the option, say, Code(0xA000) then my firmware loads from address 0xA000 to about 0xC000. But, when I try to extend the firmware past 0xFFFF, with say Code(0xF000), I get Address Space Overflow errors.

The spec sheet for the STM8S208RBs says 128kb, and it looks like I'm being stopped at around 28kb. Flash should run from 0x8080 to 0x02FFFF. Is there some page select I'm missing? Or a compiler option? Processor Options for the STM8S208RB lists a ROM size of 0x20000, so it seems like the compiler shouldn't be giving a Address Space Overflow.

Thanks for the help.

-Dan

Replies
Post Information Post
+1
0
-1
June 22, 2011 - 9:59am
Raisonance Support Team

Hi Dan,

The STM8S208RB actually has 128KB of flash. The thing is that the core an be either in SMALL mode (limited to 16-bit addressing i.e., the first 64KB of address space) or in LARGE mode (which allows 24-bit addressing on 24MB). The main difference is that flash addresses (functions for instance) get a 24-bit address in LARGE mode and must be called by CALLF/RETF instead of CALL/RET.

=> Use the LARGE mode and things should get better.

Best Regards,

+1
0
-1
June 28, 2011 - 8:18pm
Guest

Hey Bruno,

I thought I had solved this problem when you posted your reply, but I am still getting Address Overflow errors. Using an STM8S208RB, set to that model in compiler options, and Program Model set to "STM8 Large ROM", my firmware compiles and runs fine, from 0x8080 to 0xB1D9. When I use the CODE(0xA000), again the program takes up 0xA000 to 0xD159. Once I set the start of my firmware to CODE(0xF000), I get " ***ERROR 107 : ADDRESS SPACE OVERFLOW ". Am I forgetting anything?

-Dan

+1
0
-1
June 29, 2011 - 10:54am
Raisonance Support Team

Hi Dan,

We have not been able to reproduce this in our Labs. What you have to do is check your map file and look at the *type* of each segment. You will have CODE segments as well as FCODE segments. The CODE ones must be in the first 64KB!
Note that the strings must be in the first 64KB as well, which eats up some memory space.

If you still have the issue, please send us a zipped copy of your project so that we can analyze it here.
Best Regards,

+1
0
-1
June 29, 2011 - 7:19pm
Guest

Hey Bruno,

Looks like I found the fix. To set to Large, I was setting the "Model" of the application to "STM8 Large Rom" under Compiler Options -> Program Model. This did not work. When I selected the Properties of the application, and set the overall Configuration to "STM8-Large," THIS seems to work. Or at least, it lets me set Code(0xF000) and overflow into the 0x10000+ addresses. If I set Code() to anything greater than 0xFFFF I still get an overflow error. Maybe the parameter for Code was only accounted 16 bits? Either way, I don't need to use that much space right now, so that problem is fixed.

I'm still having an issue merging my Bootloader code into my program, so instead of asking specific questions and getting stuck in small increments, let me just explain my entire situation. I have two independent applications, a Bootloader and a Firmware. They each use CAN communication and an internal clock, which requires a lot of libraries, so they actually are of a comparable size. Independently, they each work fine, and they are set so none of their ROM memory overlaps.

I can add both applications to the same project, but only debug one application at a time, although each application still works independently within the project. I have been using the help in other forums posts, and created a main() for the Bootloader, and an "at 0xE000 void main_fw(void)" for the Firmware with an "extern at 0xE000 void main_fw(void)" and a "main_fw()" call in my bootloader. This gives me an error:
*** ERROR #46 IN LINE 679 OF C:\PROGRAM FILES\RAISONANCE\RIDE\EXAMPLES\STM8\REVA\STM8S208RB\SRC\MAIN.SRC : UNDEFINED SYMBOL CHECK CASESENSITIVITY AND THE TARGET (PASS-2) '?main_fw'
at CALLF ?main_fw within my Main.SRC

So my question is, what is the best way to merge my Bootloader and my Firmware applications? I'd rather keep them separate applications, as having the Code(0xXXXX) option to shift all of my Firmware to a specific starting point makes rewriting the firmware a lot easier, and merging the two applications and having to define the address of every function and global variable in the Firmware would be too difficult at this point. Is it a matter of fixing this error with the "main_fw()" Firmware main function, or am I going about this incorrectly to begin with?

Thank you so much for all the assistance so far. I have gotten a lot more help in these forums than I had expected.

-Dan

+1
0
-1
July 4, 2011 - 9:37am
Raisonance Support Team

Hi Dan,

Concerning the CODE directive, there are always some items that must go under the 0x10000 limit (strings, data init...), which is why you cannot place a CODE directive higher than 0xFFFF.

You error #46 probably comes from the fact that you forgot to declare the ?main_fw. You must place an EXTRN CODE(main_fw) directive.

You solution of keeping 2 separate applications looks fine to me. If you fix the error above, it should work fine.

Best Regards,

+1
0
-1
July 5, 2011 - 7:02pm
Guest

Hi Bruno,

Sorry, still having trouble with this. I realized I had made a mistake in my code, but using your suggestions in

http://forum.raisonance.com/viewtopic.php?id=3308

, with "extern at 0x9080 void main_high(void);", or in my case, "extern at 0xE000 void main_fw(void);" gives a Too Many Storage Classes error. Is there another way to do this?

I think if I can just figure out how to apply your instructions from the above linked post to my project, I can get this.

Thanks,

Dan

+1
0
-1
July 6, 2011 - 9:31am
Raisonance Support Team

Hi Dan,

What you can do is just remove the "extern" qualifier.
I transferred the issue to the development team, they will check whether this is an actual problem or not.

Best regards,

+1
0
-1
July 6, 2011 - 7:03pm
Guest

Hey Bruno,

I've spent several more hours on this issue and still have made no progress. It's the last major issue I need to complete this project, so I'm somewhat anxious to get it finished up.

I still have two separate projects, a Bootloader and a Firmware, which need to be kept separate because they are large projects, and I need to make use of the Code(0xXXXX) option for the Firmware project.

Again, using "extern" and "at 0xC000" to declare a function gives a Too Many Storage Classes error, so I've dropped "extern."

I've changed the "main()" function in my Firmware to "at 0xC000 void main_fw(void)" This builds without error.

In my Bootloader, I've declared "at 0xC000 void main_fw(void)", which builds without error. Adding a call, however, gives me the error: "*** ERROR #46 IN LINE 1326 OF C:\PROGRAM FILES\RAISONANCE\RIDE\EXAMPLES\STM8\REVA\STM8S208RB\SRC\MAIN.SRC : UNDEFINED SYMBOL CHECK CASESENSITIVITY AND THE TARGET (PASS-2) '?main_fw' "

Sharing a header file between the two projects just declaring the "main_fw()", bypassing the need for an extern call, produces the same error.

Dropping the "at 0xC000" and leaving only an "extern", and then calling "main_fw()' gives me an Unresolved External.

I've tried several dozen combinations of "extern"s and "0xC000" calls in each project, and always get one of the 3 errors above.

I could be missing something very basic, as I don't have a ton of experience trying to merge applications like this onto one MCU. Could you please walk me through, step-by-step, how to merge these two projects? I am starting with each project independently working, one at a time, on the chip. I would like to end with both projects fitting on the chip, with the Bootloader containing the "void main(void)", the Firmware starting with "at 0xC000 void main_fw(void)", and being able to call main_fw() within the Bootloader.

Thanks again for the help, I really appreciate it.

-Dan

+1
0
-1
July 7, 2011 - 3:34pm
Raisonance Support Team

Ahaah! I love this It's the last major issue I need to complete.

Writing a bootloader is always very frustrating, because although the C language is well standardized, there are quite common needs that are NOT standard. Absolute functions are one of these.

The basic problem you have is that you try to share the "entry point" of your bootloaded application with your bootloader code. You should not, as they are separate portions of code, and the linker will attempt at resolving references it cannot resolve (as the code bases are independent).

The easy way is to declare you external entry point in your bootloader as:

#define main_fw (*((void(*)(void))0xC000))

You just have to later call "main_fw();" and the compiler will do the trick.

No very clean, not very readable, but it works!

Best Regards

+1
0
-1
July 7, 2011 - 8:29pm
Guest

It works. Thanks!

Now my current problem is Interrupt Vectors. I have two sets, one for the Bootloader and one for the Firmware. The bootloader IRQs are located at 0x8008, while I've used your advice from other posts and placed the Firmware IRQs at 0xBA00 using INTVECTOR(0xBA00).

My question is, how do I tell the firmware program to start using the Interrupt Vectors at 0xBA00, once my bootloader has completed and my firmware has started? Just as a test, I set up a function that Reads the bytes from 0xBA00 to 0xBA80 and Rewrites them onto 0x8008 to 0x8080. This technically works, but is an impractical fix, since it erases the old IRQs and requires the base to be reprogrammed.

-Dan

+1
0
-1
July 8, 2011 - 9:55am
Raisonance Support Team

Hi Dan,

The STM8 is limited in terms of interrupt remapping: The interrupt vectors must ALWAYS be in the 0x8000-0x8080 space, and not changeable.
Reflashing this area "on the fly" (when the bootloader transfers control to application) is dangerous and should be avoided.

What you can do is:
- For bootloader-specific interrupts: Let the compiler handle it.
- For application-specific interrupts (not handled by the bootloader): Place each of these interrupts at an absolute address (using "at" keyword), and manually set the interrupt handler in the bootloader (see http://forum.raisonance.com/viewtopic.php?id=2843 for detail). Do NOT activate the interrupt source until the application is loaded, or interrupts will trigger spurious code.
- For interrupts shared between the bootloader and the application, place the interrupt handler in the bootloader, and keep a global variable "appstarted" indicating whether the application has already been started or not. Then have something such as

void irqswitch(void) interrupt 5
{
    if(appstarted)
        irq5handler_inapp();    // At absolute address. Dan you know how to do this now ;-)
   else
        irq5handler_inbootloader();
}

Other solutions may be to have some ISR function pointers in RAM and call them. You can modify them at will, it may be simpler but takes up more space...

Best Regards,

+1
0
-1
July 11, 2011 - 10:05pm
Guest

Hey Bruno,

Since all the interrupts are shared between the Bootloader and the Application, I just used the advice in your third bullet. I should have thought of that...

It seems to be working well at the start. My Bootloader will call "irqhandler_inbootloader()" while still in the Bootloader main() code. Later I load the Application, I activate "appstarted" and now my interrupt redirects to "irqhandler_inapp()" while in the main_fw() code (my main loop once i'm in my application).

The problem is, once the interrupt occurs from my Application, and "irqhandler_inapp()" successfully runs, and the interrupt is over, my code does not return to where it was interrupted. It should returned to an infinite "while" loop in my main_fw(). Usually, however, it enters at the BEGINNING of the main_fw() function, which restarts the MCU from its entry point in the application. Other times, it re-enters the program at main(), restarting the chip from the Bootloader. And between the end of the interrupt and its re-entry in the program, there is a delay anywhere from 2 to 30 seconds, seemingly random.

Is there anything you can think of that would cause the end of an interrupt to not properly return to the right bit of code? I've double-checked that my "irq handler" functions are Re-entrant.

Thanks again,

-Dan

+1
0
-1
July 12, 2011 - 11:41am
Raisonance Support Team

Hi Dan,

I do not see what may be causing this. Can you experiment with the compiler optimization disabled (level 0) just to make sure that you do not have some overoptimization?

If this is still not working in O(0), you will have to reduce the problem down in order to understand it better. I do not see why there should be a link with the bootloader stuff.

Best Regard,

+1
0
-1
July 13, 2011 - 10:19pm
Guest

Hi Bruno,

Unfortunately, the disabling the compiler optimization did not seem to work, but I have isolated the problem slightly more, and can ask a more specific question. Here is some simplified pseudo-code that shows the problem, with a FlashLED(x) flashing the LED on the board x times to debug the program:

extern int appStart;
#define CAN_GetDataFW (*((void(*)(void))0xBB00))

void CAN_RX_IRQHandler (void) interrupt 8
{
if(appStart)
{
FlashLEDs(1);

CAN_GetDataFW();

FlashLEDs(4);
}
else
CAN_GetData();

}

and in a separate project, the application...

at 0xBB00 void CAN_GetDataFW(void)
{
FlashLEDs(2);

CAN_Receive(&_RxMessage);
more code that successfully runs...
.......

FlashLEDs(3);
}

So the problem is, I can successfully get through the bootloader code, using CAN_GetData(). The application starts, and appStart = 1, and I'm in the application. I send another message over the CAN, and now I trigger the interrupt 8, with appStart. FlashLED(1) runs and I see One flash. I successfully make it to CAN_GetDataFW() and see Two flashes on the LED. The code in CAN_GetDataFW successfully runs, I see its results on my server-side program, and FlashLEDs(3) runs, showing 3 flashes. But, I never get to FlashLEDs(4). Right after FlashLEDs(3), the program stalls for about 20 seconds, and then it will usually restart the base in main() or main_fw().

It is as though the program does not know to return to the interrupt once it finished CAN_GetDataFW(). Could this be some problem with putting a function with a specific address (CAN_GetDataFW at 0xBB00) within an interrupt? I think this is at a level of the program that I do not understand very well.

-Dan

+1
0
-1
July 18, 2011 - 11:08am
Raisonance Support Team

Dan,

I have no clear idea about this problem.

What you have to do is to debug up to the failing part (after FlashLEDs(3);) then switch to disassembly mode. Once there you must step into each disassembly opcode, and try to understand why it fails.

Another thing to do is to remove the CAN_Receive(&_RxMessage) code and check if it works with no code in CAN_GetDataFW() except for the FlashLEDs() calls.

The flash process may cause some problems. We have seen that in the past, and some delays (_nop_() calls) were sufficient to fix the instability.

Let us know how you get through.
Best Regards,