| Details | Message |
|---|
Read-Only Author Franquet Damien Posted 2-Oct-2007 16:58 GMT Toolset C51 |  Firmware and application cohabitation on the same device Franquet Damien 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. |
|
Read-Only Author Andy Neil Posted 2-Oct-2007 17:13 GMT Toolset C51 |  RE: Firmware and application cohabitation on the same device Andy Neil 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...? |
|
Read-Only Author Franquet Damien Posted 2-Oct-2007 17:26 GMT Toolset C51 |  RE: Firmware and application cohabitation on the same device Franquet Damien 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 |
|
Read-Only Author Andy Neil Posted 2-Oct-2007 17:44 GMT Toolset C51 |  Non-sequitur Andy Neil "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? |
|
Read-Only Author Franquet Damien Posted 2-Oct-2007 17:49 GMT Toolset C51 |  RE: Non-sequitur Franquet Damien Yes I have APIs that allow to read/write my flash (they are part of my firmware). Thanks, Damien |
|
Read-Only Author Drew Davis Posted 2-Oct-2007 17:48 GMT Toolset C51 |  RE: Firmware and application cohabitation on the same device Drew Davis 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. |
|
Read-Only Author Franquet Damien Posted 2-Oct-2007 18:50 GMT Toolset C51 |  RE: Firmware and application cohabitation on the same device Franquet Damien 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. |
|
Read-Only Author Andy Neil Posted 2-Oct-2007 19:51 GMT Toolset C51 |  Are we making things too complicated? Andy Neil 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? |
|
Read-Only Author Per Westermark Posted 2-Oct-2007 20:08 GMT Toolset C51 |  RE: Are we making things too complicated? Per Westermark No - stay away from simple solutions. They have a tendancy to actually work. What would we then do with our spare time? |
|
Read-Only Author Franquet Damien Posted 3-Oct-2007 09:46 GMT Toolset C51 |  RE: Are we making things too complicated? Franquet Damien 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. |
|
Read-Only Author Per Westermark Posted 3-Oct-2007 09:55 GMT Toolset C51 |  RE: Are we making things too complicated? Per Westermark 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! |
|
Read-Only Author Franquet Damien Posted 3-Oct-2007 10:36 GMT Toolset C51 |  RE: Are we making things too complicated? Franquet Damien 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 :) Damien. |
|
Read-Only Author Andy Neil Posted 3-Oct-2007 10:44 GMT Toolset C51 |  Still overcomplicating Andy Neil "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... |
|
Read-Only Author Franquet Damien Posted 3-Oct-2007 11:20 GMT Toolset C51 |  RE: Still overcomplicating Franquet Damien 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. |
|
Read-Only Author Per Westermark Posted 3-Oct-2007 15:13 GMT Toolset C51 |  RE: Still overcomplicating Per Westermark 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. |
|
Read-Only Author Franquet Damien Posted 3-Oct-2007 16:35 GMT Toolset C51 |  RE: Still overcomplicating Franquet Damien "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. |
|
Read-Only Author Drew Davis Posted 3-Oct-2007 17:20 GMT Toolset C51 |  RE: Still overcomplicating Drew Davis I have no BIOS available into my chip. 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. |
|
Read-Only Author Franquet Damien Posted 3-Oct-2007 17:36 GMT Toolset C51 |  RE: Still overcomplicating Franquet Damien 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...) Damien. |
|
Read-Only Author Per Westermark Posted 3-Oct-2007 22:41 GMT Toolset C51 |  RE: Still overcomplicating Per Westermark 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. |
|
Read-Only Author Franquet Damien Posted 4-Oct-2007 10:28 GMT Toolset C51 |  RE: Still overcomplicating Franquet Damien 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. Damien. |
|
Read-Only Author Per Westermark Posted 4-Oct-2007 13:45 GMT Toolset C51 |  RE: Still overcomplicating Per Westermark 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. |
|
Read-Only Author Andy Neil Posted 4-Oct-2007 14:14 GMT Toolset None |  Mutually exclusive? Andy Neil "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. |
|
Read-Only Author erik malund Posted 4-Oct-2007 14:36 GMT Toolset None |  RE: Mutually exclusive? erik malund 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 |
|
Read-Only Author Franquet Damien Posted 4-Oct-2007 15:10 GMT Toolset None |  RE: Mutually exclusive? Franquet Damien 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) http://www.keil.com/support/man/docs/c51/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 |
|
Read-Only Author erik malund Posted 4-Oct-2007 15:50 GMT Toolset None |  I'd do it like this erik malund 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). It should be obvoous that if you change the bootloader/BIOS you need to change the app as well, the below requires that. write an assembler module with all global BDATA/DATA/IDATA/PDATA/XDATA that the bootloader/BIOS uses and link it with both bootloader/BIOS and app. for the bootloader/BIOS write a .h module that defines all variables in the asm module as extern. If you want to, you can even link that with the app. There will be a requirement that all functions are declared reentrant to make them not use call tree since one will not be aware of the other. If main() can not be declared reentrant there can be no locval variables in main() Erik |
|
Read-Only Author Franquet Damien Posted 4-Oct-2007 16:09 GMT Toolset None |  RE: I'd do it like this Franquet Damien |
|
Read-Only Author Franquet Damien Posted 4-Oct-2007 16:11 GMT Toolset C51 |  RE: I'd do it like this Franquet Damien Damn it did not post my reply! Here it is again It should be obvoous that if you change the bootloader/BIOS you need to change the app as well, the below requires that. Yes I was aware of that :) write an assembler module with all global BDATA/DATA/IDATA/PDATA/XDATA that the bootloader/BIOS uses and link it with both bootloader/BIOS and app. That's a good idea, I'll try that! But I have some libs and I don't have its source code, so I can't define them all in my firmware ASM file. I'll have to make a new ASM file for the application including all firmware variables. Too bad :( There will be a requirement that all functions are declared reentrant to make them not use call tree since one will not be aware of the other. If main() can not be declared reentrant there can be no locval variables in main() Why do have I to set function reentrant? I'm not using any OS, so when I'm running a firmware function, the application can not perform something else. reetrant is not for functions that can be called twice at the "same time", like isr or tasks? Thanks! Damien. |
|
Read-Only Author erik malund Posted 4-Oct-2007 16:45 GMT Toolset C51 |  RE: I'd do it like this erik malund That's a good idea, I'll try that! But I have some libs and I don't have its source code, so I can't define them all in my firmware ASM file. I'll have to make a new ASM file for the application including all firmware variables. Too bad :( If you do not have the source , you simply CAN NOT do what you want (see below) Why do have I to set function reentrant? I'm not using any OS, so when I'm running a firmware function, the application can not perform something else. let us take an example: BB (bootloader BIOS) is compiled and linked separately, app is compiled and linked separately, all BB global varibales are avoided by the app.
the app
void main (void)
{
U8 var1; // placed by the linker at end of globals
U16 var2; // placed by the linker at end of globals+1
BBfunc1()
}
void BBfunc1(void)
(
// the BB is not 'aware' that the app placed temp variables by the call tree
U8 bvar1; // placed by the linker at end of globals
U16 bvar2; // placed by the linker at end of globals+1
}
Thus you need reentranr, not for reentancy, but for no call tree. Erik |
|
Read-Only Author Franquet Damien Posted 4-Oct-2007 18:09 GMT Toolset C51 |  RE: I'd do it like this Franquet Damien Ok! Thanks!! If I specify a new zone for my application's global variable (_IBIT_GROUP_, _DATA_GROUP_, _IDATA_GROUP_, _XDATA_GROUP_), then I don't need to define them as reentrant? BL51 linker:
XDATA([...], _XDATA_GROUP_ (0x1806))
It will use more memory, but it will be possible to call functions from my library, right? Damien. |
|
Read-Only Author erik malund Posted 4-Oct-2007 18:18 GMT Toolset C51 |  you do not define variables as 'reentrant' erik malund If I specify a new zone for my application's global variable (_IBIT_GROUP_, _DATA_GROUP_, _IDATA_GROUP_, _XDATA_GROUP_), then I don't need to define them as reentrant? you define functions as reentrant RTFM as to how. Erik |
|
Read-Only Author Franquet Damien Posted 5-Oct-2007 10:24 GMT Toolset C51 |  RE: you do not define variables as 'reentrant' Franquet Damien I'm sorry, I don't understand "RTFM as to how". Does it mean "Read the manual to know how reentrant function works, please"? Then I'm sorry to disappoint you, but I did. From this article http://www.keil.com/support/docs/1854.htm , I understand that normal function use _DATA_GROUP_ for local variables. From this article: http://www.keil.com/support/man/docs/c51/c51_le_reentrantfuncs.htm Reentrant directive inform the compiler/linker to not use _DATA_GROUP_ but a separate stack (XDATA for me, because I use LARGE model). So I thought that if I declare two different _DATA_GROUP_, one for my firmware, and one for my application, I don't need reentrant functions. Let me explain: FIRMWARE
void BBfunc1(void)
(
U8 bvar1;
U16 bvar2;
}
APPLICATION
void main (void)
{
U8 var1;
U16 var2;
BBfunc1()
}
I specify the _XDATA_GROUP_ (LARGE model) for application at 0xEC00 _XDATA_GROUP_ for the firmware is placed by the linker, I do not give any specification: 0x1800 is the address of the _XDATA_GROUP_ of the firmware. Once complied/linked, I'll have: FIRMWARE
SEGMENT XDATA_GROUP
+--> CALLED SEGMENT START LENGTH
----------------------------------------------
?PR?BBFUNCT1?FIRMWARE_FUNC 1808H 0006H
APPLICATION
SEGMENT XDATA_GROUP
+--> CALLED SEGMENT START LENGTH
----------------------------------------------
?PR?MAIN?MAIN EC00H 0006H
+--> ?PR?BBFUNCT1?FIRMWARE_FUNC
==> var1/var2 and bvar1/bvar2 are not located at the same address because _XDATA_GROUP_ are not located at the same address.
==> Do I still need reentrant functions?? I don't think so. Am I wrong? Damien. |
|
Read-Only Author erik malund Posted 5-Oct-2007 13:55 GMT Toolset C51 |  Uh, Oh erik malund I just read up on reentrant (which I never have or would use) and saw the thing about 'stack location'. I, incorrectly, assumed it was like it was once (passing parametres on the internal st6ack) MY BAD. Now, for your thingy you need contact Keil support (since you use allmost 64k, you must have a license) and find out how to avoid having separate stack pointers. Erik |
|