Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial pass at ESP32 support #71

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
49 changes: 43 additions & 6 deletions examples/ConfigurableFirmataWiFi/ConfigurableFirmataWiFi.ino
Expand Up @@ -14,7 +14,7 @@
Copyright (C) 2013 Norbert Truchsess. All rights reserved.
Copyright (C) 2014 Nicolas Panel. All rights reserved.
Copyright (C) 2015-2016 Jesse Frush. All rights reserved.
Copyright (C) 2009-2016 Jeff Hoefs. All rights reserved.
Copyright (C) 2009-2017 Jeff Hoefs. All rights reserved.
Copyright (C) 2016 Jens B. All rights reserved.

This library is free software; you can redistribute it and/or
Expand All @@ -24,7 +24,7 @@

See file LICENSE.txt for further informations on licensing terms.

Last updated by Jeff Hoefs: August 14th, 2016
Last updated by Jeff Hoefs: May 28th, 2017
*/

/*
Expand All @@ -43,6 +43,7 @@
- ESP8266 WiFi board compatible with ESP8266 Arduino core
- Arduino WiFi Shield 101
- Arduino WiFi Shield (or clone)
- ESP32 board compatible with ESP32 Arduino core

Follow the instructions in the wifiConfig.h file (wifiConfig.h tab in Arduino IDE) to
configure your particular hardware.
Expand All @@ -53,6 +54,7 @@
https://github.com/arduino-libraries/WiFi101)
- ESP8266 requires the Arduino ESP8266 core v2.1.0 or higher which can be obtained here:
https://github.com/esp8266/Arduino
- ESP32 requires the Arduino ESP32 core: https://github.com/espressif/arduino-esp32

In order to use the WiFi Shield 101 with Firmata you will need a board with at least 35k of Flash
memory. This means you cannot use the WiFi Shield 101 with an Arduino Uno or any other
Expand Down Expand Up @@ -85,7 +87,7 @@
* connection that may help in the event of connection issues. If defined, some boards may not begin
* executing this sketch until the Serial console is opened.
*/
//#define SERIAL_DEBUG
#define SERIAL_DEBUG
#include "utility/firmataDebug.h"

#define MAX_CONN_ATTEMPTS 20 // [500 ms] -> 10 s
Expand All @@ -100,8 +102,8 @@
*============================================================================*/

// STEP 1 [REQUIRED]
// Uncomment / comment the appropriate set of includes for your hardware (OPTION A, B or C)
// Arduino MKR1000 or ESP8266 are enabled by default if compiling for either of those boards.
// Uncomment / comment the appropriate set of includes for your hardware (OPTION A, B, C, or D).
// Arduino MKR1000, ESP8266 and ESP32 boards are enabled by default if compiling for any of those boards.

/*
* OPTION A: Configure for Arduino MKR1000 or Arduino WiFi Shield 101
Expand Down Expand Up @@ -186,6 +188,30 @@
#endif
#endif

/*
* OPTION D: Configure for ESP32
*
* This will configure ConfigurableFirmataWiFi to use the ESP32 WiFi library for boards
* with an ESP32 chip. It is compatible with 802.11 B/G/N networks.
*
* The appropriate libraries are included automatically when compiling for the ESP32 so
* continue on to STEP 2.
*
* IMPORTANT: You must have the esp32 board support installed. To easily install this board see
* the instructions here: https://github.com/espressif/arduino-esp32#installation-instructions.
*/
#ifdef ESP32
#define ESP32_WIFI
#include <WiFi.h>
#include "utility/WiFiClientStream.h"
#include "utility/WiFiServerStream.h"
#ifdef WIFI_LIB_INCLUDED
#define MULTIPLE_WIFI_LIB_INCLUDES
#else
#define WIFI_LIB_INCLUDED
#endif
#endif


// STEP 2 [OPTIONAL for all boards and shields]
// By default the board/shield is configured as a TCP server.
Expand Down Expand Up @@ -282,7 +308,7 @@ char wep_key[] = "your_wep_key";
#error "you must define a wifi security type in wifiConfig.h."
#endif //WIFI_* security define check

#if (defined(ESP8266_WIFI) && !(defined(WIFI_NO_SECURITY) || (defined(WIFI_WPA_SECURITY))))
#if ((defined(ESP8266_WIFI) || defined(ESP32_WIFI)) && !(defined(WIFI_NO_SECURITY) || (defined(WIFI_WPA_SECURITY))))
#error "you must choose between WIFI_NO_SECURITY and WIFI_WPA_SECURITY"
#endif

