You can chat about native SDK questions and issues here.

User avatar
By Agentsmithers
#89490
Code: Select all/*
 * ESPRSSIF MIT License
 *
 * Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
 *
 * Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
 * it is 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 UART_APP_H
#define UART_APP_H

#include "uart_register.h"
#include "eagle_soc.h" //~/esp-open-sdk/xtensa-lx106-elf/sysroot/usr/include <-- pulled from here
#include "c_types.h"
#include "pin_mux_register.h"
//#include "task.h"
#define recvTaskPrio        0
#define recvTaskQueueLen    64

#define UART_BUFF_EN     0   //use uart buffer  , FOR UART0
#define UART_SELFTEST     0   //set 1:enable the loop test demo for uart buffer, FOR UART0

#define UART_HW_RTS      1   //set 1: enable uart hw flow control RTS, PIN MTDO, FOR UART0
#define UART_HW_CTS   1   //set1: enable uart hw flow contrl CTS , PIN MTCK, FOR UART0

#define UART0   0
#define UART1   1

//calc bit 0..5 for  UART_CONF0 register
#define CALC_UARTMODE(data_bits,parity,stop_bits) \
   (((parity == NONE_BITS) ? 0x0 : (UART_PARITY_EN | (parity & UART_PARITY))) | \
   ((stop_bits & UART_STOP_BIT_NUM) << UART_STOP_BIT_NUM_S) | \
   ((data_bits & UART_BIT_NUM) << UART_BIT_NUM_S))
//get data_bits from UART_CONF0 register
#define GETUART_DATABITS(uartmode) ((uartmode >> UART_BIT_NUM_S) & UART_BIT_NUM)
//get stop_bits from UART_CONF0 register
#define GETUART_STOPBITS(uartmode) ((uartmode >> UART_STOP_BIT_NUM_S) & UART_STOP_BIT_NUM)
//get parity from UART_CONF0 register
#define GETUART_PARITYMODE(uartmode) ((uartmode & UART_PARITY_EN) ? uartmode & UART_PARITY : NONE_BITS)


typedef enum {
    FIVE_BITS = 0x0,
    SIX_BITS = 0x1,
    SEVEN_BITS = 0x2,
    EIGHT_BITS = 0x3
} UartBitsNum4Char;

typedef enum {
    ONE_STOP_BIT             = 0x1,
    ONE_HALF_STOP_BIT        = 0x2,
    TWO_STOP_BIT             = 0x3
} UartStopBitsNum;

typedef enum {
    NONE_BITS = 0x2,
    ODD_BITS   = 1,
    EVEN_BITS = 0
} UartParityMode;

typedef enum {
    STICK_PARITY_DIS   = 0,
    STICK_PARITY_EN    = 1
} UartExistParity;

typedef enum {
    UART_None_Inverse = 0x0,
    UART_Rxd_Inverse = UART_RXD_INV,
    UART_CTS_Inverse = UART_CTS_INV,
    UART_Txd_Inverse = UART_TXD_INV,
    UART_RTS_Inverse = UART_RTS_INV,
} UART_LineLevelInverse;


typedef enum {
    BIT_RATE_300 = 300,
    BIT_RATE_600 = 600,
    BIT_RATE_1200 = 1200,
    BIT_RATE_2400 = 2400,
    BIT_RATE_4800 = 4800,
    BIT_RATE_9600   = 9600,
    BIT_RATE_19200  = 19200,
    BIT_RATE_38400  = 38400,
    BIT_RATE_57600  = 57600,
    BIT_RATE_74880  = 74880,
    BIT_RATE_115200 = 115200,
    BIT_RATE_230400 = 230400,
    BIT_RATE_460800 = 460800,
    BIT_RATE_921600 = 921600,
    BIT_RATE_1843200 = 1843200,
    BIT_RATE_3686400 = 3686400,
} UartBautRate;

typedef enum {
    NONE_CTRL,
    HARDWARE_CTRL,
    XON_XOFF_CTRL
} UartFlowCtrl;

typedef enum {
    USART_HardwareFlowControl_None = 0x0,
    USART_HardwareFlowControl_RTS = 0x1,
    USART_HardwareFlowControl_CTS = 0x2,
    USART_HardwareFlowControl_CTS_RTS = 0x3
} UART_HwFlowCtrl;

typedef enum {
    EMPTY,
    UNDER_WRITE,
    WRITE_OVER
} RcvMsgBuffState;

typedef struct {
    uint32     RcvBuffSize;
    uint8     *pRcvMsgBuff;
    uint8     *pWritePos;
    uint8     *pReadPos;
    uint8      TrigLvl; //JLU: may need to pad
    RcvMsgBuffState  BuffState;
} RcvMsgBuff;

typedef struct {
    uint32   TrxBuffSize;
    uint8   *pTrxBuff;
} TrxMsgBuff;

typedef enum {
    BAUD_RATE_DET,
    WAIT_SYNC_FRM,
    SRCH_MSG_HEAD,
    RCV_MSG_BODY,
    RCV_ESC_CHAR,
} RcvMsgState;

typedef struct {
    UartBautRate         baut_rate;
    UartBitsNum4Char  data_bits;
    UartExistParity      exist_parity;
    UartParityMode        parity;   
    UartStopBitsNum   stop_bits;
    UartFlowCtrl         flow_ctrl;
    RcvMsgBuff          rcv_buff;
    TrxMsgBuff           trx_buff;
    RcvMsgState        rcv_state;
    int                      received;
    int                      buff_uart_no;  //indicate which uart use tx/rx buffer
} UartDevice;

//void uart_init(UartBautRate uart0_br, UartBautRate uart1_br);
void ICACHE_FLASH_ATTR uart_init(UartBautRate uart0_br, UartBautRate uart1_br, void * callback);
void uart0_sendStr(const char *str);


///////////////////////////////////////

 struct UartBuffer{
    uint32     UartBuffSize;
    uint8     *pUartBuff;
    uint8     *pInPos;
    uint8     *pOutPos;
    STATUS  BuffState;
    uint16    Space;  //remanent space of the buffer
    uint8  TcpControl;
    struct  UartBuffer     *  nextBuff;
};

struct UartRxBuff{
    uint32     UartRxBuffSize;
    uint8     *pUartRxBuff;
    uint8     *pWritePos;
    uint8     *pReadPos;
    STATUS RxBuffState;
    uint32    Space;  //remanent space of the buffer
} ;

typedef enum {
    RUN = 0,
    BLOCK = 1,
} TCPState;

//void ICACHE_FLASH_ATTR uart_test_rx();
//STATUS uart_tx_one_char(uint8 uart, uint8 TxChar);
STATUS uart_tx_one_char_no_wait(uint8 uart, uint8 TxChar);
void  uart1_sendStr_no_wait(const char *str);
struct UartBuffer*  Uart_Buf_Init();


#if UART_BUFF_EN
LOCAL void  Uart_Buf_Cpy(struct UartBuffer* pCur, char* pdata , uint16 data_len);
void  uart_buf_free(struct UartBuffer* pBuff);
void  tx_buff_enq(char* pdata, uint16 data_len );
LOCAL void  tx_fifo_insert(struct UartBuffer* pTxBuff, uint8 data_len,  uint8 uart_no);
void  tx_start_uart_buffer(uint8 uart_no);
uint16  rx_buff_deq(char* pdata, uint16 data_len );
void  Uart_rx_buff_enq();
#endif
void  uart_rx_intr_enable(uint8 uart_no);
void  uart_rx_intr_disable(uint8 uart_no);
void uart0_tx_buffer(uint8 *buf, uint16 len);

//==============================================
#define FUNC_UART0_CTS 4
#define FUNC_U0CTS                      4
#define FUNC_U1TXD_BK                   2
#define UART_LINE_INV_MASK  (0x3f<<19)
void UART_SetWordLength(uint8 uart_no, UartBitsNum4Char len);
void UART_SetStopBits(uint8 uart_no, UartStopBitsNum bit_num);
void UART_SetLineInverse(uint8 uart_no, UART_LineLevelInverse inverse_mask);
void UART_SetParity(uint8 uart_no, UartParityMode Parity_mode);
void UART_SetBaudrate(uint8 uart_no,uint32 baud_rate);
void UART_SetFlowCtrl(uint8 uart_no,UART_HwFlowCtrl flow_ctrl,uint8 rx_thresh);
void UART_WaitTxFifoEmpty(uint8 uart_no , uint32 time_out_us); //do not use if tx flow control enabled
void UART_ResetFifo(uint8 uart_no);
void UART_ClearIntrStatus(uint8 uart_no,uint32 clr_mask);
void UART_SetIntrEna(uint8 uart_no,uint32 ena_mask);
void UART_SetPrintPort(uint8 uart_no);
bool UART_CheckOutputFinished(uint8 uart_no, uint32 time_out_us);
//==============================================

#endif




/*
 * File   : uart.c
 * This file is part of Espressif's AT+ command set program.
 * Copyright (C) 2013 - 2016, Espressif Systems
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of version 3 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/*#include "ets_sys.h"
#include "osapi.h"
#include "driver/uart.h"
#include "osapi.h"
#include "driver/uart_register.h"
//#include "ssc.h"
#include "task.h"
*/
// UartDev is defined and initialized in rom code.
extern UartDevice    UartDev;
//extern os_event_t    at_recvTaskQueue[at_recvTaskQueueLen];

