Hello,
I would like to create a firmware and an application running on the same device.
The application needs to call some functions of the firmware. The application can be updated whereas the firmware is still the same.
Therefore, i want to have 2 projects: one for the firmware (C coded) and one for the application (C coded).
I have seen that it's possible to forbid idata, xdata and code area in order to prevent the application to overwrite the firmware and its variables, but I have no clues on how to give my firmware prototype to my application. Of course parameters and functions' addresses must map with the firmware mapping.
Does anyone have an idea how I can do this?
Thanks for your help! Damien.
No - stay away from simple solutions. They have a tendancy to actually work. What would we then do with our spare time?
Well, I want my firmware to control the hardware and to provide simple API for the application. So I NEED interaction with my application.
Damien.
You started with "want to" and ended with "need to".
If you only "want to" let the firmware control the hardware, then you only "want to" implement an interface for the two to interact.
It is only when you have a hard requirement to control the hardware from your boot loader/monitor/bios that you "need" the interaction part.
Why do I mention this? It is absolutely vital to never mix up "want" and "need" in a development process. Such a tiny little error may multiply the development and/or product cost by a very high factor!
Yes, you're right, and I thank you for the correction (english is not my native language).
=> I want interaction between my firmware and my application :)
"Well, I want my firmware to control the hardware and to provide simple API for the application."
That doesn't answer the question of why you need this separation of "firmware" and "application"
Why not, as is more common, just have a simple Bootloader to download the application - which includes the hardware interaction stuff?
You could make the hardware interaction stuff into a library, if you don't want to recompile it every time.
"So I NEED interaction with my application"
Actually, even if you go this way, you probably don't - your application may need to call upon the services of your "firmware", but the firmware shouldn't need to call the application...
Ok, my firmware/bootloader will be able to download the new application via USB, write it into the flash, and manage other stuff.
I want an autonomous firmware (access USB, flash, ...), but I don't want to increase my application size by adding a library that will allow accessing USB, flash, ...: those functions are already into my firmware. I don't want to have the USB function into my firmware AND into the application. So I don't want to include a library holding all functions of my firmware into my application.
If no application is present, the firmware will wait for an application update.
""So I NEED interaction with my application"
Actually, even if you go this way, you probably don't - your application may need to call upon the services of your "firmware", but the firmware shouldn't need to call the application..."
Yes, I mixed up... Sorry! It's more like: So I want my application to interact with my firmware.
The go the BIOS route. Add a single access function that takes a cmd id and a pointer to a struct or similar and then performs the request.
"The go the BIOS route. Add a single access function that takes a cmd id and a pointer to a struct or similar and then performs the request."
I have no BIOS available into my chip.
Do you suggest me to make something like:
typedef struct _my_parameters { char param1; char param2; } t_my_parameters; int firm_function(int function_number, t_my_parameters *param); #define LCD_FUNC 0x01 #define ICC_FUNC 0x02 [...] void main (void) { t_my_parameters parameters; [...] parameters.param1 = 20; firm_function(LCD_FUNC, & parameters); // instead of "firm_lcd(20)" [...] }
This is really not easy to use. But maybe you had an other idea?
Thanks, Damien.
You're writing the BIOS for your chip. The question is what the interface into the "BIOS" should be.
Usually, a small embedded application for an 8051 is so intimately tied to the hardware that it doesn't make a lot of sense for the application to be independent, in the sense that desktop application software tries to be independent of the hardware or even the OS. Sure, there's a layer of code to handle the hardware. But do you really need an application that ports from this 8051 to that 8051 to that 68HC11 to that ARM, all using a common BIOS-like interface so that the app doesn't change?
If so, you have three choices already: - single well-known function entry (command + parameters) - vector table of function pointers - many well-known addresses, fixed by the linker
One alternative to all of the above is simply to write a library that handles the hardware and deliver that to the application programmer. They don't have to mess with bits in registers (same as with a BIOS-ish design), they can build new code and upgrade it while still linking to the old library, and you can have a simple bootloader that does nothing but load the app, without providing this BIOS-like layer.
Yes but this bootloader will use USB and Flash functions (USB to receive the appplication). Therefore, if my application needs to receive other kind of data via USB, USB functions will be duplicated, the same goes for Flash functions.
In order to prevent function duplication, I want my application to be able to access those functions stored into the bootloader/firmware.
My application will NOT run on other chip (ARM, ...) but I want to be able to update the application via USB. To do so, I need a bootloader. This bootloader have access to USB, Flash and other stuff, so I called it firmware.
If I do not create a bootloader, it will be hard to update the application because if I'm erasing flash functions, while using them, it will crash.
This is why I want a "firmware". (Maybe firmware is not the correct word...)
I think the above is a reasonable approach, but you might make the source nicer by either creating inline functions that sets the struct parameters and makes the call, or by using #define.
Using a vector table requires a bit harder coupling between the two parts. You have to look into parameter passing, and it isn't easy to extend a function with an extra parameter and have a new application auto-adjust to an older firmware.
If you have a fixed entry in the struct with API version, you can manage to handle situations where the application support a newer or older API version than the firmware. A newer firmware will realize when an older application fails to pass an extra parameter. A newer application may set an extra parameter in the struct that gets used by a new firmware but ignored by older firmware.
Ok, I understand the concept, but I have no idea how I should do this... Will my application be able to use functions with normal parameters?
LCD_display(param1, param2);
with a macro like
typedef struct { long param1; // long in order to accept long param2; // all kind of parameters long param3; } struct_param; struct_param p; void firm_func(char func_type, struct_param *p); #define LCD_display(_x, _y) \ { \ p.param1 = _x; \ p.param2 = _y; \ p.param3 = 0; \ firm_func(0x01, &p); \ }
I don't really like the global "struct_param p" but I have no ideas how to remove it. And how do have I returned values?
result = my_function(param1, param2);
The previous macro does not allow returned values. How can I do this?
The firmware function will also generate lots of code, something like:
void firm_func(char func_type, struct_param *p) { switch(func_type) { case 0x01: LCD_display((char)p->param1, (char)p->param2); break; case 0x02: FlashRead((int)p->param1, (int)p->param2, (char*)p->param3); break; } }
generates around 25 bytes for a function with one parameter and 60 bytes for a function with 3 parameters. This is really too much... (81 functions of 1 parameter => 2025 bytes!!)
I need to find an other solution. Maybe it was not what you were thinking... Then give me some more hints please.
First of all - the chip isn't the worlds most powerful. Hence the question if you should take this fight.
Second - if you really do make a "firmware" part, the firmware can set parameters in the struct before returning. Your inline function or define can then pick up this value.
Third - you can't afford a switch that extracts all parameters and immediately calls the individual functions. You might save most code space by performing a copy of the struct to a fixed location in the firmware RAM space, and have the individual functions pick up their parameters directly from that global struct. Or, if you can have the caller know the address of the struct and setting the parameters in a shared struct.
"This is really too much... (81 functions of 1 parameter => 2025 bytes!!)"
Writing all-purpose, general software and tight, compact code are (almost always) mutually exclusive!
In essence, that's why PCs have (and use!) huge resources, and 8051s don't.
So, as Per says, you need to decide what your real requirement is here - do you want something small, compact, and efficient, or something very general purpose?
If you want small, compact, and efficient, then an 8051 is probably ideal; if you don't, then it isn't.
the simple solution would be to abandon all ideas of a 'homemade' bootloader, just compile and link all of it in one piece.
Then use a chip (there are sooooooo many) with ISP. You can get funky Atmel ISP, serial port ISP, JTAG ISP, USB ISP and probably some other flavors.
The impression your posts leave is that you are trying to code the '51 as a PC, GIVE IT UP, many have tried and all have failed.
The '51 is absolutely wonderful when used as intended and absolutely horrible when not.
Thus either code the '51 as a '51 or use some other chip.
Erik
Well, this thread went a bit out of the topic.
I have to develop on a 73S1113 chip based on 8052, and I have to develop something that can download an application via USB (ISP is deactivated). This is not optional.
I wanted to know how to be sure that my firmware and my application can cohabit, knowing that I have "only" 64kb of flash and the application will use most of it.
I understood that there were different methods in order to do this work. The vector table seems interesting and I think I'll choose this method.
I understood that registers are automatically selected by the compiler (I don't need to worry about it) www.keil.com/.../c51_le_passingparmsinregs.htm
I just have to find how to tell the linker to not use some part of ibit and idata. So far, my attempts were not successful (using IBIT and IDATA linker directive).
Damien