Introduction

Moteino began as a low power wireless Arduino compatible development platform based on the popular ATmega328p chip used in the Arduino-UNO. There are now several Moteino development boards including MoteinoMEGA based on the Atmega1284P and MoteinoM0 based on the SAMD21G18 Cortex M0+.

For programming you will need an external FTDI-Adapter to load sketches, the advantages being lower cost, smaller size. The MoteinoUSB and MoteinoMEGA-USB variant includes the USB-serial converter.

Moteinos are compatible and can communicate with any other Arduino or development platform that uses the popular HopeRF RFM69 or LoRa transceivers, or even the older RFM12B. Moteino also comes with an optional SPI flash memory chip for wireless programming, or data logging.

Video introduction to Moteino R3 and the RFM69 transceivers and library:

What about MoteinoUSB?

Moteino-USB includes the USB-serial FTDI chip. Technically a MoteinoUSB is the combination of an FTDI-Adapter and a regular Moteino. It can be programmed and powered via the USB connector but can also run from a battery (VIN pin) just as well:

What about MoteinoMEGA?

The MoteinoMEGA uses the Atmega1284p microcontroller. It still runs at 3.3V/16Mhz but has 128KB of internal flash (vs 32KB on Atmega328p), 16KB of RAM (vs 2KB), 4KB EEPROM (vs 1KB), 2x hardware serial ports, 8x PWM pins and bunch more GPIO pins. Still a small board at just 1.0×2.0″ and breadboard friendly. Comes with the same DualOptiboot bootloader making it “OTA” wireless programming capable, and can take up to 16V of input on the VIN pins (MCP1703 regulated).

To upload sketches to MoteinoMEGA you will need to first install the Moteino Core (instructions here). This defines the pin map and other important core definitions that allow the MEGA to be programmed from the Arduino IDE. Once that is done you should have a new board target under Tools>Boards called MoteinoMEGA


Moteino with trace antenna (868-915Mhz)

There are also two special Moteino variants with integrated PCB trace antennas, these are available for Moteino and MoteinoMEGA. The PCB antennas are tuned for the 868-915mhz bands and have an excellent performance given their compact size. Other than the PCB antenna, they are identical and work the same as regular Moteinos.

Why Moteino?

Moteino was designed to be a compact, highly customizable and affordable development platform, suitable for IoT, home automation and long range wireless projects. Here are some of the features that set Moteino apart:

  • small & light modular design fits in tiny enclosures
  • breadboard friendly and allows stackable shields
  • flexible configurations allow several wireless transceivers to be used
  • true ultra low power: with just ~2uA achievable in deep sleep mode, AVR Moteinos allow battery friendly projects like wireless motion/environment sensors to run for years. Watchdog sleep mode is at ~6uA (periodic wake). The new 8Mhz Moteino allows the lowest possible 100nA sleep mode. The new SAMD21 Cortex M0+ based MoteinoM0 sleeps at just ~8uA!
  • sub-Ghz and LoRa radios yield much longer range than 2.4Ghz bands
  • wirelessly (aka OTA) programmable: be able to re-flash it without wires, when deployed in difficult locations (supported with RFM69 radios only)
  • easy to use from the familiar Arduino IDE, many code examples given to help get started
  • affordable: zero-cost wire monopole antennas yield excellent RF range for all-around wireless projects. With the u.FL/IPEX and SMA connector pads you can attach any other external antennas with higher gain
  • visit the user projects forum to see how people are using Moteinos
  • See LowPowerLab’s home automation platform: Moteino IoT Gateway project

Why the funky name “Moteino”?

Mote + ino, obviously.

Moteino aka…

Since “Moteino” is so hard to pronounce, write and remember, here is a list of (funny) names that people have dubbed it over the years:

Moreduino
Moetino
Moiteno
Moduino
Modeino
Montenio
Moneinto
Monetino
Monteino
Moreno
Moteduino
Noteino
Motenio
Moteiono
Motuino
Motenino
motetino
Moteuino
Motino
Motion
Moteion

And no, we didn’t make this list up!

Out of box, pinouts

Moteinos come without any soldered headers or antennas. Without the wire antenna the range will be only a few feet, and while this is OK for testing purposes it’s recommended that an antenna be soldered before real application use of the transmitter. The provided wire monopole antenna has to be soldered to the “ANT” pin hole (just above the FLASH chip) to achieve any usable range. Regular Moteinos will come with a 1×6 male header that you have to solder before you can power it and upload sketches through an FTDI Adapter. Moteino-USB has built in USB so you only need a mini-USB cable for programming.

Video demonstration of soldering headers and wire antenna:

Pinout diagrams (click to enlarge):

Specifications

Moteino

MicrocontrollerATmega328p
TransceiverRFM69,  RFM95/RFM96 LoRa,  RFM12b
Frequency bands433Mhz, 868Mhz (EU), 915Mhz (US, Australia, etc.)
Input Voltage (VIN pin)3.6V-16V (up to 12V recommended)
Core operating voltage3.3V (regulated via MCP1703 low dropout regulator)
Digital I/O Pins14+6 (6 PWM capable: marked with “~“)
Analog Pins8 (2x analog-only pins more than regular Arduinos)
DC Current per pin10 mA
Program Memory32 KB of which 1 KB used by DualOptiboot bootloader *
SRAM2 KB
EEPROM1 KB
Clock Speed16 MHz via external ceramic resonator
Power usage~8mA (no sleep, LED blinky sketch)
Lowest power6.5uA with stock regulator & fuses (sample sketch)
MISCOnboard LED on pin D9 (PWM capable!)
Radio transceiver SPI-CS on D10
FLASH SPI-CS on D8
A6 and A7 are analog pins only, cannot be used as digital pins

* DualOptiboot is a modified version of the standard Optiboot bootloader (size is 1k instead of 512bytes). For plain FTDI/serial programming you can still use the Arduino Uno target for uploading to a Moteino, as long as your sketch won’t exceed 31KB. To avoid issues and support MoteinoMEGA, you should install the Moteino Core which contains the definitions for all Moteino boards.

MoteinoMEGA

MicrocontrollerATmega1284p
TransceiverRFM69,  RFM95/RFM96 LoRa
Frequency bands433Mhz, 868Mhz (EU), 915Mhz (US, Australia, etc.)
Input Voltage (VIN pin)3.6V-16V (up to 12V recommended)
Core voltage3.3V (regulated via MCP1703 low dropout regulator)
Digital I/O Pins24+8 (8 PWM capable: marked with “”)
Analog Pins8
DC Current per pin10 mA
Program Memory128 KB of which 1 KB used by DualOptiboot bootloader *
SRAM16 KB
EEPROM4 KB
Clock Speed16 MHz via external ceramic resonator
Power usage~8mA (no sleep, LED blinky sketch)
Lowest power6.5uA with stock regulator & fuses (sample sketch)
MISCOnboard LED on pin D15 (PWM capable!)
Radio transceiver SPI-CS on D4
FLASH SPI-CS on D23

Moteino 8Mhz variant

There is now a Moteino 8Mhz variant. This has no LDO and hence allows to harvest the lowest power modes from the Atmega328p MCU. It has the following differences to the regular Moteino:

  • no LDO linear regulator
  • the VIN and 3v3 pins are connected by a 0ohm resistor (bridge)
  • must be powered from 3.6v or less when RFM radio and/or FLASH-MEM are installed. The RFM radio and FLASH-MEM are damaged by 5V. Without these components the board will work up to 5V.
  • 16mhz resonator is still installed but not used with the 8Mhz fuses. This means you can change the fuses yourself and run the board at 16Mhz it if you’d like, but this will only be safe down to about 3.3V
  • fuses are: LOW: 0xD2, HI: 0xDC, EXTENDED: 0xFE
  • even more ultra low power – 2uA less current than the regular Moteino
  • runs DualOptiboot compiled for 8mhz
  • 57600baud upload programming speed (vs. 115200)
  • you will need to install the latest Moteino definition (v1.3 or newer) in your Arduino IDE Board Manager to gain the new Moteino (8Mhz) target board:

These types of Moteinos are ideal for ultra low power coin cell and other micro power powered nodes – power them from 3.6V or less. Of course, when you have such tiny power supplies, you must choose your transceiver carefully, as you likely cannot transmit at full 20dBm power from a tiny coincell. The W/CW 13dBm radios running the auto-power-dial RFM69_ATC library extension would be recommended for running on coin cells or small solar cells.

To program this Moteino the FTDI-Adapter offered in the shop can be modified to pass a safe 3.3V to the 8Mhz LDO-less Moteino – cut the *5V Output Voltage jumper and solder the 3.3V one:

Note that this mod will make the FTDI-Adapter regulate power, but it can only supply about 50mA to the Moteino, if you draw more power, the adapter might drop and reconnect to your computer

Alternatively, you can build a dedicated adapter that takes the 5V from the USB and regulates it to 3.3v, here’s such an example which uses the LDO from the Moteino itself (MCP1703) along with a 1uF and 0.1uF caps, all other connections are passed through and assumed to be 3.3v levels:

You would then use it in between your stock unmodified FTDI-Adapter (or equivalent board, providing 5V VIN power and 3.3V TX/RX/DTR signals), and the no-LDO Moteino which requires 3.3V when radio/flash are present:

Moteino M0

The MoteinoM0 (release notes) is a SAMD21 Cortex M0+ based Moteino featuring these general specifications:

  • ATSAMD21G18A microcontroller (48pin LQFP) running at 48Mhz, 3.3V core
  • Input voltage: 3.6-6V
  • Digital pins: 23 (11 PWM)
  • Analog ADC pins: 6 (12bit)
  • Analog DAC pins: 1 (10bit)
  • Flash Program memory: 256KB (8KB used by bootloader)
  • SRAM: 32KB
  • Transceivers: RFM69HCW, RFM95, RFM96
  • Low power: ~8uA in standby mode (FLASH and transceiver in deep sleep)

Memory & Bootloader

The MoteinoM0 runs the standard Arduino Zero bootloader – enhanced to allow flashing the memory from the external FLASH-MEM memory. This is similar/compatible with Dualoptiboot for AVR Moteinos and OTA/Wireless programming. The booloader is located in the first 8KB of internal flash memory and is protected by the NVM user byte fuse.

There is no dedicated EEPROM on the SAMD21 microcontroller but EEPROM can be emulated up to 16kb and the Arduino EEPROM library can be used to access this emulated EEPROM.

The M0 bootloader is available here for download if you wish to reinstall in on a M0 board using a SWD programmer (ex. Atmel ICE).

Pin reference

Schematic

Input voltage – VIN

Please note that on the first batch of PCBs, there is an error on the silkscreen next to the VIN pin, the input voltage when the MoteinoM0 is powered from the VIN pin, should be 3-6V (the limiting factor is the MCP73831 charger which can take no more than 6V). This error will be corrected in a future revision of the PCB, and current boards will ship with a small marking to cover the “1” in 3-16V:

Example reading the VIN

The sketch below illustrates how to read the input voltage (USB or battery). The MoteinoM0 has a simple voltage monitor connected to A5 throug a half (50%) voltage divider (see schematic). When the reading is around 1 schottky diode below 5V it means USB is connected. When the battery is connected in addition to USB, the reading is typically around 4.2V. When only the battery is connected, then A5 will read the actual battery voltage. Below is a sample of code to correctly read the voltage monitor through pin A5:

#if defined (MOTEINO_M0) && defined(SERIAL_PORT_USBVIRTUAL)
  #define Serial SERIAL_PORT_USBVIRTUAL // Required for Serial on Zero based boards
#endif

// the setup function runs once when you press reset or power the board
void setup() {
  Serial.begin(115200);
  pinMode(A5, INPUT);
}

// the loop function runs over and over again forever
void loop() {
  float vin = analogRead (A5) * 2 * 0.003226; // 0.003226 = 3.3 / 1023
  Serial.println(vin);
  delay(1000);                       // wait for a second
}

Solder Jumpers

There are 4 solder jumpers on the bottom of MoteinoM0. You can see each one in the schematic. Here’s a short explanation of each jumper’s function and (default state):

  • LED_EN (shorted): cut this open and the onboard LED is disconnected – a measn to save a little extra power, or use pin D13 for other purposes
  • DIODE_BYPASS (open): solder this jumper and you will short the Schottky diode that blocks current to flow back into the USB connector. This is experimental and should be left open.
  • VMON_EN A & B (both shorted): these two jumpers allow you to disconnect the onboard battery monitoring voltage divider circuit. Both should be the same state – either open or shorted. If you open them, then pin A5 will be available for other purposes.

Hardware / Driver install

To use MoteinoM0 with ArduinoIDE you will need to install the latest Arduino SAMD Boards package and then also the Moteino SAMD Boards package by LowPowerLab.

First add the Moteino core json definition URL to your Board Manager.

Then in Board Manager you will see AVR and SAMD boards by LowPowerLab.

If you’re on MAC or Linux you should not need any drivers. Also Windows 10 will probably detect the board as a virtual serial port and assign it a COM port by default without the need of installing a driver. Older Windows versions are likely going to fail to install a driver when MoteinoM0 is first plugged in. Click below to get the USB driver and unzip it to your Desktop or another folder. The ZIP file contains a screenshot walkthrough of how to install the driver.

Using with the ArduinoIDE

It’s important to understand how the board operates and how to enter the bootloader to ensure you can program it regardless what state the board is in. The bootloader behaves identically to the Arduino Zero samba bootloader, so if you’re familiar with that board, you should be all set.

If you load a low power sketch, or turn off the USB-Device (serial port) in your sketch, or even using certain sketches will cause the board to appear unresponsive to an Upload command while it’s in sleep mode or if it’s caught up doing other things. In such cases an Upload will fail from the IDE, and it’s necessary to do a fast double-tap on the RST button to put the board in bootloader mode. In some even more precarious situations where the board does to sleep immediately after boot, you might need to first do a single tap, then shortly after do the double-tap. You know you have entered the bootloader when the onboard LED is in a breathing pattern and a new serial port appears. Once there, select the new serial port, and try an Upload. There will be a delay until the board receives the sketch, or if you’re in a hurry you can jump start the upload by doing another double-tap. It’s only confusing until you manage to do this a few times!

Example deep sleep sketch

The sketch below illustrates how to put the MoteinoM0 to standby sleep (lowest power sleep), and optionally wake it from an external interrupt (active low on digital pin 0). It also puts the FLASH-MEM and transceiver (if any) to sleep.

//Standby sleep example for MoteinoM0 with external interrupt wakeup
//expected current in standby sleep: 7.5uA
const int pin = 0; //pin to use as interrupt (can be any digital pin)

//#define WITHRFM69  //comment this out if you don't have a radio installed on your MoteinoM0

#ifdef WITHRFM69
  #include <RFM69.h>    //get it here: https://www.github.com/lowpowerlab/rfm69
  #define NODEID        2   //must be unique for each node on same network (range up to 254, 255 is used for broadcast)
  #define NETWORKID     100  //the same on all nodes that talk to each other (range up to 255)
  #define GATEWAYID     1
  #define FREQUENCY     RF69_915MHZ
  #define IS_RFM69HW    //uncomment only for RFM69HW! Leave out if you have RFM69W!
  RFM69 radio;
#endif

#include <SPIFlash.h> //get it here: https://www.github.com/lowpowerlab/spiflash
SPIFlash flash(SS_FLASHMEM, 0xEF30); //EF30 for 4mbit  Windbond chip (W25X40CL)

//replace Serial with SerialUSB
#if defined (MOTEINO_M0)
  #if defined(SERIAL_PORT_USBVIRTUAL)
    #define Serial SERIAL_PORT_USBVIRTUAL // Required for Serial on Zero based boards
  #endif
#endif

void setup()
{
  Serial.begin(115200);
  delay(500);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(0, INPUT_PULLUP); //using internal pullup, makes pin 0 active low

  //Uses internal pullup eliminates the need for external resistor and makes interupt pin active low
  //If you need active high, then attach to HIGH and declare pin as INPUT without PULLUP, then use external resistor from GND to pin to keep it from floating
  attachInterrupt(pin, wakeupISR, LOW); //note: RISING and FALLING do not seem to work, use LOW or HIGH instead

  if (flash.initialize())
  {
    Serial.println("flash.init() OK, sleeping it...");
    flash.sleep();
  }
  else Serial.println("flash.init() FAIL");

#ifdef WITHRFM69
  if (!radio.initialize(FREQUENCY,NODEID,NETWORKID))
    Serial.println("radio.init() FAIL");
  else
    Serial.println("radio.init() SUCCESS");
  
  #ifdef IS_RFM69HW
    radio.setHighPower(); //uncomment only for RFM69HW!
  #endif
    radio.sleep();
#endif

  for (byte count=0; count < 3; count++)
  {
    Serial.print(".");
    blink(500);
  }
  Serial.println("Entering standby sleep mode...");
  delay(100);
}

void loop() 
{
  standbySleep();

  //interrupt happened: WAKE UP and blink the LED!
  blink(50);
}

void blink(int ms) {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(ms);
  digitalWrite(LED_BUILTIN, LOW);
  delay(ms);
}

byte toggle=true;
void wakeupISR(void)
{
  //nothing here, just a placeholder
}

void standbySleep() {
  //Disable USB (optional)
  //USBDevice.detach();

  //Standby - lowest power sleep mode
  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
  __DSB();
  __WFI(); // Wait For Interrupt call

  //Sleep until woken by interrupt...

  //Enable USB
  //USBDevice.attach();
}

Example periodic sleep using RTCZero library

The sketch below illustrates how to put the MoteinoM0 to sleep and wake it up periodically using the RTC (Real Time Clock timer). On a bare MoteinoM0 this sketch should achieve ~8.7uA while sleeping.

#include <RTCZero.h>

RTCZero zerortc;

// Set how often alarm goes off here
const byte alarmSeconds = 3;
const byte alarmMinutes = 0;
const byte alarmHours = 0;

volatile bool alarmFlag = false; // Start awake

#if defined (MOTEINO_M0)
  #if defined(SERIAL_PORT_USBVIRTUAL)
    #define Serial SERIAL_PORT_USBVIRTUAL // Required for Serial on Zero based boards
  #endif
#endif

void setup()
{
  Serial.begin(115200);
  delay(1000); // Wait for console
  
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  zerortc.begin(); // Set up clocks and such
  
  resetAlarm();  // Set alarm
  zerortc.attachInterrupt(alarmMatch); // Set up a handler for the alarm
}

void loop()
{
  if (alarmFlag == true) {
    alarmFlag = false;  // Clear flag
    digitalWrite(LED_BUILTIN, HIGH);
    Serial.println("Alarm went off - I'm awake!");
  }
  resetAlarm();  // Reset alarm before returning to sleep
  Serial.println("Alarm set, going to sleep now.");
  digitalWrite(LED_BUILTIN, LOW);
  zerortc.standbyMode();    // Sleep until next alarm match
}

void alarmMatch(void)
{
  alarmFlag = true; // Set flag
}

void resetAlarm(void) {
  byte seconds = 0;
  byte minutes = 0;
  byte hours = 0;
  byte day = 1;
  byte month = 1;
  byte year = 1;
  
  zerortc.setTime(hours, minutes, seconds);
  zerortc.setDate(day, month, year);

  zerortc.setAlarmTime(alarmHours, alarmMinutes, alarmSeconds);
  zerortc.enableAlarm(zerortc.MATCH_HHMMSS);
}

USB Device

MoteinoM0 can act like any USB device. It can emulate a keyboard or a joystick, a mouse or even a USB stick. You could prank a friend and plug a MoteinoM0 into their PC that simulates a keyboard, and remotely have another MoteinoM0 that hosts a real keyboard on which you can type (in that case it would act as a USB-Device, see below) and remotely type keys on your friend’s computer through the radio link, that would make quite a prank!

Check out the standard Arduino examples which provide samples to make the MoteinoM0 be a keyboard, mouse, or a combination of these:

USB Host

MoteinoM0 can also act like any USB-Host. It can host another USB-device on its USB-micro connector, via a USB-OTG adapter. Since USB devices require 5V, powering both the M0 and the attached USB-device from a LiPo battery (4v) is not enough, hence it is required to provide a stable 5V on the VUSB pin. The photo below illustrates how this wiring is achieved. The Keyboard could be replaced with any other USB device:

Here is a sample sketch that reads the inputs from the attached keyboard, and outputs them to the Serial port (pins 30,31):

/*
 Keyboard Controller Example

 Shows the output of a USB Keyboard connected to
 the USB-micro port (through USB-OTG adapter) on a MoteinoM0 board.
 See https://lowpowerlab.com/guide/moteino/moteinoM0/ for wiring
 Output is provided on the SERIAL_PORT_MONITOR, ie Serial port on pins 30,31

 created 8 Oct 2012 by Cristian Maglie
 adapted for MoteinoM0 by Felix Rusu (LowPowerLab.com)

 http://arduino.cc/en/Tutorial/KeyboardController

 This sample code is part of the public domain.
 */

// Require keyboard control library
#include <KeyboardController.h>

// Initialize USB Controller
USBHost usb;
#define LED LED_BUILTIN

// Attach keyboard controller to USB
KeyboardController keyboard(usb);

void printKey();

// This function intercepts key press
void keyPressed() {
  SERIAL_PORT_MONITOR.print("Pressed:  ");
  printKey();
}

// This function intercepts key release
void keyReleased() {
  SERIAL_PORT_MONITOR.print("Released: ");
  printKey();
}

void printKey() {
  digitalWrite(LED, HIGH); delay(10);
  // getOemKey() returns the OEM-code associated with the key
  SERIAL_PORT_MONITOR.print(" key:");
  SERIAL_PORT_MONITOR.print(keyboard.getOemKey());

  // getModifiers() returns a bits field with the modifiers-keys
  int mod = keyboard.getModifiers();
  SERIAL_PORT_MONITOR.print(" mod:");
  SERIAL_PORT_MONITOR.print(mod);

  SERIAL_PORT_MONITOR.print(" => ");

  if (mod & LeftCtrl)
    SERIAL_PORT_MONITOR.print("L-Ctrl ");
  if (mod & LeftShift)
    SERIAL_PORT_MONITOR.print("L-Shift ");
  if (mod & Alt)
    SERIAL_PORT_MONITOR.print("Alt ");
  if (mod & LeftCmd)
    SERIAL_PORT_MONITOR.print("L-Cmd ");
  if (mod & RightCtrl)
    SERIAL_PORT_MONITOR.print("R-Ctrl ");
  if (mod & RightShift)
    SERIAL_PORT_MONITOR.print("R-Shift ");
  if (mod & AltGr)
    SERIAL_PORT_MONITOR.print("AltGr ");
  if (mod & RightCmd)
    SERIAL_PORT_MONITOR.print("R-Cmd ");

  // getKey() returns the ASCII translation of OEM key
  // combined with modifiers.
  SERIAL_PORT_MONITOR.write(keyboard.getKey());
  SERIAL_PORT_MONITOR.println();
  digitalWrite(LED, LOW);
}

void setup()
{
  SERIAL_PORT_MONITOR.begin( 115200 );
  while (!SERIAL_PORT_MONITOR); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection
  SERIAL_PORT_MONITOR.println("Keyboard Controller Program started");

  if (usb.Init() == -1)
	  SERIAL_PORT_MONITOR.println("OSC did not start.");
  
  delay( 20 );
}

void loop()
{
  // Process USB tasks
  usb.Task();
}

Eagle library components

You can now use the Moteino Eagle library (Moteino.lbr) and drop-in Moteino layouts including MoteinoM0, straight into your design. Import the Moteino.lbr library in Eagle and add the recommended routing to accomodate the radio module mounted on the MoteinoM0 bottom (if any). This way you can flush-mount MoteinoM0 directly on your PCB, here is an example:

M0 Sensor Shields

There are now a few compact low-power sensor breakouts available that can flat-mount straight on the M0 PCB (bottom side).

BME280 Breakout

This breakout includes a BME280 sensor (same sensor as the popular WeatherShield):

Please see the WeatherShield guide for sample code.

LSM9DS1 9DoF IMU Breakout

There is now a 9D0F LSM9DS1 sensor breakout which includes 3 sensors in 1 chip – 3-axis accelerometer, 3-axis gyroscope and 3-axis magnetometer!

Here’s a sample sketch that you can use to get the various readings available from the LSM9DS1 sensors:

/*****************************************************************
SFE_LSM9DS1 Library Simple Example Code - I2C Interface
The LSM9DS1 is a versatile 9DOF sensor. It has a built-in
accelerometer, gyroscope, and magnetometer. Very cool!

This Arduino sketch is a demo of the simple side of the SFE_LSM9DS1 library.
It'll demo the following:
* How to create a LSM9DS1 object, using a constructor (global variables section).
* How to use the begin() function of the LSM9DS1 class.
* How to read the gyroscope, accelerometer, and magnetometer
  using the readGryo(), readAccel(), readMag() functions and 
  the gx, gy, gz, ax, ay, az, mx, my, and mz variables.
* How to calculate actual acceleration, rotation speed, 
  magnetic field strength using the calcAccel(), calcGyro() 
  and calcMag() functions.
* How to use the data from the LSM9DS1 to calculate
  orientation and heading.

This example demonstrates how to use I2C. The pin-out is as follows:
   LSM9DS1 --------- Moteino
	 SCL ------------- SCL (A5 on Moteino/Arduino)
	 SDA ------------- SDA (A4 on Moteino/Arduino)
	 VDD ------------- 3.3V
	 GND ------------- GND

The LSM9DS1 has a maximum voltage of 3.6V. Make sure you power it
off the 3.3V rail! I2C pins are open-drain, so you'll be 
(mostly) safe connecting the LSM9DS1's SCL and SDA pins 
directly to a Moteino/Arduino.

Code by Jim Lindblom @ SparkFun Electronics
Adapted for MoteinoM0 by Felix Rusu, LowPowerLab.com
Original Creation Date: April 30, 2015
Distributed as-is; no warranty is given.
*****************************************************************/
// The SFE_LSM9DS1 library requires both Wire and SPI be
// included BEFORE including the 9DS1 library.
#include <Wire.h>
#include <SPI.h>
#include <SparkFunLSM9DS1.h>

#ifdef MOTEINO_ZERO
  #ifdef SERIAL_PORT_USBVIRTUAL
    #define Serial SERIAL_PORT_USBVIRTUAL // Required for Serial on Zero based boards
  #endif
#endif

//////////////////////////
// LSM9DS1 Library Init //
//////////////////////////
// Use the LSM9DS1 class to create an object
LSM9DS1 imu;

///////////////////////
// Example I2C Setup //
///////////////////////
// SDO_XM and SDO_G are both pulled high, so our addresses are:
#define LSM9DS1_M	0x1E // Would be 0x1C if SDO_M is LOW
#define LSM9DS1_AG	0x6B // Would be 0x6A if SDO_AG is LOW

////////////////////////////
// Sketch Output Settings //
////////////////////////////
#define PRINT_CALCULATED
//#define PRINT_RAW
#define PRINT_SPEED 1000 // 250 ms between prints

// Earth's magnetic field varies by location. Add or subtract 
// a declination to get a more accurate heading. Calculate 
// your's here:
// http://www.ngdc.noaa.gov/geomag-web/#declination
#define DECLINATION -8.58 // Declination (degrees) in Boulder, CO.

#ifdef MOTEINO_ZERO
  #ifdef SERIAL_PORT_USBVIRTUAL
    #define Serial SERIAL_PORT_USBVIRTUAL // Required for Serial on Zero based boards
  #endif
#endif
  
void setup() 
{
  pinMode(LED_BUILTIN,OUTPUT);
  Serial.begin(115200);
  Wire.begin();
  delay(2000);
}

byte imuSetup() {
  // Before initializing the IMU, there are a few settings
  // we may need to adjust. Use the settings struct to set
  // the device's communication mode and addresses:
  imu.settings.device.commInterface = IMU_MODE_I2C;
  imu.settings.device.mAddress = LSM9DS1_M;
  imu.settings.device.agAddress = LSM9DS1_AG;
  // The above lines will only take effect AFTER calling
  // imu.begin(), which verifies communication with the IMU
  // and turns it on.
  if (!imu.begin())
  {
    Serial.println("Failed to communicate with LSM9DS1.");
    Serial.println("Double-check wiring.");
    Serial.println("Default settings in this sketch will " \
                  "work for an out of the box LSM9DS1 " \
                  "Breakout, but may need to be modified " \
                  "if the board jumpers are.");
    return false;
  }
  return true;
}

void loop()
{
  if (imuSetup()) {
    printGyro();  // Print "G: gx, gy, gz"
    printAccel(); // Print "A: ax, ay, az"
    printMag();   // Print "M: mx, my, mz"
    
    // Print the heading and orientation for fun!
    // Call print attitude. The LSM9DS1's magnetometer x and y axes are opposite to the accelerometer, so my and mx are substituted for each other.
    printAttitude(imu.ax, imu.ay, imu.az, -imu.my, -imu.mx, imu.mz);
    Serial.println();
  }
  delay(PRINT_SPEED);
  //imu.sleepGyro();
}

void printGyro()
{
  // To read from the gyroscope, you must first call the
  // readGyro() function. When this exits, it'll update the
  // gx, gy, and gz variables with the most current data.
  imu.readGyro();
  
  // Now we can use the gx, gy, and gz variables as we please.
  // Either print them as raw ADC values, or calculated in DPS.
  Serial.print("G: ");
#ifdef PRINT_CALCULATED
  // If you want to print calculated values, you can use the
  // calcGyro helper function to convert a raw ADC value to
  // DPS. Give the function the value that you want to convert.
  Serial.print(imu.calcGyro(imu.gx), 2);
  Serial.print(", ");
  Serial.print(imu.calcGyro(imu.gy), 2);
  Serial.print(", ");
  Serial.print(imu.calcGyro(imu.gz), 2);
  Serial.println(" deg/s");
#elif defined PRINT_RAW
  Serial.print(imu.gx);
  Serial.print(", ");
  Serial.print(imu.gy);
  Serial.print(", ");
  Serial.println(imu.gz);
#endif
}

void printAccel()
{
  // To read from the accelerometer, you must first call the
  // readAccel() function. When this exits, it'll update the
  // ax, ay, and az variables with the most current data.
  imu.readAccel();
  
  // Now we can use the ax, ay, and az variables as we please.
  // Either print them as raw ADC values, or calculated in g's.
  Serial.print("A: ");
#ifdef PRINT_CALCULATED
  // If you want to print calculated values, you can use the
  // calcAccel helper function to convert a raw ADC value to
  // g's. Give the function the value that you want to convert.
  Serial.print(imu.calcAccel(imu.ax), 2);
  Serial.print(", ");
  Serial.print(imu.calcAccel(imu.ay), 2);
  Serial.print(", ");
  Serial.print(imu.calcAccel(imu.az), 2);
  Serial.println(" g");
#elif defined PRINT_RAW 
  Serial.print(imu.ax);
  Serial.print(", ");
  Serial.print(imu.ay);
  Serial.print(", ");
  Serial.println(imu.az);
#endif
}

void printMag()
{
  // To read from the magnetometer, you must first call the
  // readMag() function. When this exits, it'll update the
  // mx, my, and mz variables with the most current data.
  imu.readMag();
  
  // Now we can use the mx, my, and mz variables as we please.
  // Either print them as raw ADC values, or calculated in Gauss.
  Serial.print("M: ");
#ifdef PRINT_CALCULATED
  // If you want to print calculated values, you can use the
  // calcMag helper function to convert a raw ADC value to
  // Gauss. Give the function the value that you want to convert.
  Serial.print(imu.calcMag(imu.mx), 2);
  Serial.print(", ");
  Serial.print(imu.calcMag(imu.my), 2);
  Serial.print(", ");
  Serial.print(imu.calcMag(imu.mz), 2);
  Serial.println(" gauss");
#elif defined PRINT_RAW
  Serial.print(imu.mx);
  Serial.print(", ");
  Serial.print(imu.my);
  Serial.print(", ");
  Serial.println(imu.mz);
#endif
}

// Calculate pitch, roll, and heading.
// Pitch/roll calculations take from this app note:
// http://cache.freescale.com/files/sensors/doc/app_note/AN3461.pdf?fpsp=1
// Heading calculations taken from this app note:
// http://www51.honeywell.com/aero/common/documents/myaerospacecatalog-documents/Defense_Brochures-documents/Magnetic__Literature_Application_notes-documents/AN203_Compass_Heading_Using_Magnetometers.pdf
void printAttitude(
float ax, float ay, float az, float mx, float my, float mz)
{
  float roll = atan2(ay, az);
  float pitch = atan2(-ax, sqrt(ay * ay + az * az));
  
  float heading;
  if (my == 0)
    heading = (mx < 0) ? 180.0 : 0;
  else
    heading = atan2(mx, my);

  heading -= DECLINATION * PI / 180;

  if (heading > PI) heading -= (2 * PI);
  else if (heading < -PI) heading += (2 * PI);
  else if (heading < 0) heading += 2 * PI;

  // Convert everything from radians to degrees:
  heading *= 180.0 / PI;
  pitch *= 180.0 / PI;
  roll  *= 180.0 / PI;
  
  Serial.print("Pitch, Roll: ");
  Serial.print(pitch, 2);
  Serial.print(", ");
  Serial.println(roll, 2);
  Serial.print("Heading: "); Serial.println(heading, 2);
}