LOCAL void uart0_rx_intr_handler(void *para);

/******************************************************************************
 * FunctionName : uart_config
 * Description  : Internal used function
 *                UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled
 *                UART1 just used for debug output
 * Parameters   : uart_no, use UART0 or UART1 defined ahead
 * Returns      : NONE
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR uart_config(uint8 uart_no, void * callback(uint8))
{//http://smallbits.marshall-tribe.net/blog/2016/11/13/esp8266-quiet-uart
   #if UART_HW_CTS
      os_printf("uart_config with CTS:%d\r\n", uart_no);
   #else
      os_printf("uart_config without CTS:%d\r\n", uart_no);
   #endif
   #if UART_HW_RTS
      os_printf("uart_config with RTS:%d\r\n", uart_no);
   #else
      os_printf("uart_config without RTS:%d\r\n", uart_no);
   #endif
   if (uart_no == UART0)
   {
      /* UART0 */
      if (callback != NULL)
      {
         os_printf("Attaching UART callback for UART:%d", uart_no);
         ETS_UART_INTR_ATTACH(uart0_rx_intr_handler,  callback);
      }
      else
      {
         os_printf("Skipping UART callback for UART:%d", uart_no);
      }
      PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
      PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
      //Enable RxD pin
      PIN_PULLUP_EN(PERIPHS_IO_MUX_U0RXD_U);
      PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD);   

       #if UART_HW_RTS
         PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS);   //HW FLOW CONTROL RTS PIN
      #endif
      #if UART_HW_CTS
         PIN_PULLUP_EN(PERIPHS_IO_MUX_MTCK_U);
         PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_U0CTS);   //HW FLOW CONTROL CTS PIN
      #endif   
   }
   else
   {
      PIN_PULLUP_DIS(PERIPHS_IO_MUX_GPIO2_U);
      PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK); //D4 used for Debug out.
      PIN_PULLUP_EN(PERIPHS_IO_MUX_GPIO2_U);
   }

   uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate));

   WRITE_PERI_REG(UART_CONF0(uart_no), CALC_UARTMODE(EIGHT_BITS, NONE_BITS, ONE_STOP_BIT));

   //clear rx and tx fifo,not ready
   SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
   CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
   WRITE_PERI_REG(UART_CONF1(uart_no), ((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S)
   #if UART_HW_RTS
        | ((110 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) | UART_RX_FLOW_EN   //enbale rx flow control
        #endif
   );

   //clear all interrupt
   WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff);
   //enable rx_interrupt
   SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA);
   #if UART_HW_CTS
           //SET_PERI_REG_MASK( UART_CONF0(uart_no),UART_TX_FLOW_EN);  //add this sentense to add a tx flow control via MTCK( CTS )
        #endif
}

