Speeding up the ADC on an Arduino ATMega 328P

ADC steps
courtesy Spinningspark at Wikipedia

This is a continuation of the performance enhancements for reading the ADC on Arduino.  Similar steps apply to many non Arduino/ATMega processors.

That other article is here: Arduino Library Functions & Macros and introduces startSample(), sampleDone(), and getSampleResult() as a way of avoiding blocking when doing an analogRead.  Here we will update the second two functions and introduce a new function: startFreeRunningADC().

This time we delve a little deeper into the ATMega328 and 168, we implement the free running mode and increase the clock rate to achieve 38,462 samples per second compared to the 8,966 samples per second that analogRead() can do.   Other than the example, none of this is Arduino dependent.  It works on any microcontroller in the same series as the ATMega328 and similar steps can be done on just about any microcontroller with a successive approximation ADC.

The first step to improve performance is to have the ADC operate in Free Running mode, constantly sampling and updating the ADC results registers.  The first conversion is started by calling startFreeRunningADC() from setup().  In this mode the ADC will perform successive conversions every 13 ADC clocks indefinitely instead of doing one conversion in 25 ADC clocks and then waiting to be restarted.  Note, the sampleDone() and getSampleResult() are also slightly updated.  This alone more than doubles performance.

The remaining step is to increase the ADC clock speed from Arduino’s default of 125KHz to 500KHz.  This has a side effect of reducing the sample time which reduces resolution.  To minimize the impact of the reduced sample time, avoid high value resistor dividers and use the lowest value that your signal source can accept, or buffer the signal with an opamp.  There is a compromise speed commented out if you’d prefer the accuracy of remaining close to the 200KHz required for best resolution.  With Free Running mode and a 500KHz ADC clock, the ADC runs at 38,462 samples per second.

Finally, not implemented here, you can trigger an interrupt on conversion complete to avoid polling for results as is implemented here.  In many interrupt driven programs, the ADC results are simply stored and then the stored result is polled, leading to no real improvements in speed.

Here are the functions:

#include "wiring_private.h"
#include "pins_arduino.h"

