SAMD21E17/E18 devkit board

This project is a SAMD21 version of my SAMD devkit series. Just like the SAMD11C, the idea is:

  • Almost all pins used: offer all functionality of the chip.
  • Readable text: label every GPIO or power pin with text on the copper.
  • JTAG ARM connector: provide a 10-pin standard JTAG connector for flashing and realtime debugging.
  • Robust 3.3V regulator: a larger SOT223 regulator for providing up to 1A of current for external devices.
  • Serial port protection: the entire board is based on 3.3V, but a resistor protects the RX pin if used against TTL levels.

Schematic

The schematic of the board is not surprising. Notice that unlike the SAMD11, there are several distinct power pins on the SAMD, which should all be connected. There is also a capacitor required to stabilize the internally-regulated 1.6V core level.

Board

When designing the board, I put extra care in having a compact board with short tracks. There is also enough room around the JTAG connector to put a shrouded connector (good practice if available).

By default, I use a mini-USB connector as they are reliable and relatively easy to solder. If there is a specific need for a USB-A version, I might design one.

Production

Milling

The board is milled on our trusty Bantam desktop milling machine, with a 1/64” flat end mill for engraving, and a 1mm flat end mill for the edge cuts.

The board came out perfect after 30 minutes of milling.

I also milled a SAMD21E18 version. The only difference is the name of board on top so I don’t confuse them. The SAMD21E18 has 256kb of flash, while the E17 variant has 128kb.

Soldering

I then proceed to solder the minimal amount of components; I want to see whether I can successfully prorgam the chip before moving on to the other components.

Note that this board looks silver because I treated it with “liquid tin”, which in my case is a mix of sulfuric acid and dissolved tin. The acid helps tin getting fixed onto the copper. I like this process because it prevents my circuits from oxidizing on the long run.

With the minimal amount of components soldered, I could test the board by programming it (see below) and see that everything worked OK.

After adding the LEDs and pin headers, the boards are complete.

Programming

As with my SAMD11C devkit, I suggest loading the appropriate SAM BA bootloader so that the board can be re-programmed through USB at will. The bootloaders and instructions to install the Arduino core are available on Mattairtech’s github page.

Under bootloader/zero/binaries, you will find the generic SAMD21E17A and generic SAMD21E18A variants of the SAM BA bootloader.

The procedure for flashing the board with EDBG and a DAP programmer is detailed in my SAMD11C devkit page.

CircuitPython (E18 only)

CircuitPython is a lightweight Python interpreter and libraries maintained by Adafruit and compatible with a wide range of microcontrollers. When it comes to SAMD, there is an “official” board similar to ours but based on the SAMD21G18; the feather M0.

Because our SAMD21E18 has less pins, a specific CircuitPython firmware must be compiled. Note that the SAMD21E17 does not have enough flash, only the E18 variant can fit the firmware in its 256kb flash and still have some free space for Python scripts. I started by cloning the repository from Adafruit, then added a folder named samd21_devkit under ports/atmel-samd/boards. This folder contains four files:

  • board.c
