Skip to content

Serial RX Interrupt #2239

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

Merged
merged 21 commits into from
Jul 8, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 17 additions & 33 deletions cores/esp8266/HardwareSerial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,31 +32,34 @@


HardwareSerial::HardwareSerial(int uart_nr)
: _uart_nr(uart_nr)
: _uart_nr(uart_nr), _rx_size(256)
{}

void HardwareSerial::begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin)
{
end();
_uart = uart_init(_uart_nr, baud, (int) config, (int) mode, tx_pin, _rx_size);
}

void HardwareSerial::end()
{
if(uart_get_debug() == _uart_nr) {
uart_set_debug(UART_NO);
}

if (_uart) {
free(_uart);
uart_uninit(_uart);
_uart = NULL;
}

_uart = uart_init(_uart_nr, baud, (int) config, (int) mode, tx_pin);
_peek_char = -1;
}

void HardwareSerial::end()
{
if(uart_get_debug() == _uart_nr) {
uart_set_debug(UART_NO);
size_t HardwareSerial::setRxBufferSize(size_t size){
if(_uart) {
_rx_size = uart_resize_rx_buffer(_uart, size);
} else {
_rx_size = size;
}

uart_uninit(_uart);
_uart = NULL;
return _rx_size;
}

void HardwareSerial::swap(uint8_t tx_pin)
Expand Down Expand Up @@ -114,14 +117,7 @@ bool HardwareSerial::isRxEnabled(void)

int HardwareSerial::available(void)
{
if(!_uart || !uart_rx_enabled(_uart)) {
return 0;
}

int result = static_cast<int>(uart_rx_available(_uart));
if (_peek_char != -1) {
result += 1;
}
if (!result) {
optimistic_yield(10000);
}
Expand All @@ -130,25 +126,13 @@ int HardwareSerial::available(void)

int HardwareSerial::peek(void)
{
if (_peek_char != -1) {
return _peek_char;
}
// this may return -1, but that's okay
_peek_char = uart_read_char(_uart);
return _peek_char;
return uart_peek_char(_uart);
}

int HardwareSerial::read(void)
{
if(!_uart || !uart_rx_enabled(_uart)) {
return -1;
}

if (_peek_char != -1) {
auto tmp = _peek_char;
_peek_char = -1;
return tmp;
}
// this may return -1, but that's okay
return uart_read_char(_uart);
}

Expand Down
4 changes: 3 additions & 1 deletion cores/esp8266/HardwareSerial.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ class HardwareSerial: public Stream

void end();

size_t setRxBufferSize(size_t size);

void swap()
{
swap(1);
Expand Down Expand Up @@ -138,7 +140,7 @@ class HardwareSerial: public Stream
protected:
int _uart_nr;
uart_t* _uart = nullptr;
int _peek_char = -1;
size_t _rx_size;
};

extern HardwareSerial Serial;
Expand Down
185 changes: 164 additions & 21 deletions cores/esp8266/uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,51 +47,163 @@

static int s_uart_debug_nr = UART0;

struct uart_rx_buffer_ {
size_t size;
size_t rpos;
size_t wpos;
uint8_t * buffer;
};

struct uart_ {
int uart_nr;
int baud_rate;
bool rx_enabled;
bool tx_enabled;
uint8_t rx_pin;
uint8_t tx_pin;
struct uart_rx_buffer_ * rx_buffer;
};

void uart_write_char(uart_t* uart, char c)
size_t uart_resize_rx_buffer(uart_t* uart, size_t new_size)
{
if(uart == NULL || !uart->tx_enabled) {
return;
if(uart == NULL || !uart->rx_enabled) {
return 0;
}
while((USS(uart->uart_nr) >> USTXC) >= 0x7f);
USF(uart->uart_nr) = c;
}

void uart_write(uart_t* uart, const char* buf, size_t size)
{
if(uart == NULL || !uart->tx_enabled) {
return;
if(uart->rx_buffer->size == new_size) {
return uart->rx_buffer->size;
}
while(size--) {
uart_write_char(uart, *buf++);
uint8_t * new_buf = (uint8_t*)malloc(new_size);
if(!new_buf) {
return uart->rx_buffer->size;
}
size_t new_wpos = 0;
ETS_UART_INTR_DISABLE();
while(uart_rx_available(uart) && new_wpos < new_size) {
new_buf[new_wpos++] = uart_read_char(uart);
}
uint8_t * old_buf = uart->rx_buffer->buffer;
uart->rx_buffer->rpos = 0;
uart->rx_buffer->wpos = new_wpos;
uart->rx_buffer->size = new_size;
uart->rx_buffer->buffer = new_buf;
free(old_buf);
ETS_UART_INTR_ENABLE();
return uart->rx_buffer->size;
}

int uart_read_char(uart_t* uart)
int uart_peek_char(uart_t* uart)
{
if(uart == NULL || !uart->rx_enabled) {
return -1;
}
if (!uart_rx_available(uart)) {
return -1;
}
return USF(uart->uart_nr) & 0xff;
return uart->rx_buffer->buffer[uart->rx_buffer->rpos];
}

int uart_read_char(uart_t* uart)
{
int data = uart_peek_char(uart);
if(data != -1) {
uart->rx_buffer->rpos = (uart->rx_buffer->rpos + 1) % uart->rx_buffer->size;
}
return data;
}

size_t uart_rx_available(uart_t* uart)
{
if(uart == NULL || !uart->rx_enabled) {
return -1;
return 0;
}
if(uart->rx_buffer->wpos < uart->rx_buffer->rpos) {
return (uart->rx_buffer->wpos + uart->rx_buffer->size) - uart->rx_buffer->rpos;
}
return uart->rx_buffer->wpos - uart->rx_buffer->rpos;
}


void ICACHE_RAM_ATTR uart_isr(void * arg)
{
uart_t* uart = (uart_t*)arg;
if(uart == NULL || !uart->rx_enabled) {
USIC(uart->uart_nr) = 0xffff;
ETS_UART_INTR_DISABLE();
return;
}

uint32_t int_status = USIS(uart->uart_nr);

if(int_status & (1 << UIFR)) {
USIC(uart->uart_nr) = (1 << UIFR);//clear any frame error
}

if(int_status & (1 << UIFF) || int_status & (1 << UITO)){
ETS_UART_INTR_DISABLE();
while(((USS(uart->uart_nr) >> USRXC) & 0x7F) != 0){
uint8_t data = USF(uart->uart_nr);
size_t nextPos = (uart->rx_buffer->wpos + 1) % uart->rx_buffer->size;
if(nextPos != uart->rx_buffer->rpos) {
uart->rx_buffer->buffer[uart->rx_buffer->wpos] = data;
uart->rx_buffer->wpos = nextPos;
} else {
//rx buffer OverFlow
//maybe stop the loop and try later?
}
}
int_status = USIS(uart->uart_nr);
if(int_status & (1 << UIFF)) {
USIC(uart->uart_nr) = (1 << UIFF);//clear any FIFO FULL error
}
if(int_status & (1 << UITO)) {
USIC(uart->uart_nr) = (1 << UITO);//clear any TimeOut error
}
ETS_UART_INTR_ENABLE();
}
}

void uart_start_isr(uart_t* uart)
{
if(uart == NULL || !uart->rx_enabled) {
return;
}
USC1(uart->uart_nr) = (127 << UCFFT) | (0x02 << UCTOT) | (1 <<UCTOE );
USIC(uart->uart_nr) = 0xffff;
USIE(uart->uart_nr) = (1 << UIFF) | (1 << UIFR) | (1 << UITO);
ETS_UART_INTR_ATTACH(uart_isr, (void *)uart);
ETS_UART_INTR_ENABLE();
}

void uart_stop_isr(uart_t* uart)
{
if(uart == NULL || !uart->rx_enabled) {
return;
}
ETS_UART_INTR_DISABLE();
USC1(uart->uart_nr) = 0;
USIC(uart->uart_nr) = 0xffff;
USIE(uart->uart_nr) = 0;
ETS_UART_INTR_ATTACH(NULL, NULL);
}


void uart_write_char(uart_t* uart, char c)
{
if(uart == NULL || !uart->tx_enabled) {
return;
}
while((USS(uart->uart_nr) >> USTXC) >= 0x7f);
USF(uart->uart_nr) = c;
}

void uart_write(uart_t* uart, const char* buf, size_t size)
{
if(uart == NULL || !uart->tx_enabled) {
return;
}
while(size--) {
uart_write_char(uart, *buf++);
}
return (USS(uart->uart_nr) >> USRXC) & 0xff;
}

size_t uart_tx_free(uart_t* uart)
Expand Down Expand Up @@ -121,6 +233,10 @@ void uart_flush(uart_t* uart)
uint32_t tmp = 0x00000000;
if(uart->rx_enabled) {
tmp |= (1 << UCRXRST);
ETS_UART_INTR_DISABLE();
uart->rx_buffer->rpos = 0;
uart->rx_buffer->wpos = 0;
ETS_UART_INTR_ENABLE();
}

if(uart->tx_enabled) {
Expand Down Expand Up @@ -148,7 +264,7 @@ int uart_get_baudrate(uart_t* uart)
return uart->baud_rate;
}

uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin)
uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx_size)
{
uart_t* uart = (uart_t*) malloc(sizeof(uart_t));
if(uart == NULL) {
Expand All @@ -159,9 +275,29 @@ uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin)

switch(uart->uart_nr) {
case UART0:
ETS_UART_INTR_DISABLE();
ETS_UART_INTR_ATTACH(NULL, NULL);
uart->rx_enabled = (mode != UART_TX_ONLY);
uart->tx_enabled = (mode != UART_RX_ONLY);
uart->rx_pin = (uart->rx_enabled)?3:255;
if(uart->rx_enabled) {
struct uart_rx_buffer_ * rx_buffer = (struct uart_rx_buffer_ *)malloc(sizeof(struct uart_rx_buffer_));
if(rx_buffer == NULL) {
free(uart);
return NULL;
}
rx_buffer->size = rx_size;//var this
rx_buffer->rpos = 0;
rx_buffer->wpos = 0;
rx_buffer->buffer = (uint8_t *)malloc(rx_buffer->size);
if(rx_buffer->buffer == NULL) {
free(rx_buffer);
free(uart);
return NULL;
}
uart->rx_buffer = rx_buffer;
pinMode(uart->rx_pin, SPECIAL);
}
if(uart->tx_enabled) {
if (tx_pin == 2) {
uart->tx_pin = 2;
Expand All @@ -173,9 +309,6 @@ uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin)
} else {
uart->tx_pin = 255;
}
if(uart->rx_enabled) {
pinMode(uart->rx_pin, SPECIAL);
}
IOSWAP &= ~(1 << IOSWAPU0);
break;
case UART1:
Expand All @@ -199,6 +332,11 @@ uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin)
USC0(uart->uart_nr) = config;
uart_flush(uart);
USC1(uart->uart_nr) = 0;
USIC(uart->uart_nr) = 0xffff;
USIE(uart->uart_nr) = 0;
if(uart->uart_nr == UART0 && uart->rx_enabled) {
uart_start_isr(uart);
}

return uart;
}
Expand Down Expand Up @@ -230,6 +368,11 @@ void uart_uninit(uart_t* uart)
break;
}

if(uart->rx_enabled){
free(uart->rx_buffer->buffer);
free(uart->rx_buffer);
//uart_stop_isr(uart);
}
free(uart);
}

Expand Down
5 changes: 4 additions & 1 deletion cores/esp8266/uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ extern "C" {
struct uart_;
typedef struct uart_ uart_t;

uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin);
uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx_size);
void uart_uninit(uart_t* uart);

void uart_swap(uart_t* uart, int tx_pin);
Expand All @@ -125,9 +125,12 @@ bool uart_rx_enabled(uart_t* uart);
void uart_set_baudrate(uart_t* uart, int baud_rate);
int uart_get_baudrate(uart_t* uart);

size_t uart_resize_rx_buffer(uart_t* uart, size_t new_size);

void uart_write_char(uart_t* uart, char c);
void uart_write(uart_t* uart, const char* buf, size_t size);
int uart_read_char(uart_t* uart);
int uart_peek_char(uart_t* uart);
size_t uart_rx_available(uart_t* uart);
size_t uart_tx_free(uart_t* uart);
void uart_wait_tx_empty(uart_t* uart);
Expand Down