Maple Bootloader 2.0

RogerClark
Mon Apr 27, 2015 11:16 am
The an bootloader is being developed to replace the existing Maple bootloader.

The improvements in the “bootloader 2.0” are

  • All RAM in the processor is available to the Sketch for uploads to Flash. In the old bootloader, 3k is always allocated to the bootloader even though the bootloader does not run after the sketch starts, so 3k does not need to be reserved
  • “Bootloader 2.0” is 12k smaller than the old bootloader, so that there is 12k more for the sketch
  • Uploads on OSX and Linux should be much faster

Current Status

The bootloader works for Maple mini, when used with the latest version of Arduino STM32 from GitHub.
You also need to select “Bootloader 2.0” from the “Bootloader version” menu within the Maple mini board selection.

There is however one bug that needs to be resolve. Uploads to RAM do not currently work.
This is because the old upload to RAM could fail intermittently to run. This is because the bootloader attempts to detect if the RAM contains a sketch or just variables, and the “magic number” used for this purpose is weak.

I am developing a new system which uses a 64 or possibly a 128 bit magic number, rather than the effective 13 bit magic number that the old bootloader used.


victor_pv
Mon Apr 27, 2015 3:13 pm
Roger, I suggest to just change the mask used to filter the SP address in checkUserCode in hardware.c

if ((sp & 0xFFFE0FFF) == 0x20000000) {

That only leaves 5 bits out, that cover the range from 4KB to 64KB. There could still be false positives, but much less likely that the current one.


victor_pv
Mon Apr 27, 2015 3:29 pm
Actually, what about this?

Seems to compile fine for me. I’m not at home so didn’t have a chance to test it.

#if defined(TARGET_MAPLE_MINI)
if (sp == 0x20005000) {
#elif defined(TARGET_MAPLE_REV3)
if ((sp & 0x2FFE0FFF) == 0x20000000) {
#endif


RogerClark
Wed Apr 29, 2015 1:18 am
Victor

The problem is not the two different versions of board.

The problem is the upload to RAM

When the bootloader resets its self after an upload to RAM, it has to look for a flag in the RAM that indicates that a sketch is in the RAM

Previously it looked at 0x20000c0 for that pattern (as shown in your code) but when we allocate all RAM to the sketch, the sketch variables will be put into the RAM location that the bootloader checks

And the issue is that we’ve no control of what the sketch will put at offset 0xc00 from the base of RAM

At the moment, the sketch seems to consistently put a value (from its vars) into that location, which the bootloader reads as a valid SP vector

Hence to free up all RAM for the sketch we had to build a new version of the bootloader that doesnt do the RAM check.

But for backwards compatibility, I was hoping to keep the RAM upload, even though its almost impossible to use, even on the old Maple IDE, because the blink sketch in the old IDE only just fits in RAM on a Maple mini

I thought that after an upload to ram, that the bootloader could just switch to executing from RAM, but it doesn’t seem to do that. It seems to reset its self (not sure why), and then restarts main() from the beginning.
So unless I can get it to run without resetting, we’d need to store a much more reliable flag in the code to indicate the last upload was to RAM

The guaranteed way to do this is to not allow the sketch to use the lower 4 or 8 bytes of ram, and get the bootloader to set some magic number in there that we know the sketch will not overwrite, as it wouldnt use those bytes.

But I don’t like the thought of not having all ram available for the sketch

I think people would perhaps prefer if we just get rid of upload to ram. Well I can leave it in the code, but perhaps return an error, e.f. upload to ram no supported


victor_pv
Wed Apr 29, 2015 12:07 pm
Roger, I understand the sketch may load whatever it wish in …C00, but given that the address 0x20005000 is actually out of the range of RAM for that MCU, and as far as I know is only used for the SP, what are the chances that a sketch will use that 32 bit value somewhere, and then the chances that will store that exactly at C00?

The original code mask all the bottom bits, which I think causes the issue, because any RAM address will fit a pattern when you are masking out all the bottom bits of the addresses, and even some top ones… so if the sketch loaded the value of any valid RAM address in that position, the check would be positive.

But by checking to 1 single 32bit number, which on top is an address out of range, I don’t think we should get false positives.
I compiled a bootloader to test it, but that was right when my mini died and never got a chance to test it. Now I think I repaired the short in the board (burnt 1117), and my bootloader works, but I suspect higher flash addresses get corrupt because I detect the Serial port but with the wrong hardware id (0E0F rather than 1EAF) so the drivers wont load for it. I will try testing all my flash later with ST-Link with different bit patterns to see if any address fails, and if so make a bootloader for that board that loads the sketches higher than that… that will keep me busy until another maple mini arrives ;)


RogerClark
Wed Apr 29, 2015 12:22 pm
Victor,

Using the top of the RAM seems worth trying.

Perhaps a 64bit one e.g unsigned long 0x1EAF1AB5

I.e in homage to LeafLabs ;-)

Ps see my postings about stlink now working much better


victor_pv
Wed Apr 29, 2015 12:50 pm
Roger,

I believe checking for exactly 2005000 should be very reliable, but if not, what about this?
-Uploads to RAM set the top of the RAM 4 bytes shorter than the actual RAM, and the SP address 1 byte lower.
We store 1 particular value at those bytes, and check for them.


RogerClark
Wed Apr 29, 2015 10:02 pm
Victor,

I will test and get back to you. I think there may be a simpler solution ;-)


bobc
Thu Apr 30, 2015 10:10 pm
Personally, I would drop the upload to RAM option. In introduces an unnecessary complexity, and I just can’t see the need. Certainly the “quick and simple” method LeafLabs chose is unreliable.

I think this is one of the mis-steps Leaflabs made. My experience with bootloaders is that robustness is far more important than features.

Btw, I use emblocks to build the bootloader, and STLINK JTAG to debug, which proved really useful in tracking down the problems caused by the upload to RAM option.


RogerClark
Thu Apr 30, 2015 10:40 pm
Bob

I was hoping for 100% backwards compatibility, but I agree, the whole upload to ram thing is fairly pointless

As a test I ran the original Maple IDE, and uploaded their Blink sketch to RAM, and it ran OK, but Blink takes around 90% of available RAM

So in the real world upload to ram is basically useless for any sketch that actually does any work.

I agree it was a gimic.

I’ll see if I can get the bootloader to return an error message if an upload is requested to RAM. I know it can return error codes, but I’m not sure the mechanism to attach a message, as the code doesnt ever seem to return error messages

PS. Thanks for the tip about using em:blocks to build, so I can debug via stlink

Exellent idea.

I also have CooCox, so I could probably use that as well


RogerClark
Fri May 01, 2015 11:51 am
Bob and Victor

Rethinking this. … Ignore my posting below

Whichever way I do this, its going to be a bit of a hack.

I will remove the RAM upload option, by returning an error if ALT ID 0 is selected.
I will see if there is a way to return an error message under the DFU protocol

—————– ignore the rest of the posting ————

Apart from just dropping the RAM upload entirely, which is still probably the best idea,

I was toying with the idea of doing this as a test (see below)

If I use __attribute__ ((section (“.noinit”)))

I think its going to tell the compiler not to initialise any variables at all.

so the global unsigned long ramUploadMagic; won’t get initialised after a warm boot, hence if I set it to a big magic number after the RAM upload is complete, when it boots again, when the code reads the value of this, it should contain the same magic number

i.e this relies on the fact that the code compiler will put the location of that global variable in the same place in ram ever time

But I guess this could be seen as a bit of a hack

The other option is just to use a hard coded pointer to 8 bytes at the top of RAM

I know either way is not fool proof, but the only way to do this in a foolproof manner is to save the value in flash / eeprom

Edit. BTW. Yes. I know the bootloader may not work at all with the noinit setting as the code may be relying on C setting a variable to zero, so that would need to be sorted out first, ie make sure there is code to init every var that needs to be init’ed. (personally I always do this anyway)

