Driven by the idea of building a Bluetooth keyboard like device, I've bought the SparkFun Artemis Thing Plus board. It's a board designed for small, power efficient devices with Bluetooth capability.
The board carries an Ambiq Apollo3 processor. It's an ARM Cortex-M4F chip. Runs at 48MHz but can, for a brief amount of time, go up to 96MHz. Here you can read more about the whole Apollo line-up.
The SparkFun‘s board brings some cool features. It has a 1S battery charger, USB-C port (routed to the one of the UART ports which means it can be easily programmed and debugged), microphone, JTAG connector, RTC clock. It can also be programmed via the Arduino environment. SparkFun seems to be very proud to say it's…
World's first open source hardware module using a Cortex-M4F capable of running TensorFlow models and Arduino sketches.
The repository for the hardware can be found here.
Even though being able to use the Arduino environment is nice, I'm not interested in going that direction. For what I need to do I'll need to use the vendor's SDK, and that's what I want to document with this, and upcoming, posts.
SparkFun is hosting a guide on how to setup the development environment here. Unfortunately it's a bit lacking. That's why I've decided to write down my own experience.
Some things worth noting about the Artemis module:
The Artemis module is loaded with two bootloaders: the ASB and SVL. The Ambiq Secure Boot Loader (ASB) resides from 0x00 to 0xC000. This bootloader is physically part of the IC and is configured using the info0 registers. At power up, if the ASB is not activated, it jumps to 0xC000.
The processor goes through the typical boot process, which we will explore a bit later, and starts
executing code from address
0x00. In this case it's the ASB bootloader.
The SparkFun Variable Bootloader (SVL) resides at 0xC000 and will wait for an incoming serial character. If a character is received, the baud rate will be auto-detected, the SVL will load new code, then jump to the new user code starting at 0x10000. The SVL times out after 50ms.
The second bootloader, flashed by SparkFun, is there so you can program the processor with the Arduino environment. Bootloaders are only about communication between your computer and the board itself, meaning a code which is not using the Arduino framework can also be uploaded using this bootloader. If you are using the SDK and need more memory you can overwrite the SparkFun‘s bootloader. You can read more about the bootloaders here.
SparkFun‘s guide suggests to download the Ambiq's SDK and add the SparkFun‘s boards BSPs (Board Support Packages), by cloning this in the root folder of the SDK.
What I would suggest is to clone SparkFun's copy of the Ambiq's SDK since it already references the BSPs repository as a git module. Lets go with some concrete steps:
mkdir your_project echo '# Amazing project that will change the world' > README.md git init git add README.md git commit -m "Initial commit" git submodule add https://github.com/sparkfun/AmbiqSuiteSDK git submodule update --init --recursive
The short list of commands above creates a folder for your project,
README.md file with a
Markdown header. Then a git respository gets initialized and the
README.md file gets commited
as an initial commit. The Ambiq SDK gets added as a submodule. If you look at the
repository you'll see it references the
SparkFun_Apollo3_AmbiqSuite_BSPs repository via the
boards_sfe folder. In order to init submodule in a submodule you have to run the last command in
the list above. After going through those steps the project structure should look as follows:
. ├── AmbiqSuiteSDK << git submodule │ ├── AM-BSD-EULA.txt │ ├── ambiq_ble │ ├── Apollo3_Examples.txt │ ├── boards │ ├── boards_sfe << git submodule │ ├── bootloader │ ├── CMSIS │ ├── devices │ ├── docs │ ├── makedefs │ ├── Makefile │ ├── mcu │ ├── pack │ ├── README.md │ ├── third_party │ ├── tools │ ├── utils │ └── VERSION.txt └── README.md
How I proceed from this point on is by creating a
src folder in the root folder of the project.
Next, I copy several files from the
makefile_template.mk- a template of the Makefile you'll use to build the binaries.
startup_gcc.c- initial instructions the processor has to perform.
makefile_template.mk gets copied but also renamed to
Makefile. While we are at it, the
main.c file from the
AmbiqSuiteSDK/boards_sfe/common/examples/blinky/ also gets copied to the
src folder. That will be our first program that will blink the LED.
. ├── AmbiqSuiteSDK │ ├── AM-BSD-EULA.txt │ ├── ambiq_ble │ ├── Apollo3_Examples.txt │ ├── boards │ ├── boards_sfe │ ├── bootloader │ ├── CMSIS │ ├── devices │ ├── docs │ ├── makedefs │ ├── Makefile │ ├── mcu │ ├── pack │ ├── README.md │ ├── third_party │ ├── tools │ ├── utils │ └── VERSION.txt ├── README.md └── src ├── Makefile ├── startup_gcc.c └── main.c
One small thing before we can go further… We don't have the proper compiler for the platform.
You can go here
and download the latest toolchain. You can unpack it in the home directory (
I'm assuming you are using Linux…). What I would expect your toolchain path to look like would be:
/home/your_username/ │ └── gcc-arm-none-eabi-9-2019-q4-major ├── arm-none-eabi ├── bin ├── lib └── share
Lets get back to our project directory. You can almost compile the blinky code. In order to do that
you have to trigger the
make command with some parameters specified. What I do is I create a few
bash scripts in the project's root directory that trigger the
make command with the necessary
parameters set. So the script for building (
project_root_dir/build.sh) would look like so:
_TC=$HOME/gcc-arm-none-eabi-9-2019-q4-major/bin PATH=$_TC:$PATH _SDK=$PWD/AmbiqSuiteSDK make -C src \ ASB_UPLOAD_BAUD=115200 SVL_UPLOAD_BAUD=115200 PYTHON3=python3 COM_PORT=/dev/ttyUSB0 \ SDKPATH=$_SDK \ COMMONPATH=$_SDK/boards_sfe/common/ \ BOARDPATH=$_SDK/boards_sfe/artemis_thing_plus/ \ PROJECTPATH=..
_TC- variable that holds the path to the toolchain binaries.
PATH- a default variable that gets expanded with the path to the toolchain binaries.
_SDK- variable that holds the path to the SDK.
Most of the passed parameters expand the
_SDK variable. Parameters like
SVL_UPLOAD_BAUD specify the buadrate for the flashing process.
Final look at the project structure before we pull the trigger:
. ├── AmbiqSuiteSDK ├── README.md ├── src │ ├── Makefile │ ├── startup_gcc.c │ └── main.c └── build.sh
And lets do it:
And if everything went as expected… it failed. If you filter out the unnecessary noise the list of errors comes down to:
...undefined reference to 'am_devices_led_off' ...undefined reference to 'am_devices_led_on' ...undefined reference to 'am_util_delay_ms' ...undefined reference to 'am_util_stdio_printf_init'
Means we didn't define those symbols in any of the source files or the libraries. We need to modify
Makefile a bit, so the compiler can generate those symbols and linker can find them:
SRC= SRC+= main.c SRC+= startup_gcc.c SRC+= am_devices_led.c # << the new entry SRC+= am_util_delay.c # << the new entry SRC+= am_util_stdio.c # << the new entry SRC+= # VPATH (Add paths to where your source files are located) VPATH= VPATH+= $(PROJECTPATH)/src VPATH+= $(SDKPATH)/utils VPATH+= $(PROJECTPATH)/tools_sfe/templates VPATH+= $(PROJECTPATH)/devices # << the new entry VPATH+=
We expand the list of the source files with
VPATH is the list of the directories that will be looked up to actually find the source files.
That's why we also need to modify it, so the compliation process can find the
This time running the
build.sh script should succesfully create a
example_asb.bin file in the
Few things before I'm done with this post. I've added
flash.sh scripts. As you can
see the difference between those and
build.sh very small. Those two just pass targets (
_TC=~/Downloads/gcc-arm-none-eabi-9-2019-q4-major/bin PATH=$_TC:$PATH _SDK=~/AmbiqSuite-Rel2.2.0 make -C src clean \ ASB_UPLOAD_BAUD=115200 SVL_UPLOAD_BAUD=115200 PYTHON3=python3 COM_PORT=/dev/ttyUSB0 \ SDKPATH=$_SDK \ COMMONPATH=$_SDK/boards_sfe/common/ \ BOARDPATH=$_SDK/boards_sfe/artemis_thing_plus/ \ PROJECTPATH=..
_TC=~/Downloads/gcc-arm-none-eabi-9-2019-q4-major/bin PATH=$_TC:$PATH _SDK=~/AmbiqSuite-Rel2.2.0 make -C src bootload \ ASB_UPLOAD_BAUD=115200 SVL_UPLOAD_BAUD=115200 PYTHON3=python3 COM_PORT=/dev/ttyUSB0 \ SDKPATH=$_SDK \ COMMONPATH=$_SDK/boards_sfe/common/ \ BOARDPATH=$_SDK/boards_sfe/artemis_thing_plus/ \ PROJECTPATH=..
There is a lot of code duplication between those 3 scripts. If that bothers you, you can wrap those
scripts into one and control the behavior by passing argument. You can call the
directly. Do what feels comfortable for you.
This was a very brief guide on how to setup a basic project. There is a lot more to explore and explain but I do encourage you to poke and probe what's there.