Add -t none or -t binary

I’d like to build the .bin, but without uploading it anywhere.

at the moment using platformio run, without target (at least on ESP) stops at the .elf, and doesn’t generate the binary.

is it posible to build the binary as well, or have a target binary to build the image…

or is there another way, I’m missing?

cheers

ok, ignore that.

run does generate it… i missed the -o flag in esptool. sorry

Hey,

Just trying to do the same thing.
Are you doing this from the CLI? or the IDE?

Mind sharing some more info?

Cheers!

Guys, what do you mean? PlatformIO generates .elf and .bin by default. They are located in the .pioenvs/%ENV%/firmware.*.

See wiring example:

tree -La 3 examples/wiring-blink
├── .clang_complete
├── .gcc-flags.json
├── .gitignore
├── .pioenvs
│   ├── .sconsign.dblite
│   ├── nodemcu
│   │   ├── FrameworkArduino
│   │   ├── FrameworkArduinoVariant
│   │   ├── firmware.bin
│   │   ├── firmware.elf
│   │   ├── generic
│   │   ├── libFrameworkArduino.a
│   │   ├── libFrameworkArduinoVariant.a
│   │   └── src
│   └── structure.hash
├── .travis.yml
├── README.rst
├── lib
│   └── readme.txt
├── platformio.ini
└── src
    └── main.cpp

8 directories, 14 files

I know this is an old post but I can’t find firmware.bin anywhere. The project(s) I am working on are a variant of Teensy 3.1 (custom design using the NXP Kinetis MK20DX128… called teensy3x). My .pioenvs folder(s) don’t have a nodemcu folder and only have firmware.elf and firmware.hex in the .pioenvs folder.

What I have is all I typically need but I am looking at how to use utasker as a bootloader and I need binary files for that. I am using a JLINK as HEX file uploader and debugger and that is working OK.

The previous post by Ivan states the firmware.bin file is created by default but it looks like for Teensy this isn’t the case. What do I need to change to get the binary file?

My platformio.ini, extra_script.py, teensy3x.json, and mk20dx128V.ld files follow:

platformio.ini:

[env:jlink_debug_and_upload]
platform = teensy
framework = arduino
board = teensy3x
board_build.f_cpu = 96000000L
monitor_speed = 115200
extra_scripts = extra_script.py
debug_tool = custom
debug_init_break =  
debug_server =
  C:\JLINK\JLinkGDBServerCL.exe
  -singlerun
  -if  ;was ifls?  
  SWD
  -select
  USB
  -port
  2331
  -device
  MK20DX128xxx7

extra_script.py:

from os import makedirs
from os.path import isdir, join
Import('env')

# Optional block, only for Teensy
env.AddPostAction(
    "$BUILD_DIR/firmware.hex",
    env.VerboseAction(" ".join([
        "sed", "-i.bak",
        "s/:10040000FFFFFFFFFFFFFFFFFFFFFFFFDEF9FFFF23/:10040000FFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFD/",
        "$BUILD_DIR/firmware.hex"
    ]), "Fixing $BUILD_DIR/firmware.hex secure flash flags"))


def _jlink_cmd_script(env, source):
    build_dir = env.subst("$BUILD_DIR")
    if not isdir(build_dir):
        makedirs(build_dir)
    script_path = join(build_dir, "upload.jlink")
    commands = ["h", "loadbin %s,0x0" % source, "r", "q"]
    with open(script_path, "w") as fp:
        fp.write("\n".join(commands))
    return script_path

env.Replace(
    __jlink_cmd_script=_jlink_cmd_script,
    UPLOADER="C:\JLINK\JLINK.exe",
    UPLOADERFLAGS=[
        "-device", "MK20DX128xxx7",
        "-speed", "4000",
        "-if", "swd",
        "-autoconnect", "1"
    ],
    UPLOADCMD='"$UPLOADER" $UPLOADERFLAGS -CommanderScript ${__jlink_cmd_script(__env__, SOURCE)}'
    )

teensy3x.json:

