Skip to content

Commit

Permalink
Refactored interrupts disabling and proper FreeRTOS-compliant code fo…
Browse files Browse the repository at this point in the history
…r ESP32 class of MCUs.
  • Loading branch information
dok-net committed Nov 27, 2021
1 parent b1aae5c commit eb4b290
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 10 deletions.
37 changes: 28 additions & 9 deletions src/SoftwareSerial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,29 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "SoftwareSerial.h"
#include <Arduino.h>

#ifdef ESP32
#define xt_rsil(a) (a)
#define xt_wsr_ps(a)
#ifndef ESP32
uint32_t SoftwareSerial::m_savedPS = 0;
#else
portMUX_TYPE SoftwareSerial::m_interruptsMux = portMUX_INITIALIZER_UNLOCKED;
#endif

inline void IRAM_ATTR SoftwareSerial::disableInterrupts()
{
#ifndef ESP32
m_savedPS = xt_rsil(15);
#else
taskENTER_CRITICAL(&m_interruptsMux);
#endif
}

inline void IRAM_ATTR SoftwareSerial::restoreInterrupts()
{
#ifndef ESP32
xt_wsr_ps(m_savedPS);
#else
taskEXIT_CRITICAL(&m_interruptsMux);
#endif
}

constexpr uint8_t BYTE_ALL_BITS_SET = ~static_cast<uint8_t>(0);

Expand Down Expand Up @@ -287,10 +306,10 @@ void IRAM_ATTR SoftwareSerial::preciseDelay(bool sync) {
if (!sync)
{
// Reenable interrupts while delaying to avoid other tasks piling up
if (!m_intTxEnabled) { xt_wsr_ps(m_savedPS); }
if (!m_intTxEnabled) { restoreInterrupts(); }
const auto expired = ESP.getCycleCount() - m_periodStart;
const int32_t remaining = m_periodDuration - expired;
const int32_t ms = remaining / 1000L / static_cast<int32_t>(ESP.getCpuFreqMHz());
const int32_t ms = remaining > 0 ? remaining / 1000L / static_cast<int32_t>(ESP.getCpuFreqMHz()) : 0;
if (ms > 0)
{
delay(ms);
Expand All @@ -302,7 +321,7 @@ void IRAM_ATTR SoftwareSerial::preciseDelay(bool sync) {
}
while ((ESP.getCycleCount() - m_periodStart) < m_periodDuration) {}
// Disable interrupts again if applicable
if (!sync && !m_intTxEnabled) { m_savedPS = xt_rsil(15); }
if (!sync && !m_intTxEnabled) { disableInterrupts(); }
m_periodDuration = 0;
m_periodStart = ESP.getCycleCount();
}
Expand Down Expand Up @@ -349,7 +368,7 @@ size_t IRAM_ATTR SoftwareSerial::write(const uint8_t* buffer, size_t size, Softw
uint32_t offCycle = 0;
if (!m_intTxEnabled) {
// Disable interrupts in order to get a clean transmit timing
m_savedPS = xt_rsil(15);
disableInterrupts();
}
const uint32_t dataMask = ((1UL << m_dataBits) - 1);
bool withStopBit = true;
Expand Down Expand Up @@ -415,8 +434,8 @@ size_t IRAM_ATTR SoftwareSerial::write(const uint8_t* buffer, size_t size, Softw
}
writePeriod(dutyCycle, offCycle, true);
if (!m_intTxEnabled) {
// restore the interrupt state
xt_wsr_ps(m_savedPS);
// restore the interrupt state if applicable
restoreInterrupts();
}
if (m_txEnableValid) {
digitalWrite(m_txEnablePin, LOW);
Expand Down
8 changes: 7 additions & 1 deletion src/SoftwareSerial.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@ class SoftwareSerial : public Stream {
/* check m_rxValid that calling is safe */
void rxBits();
void rxBits(const uint32_t isrCycle);
static void disableInterrupts();
static void restoreInterrupts();

static void rxBitISR(SoftwareSerial* self);
static void rxBitSyncISR(SoftwareSerial* self);
Expand Down Expand Up @@ -261,7 +263,11 @@ class SoftwareSerial : public Stream {
std::unique_ptr<circular_queue<uint8_t> > m_parityBuffer;
uint32_t m_periodStart;
uint32_t m_periodDuration;
uint32_t m_savedPS = 0;
#ifndef ESP32
static uint32_t m_savedPS;
#else
static portMUX_TYPE m_interruptsMux;
#endif
// the ISR stores the relative bit times in the buffer. The inversion corrected level is used as sign bit (2's complement):
// 1 = positive including 0, 0 = negative.
std::unique_ptr<circular_queue<uint32_t, SoftwareSerial*> > m_isrBuffer;
Expand Down

0 comments on commit eb4b290

Please sign in to comment.