After some very crude hacking I got it to compile + link successfully.
Since I don’t have ARMCC (v5 I guess?) I can’t do much here.
After some very crude hacking I got it to compile + link successfully.
Since I don’t have ARMCC (v5 I guess?) I can’t do much here.
Nice. This helped me realize that using -M
option prevents creation of output files, apparently. Now, with -M
removed, output files get generated under the .pio
workspace folder and .elf
file is finally generated as well.
Another difference between your project and mine is that I have a custom linker .ld
file. But for some reason PIO is trying to access the built-in linker file it has for this specific STM target. I get the following error:
Fatal error: L6002U: Could not open file C:\Users\gacnik\.platformio\platforms\ststm32\ldscripts: Permission denied
Again, not sure why it is trying to open default linker file (and also what prevents it from opening, since multiple .ld
files are located in that folder) when I have defined the path to my own linker file (from CubeMX) inside platform.ini
file like so:
board_build.ldscript = "src\STM32F103VCTx_FLASH.ld"
Any more ideas?
EDIT: Actually, .elf
file doesn’t get generated. Last step before error occurs is linking. And of course if linker file cannot be accessed for some reason, .elf
can’t be created.
I’ve had this error when there were -LC:\Users\gacnik\.platformio\platforms\ststm32\ldscript
flags present, I had to clear that out using
Okay, this has resolved my last issue I had (in addition to OBJCOPY additional options to generate .bin
file). I have yet to try this on HW and see if additionals modifications are needed.
Otherwise I would just like to know what is the purpose of the following? For sake of completeness.
SIZEPROGREGEXP=r"^(?:ER_IROM1)\s+(\d+).*",
SIZEDATAREGEXP=r"^(?:RW_IRAM1)\s+(\d+).*",
I built my project without this and it builds okay. I would say these are some linker file specific since I see ROM and RAM and RW (read write?).
Additionally, why you omitted putting -o $TARGET
in your project’s script? Didn’t you say it’s bad if you leave it out? On the other hand, if you check env
object’s contents you will see that -o
is included during build by default. So, IMO, adding this from script would only add redundant -o
options (or overwritten existing ones).
P.S.: Can you just delete the comments with absolute path and name of my projects from your github project? Thanks
That’s so that the “Flash X% […] X Bytes” display is correct. PlatformIO will use arm-none-size-eabi -A -d <firmware.elf
> to print all sections (and their sizes) of the .elf
file. The armlink
in conjuction with the used scatter file basically creates these two main sections, one for flash (“ROM”) and one for data (RAM). Without that, PlatformIO would report the flash and RAM usage as both 0 bytes since it’s default-setup for section names generated by the GNU compiler and the linker scripts.
I looked in the verbose output and saw PlatformIO / SCons added it automatically in the invocation.
Done.
I see that size information doesn’t work for me and displays 0 bytes for each RAM and FLASH. I used your modification of SIZEPROGREGEXP
and SIZEDATAREGEXP
. I also see the there is no size tool under the MDK-ARM (ARMCC). Should it still be able to generate this information if there is no size tool?
This is what I get in the verbose output:
'SIZECHECKCMD': '$SIZETOOL -A -d $SOURCES',
'SIZEDATAREGEXP': '^(?:RW_IRAM1)\\s+(\\d+).*',
'SIZEPRINTCMD': '$SIZETOOL -B -d $SOURCES',
'SIZEPROGREGEXP': '^(?:ER_IROM1)\\s+(\\d+).*',
'SIZETOOL': 'arm-none-eabi-size',
This is trivial. But what I’m more worried about is when I’m trying to load .elf
on target device, I get this:
** Programming Started **
Warn : no flash bank found for address 0x00008000
** Programming Finished **
** Verify Started **
Error: checksum mismatch - attempting binary compare
embedded:startup.tcl:1070: Error: ** Verify Failed **
in procedure 'program'
in procedure 'program_error' called at file "embedded:startup.tcl", line 1131
at file "embedded:startup.tcl", line 1070
*** [upload] Error 1
This are address bases that are defined in my linker .ld
script. Looks like FLASH base from the error log is not the same as what linker file says. Maybe I can tweak these upload-related settings in PIO as well?
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 256K
}
It seems my linker file isn’t used. I may have found the problem but no solution. This is ARMCC specific and not PIO. If one uses linker file .ld
(which is normally used in combination with GCC linker) additional options like “–sysv” and “–ld_script=linker_script.ld” need to be used (or “–scatter=scatter_file.sct” which is a default ARM memory layout file). However the problem is that none of mentioned options is recognized by the ARMLINK although these options are in fact valid for this version of ARMLINK. This also happens for other kind of options. Only the most commonly used ones like “-g”, “-c”, “–c99”, “-cpu=Cortex-M3”, etc. are recognized. For most others I get this kind of error:
Fatal error: C3900U: Unrecognized option '--split_section'.
Maybe I should ask this elsewhere as this discussion is reaching out of the scope of initial problem I had to solve.
@maxgerhardt How can I provide linker options so that when ARMLINK is run something like this will be executed?
--scatter file1.o file2.o file3.o ... -o .pio\build\genericSTM32F103VC\proj_name.axf
It seems just providing --scatter
option would result in error since no input (the .o
files) is provided as its argument.
The object files and -o <firmware.elf>
are added automatically, you should not try to add them yourself. I added the --scatter
option via linkflags.
Are you sure armlink
is invoked? Unless I overrode env["LINKER"] = "armlink"
, it would still try to invoke the $CXX
.
What’s the current full linker invocation? (pio run -v -j1
)
The problem is that if I used the --scatter
option in existing script under LINKFLAGS
I got error Unrecognized option
even though this is a valid option. Then I tried this manually from PIO CLI and --scatter
was successfully recognized and produced .axf
output. Which I then used to generate .elf
and was able to successfully load firmware onto my board!
Maybe I am getting Unrecognized option
when I use --scatter
inside LINKFLAGS
without this option being followed with arguments (the output .o
files).
I added the
--scatter
option via linkflags.
If I add this option directly to LINKFLAGS
without providing any additionall argument I get the following error:
".pio\build\genericSTM32F103VC\src\Core\Src\fooFoo.o", line 1 (column 8): Error: L6226E: Missing base address for region \177ELF\001\001\001.
".pio\build\genericSTM32F103VC\src\Core\Src\fooFoo.o", line 1 (column 8): Error: L6228E: Expected '{', found ''.
Error: L6372E: Image needs at least one load region.
This is because --scatter
remains under LINKFLAGS
without any argument. Whereas a .sct
file should first be provided, then all the output files as the following arguments. This is how it looked like when I provided a valid output from PIO CLI (just so you know what I have in mind):
C:\Keil_v5\ARM\ARMCC\bin\armlink --scatter PCV2-SES.sct
.pio\build\genericSTM32F103VC\src\Core\Src\main.o
.pio\build\genericSTM32F103VC\src\Core\Src\fooFoo.o
.pio\build\genericSTM32F103VC\src\Core\Src\stm32f1xx_hal_msp.o
.pio\build\genericSTM32F103VC\src\Core\Src\stm32f1xx_it.o
.pio\build\genericSTM32F103VC\src\Core\Src\system_stm32f1xx.o
.pio\build\genericSTM32F103VC\src\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_adc_ex.o
.pio\build\genericSTM32F103VC\src\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_adc.o
.pio\build\genericSTM32F103VC\src\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_can.o
.pio\build\genericSTM32F103VC\src\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_cortex.o
.pio\build\genericSTM32F103VC\src\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_dac_ex.o
.pio\build\genericSTM32F103VC\src\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_dac.o
.pio\build\genericSTM32F103VC\src\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_dma.o
.pio\build\genericSTM32F103VC\src\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_exti.o
.pio\build\genericSTM32F103VC\src\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_flash_ex.o
.pio\build\genericSTM32F103VC\src\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_flash.o
.pio\build\genericSTM32F103VC\src\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_gpio_ex.o
.pio\build\genericSTM32F103VC\src\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_gpio.o
.pio\build\genericSTM32F103VC\src\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_i2c.o
.pio\build\genericSTM32F103VC\src\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_pwr.o
.pio\build\genericSTM32F103VC\src\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_rcc_ex.o
.pio\build\genericSTM32F103VC\src\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_rcc.o
.pio\build\genericSTM32F103VC\src\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_tim_ex.o
.pio\build\genericSTM32F103VC\src\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_tim.o
.pio\build\genericSTM32F103VC\src\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal_uart.o
.pio\build\genericSTM32F103VC\src\Drivers\STM32F1xx_HAL_Driver\Src\stm32f1xx_hal.o
.pio\build\genericSTM32F103VC\src\startup_stm32f103xe.o
-o .pio\build\genericSTM32F103VC\firmware.axf
This generated .axf
file from where I re-generated a valid .elf
file (valid because it was generated based on valid memory layout) using the following set of options:
C:\Keil_v5\ARM\ARMCC\bin\fromelf --elf --output .pio\build\genericSTM32F103VC\firmware.elf .pio\build\genericSTM32F103VC\firmware.axf
And this is all I’m trying to automate using that python script. To recap: create .axf
file from .sct
file using --scatter
and all the .o
files in the project. Then use fromelf
to create .elf
from .axf
.
This is because
--scatter
remains underLINKFLAGS
without any argument. Whereas a.sct
file should first be provided, then all the output files as the following arguments
My bad, I misremembered – actually by setting my scatter file as the board_build.ldscript = ..
option in the platformio.ini
and with PlatformIO / SCons automatically generating a -T <linker script>
argument, I just go in and transform the -T
flag to --scatter
. The argument after it remains unchanged and correct.
- old_flags = e["LINKFLAGS"].copy()
- # replace "-T" with "--scatter" for linker scirpt
- try:
- i = old_flags.index("-T")
- #print("INDEX: " + str(i))
- old_flags[i] = "--scatter"
- e.Replace(LINKFLAGS=old_flags)
- except:
- pass
-
--scatter
is not added to LINKFLAGS.
Ahh okay. But otherwise, intially I already had .sct
path defined with board_build.ldscript
.
Otherwise that replacement code where -T
are replaced with --scatter
, doesn’t this assume that you first built a project using GCC and then ARMCC? Or is the -T
option put into LINKFLAGS
by default when PIO is installed?
Otherwise, with this setup where -T
are replaced with --scatter
and proper .sct
file is provided, this is now successfully uploaded to target. I was initially filtering out -T
options and therefore this replacement didn’t work out as expected.
Or is the
-T
option put intoLINKFLAGS
by default when PIO is installed?
PIO appends this option if the LDSCRIPT_PATH is set (which it is with board_build.ldscript
, for example)
- # append into the beginning a main LD script
- if env.get("LDSCRIPT_PATH") and not any("-Wl,-T" in f for f in env["LINKFLAGS"]):
- env.Prepend(LINKFLAGS=["-T", env.subst("$LDSCRIPT_PATH")])
I would only like to know how to provide additional options to linker flags so that I would be able to generate additional files (like .map
, .lst
, .axf
) in the same folder that .elf
and .bin
are located? What I mean is how to let the PIO script (main.py probably) insert the current project name, .pio folder, etc. so that these files are always located under the same folder.
As far as I understand, .axf
= .elf
. Map should be generatable by prepending to LINKFLAGS with the appropriate “–map”, “$BUILD_DIR/$PROGNAME.map” argument
https://developer.arm.com/documentation/dui0474/m/linker-command-line-options/--map----no-map
- '-Wl,-Map="%s"' % join("${BUILD_DIR}", "${PROGNAME}.map")
And .lst
, not sure where the disassembler is, but you could add a post action to the $PROGNAME.elf file to call upon `arm-none-eabi-objdump -d firwmare.elf > disassembly.lst".
https://docs.platformio.org/en/latest/scripting/actions.html
Map should be generatable by prepending to LINKFLAGS with the appropriate “–map”, “$BUILD_DIR/$PROGNAME.map” argument
I tried but I get the following error:
*** [.pio\build\genericSTM32F103VC\firmware.elf] AttributeError `'str' object has no attribute 'map'' trying to evaluate `$PROGNAME.map'
Mh the env vars need to be wrapped in ${}
then like in the platformio-build-esp32.py seen above.
This is the exact string it generates but I get error that --map
doesn’t expects such argument. Shouldn’t actual path be created before storing this string to LINKFLAGS
?
'--map="${BUILD_DIR}\\${PROGNAME}.map"'