SD-card Logger Breakout

Need a few gigs of logging memory to complement your MoteinoM0 or other wireless projects? It's no problem with this mini SD-card breakout which includes a power switch to put your SD-Card to sleep.

Here's a simple sketch for MoteinoM0 that will read the SD-Card content then sleep the SD card and everything else (radio, FLASH-MEM, if any) for sub 10uA sleep:

/*****************************************************************
 LowPowerLab SD-card Breakout Listfiles Example Sketch
 This example shows how to list the files on an SD card
 For MoteinoM0 this can be flat-mounted on the PCB, just align with SPI pins
 Wiring for use with other Moteinos/Arduinos using SPI bus:
  MOSI - pin 11
  MISO - pin 12
  CLK - pin 13
  CS - pin 4
*****************************************************************/
#include <SPI.h>
#include <SD.h>
#include <SPIFlash.h>         //get it here: https://www.github.com/lowpowerlab/spiflash
#include <RFM69.h>    //get it here: https://www.github.com/lowpowerlab/rfm69
/****************************************************************/
#define NODEID        2   //must be unique for each node on same network (range up to 254, 255 is used for broadcast)
#define NETWORKID     100  //the same on all nodes that talk to each other (range up to 255)
#define GATEWAYID     1
#define FREQUENCY     RF69_915MHZ
#define IS_RFM69HW_HCW //uncomment only for RFM69HW! Leave out if you have RFM69W!
/****************************************************************/
#ifdef MOTEINO_M0
  #define SD_CS    10
  #define SD_ON    11
#endif

#define BOARD_MOSI_PORT  (1)
#define BOARD_MOSI_PIN   (10)
#define BOARD_MISO_PORT  (0)
#define BOARD_MISO_PIN   (12)
#define BOARD_SCK_PORT   (1)
#define BOARD_SCK_PIN    (11)
//#define SS_PORT        (1)
//#define SS_PIN         (9)
#define SD_CS_PORT       (0)
#define SD_CS_PIN        (18)

RFM69 radio;  //#if defined (__AVR_ATmega32U4__) RFM69 radio(8,7);
SPIFlash flash(SS_FLASHMEM, 0xEF30); //EF30 for 4mbit  Windbond chip (W25X40CL)
File root;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(SS_FLASHMEM, OUTPUT);
  pinMode(A2, OUTPUT);
  pinMode(SD_CS, OUTPUT);
  pinMode(SD_ON, OUTPUT);
  digitalWrite(SS_FLASHMEM, HIGH);
  digitalWrite(A2, HIGH);
  digitalWrite(SD_CS, HIGH);
  digitalWrite(SD_ON, HIGH);

  Serial.begin(115200);
  delay(5000);

  if (radio.initialize(FREQUENCY,NODEID,NETWORKID))
  {
    Serial.println("Radio init OK, putting it to sleep...");
    radio.sleep();
  }
  else {
    Serial.println("Radio init fail, moving on...");
    //return;
  }

  if (flash.initialize())
  {
    Serial.println("Flash-MEM init OK, putting it to sleep...");
    flash.sleep();
  }
  else {
    Serial.println("Flash init fail, moving on...");
    //return;
  }

  digitalWrite(SD_ON, LOW); //SD power ON

  if (SD.begin(SD_CS))
  {
    Serial.println("SD card init OK, listing content...");
    root = SD.open("/");
    printDirectory(root, 0);
    Serial.println("done!");
  }
  else {
    Serial.println("SD card init fail, moving on");
    //return;
  }

  digitalWrite(LED_BUILTIN, HIGH);
  Serial.println("Sleeping MCU in 3 seconds...");
  delay(3000);
  
  digitalWrite(LED_BUILTIN, LOW);
  digitalWrite(SD_ON, HIGH); //SD power OFF

  //reset SD CS direction to ensure there is no drainage
  PORT->Group[SD_CS_PORT].OUTCLR.reg = (1<<SD_CS_PIN);
  PORT->Group[SD_CS_PORT].DIRCLR.reg = (1<<SD_CS_PIN);
  PORT->Group[BOARD_MOSI_PORT].PINCFG[BOARD_MOSI_PIN].reg = 0;

  Serial.flush();
  delay(5000);
    
  standbySleep(); //puts the M0 to "forever" deep sleep for lowest power sleep mode
}

void loop() {
  //nothing here
}