//IO SWAP Register
#define IOSWAP    ESP8266_DREG(0x28)
#define IOSWAPU   0 //Swaps UART
#define IOSWAPS   1 //Swaps SPI
#define IOSWAPU0  2 //Swaps UART 0 pins (u0rxd <-> u0cts), (u0txd <-> u0rts)
#define IOSWAPU1  3 //Swaps UART 1 pins (u1rxd <-> u1cts), (u1txd <-> u1rts)
#define IOSWAPHS  5 //Sets HSPI with higher prio
#define IOSWAP2HS 6 //Sets Two SPI Masters on HSPI
#define IOSWAP2CS 7 //Sets Two SPI Masters on CSPI
/******************************************************************************
 * FunctionName : uart0_alt
 * Description  : Internal used function
 *                UART0 pins changed to 13,15 if 'on' is set, else set to normal pins
 * Parameters   : on - 1 = use alternate pins, 0 = use normal pins
 * Returns      : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR uart0_alt(bool on)
{
    if (on)
    {
        PIN_PULLUP_DIS(PERIPHS_IO_MUX_MTDO_U);
        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS);
        PIN_PULLUP_EN(PERIPHS_IO_MUX_MTCK_U);
        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_U0CTS);
        // now make RTS/CTS behave as TX/RX
        //IOSWAP |= (1 << IOSWAPU0);
    }
    else
    {
        PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
        PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
        PIN_PULLUP_EN(PERIPHS_IO_MUX_U0RXD_U);
        PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD);
        // now make RX/TX behave as TX/RX
        //IOSWAP &= ~(1 << IOSWAPU0);
    }
}

/******************************************************************************
 * FunctionName : uart1_tx_one_char
 * Description  : Internal used function
 *                Use uart1 interface to transfer one char
 * Parameters   : uint8 TxChar - character to tx
 * Returns      : OK
*******************************************************************************/
//LOCAL STATUS uart_tx_one_char(uint8 uart, uint8 TxChar)
STATUS uart_tx_one_char(uint8 uart, uint8 TxChar)
{
    while (true)
    {
      uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<<UART_TXFIFO_CNT_S);
      if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) {
        break;
      }
    }

    WRITE_PERI_REG(UART_FIFO(uart) , TxChar);
    return OK;
}

/******************************************************************************
 * FunctionName : uart1_write_char
 * Description  : Internal used function
 *                Do some special deal while tx char is '\r' or '\n'
 * Parameters   : char c - character to tx
 * Returns      : NONE
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR uart1_write_char(char c)
{
  if (c == '\n')
  {
    uart_tx_one_char(UART1, '\r');
    uart_tx_one_char(UART1, '\n');
  }
  else if (c == '\r')
  {
  }
  else
  {
    uart_tx_one_char(UART1, c);
  }
}
/******************************************************************************
 * FunctionName : uart0_tx_buffer
 * Description  : use uart0 to transfer buffer
 * Parameters   : uint8 *buf - point to send buffer
 *                uint16 len - buffer len
 * Returns      :
*******************************************************************************/
void ICACHE_FLASH_ATTR uart0_tx_buffer(uint8 *buf, uint16 len)
{
  uint16 i;

  for (i = 0; i < len; i++)
  {
    uart_tx_one_char(UART0, buf[i]);
  }
}

/******************************************************************************
 * FunctionName : uart0_tx_buffer
 * Description  : use uart0 to transfer buffer
 * Parameters   : uint8 *buf - point to send buffer
 *                uint16 len - buffer len
 * Returns      :
*******************************************************************************/
void ICACHE_FLASH_ATTR uart1_tx_buffer(uint8 *buf, uint16 len)
{
  uint16 i;

  for (i = 0; i < len; i++)
  {
    uart_tx_one_char(UART1, buf[i]);
  }
}

/******************************************************************************
 * FunctionName : uart0_sendStr
 * Description  : use uart0 to transfer buffer
 * Parameters   : uint8 *buf - point to send buffer
 *                uint16 len - buffer len
 * Returns      :
*******************************************************************************/
void ICACHE_FLASH_ATTR uart0_sendStr(const char *str)
{
   while(*str)
   {
      uart_tx_one_char(UART0, *str++);
   }
}

/******************************************************************************
 * FunctionName : uart0_rx_intr_handler
 * Description  : Internal used function
 *                UART0 interrupt handler, add self handle code inside
 * Parameters   : void *para - point to ETS_UART_INTR_ATTACH's arg
 * Returns      : NONE
*******************************************************************************/
typedef void (*UARTFunctionCallback)(char ByteReceived);
UARTFunctionCallback UARTCallback = NULL;
bool gProcessUART = true;
LOCAL void uart_deinit()
{
   gProcessUART = false;
   ETS_UART_INTR_DISABLE();
}
LOCAL void uart_reinit()
{
   gProcessUART = true;
   ETS_UART_INTR_ENABLE();
}
   
LOCAL void uart0_rx_intr_handler(void * para)
{
   char RcvChar[0];
   os_printf("1");
   //If I remove pRXbuff my program crashes, This may be due to not enough stackspace
   RcvMsgBuff *pRxBuff = (RcvMsgBuff *)para; //This is now a Callback pointer
   os_printf("2");
   if (UART_RXFIFO_FULL_INT_ST != (READ_PERI_REG(UART_INT_ST(UART0)) & UART_RXFIFO_FULL_INT_ST)) {
      return;
   }
   os_printf("3");
   WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR);
   os_printf("4");
   while (READ_PERI_REG(UART_STATUS(UART0)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S))
   {
      ETS_UART_INTR_DISABLE();
      RcvChar[0] = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF;      
      /* you can add your handle code below.*/
      if (para != NULL)
      {   
         os_printf("!");
         UARTCallback = para;
         UARTCallback(RcvChar[0]);
      }
      /*
      gpio_output_set((1 << 2), 0, 0, 0);
      uart0_tx_buffer(RcvChar, 1);
      if (RcvChar[0] == '\n')
      {
         gpio_output_set(0, (1 << 2), 0, 0);
         uart0_sendStr("\r\nGot enter N\r\n");
      }
      if (RcvChar[0] == '\r')
      {
         gpio_output_set(0, (1 << 2), 0, 0);
         uart0_sendStr("\r\nGot enter R\r\n");
      }
      */
       // Clear pending FIFO interrupts
      WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_TOUT_INT_CLR | UART_RXFIFO_FULL_INT_ST);
      if (gProcessUART)
      {
         ETS_UART_INTR_ENABLE();
      }
   }
}

