Bootloader - Arduino code offset?

Hi Guys,

I think I have a vague understanding of how this works, let me check:

The STM is running zephyr, with a bootloader. On reset this boot loader is run.

The boot loader then checks to see if a valid sketch is flashed and jumps to it if so.

When I build in the Arduino V2 IDE, I get a debug elf, and a smaller elf. I am imagining the smaller elf is just a stripped version, there is also a bin file that is used to program a part of the flash. I’m guessing this bin file also has some kind of header for the boot loader to check.

The symbols in the debug elf and map file are 0 based, so when using in a debugger they need to be offset to the correct address offset in flash.

Does anyone know what this offset is?

Thanks

Andy

Hopefully one of the main Zephyr people can give you a better answer.
I have not tried debug on these so not exactly sure on some parts.

Semi-related, earlier I opened up an Issue about when the app crashes, and the
Serial monitor prints out an address, how do I convert this back to the code.

How to decode a fault address? · Issue #52 · arduino/ArduinoCore-zephyr

The Arduino Zephyr code - uses Zephyr + LLExt. Which is, the Arduino people build
a zephyr app, with a subset of zephyr features and the like, and the output of which
we call the "Bootloader", which we then use the Burn bootloader command to program
the Zephyr based board. Contained within this is the ability to load in an Extention.
which can access a subset of the entrypoints contained within the "Bootloader"

There are currently two ways that the extension (your sketch) can be linked in:
image

The default is Dynamic, where your sketches gets loaded into the LLExt area, and all
references go code within the bootloader goes through an indirection. Plus of this
is you can most of the time update bootloader and sketch can still work. Down side
you could not easily convert addresses back to the code. Also everything has to fit
into the LLExt region. So for example if you have large const static data items that
don't fit into that region, you can not link.

However the Static build: it more or less relinked the sketch with the whole bootloader,
and all of the address are static. For example if you look at a map file or the like,
the addresses you see are the addresses used, which is a real Plus, but downside
is if you burn new bootloader, your sketch will most likely crash or strange things.

Also with Static, there is/was a Pull request, that allowed const static data to be
stored outside of the LLExt region. I think it is:
misc: Implement two-pass linking to separate rodata sections. by iabdalkader · Pull Request #245 · arduino/ArduinoCore-zephyr

So short answer is, maybe try Static linking and see if that helps

Thanks Kurt.

I will give that Static linking a go…

So are there two “bootloaders”, the loader from here: GitHub - arduino/ArduinoCore-zephyr: Arduino Core based on Zephyr+llext and another loader generated by the IDE? Or am I misunderstanding?

With static I get:

Linking everything together...
/bin/true
fork/exec /bin/true: no such file or directory

Compilation error: fork/exec /bin/true: no such file or directory

now this file exists on the Uno Q:

arduino@unoqboard:~$ ls -ltr /bin/true
-rwxr-xr-x 1 root root 68048 Jun  4  2025 /bin/true

But not in that location on my host machine where the build is running!


% whereis true
true: /usr/bin/true

So I edited platform.txt and changed build.check_command-static=/usr/bin/truenow it is working.

Where is the best place to report these issues I am getting on OSX?

@ptillisch would probably know the best place to report this.

But I would suggest probably to the ArduinoCore-zephyr project on github.
Issues · arduino/ArduinoCore-zephyr

Thanks Kurt, will do…

There are multiple layers of stuff: IDE Build, ArduinoCore-zephyr build, Zephyr build.
Sorry in advance if this is too much information:

zephyr
Start at the bottom: Zephyr
You can setup a build environment to build using the zephyr setup using the
instructions up at:

zephyrproject-rtos/zephyr: Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.

I have it setup on my machines (mainly windows, some Ubuntu, recently added to old MAC (I think)). I use this to test things directly out on Zephyr and to create and test
out Pull Requests to zephyr components. Like I have few in review stages now.
And for example to test out one now that outputs to the RGB leds on Arduino GIGA
I might switch to their sample app and issue a build command like:
(.venv) D:\zephyrproject\zephyr\samples\drivers\led\is31fl319x>west build -p auto -b arduino_giga_r1//m7

note actually the command I should have used was:
(.venv) D:\zephyrproject\zephyr\samples\drivers\led\is31fl319x>west build -p auto -b arduino_giga_r1//m7 --shield arduino_giga_display_shield

But in this case it built anyway...
and to flash the GIGA with this, I use the command
west flash

Which writes out the generated binary and now the leds
This writes out the whole binary in the same way building for MBED on the GIGA would

Note: I showed the above on GIGA as, AFAIK I can build for the arduino_uno_q here and maybe use debugger, but there was no currently defined flash binary...

Note: I have some of my own test apps up on github in:
GitHub - KurtE/zephyr_test_sketches: My test sketches for native zephyr sketches

Note: After you update your board using this, and then wish to run Arduino Zephyr
sketches, you must use the burn bootloader command in Arduino IDE, or
Arduino

ArduinoCore-zephyr
You can install ArduinoCore-zephyr following the instructions up at:
arduino/ArduinoCore-zephyr: Arduino Core based on Zephyr+llext

Note: while Zephyr has a native setup for building on Windows, Arduino does not.
A few of us setup a round about way to do it using WSL, where we build under
Ubuntu and either build it in the Windows directory space or copy it into the
Windows file system... I usually do the later.

With this setup you might do something like:

