Verified Commit edd35de9 authored by Rahix's avatar Rahix
Browse files

doc: Write lots of docs

Signed-off-by: Rahix's avatarRahix <>
parent 4fc2e7a6
.. _debugger:
If you have one of our debuggers for card10, this page details how you can use
it. The debugger looks like either one in the following pictures:
.. todo::
Debugger Picture
For debugging card10, you need our `own fork`_ of OpenOCD. It contains a patch
which allows flashing both flash-banks instead of just one. Install it using
the following commands:
.. _own fork:
.. code-block:: shell-session
$ git clone
$ cd openocd
$ git submodule update --init
$ ./bootstrap
$ ./configure --disable-werror
$ make -j8
Make sure ``CMSIS-DAP Compliant Debugger`` is set to **yes (auto)** after
running ``./configure`` (if it is not, you might need to install libusb). If
you get errors making the documentation you can ``touch doc/`` to
skip it and continue with ``make``.
Please run ``make install`` after removing any already installed OpenOCD
version. Otherwise please always specify the full path to OpenOCD (the binary
is under ``src/openocd``).
GDB (``arm-none-eabi-gdb``)
Apart from OpenOCD you also need ``arm-none-eabi-gdb``. You should install
that package from your distros repositories:
* Ubuntu: ``gdb-arm-none-eabi``
* Arch: ``arm-none-eabi-gdb``
First of all, you need to connect your debugger and card10. There are three
connections that you need (take a look at the above diagram for more info):
* ``HDK``: This connection provides debugging (SWD) and UART.
* ``DEV``: This connection provides power (battery charger) and the native USB
connection (bootloader).
* ``USB-C``: Connect the proved USB-C cable with the side which has the blue
dot, so the blue dots have the same side.
Run OpenOCD from the ``openocd/scripts`` directory in the firmware repository.
Call it as ``openocd -f interface/cmsis-dap.cfg -f target/max32665.cfg``. If
the debugger and card10 are connected correctly, you should see the following
.. code-block:: shell-session
$ openocd -f interface/cmsis-dap.cfg -f target/max32665.cfg
Info : CMSIS-DAP: SWD Supported
Info : CMSIS-DAP: FW Version = 1.0
Info : CMSIS-DAP: Interface Initialised (SWD)
Info : SWCLK/TCK = 0 SWDIO/TMS = 1 TDI = 0 TDO = 0 nTRST = 0 nRESET = 1
Info : CMSIS-DAP: Interface ready
Info : clock speed 2000 kHz
Info : SWD DPIDR 0x2ba01477
Info : max32xxx.cpu: hardware has 6 breakpoints, 4 watchpoints
Info : Listening on port 3333 for gdb connections
Next, start *gdb* in parallel and connect it to OpenOCD. You can do this easily
if you run gdb from the firmware repository root where we have provided a
``.gdbinit`` file. Apart from automatically connecting to OpenOCD, this script
file also defines a ``reset`` command to soft-reset card10.
.. code-block:: shell-session
$ arm-none-eabi-gdb build/hw-tests/hello-world/hello-world.elf
You are now connected to card10 and ready to start debugging! If card10 is
still running, stop it using
.. code-block:: text
(gdb) mon reset halt
Following that, you can debug as you would normally.
......@@ -5,8 +5,17 @@ Epicardium API
.. warning::
This version of the documentation was built without
`Hawkmoth <>`_ available. This means,
no documentation for the Epicardium API was generated.
This version of the documentation was built without `Hawkmoth`_ working
(most likely python3-clang was not installed). This means, no
documentation for the Epicardium API was generated.
.. _Hawkmoth:
This page details all available *Epicardium API* functions. All these
functions are defined in
.. code-block:: c++
#include "epicardium.h"
.. c:autodoc:: epicardium/epicardium.h
Epicardium Intro
Epicardium is the main component of the firmware. It runs on core0 and is
based on FreeRTOS. Epicardium provides an API to a payload running on the
other core which exposes most functionality.
API Design
.. note::
This is the current design. We might adjust it in the future to allow for
more performance in cases where this approach is too slow.
The API is strictly synchroneous. This means, an API call looks exactly the
same as calling any other function. Internally, the call will wake up
Epicardium and dispatch the call. Once the call has finished, it will return a
API Conventions
The API functions follow the kernel convention of either returning a boolean if
the function is a predicate or returning a success integer (with negative
values denoting errors) if it is an action or imperative command. To quote:
**16) Function return values and names**
Functions can return values of many different kinds, and one of the
most common is a value indicating whether the function succeeded or
failed. Such a value can be represented as an error-code integer
(-Exxx = failure, 0 = success) or a ``succeeded`` boolean (0 = failure,
non-zero = success).
Mixing up these two sorts of representations is a fertile source of
difficult-to-find bugs. If the C language included a strong distinction
between integers and booleans then the compiler would find these mistakes
for us... but it doesn't. To help prevent such bugs, always follow this
.. code-block:: text
If the name of a function is an action or an imperative command,
the function should return an error-code integer. If the name
is a predicate, the function should return a "succeeded" boolean.
For example, ``add work`` is a command, and the add_work() function returns 0
for success or -EBUSY for failure. In the same way, ``PCI device present`` is
a predicate, and the pci_dev_present() function returns 1 if it succeeds in
finding a matching device or 0 if it doesn't.
Epicardium, the "main" firmware running on core 0, exposes a lot of
functionality to user-code via the so-called *Epicardium API*. This API
consists of a number of calls that can be issued by core 1 using an
auto-generated library.
API Design
.. note::
This is the current design. We might adjust it in the future to allow for
more performance in cases where this approach is too slow. This will most
likely be the addition of some form of asynchroneous calls.
The API is strictly synchroneous. This means, an API call looks exactly the
same as calling any other function. Internally, the call will wake up
Epicardium and there the call will be dispatched. It will then block until
Epicardium finished executing the call and return whatever the call has as a
return value. In code:
.. code-block:: c++
#include "epicardium.h"
int main(void)
/* ... */
/* Call the API to write to UART. */
epic_uart_write_str("Hello from core 1!\r\n", 20);
* Call the API to receive a byte from UART.
* This will block until at least one character is received.
char chr = epic_uart_read_chr();
/* ... */
In most cases, you won't need to care about the actual implementation of the
API as it is well hidden inside the auto-generated library. If you want to
know anyway, here is a rough overview:
The current design is based around a shared memory region, the semaphore
peripherals provided by MAX32666, and the SEV/WFE mechanism. When issuing a
call, this is what happens:
.. image:: ../static/synchroneous-api-call.svg
There is one important thing to note here: Right now, the API is only ever
polled for new calls from Epicardium inside the idle task. This means, that if
it is busy with other things, the API will have the least priority. For now,
this has not been an issue as Epicardium is sleeping most of the time anyway.
If it becomes one in the future we will have to introduce another
synchronization point.
How To Build
If you just want to write MicroPython code for card10, you probably **won't**
need to build the firmware yourself. This page is for people who want to work
on the underlying firmware itself.
* **gcc**, **binutils** & **newlib** for ``arm-none-eabi``: The packages have
slightly different names on different distros.
- Ubuntu: ``gcc-arm-none-eabi``, ``binutils-arm-none-eabi``, ``libnewlib-arm-none-eabi``
- Arch: ``arm-none-eabi-gcc``, ``arm-none-eabi-binutils``, ``arm-none-eabi-newlib``
- Alternative: Download `ARM's GNU toolchain`_. **TODO**
* **python3**: For meson and various scripts needed for building.
* **meson** (>0.43.0): Unfortunately most distros only have very old versions
of meson in their repositories. Instead, you'll probably save yourself a lot
of headaches by installing meson from ``pip3 install --user meson``.
* **python3-crc16**: Install with ``pip3 install --user crc16``.
.. _ARM's GNU toolchain:
Build using the following two commands:
.. code-block:: shell-session
$ ./
$ ninja -C build/
```` initializes git submodules and runs *meson*. Afterwards you
can build with *ninja*.
.. note::
Our build-system contains a few workarounds around short-comings in meson.
These workarounds might break on some setups which we did not yet test. If
this is the case for you, please open an issue in our `issue tracker`_!
.. _issue tracker:
If ninja succeeds, the binaries are in ``build/``. They are available in two
formats: As an ``.elf`` which can be flashed using a debugger and as a
``.bin`` which can be loaded using the provided bootloader. Here is a list of
the binaries:
- ``build/bootloader/bootloader.elf``: Our bootloader. It should already be on
your card10. The bootloader can only be flashed using a debugger.
- ``build/pycardium/pycardium_epicardium.bin``: The entire firmware in one ``.bin``.
- ``build/epicardium/epicardium.elf``: The core 0 part of the firmware, called Epicardium.
- ``build/pycardium/pycardium.elf``: Our MicroPython port, the core 1 part of the firmware.
How To Flash
Depending on whether you have a debugger or not, you have to use a different
method of flashing:
Flash Without Debugger
If you do not have a debugger, you have to update the firmware using our
bootloader. To do so, you need to reboot card10 while keeping the buttom on
the bottom right pressed. Rebooting is done by either short pressing the power
button (top left) while you have a working firmware, or turning the card10 off
completely (by pressing the power button for 8 seconds) and then starting it again.
.. todo::
Image showing the location of the buttons
If you did everything correctly, the bootloader will display:
.. code-block:: text
Jul 12 2019
USB activated.
On your host, you should now see an 8MB flash-device appear. You can now drop
the firmware's ``.bin`` (from ``build/pycardium/pycardium_epicardium.bin`` in
most cases) into this flash-storage. You **must** call the file ``card10.bin``
for the bootloader to use it.
Afterwards **eject** the flash device and reboot card10. You should now see
your new firmware boot up!
.. warning::
**You must EJECT the flash device!** ``umount`` & ``sync`` is **not**
enough and will result in the bootloader not loading the new binary.
Flash Using Debugger
.. warning::
With the current version of the bootloader, before attempting to flash using
the debugger, make sure there is not ``card10.bin`` stored on the device.
If there is, the bootloader will overwrite whatever you just flashed after
reboot every time.
First, setup everything as explained on the :ref:`debugger` page. Following
that and after connecting to card10, you can flash your binary using the
``load`` command. After loading, you need to use ``reset`` to reboot card10
using your new firmware.
.. code-block:: text
(gdb) load
Loading section .text, size 0x12514 lma 0x10010000
Loading section .ARM.exidx, size 0x8 lma 0x10022514
Loading section .data, size 0x8d8 lma 0x1002251c
Start address 0x10012160, load size 77300
Transfer rate: 19 KB/sec, 11042 bytes/write.
card10 firmware docs
This is the API documentation for card10's default firmware.
**Dear traveller,**
these transcripts describe how you can write code for your card10. This
includes the Python modules that are available but also documentation of the
lower level firmware components.
The design roughly looks like this:
If you want to write Python code for card10, you will want to take a look at
the :ref:`pycardium_index` docs. If you are interested in writing applications
in other languages, you'll probably want to interface with
:ref:`epicardium_api_index` directly.
.. image:: static/overview.svg
Last but not least, if you want to start hacking the lower-level firmware, the
:ref:`firmware_index` section of these docs is a good starting place.
.. toctree::
:maxdepth: 2
:caption: Epicardium
.. _pycardium_index:
.. toctree::
:maxdepth: 2
:maxdepth: 1
:caption: Pycardium
.. _epicardium_api_index:
.. toctree::
:maxdepth: 1
:caption: Epicardium API
.. _firmware_index:
.. toctree::
:maxdepth: 1
:caption: Firmware
To make the most of card10's dual-core processor, its firmware will have been
divided into two parts: The "main" firmware running on core 0 which will have
been called *Epicardium* and the "user-code" running on core 1. In most cases
this will have been *Pycardium*, our MicroPython port.
.. image:: ./static/overview.svg
Epicardium is based on `FreeRTOS`_. There are a number of tasks that will have
been keeping card10 running. These are:
* **Dispatcher**: The dispatcher task handles API calls from core 1.
* **PMIC**: The power manager task checks the battery level and other interesting
statistics that can be gathered from our power manager IC (MAX77650).
* **Serial**: Handles serial communication via *UART*, *CDC ACM* and possibly
.. todo::
The following tasks have not yet been implemented/are currently in the works:
- **Bluetooth**: The bluetooth stack
- **Payload Controller**: Control what is running on core 1
.. _FreeRTOS:
Pycardium is our MicroPython fork. Its purpose is to make it as easy as
possible to interact with card10.
.. warning::
We have not yet been able to determine if card10 will have had the abilities
described in this section. And if yes, how they will have been implemented.
Next to Pycardium, other bare-metal code can also run on core 1. For example,
a Rustcardium or Cccardium.
Pycardium Intro
Pycardium is a core1 payload based on MicroPython. It can interface with
card10 using the Epicardium API, which is wrapped in a bunch of python modules.
Pycardium also contains a number of Python stdlib modules. To see the full
list, type:
.. code-block:: python
The following pages detail card10 specific modules.
Pycardium is what we call our MicroPython port for card10. For the most part,
it will behave like a normal MicroPython, enhanced by a few modules to
interface with card10's hardware. We have also included modules from Python's
standard library so you have lots of familiar functionality at hand to start
.. note::
Right now, MicroPython is only available via the serial console. card10
makes its console available as a CDC ACM device via USB or, if you have a
debugger, on the debugging serial port.
This means, you can only interact with Python through a REPL for now.
However, this will soon change, once `#10`_ and `#11`_ are implemented.
.. _#10:
.. _#11:
.. todo::
Getting Started Guide for people interested in writing Python code.
......@@ -148,15 +148,15 @@
......@@ -301,20 +301,20 @@
id="tspan1028">(core 0)</tspan></text>
......@@ -393,7 +393,7 @@
......@@ -401,12 +401,12 @@
id="tspan1032">(core 1)</tspan></text>
......@@ -420,7 +420,7 @@
d="M 19.222455,122.34974 H 10.72299 v 46.42197 h 23.044261"
......@@ -456,6 +456,17 @@
style="stroke-width:0.26458332"> </tspan></text>
This diff is collapsed.
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment