[solved]SD Card Loader hang with big binaries

@jonne I have done some testing of the SD Card Loader hang that was earlier noticed with bigger size binaries. I added “const uint8_t background_bmp[] {…}” table to a simple C++ test app, and tested the background_bmp with different allocated sizes. I think it does not matter much what kind of test app is used. I used the sound test app.

If the resulted binary was 129 kb or lower, I did not experience any hang. With the 135 kb binary it was hanging. However, it was not so straightforward, as 138 kb binary did not hang (!).

I have attached it the"main.cpp" & “My_settings.h” which should result 135 kb binary. Replace the original files in the “Examples/HelloWorld” folder with new ones, and copy the resulted binary to the SD card. The hang should occur after the “success!!” text was displayed in the loader.

HelloWorld.zip (7.6 KB)

hello - hangs with SD loader.bin (134.1 KB)

Edit: just to note that when using the USB flashing, the 135 kb binary works just fine.

1 Like

Thanks @Hanski

Your description of the problem and max size where problem arises gives me an idea what is the matter.

I put a safety catch (max sector number) in early stages of development to make sure high area of memory was not overwritten. I have a feeling it might still be effective :blush:

If so, that’ll be an easy fix



@Hanski : the problem turned out to be more difficult to track than I thought

The problem was that my function for calculating first page of each flash sector was faulty

/* Check is it the first page in the sector */

if (address == (sector-24)*0x4000 + 0x18000) firstpage = true;

So the mistake was that each sector below 0x18000 is 4 kB (0x1000). (as per User Manual for LPC11U68, page 438) and each sector above 0x18000 is 32kB and my algorithm was faulty.

Now, if you look at my formula, for sector 25 (address 0x20000) the formula gave 0x1C000 (not 0x20000) meaning the first page of the flash sector would have not been identified

Why this made a difference is that prior to writing each sector each sector must be erased correctly which was not happening. Firstpage was never true for address above 0x20000, the sectors above 24 were not erased and therefore binary was never written to flash.

The reason why I never noticed this that for the first 32kB sector (sector 24, address 0x18000) the formula does return the right address. So sector 24 did work, everything looked alright but all big binaries were truncated at 0x20000 !

By replacing the faulty calculation with a brute force check, the problem was solved.

if (address == 0x18000 || address == 0x20000 || address == 0x28000 || address == 0x30000 || address == 0x38000) 
                firstpage = true;

Big binaries work now. An update to loader and a new gamedisk including all big game binaries & Hanski’s python games is coming this weekend!

Another lesson in the incredibly interesting land of embedded electronics!


That is A-W-E-S-O-M-E news!

1 Like

An updated gif-anim or teaser video about the Pokitto game catalog could speed-up sales :wink:

1 Like

Instead of a brute force, why don’t we just fix your calculation?

The problem is that 0x4000 isn’t 32KB, it’s 16KB.
32 * 1024 converted to hex is 0x8000.

Therefore your calculation can be fixed by making it:

 /* Check is it the first page in the sector */
if (sector < 24) {
    if (address == sector * 0x1000) firstpage = true;
} else {
    if (address == (sector - 24) * 0x8000 + 0x18000) firstpage = true;

(Unrelated: I wonder if the Cortex M0+ has a fused multiply-add instruction?)

I took the liberty of creating a pull request for this method:

I haven’t checked with an actual SD card because I haven’t got round to getting a microSD for the Pokitto,
but I checked the maths involved and I’m almost certain that it calculates the offset properly.

I tested the calculations using a C# program:

using System;

namespace SectorTest
    class Program
        static void Main(string[] args)
            for (uint i = 0; i <= 28; ++i)
                Console.WriteLine("Test {0}", i);
                uint bad = BadAddress(i);
                uint good = GoodAddress(i);

                Console.WriteLine("Bad Range: {0:X} - {1:X}", bad, bad + (0x8000 - 1));
                Console.WriteLine("Good Range: {0:X} - {1:X}", good, good + (0x8000 - 1));

        static uint BadAddress(uint sector)
            if (sector < 24)
                return sector * 0x1000;
                return (sector - 24) * 0x4000 + 0x18000;

        static uint GoodAddress(uint sector)
            if (sector < 24)
                return sector * 0x1000;
                return (sector - 24) * 0x8000 + 0x18000;

The GoodAddress method matches up with the chart you provided.

(While peeking at the code I can see a few other possible improvements as well,
but I’m not sure how I’d go about testing them or if they’d be worthwhile.)

1 Like

Because with only so many checks it doesn’t make a difference.

BTW, another way to check would be:

if ((sector<24 && !address&0xFFF) firstpage=true; else if (!address&0x7FFF) firstpage=true;

Maybe not in speed, but it probably makes a small size difference.

Are you sure about that?
! has a higher precedence than & so that’s equivalent to:

if ((sector < 24) && ((!address) & 0xFFF)) firstpage=true;
else if ((!address) & 0x7FFF) firstpage=true;

I think you probably meant:

if ((sector < 24) && !(address & 0xFFF)) firstpage=true;
else if (!(address & 0x7FFF)) firstpage=true;
1 Like

Now I’ve thought about it, I think the masking based approach would probably be both smaller and faster, so maybe I should withdraw my PR and either submit a new one or allow you to add the change?

I’ll leave it to you to decide.

It’s also possible to reduce it to just a one-liner:

firstpage = (sector < 24) ? ((address & 0xFFF) == 0) : ((address & 0x7FFF) == 0);

I’m not sure what sort of stylistic conventions the library follows/prefers, if any.

1 Like

Instead of withdrawing my PR I’ve just applied a new commit on top of the other one since both achieve the same thing and it’s probably less hassle than closing and making a new commit.

As I said before, what we do is up to you.
I don’t mind if you’d rather I closed the PR and you applied the change yourself since the masking approach was your idea.

(Also, sorry for making 3 replies a row, but I can never remember if people get notified of edits or not.)

1 Like

Sorry to bump, but the PR hasn’t been merged yet.

Are you waiting to check it over first to make sure it works properly,
or have you just been busy?

I’m not trying to be pushy or anything,
I’d just like to know what the situation is.

I’ve never looked yet but are we able to trigger the sd loader from our own applications?

Super busy. I am leaving for US tomorrow

EDIT: merged

@adekto : mode14 non-working example also included

Please consider making a PR about your faster directBitmap routine

1 Like

Ah, in that case it could’ve waited.
Either way it’s merged now, so people can enjoy the fix.

(I also thought you might have been expecting me to merge it (i.e. you thought I had write access).)

Nah. Its good that people remind me of things. I am handling so many things at the same time with Pokitto.


Ironically this is why I don’t like to keep posting reminders.

It’s also one of the reasons I try to answer people’s questions or help out where I can.
(And occasionally try to even if I don’t know the answer.)

The more forum members pitch in to help, the more time you have to keep production working or to work on new features.


@jonne You can create topics for each TODO task and community members could work on it. If work is so complicated cut them into little pieces for example not whole graphic DMA integration but just DMA integration for high resolution mode etc. Experienced community members could look PRs and decide to merge or not.


7 posts were split to a new topic: Loader stops working properly with more than ~80 .bin files

A post was merged into an existing topic: Loader stops working properly with more than ~80 .bin files