/******************************************************************************
 * FunctionName : uart_init
 * Description  : user interface for init uart
 * Parameters   : UartBautRate uart0_br - uart0 bautrate
 *                UartBautRate uart1_br - uart1 bautrate
 * Returns      : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR uart_init(UartBautRate uart0_br, UartBautRate uart1_br, void * callback)
{
   // rom use 74880 baut_rate, here reinitialize
   UartDev.baut_rate = uart0_br;
   uart_config(UART0, callback);

   UartDev.baut_rate = uart1_br;
   uart_config(UART1, callback);

   ETS_UART_INTR_ENABLE();

   // install uart1 putc callback
   //system_uart_swap(); //http://smallbits.marshall-tribe.net/blog/2016/11/13/esp8266-quiet-uart
   //PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK);
   //os_install_putc1((void *)uart1_write_char);
}

void ICACHE_FLASH_ATTR uart_reattach()
{
   uart_init(BIT_RATE_74880, BIT_RATE_74880, NULL);
//  ETS_UART_INTR_ATTACH(uart_rx_intr_handler_ssc,  &(UartDev.rcv_buff));
//  ETS_UART_INTR_ENABLE();
}

void ICACHE_FLASH_ATTR UART_SetFlowCtrl(uint8 uart_no,UART_HwFlowCtrl flow_ctrl,uint8 rx_thresh)
{
    if(flow_ctrl&USART_HardwareFlowControl_RTS){
        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS);
        SET_PERI_REG_BITS(UART_CONF1(uart_no),UART_RX_FLOW_THRHD,rx_thresh,UART_RX_FLOW_THRHD_S);
        SET_PERI_REG_MASK(UART_CONF1(uart_no), UART_RX_FLOW_EN);
    }else{
        CLEAR_PERI_REG_MASK(UART_CONF1(uart_no), UART_RX_FLOW_EN);
    }
    if(flow_ctrl&USART_HardwareFlowControl_CTS){
        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_UART0_CTS);
        SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_TX_FLOW_EN);
    }else{
        CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_TX_FLOW_EN);
    }
}

void ICACHE_FLASH_ATTR
UART_WaitTxFifoEmpty(uint8 uart_no , uint32 time_out_us) //do not use if tx flow control enabled
{
    uint32 t_s = system_get_time();
    while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S)){

        if(( system_get_time() - t_s )> time_out_us){
            break;
        }
    WRITE_PERI_REG(0X60000914, 0X73);//WTD

    }
}





SoftUart
Code: Select all#ifndef SoftUART_APP_H
#define SoftUART_APP_H

static ICACHE_FLASH_ATTR inline u8 chbit(u8 data, u8 bit)
{
    if ((data & bit) != 0)
    {
       return 1;
    }
    else
    {
       return 0;
    }
}

void ICACHE_FLASH_ATTR sendUART(int GPIO, int command[], int sizeofcmd, long baud) //Did not work
{
   int i=0;
   int ii=0;
   system_soft_wdt_feed();
   
   for (i=0; i<sizeofcmd; i++)
   {
      gpio_output_set(0, (1 << 2), (1 << 2), 0);
      os_delay_us(7);
      for(ii = 0; ii < 8; ii ++ )
      {
         
         if (chbit(command[i],1<<ii))
         {
            gpio_output_set((1 << 2), 0, (1 << 2), 0);            
            //GPIO_OUTPUT_SET((1 << GPIO), chbit('T',1<<i));
            //os_printf("on");
         }         
         else
         {
            gpio_output_set(0, (1 << 2), (1 << 2), 0);
            //GPIO_OUTPUT_SET((1 << GPIO), chbit('T',1<<i));
            //os_printf("off");
         }
         os_delay_us(7);
      }
      gpio_output_set((1 << 2), 0, (1 << 2), 0);
      //os_delay_us(4);
      //system_soft_wdt_feed();
   }
   //os_printf("\r\nSignal sent\r\n");
}

static ICACHE_FLASH_ATTR int soft_uart_putchar_c(int GPIO, unsigned bit_time, char data)
{
   unsigned i;
   unsigned start_time = 0x7FFFFFFF & system_get_time();

   //Start Bit
   gpio_output_set(0, (1 << GPIO), 0, 0); //LOW
   for(i = 0; i <= 8; i ++ )
   {
      while ((0x7FFFFFFF & system_get_time()) < (start_time + (bit_time*(i+1))))
      {
         //If system timer overflow, escape from while loop
         if ((0x7FFFFFFF & system_get_time()) < start_time){break;}
      }
      GPIO_OUTPUT_SET(GPIO_ID_PIN(GPIO), chbit(data,1<<i)); //if GPIO_OUTPUT_SET is all capped it's calling the Macro, if not it's calling a different api
   }

   // Stop bit
   while ((0x7FFFFFFF & system_get_time()) < (start_time + (bit_time*9)))
   {
      //If system timer overflow, escape from while loop
      if ((0x7FFFFFFF & system_get_time()) < start_time){break;}
   }
   gpio_output_set((1 << GPIO), 0, 0, 0);
   // Delay after byte, for new sync
   os_delay_us(bit_time*6);
   return 1;
}

void ICACHE_FLASH_ATTR convert2hex(char buffer[], int length)
{
   long int i=0;
   char itoabuffer[4];

   int s=0;
   for(; s < length; ++s )
   {
      if ((buffer[s] < 32) || (buffer[s] > 126))
      {
         os_printf("\\x");
         os_sprintf(itoabuffer, "%X", buffer[s]);         
         for(i=0; i < strlen(itoabuffer); ++i )
         {
            os_printf("%c", itoabuffer[i]);
         }
      }
      else
      {
         os_printf("%c", buffer[s]);
      }
   }
}

//You can call this with the following line to redirect PrintF after a UART Swap
//os_install_putc1((void *)USBRTS_BAUD115200_write_char); //Redirect OS_PRINTF to GPIO1(TX)
LOCAL void ICACHE_FLASH_ATTR USBRTS_BAUD115200_write_char(char c)
{
   const unsigned bit_time = (1000000 / 115200);
   if (c == '\n')
   {
      soft_uart_putchar_c(1, bit_time, '\r');
      soft_uart_putchar_c(1, bit_time, '\n');
   }
   else if (c == '\r')
   {
   }
   else
   {
      soft_uart_putchar_c(1, bit_time, c);
   }
}
//os_install_putc1((void *)USBRTS_BAUD57600_write_char); //Redirect OS_PRINTF to UART1, our debug port (What is UART1 on Wemos?)
LOCAL void ICACHE_FLASH_ATTR USBRTS_BAUD57600_write_char(char c)
{
   const unsigned bit_time = (1000000 / 57600);
   if (c == '\n')
   {
      soft_uart_putchar_c(1, bit_time, '\r');
      soft_uart_putchar_c(1, bit_time, '\n');
   }
   else if (c == '\r')
   {
   }
   else
   {
      soft_uart_putchar_c(1, bit_time, c);
   }
}

LOCAL void ICACHE_FLASH_ATTR USBRTS_BAUD57600_write_charToHex(char c)
{
   int i=0;
   char itoabuffer[4];
   if (((c < 32) || (c > 126)) && ((c != 10) && (c != 13)))
   {
      //os_printf("\\x");
      USBRTS_BAUD57600_write_char('\\');
      USBRTS_BAUD57600_write_char('x');
      os_sprintf(itoabuffer, "%X", c);         
      for(i=0; i < strlen(itoabuffer); ++i )
      {
         //os_printf("%c", itoabuffer[i]);
         USBRTS_BAUD57600_write_char(itoabuffer[i]);
      }
   }
   else
   {
      //os_printf("%c", c);
      USBRTS_BAUD57600_write_char(c);
   }
}
//os_install_putc1((void *)USBRTS_BAUD9600_write_char); //Redirect OS_PRINTF to GPIO1(TX)
LOCAL void ICACHE_FLASH_ATTR USBRTS_BAUD9600_write_char(char c)
{
   const unsigned bit_time = (1000000 / 9600);
   if (c == '\n')
   {
      soft_uart_putchar_c(1, bit_time, '\r');
      soft_uart_putchar_c(1, bit_time, '\n');
   }
   else if (c == '\r')
   {
   }
   else
   {
      soft_uart_putchar_c(1, bit_time, c);
   }
}

int ICACHE_FLASH_ATTR softuart_write(int GPIO, const char* data, unsigned len, long baudrate )
{
    //const unsigned baudrate = 57600; //Highest I've been able to go is 57600 Baud, 115200 misses some but 74880 misses alot
    const unsigned bit_time = (1000000 / baudrate);

    gpio_output_set((1 << GPIO), 0, 0, 0); //High
    os_delay_us(bit_time*8);
    int s=0;
    for(; s < len; ++s )
    {
        soft_uart_putchar_c(GPIO, bit_time, data[ s ]);
    }
    return 0;
}
#endif


Main Usercode that uses three UARTS, Two Hardware and one Software.

Code: Select all//https://www.mikrocontroller.net/attachment/263828/The-ESP8266-Book-August-2015.pdf
#include "ets_sys.h"
#include "osapi.h"
#include "gpio.h"
#include "os_type.h"
#include "ip_addr.h"
#include "mem.h"
#include "user_interface.h"
#include "lwip/stats.h"
#include "espconn.h"

#include "c_types.h" ////ONE WIRE

#include "../library/uart.h" //Copy these from your Driver Lib to your local folder
#include "../library/gpio16.h" //Copy these from your Driver Lib to your local folder

#include "../library/softuart.h" //Uses USB-COM on GPIO1(TX) for wemos d1 mini pro
#include "../library/common.h"

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

#define user_procTaskPrio        0
#define user_procTaskQueueLen    1
os_event_t user_procTaskQueue[user_procTaskQueueLen];

void uart0_tx_buffer(uint8 *buf, uint16 len);

char rxbuff[31];
char rxindex = 0;

void UartReceive(char ByteReceived)
{
   os_printf("[%s] Got UART Callback!\r\n", __func__);
   os_printf("Byte Recevied: %c\r\n", ByteReceived);

   rxbuff[rxindex++] = ByteReceived;
   if (rxindex == sizeof(rxbuff))
   {
      rxindex = 0;
   }
   else
   {
      os_printf("%d != %d\r\n", rxindex, sizeof(rxbuff));
   }
   os_printf("Buffer: %s\r\n", rxbuff);

   hex_printf(rxbuff,rxindex);
   return;
}

void ICACHE_FLASH_ATTR sdk_init_done_cb(void)
{
   os_printf("[%s] initializing ESP8266!\n", __func__);
   PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_GPIO1); //Set GPIO1(TX) as a manual GPIO Pin
   gpio_output_set((1 << 1), 0, (1 << 1), 0); //Set Pin as an OUT and Set it High for idle ready state
   while(true)
   {
      os_printf("This is a test from PrintF\xff\xff\xff\r\n");
      uart0_tx_buffer("UART0\xff\xff\xff\r\n", 9); //This is our Prod Port, RX uses D7 and D8 instead of the TX port after system_uart_swap() is called
      //uart1_tx_buffer("UART1\xff\xff\xff\r\n", 9); //This is our D4 Port
      uart1_tx_buffer("\x7E\xFF\x06\x09\x00\x00\x02\xEF", 8); //Select storage device to TF card 7E FF 06 09 00 00 02 EF
      uart1_tx_buffer("\x7E\xFF\x06\x03\x00\x00\x01\xEF", 8); //Play MP3 Song
      uart1_tx_buffer("\x7E\xFF\x06\x06\x00\x00\x1E\xEF", 8); //Max volume
      os_printf("Done!");
      return;
      softuart_write(1, "This is a test from SoftUART\xff\xff\xff\r\n", 20, 57600); //This is our USB-COM Port
      delay_second();
      delay_second();
   }
}

void ICACHE_FLASH_ATTR SetupUART(void)
{
   //Careful when the callback is triggered that it does not kick off any premature events like sending network packets before the network is connected, thus crashing your app
   //uart_init(BIT_RATE_57600, BIT_RATE_9600, &UartReceive); //This only seems to be kicked off via the COM-USB onboard & D4 Port, Not the TX/RX port
   uart_init(BIT_RATE_57600, BIT_RATE_9600, &UartReceive); //This only seems to be kicked off via the COM-USB onboard & D4 Port, Not the TX/RX port
   system_set_os_print(1); //Turns os_PrintF Log Printing On or Off
   //We use UART swap because the RXpin is always High from external outputs causing issues when loading new firmware.
   //Keep in mind uart swap only swaps the RTS and CTS of the same UART to the RX and TX of the same UART, NOT UART1 to UART0
   //"UART0 swap. Use MTCK as UART0 Rx, MTDO as UART0 Tx, so ROM log will not output from this new UART0. MTDO (U0RTS) and MTCK (U0CTS) also need to be used as UART0 in hardware
   system_uart_swap(); //http://smallbits.marshall-tribe.net/blog/2016/11/13/esp8266-quiet-uart - Makes D7 RX (MTCK) and D8 TX (MTDO)

   //Pick here where you want PrintF to output
   //os_install_putc1((void *)uart1_write_char); //Redirect OS_PRINTF to UART1 (D4)
   //os_install_putc1((void *)USBRTS_BAUD57600_write_char); //Redirect OS_PRINTF to USBCOMM, our debug port
   os_install_putc1((void *)USBRTS_BAUD57600_write_charToHex); //Redirect OS_PRINTF to USBCOMM, our debug port Plus converting nonreadable to hex
}

void ICACHE_FLASH_ATTR user_init()
{
   
   SetupUART();

   system_init_done_cb(sdk_init_done_cb);

   wifi_set_opmode(0);
   wifi_set_sleep_type( NONE_SLEEP_T );

   ETS_GPIO_INTR_DISABLE();// Disable gpio interrupts
   gpio_init();   

   SetAllGPIOPinsAsOutput();

   /* Need to fix this to display value   */
   /* Need to fix this to display value   */
   uint32 VDDADCByte[4] = {0};
   spi_flash_read(0x3fc06b, (uint32 *)&VDDADCByte, 1); //Read pads the other 3 bytes with FF

   if (system_get_userbin_addr() == 0x0)
   {
      os_printf("\r\n\r\nStarting ESP8266!\r\nSDK version:%s\r\nLoaded from: 0x%02x\r\nVdd33_Const: %02x\r\n", system_get_sdk_version(), system_get_userbin_addr(), (VDDADCByte[0] & 0xff));
   }
   else
   {
      os_printf("\r\n\r\nStarting ESP8266 FOTA!\r\nSDK version:%s\r\nLoaded from: 0x%02x\r\nVdd33_Const: %02x\r\n", system_get_sdk_version(), system_get_userbin_addr(), (VDDADCByte[0] & 0xff));
   }

   //Turn off LED, We cannot touch this pin as this is our debug pin D4/GPIO2
   //PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
   //gpio_output_set((1 << 2), 0, 0, 0);

   //Start os task
   system_init_done_cb(sdk_init_done_cb);
   //system_os_task(loop, user_procTaskPrio, user_procTaskQueue, user_procTaskQueueLen); //Task to Signal for later
}
User avatar
By Agentsmithers
#89512
YRabbit wrote:Thank you! :)


Your welcome, let me know if anything pops up. its been a bit but I still recall a good chuck of the code experience. I was able to get three UARTS out (I think 1 in, maybe 2 in's) at once using that code.