Bare metal on arduino due / atmelsam

What is the way to develop bare metal (= no non-project code, except for the device header files) for the arduino due (atmelsam)? For an uno I use

platform = atmelavr
board_build.mcu = atmega328p
board_build.f_cpu = 16000000L

And that gives me access to the header files (and auto-includes the linker script and stratup code). For a due

platform = atmelsam
board = due

doesn’t give me access to the sam3.h header. I tried

framework = framework-cmsys

but that complains about not being compatible with the due board. Using

framework = arduino

does provide access to the header file I need, but it also add the full arduino library. Can I maybe force the (arduino) framework files not to be compiled and linked into my project?

1 Like

Available framework values are always documented for each board. See Here, it’s either arduino, simba, zephyr or implicltly no framework = ... line, which will prevent any framework being compiled in, giving you a baremetal project. Baremetal in the sense that the only headers you have access to come from the compiler toolchain or the ones in your own project.

(On a minor note, I think you refer to cmsis here, not cmsys.)

For Arduino Uno / AVR baremetal that works out nicely because the device header is part of the toolchain, avr-gcc. This is not the case with the toolchain used for the Due, which is a standard gcc-arm-none-eabi. It does not have the ARM CMSIS headers for that Atmel chip – and also isn’t supposed to have it. The AVR toolchain is a rather special case here, they have the files for convience and the rather limited amount of known devices. The gcc-arm-none-eabi toolchain hower doesn’t have device headers of every known ARM device under the sun, in fact, it has none.

In any case, when you compile an Arduino project for the due and look at the start of compilation, it shows the used packages

HARDWARE: AT91SAM3X8E 84MHz, 96KB RAM, 512KB Flash
DEBUG: Current (atmel-ice) External (atmel-ice, blackmagic, jlink, stlink)
 - framework-arduino-sam 1.6.12 
 - framework-cmsis 1.40500.0 (4.5.0) 
 - framework-cmsis-atmel 1.2.2 
 - toolchain-gccarmnoneeabi 1.70201.0 (7.2.1)

Whereas in the framework-cmsis-atmel package there is

$ ls ~/.platformio/packages/framework-cmsis-atmel/CMSIS/Device/ATMEL/
sam3.h  sam4c   sam4n   samc.h  samd21  same51  samg54  sam.h                    saml21b  samr.h
sam3u   sam4e   sam4s   samd10  samd51  same70  samg55  sam-headers-version.txt  saml.h   sams70
sam3xa  sam4.h  samc21  samd11  samd.h  same.h  samg.h  saml21a1                 samr21   sams.h

all these device headers, e.g. for the Due’s AT91SAM3X8E, there’s sam3xa/include/sam3x8e.h.

In framework-cmsis there is

$ ls ~/.platformio/packages/framework-cmsis/CMSIS/Core/Include/
cachel1_armv7.h       cmsis_compiler.h  core_armv81mml.h  core_cm0plus.h  core_cm35p.h  core_cm7.h    mpu_armv8.h
cmsis_armcc.h         cmsis_gcc.h       core_armv8mbl.h   core_cm1.h      core_cm3.h    core_sc000.h  pmu_armv8.h
cmsis_armclang.h      cmsis_iccarm.h    core_armv8mml.h   core_cm23.h     core_cm4.h    core_sc300.h  tz_context.h
cmsis_armclang_ltm.h  cmsis_version.h   core_cm0.h        core_cm33.h     core_cm55.h   mpu_armv7.h

more of the general CMSIS stuff, like the general core_cm3.h header etc.

To include these headers and build certain files (like, the startup file and startup_sam3xa.c), one can use a little bit of Advanced scripting. For other platforms (such as ST-STM32), PlatformIO directly offers framework = cmsis for this, but not for the Atmel-SAM platform, so I had to roll my own here.

I’ve setup a basic compiling project at GitHub - maxgerhardt/pio-baremetal-atmel-cmsis.

