blob: 0d6e5b3f2665d4a67a9665520e9157c3d1e1f00e [file] [log] [blame]
BSP Porting
===========
.. contents::
:local:
:depth: 2
Introduction
~~~~~~~~~~~~
The Apache Mynewt core repo contains support for several different boards. For each supported board, there is a Board
Support Package (BSP) package in the ``hw/bsp`` directory. If there isn't a BSP package for your hardware, then you will need to make one
yourself. This document describes the process of creating a BSP package from scratch.
While creating your BSP package, the following documents will probably come in handy:
- The datasheet for the MCU you have chosen.
- The schematic of your board.
- The information on the CPU core within your MCU if it is not included in your MCU documentation.
This document is applicable to any hardware, but it will often make reference to a specific board as an example. Our
example BSP has the following properties:
- **Name:** ``hw/bsp/myboard``
- **MCU:** Nordic nRF52
Download the BSP package template
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We start by downloading a BSP package template. This template will serve as a good starting point for our new BSP.
Execute the ``newt pkg new`` command, as below:
.. code-block:: console
$ newt pkg new -t bsp hw/bsp/myboard
Download package template for package type bsp.
Package successfuly installed into /home/me/myproj/hw/bsp/myboard.
Our new package has the following file structure:
.. code-block:: console
$ tree hw/bsp/myboard
hw/bsp/myboard
├── README.md
├── boot-myboard.ld
├── bsp.yml
├── include
│   └── myboard
│   └── bsp.h
├── myboard.ld
├── myboard_debug.sh
├── myboard_download.sh
├── pkg.yml
├── src
│   ├── hal_bsp.c
│   └── sbrk.c
└── syscfg.yml
3 directories, 11 files
We will be adding to this package throughout the remainder of this document. See `Appendix A: BSP files`_ for a full
list of files typically found in a BSP package.
Create a set of Mynewt targets
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We'll need two :ref:`targets <mynewt-target>` to test our BSP as we go:
1. Boot loader
2. Application
A minimal application is best, since we are just interested in getting the BSP up and running. A good app for our
purposes is :doc:`blinky <../../../tutorials/blinky/blinky>`.
We create our targets with the following set of newt commands:
::
newt target create boot-myboard &&
newt target set boot-myboard app=@apache-mynewt-core/apps/boot \
bsp=hw/bsp/myboard \
build_profile=optimized
newt target create blinky-myboard &&
newt target set blinky-myboard app=apps/blinky \
bsp=hw/bsp/myboard \
build_profile=debug
Which generates the following output:
::
Target targets/boot-myboard successfully created
Target targets/boot-myboard successfully set target.app to @apache-mynewt-core/apps/boot
Target targets/boot-myboard successfully set target.bsp to hw/bsp/myboard
Target targets/boot-myboard successfully set target.build_profile to debug
Target targets/blinky-myboard successfully created
Target targets/blinky-myboard successfully set target.app to apps/blinky
Target targets/blinky-myboard successfully set target.bsp to hw/bsp/myboard
Target targets/blinky-myboard successfully set target.build_profile to debug
Fill in the ``bsp.yml`` file
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The template ``hw/bsp/myboard/bsp.yml`` file is missing some values that need to be added. It also assumes certain
information that may not be appropriate for your BSP. We need to get this file into a usable state.
Missing fields are indicated by the presence of ``XXX`` markers. Here are the first several lines of our ``bsp.yml``
file where all the incomplete fields are located:
::
bsp.arch: # XXX <MCU-architecture>
bsp.compiler: # XXX <compiler-package>
bsp.linkerscript:
- 'hw/bsp/myboard/myboard.ld'
# - XXX mcu-linker-script
bsp.linkerscript.BOOT_LOADER.OVERWRITE:
- 'hw/bsp/myboard/myboard/boot-myboard.ld'
# - XXX mcu-linker-script
So we need to specify the following:
- MCU architecture
- Compiler package
- MCU linker script
Our example BSP uses an nRF52 MCU, which implements the ``cortex_m4`` architecture. We use this information to fill in
the incomplete fields:
.. code-block:: yaml
:emphasize-lines: 1, 2, 5, 8
bsp.arch: cortex_m4
bsp.compiler: '@apache-mynewt-core/compiler/arm-none-eabi-m4'
bsp.linkerscript:
- 'hw/bsp/myboard/myboard.ld'
- '@apache-mynewt-core/hw/mcu/nordic/nrf52xxx/nrf52.ld'
bsp.linkerscript.BOOT_LOADER.OVERWRITE:
- 'hw/bsp/myboard/boot-myboard.ld'
- '@apache-mynewt-core/hw/mcu/nordic/nrf52xxx/nrf52.ld'
Naturally, these values must be adjusted accordingly for other MCU types.
Flash map
~~~~~~~~~
At the bottom of the ``bsp.yml`` file is the flash map. The flash map partitions the BSP's flash memory into sections
called areas. Flash areas are further categorized into two types: 1) system areas, and 2) user areas. These two area
types are defined below.
**System areas**
- Used by Mynewt core components.
- BSP support is mandatory in most cases.
- Use reserved names.
**User areas**
- Used by application code and supplementary libraries.
- Identified by user-assigned names.
- Have unique user-assigned numeric identifiers for access by C code.
The flash map in the template ``bsp.yml`` file is suitable for an MCU with 512kB of internal flash. You may need to
adjust the area offsets and sizes if your BSP does not have 512kB of internal flash.
The system flash areas are briefly described below:
+--------------------------------+---------------------------------------------------------+
| Flash area | Description |
+================================+=========================================================+
| ``FLASH_AREA_BOOTLOADER`` | Contains the Mynewt boot loader. |
+--------------------------------+---------------------------------------------------------+
| ``FLASH_AREA_IMAGE_0`` | Contains the active Mynewt application image. |
+--------------------------------+---------------------------------------------------------+
| ``FLASH_AREA_IMAGE_1`` | Contains the secondary image; used for image upgrade. |
+--------------------------------+---------------------------------------------------------+
| ``FLASH_AREA_IMAGE_SCRATCH`` | Used by the boot loader during image swap. |
+--------------------------------+---------------------------------------------------------+
Add the MCU dependency to ``pkg.yml``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A package's dependencies are listed in its ``pkg.yml`` file. A BSP package always depends on its corresponding MCU
package, so let's add that dependency to our BSP now. The ``pkg.deps`` section of our ``hw/bsp/myboard/pkg.yml`` file
currently looks like this:
.. code-block:: yaml
pkg.deps:
# - XXX <MCU-package>
- '@apache-mynewt-core/kernel/os'
- '@apache-mynewt-core/libc/baselibc'
Continuing with our example nRF52 BSP, we replace the marked line as follows:
.. code-block:: yaml
:emphasize-lines: 2
pkg.deps:
- '@apache-mynewt-core/hw/mcu/nordic/nrf52xxx'
- '@apache-mynewt-core/kernel/os'
- '@apache-mynewt-core/libc/baselibc'
Again, the particulars depend on the MCU that your BSP uses.
Check the BSP linker scripts
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Linker scripts are a key component of the BSP package. They specify how code and data are arranged in the MCU's memory.
Our BSP package contains two linker scripts:
+-----------------------+------------------------------------------------+
| **Filename** | **Description** |
+=======================+================================================+
| ``myboard.ld`` | Linker script for Mynewt application images. |
+-----------------------+------------------------------------------------+
| ``boot-myboard.ld`` | Linker script for the Mynewt boot loader. |
+-----------------------+------------------------------------------------+
First, we will deal with the application linker script. You may have noticed that the ``bsp.linkerscript`` item in
``bsp.yml`` actually specifies two linker scripts:
- BSP linker script (``hw/bsp/myboard.ld``)
- MCU linker script (``@apache-mynewt-core/hw/mcu/nordic/nrf52xxx/nrf52.ld``)
Both linker scripts get used in combination when you build a Mynewt image. Typically, all the complexity is isolated to
the MCU linker script, while the BSP linker script just contains minimal size and offset information. This makes the job
of creating a BSPpackage much simpler.
Our ``myboard.ld`` file has the following contents:
.. code-block:: c
MEMORY
{
FLASH (rx) : ORIGIN = 0x00008000, LENGTH = 0x3a000
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000
}
/* This linker script is used for images and thus contains an image header */
_imghdr_size = 0x20;
Our task is to ensure the offset (``ORIGIN``) and size (``LENGTH``) values are correct for the ``FLASH`` and ``RAM``
regions. Note that the ``FLASH`` region does not specify the board's entire internal flash; it only describes the area
of the flash dedicated to containing the running Mynewt image. The bounds of the ``FLASH`` region should match those of
the ``FLASH_AREA_IMAGE_0`` area in the BSP's flash map.
The ``_imghdr_size`` is always ``0x20``, so it can remain unchanged.
The second linker script, ``boot-myboard.ld``, is quite similar to the first. The important difference is the ``FLASH``
region: it describes the area of flash which contains the boot loader rather than an image. The bounds of this region
should match those of the ``FLASH_AREA_BOOTLOADER`` area in the BSP's flash map. For more information about the Mynewt
boot loader, see :doc:`this page <../../modules/bootloader/bootloader/>`.
Copy the download and debug scripts
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The newt command line tool uses a set of scripts to load and run Mynewt images. It is the BSP package that provides
these scripts.
As with the linker scripts, most of the work done by the download and debug scripts is isolated to the MCU package. The
BSP scripts are quite simple, and you can likely get away with just copying them from another BSP. The template
``myboard_debug.sh`` script indicates which BSP to copy from:
.. code-block:: bash
#!/bin/sh
# This script attaches a gdb session to a Mynewt image running on your BSP.
# If your BSP uses JLink, a good example script to copy is:
# repos/apache-mynewt-core/hw/bsp/nrf52dk/nrf52dk_debug.sh
#
# If your BSP uses OpenOCD, a good example script to copy is:
# repos/apache-mynewt-core/hw/bsp/rb-nano2/rb-nano2_debug.sh
Our example nRF52 BSP uses JLink, so we will copy the nRF52dk BSP's scripts:
::
cp repos/apache-mynewt-core/hw/bsp/nrf52dk/nrf52dk_debug.sh hw/bsp/myboard/myboard_debug.sh
cp repos/apache-mynewt-core/hw/bsp/nrf52dk/nrf52dk_download.sh hw/bsp/myboard/myboard_download.sh
Fill in BSP functions and defines
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There are a few particulars missing from the BSP's C code. These areas are marked with ``XXX`` comments to make them
easier to spot. The missing pieces are summarized in the table below:
+-------------------------+-------------------------------------------------------------------------------------------------+--------------------------------------------------------------+
| File | Description | Notes |
+=========================+=================================================================================================+==============================================================+
| ``src/hal_bsp.c`` | ``hal_bsp_flash_dev()`` needs to return a pointer to the MCU's flash object when ``id == 0``. | The flash object is defined in MCU's ``hal_flash.c`` file. |
+-------------------------+-------------------------------------------------------------------------------------------------+--------------------------------------------------------------+
| ``include/bsp/bsp.h`` | Define ``LED_BLINK_PIN`` to the pin number of the BSP's primary LED. | Required by the blinky application. |
+-------------------------+-------------------------------------------------------------------------------------------------+--------------------------------------------------------------+
For our nRF52 BSP, we modify these files as follows:
**src/hal\_bsp.c:**
.. code-block:: c
:emphasize-lines: 1
#include "mcu/nrf52_hal.h"
.. code-block:: c
:emphasize-lines: 7
const struct hal_flash *
hal_bsp_flash_dev(uint8_t id)
{
switch (id) {
case 0:
/* MCU internal flash. */
return &nrf52k_flash_dev;
default:
/* External flash. Assume not present in this BSP. */
return NULL;
}
}
**include/bsp/bsp.h:**
.. code-block:: c
:emphasize-lines: 5
#define RAM_SIZE 0x10000
/* Put additional BSP definitions here. */
#define LED_BLINK_PIN 17
Add startup code
~~~~~~~~~~~~~~~~
Now we need to add the BSP's assembly startup code. Among other things, this is the code that gets executed immediately
on power up, before the Mynewt OS is running. This code must perform a few basic tasks:
- Assign labels to memory region boundaries.
- Define some interrupt request handlers.
- Define the ``Reset_Handler`` function, which:
- Zeroes the ``.bss`` section.
- Copies static data from the image to the ``.data`` section.
- Starts the Mynewt OS.
This file is named according to the following pattern: ``hw/bsp/myboard/src/arch/<ARCH>/gcc_startup_<MCU>.s``
The best approach for creating this file is to copy from other BSPs. If there is another BSP that uses the same MCU, you
might be able to use most or all of its startup file.
For our example BSP, we'll just copy the nRF52dk BSP's startup code:
.. code-block:: console
$ mkdir -p hw/bsp/myboard/src/arch/cortex_m4
$ cp repos/apache-mynewt-core/hw/bsp/nrf52dk/src/arch/cortex_m4/gcc_startup_nrf52.s hw/bsp/myboard/src/arch/cortex_m4/
Satisfy MCU requirements
~~~~~~~~~~~~~~~~~~~~~~~~
The MCU package probably requires some build-time configuration. Typically, it is the BSP which provides this configuration.
Completing this step will likely involve some trial and error as each unmet requirement gets reported as a build error.
Our example nRF52 BSP requires the following changes:
1. Macro indicating MCU type. We add this to our BSP's ``pkg.yml`` file:
.. code-block:: yaml
:emphasize-lines: 2
pkg.cflags:
- '-DNRF52'
2. Enable exactly one low-frequency timer setting in our BSP's ``syscfg.yml`` file. This is required by the nRF51 and nRF52 MCU packages:
.. code-block:: yaml
:emphasize-lines: 3
# Settings this BSP overrides.
syscfg.vals:
XTAL_32768: 1
Test it
~~~~~~~
Now it's finally time to test the BSP package. Build and load your boot and blinky targets as follows:
.. code-block:: console
$ newt build boot-myboard
$ newt load boot-myboard
$ newt run blinky-myboard 0
If everything is correct, the blinky app should successfully build, and you should be presented with a gdb prompt. Type
``c <enter>`` (continue) to see your board's LED blink.
Appendix A: BSP files
~~~~~~~~~~~~~~~~~~~~~
The table below lists the files required by all BSP packages. The naming scheme assumes a BSP called "myboard".
+---------------------------------------------+-----------------------------------------------------------------------+
| **File Path Name** | **Description** |
+=============================================+=======================================================================+
| ``pkg.yml`` | Defines a Mynewt package for the BSP. |
+---------------------------------------------+-----------------------------------------------------------------------+
| ``bsp.yml`` | Defines BSP-specific settings. |
+---------------------------------------------+-----------------------------------------------------------------------+
| ``include/bsp/bsp.h`` | Contains additional BSP-specific settings. |
+---------------------------------------------+-----------------------------------------------------------------------+
| ``src/hal_bsp.c`` | Contains code to initialize the BSP's peripherals. |
+---------------------------------------------+-----------------------------------------------------------------------+
| ``src/sbrk.c`` | Low level heap management required by ``malloc()``. |
+---------------------------------------------+-----------------------------------------------------------------------+
| ``src/arch/<ARCH>/gcc_startup_myboard.s`` | Startup assembly code to bring up Mynewt |
+---------------------------------------------+-----------------------------------------------------------------------+
| ``myboard.ld`` | A linker script providing the memory map for a Mynewt application. |
+---------------------------------------------+-----------------------------------------------------------------------+
| ``boot-myboard.ld`` | A linker script providing the memory map for the Mynewt bootloader. |
+---------------------------------------------+-----------------------------------------------------------------------+
| ``myboard_download.sh`` | A bash script to download code onto your platform. |
+---------------------------------------------+-----------------------------------------------------------------------+
| ``myboard_debug.sh`` | A bash script to initiate a gdb session with your platform. |
+---------------------------------------------+-----------------------------------------------------------------------+
A BSP can also contain the following optional files:
+---------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------+
| **File Path Name** | **Description** |
+===================================================+==========================================================================================================================+
| ``split-myboard.ld`` | A linker script providing the memory map for the "application" half of a :doc:`split image <../../modules/split/split>` |
+---------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------+
| ``no-boot-myboard.ld`` | A linker script providing the memory map for your bootloader |
+---------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------+
| ``src/arch/<ARCH>/gcc_startup_myboard_split.s`` | Startup assembly code to bring up the "application" half of a :doc:`split image <../../modules/split/split>`. |
+---------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------+
| ``myboard_download.cmd`` | An MSDOS batch file to download code onto your platform; required for Windows support. |
+---------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------+
| ``myboard_debug.cmd`` | An MSDOS batch file to intiate a gdb session with your platform; required for Windows support. |
+---------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------+