#include "common.h"
#include "dfu.h"
extern volatile dfuUploadTypes_t userUploadType;
__attribute__ ((section (".noinit")))
unsigned long ramUploadMagic;
#define RAM_UPLOAD_MAGIC 0x1eaf1abs
int main()
{
systemReset(); // peripherals but not PC
setupCLK();
setupLED();
setupUSB();
setupBUTTON();
setupFLASH();

strobePin(LED_BANK, LED, STARTUP_BLINKS, BLINK_FAST);

/* wait for host to upload program or halt bootloader */
bool no_user_jump = (!checkUserCode(USER_CODE_FLASH0X8005000) && !checkUserCode(USER_CODE_FLASH0X8002000)) || readPin(BUTTON_BANK,BUTTON);
int delay_count = 0;

while ((delay_count++ < BOOTLOADER_WAIT) || no_user_jump)
{

strobePin(LED_BANK, LED, 1, BLINK_SLOW);

if (dfuUploadStarted())
{
dfuFinishUpload(); // systemHardReset from DFU once done
}
}

if (ramUploadMagic==RAM_UPLOAD_MAGIC)
{
// if we have just uploaded to RAM, then run whats in RAM
jumpToUser(USER_CODE_RAM);
}
else


victor_pv
Sat May 02, 2015 2:16 pm
Roger, remember there is a string in the code that identifies each ID?
The one that shows something like “DFU Flash 0x8005000”.
What about changing that for the ram ID, so it shows something like “Upload to RAM NOT SUPPORTED”.
As that string is returned by the bootloader when an option is selected, if you can return that before an error code, anyone looking for why his upload to RAM failed, should be able to read the message right there.
That could be an option to return a message.

RogerClark
Sat May 02, 2015 9:01 pm
Hi Victor,

Great minds think alike ;-)

BTW.

Because those messages are a pain to put into the code because every character seems to need a zero byte after it ( not sure why, perhaps its Unicode )

In the bottom of usb_desciption.c , I put a small JavaScript utility, as a comment.
If you copy the commented HTML js code to a temporary HTML file and open it in the browser
It spits out the code for the 3 ALT ID arrays, so save having to do them by hand.

I have figured also worked out,what the Mask stuff in the config does. It’s to mask off the 4 bits in the control register when the bootloader sets the pin mode of the led as output and the button as input.

So if I get chance I will add the code for my Maple Rev3 clone, and see if I can update that bootloader as well


RogerClark
Mon May 04, 2015 12:06 pm
Guys

I have been doing some more work on the Bootloader to add some code comments in how to port to different boards.
But it’s not all working yet.

And I have setup 4 different build targets, maple mini, maple rev 3, maple rev 5 (same as maple rev 6 and maple Ret), and a build for my generic stm32f103c8 , just to test on a different led.

I’ve also written a simple HTML JavaScript utility to generate the USB DFU description strings

The GPIO in the bootloader has to be setup form first principals, but I don’t think I have figured it all out yet, as I can’t get the led on pc13 to flash .

I was thinking that as well as version number, the DFU messages should possibly contain which target the build is for e.g. Put (maple mini) at the end of the texts.


RogerClark
Tue May 05, 2015 12:28 am
Victor

I’m not sure whats going wrong, but I can’t seem to change it so that the bootloader has the LED on Port C instead of port B

The Maple mini config code looks like this


#define LED_BANK GPIOB
#define LED 1
#define LED_BANK_CR GPIO_CRL(LED_BANK)
#define LED_CR_MASK 0xFFFFFF0F
#define LED_CR_MODE 0x00000010
#define RCC_APB2ENR_LED 0x00000008 /* enable Port B (bit 3 - see table above IOPBEN)*/

/* On the Mini, BUT is PB8 */
#define BUTTON_BANK GPIOB
#define BUTTON 8
#define BUT_BANK_CR GPIO_CRH(BUTTON_BANK)
#define BUT_CR_MASK 0xFFFFFFF0
#define BUT_CR_OUTPUT_IN 0x00000004
#define RCC_APB2ENR_BUT 0x00000008 /* enable Port B (bit 3 - see table above IOPBEN)*/


victor_pv
Wed May 06, 2015 4:39 am
Roger did you check how it compares to the Maple bootloader, which apparently had the led in GPIOA:

I was having a look at the code and seems like it is just the masks that change:
https://github.com/leaflabs/maple-bootl … hardware.c

Also this initial commit adapting the bootloader to a board called robotis may help, as the led was moved to another pin:
https://github.com/Gregwar/maple-bootlo … bddaf2b05f


RogerClark
Wed May 06, 2015 4:58 am
Victor

yes. I checked against the Maple RET5 / 6 and what I changed seemed to be correct

I only think one person has a Maple RET6 and he built it himself, and has not asked for the new bootloader

It looks like the Maple Rev3 may work with the Maple mini bootloader, I think it has the same pins for LED and button,
I don;t even think I need to change the Flash size in the bootloader, as the Maple REV 3 uses a F103RB which seems to be the same as the CB just in a bigger package


tekk
Tue Jun 30, 2015 8:53 am
Hi there,
Sorry, I have a really noob question.

How do I burn the 2.0 Bootloader on my maple mini clone?

I’ve read somewhere that stm32flash utility in the tools could burn it, but I can’t find .bin file of the 2.0 Bootloader.
Could anybody please explain me the process of burning the bootloader on BAITE maple mini clone?

Thanks a lot.


RogerClark
Tue Jun 30, 2015 9:58 am
If you have a maple mini with a bootloader on it already, just load the sketch, I posted, (see link below) and follow the instructions

viewtopic.php?f=21&t=257&p=3229&hilit=updater#p3241


mrburnette
Tue Jun 30, 2015 12:07 pm
tekk wrote:<…>
How do I burn the 2.0 Bootloader on my maple mini clone?

RogerClark
Tue Jun 30, 2015 12:15 pm
Ray,

It should still work if they select the old bootloader, they just don’t get the benefit unless they select the new one.

Actually on OSX and Linux the instant benefit is much faster uploads (though I’m not sure why this is, as it was something that had already been addressed in the code that we found, i.e an enhanced version of the original leaflabs version)


mrburnette
Tue Jun 30, 2015 12:31 pm
RogerClark wrote:Ray,

It should still work if they select the old bootloader, they just don’t get the benefit unless they select the new one.

Actually on OSX and Linux the instant benefit is much faster uploads (though I’m not sure why this is, as it was something that had already been addressed in the code that we found, i.e an enhanced version of the original leaflabs version)


tekk
Wed Jul 01, 2015 6:26 am
mrburnette wrote:RogerClark wrote:
Honestly, I have never tried the “normal’ setting on my modified-mini… I only upgraded the bootloader for the additional SRAM.

RogerClark
Wed Jul 01, 2015 12:07 pm
@tekk

The new bootloader has an additional upload mode that the old one didnt have.

The new mode (DFU Alt ID 2) uploads with the start address of 0x8002000
Where as the old bootloader only had one upload to flash location (DFU Alt ID 1) of 0x8005000

So if you try to use the bootloader 2 upload on an old bootloader, I suspect I will give an error, as it won’t understand the upload mode ID.

The Old bootloader has upload to RAM, (DFU Alt ID 0), however this is effectively removed in the new bootloader because its virtually useless, as most sketches won’t fit in the 20k ram on a Maple mini – and there were other technical reasons about the bootloader determining whether it had a valid sketch in RAM after soft reset, which make the upload to RAM problematic.

(The upload to RAM option was removed from the upload menu some time ago)

But for compatibility, DFU Alt ID 0 (upload to RAM) is retained in the new bootloader, it simply returns an error code if you try to use it (i.e by modifying platform.txt or some of the other core files)


Leave a Reply

Your email address will not be published. Required fields are marked *