{
  "build": {
    "core": "teensy3", 
    "cpu": "cortex-m4", 
    "extra_flags": "-D__MK20DX256__ -DTEENSY31", 
    "f_cpu": "96000000L", 
    "ldscript": "mk20dx128V.ld", 
    "mcu": "mk20dx128"
  }, 
  "debug": {
    "jlink_device": "MK20DX128xxx7"
  },
  "frameworks": [
    "arduino" 
  ], 
  "name": "teensy3x", 
  "upload": {
    "maximum_ram_size": 16384, 
    "maximum_size": 131072,
  "protocols": [
    "jlink"
    ],
   "protocol": "jlink"
  }, 
  "url": "https://www.pjrc.com/store/teensy31.html", 
  "vendor": "Teensy"
}

mk20dx128V.ld:

MEMORY
{
    FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 128K
    RAM  (rwx) : ORIGIN = 0x1FFFC000, LENGTH = 32K
}


SECTIONS
{
	.text : {
		. = 0;
		KEEP(*(.vectors))
		*(.startup*)
		/* TODO: does linker detect startup overflow onto flashconfig? */
		. = 0x400;
		KEEP(*(.flashconfig*))
		*(.text*)
		*(.rodata*)
		. = ALIGN(4);
		KEEP(*(.init))
		. = ALIGN(4);
		__preinit_array_start = .;
		KEEP (*(.preinit_array))
		__preinit_array_end = .;
		__init_array_start = .;
		KEEP (*(SORT(.init_array.*)))
		KEEP (*(.init_array))
		__init_array_end = .;
	} > FLASH = 0xFF

	.ARM.exidx : {
		__exidx_start = .;
		*(.ARM.exidx* .gnu.linkonce.armexidx.*)
		__exidx_end = .;
	} > FLASH
	_etext = .;

The files generated will be board / environment specific. Since you’re not compiling for a nodemcu/esp8266 target, you won’t have that folder. What is in your .pioenvs/jlink_debug_and_upload folder, since whatever files are generated are located in:

When I tried against teensy30, what was compiled was a .hex and .elf.

image

That is consistent to what I am seeing, i.e. no firmware.bin file. Here is what my .pioenvs has:

snap0957

and upload.jlink has this:
snap0958

I could create a firmware.bin file if I knew where the script is that results from pio run. Specifically, unless there is a better way, I could add another call to arm-none-eabi-objcopy bit to create a binary file from firmware.elf

However, if the binary file is created and then deleted, where can I stop its deletion?

I’m reading thru the custom scripts section but the answer isn’t readily obvious.

Any advice?

Looking at platform-teensy/main.py at develop · platformio/platform-teensy · GitHub and platform-teensy/main.py at develop · platformio/platform-teensy · GitHub can you maybe add a call to to the ElfToBin like env.ElfToBin(join("$BUILD_DIR", "${PROGNAME}"), target_elf)? (you have this Script in C:\Users\<user>\.platformio\platforms\teensy\builder)

Or actually a PostBuild action like you did with the firmware.hex file to replace secure flash flags should also work there?

I actually have been trying to add a Post Build actin and can’t get it work. I also just came across the ElfToBin function and was about to try that. Thanks for the location of Main.py as I was having trouble finding it.

OK… so I am finding there are many Main.py files associated with PIO. In the folder C:\Users&lt;user>.platformio\platforms\teensy\builder there is one but also another .platform folder so a Main.py in C:\Users&lt;user>.platformio.platformio\platforms\teensy\builder. I added a print statement and a call to ElftoBin in both of those and it didn’t have an effect.

Any clues as to where the real Main.py would be located?

The content of the folder C:\Users\<user>\.platformio\platforms\teensy is exactly the clone of the repository GitHub - platformio/platform-teensy: Teensy: development platform for PlatformIO so I’m not sure which main.py you mean?

That is exactly the question since I have main.py in both two folders under <users…>/.platformio like this:

I don’t know why I have two folders like that but I’ll fix it later. I determined that the main.py that is executing is the one in the highlighted builder folder. However, I have tried many things and cannot get a binary file. Here is what I have (among others) and it doesn’t work.

#
# Target: Build executable and linkable firmware
#

target_elf = None
if "nobuild" in COMMAND_LINE_TARGETS:
    target_firm = join("$BUILD_DIR", "${PROGNAME}.hex")
else:
    target_elf = env.BuildProgram()
    target_firm = env.ElfToHex(join("$BUILD_DIR", "${PROGNAME}"), target_elf)
#added by Al *************************
    target_firm_bin = join("$BUILD_DIR", "${PROGNAME}.bin")
    print "****** Creating binary file... (maybe!!!)***********"
    target_firm_bin = env.ElfToBin(join("$BUILD_DIR", "${PROGNAME}"), target_elf)
    print "************* binary file should be created ***************"
#*****************************

Well I just found the easy fix: replace

target_firm = env.ElfToHex(join("$BUILD_DIR", "${PROGNAME}"), target_elf)

with

target_firm = env.ElfToBin(join("$BUILD_DIR", "${PROGNAME}"), target_elf)

Then pio run -t clean && pio run and you now have the firmware.bin.

C:\Users\Maxi\Desktop\teensy_test>file .pioenvs\teensy31\firmware*
.pioenvs\teensy31\firmware.bin; data
.pioenvs\teensy31\firmware.elf; ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, not stripped

I’ll check if I can construct a post-build script for a more general solution.

1 Like

Well that was easy. Just copy the VerboseAction that the ElfToBin function would execute.

platformio.ini

[env:teensy31]
platform = teensy
board = teensy31
framework = arduino
extra_scripts = extra_script.py

extra_script.py

from os.path import join
Import("env", "projenv")

# Custom BIN from ELF
env.AddPostAction(
	"$BUILD_DIR/${PROGNAME}.elf",
	env.VerboseAction(" ".join([
				"$OBJCOPY",
				"-O",
				"binary",
				"$TARGET",
				"$BUILD_DIR/${PROGNAME}.bin"
			]), "Building $TARGET"))
C:\Users\Maxi\Desktop\teensy_test>pio run
[...]
====================================================================== [SUCCESS] Took 3.96 seconds ======================================================================

C:\Users\Maxi\Desktop\teensy_test>file .pioenvs\teensy31\*
.pioenvs\teensy31\firmware.bin;          data
.pioenvs\teensy31\firmware.elf;          ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, not stripped
.pioenvs\teensy31\firmware.hex;          ASCII text, with CRLF line terminators
.pioenvs\teensy31\FrameworkArduino;      directory
.pioenvs\teensy31\libFrameworkArduino.a; current ar archive
.pioenvs\teensy31\src;                   directory

EDIT: Changed $SOURCES to the ELF file, otherwise this only translates the main.cpp.o file binary…

4 Likes

That’s great! Thanks for helping with this.

What you have is sort of what I did except I tried to get both files but mine didn’t work? I tried that again after a Clean but it still failed to produce the bin file. I then tried what you did and it worked. However, I still need the hex file.

I also tried added this to my extra_script.py and it doesn’t seem to run

env.AddPostAction(
    "$BUILD_DIR/$firmware.elf",
    env.VerboseAction(" ".join([
        "$OBJCOPY", "-O", "binary", "-R", ".eeprom",
        "$BUILD_DIR/firmware.elf", "$BUILD_DIR/firmware.bin"
    ]), "Where is the binary file???"))
#        ]), "Building $BUILD_DIR/firmware.bin"))

The creation of the hex file is untouched since it’s just adding another Post action to the firmware.elf build step. Maybe you didn’t revert the modification in the main.py?

Our posts/replies have gotten out of time sync. What I had shown earlier for a PostAction was very close but wouldn’t run. The PostAction you posted works great. One thing to suggest is to change the last line to “Building ${PROGNAME}.bin” else it prints out Building firmware.elf" Many thanks!

PS I just did a similar thing and created an S-record file!

PSS Now what I need to do is to rebuild the uTasker bootloader for my configuration (custom K20 board) but
using PIO (and not Codewarrior or GCC toolchain directly!)

Thanks again for your help with this.

2 Likes