void startFreeRunningADC(uint8_t pin){
 ADMUX=(1<<REFS0)|((pin-14)&0x07); //select AVCC as reference and set MUX to pin
 ADCSRB = 0; //set free running mode
ADCSRA=(1<<ADEN)|(1<< ADATE)|(1<<ADPS2)|(1<<ADPS0); //set adc clock to 500Khz, enable, free running mode
//ADCSRA=(1<<ADEN)|(1<< ADATE)|(1<<ADPS2)|(1<<ADPS1); //set adc clock to 250Khz, enable, free running mode
 sbi(ADCSRA, ADSC); //start the ADC

inline uint8_t sampleDone(){
 // ADIF is set when the conversion finishes
 return bit_is_set(ADCSRA, ADIF);

inline uint16_t getSampleResult(){
 uint8_t low, high;
 low = ADCL; //make sure to read L value first
 high = ADCH;
 sbi(ADCSRA, ADIF); //clear conversion complete flag
 return (high << 8) | low;

Here is a sample program using these functions:

#define ADCport A4
void setup() {
  Serial.begin(230400); //the ADC is so fast that we need faster serial!
  startFreeRunningADC(ADCport); //free running mode, only needs to start once.

void loop() {
  if( sampleDone()){

OpenOCD for programming nRF51822 via nothing but wires and a Raspberry Pi

nRF51822 BoardThe Hardware here is simple and cheap, it can be done with any Pi, though I used a Pi Zero.  For me, it was free because I had the Pi Zero and the wire.

The default pins are:

Ground                        to Ground
3.3V power              to 3.3V power
Pi header pin 22  to swclk
Pi header pin 18   to swdio

At the time this was written, OpenOCD didn’t have bcm2835gpio in the main release so we git clone it.
The debugger/programmer install is:

cd ~/Downloads
sudo bash
apt-get install libtool libusb-dev libusb-1.0 autoconf automake texinfo
git clone git://git.code.sf.net/p/openocd/code openocd-code
cd openocd-code/
./configure --enable-sysfsgpio --enable-bcm2835gpio
make install

The raspberrypi-native.cfg didn’t have SWD support, so add them from raspberrypi2-native.cfg.  I needed to comment out:

#bcm2835gpio_jtag_nums 11 25 10 9

and to add:

# Each of the SWD lines need a gpio number set: swclk swdio
# Header pin numbers: 22 18
bcm2835gpio_swd_nums 25 24

The peripheral base address is different on some Pi models.  You can check yours by grabbing the middle 8 digits from:

hexdump -s4 -n4 -e '"0x" 4/1 "%02X""\n"" "' /proc/device-tree/soc/ranges

Edit it with:

vi /usr/local/share/openocd/scripts/interface/raspberrypi-native.cfg

Check to be sure your default speed is 700Mhz, or adjust bcm2835gpio_speed_coeffs:

cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq

To run openocd:

openocd -f interface/raspberrypi-native.cfg -c "transport select swd; set WORKAREASIZE 0" -f target/nrf51.cfg

If it worked correctly, the last line should read (nothing before this indicates you successfully connected):

Info : nrf51.cpu: hardware has 4 breakpoints, 2 watchpoints

To connect from your development platform:

telnet pi0 4444

To burn the code, we need two files, in my case both are on a different machine (host) so I use sshfs to mount that.

mkdir ~/host
sshfs user@host:/ ~/host

Since the path is rather long, I break it in two and store into variables. This is the proximity example from the SDK:

set BASEPATH ~/host/home/user/Downloads/nRF5_SDK_11.0.0_89a8197
set SOFTDEV $BASEPATH/components/softdevice/s130/hex/s130_nrf51_2.0.0_softdevice.hex
set HEXFILE $BASEPATH/examples/ble_peripheral/ble_app_proximity/pca10028/s130/armgcc/_build/nrf51422_xxac_s130.hex
#halt, erase, write softdevice and binary, verify both, run it.
halt; nrf51 mass_erase; sleep 500; flash write_image $SOFTDEV 0; flash write_image $HEXFILE 0; verify_image $SOFTDEV 0; verify_image $HEXFILE 0; reset run

At this point, your sniffer or phone or whatever should see the Nordic_Prox device.

Installing GCC-arm for use with Nordic nRF8122 nRF5_SDK_11.0.0_89a8197

nRF51822 BoardSo, this is really just my notes for installing it again next time.  If it helps, great.

Per Nordic’s documentation/release_notes.txt, the library is compiled using a slightly older version so we’ll stick to that here.

cd ~/Downloads
wget "http://launchpad.net/gcc-arm-embedded/5.0/5-2015-q1-major/+download/gcc-arm-none-eabi-4_9-2015q1-20150306-linux.tar.bz2"
sudo bash
cd /usr/local/
tar -xjvf /home/user/Downloads/gcc-arm-none-eabi-4_9-2015q1-20150306-linux.tar.bz2

That’s it.

Installing the Library is equally easy:

cd ~/Downloads
wget "http://developer.nordicsemi.com/nRF5_SDK/nRF5_SDK_v11.x.x/nRF5_SDK_11.0.0_89a8197.zip"
mkdir nRF5_SDK_11.0.0_89a8197
cd nRF5_SDK_11.0.0_89a8197
unzip ../nRF5_SDK_11.0.0_89a8197.zip

To compile the proximity example:

cd nRF5_SDK_11.0.0_89a8197/examples/ble_peripheral/ble_app_proximity/pca10028/s130/armgcc

Arduino Library Functions & Macros


I think the one consensus about Arduino is that the build environment and the library suck.  That said, I use it.  This is some code I have written to try to make it a bit better for at least the limited things that I do with it.

For this post, I’m assuming you know how to use the Arduino IDE and how to program in it.  I make no effort to teach programming here and just present the code.

Diving right in with one of the worst: digitalWrite()

http://pastebin.com/dSRSxgax is a friend’s example of just how bad it is compared to harder to read but faster and smaller code.

My solution:  A macro that compiles down to an sbi or cbi.  All ATmega328 series boards should work, but I only tested on the Nano.  Comments with patches for other boards will be considered.

A quick look at the schematic shows the following ports:


For example:

  #define OutputPin A5
  digitalWrite(OutputPin, HIGH);

is far more efficient as:

  #define OutputPin A5
  PORTC |= (1<<OutputPin-A0);

The following are macros for both read and write that do the above but work for any pin and also include a pinMode() replacement: (not my code)

#define digitalPinToPortReg(P) (((P) >= 0 && (P) <= 7) ? &PORTD : (((P) >= 8 && (P) <= 13) ? &PORTB : &PORTC))
#define digitalPinToPINReg(P) (((P) >= 0 && (P) <= 7) ? &PIND : (((P) >= 8 && (P) <= 13) ? &PINB : &PINC))
#define digitalPinToBit(P) (((P) >= 0 && (P) <= 7) ? (P) : (((P) >= 8 && (P) <= 13) ? (P) - 8 : (P) - 14))
#define digitalPinToDDRReg(P) (((P) >= 0 && (P) <= 7) ? &DDRD : (((P) >= 8 && (P) <= 13) ? &DDRB : &DDRC))
#define pinModeFast(P, V) bitWrite(*digitalPinToDDRReg(P), digitalPinToBit(P), (V))
#define digitalWriteFast(P, V) bitWrite(*digitalPinToPortReg(P), digitalPinToBit(P), (V))
#define digitalReadFast(P) bitRead(*digitalPinToPINReg(P), digitalPinToBit(P))

This simple to use set of macros assumes PWM and timers are not in use on the related pins and it will fail to compile if the pin (P) isn’t a constant. Variables of type const will not work, #define does work.
These are all things the programmer can keep in mind while writing their code and are hardly a burden.  If not all of the above apply, use the bigger, slower digitalWrite() instead.

Simplified Level Shifting is also possible.  The usual voltage divider or transistor to write to a 3.3V device requires at least two components and in the case of the voltage divider, will create a poor quality signal.  The method described here only requires a single resistor.
There is a caveat, you must burn the code before connecting the hardware and if you make a mistake in your code, you can damage your hardware.
The trick here is that to output a HIGH to a 3.3V device we actually set the port to INPUT and use an external 4.7K pull-up resistor to 3.3V.  To output a low, the pin is set to LOW and the pinMode is set to OUTPUT.

DO NOT use pinModeFast(pin, OUTPUT) or pinMode(pin, OUTPUT) with this function.

Assuming D2 is and output and D3 is an input, the hardware would be as shown:
The code to handle simplified level shifting is:

#define digitalWriteLevelShift(P, V) (V) ? bitClear(*digitalPinToDDRReg(P), digitalPinToBit(P)) : (bitClear(*digitalPinToPortReg(P),digitalPinToBit(P));bitSet(*digitalPinToDDRReg(P), digitalPinToBit(P)))

This macro depends on the macros from the section above.  To use it, do nothing in setup(), do not use the usual pinMode(pin, OUTPUT); call.  Simply use digitalWriteLevelShift(pin,HIGH); or digitalWriteLevelShift(pin,LOW);.  As with the other functions, V can be a variable but pin (P) must meet all the restrictions for the other macros above.  For P, variables of type const will not work, #define does work.

An even bigger speedup can come from improving the way the ADC is read.  With default settings, the Arduino library sits doing nothing for about 110uS while waiting for the ADC to convert, that’s a very large chunk of time that could be used to do other things.

Courtesy Spinningspark at Wikipedia
Courtesy Spinningspark at Wikipedia

This one isn’t just limited to the Arduino library, the majority of code I’ve seen for all chips is done the same way.  There is another option:

Split the ADC read into 3 parts, Start, Poll, and Read.  To use it, you start a conversion, then continue doing whatever else you want, and poll whenever convenient to see if it’s done.  When the polling says it’s done, you read the result.  Usually you’ll start the first conversion in setup() and after each result, you’ll start the next reading.  The overall improvement is a bit hard to quantify but the startSample() call takes 2.1uS, the sampleDone() check takes 1.7uS and the getSampleResult() call takes 1.8uS leaving your code more than 100uS more time per ADC read to do calculations or to speed it’s main loop.  This might allow you to get your response latency for other things down to an acceptable level without resorting to interrupts and thereby simplify your system.  If you actually need the ADC to do more conversions per second, see part 2 of this article (referenced below the code.)

#include "wiring_private.h"
#include "pins_arduino.h"

void startSample(uint8_t pin){
  uint8_t analog_reference = DEFAULT;
  #if defined(analogPinToChannel)
    #if defined(__AVR_ATmega32U4__)
      if (pin >= 18) pin -= 18; // allow for channel or pin numbers
    pin = analogPinToChannel(pin);
  #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    if (pin >= 54) pin -= 54; // allow for channel or pin numbers
    #elif defined(__AVR_ATmega32U4__)
      if (pin >= 18) pin -= 18; // allow for channel or pin numbers
    #elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__)
      if (pin >= 24) pin -= 24; // allow for channel or pin numbers
      if (pin >= 14) pin -= 14; // allow for channel or pin numbers
  #if defined(ADCSRB) && defined(MUX5)
    // the MUX5 bit of ADCSRB selects whether we're reading from channels
    // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
    ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
  // set the analog reference (high two bits of ADMUX) and select the
  // channel (low 4 bits). this also sets ADLAR (left-adjust result)
  // to 0 (the default).
  #if defined(ADMUX)
    ADMUX = (analog_reference << 6) | (pin & 0x07);
  // without a delay, we seem to read from the wrong channel
  #if defined(ADCSRA) && defined(ADCL)
    // start the conversion
    sbi(ADCSRA, ADSC);
uint8_t sampleDone(){
  // ADSC is cleared when the conversion finishes
  return bit_is_clear(ADCSRA, ADSC);
uint16_t getSampleResult(){
  uint8_t low, high;
  // we have to read ADCL first; doing so locks both ADCL
  // and ADCH until ADCH is read. reading ADCL second would
  // cause the results of each conversion to be discarded,
  // as ADCL and ADCH would be locked when it completed.
  #if defined(ADCSRA) && defined(ADCL)
    low = ADCL;
    high = ADCH;
    // we dont have an ADC, return 0
    low = 0;
    high = 0;
  // combine the two bytes
  return (high << 8) | low;

Further improvements to ADC performance are in my post: Speeding up the ADC on an Arduino ATMega 328P

Next up is code for doing linear conversions and scaling.

This is similar to Arduino’s:

long map(long x, long in_min, long in_max, long out_min, long out_max)

The version presented here  doesn’t simply throw longer integers at the problem and it avoids doing everything with slower 32 bit math.

scale(): Effectively this is the same as a units conversion equation with support for different zero points such as the celsius conversion described at http://oakroadsystems.com/math/convert.htm
The equation is arranged as below to reduce lost precision from using integers by doing the division as late as possible.  The simple form should be familiar from 9th grade chemistry class.

The simple form of this equation is:

or solved for returnValue:

EXAMPLE 1: Fahrenheit to Celsius in integer

#define Extrapolate
int16_t c = scale(f,32,212,0,100);

//c=((70-212)*(0-100))/(32-212)+100 //70F randomly chosen
//c=14200/-180+100 //notice 14200 is quite large, that is the reason for the 32bit cast.
//c=22 //notice the error due to integer math, 21.111… is more accurate but to get that would require slower math.

EXAMPLE 2: Fahrenheit to Celsius in fixed point math (100ths of F -> 100ths of C)

#define Extrapolate
int16_t c = scale(f,3200,21200,0,10000);

//c=((7000-21200)*(0-10000))/(3200-21200)+10000 //70.00F randomly chosen
//c=142000000/-18000+10000 //notice 142,000,000 is quite large, that is the reason for the 32bit cast.
//c=2112 //21.12C is still a bit off but is much closer and runs without using much slower floating point math.

EXAMPLE 3:  Time correcting with linear iterpolation

GraphWhen correlating two sample sets, you often find that the offset time indexes don’t line up correctly.  If the data is compatible, often you can graph the samples on Y with time on X and draw a line between the closest two points, then find the intersection with the offset time of the sample in the other data set.  The image to the right shows an example group of data points from two sample sets graphed against time.  The 3 black points are the ones we’re using.

The process could also be used to take virtual samples at specific offset times, creating approximate data with regular intervals out of measured data at irregular intervals.


If the samples are:

Red[1] 19,72  Blue[1] 33,79
Red[2] 52,83  Blue[2] 66,90
Red[3] 89,93  Blue[3] 96,91
Red[3] 118,89

Then the above becomes:


Looking at the graph, we can visually observe that this is about right.

Without further ado, here is the code:

int16_t scale( int16_t inputValue,
               int16_t inputRangeOne,
               int16_t inputRangeTwo,
               int16_t outputRangeOne,
               int16_t outputRangeTwo){
//#define Extrapolate //define if values outside of inputRangeOne to inputRangeTwo are permitted
#ifndef Extrapolate
//special case for input at end of range or out of range.
// equation supports inverting (higher inputs result in lower outputs) so 
// detect that first to allow propper out/end of range detection
  if(inputRangeOne>inputRangeTwo){ //not input inverted
    if(inputValue>=inputRangeOne) return outputRangeOne;
    if(inputValue<=inputRangeTwo) return outputRangeTwo;
  }else{ //input inverted
    if(inputValue<=inputRangeOne) return outputRangeOne;
    if(inputValue>=inputRangeTwo) return outputRangeTwo;
  //main equation as described above
  return ((int32_t)((int16_t)inputValue-inputRangeTwo)*((int16_t)outputRangeOne-outputRangeTwo))/(inputRangeOne-inputRangeTwo)+outputRangeTwo;

More functions and macros will be added to this post over time.

“the breadboard image above was created with Fritzing”

ESP8266-01 Programming with an Arduino Nano


Programming the ESP8266-01 can have a bit of a steep learning curve.  If you have a Nano and an -01, this just might be your blog.

The approach presented here does away with the need to buy an extra  FTDI, CP2102, or CH340G serial adapter just to program your ESP8266.

When you’re done, you’ll have the ability to use the Nano as a programmer and the example program will give you a transparent wifi to serial gateway that you can use to communicate with your future Nano projects.

I’m going to assume some fairly minimal experience.  You need to be able to read resistor color codes or at least be willing to look them up.  I’ll assume you understand voltage dividers.  You need to be able to wire a breadboard and use a meter.

The tools you’ll need:
Arduino 1.6.4 IDE (or later)
Arduino Core for ESP8266
A Breadboard & a few jumper wires;  M-M and M-F types
A voltage meter that is accurate to 3 digits
An assortment of resistors
A single capacitor between 1uF and 10uF
An Arduino Nano clone
An LDO regulator like an LM317t or a DC-DC buck converter
A DC power source between 6.5V and 40V
If your supply is over about 15V, you’ll need a heat sink or the DC-DC buck converter

I picked a CH340G variant of the Nano because they’re cheap, it’s not FTDI and the drivers have been built into Linux for a long time.  Windows users might have more pain between incompatible FTDI clones, Russian sourced CH340G drivers, or scarce cp2102 based Nano boards.

Get your Nano working in the IDE first, if it doesn’t work then neither will this.  The code in your Nano doesn’t matter much as long as it works, I used the Blink example so that I could see visually if the Nano was running or being held in reset.

[Soothing music plays while you Google for another blog to help you get your Nano programmed for the first time]

LM317t pinout Next, we tackle power for the ESP8266-01.  It needs 3.0V to 3.6V and about 250mA of current.
We’ll be using an external power source because the Nano receives power from USB through a diode and the diodes used by cheap Nano clones like the one I have are 0.7V forward voltage leaving only 4.3V for the ATmega328p and the “+5V” pin.  My buck converter and my LDO couldn’t handle that low a voltage.
I picked an LM318t and a 12v battery that I had sitting here and I chose 3.40V in hopes of minimizing the level conversion headaches.  Wire your power supply at the far right of your breadboard.  The circuit is 12V to Vin, Vout to the +rail, a 2.2K resistor between Vout and Adj, and a 3.9K resistor to the ground rail.  The schematic is: LM317t schematic I took my handy multi-meter and measured the output…  3.65V, way too high, so some adjustments needed.  The LM317 formula said it should have been 3.47V so I was about .2V high.  .2V works out to about .4K lower on the 3.9K resistor so a parallel 33K resistor comes up about right.  I added the resistor and took another measurement, 3.40V dead on.  I picked the whole thing up and brought it to my nice bench meter, 3.3999V, not too shabby.
LM317t schematic The adjusted schematic is to the left.  Bottom line, each approximately 15k in parallel with the resistor to ground will reduce the voltage by .1V.  Try to get the voltage within .05V.  Note, some regulators or supplies don’t work well with no load, put 220 ohms across the output while taking this measurement and most are happy.  Add the 1uF to 10uF capacitor across the output and ground to keep things stable.

Now that there is power, the next thing to deal with is the level shift beteewn 5V the Nano and the ESP which is 3.3V.  The solution is easy, http://jamesreubenknowles.com/level-shifting-stragety-experments-1741 says there are lots of options but programming is a rare task so power loss doesn’t matter, a good strong signal and simplicity are the priorities.  A resistor divider with low value resistors meets the goal.  If you achieved 3.4V in the prior step and have a cheap Nano with 4.3V on the “5V” pin, then the resistor divider values work out to 330 ohms between the Nano’s RX pin and the -01’s RX pin and 1200 ohms from the -01’s RX to ground and results in 3.37V on the -01’s RX pin.  If you didn’t achieve 3.4V on the power supply, you may need to adjust the resistors here instead.   Note, we really are connecting the RX pin to the RX pin and not crossing them like you usually would.  That’s because we’re not talking to the Nano, but actually talking to the CH340G.

The TX pin on the Nano goes directly to the TX pin on the -01.

Connect a wire from the Nano’s RST pin to ground.  This will permanently hold the ATmega328p in reset and prevent it from bothering the RX and TX pins what we’re using to talk with the CH340G.

Breadboard Image

Lastly, we need to wire up the rest of the pins on the -01.  The main points are to connect power, connect GPIO0 to ground to request programming mode, CHPD to 3.4V, and reset to 3.4V through a small resistor.  This resistor should be over 300 ohms and under 33K ohms, but is not critical otherwise, use 2.2K if convenient.  The complete breadboard that I used is to the right.

Now that we have hardware, install the ESP8266 Core using the instructions at https://github.com/esp8266/Arduino#installing-with-boards-manager

The promised serial gateway program is basically just a slightly patched version of the example WiFiTelnetToSerial.  I adjusted the sbuf allocation and the port but other than that I only removed all the serial messages.  Given that not much was done, I’ll go straight to the code:

  Based entirely on the WiFiTelnetToSerial Example 

  Copyright (c) 2015 Hristo Gochkov. All rights reserved.
  This file is part of the ESP8266WiFi library for Arduino environment.
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
#include <ESP8266WiFi.h> 

//how many clients should be able to telnet to this ESP8266

#define TCP_PORT 2167 //raw-serial
#define MAX_BUFF 32
const char* ssid = "********";
const char* password = "************";

WiFiServer server(TCP_PORT);
WiFiClient serverClients[MAX_SRV_CLIENTS];

void setup() {
  WiFi.begin(ssid, password);
  uint8_t i = 0;
  while (WiFi.status() != WL_CONNECTED && i++ < 20) delay(500);
  if(i == 21){
    while(1) delay(500);
  //start UART and the server

void loop() {
  uint8_t i;
  size_t bufsize = MAX_BUFF;
  uint8_t sbuf[bufsize];
  //check if there are any new clients
  if (server.hasClient()){
    for(i = 0; i < MAX_SRV_CLIENTS; i++){
      //find free/disconnected spot
      if (!serverClients[i] || !serverClients[i].connected()){
        if(serverClients[i]) serverClients[i].stop();
        serverClients[i] = server.available();
    //no free/disconnected spot so reject
    WiFiClient serverClient = server.available();
  //check clients for data
  for(i = 0; i < MAX_SRV_CLIENTS; i++){
    if (serverClients[i] && serverClients[i].connected()){
        //get data from the telnet client and push it to the UART
        while(serverClients[i].available()) Serial.write(serverClients[i].read());
  //check UART for data
    size_t len = Serial.available();
    if(len>MAX_BUFF) len=MAX_BUFF;
    Serial.readBytes(sbuf, len);
    //push UART data to all connected telnet clients
    for(i = 0; i < MAX_SRV_CLIENTS; i++){
      if (serverClients[i] && serverClients[i].connected()){
        serverClients[i].write(sbuf, len);

To use this code, paste it into the IDE, edit the SSID and Password, choose board type “Generic ESP8266 Module”, plug in your Nano’s USB cable, and choose the appropriate USB port.

To enter programming mode, we add just one more jumper wire from reset to ground.  To program, you connect this wire, then press the “Upload” Button Image button in the Arduino IDE, wait for the white text to stop scrolling, then pull the wire.  The timing is tricky, for me I wait about 1 second after the white text stops but try different delays until you find one that works for you.  I still only succeed about half the time so don’t feel bad if it takes some trial and error to get the timing right.  Once you have something programmed, remove the GPIO0 wire and reset again to let it run.

Using your new Serial Gateway with your Nano project, you may have to adjust the voltage divider on the -01’s RX pin to match the voltage on the “+5V” pin when installed in your project.  Use the Raltron.com voltage divider calculator (link below) to find small resistors that provide just a hair under the -01’s voltage when the input voltage is whatever you measure on the Nano’s “+5V” pin.  The sum of the two resistors added together should be between about 1K and 2K so that you get a nice clean signal.  If you’re using a battery or are power sensitive, consider one of the other level shift options over at jamesreubenknowles.com or the links in his Addendum, this one is power hungry.  Make sure the level shifter or divider stays on the -01’s RX pin.  Since we’ll be connecting to the Nano and not the CH340G, you now cross the RX and TX pins like usual and since we’re using those pins, nothing can be connected to the USB data pins.  Note most chargers short the data pins and that may activate the USB chip which could blow up either the USB chip or the -01.  If you do decide to try a USB charger, at least put a 1K resistor on the -01’s TX line to give it a chance should your USB chip be activated.  Talking to it is as simple as opening a terminal and entering:

nc ipaddress 2167



“the breadboard image above was created with Fritzing”

Fedora 23 on Raspberry Pi 2 or 3

Raspberry Pi 2B
Credit: raspberrypi.org

Installing Fedora 23 on the Pi2 or 3 is pretty reasonable with a little effort and worth the trouble.  A real distro may not be exactly snappy on the Pi3 but the advantage of a familiar environment with a real browser makes up for a little slowness. Something to note, activating WiFi is not included here, so have a wired connection please.

If you came in from Redit or StackExchange or similar, please upvote my posting there so that others will see this page too.

pi 2B Terminal I’m going to assume you have the ability to write a Raspberry image to SD card with some confidence, to issue basic commands in a terminal session and that you have root access on a Linux machine to work with. My apologies to those with more skills but I’m targeting as wide an audience as possible. These instructions were tested using copy and paste from each of the code blocks below. If you’re unable to copy and paste, please pay careful attention to word-wrap because some of the lines are rather long.

I started with Jon Archer’s directions along with the steps in the comments plus a missing instruction that was critical to my install; with his directions the USB mouse and keyboard don’t work until you upgrade the Pi’s firmware images. Here I avoid the issue by downloading the firmware .zip file rather than cloning the firmware repository.

Download your interface of choice from http://mirrors.oit.uci.edu/fedora/linux/releases/23/Images/armhfp/

In my case, I used Mate in hopes of a reasonable trade off between resources and capabilities. My choice would be:

wget http://mirrors.oit.uci.edu/fedora/linux/releases/23/Images/armhfp/Fedora-Mate-armhfp-23-10-sda.raw.xz

Download errors happen so before wasting a ton of time on a bad image, compare the checksum in http://mirrors.oit.uci.edu/fedora/linux/releases/23/Images/armhfp/Fedora-Images-armhfp-23-CHECKSUM to the output of:

sha256sum Fedora-Images-armhfp-23-CHECKSUM

The mirrors I used were all throttled and the only torrent I found had only 2 seeders, so I recommend doing the following download in parallel in an additional terminal session:

wget -O ~/Downloads/master.zip https://github.com/raspberrypi/firmware/archive/master.zip

SD Card Before issuing the commands below, make sure you know exactly where your sdcard is and that your device options match the device.  A good way to find it is to insert the card and run:

dmesg | tail

Some likely names include /dev/sda, /dev/sdb, and /dev/mmcblk0.

I didn’t have a desktop with Windows, IOS or Linux, just the Pi2 running Raspbian, so I used a SD to USB adapter which appears as /dev/sda.  Make sure all the partitions on your SD card are not mounted and unmount them if needed.  Mine had one partition auto-mounted so I unmounted that with the following command:

umount /dev/sda1

This command, like just about everything below, requires root.

The next step was to copy the image to SD with the following command (again edit the version number if needed):

xzcat Fedora-Mate-armhfp-23-10-sda.raw.xz |dd of=/dev/sda bs=1M;sync

The image write took 16 minutes for me, so this might be a good time to get a fresh cup of coffee.

Change the partition type of partition 1 from 0x83 to 0x0B and expand the root partition to fill the disk with your preferred tools or with something like:

echo -e "p\nt\n1\nb\nd\n3\nn\np\n3\n`fdisk -l /dev/sda|tail -1|tr -s ' '|cut -d' ' -f2`\n\np\nw\n"|fdisk /dev/sda; sync; partprobe

Replace the ext3 filesystem with a fat32 one using:

mkfs.vfat /dev/sda1

Expand the root partition to fill the disk with:

e2fsck -f /dev/sda3
resize2fs /dev/sda3

Mount the partitions with:

mkdir /mnt/sdcard
mount /dev/sda3 /mnt/sdcard
mount /dev/sda1 /mnt/sdcard/boot

Extract the boot and module files from the raspberry firmware archive downloaded earlier:

unzip ~/Downloads/master.zip firmware-master/boot/* -d /mnt/sdcard/boot/
mv /mnt/sdcard/boot/firmware-master/boot/* /mnt/sdcard/boot/
rm -rf /mnt/sdcard/boot/firmware-master
unzip ~/Downloads/master.zip firmware-master/modules/*-v7+/* -d /mnt/sdcard/lib/
mv /mnt/sdcard/lib/firmware-master/modules/*-v7+/ /mnt/sdcard/lib/modules/
rm -rf /mnt/sdcard/lib/firmware-master/

Edit /mnt/sdcard/etc/fstab, setting the boot partition type to vfat and replacing the UUID of the boot partition with the UUID from:

blkid -s UUID /dev/sda1

Note, vfat UUIDs really are much shorter.  It will be 8 hex digits with a dash in the middle.

Create the cmdline.txt file with:

echo "dwc_otg.lpm_enable=0 console=ttyAMA0,115200 console=tty1 \
root=/dev/mmcblk0p3 rootfstype=ext4 elevator=deadline rootwait"\

Create config.txt with something like:

cat </mnt/sdcard/boot/config.txt

The above settings force full HD over HDMI with no overscan, even if you boot while the monitor is off or disconnected.  Adjust as needed per the Raspberry PI docs, or pull the config.txt from your existing Pi setup.

Install rpi-update with:

wget -O /mnt/sdcard/usr/bin/rpi-update https://raw.githubusercontent.com/Hexxeh/rpi-update/master/rpi-update
chmod +x /mnt/sdcard/usr/bin/rpi-update

Adjust the root password by copying from an existing /etc/shadow file to /mnt/sdcard/etc/shadow.  The password is the long string between the 1st and 2nd : characters, or set it using the following commands:

read -s -p "Enter password: " pass
echo -n root:$pass | chpasswd -c SHA512 -R /mnt/sdcard

Finish up this phase of the install with:

umount /mnt/sdcard/boot
umount /mnt/sdcard

Install the SD card in your Pi2 and boot.

At this point, your Pi2 pi might come up to the Fedora first boot screen but the mouse and keyboard don’t work.  The problem will probably be resolved by running rpi-update.

Get the DHCP address from your router or DHCP server and ssh into the Pi2 as root.  (if you’re doing all this from your Pi2 like I did, you can reasonably guess that the address won’t change.)  In my case, this was the only “desktop” I had so I used ConnectBot from my phone.

Install binutils so that rpi-update can run:

dnf install binutils

Update your Fedora install and Pi2 firmware with:

dnf update

Reboot with the new firmware and the mouse/keyboard should work:

init 6

Complete the Fedora firstboot menus.

At this point, you have a basic functioning Fedora desktop.

If sound is not working in 23, try this:
cat </etc/modules-load.d/snd_bcm2835.conf
#load Raspberry Pi sound module
modprobe snd_bcm2835

See my next post about what to do after install to make a more complete desktop Fedora system with multimedia.