Skip to content

Commit cfe7ae1

Browse files
Put HardwareSerial and cbuf methods called from interrupt context in RAM.
This is required per the non-OS SDK doc, which states: "Using non-OS SDK, please do not call any function defined with ICACHE_FLASH_ATTR in the interrupt handler." This avoids an "Illegal instruction" exception with epc1 pointing at a valid instruction (in flash) for one of the moved methods.
1 parent 83398f6 commit cfe7ae1

File tree

3 files changed

+77
-34
lines changed

3 files changed

+77
-34
lines changed

cores/esp8266/HardwareSerial.cpp

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,13 @@ int uart_get_debug();
116116
// ####################################################################################################
117117
// ####################################################################################################
118118

119+
// These function internals can be used from interrupt handlers to ensure they
120+
// are in instruction RAM, or anywhere that the uart_nr has been validated.
121+
#define UART_GET_TX_FIFO_ROOM(uart_nr) (UART_TX_FIFO_SIZE - ((USS(uart_nr) >> USTXC) & 0xff))
122+
#define UART_TRANSMIT_CHAR(uart_nr, c) do { USF(uart_nr) = (c); } while(0)
123+
#define UART_ARM_TX_INTERRUPT(uart_nr) do { USIE(uart_nr) |= (1 << UIFE); } while(0)
124+
#define UART_DISARM_TX_INTERRUPT(uart_nr) do { USIE(uart_nr) &= ~(1 << UIFE); } while(0)
125+
119126
void ICACHE_RAM_ATTR uart_interrupt_handler(uart_t* uart) {
120127

121128
// -------------- UART 0 --------------
@@ -160,7 +167,7 @@ size_t uart_get_tx_fifo_room(uart_t* uart) {
160167
if(uart == 0)
161168
return 0;
162169
if(uart->txEnabled) {
163-
return UART_TX_FIFO_SIZE - ((USS(uart->uart_nr) >> USTXC) & 0xff);
170+
return UART_GET_TX_FIFO_ROOM(uart->uart_nr);
164171
}
165172
return 0;
166173
}
@@ -177,7 +184,7 @@ void uart_transmit_char(uart_t* uart, char c) {
177184
if(uart == 0)
178185
return;
179186
if(uart->txEnabled) {
180-
USF(uart->uart_nr) = c;
187+
UART_TRANSMIT_CHAR(uart->uart_nr, c);
181188
}
182189
}
183190

@@ -241,15 +248,15 @@ void uart_arm_tx_interrupt(uart_t* uart) {
241248
if(uart == 0)
242249
return;
243250
if(uart->txEnabled) {
244-
USIE(uart->uart_nr) |= (1 << UIFE);
251+
UART_ARM_TX_INTERRUPT(uart->uart_nr);
245252
}
246253
}
247254

248255
void uart_disarm_tx_interrupt(uart_t* uart) {
249256
if(uart == 0)
250257
return;
251258
if(uart->txEnabled) {
252-
USIE(uart->uart_nr) &= ~(1 << UIFE);
259+
UART_DISARM_TX_INTERRUPT(uart->uart_nr);
253260
}
254261
}
255262

@@ -536,13 +543,13 @@ void HardwareSerial::setDebugOutput(bool en) {
536543
}
537544
}
538545