void printDirectory(File dir, int numTabs) {
  while (true) {

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println("/");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}

void standbySleep() {
    // Set sleep mode
  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;

  //Disable USB
  USB->DEVICE.CTRLA.reg &= ~USB_CTRLA_ENABLE;

  //Enter sleep mode
  __WFI();

  //...Sleep forever

  //Enable USB
  USB->DEVICE.CTRLA.reg |= USB_CTRLA_ENABLE;
}

As can be seen in the commented code, here are the required connections for this breakout (also marked on the silkscreen):

  • SPI pins (MI, MO, SCK, CS)
  • power (3V, GND)
  • EN (power enable) - this needs to go LOW as in the sample code to provide power to the SD card
  • CD (card detect) - this one has an OPEN solder jumper, this pin is not commonly used

Nothing stops you to mount all three of the above breakouts on a single Moteino M0, just be careful to align the pins correctly!

Transceivers

Here is a quick side by side comparison of different HopeRF radio transceivers. There are different aspects of compatibility between them which we discuss below.

If you’re new to these transceivers, please take a few minutes to watch this in depth overview packed with tips and a quick usage guide:

For the transceivers to work properly with the RFM69 library, you must always check the radio settings in your sketch. Particularly the RFM69HW and RFM69HCW radios require invoking radio.setHighPower() after radio.init() (usually controlled by the #define IS_RFM69HW_HCW directive), see how this pattern is implemented in the library examples. For RFM69W & RFM69CW you should *not* call radio.setHighPower() – ie comment out the #define IS_RFM69HW_HCW line. Doing this incorrectly will result in no wireless range and can even damage your transceiver!

All Moteinos now accept these types of transceivers:

What is the difference between W/CW/HW?

The W/CW/HW are different configurations of the same Semtech SX1231h transceiver chip (custom packaging by HopeRF). They come in different transmission power and frequency variants. For instance the W and CW are 13dBm power output. The HW and HCW are 20dBm power output.

All RFM69 radios can communicate with each other regardless of their configuration/layout (as long as the above settings are correctly set) when their network ID and encryption (optional) keys match. Their node IDs should be unique, the RFM69 library supports up to 255 nodes per network. The broadcast address is 255, sending a message to that node ID=255 will make all listening nodes receive that message.

Pin compatibility

The W and HW are pin compatible. The HCW are only pin compatible with the RFM95/96 LoRa radios. The CW radios are pin compatible with the older RFM12B.

Code/settings compatibility

The W and CW are equivalent in coding and settings usage, and same is true for the HW and HCW. In fact, the only setting difference between W/CW and HW/HCW is the very important #define IS_RFM69HW_HCW directive discussed above.

Frequency markings

Since it’s not easy to distinguish between the same radio of different frequencies (except marked on the bottom by HopeRF), LowPowerLab has its own marking convention for the transceivers to quickly identify frequency once they are soldered to Moteinos. The 433mhz radios are marked with a gold dot. The 868/915mhz are marked with a silver dot. Other vendors also mark their HopeRF radios but have different colors.

RFM69 and RFM95/96 LoRa compatibility

RFM95 and RFM96 are *not* compatible with RFM69 and require a 3rd party library, see the LoRa page for details. However RFM6 (HCW only) and RFM95/96 LoRa radios are pin compatible, enabling them to share the same mounting pads.

Chip marking confusion between RFM95 and RFM96

RFM95 and RFM96 can be confused because they both have a chip marked with “RF96“. They are in fact different, as can be noticed in the photo above. Although the chip is the same, the components are mounted differently, reflecting their different frequency operation. The markings on the back of the module also makes this distinction.

What about RFM12B?

RFM12B can be used on Moteino/MoteinoUSB/MoteinoMEGA but this radio is not supported for new development and older code/library is only kept for reference.

LoRa support

Since 2015 Moteino also supports LoRa transceivers:

The LoRa technology from Semtech brings exceptional features like high reception sensitivity and spread spectrum modulation allowing these radios to dramatically increase range at low bitrates, while still operating at a battery friendly output power (20dBm/100mW) and ultra low power sleep mode. These radios also support FSK modulations but they are intended to be used with the LoRa (Long Range) modulation technology and as such they will only be supported by LowPowerLab in that operation mode. This also implies they cannot communicate with any RFM69 radios (except via a bridge module between two such networks is built). In other words, they are a completely different type of radio for a different category of communications.

While Moteinos are pin compatible with all LoRa radios (RFM92-RFM98), the LowPowerLab Shop carries the RFM95 (868-915mhz) and RFM96 (434mhz).

Long range possibilities of LoRa

For an in-depth technical review of this technology please see this great instructable. Here’s how the LoRa modulation looks like:Here’s a test performed at 1000bps (see instructable for more details):

Library & usage of LoRa modules with MoteinoMEGA & MoteinoM0

The recommended library to use with RFM95/95 LoRa modules can be downloaded here (this should be installed like any other library under your Arduino/libraries folder). This the popular RadioHead library by Mike McCauley. The examples to get started with are under examples/rf95: rf95_server and rf95_client. Choose your Moteino target under Arduino>Tools>Board and upload the examples to your Moteino. Note that the LED is on D15 (MoteinoMEGA) and D9 (all other Moteinos). If you have an RFM95 then set frequency to 915Mhz, for RFM96 use 434Mhz. For details and documentation visit the official RadioHead library page.

For MoteinoMEGA, the SPI slave select pin is digital pin 4, and radio interrupt pin is digital pin 2. If you use the original RadioHead library you must call the constructor like this with MoteinoMEGA (complete reference here):

RH_RF95 rf95(4); //SPI CS init with MoteinoMEGA

For MoteinoM0 you must call the constructor like this:

RH_RF95 rf95(A2, 9); //SPI CS init with MoteinoM0

RadioHead library (patched)

You may also download a patched version of RadioHead v1.121 which ensures the default constructor works with all Moteino boards including MoteinoMEGA, MoteinoM0, RFGatewayM4. The previous patched RadioHead library v1.116 is also available.

If you use IDE 1.0.6 or older and having trouble compiling the latest RadioHead, you may try this older archived version of RadioHead.

Programming & libraries

For programming any LowPowerLab boards, you need to install the Moteino package in your Arduino IDE – this includes definitions for all Moteino boards, MightyHat, CurrentRanger etc. First add the Moteino core json definition URL to your Board Manager.

Then in Board Manager you will see AVR and SAMD boards by LowPowerLab.

For AVR based Moteinos and MightyHat you need to install the Moteino AVR Boards package. For MoteinoM0 you need to install the Moteino SAMD Boards.

For SAMD based boards (ex. MoteinoM0, CurrentRanger) you need to also ensure you have the official Arduino SAMD Boards package installed in your Arduino IDE (in addition to the Moteino SAMD Boards package):

Once the required packages are installed the new boards will show in your Tools>Boards menu:

There is now a programming guide for Moteinos which helps you get started with libraries and programming in Arduino IDE, please check it out if you are new to Arduino. Quick steps to programming in the Arduino IDE:

  • First, you need to download and install the necessary libraries in your Arduino/libraries folder: RFM69 library, SPIFlash library, you can use the Arduino Library Manager (unde Tools > Manage Libraries menu) to install the latest version of these libraries:
  • For RFM95/96 LoRa radios please see the LoRa section of this guide
  • Get started with RFM69 example sketches: Sender and Receiver
  • To upload a sketch, select Moteino in the Tools>Boards menu in the Arduino IDE, and the serial port emulated by your FTDI-Adapter or USB-serial adapter in Tools>Serial Port. Note that choosing Arduino Uno as the target board should also work for AVR Moteinos based on Atmega328, but some pin definitions (like the LED_BUILTIN) are different.
An FTDI-Adapter that can be used to program Moteinos (non USB variants). If you have any board with built in USB (ex. MoteinoUSB, MoteinoMEGA-USB, MoteinoM0) a separate FTDI-Adapter is not necessary

The VIN pin of AVR Moteinos is shared with the VIN pin on the FTDI header. If you power your Moteino externally from the VIN pin, make sure to disconnect the external source when you attach the FTDI-Adapter!

The FTDI header has silkscreen markings for the GND and DTR pins to help you align your FTDI Adapter (black and green wires respectively on the FTDI cable). Usually the PCB based FTDI adapters also have the same markings on their end (see the FTDI Adapter).

The Moteino can be used like Arduino, but for wireless communications you will need a library for the RFM69 transceiver. You can use the official RFM69 library for RFM69 Moteinos, it has a suite of examples to get you started.  The simplest way is to start with the Node and Gateway examples. For RFM95/96 LoRa transceivers please see this section for more details. See this official tutorial on installing Arduino libraries if you’re not sure how to install an Arduino library.

Wireless programming

All Moteinos come with the DualOptiboot bootloader which enables them to be wirelessly programmed when the FLASH MEM chip is installed (also available separately).

The wireless programming protocol is generic and supported by all Moteinos with DualOptiboot and FLASH Memory option, but the example implementation was only done for RFM69 transceivers

You will need to program a Moteino with a sketch that listens to such wireless programming commands first before it can be programmed over the air. There’s a proof of concept and source code described in this blog post.

A Windows desktop GUI app is available to make wireless programming easy. This program is available here at Gihub. The sample programmer and target sketches that support the wireless programming are in the RFM69 library. Here’s the GUI interface:Here’s a rundown of the features:

  • gives you a list of available serial ports so you don’t have to guess (you still have to know which serial port your wireless programmer Moteino is connected to)
  • allows you to type/paste or browse for a hex file
  • allows a numeric target node ID
  • once all controls are populated with valid info, the Start! button is enabled
  • upon exit, it saves the settings to registry and attempts to read them back in future launches

Using python instead of desktop app

You can now use the OTA.py python script cross platform which does the same thing as the Windows application except it needs to be passed command line arguments (com port, baud, hex file etc) – type python OTA.py -help for details. The OTA.py script is now bundled and can be invoked in the Windows application.

Antenna options

If you are new to RF and Antennas, consider reading this RF Best Practices guide for a basic understanding of wireless and radio technology

Moteinos are provided with a 1/4 wavelength Monopole wire that should be soldered to the ANT pin. Each frequency has a specific antenna wire length. You should not use the transceivers without any antenna attached or there will be no range and you risk damaging them. The default basic Monopole wire has an excellent performance to cost ratio. You may have increased performance and signal strength using a Dipole antenna (1/2 wavelength).

There is now a wideband PCB Dipole available for 868-915mhz:

 

You can also solder SMA or U.FL connectors and hook up other types of antennas:

On older Moteinos you can carefully solder u.FL or SMA connectors between the ANT pin and GND:

Range is difficult to specify or estimate because signal propagation is influenced by factors, including the radio software parameters. Range tests are typically performed in open air. Note that atmospheric conditions can also have an impact on signal propagation (humidity, rain, snow etc). Even with the simple Monopole antenna, the range can reach beyond a mile in open air.

RFM69HCW is a higher power version of RFM69CW (20dBm vs. just 13dBm) and thus it can reach significantly further. Other users have done some experiments and have reported various ranges:

Here is an example range test of 2.5Km with stock Moteinos and some interesting BiQuad antennas, build details in the forum:

  

FLASH-MEM option

The FLASH-MEM option was introduced in Moteino R2 to allow SPI flash memory (SOIC JEDEC 3.9/5.3mm body width package) to be added to Moteinos primarily for wireless programming (but can be used as non-volatile storage for any purpose). There is an SPIFlash library just for using this memory chip. The SPI CS select for this is connected to D8 on all Moteinos (D23 on MoteinoMEGAs).

The chip shipped on all Moteinos is the Windbond 4mbit W25X40CLSNIG. Higher capacities are available upon request for custom batches.

The DualOptiboot bootloader allows you to reflash the program from a flash image stored on the external FLASH MEM chip (wirelessly programming it). See this blog post for how wireless programming is achieved using DualOptiboot and more details. This is the pinout of the FLASH MEM chip used on all Moteinos:

FLASH_pinout

Why flash chips and not SD cards that come in much larger sizes at low cost? Because of the size and power constraints, an SD card slot would increase the cost. A separate SD-card Moteino shield would be more appropriate for an SD card add-on.

Revision history

  • Moteino R4 – same as R3 except it can take RFM69W/HW transceivers. It replaces R3 and R2. Includes the FLASH-MEM option, comes with DualOptiboot, and has a full GND pour on both sides. Also ENIG lead-free finish. Needs an FTDI Adapter for programming.
  • Moteino R5-USB – same as regular Moteino but has built in USB serial bridge which allows direct programming through a mini-USB cable without a separate FTDI Adapter.
  • MoteinoMEGA – Moteino based on atmega1284p with 128KB of internal flash and 16KB of RAM for the most memory demanding sketches. A bunch more IO and an extra hardware serial port make it the ideal choice for for more complex projects.
  • MoteinoLR and MoteinoMEGA-LoRa – Same as other Moteinos, except they work with RFM95/96 LoRa and RFM69HCW radios, see the LoRa page for more details.
  • R3 – same as R2 except with support for the new RFM69W/HW transceivers. Includes the FLASH memory footprint and loaded with a modified Optiboot bootloader (DualOptiboot) to allow wireless programming.
    Moteino_R3_banner 
  • Moteino R2 – Green mass produced PCBs. Includes the FLASH memory footprint. Loaded with a modified Optiboot bootloader (DualOptiboot).
    Moteino_R2Moteino_r2_bunch
  • Moteino R1 – The first Moteino revision. These were produced at OSHPark (purple), did not include a FLASH footprint, and had slightly different bootloader and fuse settings. Some early orders received this version.
    Moteino_front_back2Moteino_assembledMoteino_with_RFM12B
  • MoteinoLeo (discontinued) – Arduino Leonardo variant based on the ATMega32u4 chip and Caterina bootloader. It has been discontinued, but you can find some of the the design files on Github. For the initial prototype details click here.
    MoteinoLeo_R1_withFlashMoteinoLeo_bottom_compared_small

Design files

Schematics

You can also find Eagle format board layout and DXF in the Moteino Github repository. The schematics for MoteinoUSB is available in PDF format.

Mechanical / dimensional drawings

Eagle library components

You can now use the Moteino Eagle library (Moteino.lbr) and drop-in Moteino layouts including MoteinoM0, straight into your design. Import the Moteino.lbr library in Eagle and add the recommended routing to accomodate the radio module mounted on the Moteino bottom (if any). Here is an example PCB showing a MoteinoM0 that can be flush-mounted directly on the PCB:

CAD model

There is now a CAD model for the Moteino-TraceAnt here:

And here’s one for MoteinoMEGA-TraceAnt here:

Fritzing components

Thanks to the generous contribution of Donnie Plumly there are now Fritzing Parts available for Moteino. Check out this Github repository for the details. Here’s a video he put together that shows how he actually built the Moteino part in Fritzing:

Side note: although Fritzing is not the best PCB layout software, some folks find it visually appealing to start laying out a circuit in Fritzing and perhaps build a PCB from that if the schematic and routing requirements are pretty basic. It’s great for illustrations and getting started with basic schematic and circuit layout.

 

MISC

How Moteinos are made

In the present all Moteinos are machine assembled on a pick and place and reflowed in a 3-zone conveyor SMT reflow oven. Watch this video lapse of a MoteinoMEGA panel assembly:

In the beginning…

… there was a lot of hand picking and placing. Moteinos were hand assembled using various tools that I built to make the job easier and faster. For instance I perfected a method to make soda-can SMD metal stencils and spread solder paste to the bare PCBs. Back then stencils were still expensive. I then placed the SMD components using a manual home-made PnP (pick and place) apparatus. I reflowed the boards in a toaster oven following a reflow profile, and hand solder the transceivers on the bottom. I then set the fuses and load the bootloader using a programming jig. Many thousands of early revision Moteinos were made this way.

apply pastebakeprogramming jig

Here’s a video of some hand assembly action:

Moteino first revision & 3rd party reviews