Expand Down Expand Up @@ -317,6 +343,9 @@ char wep_key[] = "your_wep_key";
#elif defined(ESP8266_WIFI) && defined(SERIAL_DEBUG)
#define IS_IGNORE_PIN(p) ((p) == 1)

#elif defined(ESP32_WIFI) && defined(SERIAL_DEBUG)
#define IS_IGNORE_PIN(p) ((p) == 1 || (p) == 3)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not been able to determine if this is absolutely necessary for the ESP32 since the connection is so flaky.


#endif

/*==============================================================================
Expand All @@ -339,12 +368,18 @@ DigitalOutputFirmata digitalOutput;
#include <AnalogInputFirmata.h>
AnalogInputFirmata analogInput;

// analogWrite not supported for ESP32 boards
#ifndef ESP32
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hate to have to do this... will probably not merge this branch until analogWrite is added to the esp32 library.

#include <AnalogOutputFirmata.h>
AnalogOutputFirmata analogOutput;
#endif

// servo not supported for ESP32 boards
#ifndef ESP32
#include <Servo.h>
#include <ServoFirmata.h>
ServoFirmata servo;
#endif
// ServoFirmata depends on AnalogOutputFirmata
#if defined ServoFirmata_h && ! defined AnalogOutputFirmata_h
#error AnalogOutputFirmata must be included to use ServoFirmata
Expand Down Expand Up @@ -514,6 +549,8 @@ void initTransport()
DEBUG_PRINTLN( "using the legacy WiFi library." );
#elif defined(ESP8266_WIFI)
DEBUG_PRINTLN( "using the ESP8266 WiFi library." );
#elif defined(ESP32_WIFI)
DEBUG_PRINTLN( "using the ESP32 WiFi library." );
//else should never happen here as error-checking in wifiConfig.h will catch this
#endif //defined(WIFI_101)

Expand Down
10 changes: 8 additions & 2 deletions src/AnalogInputFirmata.cpp
Expand Up @@ -52,7 +52,8 @@ void AnalogInputFirmata::reportAnalog(byte analogPin, int value)
// Send pin value immediately. This is helpful when connected via
// ethernet, wi-fi or bluetooth so pin states can be known upon
// reconnecting.
Firmata.sendAnalog(analogPin, analogRead(analogPin));
// Firmata.sendAnalog(analogPin, analogRead(analogPin));
Firmata.sendAnalog(analogPin, analogRead(analogInputToDigitalPin(analogPin)));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should really be fixed in the esp32 arduino library. analogRead should be able to accept the analog pin number or the digital pin number.

}
}
}
Expand All @@ -79,7 +80,11 @@ void AnalogInputFirmata::handleCapability(byte pin)
{
if (IS_PIN_ANALOG(pin)) {
Firmata.write(PIN_MODE_ANALOG);
#ifdef DEFAULT_ADC_RESOLUTION
Firmata.write(DEFAULT_ADC_RESOLUTION);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be added for all of the StandardFirmata variants in the firmata/arduino repo as well.

#elif
Firmata.write(10); // 10 = 10-bit resolution
#endif
}
}

Expand All @@ -102,7 +107,8 @@ void AnalogInputFirmata::report()
if (IS_PIN_ANALOG(pin) && Firmata.getPinMode(pin) == PIN_MODE_ANALOG) {
analogPin = PIN_TO_ANALOG(pin);
if (analogInputsToReport & (1 << analogPin)) {
Firmata.sendAnalog(analogPin, analogRead(analogPin));
// Firmata.sendAnalog(analogPin, analogRead(analogPin));
Firmata.sendAnalog(analogPin, analogRead(analogInputToDigitalPin(analogPin)));
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/AnalogOutputFirmata.cpp
Expand Up @@ -20,6 +20,11 @@
#include "AnalogFirmata.h"
#include "AnalogOutputFirmata.h"

// Hack to compile for ESP32 boards until arduino-esp32 supports analogWrite
#ifdef ESP32
void analogWrite(byte pin, int value);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Necessary because Arduino compiles all cpp files whether or not they are included.

#endif

AnalogOutputFirmata::AnalogOutputFirmata()
{
Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
Expand Down
8 changes: 5 additions & 3 deletions src/ConfigurableFirmata.h
Expand Up @@ -100,8 +100,8 @@
#define SYSEX_SAMPLING_INTERVAL 0x7A // same as SAMPLING_INTERVAL

// pin modes
//#define INPUT 0x00 // defined in Arduino.h
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the esp32 library redefines INPUT, OUTPUT and ANALOG

//#define OUTPUT 0x01 // defined in Arduino.h
#define PIN_MODE_INPUT 0x00 // pin connfigured for digital input
#define PIN_MODE_OUTPUT 0x01 // pin configured for digital output
#define PIN_MODE_ANALOG 0x02 // analog pin in analogInput mode
#define PIN_MODE_PWM 0x03 // digital pin in PWM output mode
#define PIN_MODE_SERVO 0x04 // digital pin in Servo output mode
Expand All @@ -115,7 +115,9 @@
#define PIN_MODE_IGNORE 0x7F // pin configured to be ignored by digitalWrite and capabilityResponse
#define TOTAL_PIN_MODES 13
// DEPRECATED as of Firmata v2.5
#define ANALOG 0x02 // same as PIN_MODE_ANALOG
// #undef ANALOG
// #define ANALOG 0x02 // same as PIN_MODE_ANALOG
#undef PWM
#define PWM 0x03 // same as PIN_MODE_PWM
#define SERVO 0x04 // same as PIN_MODE_SERVO
#define SHIFT 0x05 // same as PIN_MODE_SHIFT
Expand Down
6 changes: 3 additions & 3 deletions src/DigitalInputFirmata.cpp
Expand Up @@ -91,9 +91,9 @@ void DigitalInputFirmata::reportDigital(byte port, int value)
boolean DigitalInputFirmata::handlePinMode(byte pin, int mode)
{
if (IS_PIN_DIGITAL(pin)) {
if (mode == INPUT || mode == PIN_MODE_PULLUP) {
if (mode == PIN_MODE_INPUT || mode == PIN_MODE_PULLUP) {
portConfigInputs[pin / 8] |= (1 << (pin & 7));
if (mode == INPUT) {
if (mode == PIN_MODE_INPUT) {
pinMode(PIN_TO_DIGITAL(pin), INPUT);
} else {
pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP);
Expand All @@ -110,7 +110,7 @@ boolean DigitalInputFirmata::handlePinMode(byte pin, int mode)
void DigitalInputFirmata::handleCapability(byte pin)
{
if (IS_PIN_DIGITAL(pin)) {
Firmata.write((byte)INPUT);
Firmata.write((byte)PIN_MODE_INPUT);
Firmata.write(1);
Firmata.write((byte)PIN_MODE_PULLUP);
Firmata.write(1);
Expand Down
12 changes: 6 additions & 6 deletions src/DigitalOutputFirmata.cpp
Expand Up @@ -35,7 +35,7 @@ void digitalOutputWriteCallback(byte port, int value)
void handleSetPinValueCallback(byte pin, int value)
{
if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) {
if (Firmata.getPinMode(pin) == OUTPUT) {
if (Firmata.getPinMode(pin) == PIN_MODE_OUTPUT) {
digitalWrite(pin, value);
Firmata.setPinState(pin, value);
}
Expand Down Expand Up @@ -71,11 +71,11 @@ void DigitalOutputFirmata::digitalWritePort(byte port, int value)
// do not disturb non-digital pins (eg, Rx & Tx)
if (IS_PIN_DIGITAL(pin)) {
// do not touch pins in PWM, ANALOG, SERVO or other modes
if (Firmata.getPinMode(pin) == OUTPUT || Firmata.getPinMode(pin) == INPUT) {
if (Firmata.getPinMode(pin) == PIN_MODE_OUTPUT || Firmata.getPinMode(pin) == PIN_MODE_INPUT) {
pinValue = ((byte)value & mask) ? 1 : 0;
if (Firmata.getPinMode(pin) == OUTPUT) {
if (Firmata.getPinMode(pin) == PIN_MODE_OUTPUT) {
pinWriteMask |= mask;
} else if (Firmata.getPinMode(pin) == INPUT && pinValue == 1 && Firmata.getPinState(pin) != 1) {
} else if (Firmata.getPinMode(pin) == PIN_MODE_INPUT && pinValue == 1 && Firmata.getPinState(pin) != 1) {
pinMode(pin, INPUT_PULLUP);
}
Firmata.setPinState(pin, pinValue);
Expand All @@ -89,7 +89,7 @@ void DigitalOutputFirmata::digitalWritePort(byte port, int value)

boolean DigitalOutputFirmata::handlePinMode(byte pin, int mode)
{
if (IS_PIN_DIGITAL(pin) && mode == OUTPUT && Firmata.getPinMode(pin) != PIN_MODE_IGNORE) {
if (IS_PIN_DIGITAL(pin) && mode == PIN_MODE_OUTPUT && Firmata.getPinMode(pin) != PIN_MODE_IGNORE) {
digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM
pinMode(PIN_TO_DIGITAL(pin), OUTPUT);
return true;
Expand All @@ -100,7 +100,7 @@ boolean DigitalOutputFirmata::handlePinMode(byte pin, int mode)
void DigitalOutputFirmata::handleCapability(byte pin)
{
if (IS_PIN_DIGITAL(pin)) {
Firmata.write((byte)OUTPUT);
Firmata.write((byte)PIN_MODE_OUTPUT);
Firmata.write(1);
}
}
33 changes: 32 additions & 1 deletion src/utility/Boards.h
Expand Up @@ -596,6 +596,33 @@ writePort(port, value, bitmask): Write an 8 bit port.
#define PIN_TO_SERVO(p) (p)
#define DEFAULT_PWM_RESOLUTION 10

// ESP32
// Tested on Sparkfun ESP32 Thing, may work with other ESP32 boards, but not verified.
// Pins D34 - D39 Digital Input only
// TODO: validate if Serial2 maps to rx = 16, tx = 17
// ESP32 boards currently only work with Firmata over Wi-Fi.
// Supply > 500mA to the board (laptop USB current is typically not enough, use a powered USB hub).
#elif defined(ESP32)
#define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS
#define TOTAL_PINS NUM_DIGITAL_PINS
#define VERSION_BLINK_PIN LED_BUILTIN
// Serial0 not supported
// #define PIN_SERIAL_RX 3
// #define PIN_SERIAL_TX 1
#define IS_PIN_DIGITAL(p) ((p) < 6 || ((p) >= 12 && (p) < 24) || ((p) >= 25 && (p) < 28) || ((p) >= 32 && (p) <= 39))
#define IS_PIN_ANALOG(p) ((p) == 0 || (p) == 2 || (p) == 4 || ((p) >= 12 && (p) < 16) || ((p >= 25 && (p) < 28) || ((p) >= 32 && (p) < 37) || (p) == 39))
#define IS_PIN_PWM(p) (0) // analogWrite is not yet supported
#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS)
#define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL)
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
#define IS_PIN_INTERRUPT(p) (digitalPinToInterrupt(p) > NOT_AN_INTERRUPT)
// #define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL_RX || (p) == PIN_SERIAL_TX)
#define PIN_TO_DIGITAL(p) (p)
#define PIN_TO_ANALOG(p) digitalPinToAnalogChannel(p) // defined in esp32-hal-gpio.h
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
#define PIN_TO_SERVO(p) (p)
#define DEFAULT_ADC_RESOLUTION 12


// anything else
#else
Expand All @@ -604,7 +631,7 @@ writePort(port, value, bitmask): Write an 8 bit port.

// as long this is not defined for all boards:
#ifndef IS_PIN_SPI
#define IS_PIN_SPI(p) (0)
#define IS_PIN_SPI(p) 0
#endif

#ifndef IS_PIN_SERIAL
Expand All @@ -615,6 +642,10 @@ writePort(port, value, bitmask): Write an 8 bit port.
#define DEFAULT_PWM_RESOLUTION 8
#endif

#ifndef DEFAULT_ADC_RESOLUTION
#define DEFAULT_ADC_RESOLUTION 10
#endif

/*==============================================================================
* readPort() - Read an 8 bit port
*============================================================================*/
Expand Down
8 changes: 4 additions & 4 deletions src/utility/WiFiStream.h
Expand Up @@ -69,7 +69,7 @@ class WiFiStream : public Stream
* network configuration
******************************************************************************/

#ifndef ESP8266
#if !defined(ESP8266) && !defined(ESP32)
/**
* configure a static local IP address without defining the local network
* DHCP will be used as long as local IP address is not defined
Expand All @@ -90,7 +90,7 @@ class WiFiStream : public Stream
_local_ip = local_ip;
_subnet = subnet;
_gateway = gateway;
#ifndef ESP8266
#if !defined(ESP8266)
WiFi.config( local_ip, IPAddress(0, 0, 0, 0), gateway, subnet );
#else
WiFi.config( local_ip, gateway, subnet );
Expand All @@ -115,7 +115,7 @@ class WiFiStream : public Stream
*/
virtual bool maintain() = 0;

#ifdef ESP8266
#if defined(ESP8266)
/**
* get status of TCP connection
* @return status of TCP connection
Expand Down Expand Up @@ -160,7 +160,7 @@ class WiFiStream : public Stream
return WiFi.status();
}

#ifndef ESP8266
#if !defined(ESP8266) && !defined(ESP32)
/**
* initialize WiFi with WEP security and initiate client connection
* if WiFi connection is already established
Expand Down