kurte@KurtXPS8950:~$ cd git
kurte@KurtXPS8950:~/git$ cd ArduinoCore-zephyr/
kurte@KurtXPS8950:~/git/ArduinoCore-zephyr$ ./extra/build.sh unoq

The end result of this is it generates the "Bootloader" that use in Arduino world.
The Device Tree is defined here and you can not change it in the "Arduino" builds.

Note to build all of the boards defined in here use the command:

./extra/build_all.sh

When this completes, I copy the appropriate stuff in the Windows File system:
in my case: d:\github\ArduinoCore-zephyr.

But where Arduino wishes to see it is under the Arduino Sketch folder in hardware...
In my case:

(.venv) C:\Users\kurte\Documents\Arduino\hardware\arduino-git>ls -l
total 945
lrwxrwxrwx 1 kurte 197609     28 Dec  9  2024 ArduinoCore-zephyr -> /d/github/ArduinoCore-zephyr
-rw-r--r-- 1 kurte 197609    114 Nov 29  2024 github.sublime-project
-rw-r--r-- 1 kurte 197609 962910 Nov 29  2024 github.sublime-workspace
lrwxrwxrwx 1 kurte 197609     13 Nov  7  2024 mbed -> /d/mbed_debug

I have a symbolic link to it. Then when you restart Arduino IDE you will see them
under boards:

To use your built version you need to select board here, and do the command
tools->burn bootloader
And then you can build with all of the new stuff that you may have added or changed.

Arduino
When Arduino decides to generate a release, they run some additional scripts
which split up the above build of board into 3 parts:
image


You install each of these separately within the boards manager.

And as I have mentioned before when you switch between the bootloaders you build
your self and the released versions you may or may not have to burn the bootloader
(Make sure to select the board from the right group first)

Hope that helps and again sorry for being probably overly verbose.

Nice one Kurt, thanks for all the info here and in the other thread you answered. Had a few Bourbons here so will look at this and the other answer closely in the morning when my brain has some chance of understanding it.

Once again thanks for taking the time to give me this detailed info.

Hi Kurt,

That is some very useful info there, exactly what I have been looking for on the internet with no joy. This page is bookmarked now :slight_smile:

One question: The uart:~$ stuff running on the mcu UART, is that the ArduinoCore-zephyr?

I think I am going to start at the bottom and set up a Zephyr build environment here and start experimenting at that level.

I will have a look at your PRs to see what you have been up to…

My first task is to “just” get the UART based messages stuff working from C++ on the linux board and the SPI coms between the processors working, also from C++ on the linux side.

p.s. The build with “static” can be debugged :slight_smile:

Trying to work out now how to integrate it all with the V2 Ide so it’s easy for people to use…

So, I have Zephyr all installed.

I can build, I can sort of flash by using west debug -r openocd, west flash does not seem quite ready yet.

I can also debug from Visual studio, it’s all very heath Robinson though.

I am trying to work out the “commands” that west debug -r openocdis actually running, then I can get the flashing done via Visual Studio, and I will be a happy boy.

I have looked in the boards folder to see if there are any hints there but can’t find anything.

The runner is zephyr/scripts/west_commands/runners/openocd.py at main · zephyrproject-rtos/zephyr · GitHub and I’m guessing that I need to work out where this is getting its config variables from for the Uno Q?

Specifically the load command:

 def do_flash(self, **kwargs):
        self.ensure_output('hex')
        if self.load_cmd is None:
            raise ValueError('Cannot flash; load command is missing')
        if self.verify_cmd is None:
            raise ValueError('Cannot flash; verify command is missing')

Have you by any chance ever looked at this?

Sorry, as I mentioned, so far I have not done any direct programming of the Q
using the straight zephyr. I have done the: GIGA, Portenta H7, Portenta C33, Nicla Sense

For this probably could use some input from the Arduino people!

@ptillisch @facchinm or others, do you know if anyone has done anything recently to allow you to do something directly on zephyr, like: west flash
that works with the Q?

Ah sorry, I must have misread what you are saying (looking back that’s exactly what I did!)

The whole Zephyr infrastructure seems quite complex, it seems to have installed quite a lot of stuff to say the least! The code side looks quite simple though, sort of the other way round in my mind :)

west flash seems to make use of the local openocd on the host machine west debug though can use the remote openocd on the SOC via a forwarded port via adb via gdb , I guess no-one has got round to sorting it out yet.

I might just sniff the network traffic on the 3333 port running on the SOC to see what it is doing…

west flash - Is configurable, I have not gone through to figure where that is done, but for example, I know for the Teensy boards (PJRC) like teensy41 the flash, this command
uses the teensy_loader_cli command to do the flashing.

Thanks, I’ll carry on trying to work it out in my normal bumbling way :slight_smile:

So this will flash from the host :

/home/BobTheDog/zephyr-sdk-0.17.4/arm-zephyr-eabi/bin/arm-zephyr-eabi-gdb-py -ex 'target extended-remote :3333' /home/BobTheDog/zephyrproject/zephyr/build/zephyr/zephyr.elf -ex load -ex="set confirm off" -ex exit

You also need to have port forwarding setup:

adb forward tcp:3333 tcp:3333 && adb shell arduino-debug

They may be a better way but this works!

I got it all going using VSCode on linux: Using Visual Code with Zephyr (linux) some useful info

Thanks for reporting the /bin/true issue! :hugs: The fix will be included in the next core release.

Hi @lburelli

There is another issue I had on the Mac, the adb executable is not added to the firewall when everything is installed so the network connection does not work from App Lab.