Hi All,
I am not sure whether this better belongs in the programming or bootloader sections.
I have been developing firmware for my Arduino Mega 2560 R3 based tracked robot platform for use with my Computer Science classes. I have been working on the firmware for several years. It is now pretty comprehensive for what I want. It has several switch selectable modular routines, including roam mode (soon to have mapping capability), turtle mode, bench and field diagnostics, ISP mode (for the Dagu ComMotion shield), an LCD and Serial menu system. It includes lots of library code. I intend to release the final product as Open Source.
The next requirement I intend to add is a pretty tough one though. I want to add a second layer to the firmware. I intend to reserve a large chunk of program flash memory and RAM and allow the main firmware to upload new student-written modules into it that are being sent to it via Wifi. The student modules will be compiled to binary from C++ or Haiku Java. They will have a access to an API provided via a vector table of some description written at a known address of the program memory. The module will be started / called from the main firmware. The only part I am not sure of is how to do is how to get the compiler and linker to generate code that is targeted at a non-standard start address and includes no runtime start-up. ANy ideas please?
Stephen Parry
Tough one in my view...
wouldn't it be easier to give them a .o or .a and a .h for an interface of your stuff to link against with an extern entry point / hooks and they generate a full binary?
I want to try and keep a known good core firmware that they cannot easily corrupt, a bit like a bootloader or primitive OS, that I can update separately from their code. It would also cut down on flash wear and tear because they would only be causing writes to the upper currently less 'worn' end of the flash. Plus that way you are not trying to overwrite code you are currently running.
OK - I get the intent. does not seem an easy one to me... never really tried modifying the flash memory at run time in a MEGA.
may be explore this ?
sgparry:
The only part I am not sure of is how to do is how to get the compiler and linker to generate code that is targeted at a non-standard start address and includes no runtime start-up.
You need to modify the linker script. Why do you want to exclude the startup files? The startup files initialize the envirenment to be used by the compiled program (e.g. setting up the sections in memory, initializing the .bss segment with zero, loading the .data segment from flash to sram, etc.).
As J-M-L suggested, I would rather compile your core firmware into a static library and link it against your students projects. The library will define the main function and calls into the students code by a predefined function, e.g. studentmain.
sgparry:
Plus that way you are not trying to overwrite code you are currently running.
I am not sure if I understood that correctly, but while you are updating the flash there is no other code running as the arduino has only one core.
I don't need the start-up, at least not the standard start-up, because the main firmware will have already done all that. The students code will effectively be just a set of compiled functions with known entry points, called from the main.
As I explained earlier - the students code will be uploaded via Wifi by the main firmware. If I used a single monolithic statically linked binary as you sugested:
a) It would be overwriting the code that is receiving and flashing the code...
b) if the students bork the binary or the upload, I have to reflash the robot from scratch via USB
c) if the students link with the wrong version of the main code, things become unpredictable
d) their code will be about a tenth the size of the main firmware
e) the main firmware takes appreciable time to flash
f) I have already burned a big portion of the 10,000 flash write cycles. I'd rather get as much life out of the thing as I can.
sgparry:
I don't need the start-up, at least not the standard start-up, because the main firmware will have already done all that. The students code will effectively be just a set of compiled functions with known entry points, called from the main.
Ah, I see. Well if no global or static variables are involved, compile with -nostartfiles -nostdlib. Keep in mind, that whenever you use string literals (e.g. Serial.println("Hello")) you will need to have the startup files. Depending on the linker script your students might need to name their main function __init().
sgparry:
As I explained earlier - the students code will be uploaded via Wifi by the main firmware. If I used a single monolithic statically linked binary as you sugested:
a) It would be overwriting the code that is receiving and flashing the code...
b) if the students bork the binary or the upload, I have to reflash the robot from scratch via USB
c) if the students link with the wrong version of the main code, things become unpredictable
d) their code will be about a tenth the size of the main firmware
e) the main firmware takes appreciable time to flash
f) I have already burned a big portion of the 10,000 flash write cycles. I'd rather get as much life out of the thing as I can.
a) Yes, but only if you do a flash-erase before you program it. The bootloader will stay the same.
For all other points: Agreed. What IDE are your students going to use?
The big problem with (a) is when (c) happens - because then the code doing the flashing or calling the code to do the flashing will potentially change mid write. Unless I write / acquireand burn an entire separate Wifi enabled PIN protected bootloader.
I suspect I will need to cobble together a custom replacement for start-up, callable as a function from the core firmware, that would do a subset of what the normal start-up does.
The IDE is up for debate - I am still exploring alternatives. For our main programming activities (Java, PHP and some C++) we use Netbeans, but it's C++ support is fairly minimal compared to for example Eclipse.
Ultimately, I am also hoping to use an adapted version of Haiku to provide bytecode to C++ transpiling, as Java is the students' main language and one of the main aims is to improve that skill. However, that will require a lot of work. I could also try constructing my own Java-like DSL, with C++ as intermediate, or generating my own byte code with an interpreter in the core firmware. Still working those ideas through.
I really don't see a need to remove the startup code. You can assign a different memory area to your students program than for your core firmware. This can be done, using the linker script, for both flash and sram. As for java, check out this port to an atmega8. If you are going to use c++ I highly recommend atmel studio.
Let's say I load up the student program including the standard start-up - is there a point within the start-up I can call to do the necessary initialisation that will then return control to the calling code once the initialisation is complete? C++ start up is normally a 'fire and forget' process, i.e. it never 'returns' because there is nowhere to 'return' to; instead it finishes by jumping to main. I want the student start-up to be callable, so I can keep the main execution loop within the core in a similar way the normal Arduino runtime. The core loop would call out to the functions within the student code in a similar way to how setup() and loop() are called by the runtime main().
sgparry:
Let's say I load up the student program including the standard start-up - is there a point within the start-up I can call to do the necessary initialisation that will then return control to the calling code once the initialisation is complete? C++ start up is normally a 'fire and forget' process, i.e. it never 'returns' because there is nowhere to 'return' to; instead it finishes by jumping to main. I want the student start-up to be callable, so I can keep the main execution loop within the core in a similar way the normal Arduino runtime. The core loop would call out to the functions within the student code in a similar way to how setup() and loop() are called by the runtime main().
I only thought about the students program jumping to main after initialization is done. But since you are not linking your firmware against it, this can not work. Maybe you can get your hands on the startup code and change the jump to main to a return? Also you need to remove the stack initialization. The more i think about it it might be easier to implement the startup yourself.
you should look how my ArduinoOTA library updates application and calls functions in Optiboot. and how bootloader is compiled to address at the end of the flash
and read this too https://www.avrfreaks.net/forum/eicall-app-bootloader-atmega-2560-jumps-address-0x1fe01-without-eind-set