diff --git a/examples/softuart/main.c b/examples/softuart/main.c index d684c69..75b280e 100644 --- a/examples/softuart/main.c +++ b/examples/softuart/main.c @@ -1,6 +1,7 @@ /* * Softuart example * + * Copyright (C) 2017 Ruslan V. Uss * Copyright (C) 2016 Bernhard Guillon * Copyright (c) 2015 plieningerweb * @@ -10,7 +11,13 @@ #include #include #include -#include "softuart/softuart.h" +//#include +//#include + +#include + +#define RX_PIN 5 +#define TX_PIN 4 void user_init(void) { @@ -18,15 +25,16 @@ void user_init(void) uart_set_baud(0, 115200); printf("SDK version:%s\n\n", sdk_system_get_sdk_version()); - // setup software rx to 9600 8n1 - softuart_init(9600); + // setup software uart to 9600 8n1 + softuart_open(0, 9600, RX_PIN, TX_PIN); while (true) { - if (!softuart_available()) + if (!softuart_available(0)) continue; - char c = softuart_read(); - printf("input:%c\n",c); - softuart_puts("start\r\n"); + + char c = softuart_read(0); + printf("input: %c, 0x%02x\n", c, c); + softuart_puts(0, "start\r\n"); } } diff --git a/extras/softuart/softuart.c b/extras/softuart/softuart.c index d47f2ce..7cfc0fc 100644 --- a/extras/softuart/softuart.c +++ b/extras/softuart/softuart.c @@ -1,11 +1,11 @@ /* * Softuart * + * Copyright (C) 2017 Ruslan V. Uss * Copyright (C) 2016 Bernhard Guillon * * This code is based on Softuart from here [1] and reworked to - * fit into esp-open-rtos. For now only the RX part is ported. - * Also the configuration of the pin is for now hardcoded. + * fit into esp-open-rtos. * * it fits my needs to read the GY-GPS6MV2 module with 9600 8n1 * @@ -23,36 +23,72 @@ #include #include -static softuart s; +//#define SOFTUART_DEBUG -void handle_rx(uint8_t gpio_num) +#ifdef SOFTUART_DEBUG +#define debug(fmt, ...) printf("%s: " fmt "\n", "SOFTUART", ## __VA_ARGS__) +#else +#define debug(fmt, ...) +#endif + +typedef struct { + char receive_buffer[SOFTUART_MAX_RX_BUFF]; + uint8_t receive_buffer_tail; + uint8_t receive_buffer_head; + uint8_t buffer_overflow; +} softuart_buffer_t; + +typedef struct +{ + uint8_t rx_pin, tx_pin; + uint32_t baudrate; + volatile softuart_buffer_t buffer; + uint16_t bit_time; +} softuart_t; + +static softuart_t uarts[SOFTUART_MAX_UARTS] = { { 0 } }; + +inline static int8_t find_uart_by_rx(uint8_t rx_pin) +{ + for (uint8_t i = 0; i < SOFTUART_MAX_UARTS; i++) + if (uarts[i].baudrate && uarts[i].rx_pin == rx_pin) return i; + + return -1; +} + +// GPIO interrupt handler +static void handle_rx(uint8_t gpio_num) +{ + // find uart + int8_t uart_no = find_uart_by_rx(gpio_num); + if (uart_no < 0) return; + + softuart_t *uart = uarts + uart_no; + // Disable interrupt - gpio_set_interrupt(rx_pin, GPIO_INTTYPE_NONE, handle_rx); + gpio_set_interrupt(gpio_num, GPIO_INTTYPE_NONE, handle_rx); // Wait till start bit is half over so we can sample the next one in the center - sdk_os_delay_us(s.bit_time/2); + sdk_os_delay_us(uart->bit_time / 2); // Now sample bits - unsigned i; - unsigned d = 0; - unsigned start_time = 0x7FFFFFFF & sdk_system_get_time(); + uint8_t d = 0; + uint32_t start_time = 0x7FFFFFFF & sdk_system_get_time(); - for(i = 0; i < 8; i ++ ) + for (uint8_t i = 0; i < 8; i++) { - while ((0x7FFFFFFF & sdk_system_get_time()) < (start_time + (s.bit_time*(i+1)))) + while ((0x7FFFFFFF & sdk_system_get_time()) < (start_time + (uart->bit_time * (i + 1)))) { // If system timer overflow, escape from while loop if ((0x7FFFFFFF & sdk_system_get_time()) < start_time) - { break; - } } // Shift d to the right d >>= 1; // Read bit - if(gpio_read(rx_pin)) + if (gpio_read(uart->rx_pin)) { // If high, set msb of 8bit to 1 d |= 0x80; @@ -61,106 +97,174 @@ void handle_rx(uint8_t gpio_num) // Store byte in buffer // If buffer full, set the overflow flag and return - uint8_t next = (s.buffer.receive_buffer_tail + 1) % SOFTUART_MAX_RX_BUFF; - if (next != s.buffer.receive_buffer_head) + uint8_t next = (uart->buffer.receive_buffer_tail + 1) % SOFTUART_MAX_RX_BUFF; + if (next != uart->buffer.receive_buffer_head) { // save new data in buffer: tail points to where byte goes - s.buffer.receive_buffer[s.buffer.receive_buffer_tail] = d; // save new byte - s.buffer.receive_buffer_tail = next; + uart->buffer.receive_buffer[uart->buffer.receive_buffer_tail] = d; // save new byte + uart->buffer.receive_buffer_tail = next; } else { - s.buffer.buffer_overflow = 1; + uart->buffer.buffer_overflow = 1; } // Wait for stop bit - sdk_os_delay_us(s.bit_time); - // Done - // Reenable interrupt - gpio_set_interrupt(rx_pin, GPIO_INTTYPE_EDGE_NEG, handle_rx); -} -static uint8_t inline chbit(uint8_t data, uint8_t bit) -{ - if((data & bit) != 0) - { - return 1; - } - else - { - return 0; - } -} -uint8_t softuart_putchar( char data) -{ - unsigned i; - unsigned start_time = 0x7FFFFFFF & sdk_system_get_time(); - gpio_write(tx_pin, 0); - for(i = 0; i <= 8; i++) - { - while((0x7FFFFFFF & sdk_system_get_time()) < (start_time + (s.bit_time*(i+1)))) - { - if((0x7FFFFFFF & sdk_system_get_time()) < start_time) - { - break; - } - } - gpio_write(tx_pin, chbit(data, 1<bit_time); + + // Done, reenable interrupt + gpio_set_interrupt(uart->rx_pin, GPIO_INTTYPE_EDGE_NEG, handle_rx); +} + +static bool check_uart_no(uint8_t uart_no) +{ + if (uart_no >= SOFTUART_MAX_UARTS) + { + debug("Invalid uart number %d, %d max", uart_no, SOFTUART_MAX_UARTS); + return false; + } - // Calculate bit_time - s.bit_time = (1000000 / baudrate); - if ( ((100000000 / baudrate) - (100*s.bit_time)) > 50 ) - s.bit_time++; - //Set Rx - gpio_enable(rx_pin, GPIO_INPUT); - gpio_set_pullup(rx_pin, true, false); - // Set up the interrupt handler to get the startbit - gpio_set_interrupt(rx_pin, GPIO_INTTYPE_EDGE_NEG, handle_rx); - //Set Tx - gpio_enable(tx_pin, GPIO_OUTPUT); - gpio_set_pullup(tx_pin, true, false); - gpio_write(tx_pin, 1); - sdk_os_delay_us(100000); return true; } -// Read data from buffer -uint8_t softuart_read() +static bool check_uart_enabled(uint8_t uart_no) { + if (!uarts[uart_no].baudrate) + { + debug("Uart %d is disabled", uart_no); + return false; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +/// Public +/////////////////////////////////////////////////////////////////////////////// + +bool softuart_open(uint8_t uart_no, uint32_t baudrate, uint8_t rx_pin, uint8_t tx_pin) +{ + // do some checks + if (!check_uart_no(uart_no)) return false; + if (baudrate == 0) + { + debug("Invalid baudrate"); + return false; + } + for (uint8_t i = 0; i < SOFTUART_MAX_UARTS; i++) + if (uarts[i].baudrate && i != uart_no + && (uarts[i].rx_pin == rx_pin || uarts[i].tx_pin == tx_pin || uarts[i].rx_pin == tx_pin || uarts[i].tx_pin == rx_pin)) + { + debug("Cannot share pins between uarts"); + return false; + } + + softuart_close(uart_no); + + softuart_t *uart = uarts + uart_no; + + uart->baudrate = baudrate; + uart->rx_pin = rx_pin; + uart->tx_pin = tx_pin; + + // Calculate bit_time + uart->bit_time = (1000000 / baudrate); + if (((100000000 / baudrate) - (100 * uart->bit_time)) > 50) uart->bit_time++; + + // Setup Rx + gpio_enable(rx_pin, GPIO_INPUT); + gpio_set_pullup(rx_pin, true, false); + + // Setup Tx + gpio_enable(tx_pin, GPIO_OUTPUT); + gpio_set_pullup(tx_pin, true, false); + gpio_write(tx_pin, 1); + + // Setup the interrupt handler to get the start bit + gpio_set_interrupt(rx_pin, GPIO_INTTYPE_EDGE_NEG, handle_rx); + + sdk_os_delay_us(1000); // TODO: not sure if it really needed + + return true; +} + +bool softuart_close(uint8_t uart_no) +{ + if (!check_uart_no(uart_no)) return false; + softuart_t *uart = uarts + uart_no; + + if (!uart->baudrate) return true; + + // Remove interrupt + gpio_set_interrupt(uart->rx_pin, GPIO_INTTYPE_NONE, NULL); + // Mark as unused + uart->baudrate = 0; + + return true; +} + +bool softuart_put(uint8_t uart_no, char c) +{ + if (!check_uart_no(uart_no)) return false; + if (!check_uart_enabled(uart_no)) return false; + softuart_t *uart = uarts + uart_no; + + uint32_t start_time = 0x7FFFFFFF & sdk_system_get_time(); + gpio_write(uart->tx_pin, 0); + + for (uint8_t i = 0; i <= 8; i++) + { + while ((0x7FFFFFFF & sdk_system_get_time()) < (start_time + (uart->bit_time * (i + 1)))) + { + if ((0x7FFFFFFF & sdk_system_get_time()) < start_time) + break; + } + gpio_write(uart->tx_pin, c & (1 << i)); + } + + while ((0x7FFFFFFF & sdk_system_get_time()) < (start_time + (uart->bit_time * 9))) + { + if ((0x7FFFFFFF & sdk_system_get_time()) < start_time) + break; + } + gpio_write(uart->tx_pin, 1); + sdk_os_delay_us(uart->bit_time * 6); + + return true; +} + +bool softuart_puts(uint8_t uart_no, const char *s) +{ + while (*s) + { + if (!softuart_put(uart_no, *s++)) + return false; + } + + return true; +} + +bool softuart_available(uint8_t uart_no) +{ + if (!check_uart_no(uart_no)) return false; + if (!check_uart_enabled(uart_no)) return false; + softuart_t *uart = uarts + uart_no; + + return (uart->buffer.receive_buffer_tail + SOFTUART_MAX_RX_BUFF - uart->buffer.receive_buffer_head) % SOFTUART_MAX_RX_BUFF; +} + +uint8_t softuart_read(uint8_t uart_no) +{ + if (!check_uart_no(uart_no)) return 0; + if (!check_uart_enabled(uart_no)) return 0; + softuart_t *uart = uarts + uart_no; + // Empty buffer? - if (s.buffer.receive_buffer_head == s.buffer.receive_buffer_tail) - return 0; + if (uart->buffer.receive_buffer_head == uart->buffer.receive_buffer_tail) return 0; // Read from "head" - uint8_t d = s.buffer.receive_buffer[s.buffer.receive_buffer_head]; // grab next byte - s.buffer.receive_buffer_head = (s.buffer.receive_buffer_head + 1) % SOFTUART_MAX_RX_BUFF; + uint8_t d = uart->buffer.receive_buffer[uart->buffer.receive_buffer_head]; // grab next byte + uart->buffer.receive_buffer_head = (uart->buffer.receive_buffer_head + 1) % SOFTUART_MAX_RX_BUFF; return d; } -// Is data in buffer available? -bool softuart_available() -{ - return (s.buffer.receive_buffer_tail + SOFTUART_MAX_RX_BUFF - s.buffer.receive_buffer_head) % SOFTUART_MAX_RX_BUFF; -} diff --git a/extras/softuart/softuart.h b/extras/softuart/softuart.h index fdd65be..e5fa8f6 100644 --- a/extras/softuart/softuart.h +++ b/extras/softuart/softuart.h @@ -1,6 +1,7 @@ /* * Softuart for esp-open-rtos * + * Copyright (C) 2017 Ruslan V. Uss * Copyright (C) 2016 Bernhard Guillon * * This code is based on Softuart from here [1] and reworked to @@ -27,61 +28,64 @@ extern "C" { #endif -// FIXME: for now you need to provide the gpio number for RX here -#define rx_pin 4 -#define tx_pin 5 +#ifndef SOFTUART_MAX_UARTS + #define SOFTUART_MAX_UARTS 2 +#endif -#define SOFTUART_MAX_RX_BUFF 64 -#define SOFTUART_GPIO_COUNT 16 +#ifndef SOFTUART_MAX_RX_BUFF + #define SOFTUART_MAX_RX_BUFF 64 //!< Must be power of two: 2, 4, 8, 16 etc. +#endif /** - * Private data buffer - */ -typedef struct softuart_buffer_t -{ - char receive_buffer[SOFTUART_MAX_RX_BUFF]; - uint8_t receive_buffer_tail; - uint8_t receive_buffer_head; - uint8_t buffer_overflow; -} softuart_buffer_t; - -/** - * Private softuart descriptor - */ -typedef struct -{ - uint8_t pin_rx; //!< This value is ignored by now but planned to get added again - volatile softuart_buffer_t buffer; //!< Internal buffer - uint16_t bit_time; //!< Time for one bit, filled by softuart -} softuart; - -/** - * Initialize software uart and setup interrup handlers - * - * FIXME: For now you will have to set up the - * rx_pin and handle_rx your self. - * - * @param baudrate actual baudrate + * Initialize software uart and setup interrupt handler + * @param uart_no Software uart index, 0..SOFTUART_MAX_UARTS + * @param baudrate Baudrate, e.g. 9600, 19200, etc + * @param rx_pin GPIO pin number for RX + * @param tx_pin GPIO pin number for TX * @return true if no errors occured otherwise false */ -bool softuart_init(uint32_t baudrate); +bool softuart_open(uint8_t uart_no, uint32_t baudrate, uint8_t rx_pin, uint8_t tx_pin); + +/** + * Deinitialize software uart + * @param uart_no Software uart index, 0..SOFTUART_MAX_UARTS + * @return true if no errors occured otherwise false + */ +bool softuart_close(uint8_t uart_no); + +/** + * Put char to software uart + * @param uart_no Software uart index, 0..SOFTUART_MAX_UARTS + * @param c Char + * @return true if no errors occured otherwise false + */ +bool softuart_put(uint8_t uart_no, char c); + +/** + * Put string to software uart + * @param uart_no Software uart index, 0..SOFTUART_MAX_UARTS + * @param s Null-terminated string + * @return true if no errors occured otherwise false + */ +bool softuart_puts(uint8_t uart_no, const char *s); /** * Check if data is available + * @param uart_no Software uart index, 0..SOFTUART_MAX_UARTS * @return true if data is available otherwise false */ -bool softuart_available(); +bool softuart_available(uint8_t uart_no); /** * Read current byte from internal buffer if available. * * NOTE: This call is non blocking. - * NOTE: You have to check softuart_available first. - * @return current byte + * NOTE: You have to check softuart_available() first. + * @param uart_no Software uart index, 0..SOFTUART_MAX_UARTS + * @return current byte if available otherwise 0 */ -uint8_t softuart_read(); -uint8_t softuart_putchar(char data); -void softuart_puts(const char *c); +uint8_t softuart_read(uint8_t uart_no); + #ifdef __cplusplus } #endif