Skip to content

Commit

Permalink
Add iram option to MHZ19(B) driver (#1248)
Browse files Browse the repository at this point in the history
Add iram option to MHZ19(B) driver (#1248)
  • Loading branch information
arendst committed Dec 6, 2017
1 parent 3890170 commit 4cf64af
Show file tree
Hide file tree
Showing 9 changed files with 422 additions and 3 deletions.
11 changes: 11 additions & 0 deletions lib/EspSoftwareSerial-3.3.1/README.md
@@ -0,0 +1,11 @@
# EspSoftwareSerial

Implementation of the Arduino software serial library for the ESP8266

Same functionality as the corresponding AVR library but several instances can be active at the same time.
Speed up to 115200 baud is supported. The constructor also has an optional input buffer size.

Please note that due to the fact that the ESP always have other activities ongoing, there will be some inexactness in interrupt
timings. This may lead to bit errors when having heavy data traffic in high baud rates.


228 changes: 228 additions & 0 deletions lib/EspSoftwareSerial-3.3.1/SoftwareSerial.cpp
@@ -0,0 +1,228 @@
/*
SoftwareSerial.cpp - Implementation of the Arduino software serial for ESP8266.
Copyright (c) 2015-2016 Peter Lerup. All rights reserved.
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
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
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 <Arduino.h>

// The Arduino standard GPIO routines are not enough,
// must use some from the Espressif SDK as well
extern "C" {
#include "gpio.h"
}

#include <SoftwareSerial.h>

#define MAX_PIN 15

// As the Arduino attachInterrupt has no parameter, lists of objects
// and callbacks corresponding to each possible GPIO pins have to be defined
SoftwareSerial *ObjList[MAX_PIN+1];

void ICACHE_RAM_ATTR sws_isr_0() { ObjList[0]->rxRead(); };
void ICACHE_RAM_ATTR sws_isr_1() { ObjList[1]->rxRead(); };
void ICACHE_RAM_ATTR sws_isr_2() { ObjList[2]->rxRead(); };
void ICACHE_RAM_ATTR sws_isr_3() { ObjList[3]->rxRead(); };
void ICACHE_RAM_ATTR sws_isr_4() { ObjList[4]->rxRead(); };
void ICACHE_RAM_ATTR sws_isr_5() { ObjList[5]->rxRead(); };
// Pin 6 to 11 can not be used
void ICACHE_RAM_ATTR sws_isr_12() { ObjList[12]->rxRead(); };
void ICACHE_RAM_ATTR sws_isr_13() { ObjList[13]->rxRead(); };
void ICACHE_RAM_ATTR sws_isr_14() { ObjList[14]->rxRead(); };
void ICACHE_RAM_ATTR sws_isr_15() { ObjList[15]->rxRead(); };

static void (*ISRList[MAX_PIN+1])() = {
sws_isr_0,
sws_isr_1,
sws_isr_2,
sws_isr_3,
sws_isr_4,
sws_isr_5,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
sws_isr_12,
sws_isr_13,
sws_isr_14,
sws_isr_15
};

SoftwareSerial::SoftwareSerial(int receivePin, int transmitPin, bool inverse_logic, unsigned int buffSize) {
m_rxValid = m_txValid = m_txEnableValid = false;
m_buffer = NULL;
m_invert = inverse_logic;
m_overflow = false;
m_rxEnabled = false;
if (isValidGPIOpin(receivePin)) {
m_rxPin = receivePin;
m_buffSize = buffSize;
m_buffer = (uint8_t*)malloc(m_buffSize);
if (m_buffer != NULL) {
m_rxValid = true;
m_inPos = m_outPos = 0;
pinMode(m_rxPin, INPUT);
ObjList[m_rxPin] = this;
enableRx(true);
}
}
if (isValidGPIOpin(transmitPin) || transmitPin == 16) {
m_txValid = true;
m_txPin = transmitPin;
pinMode(m_txPin, OUTPUT);
digitalWrite(m_txPin, !m_invert);
}
// Default speed
begin(9600);
}

SoftwareSerial::~SoftwareSerial() {
enableRx(false);
if (m_rxValid)
ObjList[m_rxPin] = NULL;
if (m_buffer)
free(m_buffer);
}

bool SoftwareSerial::isValidGPIOpin(int pin) {
return (pin >= 0 && pin <= 5) || (pin >= 12 && pin <= MAX_PIN);
}

void SoftwareSerial::begin(long speed) {
// Use getCycleCount() loop to get as exact timing as possible
m_bitTime = ESP.getCpuFreqMHz()*1000000/speed;
m_highSpeed = speed > 9600;

if (!m_rxEnabled)
enableRx(true);
}

long SoftwareSerial::baudRate() {
return ESP.getCpuFreqMHz()*1000000/m_bitTime;
}

void SoftwareSerial::setTransmitEnablePin(int transmitEnablePin) {
if (isValidGPIOpin(transmitEnablePin)) {
m_txEnableValid = true;
m_txEnablePin = transmitEnablePin;
pinMode(m_txEnablePin, OUTPUT);
digitalWrite(m_txEnablePin, LOW);
} else {
m_txEnableValid = false;
}
}

void SoftwareSerial::enableRx(bool on) {
if (m_rxValid) {
if (on)
attachInterrupt(m_rxPin, ISRList[m_rxPin], m_invert ? RISING : FALLING);
else
detachInterrupt(m_rxPin);
m_rxEnabled = on;
}
}

int SoftwareSerial::read() {
if (!m_rxValid || (m_inPos == m_outPos)) return -1;
uint8_t ch = m_buffer[m_outPos];
m_outPos = (m_outPos+1) % m_buffSize;
return ch;
}

int SoftwareSerial::available() {
if (!m_rxValid) return 0;
int avail = m_inPos - m_outPos;
if (avail < 0) avail += m_buffSize;
return avail;
}

#define WAIT { while (ESP.getCycleCount()-start < wait) if (!m_highSpeed) optimistic_yield(1); wait += m_bitTime; }

size_t SoftwareSerial::write(uint8_t b) {
if (!m_txValid) return 0;

if (m_invert) b = ~b;
if (m_highSpeed)
// Disable interrupts in order to get a clean transmit
cli();
if (m_txEnableValid) digitalWrite(m_txEnablePin, HIGH);
unsigned long wait = m_bitTime;
digitalWrite(m_txPin, HIGH);
unsigned long start = ESP.getCycleCount();
// Start bit;
digitalWrite(m_txPin, LOW);
WAIT;
for (int i = 0; i < 8; i++) {
digitalWrite(m_txPin, (b & 1) ? HIGH : LOW);
WAIT;
b >>= 1;
}
// Stop bit
digitalWrite(m_txPin, HIGH);
WAIT;
if (m_txEnableValid) digitalWrite(m_txEnablePin, LOW);
if (m_highSpeed)
sei();
return 1;
}

void SoftwareSerial::flush() {
m_inPos = m_outPos = 0;
}

bool SoftwareSerial::overflow() {
bool res = m_overflow;
m_overflow = false;
return res;
}

int SoftwareSerial::peek() {
if (!m_rxValid || (m_inPos == m_outPos)) return -1;
return m_buffer[m_outPos];
}

void ICACHE_RAM_ATTR SoftwareSerial::rxRead() {
// Advance the starting point for the samples but compensate for the
// initial delay which occurs before the interrupt is delivered
unsigned long wait = m_bitTime + m_bitTime/3 - 500;
unsigned long start = ESP.getCycleCount();
uint8_t rec = 0;
for (int i = 0; i < 8; i++) {
WAIT;
rec >>= 1;
if (digitalRead(m_rxPin))
rec |= 0x80;
}
if (m_invert) rec = ~rec;
// Stop bit
WAIT;
// Store the received value in the buffer unless we have an overflow
int next = (m_inPos+1) % m_buffSize;
if (next != m_outPos) {
m_buffer[m_inPos] = rec;
m_inPos = next;
} else {
m_overflow = true;
}
// Must clear this bit in the interrupt register,
// it gets set even when interrupts are disabled
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1 << m_rxPin);
}
88 changes: 88 additions & 0 deletions lib/EspSoftwareSerial-3.3.1/SoftwareSerial.h
@@ -0,0 +1,88 @@
/*
SoftwareSerial.h
SoftwareSerial.cpp - Implementation of the Arduino software serial for ESP8266.
Copyright (c) 2015-2016 Peter Lerup. All rights reserved.
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
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
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
*/

#ifndef SoftwareSerial_h
#define SoftwareSerial_h

#include <inttypes.h>
#include <Stream.h>


// This class is compatible with the corresponding AVR one,
// the constructor however has an optional rx buffer size.
// Speed up to 115200 can be used.


class SoftwareSerial : public Stream
{
public:
SoftwareSerial(int receivePin, int transmitPin, bool inverse_logic = false, unsigned int buffSize = 64);
~SoftwareSerial();

void begin(long speed);
long baudRate();
void setTransmitEnablePin(int transmitEnablePin);

bool overflow();
int peek();

virtual size_t write(uint8_t byte);
virtual int read();
virtual int available();
virtual void flush();
operator bool() {return m_rxValid || m_txValid;}

// Disable or enable interrupts on the rx pin
void enableRx(bool on);

void rxRead();

// AVR compatibility methods
bool listen() { enableRx(true); return true; }
void end() { stopListening(); }
bool isListening() { return m_rxEnabled; }
bool stopListening() { enableRx(false); return true; }

using Print::write;

private:
bool isValidGPIOpin(int pin);

// Member variables
int m_rxPin, m_txPin, m_txEnablePin;
bool m_rxValid, m_rxEnabled;
bool m_txValid, m_txEnableValid;
bool m_invert;
bool m_overflow;
unsigned long m_bitTime;
bool m_highSpeed;
unsigned int m_inPos, m_outPos;
int m_buffSize;
uint8_t *m_buffer;

};

// If only one tx or rx wanted then use this as parameter for the unused pin
#define SW_SERIAL_UNUSED_PIN -1


#endif
27 changes: 27 additions & 0 deletions lib/EspSoftwareSerial-3.3.1/examples/swsertest/swsertest.ino
@@ -0,0 +1,27 @@

#include <SoftwareSerial.h>

SoftwareSerial swSer(14, 12, false, 256);

void setup() {
Serial.begin(115200);
swSer.begin(115200);

Serial.println("\nSoftware serial test started");

for (char ch = ' '; ch <= 'z'; ch++) {
swSer.write(ch);
}
swSer.println("");

}

void loop() {
while (swSer.available() > 0) {
Serial.write(swSer.read());
}
while (Serial.available() > 0) {
swSer.write(Serial.read());
}

}
31 changes: 31 additions & 0 deletions lib/EspSoftwareSerial-3.3.1/keywords.txt
@@ -0,0 +1,31 @@
#######################################
# Syntax Coloring Map for SoftwareSerial
# (esp8266)
#######################################

#######################################
# Datatypes (KEYWORD1)
#######################################

SoftwareSerial KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
#######################################

begin KEYWORD2
read KEYWORD2
write KEYWORD2
available KEYWORD2
flush KEYWORD2
overflow KEYWORD2
peek KEYWORD2
listen KEYWORD2
end KEYWORD2
isListening KEYWORD2
stopListening KEYWORD2

#######################################
# Constants (LITERAL1)
#######################################

0 comments on commit 4cf64af

Please sign in to comment.