/*
 * This file is part of the MicroPython project, http://micropython.org/
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "supervisor/board.h"

void board_init(void) {
}

bool board_requests_safe_mode(void) {
    return false;
}

void reset_board(void) {
}
  • mpconfigboard.h
#define MICROPY_HW_BOARD_NAME "SAMD21E18 devkit"
#define MICROPY_HW_MCU_NAME "samd21e18"

#define MICROPY_PORT_A        (0)
#define MICROPY_PORT_B        (0)
#define MICROPY_PORT_C        (0)

// No microcontroller.nvm
#define CIRCUITPY_INTERNAL_NVM_SIZE 0

#define DEFAULT_I2C_BUS_SCL (&pin_PA17)
#define DEFAULT_I2C_BUS_SDA (&pin_PA16)

#define DEFAULT_SPI_BUS_SCK (&pin_PA19)
#define DEFAULT_SPI_BUS_MOSI (&pin_PA18)
#define DEFAULT_SPI_BUS_MISO (&pin_PA22)

#define DEFAULT_UART_BUS_RX (&pin_PA11)
#define DEFAULT_UART_BUS_TX (&pin_PA10)

#define IGNORE_PIN_PA12     1
#define IGNORE_PIN_PA13     1
#define IGNORE_PIN_PA20     1
#define IGNORE_PIN_PA21     1
// USB is always used.
#define IGNORE_PIN_PA24     1
#define IGNORE_PIN_PA25     1
#define IGNORE_PIN_PA30     1
#define IGNORE_PIN_PA31     1
#define IGNORE_PIN_PB01     1
#define IGNORE_PIN_PB02     1
#define IGNORE_PIN_PB03     1
#define IGNORE_PIN_PB04     1
#define IGNORE_PIN_PB05     1
#define IGNORE_PIN_PB06     1
#define IGNORE_PIN_PB07     1
#define IGNORE_PIN_PB08     1
#define IGNORE_PIN_PB09     1
#define IGNORE_PIN_PB10     1
#define IGNORE_PIN_PB11     1
#define IGNORE_PIN_PB12     1
#define IGNORE_PIN_PB13     1
#define IGNORE_PIN_PB14     1
#define IGNORE_PIN_PB15     1
#define IGNORE_PIN_PB16     1
#define IGNORE_PIN_PB17     1
#define IGNORE_PIN_PB22     1
#define IGNORE_PIN_PB23     1
#define IGNORE_PIN_PB30     1
#define IGNORE_PIN_PB31     1
#define IGNORE_PIN_PB00     1
  • mpconfigboard.mk
USB_VID = 0x1B4F
USB_PID = 0x8D23
USB_PRODUCT = "SAMD21E18 devkit"
USB_MANUFACTURER = "Fab Foundation"

CHIP_VARIANT = SAMD21E18A
CHIP_FAMILY = samd21

INTERNAL_FLASH_FILESYSTEM = 1
LONGINT_IMPL = NONE
CIRCUITPY_FULL_BUILD = 0

SUPEROPT_GC = 0
  • pins.c
#include "shared-bindings/board/__init__.h"

STATIC const mp_rom_map_elem_t board_global_dict_table[] = {
    // Digital pins
    { MP_ROM_QSTR(MP_QSTR_PA01), MP_ROM_PTR(&pin_PA01) },
    { MP_ROM_QSTR(MP_QSTR_PA02), MP_ROM_PTR(&pin_PA02) },
    { MP_ROM_QSTR(MP_QSTR_PA03), MP_ROM_PTR(&pin_PA03) },
    { MP_ROM_QSTR(MP_QSTR_PA04), MP_ROM_PTR(&pin_PA04) },
    { MP_ROM_QSTR(MP_QSTR_PA05), MP_ROM_PTR(&pin_PA05) },
    { MP_ROM_QSTR(MP_QSTR_PA06), MP_ROM_PTR(&pin_PA06) },
    { MP_ROM_QSTR(MP_QSTR_PA07), MP_ROM_PTR(&pin_PA07) },
    { MP_ROM_QSTR(MP_QSTR_PA08), MP_ROM_PTR(&pin_PA08) },
    { MP_ROM_QSTR(MP_QSTR_PA10), MP_ROM_PTR(&pin_PA10) },
    { MP_ROM_QSTR(MP_QSTR_PA11), MP_ROM_PTR(&pin_PA11) },
    { MP_ROM_QSTR(MP_QSTR_PA16), MP_ROM_PTR(&pin_PA16) },
    { MP_ROM_QSTR(MP_QSTR_PA17), MP_ROM_PTR(&pin_PA17) },
    { MP_ROM_QSTR(MP_QSTR_PA18), MP_ROM_PTR(&pin_PA18) },
    { MP_ROM_QSTR(MP_QSTR_PA19), MP_ROM_PTR(&pin_PA19) },
    { MP_ROM_QSTR(MP_QSTR_PA22), MP_ROM_PTR(&pin_PA22) },
    { MP_ROM_QSTR(MP_QSTR_PA23), MP_ROM_PTR(&pin_PA23) },

    { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&pin_PA03) },

    // UART pins
    { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_PA10) },
    { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_PA11) },
    { MP_ROM_QSTR(MP_QSTR_TX2), MP_ROM_PTR(&pin_PA14) },
    { MP_ROM_QSTR(MP_QSTR_RX2), MP_ROM_PTR(&pin_PA15) },

    // SPI pins
    { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_PA18) },
    { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_PA19) },
    { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_PA22) },

    // I2C pins
    { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PA17) },
    { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PA16) },

    // LED pins
    { MP_ROM_QSTR(MP_QSTR_LED),   MP_ROM_PTR(&pin_PA08) },

    // Comm objects
    { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
    { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
    { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
};
MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table);

I then compiled this firmware version by launching the following on a Linux machine under the folder ports/atmel-samd:

make BOARD=samd21_devkit

The Makefile automatically looks for the samd21_devkit folder created earlier and compiles the firmware in a folder named ports/atmel-samd/build-samd21_devkit, in which the firmware.uf2 file can be found.

To upload this .uf2 firmware on the board, we need to install the UF2 bootloader. UF2 is a nice alternative to using command line tools for programming the board: it turns it into a USB mass storage device in which you simply drop .uf2 files that are automatically read and stored in the flash. I compiled a custom version of the UF2 bootloader for SAMD21E18, available in the downloads section.

To test all this, I prepared a SAMD21E18 board:

The UF2 bootloader is first flashed using EDBG as usual, then the CircuitPython firmware is loaded onto it. After this, the board appears as a mass storage device called CIRCUITPY, in which Python scripts and data can be dropped. At this point, the board is ready to be used and the UF2 bootloader will not appear. If needed, it can be brought back manually by performing a double tap on the reset button of the SAMD. Unfortunately there is no reset button on this board, so you’ll have to extract it from the JTAG connector and connect it to the ground to “tap the button”.

When connecting to the USB and opening the serial port with 9600 baud, I am greeted by the Python interpreter. I can dynamically type commands or code snippets.

Downloads

SAMD21E17

SAMD21E18