From 9d80dc441fafc03bd94de9c19534bd10b1ebad33 Mon Sep 17 00:00:00 2001 From: Johan Kanflo Date: Fri, 7 Aug 2015 22:41:13 +0200 Subject: [PATCH] IRQ driven RX on UART0 See examples/terminal/ for usage --- core/newlib_syscalls.c | 3 +- examples/terminal/FreeRTOSConfig.h | 12 +++ examples/terminal/Makefile | 3 + examples/terminal/terminal.c | 37 +++++++++ extras/serial-driver/component.mk | 11 +++ extras/serial-driver/serial_driver.c | 119 +++++++++++++++++++++++++++ extras/serial-driver/serial_driver.h | 33 ++++++++ 7 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 examples/terminal/FreeRTOSConfig.h create mode 100644 examples/terminal/Makefile create mode 100644 examples/terminal/terminal.c create mode 100644 extras/serial-driver/component.mk create mode 100644 extras/serial-driver/serial_driver.c create mode 100644 extras/serial-driver/serial_driver.h diff --git a/core/newlib_syscalls.c b/core/newlib_syscalls.c index fb97f7b..813e449 100644 --- a/core/newlib_syscalls.c +++ b/core/newlib_syscalls.c @@ -45,8 +45,9 @@ long _write_r(struct _reent *r, int fd, const char *ptr, int len ) /* syscall implementation for stdio read from UART at the moment UART functionality is all still in the binary SDK + but there is support for IRQ driven UART0 RX in extras/serial-driver */ -long _read_r( struct _reent *r, int fd, char *ptr, int len ) +long __attribute__((weak)) _read_r( struct _reent *r, int fd, char *ptr, int len ) { for(int i = 0; i < len; i++) { char ch; diff --git a/examples/terminal/FreeRTOSConfig.h b/examples/terminal/FreeRTOSConfig.h new file mode 100644 index 0000000..0a9a6b7 --- /dev/null +++ b/examples/terminal/FreeRTOSConfig.h @@ -0,0 +1,12 @@ +/* Terminal FreeRTOSConfig overrides. + + This is intended as an example of overriding some of the default FreeRTOSConfig settings, + which are otherwise found in FreeRTOS/Source/include/FreeRTOSConfig.h +*/ + +/* The serial driver depends on counting semaphores */ +#define configUSE_COUNTING_SEMAPHORES 1 + +/* Use the defaults for everything else */ +#include_next + diff --git a/examples/terminal/Makefile b/examples/terminal/Makefile new file mode 100644 index 0000000..b784f87 --- /dev/null +++ b/examples/terminal/Makefile @@ -0,0 +1,3 @@ +PROGRAM=terminal +EXTRA_COMPONENTS=extras/serial-driver +include ../../common.mk diff --git a/examples/terminal/terminal.c b/examples/terminal/terminal.c new file mode 100644 index 0000000..45d0fce --- /dev/null +++ b/examples/terminal/terminal.c @@ -0,0 +1,37 @@ +/* Serial terminal example + * UART RX is interrupt driven + * Read characters until \n and echo back + * + * This sample code is in the public domain. + */ + +#include +#include +#include +#include +#include + +#define BUFFER_SIZE (81) + +void user_init(void) +{ + char buffer[BUFFER_SIZE]; + uint32_t i = 0; + sdk_uart_div_modify(0, UART_CLK_FREQ / 115200); + while(1) { + char ch; + // The thread will block here until there is data available + // NB. read(...) may be called from user_init or from a thread + // We can check how many characters are available in the RX buffer + // with uint32_t uart0_num_char(void); + if (read(0, (void*)&ch, 1)) { // 0 is stdin + if (i == BUFFER_SIZE-2 || ch == '\n') { + buffer[i] = 0; + printf("Unknown command: %s\n", (char*) buffer); + i = 0; + } else { + buffer[i++] = ch; + } + } + } +} diff --git a/extras/serial-driver/component.mk b/extras/serial-driver/component.mk new file mode 100644 index 0000000..bb17970 --- /dev/null +++ b/extras/serial-driver/component.mk @@ -0,0 +1,11 @@ +# Component makefile for extras/serial-driver +# +# See examples/terminal for usage + +INC_DIRS += $(ROOT)extras/serial-driver + +# args for passing into compile rule generation +extras/serial-driver_INC_DIR = $(ROOT)extras/serial-driver +extras/serial-driver_SRC_DIR = $(ROOT)extras/serial-driver + +$(eval $(call component_compile_rules,extras/serial-driver)) diff --git a/extras/serial-driver/serial_driver.c b/extras/serial-driver/serial_driver.c new file mode 100644 index 0000000..a702d69 --- /dev/null +++ b/extras/serial-driver/serial_driver.c @@ -0,0 +1,119 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 Johan Kanflo (github.com/kanflo) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#if (configUSE_COUNTING_SEMAPHORES == 0) + #error "You need to define configUSE_COUNTING_SEMAPHORES in a local FreeRTOSConfig.h, see examples/terminal/FreeRTOSConfig.h" +#endif + +// IRQ driven UART RX driver for ESP8266 written for use with esp-open-rtos +// TODO: Handle UART1 + +#define UART0_RX_SIZE (81) + +#ifndef UART0 +#define UART0 (0) +#endif + +static xSemaphoreHandle uart0_sem = NULL; +static char rx_buf[UART0_RX_SIZE]; +static uint8_t rd_pos = 0; +static uint8_t wr_pos = 0; +static bool inited = false; + +static void uart0_rx_init(void); + + +IRAM void uart0_rx_handler(void) +{ + // TODO: Handle UART1, see reg 0x3ff20020, bit2, bit0 represents uart1 and uart0 respectively + if (UART_RXFIFO_FULL_INT_ST != (READ_PERI_REG(UART_INT_ST(UART0)) & UART_RXFIFO_FULL_INT_ST)) { + return; + } + WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR); + while (READ_PERI_REG(UART_STATUS(UART0)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) { + char ch = READ_PERI_REG(UART_FIFO(UART0)) & 0xff; + uint8_t wr_next = (wr_pos+1) % UART0_RX_SIZE; + if (wr_next != rd_pos) { + rx_buf[wr_pos] = ch; + wr_pos = (wr_pos+1) % UART0_RX_SIZE; + xSemaphoreGiveFromISR(uart0_sem, NULL); + } + } +} + +uint32_t uart0_num_char(void) +{ + uint32_t count; + if (!inited) uart0_rx_init(); + _xt_isr_mask(1 << INUM_UART); + if (rd_pos > wr_pos) count = rd_pos - wr_pos; + else count = wr_pos - rd_pos; + _xt_isr_unmask(1 << INUM_UART); + return count; +} + +// _read_r in core/newlib_syscalls.c will be skipped in favour of this function +long _read_r(struct _reent *r, int fd, char *ptr, int len) +{ + if (!inited) uart0_rx_init(); + for(int i = 0; i < len; i++) { + char ch; + if (xSemaphoreTake(uart0_sem, portMAX_DELAY)) { + _xt_isr_mask(1 << INUM_UART); + ch = rx_buf[rd_pos]; + rd_pos = (rd_pos+1) % UART0_RX_SIZE; + _xt_isr_unmask(1 << INUM_UART); + ptr[i] = ch; + } + } + return len; +} + +static void uart0_rx_init(void) +{ + int trig_lvl = 1; + uart0_sem = xSemaphoreCreateCounting(UART0_RX_SIZE, 0); + + _xt_isr_attach(INUM_UART, uart0_rx_handler); + _xt_isr_unmask(1 << INUM_UART); + + //clear rx and tx fifo,not ready + SET_PERI_REG_MASK(UART_CONF0(UART0), UART_RXFIFO_RST | UART_TXFIFO_RST); + CLEAR_PERI_REG_MASK(UART_CONF0(UART0), UART_RXFIFO_RST | UART_TXFIFO_RST); + + //set rx fifo trigger + WRITE_PERI_REG(UART_CONF1(UART0), (trig_lvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S); + + //clear all interrupt + WRITE_PERI_REG(UART_INT_CLR(UART0), 0xffff); + //enable rx_interrupt + SET_PERI_REG_MASK(UART_INT_ENA(UART0), UART_RXFIFO_FULL_INT_ENA); + inited = true; +} diff --git a/extras/serial-driver/serial_driver.h b/extras/serial-driver/serial_driver.h new file mode 100644 index 0000000..10491ac --- /dev/null +++ b/extras/serial-driver/serial_driver.h @@ -0,0 +1,33 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 Johan Kanflo (github.com/kanflo) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __I2C_H__ +#define __I2C_H__ +#endif + +#include +#include + +// Return number of characters waiting in UART0 +uint32_t uart0_num_char(void);