Refactored: support for multiple UARTs, dynamic RX/TX pins

This commit is contained in:
UncleRus 2017-02-22 01:06:00 +05:00
parent 41225f0e6b
commit 1294538ad2
3 changed files with 260 additions and 144 deletions

View file

@ -1,6 +1,7 @@
/*
* Softuart example
*
* Copyright (C) 2017 Ruslan V. Uss <unclerus@gmail.com>
* Copyright (C) 2016 Bernhard Guillon <Bernhard.Guillon@web.de>
* Copyright (c) 2015 plieningerweb
*
@ -10,7 +11,13 @@
#include <esp/uart.h>
#include <espressif/esp_common.h>
#include <stdio.h>
#include "softuart/softuart.h"
//#include <FreeRTOS.h>
//#include <task.h>
#include <softuart/softuart.h>
#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");
}
}

View file

@ -1,11 +1,11 @@
/*
* Softuart
*
* Copyright (C) 2017 Ruslan V. Uss <unclerus@gmail.com>
* Copyright (C) 2016 Bernhard Guillon <Bernhard.Guillon@web.de>
*
* 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 <espressif/esp_common.h>
#include <stdio.h>
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<<i));
}
while((0x7FFFFFFF & sdk_system_get_time()) < (start_time + (s.bit_time*9)))
{
if((0x7FFFFFFF & sdk_system_get_time()) < start_time)
{
break;
}
}
gpio_write(tx_pin, 1);
sdk_os_delay_us(s.bit_time*6);
return 0;
}
void softuart_puts(const char *c)
{
while( *c )
{
softuart_putchar((uint8_t)*c++);
}
}
bool softuart_init(uint32_t baudrate)
{
if (baudrate == 0)
return false;
sdk_os_delay_us(uart->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;
}

View file

@ -1,6 +1,7 @@
/*
* Softuart for esp-open-rtos
*
* Copyright (C) 2017 Ruslan V. Uss <unclerus@gmail.com>
* Copyright (C) 2016 Bernhard Guillon <Bernhard.Guillon@web.de>
*
* 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