# Adafruit Feather M0 Radio with RFM69 Packet Radio

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/033/510/medium800/feather_3176_iso_ORIG.jpg?1467236319)

This is the **Adafruit Feather M0 RFM69 Packet Radio (433 or 900 MHz)**&nbsp;- our take on an microcontroller with a 433 or 868/915 MHz radio module cooked in! Great for making wireless networks that can go further than 2.4GHz 802.15.4 and similar, are more flexible than Bluetooth LE and without the high power requirements of WiFi. [We have other boards in the Feather family, check'em out here](https://www.adafruit.com/feather)

At the Feather M0's heart is an ATSAMD21G18 ARM Cortex M0 processor, clocked at 48 MHz and at 3.3V logic, the same one used in the new [Arduino Zero](https://www.adafruit.com/products/2843). This chip has a whopping 256K of FLASH (8x more than the Atmega328 or 32u4) and 32K of RAM (16x as much)! This chip comes with built in USB so it has USB-to-Serial program & debug capability built in with no need for an FTDI-like chip.

To make it easy to use for portable projects, we added a connector for any of our 3.7V Lithium polymer batteries and built in battery charging. You don't need a battery, it will run just fine straight from the micro USB connector. But, if you do have a battery, you can take it on the go, then plug in the USB to recharge. The Feather will automatically switch over to USB power when its available. We also tied the battery thru a divider to an analog pin, so you can measure and monitor the battery voltage to detect when you need a recharge.

![](https://cdn-learn.adafruit.com/assets/assets/000/033/507/medium800/feather_3176_iso_demo_ORIG.jpg?1467235497)

 **Here's some handy specs! Like all Feather M0's you get:**

- Measures 2.0" x 0.9" x 0.3" (51mm x 23mm x 8mm) without headers soldered in
- Light as a (large?) feather - 5.8 grams
- ATSAMD21G18 @ 48MHz with 3.3V logic/power
- No EEPROM
- 3.3V regulator with 500mA peak current output
- USB native support, comes with USB bootloader and serial port debugging
- You also get tons of pins - 20 GPIO pins
- Hardware Serial, hardware I2C, hardware SPI support
- 8 x PWM pins
- 10 x analog inputs
- 1 x analog output
- Built in 100mA lipoly charger with charging status indicator LED
- Pin #13 red LED for general purpose blinking
- Power/enable pin
- 4 mounting holes
- Reset button

![](https://cdn-learn.adafruit.com/assets/assets/000/033/509/medium800/feather_3176_quarter_ORIG_.jpg?1467235521)

The&nbsp; **Feather M0 Radio** uses the extra space left over to add an RFM69HCW 433 or 868/915 MHz radio module. These radios are not good for transmitting audio or video, but they do work quite well for small data packet transmission when you ned more range than 2.4 GHz (BT, BLE, WiFi, ZigBee)

- SX1231 based module with SPI interface
- Packet radio with ready-to-go Arduino libraries
- Uses the amateur or [license-free ISM bands](https://en.wikipedia.org/wiki/ISM_band): 433MHz is ITU "Europe" license-free ISM or ITU "American" amateur with limitations. 900MHz is license-free ISM for ITU "Americas"
- +13 to +20 dBm up to 100 mW Power Output Capability (power output selectable in software)
- Create multipoint networks with individual node addresses
- Encrypted packet engine with AES-128
- Simple wire antenna or spot for uFL connector

![](https://cdn-learn.adafruit.com/assets/assets/000/033/508/medium800/feather_3176_kit_ORIG.jpg?1467235510)

Comes fully assembled and tested, with a USB bootloader that lets you quickly use it with the Arduino IDE. We also toss in some header so you can solder it in and plug into a solderless breadboard. You will need to cut and solder on a small piece of wire (any solid or stranded core is fine) in order to create your antenna. **Lipoly battery and USB cable not included** but we do have lots of options in the shop if you'd like!

# Adafruit Feather M0 Radio with RFM69 Packet Radio

## Pinouts

![](https://cdn-learn.adafruit.com/assets/assets/000/131/239/medium800/adafruit_products_rfm69-100.jpg?1720808438)

[Click here to view a PDF version of the pinout diagram](https://github.com/adafruit/Adafruit-Feather-M0-RFM-LoRa-PCB/blob/master/Adafruit%20Feather%20M0%20RFM69%20Pinout.pdf)

![](https://cdn-learn.adafruit.com/assets/assets/000/131/238/medium800/adafruit_products_lora-100.jpg?1720808337)

[Click here to view a PDF version of the pinout diagram](https://github.com/adafruit/Adafruit-Feather-M0-RFM-LoRa-PCB/blob/master/Adafruit%20Feather%20M0%20RFM9x%20Pinout.pdf)

The Feather M0 Radio is chock-full of microcontroller goodness. There's also a lot of pins and ports. We'll take you a tour of them now!

Note that the pinouts are identical for both the Feather M0 RFM69 and LoRa radios - you can look at the silkscreen of the Feather to see it says "RFM69" or "LoRa"

Pinouts are also the same for both 433MHz and 900Mhz. You can tell the difference by looking for a colored dot on the chip or crystal of the radio, green/blue is 900MHz & red is 433MHz

![](https://cdn-learn.adafruit.com/assets/assets/000/032/897/medium800/feather_pinouts.jpg?1465414204)

# Power Pins
![](https://cdn-learn.adafruit.com/assets/assets/000/032/898/medium800/feather_powerpins.jpg?1465414248)

- **GND** - this is the common ground for all power and logic
- **BAT** - this is the positive voltage to/from the JST jack for the optional Lipoly battery
- **USB** - this is the positive voltage to/from the micro USB jack if connected
- **EN** - this is the 3.3V regulator's enable pin. It's pulled up, so connect to ground to disable the 3.3V regulator
- **3V** - this is the output from the 3.3V regulator, it can supply 500mA peak

# Logic pins
![](https://cdn-learn.adafruit.com/assets/assets/000/032/900/medium800/feather_logic.jpg?1465414311)

This is the general purpose I/O pin set for the microcontroller.   
**All logic is 3.3V**  
**Nearly all pins can do PWM output**  
**All pins can be interrupt inputs**

- **#0 / RX** - GPIO #0, also receive (input) pin for **Serial1** (hardware UART), also can be analog input
- **#1 / TX** - GPIO #1, also transmit (output) pin for **Serial1** ,&nbsp;also can be analog input   
- **#20 / SDA&nbsp;** - GPIO #20, also the I2C (Wire) data pin. There's no pull up on this pin by default so when using with I2C, you may need a 2.2K-10K pullup.
- **#21 / SCL** - GPIO #21, also the I2C (Wire) clock pin. There's no pull up on this pin by default so when using with I2C, you may need a 2.2K-10K pullup.
- **#5** - GPIO #5
- **#6** - GPIO #6
- **#9** - GPIO #9, also analog input **A7**. This analog input is connected to a voltage divider for the lipoly battery so be aware that this pin naturally 'sits' at around 2VDC due to the resistor divider
- **#10** - GPIO #10
- **#11** - GPIO #11
- **#12** - GPIO #12
- **#13** - GPIO #13 and is connected to the **red LED** next to the USB jack
- **A0** - This pin is analog _input_ **A0** but is also an analog _output_ due to having a DAC (digital-to-analog converter). You can set the raw voltage to anything from 0 to 3.3V, unlike PWM outputs this is a true analog output
- **A1 thru A5** - These are each analog input as well as digital I/O pins.
- **SCK/MOSI/MISO** (GPIO **24/23/22** )- These are the hardware SPI pins, you can use them as everyday GPIO pins (but recommend keeping them free as they are best used for hardware SPI connections for high speed.

# RFM/SemTech Radio Module
![](https://cdn-learn.adafruit.com/assets/assets/000/032/901/medium800/feather_rfm.jpg?1465414468)

Since not all pins can be brought out to breakouts, due to the small size of the Feather, we use these to control the radio module

- **#8** - used as the radio **CS** (chip select) pin
- **#3** - used as the radio **GPIO0** / **IRQ** (interrupt request) pin.
- **#4** - used as the radio **Reset** pin

Since these are not brought out there should be no risk of using them by accident!

There are also breakouts for 4 of the RFM's GPIO pins ( **IO1, IO2, IO3** and **IO5** ). You probably wont need these for most uses of the Feather but they are available in case you need 'em!

Danger: 

# Other Pins!
![](https://cdn-learn.adafruit.com/assets/assets/000/032/902/medium800/feather_others.jpg?1465415106)

- **RST** - this is the Reset pin, tie to ground to manually reset the AVR, as well as launch the bootloader manually
- **ARef** - the analog reference pin. Normally the reference voltage is the same as the chip logic voltage (3.3V) but if you need an alternative analog reference, connect it to this pin and select the external AREF in your firmware. Can't go higher than 3.3V!

# Adafruit Feather M0 Radio with RFM69 Packet Radio

## Assembly

We ship Feathers fully tested but without headers attached - this gives you the most flexibility on choosing how to use and configure your Feather

# Header Options!

Before you go gung-ho on soldering, there's a few options to consider!

The first option is soldering in plain male headers, this lets you plug in the Feather into a solderless breadboard

![feather_3010-05.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/192/medium640/feather_3010-05.jpg?1454100293)

![feather_3010-01.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/201/medium640/feather_3010-01.jpg?1454100690)

Another option is to go with socket female headers. This won't let you plug the Feather into a breadboard but it will let you attach featherwings very easily

A few Feather boards require access to top-side components like buttons or connectors, making stacking impractical. Sometimes you can stack in the opposite order—FeatherWing underneath—or, if _both_ Feather and Wing require top-side access,&nbsp;place the boards side-by-side with a [FeatherWing Doubler](https://www.adafruit.com/product/2890) or [Tripler](https://www.adafruit.com/product/3417).

![feather_2886-01.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/195/medium640/feather_2886-01.jpg?1454100431)

![feather_2886-02.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/196/medium640/feather_2886-02.jpg?1454100477)

![adafruit_products_2890-02.jpg](https://cdn-learn.adafruit.com/assets/assets/000/117/300/medium640/adafruit_products_2890-02.jpg?1672855047)

We also&nbsp; have 'slim' versions of the female headers, that are a little shorter and give a more compact shape

![feather_2940-01.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/197/medium640/feather_2940-01.jpg?1454100533)

![feather_2940-04.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/198/medium640/feather_2940-04.jpg?1454100544)

Finally, there's the "Stacking Header" option. This one is sort of the best-of-both-worlds. You get the ability to plug into a solderless breadboard _and_ plug a featherwing on top. But its a little bulky

![feather_2830-01.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/199/medium640/feather_2830-01.jpg?1454100588)

![feather_2830-00.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/200/medium640/feather_2830-00.jpg?1454100660)

# Soldering in Plain Headers
## Prepare the header strip:

Cut the strip to length if necessary. It will be easier to solder if you insert it into a breadboard - **long pins down**

![feather_headers.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/183/medium640/feather_headers.jpg?1454099573)

## Add the breakout board:

Place the breakout board over the pins so that the short pins poke through the breakout pads

## And Solder!

Be sure to solder all pins for reliable electrical contact.  
  
_(For tips on soldering, be sure to check out our_ [_Guide to Excellent Soldering_](http://learn.adafruit.com/adafruit-guide-excellent-soldering)_)._

![feather_solder1.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/184/medium640/feather_solder1.jpg?1454099592)

![feather_solder2.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/185/medium640/feather_solder2.jpg?1454099649)

![feather_solder3.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/186/medium640/feather_solder3.jpg?1454099655)

Solder the other strip as well.

![feather_solder4.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/187/medium640/feather_solder4.jpg?1454099662)

![feather_solder5.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/188/medium640/feather_solder5.jpg?1454099665)

![feather_solder6.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/189/medium640/feather_solder6.jpg?1454099667)

You're done! Check your solder joints visually and continue onto the next steps

![feather_done.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/190/medium640/feather_done.jpg?1454099807)

# Soldering on Female Header
## Tape In Place

For sockets you'll want to tape them in place so when you flip over the board they don't fall out

![feather_taped.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/203/medium640/feather_taped.jpg?1454101091)

## Flip & Tack Solder

After flipping over, solder one or two points on each strip, to 'tack' the header in place

![feather_tack1.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/204/medium640/feather_tack1.jpg?1454101126)

![feather_tack2.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/205/medium640/feather_tack2.jpg?1454101143)

![feather_tack3.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/206/medium640/feather_tack3.jpg?1454101147)

## And Solder!

Be sure to solder all pins for reliable electrical contact.  
  
_(For tips on soldering, be sure to check out our_ [_Guide to Excellent Soldering_](http://learn.adafruit.com/adafruit-guide-excellent-soldering)_)._

![feather_soldre1.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/207/medium640/feather_soldre1.jpg?1454101162)

![feather_solder2.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/208/medium640/feather_solder2.jpg?1454101165)

![feather_solder3.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/209/medium640/feather_solder3.jpg?1454101168)

You're done! Check your solder joints visually and continue onto the next steps

![feather_soldered.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/210/medium640/feather_soldered.jpg?1454101174)

![feather_done.jpg](https://cdn-learn.adafruit.com/assets/assets/000/030/211/medium640/feather_done.jpg?1454101177)

# Adafruit Feather M0 Radio with RFM69 Packet Radio

## Antenna Options

![](https://cdn-learn.adafruit.com/assets/assets/000/122/013/medium800/feather_boards_RPRFM95_antenna.png?1687370550)

Your Feather Radio does not have a built-in antenna. Instead, you have two options for attaching an antenna. For most low cost radio nodes, a short length of wire works great. If you need to put the Feather into an enclosure, soldering on a uFL connector (on Feathers that don’t already include this) and using a uFL to SMA adapter will let you attach an external antenna.

# Wire Antenna

A wire antenna, aka "quarter wave whip antenna" is low cost and works very well! You just have to cut the wire down to the right length.

Cut a stranded or solid core wire to the proper length for the module/frequency:

- **433 MHz** - 6.5 inches, or 16.5 cm
- **868 MHz** - 3.25 inches or 8.2 cm
- **915 MHz** - 3 inches or 7.8 cm

![feather_antennaready.jpg](https://cdn-learn.adafruit.com/assets/assets/000/031/583/medium640/feather_antennaready.jpg?1459963405)

Strip a mm or two off the end of the wire, tin and solder into the **ANT** pad on the very right hand edge of the Feather.

![feather_antennasolder.jpg](https://cdn-learn.adafruit.com/assets/assets/000/031/584/medium640/feather_antennasolder.jpg?1459963419)

That's pretty much it, you're done!

![feather_antennadone.jpg](https://cdn-learn.adafruit.com/assets/assets/000/031/585/medium640/feather_antennadone.jpg?1459963446)

# uFL Antenna

If you want an external antenna, you need to do a tiny bit more work but its not too difficult.

For Feather Radio boards that don’t already have a surface-mount **uFL connector** installed, [you’ll need to get one](https://www.adafruit.com/products/1661). _Feather RP2040 RFM boards already have this installed. Feather M0 and 32u4 require soldering._

[You'll also need a **uFL to SMA adapter**](https://www.adafruit.com/products/851) (or whatever adapter you need for the antenna you'll be using, SMA is the most common).

Of course, you will also need an **antenna** of some sort, one that matches your radio frequency.

Warning: 

### For Feather M0 and 32u4:

_(this step can be skipped for Feather RP2040 RFM, which already has a uFL connector installed)_

Check the bottom of the uFL connector, note that there's two large side pads (ground) and a little inlet pad. The other small pad is not used!

![feather_uflcheck.jpg](https://cdn-learn.adafruit.com/assets/assets/000/031/587/medium640/feather_uflcheck.jpg?1459964602)

Solder all three pads to the bottom of the Feather

![feather_ufl2.jpg](https://cdn-learn.adafruit.com/assets/assets/000/031/588/medium640/feather_ufl2.jpg?1459964646)

![feather_ufl3.jpg](https://cdn-learn.adafruit.com/assets/assets/000/031/589/medium640/feather_ufl3.jpg?1459964649)

### For all radio-capable Feather boards:
Once done attach your uFL adapter and antenna!

![feather_antennaattach.jpg](https://cdn-learn.adafruit.com/assets/assets/000/031/590/medium640/feather_antennaattach.jpg?1459964666)

# Adafruit Feather M0 Radio with RFM69 Packet Radio

## Power Management

![](https://cdn-learn.adafruit.com/assets/assets/000/113/564/medium800/wireless_feather_3178_iso_demo_ORIG.jpg?1658868160)

# Battery + USB Power

We wanted to make our Feather boards easy to power both when connected to a computer as well as via battery.

There's **two ways to power** a Feather:

1. You can connect with a USB cable (just plug into the jack) and the Feather will regulate the 5V USB down to 3.3V.
2. You can also connect a 4.2/3.7V Lithium Polymer (LiPo/LiPoly) or Lithium Ion (LiIon) battery to the JST jack. This will let the Feather run on a rechargeable battery.

**When the USB power is powered, it will automatically switch over to USB for power, as well as start charging the battery (if attached).** This happens 'hot-swap' style so you can always keep the LiPoly connected as a 'backup' power that will only get used when USB power is lost.

Danger: 

![](https://cdn-learn.adafruit.com/assets/assets/000/113/565/medium800/wireless_feather_psupp.jpg?1658868187)

The above shows the Micro USB jack (left), LiPoly JST jack (top left), as well as the 3.3V regulator and changeover diode (just to the right of the JST jack) and the LiPoly charging circuitry (to the right of the Reset button).

There's also a **CHG** LED next to the USB jack, which will light up while the battery is charging. This LED might also flicker if the battery is not connected, it's normal.

Info: 

# Power Supplies

You have a lot of power supply options here! We bring out the **BAT** pin, which is tied to the LiPoly JST connector, as well as **USB** which is the +5V from USB if connected. We also have the **3V** pin which has the output from the 3.3V regulator. We use a 500mA peak regulator. While you can get 500mA from it, you can't do it continuously from 5V as it will overheat the regulator.

It's fine for, say, powering an ESP8266 WiFi chip or XBee radio though, since the current draw is 'spikey' & sporadic.

![](https://cdn-learn.adafruit.com/assets/assets/000/113/566/medium800/wireless_feather_powerpins.jpg?1658868236)

# Measuring Battery

If you're running off of a battery, chances are you wanna know what the voltage is at! That way you can tell when the battery needs recharging. LiPoly batteries are 'maxed out' at 4.2V and stick around 3.7V for much of the battery life, then slowly sink down to 3.2V or so before the protection circuitry cuts it off. By measuring the voltage you can quickly tell when you're heading below 3.7V.

To make this easy we stuck a double-100K resistor divider on the&nbsp; **BAT** &nbsp;pin, and connected it to&nbsp; **D9** &nbsp;(a.k.a analog #7&nbsp; **A7** ). You can read this pin's voltage, then double it, to get the battery voltage.

```cpp
#define VBATPIN A7
   
float measuredvbat = analogRead(VBATPIN);
measuredvbat *= 2;    // we divided by 2, so multiply back
measuredvbat *= 3.3;  // Multiply by 3.3V, our reference voltage
measuredvbat /= 1024; // convert to voltage
Serial.print("VBat: " ); Serial.println(measuredvbat);
```

![](https://cdn-learn.adafruit.com/assets/assets/000/113/567/medium800/wireless_feather_pin9.jpg?1658868280)

# ENable pin

If you'd like to turn off the 3.3V regulator, you can do that with the **EN** (able) pin. Simply tie this pin to **Ground** and it will disable the 3V regulator. The **BAT** and **USB** pins will still be powered.

![](https://cdn-learn.adafruit.com/assets/assets/000/113/568/medium800/wireless_feather_enpin.jpg?1658868345)

# Alternative Power Options

The two primary ways for powering a feather are a 3.7/4.2V LiPo battery plugged into the JST port _or_ a USB power cable.

If you need other ways to power the Feather, here's what we recommend:

- For permanent installations, a [5V 1A USB wall adapter](https://www.adafruit.com/product/501) will let you plug in a USB cable for reliable power
- For mobile use, where you don't want a LiPoly, [use a USB battery pack!](https://www.adafruit.com/product/1959)
- If you have a higher voltage power supply, [use a 5V buck converter](https://www.adafruit.com/?q=5V%20buck) and wire it to a [USB cable's 5V and GND input](https://www.adafruit.com/product/3972)

Here's what you cannot do:

- **Do not use alkaline or NiMH batteries** and connect to the battery port - this will destroy the LiPoly charger
- **Do not use 7.4V RC batteries on the battery port** - this will destroy the board

The Feather _is not designed for external power supplies_ - this is a design decision to make the board compact and low cost. It is not recommended, but technically possible:

- **Connect an external 3.3V power supply to the 3V and GND pins.** Not recommended, this may cause unexpected behavior and the **EN** pin will no longer work. Also this doesn't provide power on **BAT** or **USB** and some Feathers/Wings use those pins for high current usages. You may end up damaging your Feather.
- **Connect an external 5V power supply to the USB and GND pins.** Not recommended, this may cause unexpected behavior when plugging in the USB port because you will be back-powering the USB port, which _could_ confuse or damage your computer.

# Radio Power Draw

You can select the power output you want via software, more power equals more range but of course, uses more of your battery.

For example, here is the Feather M0 with RFM69HCW set up for +20dBm power, transmitting a data payload of 20 bytes

The ~25mA quiescent current is the current draw for listening (~15mA) plus ~10mA for the microcontroller. This can be reduce to amost nothing with proper sleep modes and not putting the module in active listen mode!

![](https://cdn-learn.adafruit.com/assets/assets/000/113/606/medium800/wireless_feather_nosleeptx.png?1658944419)

Here is a transmit with&nbsp;`radio.setPowerLevel(0)`&nbsp;to set +5dBm power

You still have the 25mA average, but during transmit, it only uses another 20mA not 100mA

If you put the radio to sleep after transmitting with&nbsp;`radio.sleep();`&nbsp;rather than just sitting in receive mode, you can save more current, after transmit is complete, the average current drops to ~10mA which is just for the microcontroller

![](https://cdn-learn.adafruit.com/assets/assets/000/113/607/medium800/wireless_feather_radiosleep.png?1658944444)

# Adafruit Feather M0 Radio with RFM69 Packet Radio

## Arduino IDE Setup

The first thing you will need to do is to download the latest release of the Arduino IDE. You will need to&nbsp;be using **version 1.8** or higher for this guide

[Arduino IDE Download](http://www.arduino.cc/en/Main/Software)
After you have downloaded and installed **the latest version of Arduino IDE** , you will need to start the IDE&nbsp;and navigate to&nbsp;the **Preferences** menu. You can access it from the **File** menu in _Windows_ or _Linux_, or the **Arduino** menu on _OS X_.

![](https://cdn-learn.adafruit.com/assets/assets/000/041/549/medium800/flora_prefs.png?1494204209)

A dialog will pop up just like the one shown below.

![](https://cdn-learn.adafruit.com/assets/assets/000/108/455/medium800/trinket_arduino-preferences-before.png?1643387570)

We will be adding a URL to the new **Additional Boards Manager URLs** option. The list of URLs is comma separated, and _you will only have to add each&nbsp;URL once._&nbsp;New Adafruit boards and updates to existing boards&nbsp;will automatically be picked up&nbsp;by the Board Manager each time&nbsp;it is opened. The URLs point to index files that the Board Manager uses to build the list of available & installed boards.

To find the most up to date list of URLs you can&nbsp;add, you can visit the list of [third party board URLs on the Arduino IDE wiki](https://github.com/arduino/Arduino/wiki/Unofficial-list-of-3rd-party-boards-support-urls#list-of-3rd-party-boards-support-urls). We will only need to add one URL to the IDE in this example, but _ **you can add multiple URLS by separating them with commas** _. Copy and paste the link below into the&nbsp; **Additional Boards Manager URLs** option in the Arduino IDE preferences.

### `https://adafruit.github.io/arduino-board-index/package_adafruit_index.json`
![](https://cdn-learn.adafruit.com/assets/assets/000/108/456/medium800/trinket_arduino-preferences.png?1643387643)

Here's a short description of each of the Adafruit supplied packages that will be available in the Board Manager when you add the URL:

- **Adafruit AVR Boards** - Includes support for Flora, Gemma, Feather 32u4, ItsyBitsy 32u4, Trinket, & Trinket Pro.
- **Adafruit SAMD Boards** - Includes support for Feather M0 and M4, Metro M0 and M4, ItsyBitsy M0 and M4, Circuit Playground Express, Gemma M0 and Trinket M0
- **Arduino Leonardo & Micro MIDI-USB** - This adds MIDI over USB support for the Flora, Feather 32u4, Micro and Leonardo using the [arcore project](https://github.com/rkistner/arcore).

If you have multiple boards you want to support, say ESP8266 and Adafruit, have both URLs in the text box separated by a comma (,)

Once done click **OK** to save the new preference settings. Next we will look at installing boards with the Board Manager.

Now continue to the next step to actually install the board support package!

# Adafruit Feather M0 Radio with RFM69 Packet Radio

## Using with Arduino IDE

Adafruit boards that use ATSAMD21 ("M0") or ATSAMD51 ("M4") chips are easy to get working with the Arduino IDE. Most libraries (including the popular ones like NeoPixels and display) will work with those boards, especially devices & sensors that use I2C or SPI.

Now that you have added the appropriate URLs to the Arduino IDE preferences in the previous page, you can open the **Boards Manager** by navigating to the **Tools-\>Board** &nbsp;menu.

![](https://cdn-learn.adafruit.com/assets/assets/000/028/791/medium800/adafruit_products_boardmanager.png?1448652571)

Once the Board Manager opens, click on the category drop down menu on the top left hand side of the window and select **All**. You will then be able to select and install the boards supplied&nbsp;by the URLs added to the preferences.

Warning: 

# Install SAMD Support

First up, install the latest **Arduino SAMD Boards (**version **1.6.11&nbsp;** or later)

You can type **Arduino SAMD** in the top search bar, then when you see the entry, click **Install**

![](https://cdn-learn.adafruit.com/assets/assets/000/028/792/medium800/adafruit_products_arduinosamd162.png?1448652786)

# Install Adafruit SAMD

Next you can install the Adafruit SAMD package to add the board file definitions

Make sure you have **Type All** selected to the left of the _Filter your search..._ box

You can type **Adafruit SAMD** in the top search bar, then when you see the entry, click **Install**

![](https://cdn-learn.adafruit.com/assets/assets/000/028/794/medium800/adafruit_products_adafruitsamd.png?1448652973)

 **Quit and reopen&nbsp;the Arduino IDE** to ensure that all of the boards are properly installed. You should now be able to select and upload to the new boards listed in the **Tools-\>Board** menu.

Select the matching board, the current options are:

- **Feather M0** (for use with any Feather M0 other than the Express)
- **Feather M0 Express**
- **Metro M0 Express**
- **Circuit Playground Express**  
- **Gemma M0**
- **Trinket M0**  
- **QT Py M0**  
- **ItsyBitsy M0**
- **Hallowing M0**
- **Crickit M0** (this is for direct programming of the Crickit, which is probably not what you want! For advanced hacking only)
- **Metro M4 Express**
- **Grand Central M4 Express**
- **ItsyBitsy M4 Express**
- **Feather M4 Express**
- **Trellis M4 Express**
- **PyPortal M4**
- **PyPortal M4 Titano**
- **PyBadge M4 Express**
- **Metro M4 Airlift Lite**
- **PyGamer M4 Express**
- **MONSTER M4SK**
- **Hallowing M4**
- **MatrixPortal M4**
- **BLM Badge**

![](https://cdn-learn.adafruit.com/assets/assets/000/053/074/medium800/adafruit_products_availboards.png?1524019356)

## Windows 7 and 8.1
Warning: **Windows 7 and Windows 8.1** have reached end-of-life and are no longer supported. They required driver installation. A [limited set of drivers is available for older boards](https://github.com/adafruit/Adafruit_Windows_Drivers/releases), but drivers for most newer boards are not available.

# Blink

Now you can upload your first blink sketch!

Plug in the SAMD21 M0 or SAMD51 M4 board, and wait for it to be recognized by the OS (just takes a few seconds). It will create a serial/COM port, you can now select it from the drop-down, it'll even be 'indicated' as Trinket/Gemma/Metro/Feather/ItsyBitsy/QT Py/Trellis or whatever the board is named!

Info: A few boards, such as the QT Py SAMD21, Trellis M4 Express, and certain Trinkey boards, do not have an onboard pin 13 LED. You can follow this section to practice uploading but you won't see an LED blink!

![](https://cdn-learn.adafruit.com/assets/assets/000/028/796/medium800/adafruit_products_comport.png?1448653712)

Now load up the Blink example

```
// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin 13 as an output.
  pinMode(13, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);              // wait for a second
  digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);              // wait for a second
}
```

And click upload! That's it, you will be able to see the LED blink rate change as you adapt the **delay()** calls.

Info: 

# Successful Upload

If you have a successful upload, you'll get a bunch of red text that tells you that the device was found and it was programmed, verified & reset

![](https://cdn-learn.adafruit.com/assets/assets/000/028/797/medium800/adafruit_products_uploading.png?1448653908)

After uploading, you may see a message saying "Disk Not&nbsp;Ejected&nbsp;Properly" about the ...BOOT drive. You can ignore that message: it's an artifact of how the bootloader and uploading work.

# Compilation Issues

If you get an alert that looks like

**Cannot run program "{runtime.tools.arm-none-eabi-gcc.path}\bin\arm-non-eabi-g++"**

Make sure you have installed the **Arduino SAMD** boards package, you need _both_ Arduino & Adafruit SAMD board packages

![](https://cdn-learn.adafruit.com/assets/assets/000/028/798/medium800/adafruit_products_gppnotfound.png?1448653960)

# Manually bootloading

If you ever get in a 'weird' spot with the bootloader, or you have uploaded code that crashes and doesn't auto-reboot into the bootloader, click the **RST** button **twice** (like a double-click)to get back into the bootloader.

**The red LED will pulse and/or RGB LED will be green, so you know that its in bootloader mode.**

Once it is in bootloader mode, you can select the newly created COM/Serial port and re-try uploading.

![](https://cdn-learn.adafruit.com/assets/assets/000/028/799/medium800/adafruit_products_bootloadport.png?1448654424)

You may need to go back and reselect the 'normal' USB serial port next time you want to use the normal upload.

# Ubuntu&nbsp;& Linux Issue Fix

&nbsp;[Follow the steps for installing Adafruit's udev rules on this page.](../../../../adafruit-arduino-ide-setup/linux-setup#udev-rules)

# Adafruit Feather M0 Radio with RFM69 Packet Radio

## Feather HELP!

Info: 

### 

A lot of our example sketches have a

`while (!Serial);`

line in setup(), to keep the board waiting until the USB is opened. This makes it a lot easier to debug a program because you get to see all the USB data output. If you want to run your Feather without USB connectivity, delete or comment out that line

### 

 **A**  **vast number of Itsy/Feather 'failures' are due to charge-only USB cables**

We get upwards of 5 complaints a day that turn out to be due to charge-only cables!

Use only a cable that you **know** is for data syncing

If you have any charge-only cables, cut them in half throw them out. We are serious! They tend to be low quality in general, and will only confuse you and others later, just get a good data+charge USB cable.

A quality USB port is critical. Avoid plugging into USB keyboards and when possible use a USB-2 HUB to avoid USB3 issues.&nbsp;

### 

No problem! You can 'repair' a bad code upload easily. Note that this can happen if you set a watchdog timer or sleep mode that stops USB, or any sketch that 'crashes' your board

1. Turn on **verbose upload** in the Arduino IDE preferences
2. Plug in Itsy or Feather 32u4/M0, it won't show up as a COM/serial port that's ok
3. Open up the Blink example (Examples-\>Basics-\>Blink)
4. Select the correct board in the Tools menu, e.g. Feather 32u4, Feather M0, Itsy 32u4 or M0 _(physically check_ your board to make sure you have the right one selected!)
5. Compile it (make sure that works)
6. Click Upload to attempt to upload the code
7. The IDE will print out a bunch of COM Ports as it tries to upload. **During this time, double-click the reset button, you'll see the red pulsing LED that tells you its now in bootloading mode**  
8. The board will show up as the Bootloader COM/Serial port
9. The IDE should see the bootloader COM/Serial port and upload properly

![](https://cdn-learn.adafruit.com/assets/assets/000/029/525/medium800/adafruit_products_comfound.png?1452109739)

### 

This seems to happen when people select the wrong board from the Arduino Boards menu.

If you have a Feather 32u4 (look on the board to read what it is you have) Make sure you select **Feather 32u4** for ATMega32u4 based boards! Do not use anything else, do not use the 32u4 breakout board line.

If you have a Feather M0 (look on the board to read what it is you have) Make sure you select **Feather M0** - do not use 32u4 or Arduino Zero

If you have a ItsyBitsy M0 (look on the board to read what it is you have) Make sure you select **ItsyBitsy M0** - do not use 32u4 or Arduino Zero

### 

Theres **two** COM ports you can have with the 32u4/M0, one is the **user port** and one is the **bootloader port**. They are not the same COM port number!

When you upload a new user program it will come up with a user com port, particularly if you use Serial in your user program.

**If you crash your user program, or have a program that halts or otherwise fails, the user COM port can disappear.**

**When the user COM port disappears, Arduino will not be able to automatically start the bootloader and upload new software.**

So you will need to help it by performing the click-during upload procedure to re-start the bootloader, and upload something that is known working like "Blink"

### 

UNO-type Arduinos have a _seperate_ serial port chip (aka "FTDI chip" or "Prolific PL2303" etc etc) which handles all serial port capability seperately than the main chip. This way if the main chip fails, you can always use the COM port.

M0 and 32u4-based Arduinos do not have a seperate chip, instead the main processor performs this task for you. It allows for a lower cost, higher power setup...but requires a little more effort since you will need to 'kick' into the bootloader manually once in a while

### 

This is likely because the bootloader is not kicking in and you are accidentally **trying to upload to the**  **wrong COM port**

The best solution is what is detailed above: manually upload Blink or a similar working sketch by hand by manually launching the bootloader

### 

You probably don't have Feather M0 selected in the boards drop-down. Make sure you selected Feather M0.

### 

You probably don't have Feather M0 / Feather 32u4 selected in the boards drop-down. Make sure you selected Feather M0 (or Feather 32u4).

### 

Make sure your Wing doesn't use pin #9 which is the analog sense for the lipo battery!

### 

The charge LED is automatically driven by the Lipoly charger circuit. It will try to detect a battery and is expecting one to be attached. If there isn't one it may flicker once in a while when you use power because it's trying to charge a (non-existant) battery.

It's not harmful, and its totally normal!

 **The Arduino IDE gives me "Device Descriptor Request Failed"**

This can require "manual bootloading".

If you ever get in a 'weird' spot with the bootloader, or you have uploaded code that crashes and doesn't auto-reboot into the bootloader, **double-click the RST** button to get back into the bootloader. The red LED will pulse, so you know that its in bootloader mode. Do the reset button double-press right as the Arduino IDE says its attempting to upload the sketch, when you see the Yellow Arrow lit and the **Uploading...** text in the status bar.

[![microcomputers_adafruit_products_uploading.gif](https://cdn-learn.adafruit.com/assets/assets/000/028/444/medium800/microcomputers_adafruit_products_uploading.gif?1447995220)](/assets/28444)

Don't click the reset button **before** uploading, unlike other bootloaders you want this one to run at the time Arduino is trying to upload

# Adafruit Feather M0 Radio with RFM69 Packet Radio

## Adapting Sketches to M0 & M4

The ATSAMD21 and 51 are very nice little chips, but fairly new as Arduino-compatible cores go. **Most** sketches & libraries will work but here’s a collection of things we noticed.

The notes below cover a range of Adafruit M0 and M4 boards, but not every rule will apply to every board (e.g. Trinket and Gemma M0 do not have ARef, so you can skip the Analog References note!).

# Analog References

If you'd like to use the **ARef** pin for a non-3.3V analog reference, the code to use is `analogReference(AR_EXTERNAL)` (it's AR\_EXTERNAL not EXTERNAL)

# Pin Outputs & Pullups

The old-style way of turning on a pin as an input with a pullup is to use

`pinMode(pin, INPUT)``digitalWrite(pin, HIGH)`

This is because the pullup-selection register on 8-bit AVR chips is the same as the output-selection register.

For M0 & M4 boards, you can't do this anymore! Instead, use:

`pinMode(pin, INPUT_PULLUP)`

Code written this way still has the benefit of being _backwards compatible with AVR._ You don’t need separate versions for the different board types.

# Serial vs SerialUSB

99.9% of your existing Arduino sketches use **Serial.print** to debug and give output. For the Official Arduino SAMD/M0 core, this goes to the Serial5 port, which isn't exposed on the Feather. The USB port for the Official Arduino M0 core is called _ **SerialUSB** _ instead.

In the Adafruit M0/M4 Core, we fixed it so that **Serial goes to USB so it will automatically work just fine**.

**However, on the off chance you are using the official Arduino SAMD core and _not_ the Adafruit version (which really, we recommend you use our version because it’s been tuned to our boards), and you want your Serial prints and reads to use the USB port, use _SerialUSB_ instead of _Serial_ in your sketch.**

If you have existing sketches and code and you want them to work with the M0 without a huge find-replace, put

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

**right above the first** function definition in your code. For example:

![](https://cdn-learn.adafruit.com/assets/assets/000/028/800/medium800/adafruit_products_serialusb.png?1448655245)

# AnalogWrite / PWM on Feather/Metro M0

After looking through the SAMD21 datasheet, we've found that some of the options listed in the multiplexer table don't exist on the specific chip used in the Feather M0.

For all SAMD21 chips, there are two peripherals that can generate PWM signals: The Timer/Counter (TC) and Timer/Counter for Control Applications (TCC). Each SAMD21 has multiple copies of each, called 'instances'.

Each TC instance has one count register, one control register, and two output channels. Either channel can be enabled and disabled, and either channel can be inverted. The pins connected to a TC instance can output identical versions of the same PWM waveform, or complementary waveforms.

Each TCC instance has a single count register, but multiple compare registers and output channels. There are options for different kinds of waveform, interleaved switching, programmable dead time, and so on.

The biggest members of the SAMD21 family have five TC instances with two 'waveform output' (WO) channels, and three TCC instances with eight WO channels:

- TC[0-4],WO[0-1]
- TCC[0-2],WO[0-7]

And those are the ones&nbsp;shown in the datasheet's multiplexer tables.

The SAMD21G used in the Feather M0 only has three TC instances with two output channels, and three TCC instances with eight&nbsp;output channels:

- **TC[3-5],WO[0-1]**
- **TCC[0-2],WO[0-7]**

Tracing the signals to the pins broken out on the Feather M0, the following pins can't do PWM at all:

- **Analog pin A5**

The following pins can be configured for PWM without any signal conflicts as long as the SPI, I2C, and UART pins keep their protocol functions:

- **Digital pins 5, 6, 9, 10, 11, 12, and 13**
- **Analog pins A3 and A4**

If only the SPI pins keep their protocol functions, you can also do PWM on the following pins:

- **TX and SDA (Digital pins 1 and 20)**

# analogWrite() PWM range

On AVR, if you set a pin's PWM with `analogWrite(pin, 255)` it will turn the pin fully HIGH. On the ARM cortex, it will set it to be 255/256 so there will be very slim but still-existing pulses-to-0V. If you need the pin to be fully on, add test code that checks if you are trying to `analogWrite(pin, 255)` and, instead, does a `digitalWrite(pin, HIGH)`

# analogWrite() DAC on A0

If you are trying to use `analogWrite()` to control the DAC output on **A0** , make sure you do **not** have a line that sets the pin to output. _ **Remove** _: `pinMode(A0, OUTPUT)`.

# serialEvent() and serialEvent1()

`serialEvent()` and&nbsp;`serialEvent1()`&nbsp;[do not work](https://www.arduino.cc/reference/en/language/functions/communication/serial/serialevent/) on any non-AVR Arduino boards. Use `Serial.available()` instead.

# Missing header files

There might be code that uses libraries that are not supported by the M0 core. For example if you have a line with

`#include <util/delay.h>`

you'll get an error that says

`fatal error: util/delay.h: No such file or directory  #include <util/delay.h>                         ^compilation terminated.Error compiling.`

In which case you can simply locate where the line is (the error will give you the file name and line number) and 'wrap it' with #ifdef's so it looks like:

```
#if !defined(ARDUINO_ARCH_SAM) &amp;&amp; !defined(ARDUINO_ARCH_SAMD) &amp;&amp; !defined(ESP8266) &amp;&amp; !defined(ARDUINO_ARCH_STM32F2)
 #include &lt;util/delay.h&gt;
#endif
```

The above will also make sure that header file isn't included for other architectures

If the #include is in the arduino sketch itself, you can try just removing the line.

# Bootloader Launching

For most other AVRs, clicking **reset** while plugged into USB will launch the bootloader manually, the bootloader will time out after a few seconds. For the M0/M4, you'll need to **_double click_** the button. You will see a pulsing red LED to let you know you're in bootloader mode. Once in that mode, it wont time out! Click reset again if you want to go back to launching code.

# Aligned Memory Access

This is a little less likely to happen to you but it happened to me! If you're used to 8-bit platforms, you can do this nice thing where you can typecast variables around. e.g.

`uint8_t mybuffer[4];`  
`float f = (float)mybuffer;`

You can't be guaranteed that this will work on a 32-bit platform because **mybuffer** might not be aligned to a 2 or 4-byte boundary. The ARM Cortex-M0 can only directly access data on 16-bit boundaries (every 2 or 4 bytes). Trying to access an odd-boundary byte (on a 1 or 3 byte location) will cause a Hard Fault and stop the MCU. Thankfully, there's an easy work around ... just use memcpy!

`uint8_t mybuffer[4];float f;memcpy(&f, mybuffer, 4)`

# Floating Point Conversion

Like the AVR&nbsp;Arduinos, the M0 library does not have full support for converting floating point numbers to ASCII strings. Functions like sprintf will not convert floating point. &nbsp;Fortunately, the standard AVR-LIBC library includes the dtostrf function which can handle the conversion for you.

Unfortunately, the M0 run-time library does not have dtostrf. &nbsp;You may see some references to using **#include \<avr/dtostrf.h\>** to get dtostrf in your code. &nbsp;And while it will compile, it does **not** work.

Instead, check out this thread to find a working dtostrf&nbsp;function you can include in your code:

[http://forum.arduino.cc/index.php?topic=368720.0](http://forum.arduino.cc/index.php?topic=368720.0)

# How Much RAM Available?

The ATSAMD21G18 has 32K of RAM, but you still might need to track it for some reason. You can do so with this handy function:

```
extern "C" char *sbrk(int i);

int FreeRam () {
  char stack_dummy = 0;
  return &amp;stack_dummy - sbrk(0);
}
```

Thx to [http://forum.arduino.cc/index.php?topic=365830.msg2542879#msg2542879](http://forum.arduino.cc/index.php?topic=365830.msg2542879#msg2542879) for the tip!

# Storing data in FLASH

If you're used to AVR, you've probably used **PROGMEM** to let the compiler know you'd like to put a variable or string in flash memory to save on RAM. On the ARM, its a little easier, simply add **const** before the variable name:

**const char str[] = "My very long string";**

That string is now in FLASH. You can manipulate the string just like RAM data, the compiler will automatically read from FLASH so you dont need special progmem-knowledgeable functions.

You can verify where data is stored by printing out the address:  
**Serial.print("Address of str $"); Serial.println((int)&str, HEX);**

If the address is $2000000 or larger, its in SRAM. If the address is between $0000 and $3FFFF Then it is in FLASH

# Pretty-Printing out registers

There's _a lot_ of registers on the SAMD21, and you often are going through ASF or another framework to get to them. So having a way to see exactly what's going on is handy. This library from drewfish will help a ton!

[https://github.com/drewfish/arduino-ZeroRegs](https://github.com/drewfish/arduino-ZeroRegs)

# M4 Performance Options

As of version 1.4.0 of the _Adafruit SAMD Boards_ package in the Arduino Boards Manager, some options are available to wring extra performance out of M4-based devices. These are in the _Tools_ menu.

![](https://cdn-learn.adafruit.com/assets/assets/000/074/814/medium800/adafruit_products_m4-performance.png?1556044075)

 **All of these performance tweaks involve a degree of uncertainty.** There’s _no guarantee_ of improved performance in any given project, and _some may even be detrimental,_ failing to work in part or in whole. If you encounter trouble, **select the default performance settings** and re-upload.

Here’s what you get and some issues you might encounter…

## CPU Speed (overclocking)

This option lets you adjust the microcontroller core clock…the speed at which it processes instructions…beyond the official datasheet specifications.

Manufacturers often rate speeds conservatively because such devices are marketed for harsh industrial environments…if a system crashes, someone could lose a limb or worse. But most creative tasks are less critical and operate in more comfortable settings, and we can push things a bit if we want more speed.

There is a small but nonzero chance of code **locking up** or **failing to run** entirely. If this happens, try **dialing back the speed by one notch and re-upload** , see if it’s more stable.

Much more likely, **some code or libraries may not play well** with the nonstandard CPU speed. For example, currently the NeoPixel library assumes a 120 MHz CPU speed and won’t issue the correct data at other settings (this will be worked on). Other libraries may exhibit similar problems, usually anything that strictly depends on CPU timing…you might encounter problems with audio- or servo-related code depending how it’s written. **If you encounter such code or libraries, set the CPU speed to the default 120 MHz and re-upload.**

## Optimize

There’s usually more than one way to solve a problem, some more resource-intensive than others. Since Arduino got its start on resource-limited AVR microcontrollers, the C++ compiler has always aimed for the **smallest compiled program size**. The “Optimize” menu gives some choices for the compiler to take different and often faster approaches, at the expense of slightly larger program size…with the huge flash memory capacity of M4 devices, that’s rarely a problem now.

The “ **Small** ” setting will compile your code like it always has in the past, aiming for the smallest compiled program size.

The “ **Fast** ” setting invokes various speed optimizations. The resulting program should produce the same results, is slightly larger, and usually (but not always) noticably faster. It’s worth a shot!

“ **Here be dragons** ” invokes some more intensive optimizations…code will be larger still, faster still, but there’s a possibility these optimizations could cause unexpected behaviors. _Some code may not work the same as before._ Hence the name. Maybe you’ll discover treasure here, or maybe you’ll sail right off the edge of the world.

Most code and libraries will continue to function regardless of the optimizer settings. If you do encounter problems, **dial it back one notch and re-upload**.

## Cache

This option allows a small collection of instructions and data to be accessed more quickly than from flash memory, boosting performance. It’s enabled by default and should work fine with all code and libraries. But if you encounter some esoteric situation, the cache can be disabled, then recompile and upload.

## Max SPI and Max QSPI

**These should probably be left at their defaults.** They’re present mostly for our own experiments and can cause **serious headaches**.

Max SPI determines the clock source for the M4’s SPI peripherals. Under normal circumstances this allows transfers up to 24 MHz, and should usually be left at that setting. But…if you’re using write-only SPI devices (such as TFT or OLED displays), this option lets you drive them faster (we’ve successfully used 60 MHz with some TFT screens). The caveat is, if using _any_ read/write devices (such as an SD card), _this will not work at all…_SPI reads&nbsp;_absolutely_ max out at the default 24 MHz setting, and anything else will fail. **Write = OK. Read = FAIL.** This is true _even if your code is using a lower bitrate setting…_just having the different clock source prevents SPI reads.

Max QSPI does similarly for the extra flash storage on M4 “Express” boards. _Very few_ Arduino sketches access this storage at all, let alone in a bandwidth-constrained context, so this will benefit next to nobody. Additionally, due to the way clock dividers are selected, this will only provide some benefit when certain “CPU Speed” settings are active. Our [PyPortal Animated GIF Display](https://learn.adafruit.com/pyportal-animated-gif-display) runs marginally better with it, if using the QSPI flash.

# Enabling the Buck Converter on some M4 Boards

If you want to reduce power draw, some of our boards have an inductor so you can use the 1.8V buck converter instead of the built in linear regulator. If the board does have an inductor (see the schematic) you can add the line `SUPC->VREG.bit.SEL = 1;` to your code to switch to it. Note it will make ADC/DAC reads a bit noisier so we don't use it by default. [You'll save ~4mA](https://github.com/adafruit/ArduinoCore-samd/issues/128).

# Adafruit Feather M0 Radio with RFM69 Packet Radio

## Using the RFM69 Radio

This page is shared between the RFM69 breakout and the all-in-one Feather RFM69's. The example code and overall functionality is the same, only the pinouts used may differ! Just make sure the example code is using the pins you have wired up.

![feather_adafruit_products_3070_iso_ORIG.jpg](https://cdn-learn.adafruit.com/assets/assets/000/040/611/medium640/feather_adafruit_products_3070_iso_ORIG.jpg?1491191673)

![feather_3076_iso_demo_ORIG.jpg](https://cdn-learn.adafruit.com/assets/assets/000/040/612/medium640/feather_3076_iso_demo_ORIG.jpg?1491191702)

Before beginning make sure you have your Arduino or Feather working smoothly, it will make this part a lot easier. Once you have the basic functionality going - you can upload code, blink an LED, use the serial output, etc. you can then upgrade to using the radio itself.

Note that the sub-GHz radio is not designed for streaming audio or video! It's best used for small packets of data. The data rate is adjustable but its common to stick to around 19.2 Kbps (thats bits per second). Lower data rates will be more successful in their transmissions

**You will, of course, need at least two paired radios** to do any testing! The radios must be matched in frequency (e.g. two 900 MHz&nbsp; radios are ok, but mixing 900 MHz and 433 MHz is _not_). They also must use the same encoding schemes, you cannot have a 900 MHz **RFM69** packet radio talk to a 900 MHz **RFM9x LoRa** radio.

# "Raw" vs Packetized

The SX1231 can be used in a 'raw rx/tx' mode where it just modulates incoming bits from pin #2 and sends them on the radio, however there's no error correction or addressing so we wont be covering that technique.

Instead, 99% of cases are best off using _packetized_ mode. This means you can set up a recipient for your data, error correction so you can be sure the whole data set was transmitted correctly, automatic re-transmit retries and return-receipt when the packet was delivered. Basically, you get the transparency of a data pipe without the annoyances of radio transmission unreliability

# Arduino Libraries

These radios have really great libraries already written, so rather than coming up with a new standard we suggest using existing libraries such as&nbsp;[LowPowerLab's RFM69 Library](https://github.com/LowPowerLab/RFM69) and&nbsp;[AirSpayce's Radiohead library](http://www.airspayce.com/mikem/arduino/RadioHead/) which also suppors a vast number of other radios

These are really great Arduino Libraries, so please support both companies in thanks for their efforts!

We recommend using the **Radiohead**  **library** - it is very cross-platform friendly and used a lot in the community!

## RadioHead Library example

To begin talking to the radio, you will need to [download our fork of the Radiohead library from our github repository](https://github.com/adafruit/RadioHead "Link: https://github.com/adafruit/RadioHead"). You can do that by visiting the github repo and manually downloading or, easier, just click this button to download the zip:

[Download RadioHead Library](https://github.com/adafruit/RadioHead/archive/master.zip)
Rename the uncompressed folder **RadioHead** and check that the **RadioHead** folder contains files like **RH\_RF69.**** cpp **and** RH\_RF69 ****.h** (and many others!)  
  
Place the **RadioHead** &nbsp;library folder in your **_arduinosketchfolder_/libraries/** folder.   
You may need to create the **libraries** subfolder if it's your first library. Restart the IDE.  
  
We also have a great tutorial on Arduino library installation at:  
[http://learn.adafruit.com/adafruit-all-about-arduino-libraries-install-use](http://learn.adafruit.com/adafruit-all-about-arduino-libraries-install-use "Link: http://learn.adafruit.com/adafruit-all-about-arduino-libraries-install-use")

# Basic RX & TX example

Lets get a basic demo going, where one radio transmits and the other receives. We'll start by setting up the transmitter

## Basic Transmitter example code

This code will send a small packet of data once a second to another RFM69 radio, without any addressing.

Open up the example **RadioHead→feather→RadioHead69\_RawDemo\_TX**

Load this code into your Transmitter Arduino or Feather!

![](https://cdn-learn.adafruit.com/assets/assets/000/040/603/medium800/feather_basictx.png?1491189415)

Danger: 

Info: 

Once uploaded you should see the following on the serial console

![](https://cdn-learn.adafruit.com/assets/assets/000/040/599/medium800/feather_txdemo.png?1491188161)

Now open up another instance of the Arduino IDE - this is so you can see the serial console output from the TX device while you set up the RX device.

## Basic receiver example code

This code will receive and reply with a small packet of data.

Open up the example **RadioHead→feather→RadioHead69\_RawDemo\_RX**

Load this code into your **Receiver** Arduino/Feather!

![](https://cdn-learn.adafruit.com/assets/assets/000/040/604/medium800/feather_basicrc.png?1491189503)

Danger: 

Info: 

Now open up the Serial console on the receiver, while also checking in on the transmitter's serial console. You should see the receiver is...well, receiving packets

![](https://cdn-learn.adafruit.com/assets/assets/000/040/600/medium800/feather_rxdemo.png?1491188270)

And, on the transmitter side, it is now printing **Got Reply** after each transmisssion because it got a reply from the receiver

![](https://cdn-learn.adafruit.com/assets/assets/000/040/601/medium800/feather_repl.png?1491188298)

That's pretty much the basics of it! Lets take a look at the examples so you know how to adapt to your own radio network

## Radio Freq. Config

Each radio has a frequency that is configurable in software. You can actually tune outside the recommended frequency, but the range won't be good. 900 MHz can be tuned from about 850-950MHz with good performance. 433 MHz radios can be tuned from 400-460 MHz or so.

```
// Change to 434.0 or other frequency, must match RX's freq!
#define RF69_FREQ 915.0
```

For all radios they will need to be on the same frequency. If you have a 433MHz radio you will want to stick to 433. If you have a 900 Mhz radio, go with 868 or 915MHz, just make sure all radios are on the same frequency.

## Configuring Radio Pinout

At the top of the sketch you can also set the pinout. The radios will use hardware SPI, but you can select any pins for **RFM69\_CS** (an output), **RFM\_IRQ** (an input) and **RFM\_RST** (an output). RFM\_RST is manually used to reset the radio at the beginning of the sketch. **RFM\_IRQ** must be an interrupt-capable pin. Check your board to determine which pins you can use!

Also, an LED is defined.

For example, here is the Feather 32u4 pinout:

```cpp
#if defined (__AVR_ATmega32U4__)  // Feather 32u4 w/Radio
  #define RFM69_CS    8
  #define RFM69_INT   7
  #define RFM69_RST   4
  #define LED        13
```

If you're using a Feather M0, the pinout is slightly different:

```cpp
#elif defined(ADAFRUIT_FEATHER_M0) || defined(ADAFRUIT_FEATHER_M0_EXPRESS) || defined(ARDUINO_SAMD_FEATHER_M0)  // Feather M0 w/Radio
  #define RFM69_CS    8
  #define RFM69_INT   3
  #define RFM69_RST   4
  #define LED        13
```

And for Feather RP2040:

```cpp
#elif defined(ARDUINO_ADAFRUIT_FEATHER_RP2040_RFM)  // Feather RP2040 w/Radio
  #define RFM69_CS   16
  #define RFM69_INT  21
  #define RFM69_RST  17
  #define LED        LED_BUILTIN
```

If you're using an Arduino UNO or compatible, we recommend:

```cpp
#elif defined (__AVR_ATmega328P__)  // Feather 328P w/wing
  #define RFM69_CS    4  //
  #define RFM69_INT   3  //
  #define RFM69_RST   2  // "A"
  #define LED        13
```

If you're using a FeatherWing or different setup, you'll have to set up the `#define` statements to match your wiring

You can then instantiate the radio object with our custom pin numbers. Note that the IRQ is defined by the IRQ pin not number (sometimes they differ).

```
// Singleton instance of the radio driver
RH_RF69 rf69(RFM69_CS, RFM69_INT);
```

## Setup

We begin by setting up the serial console and hard-resetting the RFM69

```
void setup() 
{
  Serial.begin(115200);
  //while (!Serial) { delay(1); } // wait until serial console is open, remove if not tethered to computer

  pinMode(LED, OUTPUT);     
  pinMode(RFM69_RST, OUTPUT);
  digitalWrite(RFM69_RST, LOW);

  Serial.println("Feather RFM69 RX Test!");
  Serial.println();

  // manual reset
  digitalWrite(RFM69_RST, HIGH);
  delay(10);
  digitalWrite(RFM69_RST, LOW);
  delay(10);
```

If you are using a board with 'native USB' make sure the **while (!Serial)** line is commented out if you are not tethering to a computer, as it will cause the microcontroller to halt until a USB connection is made!

## Initializing Radio

Once initialized, you can set up the frequency, transmission power, radio type and encryption key.

For the **frequency** , we set it already at the top of the sketch

For **transmission power** you can select from 14 to 20 dBi. Lower numbers use less power, but have less range. The second argument to the function is whether it is an HCW type radio, with extra amplifier. This should _always_ be set to **true**!

Finally, if you are **encrypting** data transmission, set up the encryption key

```
  if (!rf69.init()) {
    Serial.println("RFM69 radio init failed");
    while (1);
  }
  Serial.println("RFM69 radio init OK!");
  
  // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM (for low power module)
  // No encryption
  if (!rf69.setFrequency(RF69_FREQ)) {
    Serial.println("setFrequency failed");
  }

  // If you are using a high power RF69 eg RFM69HW, you *must* set a Tx power with the
  // ishighpowermodule flag set like this:
  rf69.setTxPower(20, true);  // range from 14-20 for power, 2nd arg must be true for 69HCW

  // The encryption key has to be the same as the one in the server
  uint8_t key[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
                    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
  rf69.setEncryptionKey(key);
```

## Basic Transmission Code

If you are using the transmitter, this code will wait 1 second, then transmit a packet with "Hello World #" and an incrementing packet number, then check for a reply

```
void loop() {
  delay(1000);  // Wait 1 second between transmits, could also 'sleep' here!

  char radiopacket[20] = "Hello World #";
  itoa(packetnum++, radiopacket+13, 10);
  Serial.print("Sending "); Serial.println(radiopacket);
  
  // Send a message!
  rf69.send((uint8_t *)radiopacket, strlen(radiopacket));
  rf69.waitPacketSent();

  // Now wait for a reply
  uint8_t buf[RH_RF69_MAX_MESSAGE_LEN];
  uint8_t len = sizeof(buf);

  if (rf69.waitAvailableTimeout(500))  { 
    // Should be a reply message for us now   
    if (rf69.recv(buf, &amp;len)) {
      Serial.print("Got a reply: ");
      Serial.println((char*)buf);
      Blink(LED, 50, 3); //blink LED 3 times, 50ms between blinks
    } else {
      Serial.println("Receive failed");
    }
  } else {
    Serial.println("No reply, is another RFM69 listening?");
  }
}
```

Its pretty simple, the delay does the waiting, you can replace that with low power sleep code. Then it generates the packet and appends a number that increases every tx. Then it simply calls `send()` `waitPacketSent() `to wait until is is done transmitting.

It will then wait up to 500 milliseconds for a reply from the receiver with `waitAvailableTimeout(500)`. If there is a reply, it will print it out. If not, it will complain nothing was received. Either way the transmitter will continue the loop and sleep for a second until the next TX.

## Basic Receiver Code

The Receiver has the same exact setup code, but the loop is different

```
void loop() {
 if (rf69.available()) {
    // Should be a message for us now   
    uint8_t buf[RH_RF69_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(buf);
    if (rf69.recv(buf, &amp;len)) {
      if (!len) return;
      buf[len] = 0;
      Serial.print("Received [");
      Serial.print(len);
      Serial.print("]: ");
      Serial.println((char*)buf);
      Serial.print("RSSI: ");
      Serial.println(rf69.lastRssi(), DEC);

      if (strstr((char *)buf, "Hello World")) {
        // Send a reply!
        uint8_t data[] = "And hello back to you";
        rf69.send(data, sizeof(data));
        rf69.waitPacketSent();
        Serial.println("Sent a reply");
        Blink(LED, 40, 3); //blink LED 3 times, 40ms between blinks
      }
    } else {
      Serial.println("Receive failed");
    }
  }
}
```

Instead of transmitting, it is constantly checking if there's any data packets that have been received. `available()` will return true if a packet with the proper encryption has been received. If so, the receiver prints it out.

It also prints out the RSSI which is the receiver signal strength indicator. This number will range from about -15 to -80. The larger the number (-15 being the highest you'll likely see) the stronger the signal.

If the data contains the text "Hello World" it will also reply to the packet.

Once done it will continue waiting for a new packet

# Basic Receiver/Transmitter Demo w/OLED

OK once you have that going you can try this example, **RadioHead69\_RawDemoTXRX\_OLED**. We're using the Feather with an OLED wing but in theory you can run the code without the OLED and connect three buttons to GPIO #9, 6, and 5 on the Feathers. Upload the same code to each Feather. When you press buttons on one Feather they will be printed out on the other one, and vice versa. Very handy for testing bi-directional communication!

![](https://cdn-learn.adafruit.com/assets/assets/000/040/605/medium800/feather_oledbasic.png?1491189570)

This demo code shows how you can listen for packets and also check for button presses (or sensor data or whatever you like) and send them back and forth between the two radios!

# Addressed RX and TX Demo

OK so the basic demo is well and good but you have to do a lot of _management_ of the connection to make sure packets were received. Instead of manually sending acknowledgements, you can have the RFM69 and library do it for you! Thus the **Reliable Datagram** part of the **RadioHead** library.

Load up the **RadioHead69\_AddrDemo\_RX** and **RadioHead69\_AddrDemo\_TX** sketches to each of your boards

Warning: 

This example lets you have many 'client' RFM69's all sending data to one 'server'

Each client can have its own address set, as well as the server address. See this code at the beginning:

```auto
// Who am i? (server address)
#define MY_ADDRESS   1

// Where to send packets to! MY_ADDRESS in client (RX) should match this.
#define DEST_ADDRESS 2
```

For each client, have a unique **MY\_ADDRESS**. Then pick one server that will be address #1

Once you upload the code to a client, you'll see the following in the serial console:

![](https://cdn-learn.adafruit.com/assets/assets/000/040/606/medium800/feather_noack.png?1491190936)

Because the data is being sent to address #1, but #1 is not acknowledging that data.

If you have the server running, with no clients, it will sit quietly:

![](https://cdn-learn.adafruit.com/assets/assets/000/040/607/medium800/feather_server.png?1491191058)

Turn on the client and you'll see acknowledged packets!

![](https://cdn-learn.adafruit.com/assets/assets/000/040/608/medium800/feather_acked.png?1491191100)

And the server is also pretty happy

![](https://cdn-learn.adafruit.com/assets/assets/000/040/609/medium800/feather_server2.png?1491191127)

The secret sauce is the addition of this new object:

```
// Class to manage message delivery and receipt, using the driver declared above
RHReliableDatagram rf69_manager(rf69, MY_ADDRESS);
```

Which as you can see, is the manager for the RFM69. In **setup()** you'll need to init it, although you still configure the underlying rfm69 like before:

```
  if (!rf69_manager.init()) {
    Serial.println("RFM69 radio init failed");
    while (1);
  }
```

And when transmitting, use **sendToWait** which will wait for an ack from the recepient (at DEST\_ADDRESS)

```
  if (rf69_manager.sendtoWait((uint8_t *)radiopacket, strlen(radiopacket), DEST_ADDRESS)) {
```

on the 'other side' use the **recvFromAck** which will receive and acknowledge a packet

```
    // Wait for a message addressed to us from the client
    uint8_t len = sizeof(buf);
    uint8_t from;
    if (rf69_manager.recvfromAck(buf, &amp;len, &amp;from)) {
```

That function will wait forever. If you'd like to timeout while waiting for a packet, use **recvfromAckTimeout** which will wait an indicated # of milliseconds

```
if (rf69_manager.recvfromAckTimeout(buf, &amp;len, 2000, &amp;from)) 
```

# Adafruit Feather M0 Radio with RFM69 Packet Radio

## CircuitPython for RFM69

It's easy to use the RFM69HCW radio with CircuitPython and the&nbsp;[Adafruit CircuitPython RFM69](https://github.com/adafruit/Adafruit_CircuitPython_RFM69)&nbsp;module.&nbsp; This module allows you to easily write Python code that sends and receives packets of data with the radio. &nbsp;Be careful to note this library is for the RFM69 radio only and **will not** work with the RFM9X LoRa radios!

## Design Considerations

One thing to be aware of before you use the RFM69 series of radios with CircuitPython are some of the limitations and design considerations for its module. &nbsp;Keep these in mind as you think about projects using the RFM69 and CircuitPython:

- You can only send and receive packets up to 60 bytes in length at a time. &nbsp;The size of the radio's internal buffer dictates this limit so if you want to send longer messages you'll need to break them into a series of smaller send calls in your application code.
- Receiving packets is a 'best effort' in pure Python code. &nbsp;Unlike the Arduino versions of the RFM69 library there is no interrupt support which means when a packet is received it must be immediately processed by the Python code or it could be lost. &nbsp;For your application it will work best to only receive small, single packet messages at a time. &nbsp;Don't try to receive kilobytes of data or else you'll lose packets. &nbsp;This module is really intended for simple single packet messages like 'ON', 'OFF', etc.
- Sending and receiving packets will 'block' your Python code until the packet is fully processed. &nbsp;This means you can't do a lot of other things while sending and waiting for packets to be received. &nbsp;Design your application so the radio usage is the primary scenario and very little other tasks need to happen in the background.
- The module is written to be compatible with the RadioHead RFM69 Arduino library. &nbsp;This means by default the module will setup the radio with the same GFSK, 250kbit/s, 250khz deviation, and bit whitening radio configuration so it can send and receive data with itself and other RadioHead-driven modules. &nbsp;In addition the CircuitPython module uses the same sync word and packet preamble (4 bytes) as RadioHead. &nbsp;If you want to use different modulations or settings you'll need to configure the radio yourself (see [the initialization code](https://github.com/adafruit/Adafruit_CircuitPython_RFM69/blob/master/adafruit_rfm69.py#L299-L318) for the registers and bits to access, however you will need to consult the datasheet for the necessary values).
- You can enable encryption and set an AES encryption key. &nbsp;
- The CircuitPython module supports advanced RadioHead features like node addressing and "reliable DataGram".&nbsp; "Reliable DataGram" mode in CircuitPython has some additional parameters to control timing that are not available with the RadioHead library. It may be difficult to get reliable transmission to work between the RadioHead library and CircuitPython.

## Wiring With Breakout

First wire up a RFM69 breakout to your board as shown on the previous pages for Arduino. &nbsp;Note that the G0/interrupt line is not used by the CircuitPython module and can remain unconnected. &nbsp; Here's an example of wiring a Feather M0 to the radio with a SPI connection:

![](https://cdn-learn.adafruit.com/assets/assets/000/050/193/medium800/adafruit_products_m0_rfm69_bb.png?1516149383)

- **Board 3V** &nbsp;to&nbsp; **radio VIN**
- **Board GND** &nbsp;to&nbsp; **radio GND**
- **Board SCK** &nbsp;to&nbsp; **radio SCK**
- **Board MOSI** &nbsp;to&nbsp; **radio MOSI**
- **Board MISO&nbsp;** to&nbsp; **radio MISO**
- **Board D5&nbsp;** to&nbsp; **radio CS&nbsp;** (or any other digital I/O pin)
- **Board D6&nbsp;** to **radio RST&nbsp;** (or any other digital I/O pin)

## Usage with All-In-One Feather M0

Alternatively you can use the Feather M0 RFM69 board but be sure you've loaded the [adafruit-circuitpython-feather\_m0\_rfm69-\*.bin](https://github.com/adafruit/circuitpython/releases) version of CircuitPython on your board!&nbsp; **This is very important as the RFM69 build has special pins added to the board module which are used to access the radio's control lines!**

[For details on how to load a binary circuitpython build, check out our Non-UF2-Install guide](../../../../welcome-to-circuitpython/non-uf2-installation)

### Adafruit Feather M0 RFM69HCW Packet Radio - 868 or 915 MHz

[Adafruit Feather M0 RFM69HCW Packet Radio - 868 or 915 MHz](https://www.adafruit.com/product/3176)
This is the**&nbsp;Adafruit Feather M0 RFM69 Packet Radio&nbsp;(868 or 915 MHz)****. **We call these _RadioFruits** ,**_ our take on an microcontroller with a RFM69HCW packet radio transceiver plus built in USB and battery charging. Its an Adafruit...

In Stock
[Buy Now](https://www.adafruit.com/product/3176)
[Related Guides to the Product](https://learn.adafruit.com/products/3176/guides)
![Angled shot of rectangular microcontroller.](https://cdn-shop.adafruit.com/640x480/3176-05.jpg)

### Adafruit Feather M0 RFM69HCW Packet Radio - 433MHz

[Adafruit Feather M0 RFM69HCW Packet Radio - 433MHz](https://www.adafruit.com/product/3177)
This is the**&nbsp;Adafruit Feather M0 RFM69 Packet Radio&nbsp;(433 MHz)****. **We call these _RadioFruits** ,**_ our take on an microcontroller with a RFM69 HCW packet radio transceiver plus built in USB and battery charging. It's an Adafruit...

In Stock
[Buy Now](https://www.adafruit.com/product/3177)
[Related Guides to the Product](https://learn.adafruit.com/products/3177/guides)
![Angled shot of rectangular microcontroller.](https://cdn-shop.adafruit.com/640x480/3177-05.jpg)

## Module Install

If you have the Feather M0 RFM69 and have installed CircuitPython 6.0 or later, it is not necessary to install the library modules. They are "frozen into" the Circuitpython build. Skip to the "Usage" section below.

If you are using an older version of CircuitPython you will need to install the modules as described.

Next you'll need to install the&nbsp;[Adafruit CircuitPython RFM69](https://github.com/adafruit/Adafruit_CircuitPython_RFM69)&nbsp;module on your CircuitPython board. &nbsp;Before you do that make&nbsp;sure you are running the&nbsp;[latest version of Adafruit CircuitPython](../../../../welcome-to-circuitpython/installing-circuitpython)&nbsp;for your board too (again be sure to the load the Feather M0 RFM69 version if you're using that board and want to use its built-in radio module).

Next you'll need to install the necessary libraries&nbsp;to use the hardware--carefully follow the steps to find and install these libraries from&nbsp;[Adafruit's CircuitPython library bundle](https://github.com/adafruit/Adafruit_CircuitPython_Bundle).&nbsp; Our introduction guide has&nbsp;[a great page on how to install the library bundle](../../../../welcome-to-circuitpython/circuitpython-libraries)&nbsp;for both express and non-express boards.

Remember for non-express boards like the Adafruit Feather M0, you'll need to manually install the necessary libraries from the bundle:

- **adafruit\_rfm69.mpy**
- **adafruit\_bus\_device**

You can also download the&nbsp; **adafruit\_rfm69.mpy** &nbsp;from&nbsp;[its releases page on Github](https://github.com/adafruit/Adafruit_CircuitPython_RFM69/releases).

Before continuing make sure your board's lib folder or root filesystem has the&nbsp; **adafruit\_rfm69.mpy,&nbsp;** and **&nbsp;adafruit\_bus\_device**** &nbsp; **files and folders** &nbsp;**copied over.

&nbsp;

# Usage

To demonstrate the usage of the radio we'll initialize it and send and receive data from the board's Python REPL.

[Connect to the board's serial REPL&nbsp;](../../../../welcome-to-circuitpython/the-repl)so you are at the CircuitPython&nbsp; **\>\>\>** &nbsp;prompt.

Run the following code to import the necessary modules and initialize the SPI&nbsp;connection with the sensor:

```
import board
import busio
import digitalio
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
```

Now define a few of the pins connected to the RFM69, specifically the CS and RST pins:

```
cs = digitalio.DigitalInOut(board.D5)
reset = digitalio.DigitalInOut(board.D6)
```

However if you're using the Feather M0 RFM69 board with a built-in RFM69 radio (and you've loaded the special version of CircuitPython just for this board as mentioned above), you instead want to use these pins for the CS and RST lines:

```
cs = digitalio.DigitalInOut(board.RFM69_CS)
reset = digitalio.DigitalInOut(board.RFM69_RST)
```

You're ready to import the RFM69 module and create an instance of the RFM69 class inside it. &nbsp;Before you create the radio module instance you'll need to check if you're using a 433mhz or 915mhz radio module as the initializer requires the frequency to be specified--confirm which frequency your module uses and run **one** of the following lines. &nbsp;

For a 915mhz radio use:

```
import adafruit_rfm69
rfm69 = adafruit_rfm69.RFM69(spi, cs, reset, 915.0)
```

Or for a 433mhz radio use:

```
import adafruit_rfm69
rfm69 = adafruit_rfm69.RFM69(spi, cs, reset, 433.0)
```

Notice the initializer takes the following required parameters:

- **spi** - The SPI bus connected to the board.
- **cs** - The DigitalInOut instance connected to the CS line of the radio.
- **reset** - The DigitalInOut instance connected to the RST or reset line of the radio.
- **frequency** - The frequency in megahertz of the radio module. &nbsp;Remember this frequency depends on which type of radio you're using and the frequency you desire to use!

In addition there are some optional parameters you might specify:

- **baudrate** - The baud rate to use for the SPI connection to the radio.&nbsp; By default this is 10mhz which is as fast as the radio can handle, but in some cases it might be too fast if you're wiring up a breakout to a breadboard (breadboards can be notorious for not working well with high speed signals).&nbsp; If you run into odd errors like being unable to find the RFM69 radio try lowering the baudrate by specifying a **baudrate=1000000** keyword (which sets the speed to a lower 1mhz value).

Once the RFM69 class is created and initialized you're ready to start sending and receiving data.

Remember by default the module will be configured to interface with the "RadioHead" RFM69 setup so you can also send and receive packets with an Arduino running the 'raw' TX/RX examples!

To send a message simply call the **send** function and provide a string or byte string of data:

```
rfm69.send('Hello world!')
```

 **Remember you can only send a message up to 60 bytes in length at a time!** &nbsp; Attempting to send a message longer than 60 bytes will fail with an exception error. &nbsp;If you need to send a longer message it will have to be broken up into multiple send calls and reconstructed on the receiving side.

If you have another RFM69 on the same frequency and modulation waiting to receive messages (like another CircuitPython module running receive code below) you should see it receive the message.

![](https://cdn-learn.adafruit.com/assets/assets/000/050/233/medium800/adafruit_products_Screen_Shot_2018-01-17_at_11.50.01_AM.png?1516218974)

You can even have an Arduino running the RadioHead library's raw RX example see the message that was sent (be sure this receiving side has an encryption key setup exactly the same way as the sending side, see the `encryption_key` property discussion further below):

![](https://cdn-learn.adafruit.com/assets/assets/000/050/234/medium800/adafruit_products_Screen_Shot_2018-01-17_at_11.52.42_AM.png?1516219046)

To receive a message simply call the `receive` function. &nbsp;This function will wait for half a second for any packet to be received. &nbsp;If a packet is found it will be returned as a byte string (remember packets are at most 60 bytes long), or if no packet was found a result of `None` is returned.

```
rfm69.receive()
```

You can increase the amount of time the module waits for a packet to be received by specifying the time in seconds as a parameter to the receive call:

```python
rfm69.receive(timeout=5.0)  # Wait 5 seconds instead of 0.5 seconds.
```

Notice this waits longer at the REPL for a packet to be received before returning. &nbsp;If you have another RFM69 setup try having it send a message while the other is waiting to receive it. &nbsp;You should see a byte string returned.&nbsp; You can also have an Arduino running the RadioHead library's raw TX example send messages that are received by your code (again it must be setup with the same encryption key):

![](https://cdn-learn.adafruit.com/assets/assets/000/050/235/medium800/adafruit_products_Screen_Shot_2018-01-17_at_11.53.54_AM.png?1516219172)

One thing to note in Python byte strings aren't exactly like text strings and you might not be able to do all the text processing (like find, replace, etc.) as you expect. &nbsp;However you can convert a byte string into text by assuming a specific text encoding like ASCII. &nbsp;For example to receive a packet and convert the contents to an ASCII text string you can run code like:

```
packet = rfm69.receive()  # Wait for a packet to be received (up to 0.5 seconds)
if packet is not None:
    packet_text = str(packet, 'ascii')
    print('Received: {0}'.format(packet_text))
```

Notice this code first receives a packet, then checks if one was actually found (the packet is `not None` check--if no packet is received a value of `None` is returned), and then converts the packet data to a string assuming an ASCII text encoding.

# Beyond RX & TX

Beyond basic sending and receiving there are a few properties of the RFM69 class you might want to interact with:

- **encryption\_key** - This is an optional 16 byte string that defines the AES encryption key used by the radio for sending and receiving packets.&nbsp; Both the sending and receiving code must have the exact same encryption key set or they'll be unable to see each other's packets!&nbsp; See the [simpletest.py example](https://github.com/adafruit/Adafruit_CircuitPython_RFM69/blob/master/examples/rfm69_simpletest.py) below for an example of setting the `encryption_key` to match the default key from RadioHead library raw examples.&nbsp; By default the RFM69 class assumes no encryption key is set, and you can set this property to the value `None` to disable encryption.
- **rssi** - The received signal strength indicator is a property you can read to see the strength of the radio signal being received.&nbsp; This is updated when packets are received and returns a value in decibels (typically negative, so the _smaller_ the number and closer to 0, the higher the strength / better the signal).

![](https://cdn-learn.adafruit.com/assets/assets/000/050/237/medium800/adafruit_products_Screen_Shot_2018-01-17_at_12.02.16_PM.png?1516219542)

![](https://cdn-learn.adafruit.com/assets/assets/000/050/236/medium800/adafruit_products_Screen_Shot_2018-01-17_at_12.02.02_PM.png?1516219532)

That's all there is to the basic RFM69 radio usage! &nbsp;_Remember the CircuitPython module is designed for sending and receiving small up to 60 byte control messages and not large or high bandwidth amounts of data._

Here's a complete example of sending a message and waiting to receive and print any received messages. &nbsp;Save this as **main.py** on your board and open the serial REPL to see it print data and any received messages. &nbsp;If you have two boards and radios setup to run this code at the same time they'll send each other a message on start up!

https://github.com/adafruit/Adafruit_CircuitPython_RFM69/blob/main/examples/rfm69_simpletest.py

# Adafruit Feather M0 Radio with RFM69 Packet Radio

## Radio Module F.A.Q.

### 

All other things being equal (antenna, power output, location) you will get better range with LoRa than with RFM69 modules. We've found 50% to 100% range improvement is common.

### 

The RFM69 radios have a range of approx. 500 meters **line of sight** with tuned uni-directional antennas. Depending on obstructions, frequency, antenna and power output, you will get lower ranges - _especially_ if you are not line of sight.

### 

The RFM9x radios have a range of up to 2 km **line of sight** with tuned uni-directional antennas. Depending on obstructions, frequency, antenna and power output, you will get lower ranges - _especially_ if you are not line of sight.

### 

Your module is probably _not_ broken. Radio range is dependant on _a lot of things_ and all must be attended to make sure you get the best performance!

1. Tuned antenna for your frequency - getting a well-tuned antenna is incredibly important. Your antenna must be tuned for the exact frequency you are using
2. Matching frequency - make sure all modules are on the same exact frequency
3. Matching settings - all radios must have the same settings so they can communicate
4. Directional vs non-directional antennas - for the best range, _directional_ antennas like Yagi will direct your energy in one path instead of all around
5. Good power supply - a nice steady power supply will keep your transmissions clean and strong
6. Max power settings on the radios - they can be set for higher/lower power! Don't forget to set them to max.
7. Line of sight - No obstructions, walls, trees, towers, buildings, mountains, etc can be in the way of your radio path. Likewise, outdoors is way better than indoors because its very hard to bounce radio paths around a building
8. Radio transmission speed - trying to transmit more data faster will be hard. Go for small packets, with lots of retransmissions. Lowering the baud rate on the radio (see the libraries for how to do this) will give you better reliability

### 

Various antennas will cost diferent amounts and give you different directional gain. In general, spending a lot on a large fixed antenna can give you better power transfer if the antenna is well tuned. For most simple uses, a wire works pretty well  
  
[The ARRL antena book is recommended if you want to learn how to do the modeling and analysis](https://www.arrl.org/shop/Antennas/)  
  
But nothing beats actual tests in your environment!

### 

Look for a little colored paint dot on top of the module.

- **GREEN** , **BLUE** or **NO DOT** = **900 MHz**
- **RED** = **433 MHz**

Every now and then the paint dot shows up without a color or with the ink dot burnt. This is just a manufacturing variance and there is nothing wrong with the board. You should get the frequency you ordered though. So if you plan on mixing these up, you may want to add a new mark of your own.

### 

Nope! The radios have an ink dot on them, which sometimes gets toasty when we put the board through the oven, or rework it, so it may have a burnt appearance. The chip is fine!

### 

Each LoRa device from Adafruit should come with a small label that contains a MAC address in the form **98:76:B6:xx:yy:zz**. This might be a sticker attached to the device itself or included separately. This MAC address is needed if using the LoRa device with [LoRaWAN](https://lora-alliance.org/about-lorawan/). For example, [The Things Network](https://www.thethingsnetwork.org/) uses LoRaWAN. For non-LoRaWAN usage, the MAC address is not needed.

# Adafruit Feather M0 Radio with RFM69 Packet Radio

## Downloads

# Datasheets & Files

For the LoRa version:

- [SX127x Datasheet](https://cdn-shop.adafruit.com/product-files/3179/sx1276_77_78_79.pdf)- The RFM9X LoRa radio chip itself
- [RFM9X](https://www.hoperf.com/data/upload/portal/20190801/RFM96W-V2.0.pdf) - The radio module, which contains the SX1272 chipset

For the RFM69 version:

- [SX1231 Transceiver Datasheet](https://cdn-shop.adafruit.com/product-files/3076/sx1231.pdf)
- RFM69HCW Datasheet: [V1.1](https://cdn-shop.adafruit.com/product-files/3076/RFM69HCW-V1.1.pdf)
- [FCC Test Report](https://cdn-shop.adafruit.com/product-files/3071/p3071p3077_RFM69HCW-433S2-FCC.pdf)
- [RoHS Test Report](https://cdn-shop.adafruit.com/product-files/3076/CAN14-015141-02_EC_15137200_F.PDF)
- [RoHS Test Report](https://cdn-shop.adafruit.com/product-files/3076/CAN15-031854-04_EC_15983075_F.PDF)
- [REACH Test Report](https://cdn-shop.adafruit.com/product-files/3076/CAN15-031854-07_EC_15983075_F.PDF)
- [RFM9X 3D Models on GitHub](https://github.com/adafruit/Adafruit_CAD_Parts/tree/main/3178%20Feather%20M0%20RFM95)

For both:

- [PCB files on GitHub](https://github.com/adafruit/Adafruit-Feather-M0-RFM-LoRa-PCB)
- [Fritzing Library](https://github.com/adafruit/Fritzing-Library)

&nbsp;

- [PDF for Feather M0 RFM69 Board Diagram on GitHub](https://github.com/adafruit/Adafruit-Feather-M0-RFM-LoRa-PCB/blob/master/Adafruit%20Feather%20M0%20RFM69%20Pinout.pdf)
- [PDF for Feather M0 RFM9x Board Diagram on GitHub](https://github.com/adafruit/Adafruit-Feather-M0-RFM-LoRa-PCB/blob/master/Adafruit%20Feather%20M0%20RFM9x%20Pinout.pdf)

[SVG for Feather M0 RFM69 Board Diagram](https://cdn-learn.adafruit.com/assets/assets/000/110/922/original/Adafruit_Feather_M0_RFM69_Pinout.svg?1650390171)
[SVG for Feather M0 RFM9x Board Diagram](https://cdn-learn.adafruit.com/assets/assets/000/110/923/original/Adafruit_Feather_M0_RFM9x_Pinout.svg?1650390261)
# Schematic

Click to embiggen. Same schematic for both LoRa and RFM69 (the modules have the same pinout)

![](https://cdn-learn.adafruit.com/assets/assets/000/032/914/medium800/feather_schem.png?1465421956)

# Fabrication Print

Dimensions in Inches. Same PCB design for both LoRa and RFM69 (the modules have the same pinout)

![](https://cdn-learn.adafruit.com/assets/assets/000/032/915/medium800/feather_fabprint.png?1465422003)

![](https://cdn-learn.adafruit.com/assets/assets/000/141/537/medium800/adafruit_products_3178_Feather_M0_RFM95.jpg?1765215346 )


## Featured Products

### Adafruit Feather M0 RFM69HCW Packet Radio - 868 or 915 MHz

[Adafruit Feather M0 RFM69HCW Packet Radio - 868 or 915 MHz](https://www.adafruit.com/product/3176)
This is the**&nbsp;Adafruit Feather M0 RFM69 Packet Radio&nbsp;(868 or 915 MHz)****. **We call these _RadioFruits** ,**_ our take on an microcontroller with a RFM69HCW packet radio transceiver plus built in USB and battery charging. Its an Adafruit...

In Stock
[Buy Now](https://www.adafruit.com/product/3176)
[Related Guides to the Product](https://learn.adafruit.com/products/3176/guides)
### Adafruit Feather M0 RFM69HCW Packet Radio - 433MHz

[Adafruit Feather M0 RFM69HCW Packet Radio - 433MHz](https://www.adafruit.com/product/3177)
This is the**&nbsp;Adafruit Feather M0 RFM69 Packet Radio&nbsp;(433 MHz)****. **We call these _RadioFruits** ,**_ our take on an microcontroller with a RFM69 HCW packet radio transceiver plus built in USB and battery charging. It's an Adafruit...

In Stock
[Buy Now](https://www.adafruit.com/product/3177)
[Related Guides to the Product](https://learn.adafruit.com/products/3177/guides)
### SMA to uFL/u.FL/IPX/IPEX RF Adapter Cable

[SMA to uFL/u.FL/IPX/IPEX RF Adapter Cable](https://www.adafruit.com/product/851)
This RF adapter cable is super handy for anyone doing RF work. Often times, small electronics save space by having a pick-and-placeable u.FL connector (also called uFL, IPEX, IPAX, IPX, MHF, and AM). But most antennas have SMA or RP-SMA connectors on them. This little cable will bridge the...

In Stock
[Buy Now](https://www.adafruit.com/product/851)
[Related Guides to the Product](https://learn.adafruit.com/products/851/guides)
### uFL SMT Antenna Connector

[uFL SMT Antenna Connector](https://www.adafruit.com/product/1661)
uFL connectors are very small surface-mount parts used when an external RF antena is desired but a big bulky SMA connector takes up too much space. We use this part on our GPS and WiFi boards, they're great! Chances are your antenna doesn't use uFL as the main connector, in which case...

In Stock
[Buy Now](https://www.adafruit.com/product/1661)
[Related Guides to the Product](https://learn.adafruit.com/products/1661/guides)
### Lithium Ion Polymer Battery - 3.7v 150mAh

[Lithium Ion Polymer Battery - 3.7v 150mAh](https://www.adafruit.com/product/1317)
Lithium-ion polymer (also known as 'lipo' or 'lipoly') batteries are thin, light, and powerful. The output ranges from 4.2V when completely charged to 3.7V. This battery has a capacity of 150mAh for a total of about 0.6 Wh. If you need a larger battery, <a...></a...>

Out of Stock
[Buy Now](https://www.adafruit.com/product/1317)
[Related Guides to the Product](https://learn.adafruit.com/products/1317/guides)
### Lithium Ion Polymer Battery - 3.7V 350mAh

[Lithium Ion Polymer Battery - 3.7V 350mAh](https://www.adafruit.com/product/2750)
Lithium-ion polymer (also known as 'lipo' or 'lipoly') batteries are thin, light, and powerful. The output ranges from 4.2V when completely charged to 3.7V. This battery has a capacity of 350mAh for a total of about 1.3 Wh. If you need a larger (or smaller!) battery, <a...></a...>

Out of Stock
[Buy Now](https://www.adafruit.com/product/2750)
[Related Guides to the Product](https://learn.adafruit.com/products/2750/guides)
### Lithium Ion Polymer Battery - 3.7v 500mAh

[Lithium Ion Polymer Battery - 3.7v 500mAh](https://www.adafruit.com/product/1578)
Lithium-ion polymer (also known as 'lipo' or 'lipoly') batteries are thin, light, and powerful. The output ranges from 4.2V when completely charged to 3.7V. This battery has a capacity of 500mAh for a total of about 1.9 Wh. If you need a larger (or smaller!) battery, <a...></a...>

Out of Stock
[Buy Now](https://www.adafruit.com/product/1578)
[Related Guides to the Product](https://learn.adafruit.com/products/1578/guides)
### Lithium Ion Polymer Battery - 3.7v 1200mAh

[Lithium Ion Polymer Battery - 3.7v 1200mAh](https://www.adafruit.com/product/258)
Lithium-ion polymer (also known as 'lipo' or 'lipoly') batteries are thin, light, and powerful. The output ranges from 4.2V when completely charged to 3.7V. This battery has a capacity of 1200mAh for a total of about 4.5 Wh. If you need a larger battery, <a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/258)
[Related Guides to the Product](https://learn.adafruit.com/products/258/guides)

## Related Guides

- [Adafruit NeoPXL8 FeatherWing and Library](https://learn.adafruit.com/adafruit-neopxl8-featherwing-and-library.md)
- [CircuitPython Hardware: LED Backpacks & FeatherWings](https://learn.adafruit.com/micropython-hardware-led-backpacks-and-featherwings.md)
- [MicroPython Basics: How to Load MicroPython on a Board](https://learn.adafruit.com/micropython-basics-how-to-load-micropython-on-a-board.md)
- [Using LoraWAN and The Things Network with CircuitPython](https://learn.adafruit.com/using-lorawan-and-the-things-network-with-circuitpython.md)
- [CircuitPython Hardware: SSD1306 OLED Display](https://learn.adafruit.com/micropython-hardware-ssd1306-oled-display.md)
- [Wireless NeoPixel Controller](https://learn.adafruit.com/neotrellis-neopixel-controller.md)
- [MicroPython Displays: Drawing Shapes](https://learn.adafruit.com/micropython-displays-drawing-shapes.md)
- [MicroPython Displays: Drawing Text](https://learn.adafruit.com/micropython-displays-drawing-text.md)
- [Introducing Adafruit Feather](https://learn.adafruit.com/adafruit-feather.md)
- [3D Printed Case for Adafruit Feather](https://learn.adafruit.com/3d-printed-case-for-adafruit-feather.md)
- [CircuitPython Hardware: PCA9685 PWM & Servo Driver](https://learn.adafruit.com/micropython-hardware-pca9685-pwm-and-servo-driver.md)
- [CircuitPython Hardware: PCA9685 DC Motor & Stepper Driver](https://learn.adafruit.com/micropython-hardware-pca9685-dc-motor-and-stepper-driver.md)
- [MicroPython for SAMD21](https://learn.adafruit.com/micropython-for-samd21.md)
- [Adafruit Feather 32u4 FONA](https://learn.adafruit.com/adafruit-feather-32u4-fona.md)
- [Adafruit Feather 32u4 with LoRa Radio Module](https://learn.adafruit.com/adafruit-feather-32u4-radio-with-lora-radio-module.md)