539-
bool HardwareSerial::isTxEnabled(void) {
546+
bool ICACHE_RAM_ATTR HardwareSerial::isTxEnabled(void) {
540547
if(_uart == 0)
541548
return false;
542549
return _uart->txEnabled;
543550
}
544551

545-
bool HardwareSerial::isRxEnabled(void) {
552+
bool ICACHE_RAM_ATTR HardwareSerial::isRxEnabled(void) {
546553
if(_uart == 0)
547554
return false;
548555
return _uart->rxEnabled;
@@ -604,11 +611,12 @@ void HardwareSerial::flush() {
604611
if(!_written)
605612
return;
606613

614+
const int uart_nr = _uart->uart_nr;
607615
while(true) {
608616
{
609617
InterruptLock il;
610618
if(_tx_buffer->getSize() == 0 &&
611-
uart_get_tx_fifo_room(_uart) >= UART_TX_FIFO_SIZE) {
619+
UART_GET_TX_FIFO_ROOM(uart_nr) >= UART_TX_FIFO_SIZE) {
612620
break;
613621
}
614622
}
@@ -623,15 +631,16 @@ size_t HardwareSerial::write(uint8_t c) {
623631
_written = true;
624632

625633
bool tx_now = false;
634+
const int uart_nr = _uart->uart_nr;
626635
while(true) {
627636
{
628637
InterruptLock il;
629638
if(_tx_buffer->empty()) {
630-
if(uart_get_tx_fifo_room(_uart) > 0) {
639+
if(UART_GET_TX_FIFO_ROOM(uart_nr) > 0) {
631640
tx_now = true;
632641
} else {
633642
_tx_buffer->write(c);
634-
uart_arm_tx_interrupt(_uart);
643+
UART_ARM_TX_INTERRUPT(uart_nr);
635644
}
636645
break;
637646
} else if(_tx_buffer->write(c)) {
@@ -641,7 +650,7 @@ size_t HardwareSerial::write(uint8_t c) {
641650
yield();
642651
}
643652
if (tx_now) {
644-
uart_transmit_char(_uart, c);
653+
UART_TRANSMIT_CHAR(uart_nr, c);
645654
}
646655
return 1;
647656
}
@@ -650,26 +659,27 @@ HardwareSerial::operator bool() const {
650659
return _uart != 0;
651660
}
652661

653-
void HardwareSerial::_rx_complete_irq(char c) {
662+
void ICACHE_RAM_ATTR HardwareSerial::_rx_complete_irq(char c) {
654663
if(_rx_buffer) {
655664
_rx_buffer->write(c);
656665
}
657666
}
658667

659-
void HardwareSerial::_tx_empty_irq(void) {
668+
void ICACHE_RAM_ATTR HardwareSerial::_tx_empty_irq(void) {
660669
if(_uart == 0)
661670
return;
662671
if(_tx_buffer == 0)
663672
return;
673+
const int uart_nr = _uart->uart_nr;
664674
size_t queued = _tx_buffer->getSize();
665675
if(!queued) {
666-
uart_disarm_tx_interrupt(_uart);
676+
UART_DISARM_TX_INTERRUPT(uart_nr);
667677
return;
668678
}
669679

670-
size_t room = uart_get_tx_fifo_room(_uart);
680+
size_t room = UART_GET_TX_FIFO_ROOM(uart_nr);
671681
int n = static_cast<int>((queued < room) ? queued : room);
672682
while(n--) {
673-
uart_transmit_char(_uart, _tx_buffer->read());
683+
UART_TRANSMIT_CHAR(uart_nr, _tx_buffer->read());
674684
}
675685
}

cores/esp8266/cbuf.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
cbuf.cpp - Circular buffer implementation
3+
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
4+
This file is part of the esp8266 core for Arduino environment.
5+
6+
This library is free software; you can redistribute it and/or
7+
modify it under the terms of the GNU Lesser General Public
8+
License as published by the Free Software Foundation; either
9+
version 2.1 of the License, or (at your option) any later version.
10+
11+
This library is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
Lesser General Public License for more details.
15+
16+
You should have received a copy of the GNU Lesser General Public
17+
License along with this library; if not, write to the Free Software
18+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19+
*/
20+
21+
#include "cbuf.h"
22+
#include "c_types.h"
23+
24+
size_t ICACHE_RAM_ATTR cbuf::getSize() const {
25+
if(_end >= _begin) {
26+
return _end - _begin;
27+
}
28+
return _size - (_begin - _end);
29+
}
30+
31+
int ICACHE_RAM_ATTR cbuf::read() {
32+
if(empty()) return -1;
33+
34+
char result = *_begin;
35+
_begin = wrap_if_bufend(_begin + 1);
36+
return result;
37+
return static_cast<int>(result);
38+
}
39+
40+
size_t ICACHE_RAM_ATTR cbuf::write(char c) {
41+
if(full()) return 0;
42+
43+
*_end = c;
44+
_end = wrap_if_bufend(_end + 1);
45+
return 1;
46+
}

cores/esp8266/cbuf.h

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@
2121
#ifndef __cbuf_h
2222
#define __cbuf_h
2323

24+
#include <stddef.h>
2425
#include <stdint.h>
26+
#include <string.h>
27+
2528
class cbuf {
2629
public:
2730
cbuf(size_t size) :
@@ -32,11 +35,7 @@ class cbuf {
3235
delete[] _buf;
3336
}
3437

35-
size_t getSize() const {
36-
if(_end >= _begin) return _end - _begin;
37-
38-
return _size - (_begin - _end);
39-
}
38+
size_t getSize() const;
4039

4140
size_t room() const {
4241
if(_end >= _begin) {
@@ -59,13 +58,7 @@ class cbuf {
5958
return static_cast<int>(*_begin);
6059
}
6160

62-
int read() {
63-
if(empty()) return -1;
64-
65-
char result = *_begin;
66-
_begin = wrap_if_bufend(_begin + 1);
67-
return static_cast<int>(result);
68-
}
61+
int read();
6962

7063
size_t read(char* dst, size_t size) {
7164
size_t bytes_available = getSize();
@@ -83,13 +76,7 @@ class cbuf {
8376
return size_read;
8477
}
8578

86-
size_t write(char c) {
87-
if(full()) return 0;
88-
89-
*_end = c;
90-
_end = wrap_if_bufend(_end + 1);
91-
return 1;
92-
}
79+
size_t write(char c);
9380

9481
size_t write(const char* src, size_t size) {
9582
size_t bytes_available = room();

0 commit comments

Comments
 (0)