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.
Is this really something you want to do on an 8051??
What you're calling "firmware" here sounds like a sort of turbo-charged Bootloader - so that would be the place to start your searching...
You do realise that the CODE space in an 8051 is not writable, don't you...?
It's a 8052 from Teridian (73S1113), so I have 64kB of flash where code is stored, and therefore could be re-written in order to update the application.
Thanks, Damien
"I have 64kB of flash where code is stored, and therefore (sic) could be re-written"
Merely having 64K of flash does not, in itself, necessarily mean that the chip can re-write it itself - you need In-Application Programming (IAP) for that.
Does your chip support IAP?
One way to do this is to assign every function callable by the application a fixed address. Then you use linker directives to fix each function in your firmware to the assigned address.
A more flexible way to achieve the same goal that lets you upgrade the firmware and application individually is a vector table. The vector table lives at a well-known address in memory, and contains pointers to all the functions provided by the firmware. The application looks up the pointer in the vector table and calls the function. This data structure allows functions in the firmware to change size as needed and allows the linker to place them so that you don't have to do so manually.
An even more dynamic way to call functions is to define a single well-known entry point (a function or an interrupt vector). All calls from the application go through this function, whose parameters include a function code enumerating all the firmware services, plus any parameters those functions might need. (This is similar to the way some operating systems work.) The dispatch function looks at the function code and does the switch statement or function pointer table lookup. One advantage of this scheme over exposing the vector table is that the number of supported functions can change.
Yes I have APIs that allow to read/write my flash (they are part of my firmware).
I have thought using a vector table in order to do that, because I know how many function I have, and if I increase the number of function, I will have to change the firmware and the application. Therefore a new table will be created.
But I have found some problems about functions parameters. I have to inform my application the area used for the parameters in order to retreive them correctly once in the firmware function. I have seen that the C compiler will create a segment in data or xdata (depending on the compilation option: small, compact or large).
Into the documentation, it is sayed that some parameters are passed via register and other via data/xdata memory. So I will have to create segments in order to inform the linker where to put all parameters.
The question is: how do I inform the application/compiler that this or this parameter is sent via register R7 or R3? Should I disable register parameters via NOREGPARAMS (it will increase my very limited data/xdata memory!)? Do I have to declare the memory used for all my firmware functions (I have 81 functions (sic))? something like
NAME FIRM_FUNC PUBLIC _my_function, ?_MY_FUNCTION?BYTE ?PR?FIRM_FUNC SEGMENT CODE ;?DT?MY_FUNCTION?FIRM_FUNC SEGMENT DATA OVERLAYABLE for SMALL model ?XD?MY_FUNCTION?FIRM_FUNC SEGMENT XDATA OVERLAYABLE RSEG ?PR?FIRM_FUNC _my_function: DS 3 ; 3 bytes for a jump RSEG ?XD?MY_FUNCTION?FIRM_FUNC ?_MY_FUNCTION?BYTE: var1: DS 1 var2: DS 1 var3: DS 1 var4: DS 1
for the function
char my_function(char var1, char var2, char var3, char var4);
and then specify the linker position of: - the table (?PR?FIRM_FUNC) - parameters (?_MY_FUNCTION?BYTE) via
CODE(0x1800-0xFFFF, ?PR?FIRM_FUNC (0x1800), ?PR?MAIN?MAIN (0x1810)) DATA(?XD?MY_FUNCTION?FIRM_FUNC (28h))
(main will be easier to call if at a fixe address, isn't it?)
Here is an example when I compile the function "my_function"
------- PROC _MY_FUNCTION D:0007H SYMBOL var1 --> via register R7 X:F3DBH SYMBOL var2 --> via XDATA D:0003H SYMBOL var3 --> via register R3 X:F3DDH SYMBOL var4 --> via XDATA ------- DO X:F3DEH SYMBOL i X:F3DFH SYMBOL j X:F3E0H SYMBOL ptr_message ------- ENDDO C:1208H LINE# 1 ------- ENDPROC _MY_FUNCTION
var1 and var3 are not into xdata, but register, so my segment declaration above should be wrong (?_MY_FUNCTION?BYTE:), isn't it?
As you can see, I have tried, but could not understand completely how the compiler knows where to write parameters.
Maybe your last solution would be easier: a single well-known entry point? I'll think about it...
Any ideas how to solve my problem?
Thanks for your help, Damien.
Might it not be simpler to just make your "firmware" a very simple bootloader, so that it doesn't need to call any functions from the application?
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.