Page 1 of 14
SparkFun Blocks for Intel® Edison - Arduino
Block
Introduction
The Arduino Block for Edison provides the Intel® Edison with a direct, serial
link to an Arduino-compatible ATmega328 microprocessor.
Why would you need an Arduino connected to your Edison? Isn’t it powerful
enough to handle anything that may be thrown at it? That’s the problem –
it’s almost too powerful. Because it’s running an operating system, it’s
incapable of real-time processing – the bread-and-butter of smaller
microcontrollers like the ATmega328. Components which require precise
timing – like WS2812 LEDs or servo motors – may be incompatible with the
Edison as it can’t reliably generate clock signals.
The Arduino block allows the Edison to offload those lower-level hardware
tasks. Additional to that, if you’ve already written Arduino code for an
external component, you don’t have to port that code to the Edison – just
run it on an Arduino block!
Suggested Reading
If you are unfamiliar with Blocks, take a look at the General Guide to
Sparkfun Blocks for Intel Edison.
Other tutorials that may help you on your Arduino Block adventure include:
•
•
•
•
Edison Getting Started Guide
Powering Your Project
What is an Arduino?
Using the Arduino Pro Mini 3.3V
Board Overview
Page 2 of 14
• Expansion Header – The 70-pin Expansion header breaks out the
functionality of the Intel Edison. This header also passes signals and
power throughout the stack. These function much like an Arduino
Shield.
• Arduino I/O Pins – All of the Arduino’s I/O pins are broken out to a
pair of headers (plus a couple in between). This header footprint
exactly matches that of the Arduino Pro Mini – if you have any Mini
shields they should mate exactly to this header.
• Arduino Programming Header – The standard 6-pin FTDI header is
used to program the Arduino’s serial bootloader. Plug a 3.3V FTDI
Basic in to program your Arduino.
• D13 LED – Every good Arduino needs an LED! This small, green
LED is tied to the Arduino’s pin 13. Great for blinking “Hello, world” or
debugging.
• Power LED – The Arduino block has an on-board 3.3V regulator,
and this LED is tied to the output of that regulator.
• Arduino Reset Button – This reset button is tied to the Arduino’s
reset line. It will only reset the Arduino; it has no effect on the Edison.
Schematic Overview
The Arduino block pairs the ATmega328 to your Edison via one of two
UARTs. The board defaults to connecting the Arduino to Edison via
UART1. Jumpers (see more below) allow you to select UART2, if your
application requires. Take care using UART2, though, it’s default utility is
for console access to the Edison.
The Arduino Block has an on-board 3.3V voltage regulator, which takes its
input from the Edison’s VSYS bus. Since the Arduino is running at 3.3V, its
clock speed is limited to 8MHz.
If you want to take a closer look at the schematic, download the PDF here.
Jumpers
On the back-side of the Arduino block, there are a handful of jumpers,
which lend extra utility to the board.
Three two-way jumpers – for RX, TX, and DTR – allow you to select
between UART1 (default) and UART2. To switch these jumpers, grab a
hobby knife, cut the default traces, and drop a solder blob between the
middle pad and outer pad of your choice.
Page 3 of 14
The jumper labeled VIN/VSYS allows you to remove the VSYS line from
powering the Arduino block. This is handy if you need to isolate the Arduino
block’s power source from the Edison. In this case, you’ll need to supply
power (3.3-12V) externally via the “VIN” pin.
Using the Arduino Block
To use the Arduino Block, attach it to either an Edison or add it to a stack of
other SparkFun Block’s.
Arduino block stacked on top of a GPIO Block and a Base Block.
In order to supply power to your Edison, you’ll need at least one additon
Block in your stack. You can use a Base Block or Battery Block, for
example.
Programming the Arduino
The Arduino on the Arduino Block can be programmed while it’s either on
or off the Edison. Depending on your application, though, it’s recommended
that you load code on the Arduino while it’s disconnected from your Edison
stack, before adding it to the rest of the system.
If you’ve ever uploaded an Arduino sketch to an Arduino Pro or Pro Mini,
you’re already familiar with uploading code to the Arduino block. Connect a
3.3V FTDI Basic to the 6-pin FTDI header on the board.
Using a 3.3V FTDI Basic to program the Arduino on the Arduino Block.
In Arduino (the non-Edison version of Arduino!), select “Arduino Pro or Pro
Mini 3.3V/8MHz” from the Tools > Board menu. If you’re using the latest
release of Arduino (1.6 or later), first select Arduino Pro or Pro Mini from
the “Board” menu.
Page 4 of 14
Then select ATmega328 (3.3V, 8MHz) from the “Processor” menu.
Then upload away!
Using the Arduino Pins
The Arduino’s I/O pins are all broken out to a pair of headers. These
headers match up exactly to the Arduino Pro Mini. If you have any shields
or piggyback boards for a Pro Mini, it should work seamlessly with the
Arduino Block.
You can solder headers, wires, or any other connectors to these pins.
If you’re soldering headers to the pins, take extra care deciding which side
to solder to. Depending on the rest of your Edison stackup, those headers
might get in the way of connectors on other boards (the USB connectors on
the Base and Console Blocks, in particular).
Connecting the Edison to the Arduino
The Arduino Block connects the Arduino to the Edison through a serial
(UART) connection. Jumpers on the back of the board allow you select
which of the Edison’s two UARTs mate with the Arduino. Unless you can’t
avoid it, we recommend leaving the jumpers in the default configuration –
the Edison’s UART2 is usually devoted to console access.
Page 5 of 14
To program the Edison to control and interact with the Arduino, you’ll need
to use the UART to establish a communication protocol between the
devices. See the next section for an easy example of UART communication
between Arduino and Edison.
Controlling the Arduino Block with
Firmata
Firmata is an established protocol popular within the Arduino realm for
applications that require a separate machine (usually a computer) to control
the Arduino. It’s a serial-based protocol that uses defined messages to set
digital pins, read analog pins, and do everything else you’re used to with
Arduino.
Firmata is so useful, the standard Arduino IDE even ships with the Firmata
library. Here’s an example of how an Edison can be used to control and
interact with an Arduino running Firmata.
Upload StandardFirmata to the Arduino
Before uploading any code to the Edison, let’s load something into the
Arduino. Once the Firmata code is running on your Arduino, you may never
have to upload code to it again.
Using the standard Arduino IDE (i.e. not the IDE built for Edison), load up
the “StandardFirmata” sketch by going to File > Examples > Firmata >
StandardFirmata. If you have the Codebender addon installed, you can
use the embed below to upload the code to your Arduino Block.
StandardFirmata (/example/Firmata/StandardFirmata?board=Arduino%
[ Edit
È Clone & Edit
3 Download
20Pro%20or%20Pro%20Mini%20(3.3V,%208%20MHz)%20w/%
1 /*
(/? communicating
(https://codebende
2
* Firmata is a generic protocol for
with mic
20ATmega328)
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
* from software on a host computer. It is intended to work
* any host computer software
package.
board=Arduino%
board=Arduino%
*
* To download a host software package, please clink on the
20Pro%20or%
* to open the download page 20Pro%20or%
in your default browser.
*
* http://firmata.org/wiki/Download
20Pro%20Mini% 20Pro%20Mini%
*/
/*
Copyright
Copyright
Copyright
Copyright
20(3.3V,%208% 20(3.3V,%208%
(C)
(C)
(C)
(C)
20062008 HansChristoph Steiner. All righ
20MHz)%20w/%
20MHz)%20w/%
20102011 Paul
Stoffregen. All
rights rese
2009 Shigeru Kobayashi. All rights reserve
20092011 Jeff
Hoefs. All rights
reserved.
20ATmega328)
20ATmega328)
This library is free software; you can redistribute it an
modify it under the terms of the GNU Lesser General Publi
License as published by the Free Software Foundation; eit
version 2.1 of the License, or (at your option) any later
See file LICENSE.txt for further informations on licensin
formatted using the GNU C formatting and indenting
*/
/*
* TODO: use Program Control to load stored profiles from E
Arduino Pro or Pro Min
With the Firmata firmware uploaded, you can disconnect the FTDI Basic,
and connect the Arduino Block to your Edison stack.
Edison Firmata for Arduino Client
Page 6 of 14
The harder part of this equation is writing something that executes on the
Edison which interacts with our Firmata-running Arduino. There are tons of
great client examples in the Firmata GitHub profile, but nothing quite built
for the Edison.
Riffing on the Firmata Processing example, we wrote this sketch to enact
an Edison Firmata client.
Arduino version alert! This Arduino sketch is intended to run on the
Edison. You'll need to download the Edison Arduino IDE, and use that
to upload this code to your Edison. For more help programming the
Edison in Arduino, check out our Getting Started with Edison tutorial.
Here’s the sketch. Copy/paste from below, or grab the latest version from
this Gist:
Page 7 of 14
/*************************************************************
***
Edison Firmata Client
by: Jim Lindblom @ SparkFun Electronics
created on: Februrary 12, 2015
github:
This is an Firmata client sketch for the Edison. It can
communicate with an Arduino running Firmata over a Serial
connection.
Support for the following functions is written:
firmata_init() set up firmata and pin reporting
firmata_pinMode([pin], [0, 1, 2, 3, 4, 5, 6])
firmata_digitalWrite([pin], [LOW/HIGH])
firmata_analogWrite([pin], [0255])
firmata_analogRead([07])
firmata_digitalRead([pin])
firmata_servoWrite([pin], [value])
Development Environment Specifics:
Arduino 1.5.3 (for Edison)
Intel Edison rev C
Arduino Block for Edison
Arduino should be running StandardFirmata
This sketch is based on Firmata's processing client:
https://github.com/firmata/processing
As such, it is released under the same, free license. You c
an
redistribute it and/or modify it under the terms of the GN
U
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.
Distributed asis; no warranty is given.
**************************************************************
**/
// SerialEvent1 isn't defined in the Edison core (I think).
// To get some form of interruptdriven Serial input, we'll re
ad
// serial in on a timer.
#include
#define MAX_DATA_BYTES 4096
#define MAX_PINS 128
// Pin Mode definitons:
// Use any of these six values to set a pin to INPUT, OUTPUT,
// ANALOG, PWM, SERVO, SHIFT, or I2C.
enum const_pin_mode {
MODE_INPUT, // 0
MODE_OUTPUT, // 1
MODE_ANALOG, // 2
MODE_PWM, // 3
MODE_SERVO, // 4
MODE_SHIFT, // 5
MODE_I2C // 6
};
// Message Types
// Used by the lowlevel Firmata functions to set up the
// Firmata messages.
Page 8 of 14
#define ANALOG_MESSAGE 0xE0
#define DIGITAL_MESSAGE 0x90
#define REPORT_ANALOG 0xC0
#define REPORT_DIGITAL 0xD0
#define START_SYSEX 0xF0
#define SET_PIN_MODE 0xF4
#define END_SYSEX 0xF7
#define REPORT_VERSION 0xF9
#define SYSTEM_RESET 0xFF
// Extended Commands:
// Used by the lowlevel Firmata functions to set up the
// Firmata messages.
#define SERVO_CONFIG 0x70
#define STRING_DATA 0x71
#define SHIFT_DATA 0x75
#define I2C_REQUEST 0x76
#define I2C_REPLY 0x77
#define I2C_CONFIG 0x78
#define EXTENDED_ANALOG 0x6F
#define PIN_STATE_QUERY 0x6D
#define PIN_STATE_RESPONSE 0x6E
#define CAPABILITY_QUERY 0x6B
#define CAPABILITY_RESPONSE 0x6C
#define ANALOG_MAPPING_QUERY 0x69
#define ANALOG_MAPPING_RESPONSE 0x6A
#define REPORT_FIRMWARE 0x79
#define SAMPLING_INTERVAL 0x7A
#define SYSEX_NON_REALTIME 0x7E
#define SYSEX_REALTIME 0x7F
// Flags and variables to keep track of message reading statu
s:
boolean parsingSysex = false;
int waitForData = 0;
int storedInputData[MAX_DATA_BYTES];
int sysexBytesRead = 0;
int executeMultiByteCommand = 0;
int multiByteChannel = 0;
// Variable arrays to keep track of pin values read in.
int digitalInputData[] = {0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0};
int analogInputData[] = {0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0};
int analogChannel[MAX_PINS];
boolean blinkFlag = false;
void setup()
{
// Debug messages are sent out Serial. Use the Serial monito
r
// at 9600 bps to read pin values.
Serial.begin(9600);
// firmata_init sets up our firmata client. It tells the
// Firmata device to begin streaming analog values and any
// digital pin value changes.
firmata_init();
// Use firmata_pinMode([pin], [value]) to set up pins on the
// Firmata host:
firmata_pinMode(13, MODE_OUTPUT); // LED tied to pin 13
firmata_pinMode(4, MODE_INPUT); // Digital input on pin 4
firmata_pinMode(A0, MODE_ANALOG); // Analog input on pin 0
firmata_pinMode(3, MODE_PWM); // PWM LED on pin 3
Page 9 of 14
}
void loop()
{
// Print the value of our Firmata Arduino's A0 pin:
int a0Value = firmata_analogRead(0);
Serial.print("A0: ");
Serial.println(a0Value);
// Print the value of our digital input on pin 4:
int d4Value = firmata_digitalRead(4);
Serial.print("Pin 4: ");
Serial.println(d4Value);
if (d4Value == LOW)
{
// Scale the value of A0 to write a PWM output on pin 3:
firmata_analogWrite(3, firmata_analogRead(0) / 4);
}
else
{
// Scale the value of A0 to write a PWM output on pin 3:
firmata_analogWrite(3, 0);
}
}
///////////////////////////////////
// Upper Level Firmata Functions //
///////////////////////////////////
// Firmata functions that you should use in your sketch above.
// If this was a class, these'd be public functions.
// firmata_init()
// Initialize our Firmata Serial port.
// Set up a timer to read in Serial messages outside of loop
().
// Configure our Firmata Arduino to report all digital outpu
ts
// Configure our Firmata Arduino to report all analog output
s
void firmata_init()
{
Serial1.begin(57600);
// set a timer of length 100,000 microseconds ( 0.1 sec o
r 10Hz)
Timer1.initialize(1000);
Timer1.attachInterrupt( checkSerial ); // attach the servic
e routine here
// Turn on reporting for all digital ports
for (int i=0; i> 3) & 0x0F;
int data;
if (value)
data |= (1 7); // Digital pin 7 bitmask
}
// firmata_analogWrite([pin], [value])
// Set an Arduino pin CONFIGURED AS PWM (!) to an
// analog output value.
// [pin] Any analog output capable pin (3, 5, 6, 9, 10, 11
// [value] 0255
void firmata_analogWrite(int pin, int value)
{
Serial1.write(ANALOG_MESSAGE | (pin& 0x0F)); // Analog pin
Page 11 of 14
Serial1.write(value & 0x7F); // Analog LS 7 bits
Serial1.write(value >> 7); // Analog MS 7 bits
}
// firmata_servoWrite([pin], [value])
// Set an Arduino pin CONFIGURED AS SERVO (!) to output
// a servo signal.
void firmata_servoWrite(int pin, int value)
{
Serial1.write(ANALOG_MESSAGE | (pin & 0x0F));
Serial1.write(value & 0x7F);
Serial1.write(value >> 7);
}
/////////////////////////////////
// Low level Firmata functions //
/////////////////////////////////
// Firmata helper functions you probably won't need to call in
// your sketch. If this was a class, these'd be private functi
ons.
// checkSerial()
// Interruptrecurring function. Checks for available serial d
ata
// and processes any serial messages that come in.
void checkSerial()
{
while (Serial1.available())
{
//Serial.write(Serial1.read());
firmata_processInput((unsigned char) Serial1.read());
}
if (blinkFlag)
{
firmata_digitalWrite(13, HIGH); // Tell Arduino to write 1
3 HIGH
blinkFlag = false;
}
else
{
firmata_digitalWrite(13, LOW); // Tell Arduino to write 1
3 HIGH
blinkFlag = true;
}
}
// firmata_processInput([inputData])
// Handles all Firmata messages everything from version chec
ks
// to analog and digital readings.
void firmata_processInput(unsigned char inputData)
{
int command;
if (parsingSysex) // If we're parsing a system message
{
if (inputData == END_SYSEX)
{ // Received end of system message, process it
parsingSysex = false;
firmata_processSysexMessage();
}
else
{ // In the system message, add to it
storedInputData[sysexBytesRead] = inputData;
sysexBytesRead++;
Page 12 of 14
}
}
else if (waitForData > 0 && inputData < 128)
{ // Else waiting for data
waitForData; // Decrement wait for data
storedInputData[waitForData] = inputData;
if (executeMultiByteCommand != 0 && waitForData == 0)
{
switch(executeMultiByteCommand)
{
case DIGITAL_MESSAGE:
firmata_setDigitalInputs(multiByteChannel,
(storedInputData[0]