Read the caveats regarding the bootloader carefully. Since I have no Arduino Due board to test, I can’t verify the functionality. Comments and testing is appreciated.

Thanks, that gives me something to chew on.

A bit weird that a bord limits the frameworks in can be used with…

PS your project gives me

C:\Users\Wouter\.platformio\packages\framework-cmsis-atmel\CMSIS\Device\ATMEL\sam3xa\include/sam3x8e.h:254:10: fatal error: core_cm3.h: No such file or directory

With the trick of mentioning the frameworks as platform packes

platform_packages =

My won project gives a similar error:

src\Blink.cpp:7:10: fatal error: sam3.h: No such file or directory

Aparently the headers within CMSYS are not automatically found.

Including sam3.h compiles just fine.

If you get a compile error there, check that the verbose compile output (project task “Advanced → Verbose Build”) shows the -I flag leading to the framework-cmsis-atmel/CMSIS/Device/ATMEL main folder, and make sure that in that folder there actually is sam3.h.

I see you’ve gone a bit off-road from the original example that uses a .c file – using C++ code requires linking in stdc++. I’ve added that flag in the repo now.

I go more off-road than that: I use C++, but only what I want, so no libstdc++.

I think that problem was caused by first having installed cmsis and cmsis-atmel als frameworks, and only then as plaltform_dependencies. Clearing the platforms and packages directories solved it (when using your python). Now try to found out whether it can be done without the python.

There will never not be Python available in a PlatformIO project – PlatformIO is written in Python and it’s the intended way for custom extensions / build processes, so, Python shouldn’t be a problem.

If someone wanted to do without it, there is this thing

aka, modifying injecting these special linker flags, that is to the best of my knowledge is not possible within just the platformio.ini, I’ve tried. (with e.g. --specs=nosys.specs or -Wl,--specs=nosys.specs in the build_flags). However, it also compiles without it. Without nanolibc I’ve seen it that accessing standard-C functions that use the stack fail, so I do not recommend using that.

All else is no problem. The relevant package folders can simply be copied into the include/ folder (not as lib/ or src/ because we don’t want every .c file from in there being builtt), include paths can be added with -I build flags in the platformio.ini, the C source files to be built can be put in the src/ folder of the project, and the relevant linker script files can also be pulled out and referenced in the platformio.ini

See here for a version with Newlibc via python but everything else without python.

I’ve implemented the non-recommended way in GitHub - maxgerhardt/pio-baremetal-atmel-cmsis at zero_python for reference.

Btw, there’s an open issue CMSIS build · Issue #80 · platformio/platform-atmelsam · GitHub for native framework = cmsis support.

Not a problem, but it increases the number of files a user has to deal with. Is there a way to reference a Python script that is inside a lib_deps?

Ideally the user would have to deal with 0 Python scripts if PlatformIO implemented framework = cmsis for Atmel-SAM, but per linked issue they haven’t, so 2 lines of Python is the closest I can get them for now.

You can create a library and within the library.json reference an extraScript – that way the Python script can be a bit hidden and users just have to add the library itself to the project. An example of that can e.g. be seen in

By referencing the library in lib_deps, the Python script mentioned in its library.json will be automatically executed, no need further add the script reference in the platformio.ini.

On a technical note, if the CMSIS-Atmel libraries is to be modelled as a library, the library needs to specificy "libArchive": false – a library implementing interrupt service handler needs to be linked directly as object files and not be turned into a .a archive as an intermediate “zipping” stage, this breaks linker. Or rather, doesn’t let the linker find the right functions and the ISRs will be left unimplemented. The same setting must e.g. be used for the FreeRTOS library which implements SysTick and the SVC_Handler.

Thanks for all the - very relevant - info (somehow this is not easy to fin and understand from the platformio website).

I’ll be off for a week now, after that I’ll try to integrate the python into the library (or maybe it should be a framework) for which I am doing this. And then a few more targets to cover:) And another library/framework.