Как стать автором
Обновить

Комментарии 64

как впихнуть невпихуемое и отобразить в реальном времени трехмерную графику при помощи контроллера, у которого недостаточно ни скорости, ни памяти для этого.

Это громко сказано… про недостаточность памяти и скорости. Если сравнить со "спектрум" Z80.
Игрушки были приличные.

Не воспринимайте излишне серьезно. Будь у контроллера объективно недостаточно ресурсов, это и сделать было бы невозможно.
А на счет Спектрума — мне казалось, у него все-таки была какая-то аппаратная видеокарта. Да и вообще специфика разная.

У Спектрума аппаратная часть на рассыпухе "отображала" часть ОЗУ в видеосигналы (если упрощенно).
С учетом того, что ili9341 это то же память + аппаратная часть, а запись через SPI + DMA в ОЗУ ili9341, в общем то, сравнима с прямой записью в ОЗУ на типичных 8Мгц Z80…
Те же яйца, только вид сбоку.


И я не принял серьезно :) Вот если бы на AVR 8 битовом… что гораздо ближе к Спектруму по быстродействию и памяти.

>Вот если бы на AVR 8 битовом… что гораздо ближе к Спектруму по быстродействию и памяти.

Так-то AVR8, без зазрения совести:
ЭМУЛИРУЕТ Спектрум!


Ну и сравнивать RISC с z80…
Там, помнится, было два AVR. Один — эмуляция Z80, а второй эмуляция периферии.
Видео на втором, все остальное на первом.
И для звука еще один мелкий вроде.
Нет, у спектрума нет вообще ничего для аппаратного ускорения. Но весь экран 6144 байта (чёрно-белый)+768 байт атрибуты цветов.
Не было ли желания замахнуться на реализацию реймаршера на таком аппарате?
Нет. Эта поделка — разовая, она не для какой-то цели или отработки алгоритма для дальнейшего применения. Просто было интересно что можно выжать, и то без фанатизма. Изучать другие низкоуровневые алгоритмы вывода изображений на примере stm-ки смысла нет: мощность невелика, а все оптимизации будут жестко завязаны на ее же специфику.
Ну, многие трюки показались небезынтересными в плане ускорения вычислений. Я иногда пробую всякие волюнтаристские штуки, вроде приравнивания числа пи четырём и возведения в половинную степень вместо извлечения корня.
и возведения в половинную степень вместо извлечения корня

Это разные записи одной и той же операции

Так-то да. Только скорость выполнения разная.

А есть бенчмарки?
Я сильно сомневаюсь, что более универсальная функция pow() оптимизирована лучше специализированной sqrt(). Тем более, что последняя на многих платформах реализована аппаратно.
Если уж говорить про "грязную скорость" sqrt() (вернее 1/sqrt(), что более востребовано), то вспоминать нужно про 0x5f3759df

Эта квейковская загогулина работает не только лишь везде, а вообще мало где. Она расчитана под чистый, незамутнённый 32-битный float, и ни на что больше. Бенчмарки надо разумеется писать. Вполне может оказаться, что для ваших случаев функция отработает быстрее арифметического оператора возведения в степень "^", который я использовал вместо math.pow(). В моих поделиях оператор отработал даже быстрее переопределённой функции local pow = math.pow
Заодно вопхну сюда ответ на вопрос про число PI, поскольку набежавшие в срачик про мед. маски «специалисты по всем вопросам» подслили карму и писать комменты получается теперь не чаще раза в час.
PI=4
image

PI=3
image

PI=8
image

PI=3.1
image

Эта квейковская загогулина работает не только лишь везде, а вообще мало где. Она расчитана под чистый, незамутнённый 32-битный float, и ни на что больше

Именно поэтому это грязный хак изящная чертова магия.
В принципе подобную магию можно сотворить и под float64, но особого смысла это не имеет, т.к. метод дает приближенное значение обратного корня и точности float32 более чем достаточно.


Бенчмарки надо разумеется писать

раз вы утверждаете, что a быстрее b, то либо вы бенчмарки писали/проводили, либо ваше утверждение голословно


оператора возведения в степень "^", который я использовал вместо math.pow()

я не знаю, про какой именно язык программирования вы говорите, но в любом случае бинарный оператор это просто сахар для вызова функции/метода.

я не знаю, про какой именно язык программирования вы говорите, но в любом случае бинарный оператор это просто сахар для вызова функции/метода.

Я там опечатался в ответе. Не math.pow() имелось в виду, а math.sqrt(), по сравнению с оператором "^". Ну, немного подредактировав бенчмарки, можно сравнить например «math.pow(a)» c «a*a» и с «a^2». Касательно квадратного корня получилось вот так:
Бенчмарки
local a = os.clock()
local b = 0.0
for i = 1, 100000000 do
	b = math.sqrt(35.73)
end
a = os.clock() - a
print (a)

lua ./sqrt_lua.lua
14.738681
luajit ./sqrt_lua.lua
0.073986

local sqrt = math.sqrt
local a = os.clock()
local b = 0.0
for i = 1, 100000000 do
	b = sqrt(35.73)
end
a = os.clock() - a
print (a)

lua ./local_sqrt_lua.lua
9.867505
luajit ./local_sqrt_lua.lua
0.073703

local a = os.clock()
local b = 0.0
for i = 1, 100000000 do
	b = 35.73^0.5
end
a = os.clock() - a
print (a)

lua ./test_operator.lua
2.276411
luajit ./test_operator.lua
0.073202

Это прекрасно во всем: и использование lua для теста числодробильни и надежда на то, что 35.73^0.5 вычисляется более одного раза при интерпретации (и хотябы один раз в скомпилированном коде).


замените код вашего бенчмарка хотябы на


local a = os.clock()
local b = 100.0
for i = 1, 100000000 do
    b = math.sqrt(b)*10.0
end
a = os.clock() - a
print (a)

local a = os.clock()
local b = 100.0
for i = 1, 100000000 do
    b = (b^0.5)*10.0
end
a = os.clock() - a
print (a)

и поделитесь результатом )

Забавно. В luajit все три варианта показали примерно одинаковую скорость. А вот в lua, как таковом, внезапно быстрее оказалась локально объявленная функция.
luajit все три варианта показали примерно одинаковую скорость

Вы не догадываетесь, почему?
Скорее всего ситуацию поменяет банальный print(b) в самом конце программы (даже после print(a)). Если же компилятор уапще умный, то добавьте ввод b, как параметра командной строки

Судя по всему, вы хорошо знакомы с lua. :) Не подскажете ли вы мне такую штуку? Вот я взял модуль NodeMCU с lua-прошивкой. Открыл книжку по lua. И решил накатать преобразователь uart<->wifi. И возникли вопросы:
1) Как в lua из массива чисел (иногда с части элементов массива, идущих подряд) сделать строку из их символьных представлений? Сейчас я прогоняю циклом и каждый раз прибавляю к строке один символ, полученный через string.char от элемента массива (как-то так функция называется — пишу по памяти, так как прошивка на другом компьютере). Память кушает хорошо. Это нужно потому, что функции передачи данных работают почему-то со строками. А у меня массив байт.
2) Можно ли создать массив не задавая его элементы в цикле? А то приходится for n=1,1000,1 do a[n]=0 end делать. Как-то это не очень красиво. Память массивы тоже кушают отлично… А постоянно расширять массив a[#a+1]=byte не вариант по скорости. Я теперь сразу выделяю кусок под принятые данные в размер максимального пакета.
3) Если вы работали с модулем esp8266, то вызывает удивление передача на сервер данных через conn:send. Секундная задержка между вызовом функции send (я передаю где-то по 450 байт за раз) и вызовом функции обратного вызова, подтверждающей приём — это как-то странно. На прошивке с AT-командами такого не было (там сама прошивка вешалась периодически). Я догадываюсь, что дело может быть в том, что модуль ждёт не наберётся ли полный пакет, но как бы это отключить (такое я видел, например, в сокетном API QNX) и инициировать передачу сразу же. Или есть какой-то другой способ передачи без задержек из lua (в AT-прошивке как-то же это сделано)?
Спасибо.
Судя по всему, вы хорошо знакомы с lua

В основном на уровне написания скриптиков для openwrt. Python что-то более серьезное там развернуть ресурсов маловато, а писать на баше у меня борода недостаточно густая. На вопросы попробую ответить, но порядок придется нарушить.


2) Можно ли создать массив не задавая его элементы в цикле?

В Lua в принципе нельзя создать массив (в понимании C). Нет там такого типа данных. Есть ассоциативные массивы (tables), т.е. хранилища пар ключ(любого типа) — значение(любого типа). Если в качестве ключа вы будете использовать number, то получите типа массив. Но это не будут последовательно расположенные в памяти элементы. оверхэд такого решения вы почувствовали и сами. Инициализируете вы такой "массив" правильно.


1) Как в lua из массива чисел (иногда с части элементов массива, идущих подряд) сделать строку из их символьных представлений?

Как вы понимаете, раз нет никаких массивов, то нет и никакого 'подряд', поэтому и строку вы получаете правильно.


3) Если вы работали с модулем esp8266

Если речь про NodeMCU, то нет


ps:
Вышесказанное относилось к 'прикладному' Lua. Используя функции Lua C API, предназначенные для манипуляции с данными получаемыми/передаваемыми из внешних библиотек, теоретически возможно все это серьезно заоптимизировать. Но это (на мой взгляд) подобно сексу в гамаке стоя. Ибо зачем так извращаться, когда можно просто написать нужное на C/C++. Под ту же ESP есть ряд фреймворков, в том числе с низким порогом входа. Та же Arduino.

Спасибо за информацию!
Что касается С++ для ESP, то что-то я подозреваю, что запуск TCP и WIFI не будут простыми. Впрочем, надо посмотреть. :)

О, специалист по оптимизации подтянулся.


Поковыряйте Luajit с FFI

А что, на встроенную в NodeMCU Lua завезли Luajit ?


Цикл можно ускорить при помощи простого трюка

И как же в данном случае разворачивание цикла его ускорит ?

Откуда же мне знать-то? Моё дело — набросить. Да и захардкодить если массив a ={0,… 0,} и потом require або dofile его, тоже наверно всё зря. Или использовать local. Или всё сразу. Но лучше наверно не надо.

Сложность работы в первую очередь не от языка зависит, а от используемого фреймворка. Это не синонимы. Если писать на C, используя espressif sdk — будет не очень легко, если использовать arduino, то весь пример "мост tcp-serial" https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/examples/WiFiTelnetToSerial/WiFiTelnetToSerial.ino по мне выглядит проще, чем заняться с творческой перепаковкой данных на lua.

Если писать на C, используя espressif sdk — будет не очень легко


Я, собственно, это и имею в виду. :) Если в SDK есть компоненты достаточно высокоуровневой сокетной библиотеки, то всё будет просто. А вот если нет…

по мне выглядит проще, чем заняться с творческой перепаковкой данных на lua.


Так я не использую Arduino. :) А простое соединение я сделал и так, но меня не устроила скорость работы в lua функции send.

Впрочем, пример мигания на Си у меня откомпилировался и заработал. :)

А на lua я такое написал пока что:
Программа на lua
--****************************************************************************************************
--глобальные переменные
--****************************************************************************************************
ReceivedArray={}--принятые байты данных
ReceivedArraySize=0;--количество принятых данных
StuffingOn=false--включёна ли замена байт

BEGIN_PACKAGE=0xff--начало пакета
END_PACKAGE=0x00--конец пакета
STUFFING_ON=0xfe--включение стаффинга
MAX_RECEIVED_ARRAY=512--максимальный размер принятого пакета с данными
SCK=nil

--****************************************************************************************************
--функции
--****************************************************************************************************

------------------------------------------------------------------------------------------------------
--произошло подключение к серверу
------------------------------------------------------------------------------------------------------
function OnConnect(sck,c)
 SCK=sck
 local answer={string.byte("C",1),string.byte("O",1)}
 UARTTransmitt(answer)
end
------------------------------------------------------------------------------------------------------
--произошло отключение от сервера
------------------------------------------------------------------------------------------------------
function OnDisconnect(sck,c)
 SCK=nil
 local answer={string.byte("D",1),string.byte("O",1)}
 UARTTransmitt(answer)  
end
------------------------------------------------------------------------------------------------------
--завершена передача данных
------------------------------------------------------------------------------------------------------
function OnSend(sck,c)
 local answer={string.byte("S",1),string.byte("O",1)}
 UARTTransmitt(answer)
end
------------------------------------------------------------------------------------------------------
--получены данные
------------------------------------------------------------------------------------------------------
function OnReceive(sck,c)
end
------------------------------------------------------------------------------------------------------
--настройка UART
------------------------------------------------------------------------------------------------------
function UARTSetting()
 uart.setup(0,115200*8,8,0,1,0)
 uart.on("data",1,UARTReceive,0) 
end
------------------------------------------------------------------------------------------------------
--передача данных по UART с заменой байт
------------------------------------------------------------------------------------------------------
function UARTTransmitt(data)  
 local length=#data
 local send=""
 send=send..string.char(BEGIN_PACKAGE)
 for n=1,length,1 do
  local byte=data[n]
  if (byte==BEGIN_PACKAGE or byte==END_PACKAGE or byte==STUFFING_ON) then
   send=send..string.char(STUFFING_ON)   
  end
  send=send..string.char(byte)
 end
 send=send..string.char(END_PACKAGE)
 uart.write(0,send) 
 send=nil
 collectgarbage()
end

------------------------------------------------------------------------------------------------------
--анализ полученной команды
------------------------------------------------------------------------------------------------------
function ExecuteCommand() 
 local command=ReceivedArray[1]
 if (command==string.byte("C",1)) then--Connect
  if (SCK~=nil) then
   local answer={command,string.byte("O",1)}--уже подключено
   UARTTransmitt(answer)
   return
  end
  local port=ReceivedArray[2]+ReceivedArray[3]*256;
  local ip=string.format("%i.%i.%i.%i",ReceivedArray[4],ReceivedArray[5],ReceivedArray[6],ReceivedArray[7]);      
  conn=net.createConnection(net.TCP,0)
  conn:on("connection",OnConnect)
  conn:on("receive",OnReceive)
  conn:on("disconnection",OnDisconnect)
  conn:on("sent",OnSend)
  conn:connect(port,ip)
  return
 end
 if (command==string.byte("D",1)) then--Disconnect
  if (SCK==nil) then
   local answer={command,string.byte("E",1)}
   UARTTransmitt(answer)
   return
  end
  SCK:close()
  SCK=nil
  collectgarbage()
  local answer={command,string.byte("O",1)}
  UARTTransmitt(answer)
  return
 end
 
 if (command==string.byte("S",1)) then--Send
  if (SCK==nil) then
   local answer={command,string.byte("E",1)}
   UARTTransmitt(answer)
   return
  end
  --for n=2,ReceivedArraySize,1 do
  --SCK:send(string.char(ReceivedArray[n]))   
  --end
  local send=""
  for n=2,ReceivedArraySize,1 do
   send=send..string.char(ReceivedArray[n])
  end
  SCK:send(send)
  send=nil
  collectgarbage()
  return
 end  
  if (command==string.byte("T",1)) then--Test
   local answer={command,string.byte("O",1)}
   UARTTransmitt(answer)
 end
end

------------------------------------------------------------------------------------------------------
--получение данных с UART
------------------------------------------------------------------------------------------------------
function UARTReceive(data)
 --используем протокол с байтстаффингом
 if (ReceivedArraySize>MAX_RECEIVED_ARRAY) then--начинаем приём заново при превышении размера массива
  ReceivedArraySize=0
  StuffingOn=false
 end
  
 local byte=string.byte(data,1) 
 if (StuffingOn==false) then
  if (byte==BEGIN_PACKAGE) then--начало приёма
   ReceivedArraySize=0
   return
  end
  if (byte==END_PACKAGE) then--конец приёма
   if (ReceivedArraySize>0) then
    ExecuteCommand()
   end 
   ReceivedArraySize=0
   return
  end
  if (byte==STUFFING_ON) then--включение замены байт
   StuffingOn=true
   return
  end
  ReceivedArray[ReceivedArraySize+1]=byte
  ReceivedArraySize=ReceivedArraySize+1
  return
 end
 --замена байт включена
 StuffingOn=false
 --если принят неизвестный код, начинаем приём заново
 if (byte~=BEGIN_PACKAGE) and (byte~=END_PACKAGE) and (byte~=STUFFING_ON) then
  ReceivedArraySize=0
  return
 end 
 ReceivedArray[ReceivedArraySize+1]=byte
 ReceivedArraySize=ReceivedArraySize+1
end

------------------------------------------------------------------------------------------------------
--вывод полученного IP-адреса
------------------------------------------------------------------------------------------------------
function ShowIP(params)
 print("My IP is " .. params.IP) 
end
------------------------------------------------------------------------------------------------------
--вывод списка найденных сетей
------------------------------------------------------------------------------------------------------
function ShowWiFiNet(table)
 for ssid,v in pairs(table) do
  authmode,rssi,bssid,channel=string.match(v,"(%d),(-?%d+),(%x%x:%x%x:%x%x:%x%x:%x%x:%x%x),(%d+)")
  print(ssid,authmode,rssi,bssid,channel)  
 end
end

------------------------------------------------------------------------------------------------------
--произведено подключение к роутеру
------------------------------------------------------------------------------------------------------
function RouterConnect(params)
 ShowIP(params)
 wifi.sta.getap(ShowWiFiNet)
 UARTSetting()
end

--****************************************************************************************************
--начало программы
--****************************************************************************************************
tmr.softwd(-1)
tmr.wdclr()
--создаём массив принятых данных
for n=1,MAX_RECEIVED_ARRAY,1 do
 ReceivedArray[n]=0
end
ReceivedArraySize=0

local heap_size=node.heap()
print(" Free memory:",heap_size,"\r\n")

wifi.setmode(wifi.STATION)
station_cfg={}
station_cfg.ssid="FPV_WIFI__D49A"
station_cfg.pwd=""
station_cfg.save=false
station_cfg.got_ip_cb=RouterConnect
wifi.sta.config(station_cfg)
--local heap_size=node.heap()
--print("ReceivedArray:",#ReceivedArray," Free:",heap_size,"\r\n")


Но поскольку я использую си++ и компилятор для esp8266 запустился, то я на си++ дальше и попробую сделать прошивку. :) А lua останется так, как рудимент.
Так я не использую Arduino

По религиозным соображениям?
На всякий случай уточню — под arduino я имел в виду не отдельную плату (на AVR), к которой подключается ESP, а ESP8266 Arduino core. Где есть все обертки над espressif SDK в привычной ардуинщикам форме + возможность использовать кучу библиотек для разной периферии.
Да, конечно, используя голый SDK теоретически можно делать интереснее и лучше. Но подозреваю, что практически это будет наполнено существенно большей болью.

По религиозным соображениям?


Потому что, обычно, могу позволить себе не использовать. :)

ESP8266 Arduino core.


Спасибо, гляну, что там внутри.

Да, конечно, используя голый SDK теоретически можно делать интереснее и лучше. Но подозреваю, что практически это будет наполнено существенно большей болью.


Пока не знаю — ещё не смотрел SDK.
Всё, разобрался с wi-fi и uart из Си для ESP8266. Ничего сложного, благо примеры в инете есть. Правда, там для UDP, а у меня TCP — но там просто немного меняется логика и вместо create ставится connect. Ну и нужно оформить callback для события connect и в нём уже можно начать передавать. Теперь надо мешанину кода переделать в нормальный красивый вид и можно использовать. :)
Всё, получилось полностью требуемое на Си. Скорость возросла колоссально (мне надо было примерно пол-мегабайта передавать на сервер раз в минуту). :) Впрочем, может быть, дело было в том, что нужно было отключить энергосберегающий режим WiFi. Потом проверю эту гипотезу. Но на Си всё гораздо приятнее работает, это да. :)

С энергосберегающим режимом очень правдоподобная гипотеза. При отправке первого пакета. И второго, если он отправляется через продолжительное время. Но отправка полмегабайта в минуту — явно не тот случай. Да и на памятежор, как вы понимаете, powersave влиять не может.
Рад, что у вас получилось.

Выложу-ка я тут предварительный код. Вдруг кому пригодится — например, поиском сюда попадёт. Я так часто натыкался на форумах на вопрос и ответ через некоторое время «спасибо, всё решилось». А как решилось, не написано. На github выкладывать не буду, чтобы не засорять свои репозитории.

Этот код подключается по WiFi к роутеру и по командам по UART соединяется/отключается с заданным сервером и передаёт данные. А вот приём ответа от сервера мне не нужен — я событие вывел, но по UART обратно данные не отправляю.

user_main.с
//****************************************************************************************************
//подключаемые библиотеки
//****************************************************************************************************
#include <stdio.h>
#include <string.h>

#include <osapi.h>
#include <os_type.h>
#include <uart.h>
//#include <mem.h>
#include <ip_addr.h>
#include <espconn.h>

#include "user_interface.h"
#include "led.h"
#include "uart.h"

//****************************************************************************************************
//макроопределения
//****************************************************************************************************

#define WIFI_CLIENTSSID   "name"
#define WIFI_CLIENTPASSWORD "password"


//максимальный размер принятого пакета с данными
#define MAX_RECEIVED_ARRAY 512
//максимальный размер передаваемого пакета с данными
#define MAX_TRANSMITT_ARRAY 512

//****************************************************************************************************
//перечисления
//****************************************************************************************************

typedef enum
{
 WIFI_STATE_CONNECTING,//WiFi подключается к роутеру
 WIFI_STATE_CONNECTING_ERROR,//ошибка подключения WiFi к роутеру
 WIFI_STATE_CONNECTED,//WiFi подключён к роутеру
 WIFI_STATE_TCP_CONNECTED//установлено TCP-соединение
} WIFI_STATE;

//****************************************************************************************************
//константы
//****************************************************************************************************

static const uint8_t BEGIN_PACKAGE=0xff;//начало пакета
static const uint8_t END_PACKAGE=0x00;//конец пакета
static const uint8_t STUFFING_ON=0xfe;//включение замены байт

//****************************************************************************************************
//глобальные переменные
//****************************************************************************************************
static uint8_t ReceivedArray[MAX_RECEIVED_ARRAY];//принятые байты данных
static uint8_t TransmittArray[MAX_TRANSMITT_ARRAY];//буфер данных для отправки
static size_t ReceivedArraySize=0;//количество принятых данных
static bool StuffingOn=false;//включёна ли замена байт

static WIFI_STATE WiFi_State=WIFI_STATE_CONNECTING;
static os_timer_t WiFi_CheckIPTimer;//таймер проверки IP сети WiFi
static struct espconn ESPConnection;
static esp_tcp ESPConnectionTCP;

//****************************************************************************************************
//прототипы функций
//****************************************************************************************************

static void ICACHE_FLASH_ATTR UART_Transmitt(const uint8_t *data,size_t size);//отправить по UART данные с заменой байт
static void ICACHE_FLASH_ATTR UART_TransmittMessage(const char *str);//передать по UART текствовое сообщение с заменой байт
static void ICACHE_FLASH_ATTR UART_ExecuteCommand(const uint8_t *command_ptr,size_t size);//выполнение команды, пришедшей по UART
static void ICACHE_FLASH_ATTR UART_PushByte(uint8_t byte);//разбор принятых данных по UART
static void UART_OnReceived(const uint8_t *data,size_t size);//пришли новые данные по UART
static void UART_OnSendDone(void);//UART закончил передачу данных

static void ICACHE_FLASH_ATTR WiFi_StopTimer(void);//отключить проверку WiFi
static void ICACHE_FLASH_ATTR WiFi_StartTimer(size_t interval_ms);//запустить таймер проверки WiFi
static void ICACHE_FLASH_ATTR WiFi_OnSendDone(void* arg);//завершена передача данных по TCP
static void ICACHE_FLASH_ATTR WiFi_OnReceived(void* arg, char* pusrdata, uint16_t length);//пришли данные по TCP
static void ICACHE_FLASH_ATTR WiFi_OnConnectedTCP(void* arg);//произведено подключение по TCP
static void ICACHE_FLASH_ATTR WiFi_OnDisconnectedTCP(void* arg);//произведено отключение по TCP
static void ICACHE_FLASH_ATTR WiFi_CheckIP(void *arg);//периодическая проверка IP

//****************************************************************************************************
//реализация функций
//****************************************************************************************************

//----------------------------------------------------------------------------------------------------
//реализация системной функции, необходимой SDK
//----------------------------------------------------------------------------------------------------
uint32 ICACHE_FLASH_ATTR user_rf_cal_sector_set(void)
{
 enum flash_size_map size_map=system_get_flash_size_map();
 uint32 rf_cal_sec=0;

 switch(size_map)
 {
  case FLASH_SIZE_4M_MAP_256_256:
   rf_cal_sec=128-8;
   break;
  case FLASH_SIZE_8M_MAP_512_512:
   rf_cal_sec=256-5;
   break;
  case FLASH_SIZE_16M_MAP_512_512:
  case FLASH_SIZE_16M_MAP_1024_1024:
   rf_cal_sec=512-5;
   break;
  case FLASH_SIZE_32M_MAP_512_512:
  case FLASH_SIZE_32M_MAP_1024_1024:
   rf_cal_sec=1024-5;
   break;
  default:
   rf_cal_sec=0;
   break;
 }
 return(rf_cal_sec);
}

//----------------------------------------------------------------------------------------------------
//отправить по UART данные с заменой байт
//----------------------------------------------------------------------------------------------------
static void ICACHE_FLASH_ATTR UART_Transmitt(const uint8_t *data,size_t size)
{
 size_t transmitt_size=0;
 size_t n;
 TransmittArray[transmitt_size]=BEGIN_PACKAGE;
 transmitt_size++;
 for(n=0;n<size;n++)
 {
  uint8_t byte=data[n];
  if (byte==BEGIN_PACKAGE || byte==END_PACKAGE || byte==STUFFING_ON)
  {
   TransmittArray[transmitt_size]=STUFFING_ON;
   if (transmitt_size+3>MAX_TRANSMITT_ARRAY) break;
   transmitt_size++;
  }
  TransmittArray[transmitt_size]=byte;
  if (transmitt_size+2>MAX_TRANSMITT_ARRAY) break;
  transmitt_size++;
 }
 TransmittArray[transmitt_size]=END_PACKAGE;
 transmitt_size++;

 UART_SendData(TransmittArray,transmitt_size);
}
//----------------------------------------------------------------------------------------------------
//передать по UART текствовое сообщение с заменой байт
//----------------------------------------------------------------------------------------------------
static void ICACHE_FLASH_ATTR UART_TransmittMessage(const char *str)
{
 UART_Transmitt((uint8_t*)str,strlen(str));
}
//----------------------------------------------------------------------------------------------------
//отключить проверку WiFi
//----------------------------------------------------------------------------------------------------
static void ICACHE_FLASH_ATTR WiFi_StopTimer(void)
{
 os_timer_disarm(&WiFi_CheckIPTimer);
}
//----------------------------------------------------------------------------------------------------
//запустить таймер проверки WiFi
//----------------------------------------------------------------------------------------------------
static void ICACHE_FLASH_ATTR WiFi_StartTimer(size_t interval_ms)
{
 os_timer_setfn(&WiFi_CheckIPTimer,(os_timer_func_t *)WiFi_CheckIP,NULL);
 os_timer_arm(&WiFi_CheckIPTimer,interval_ms,0);
}
//------------------------------------------------------
//завершена передача данных по TCP
//------------------------------------------------------
static void ICACHE_FLASH_ATTR WiFi_OnSendDone(void* arg)
{
 UART_TransmittMessage("SO");
}
//------------------------------------------------------
//пришли данные по TCP
//------------------------------------------------------
static void ICACHE_FLASH_ATTR WiFi_OnReceived(void* arg, char* pusrdata, uint16_t length)
{
}
//------------------------------------------------------
//произведено подключение по TCP
//------------------------------------------------------
static void ICACHE_FLASH_ATTR WiFi_OnConnectedTCP(void* arg)
{
 UART_TransmittMessage("CO");
 UART_SendMessage("TCP connected\r\n");
 WiFi_State=WIFI_STATE_TCP_CONNECTED;
}
//------------------------------------------------------
//произведено отключение по TCP
//------------------------------------------------------
static void ICACHE_FLASH_ATTR WiFi_OnDisconnectedTCP(void* arg)
{
 UART_TransmittMessage("DO");
 WiFi_State=WIFI_STATE_CONNECTED;
}

//----------------------------------------------------------------------------------------------------
//выполнение команды, пришедшей по UART
//----------------------------------------------------------------------------------------------------
static void ICACHE_FLASH_ATTR UART_ExecuteCommand(const uint8_t *command_ptr,size_t size)
{
 if (size==7)
 {
  if (command_ptr[0]=='C')//подключение к серверу
  {
   if (WiFi_State==WIFI_STATE_TCP_CONNECTED)//соединение уже было произведено
   {
    UART_TransmittMessage("CO");
    return;
   }
   if (WiFi_State!=WIFI_STATE_CONNECTED)//нет соединения с роутером
   {
    UART_TransmittMessage("CE");
    return;
   }
   //подключаемся к серверу
   WiFi_StopTimer();

   ESPConnection.proto.tcp=&ESPConnectionTCP;
   ESPConnection.type=ESPCONN_TCP;
   ESPConnection.state=ESPCONN_NONE;

   uint16_t port=command_ptr[2];
   port<<=8;
   port|=command_ptr[1];
   uint8_t ip_str[4*4+1];//4 раза 4 символа (3 цифры с точкой) и завершающий ноль
   os_sprintf(ip_str,"%i.%i.%i.%i",command_ptr[3],command_ptr[4],command_ptr[5],command_ptr[6]);
   UART_SendMessage("Connected:");
   UART_SendMessage(ip_str);
   UART_SendMessage("\r\n");
   uint32_t ip=ipaddr_addr(ip_str);

   os_memcpy(ESPConnection.proto.tcp->remote_ip,&ip,sizeof(uint32_t));
   ESPConnection.proto.tcp->local_port=espconn_port();
   ESPConnection.proto.tcp->remote_port=port;
   //espconn_create(&pConn);

   espconn_regist_sentcb(&ESPConnection,WiFi_OnSendDone);
   espconn_regist_recvcb(&ESPConnection,WiFi_OnReceived);
   espconn_regist_connectcb(&ESPConnection,WiFi_OnConnectedTCP);
   espconn_regist_disconcb(&ESPConnection,WiFi_OnDisconnectedTCP);
   //espconn_regist_write_finish(pespconn,user_tcp_write_finish);

  //espconn_regist_write_finish(pespconn, user_tcp_write_finish); // register write
  //espconn_regist_disconcb(pespconn, user_tcp_discon_cb);
  //espconn_set_opt(pespconn, 0x04); // enable write buffer
  //espconn_regist_write_finish(pespconn, user_tcp_write_finish); // register write

   espconn_connect(&ESPConnection);

   WiFi_StartTimer(1000);
   return;
  }
 }
 if (size==1)
 {
  if (command_ptr[0]=='D')//отключение от сервера
  {
   if (WiFi_State!=WIFI_STATE_TCP_CONNECTED)
   {
    UART_TransmittMessage("DE");
    return;
   }
   espconn_disconnect(&ESPConnection);
   return;
  }
 }
 if (size>1)
 {
  if (command_ptr[0]=='S')//передача данных на сервер
  {
   if (WiFi_State!=WIFI_STATE_TCP_CONNECTED)
   {
    UART_TransmittMessage("SE");
    return;
   }
   espconn_send(&ESPConnection,(uint8_t*)(command_ptr+1),size-1);
   return;
  }
 }
}

//----------------------------------------------------------------------------------------------------
//разбор принятых данных по UART
//----------------------------------------------------------------------------------------------------
static void ICACHE_FLASH_ATTR UART_PushByte(uint8_t byte)
{
 if (ReceivedArraySize>MAX_RECEIVED_ARRAY)//начинаем приём заново при превышении размера массива
 {
  ReceivedArraySize=0;
  StuffingOn=false;
 }
 if (StuffingOn==false)
 {
  if (byte==BEGIN_PACKAGE)//начало приёма
  {
   ReceivedArraySize=0;
   return;
  }
  if (byte==END_PACKAGE)//конец приёма
  {
   if (ReceivedArraySize>0) UART_ExecuteCommand(ReceivedArray,ReceivedArraySize);
   ReceivedArraySize=0;
   return;
  }
  if (byte==STUFFING_ON)//включение замены байт
  {
   StuffingOn=true;
   return;
  }
  ReceivedArray[ReceivedArraySize]=byte;
  ReceivedArraySize++;
  return;
 }
 //замена байт включена
 StuffingOn=false;
 //если принят неизвестный код, начинаем приём заново
 if ((byte!=BEGIN_PACKAGE) && (byte!=END_PACKAGE) && (byte!=STUFFING_ON))
 {
  ReceivedArraySize=0;
  return;
 }
 ReceivedArray[ReceivedArraySize]=byte;
 ReceivedArraySize++;
}
//----------------------------------------------------------------------------------------------------
//пришли новые данные по UART
//----------------------------------------------------------------------------------------------------
static void UART_OnReceived(const uint8_t *data,size_t size)
{
 size_t n;
 for(n=0;n<size;n++) UART_PushByte(data[n]);
}

//----------------------------------------------------------------------------------------------------
//UART закончил передачу данных
//----------------------------------------------------------------------------------------------------
static void UART_OnSendDone(void)
{
}
//----------------------------------------------------------------------------------------------------
//системная функция: пред-инициализация
//----------------------------------------------------------------------------------------------------
static void ICACHE_FLASH_ATTR user_rf_pre_init(void)
{
}


//----------------------------------------------------------------------------------------------------
//периодическая проверка IP
//----------------------------------------------------------------------------------------------------
static void ICACHE_FLASH_ATTR WiFi_CheckIP(void *arg)
{
 struct ip_info ipConfig;

 WiFi_StopTimer();
 uint8_t wifi_status=wifi_station_get_connect_status();//узнаем состояние соединения с точкой доступа
 if (wifi_status==STATION_GOT_IP)
 {
  wifi_get_ip_info(STATION_IF,&ipConfig);
  if (ipConfig.ip.addr!=0)
  {
   if (WiFi_State!=WIFI_STATE_CONNECTED && WiFi_State!=WIFI_STATE_TCP_CONNECTED)
   {
    WiFi_State=WIFI_STATE_CONNECTED;
    LED_On();

    char str[255];
    os_sprintf(str,"My IP:%i.%i.%i.%i\r\n",ipConfig.ip.addr&0xff,(ipConfig.ip.addr>>8)&0xff,(ipConfig.ip.addr>>16)&0xff,(ipConfig.ip.addr>>24)&0xff);
    UART_SendMessage(str);
    return;
   }
   else
   {
    LED_Off();
   }
  }
 }
 else
 {
  LED_Off();
  WiFi_State=WIFI_STATE_CONNECTING;
  espconn_delete(&ESPConnection);
  if (wifi_station_get_connect_status()==STATION_WRONG_PASSWORD)
  {
   WiFi_State=WIFI_STATE_CONNECTING_ERROR;
   UART_SendMessage("STATION_WRONG_PASSWORD\r\n");
  }
  if(wifi_station_get_connect_status()==STATION_NO_AP_FOUND)
  {
   WiFi_State=WIFI_STATE_CONNECTING_ERROR;
   UART_SendMessage("STATION_NO_AP_FOUND\r\n");
  }
  if(wifi_station_get_connect_status()==STATION_CONNECT_FAIL)
  {
   WiFi_State=WIFI_STATE_CONNECTING_ERROR;
   UART_SendMessage("STATION_CONNECT_FAIL\r\n");
  }
  if (wifi_station_get_connect_status()!=STATION_WRONG_PASSWORD &&
      wifi_station_get_connect_status()!=STATION_NO_AP_FOUND &&
      wifi_station_get_connect_status()==STATION_CONNECT_FAIL)
  {
   WiFi_State=WIFI_STATE_CONNECTING;
  }
  WiFi_StartTimer(500);
 }
}




//----------------------------------------------------------------------------------------------------
//инициализация WiFi
//----------------------------------------------------------------------------------------------------
void WiFi_Init(void)
{
 wifi_set_opmode_current(STATION_MODE);
 wifi_station_disconnect();
 wifi_station_dhcpc_stop();

 WiFi_StopTimer();

 struct station_config stationConf;
 os_memset(&stationConf,0,sizeof(struct station_config));

 os_memset(&stationConf, 0, sizeof(struct station_config));
 os_sprintf(stationConf.ssid, "%s", WIFI_CLIENTSSID);
 os_sprintf(stationConf.password, "%s", WIFI_CLIENTPASSWORD);
 wifi_station_set_config_current(&stationConf);
 wifi_set_sleep_type(NONE_SLEEP_T);

 WiFi_StartTimer(1000);

 wifi_station_connect();
 wifi_station_dhcpc_start();

 if (wifi_get_phy_mode() != PHY_MODE_11N) wifi_set_phy_mode(PHY_MODE_11N);//включим протокол физического уровня типа 802.11n, если таковой уже не включен
 if(wifi_station_get_auto_connect()==0) wifi_station_set_auto_connect(1);//включим автоматическое соединение с точкой доступа в случае разрыва, если не включено
}


//----------------------------------------------------------------------------------------------------
//системная функция: инициализация
//----------------------------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR user_init(void)
{
 ReceivedArraySize=0;
 StuffingOn=false;
 WiFi_State=WIFI_STATE_CONNECTING;

 os_delay_us(10000);
 UART_Init();
 UART_RegisterReceivedFunction(&UART_OnReceived);
 UART_RegisterSendDoneFunction(&UART_OnSendDone);

 LED_Init();//если поставить перед UART_Init, то не работает
 LED_Off();
 WiFi_Init();//инициализация WiFi
}



user_config.h
#ifndef __USER_CONFIG_H__
#define __USER_CONFIG_H__

#include <stdio.h>

enum
{
 EVENT_UART_RECEIVED_DATA=0,//пришли данные по UART
 EVENT_UART_SEND_DONE,//завершена передача по UART
};
static const size_t EVENT_QUEUE_ID=0;//идентификатор очереди

#endif



uart.h
#ifndef UART_H
#define UART_H

//****************************************************************************************************
//подключаемые библиотеки
//****************************************************************************************************
#include <inttypes.h>
#include <stdio.h>
#include <os_type.h>

//****************************************************************************************************
//типы
//****************************************************************************************************
typedef void (*uart_received_func_ptr_t)(const uint8_t*,size_t);//указатель на функцию наличия новых данных
typedef void (*uart_send_done_func_ptr_t)(void);//указатель на функцию завершения передачи данных

//****************************************************************************************************
//макроопределения
//****************************************************************************************************

//****************************************************************************************************
//константы
//****************************************************************************************************

//****************************************************************************************************
//глобальные переменные
//****************************************************************************************************

//****************************************************************************************************
//прототипы функций
//****************************************************************************************************

void ICACHE_FLASH_ATTR UART_Init(void);//инициализация
void ICACHE_FLASH_ATTR UART_SendMessage(const char *str);//передать текстовое сообщение
void ICACHE_FLASH_ATTR UART_SendData(const uint8_t* data,size_t size);//передать данные
void ICACHE_FLASH_ATTR UART_RegisterReceivedFunction(uart_received_func_ptr_t func_ptr);//зарегистрировать функцию обратного вызова на приём данных
void ICACHE_FLASH_ATTR UART_RegisterSendDoneFunction(uart_send_done_func_ptr_t func_ptr);//зарегистрировать функцию обратного вызова на завершение передачи данных

#endif



uart.c
//****************************************************************************************************
//подключаемые библиотеки
//****************************************************************************************************
#include "uart.h"
#include "drvuart.h"
#include "user_interface.h"
#include <string.h>
#include <os_type.h>

//****************************************************************************************************
//макроопределения
//****************************************************************************************************

//размер очереди событий UART
#define UART_EVENT_QUEUE_LENGTH 100

//размер буфера приёма данных
#define UART_RECEIVED_BUFFER_SIZE 4096

//****************************************************************************************************
//константы
//****************************************************************************************************

//****************************************************************************************************
//глобальные переменные
//****************************************************************************************************

static uart_received_func_ptr_t ReceivedFunctionPtr=NULL;//указатель на функцию обратного вызова по приёму данных
static uart_send_done_func_ptr_t SendDoneFunctionPtr=NULL;//указатель на функцию обратного вызова по завершению передачи данных
static os_event_t EventQueue[UART_EVENT_QUEUE_LENGTH];//очередь событий UART

static uint8_t ReceivedBuffer[UART_RECEIVED_BUFFER_SIZE];//буфер приёма данных UART

//****************************************************************************************************
//прототипы функций
//****************************************************************************************************

static void ICACHE_FLASH_ATTR UART_EventQueueFunction(os_event_t *events);//обработчик очереди сообщений

//****************************************************************************************************
//реализация функций
//****************************************************************************************************

//----------------------------------------------------------------------------------------------------
//инициализация
//----------------------------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR UART_Init(void)
{
 ReceivedFunctionPtr=NULL;
 SendDoneFunctionPtr=NULL;

 //uart_init(BIT_RATE_115200);
 uart_init(BIT_RATE_921600);
 //регистрируем очередь событий
 system_os_task(UART_EventQueueFunction,EVENT_QUEUE_ID,EventQueue,UART_EVENT_QUEUE_LENGTH);
}
//----------------------------------------------------------------------------------------------------
//передать текстовое сообщение
//----------------------------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR UART_SendMessage(const char *str)
{
 UART_SendData((uint8_t*)str,strlen(str));
}
//----------------------------------------------------------------------------------------------------
//передать данные
//----------------------------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR UART_SendData(const uint8_t* data,size_t size)
{
 tx_buff_enq(data,size,true);
}
//----------------------------------------------------------------------------------------------------
//зарегистрировать функцию обратного вызова на приём данных
//----------------------------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR UART_RegisterReceivedFunction(uart_received_func_ptr_t func_ptr)
{
 ReceivedFunctionPtr=func_ptr;
}
//----------------------------------------------------------------------------------------------------
//зарегистрировать функцию обратного вызова на завершение передачи данных
//----------------------------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR UART_RegisterSendDoneFunction(uart_send_done_func_ptr_t func_ptr)
{
 SendDoneFunctionPtr=func_ptr;
}

//----------------------------------------------------------------------------------------------------
//обработчик очереди сообщений
//----------------------------------------------------------------------------------------------------
static void ICACHE_FLASH_ATTR UART_EventQueueFunction(os_event_t *events)
{
 if (events==NULL) return;
 if (events->sig==EVENT_UART_RECEIVED_DATA)
 {
  size_t data_length=rx_buff_get_data_len();
  if (data_length>UART_RECEIVED_BUFFER_SIZE) data_length=UART_RECEIVED_BUFFER_SIZE;
  rx_buff_deq(ReceivedBuffer,data_length);//получаем данные
  if (ReceivedFunctionPtr!=NULL) ReceivedFunctionPtr(ReceivedBuffer,data_length);
  return;
 }
 if (events->sig==EVENT_UART_SEND_DONE)
 {
  if (SendDoneFunctionPtr!=NULL) SendDoneFunctionPtr();
  return;
 }
}



led.h
#ifndef LED_H
#define LED_H

//****************************************************************************************************
//подключаемые библиотеки
//****************************************************************************************************
#include <os_type.h>

//****************************************************************************************************
//макроопределения
//****************************************************************************************************

//****************************************************************************************************
//константы
//****************************************************************************************************

//****************************************************************************************************
//глобальные переменные
//****************************************************************************************************

//****************************************************************************************************
//прототипы функций
//****************************************************************************************************

void ICACHE_FLASH_ATTR LED_Init(void);//инициализация
void ICACHE_FLASH_ATTR LED_On(void);//включить светодиод
void ICACHE_FLASH_ATTR LED_Off(void);//отключить светодиод

#endif



led.c
//****************************************************************************************************
//подключаемые библиотеки
//****************************************************************************************************
#include "led.h"
#include <gpio.h>

//****************************************************************************************************
//макроопределения
//****************************************************************************************************

#define LED_GPIO 2
#define LED_GPIO_MUX PERIPHS_IO_MUX_GPIO2_U
#define LED_GPIO_FUNC FUNC_GPIO2

//****************************************************************************************************
//константы
//****************************************************************************************************

//****************************************************************************************************
//глобальные переменные
//****************************************************************************************************

//****************************************************************************************************
//реализация функций
//****************************************************************************************************

//----------------------------------------------------------------------------------------------------
//инициализация
//----------------------------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR LED_Init(void)
{
 gpio_init();
 PIN_FUNC_SELECT(LED_GPIO_MUX,LED_GPIO_FUNC);
}
//----------------------------------------------------------------------------------------------------
//включить светодиод
//----------------------------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR LED_On(void)
{
 GPIO_OUTPUT_SET(LED_GPIO,0);
}
//----------------------------------------------------------------------------------------------------
//отключить светодиод
//----------------------------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR LED_Off(void)
{
 GPIO_OUTPUT_SET(LED_GPIO,1);
}

Дальше не мои файлы: эти файлы взяты из директорий с примерами в папках drivers. Но файлы uart.h и uart.c я переименовал в drvuart, так как мой файл тоже называется uart, а его название я менять не захотел.

drvuart_register.h
/******************************************************************************
 * Copyright 2013-2014 Espressif Systems
 *
 * FileName: uart_register.h
 *
 * Description: entry file of user application
 *
 * Modification history:
 *     2015/9/24, v1.0 create this file.
*******************************************************************************/

#ifndef UART_REGISTER_H_
#define UART_REGISTER_H_

#define REG_UART_BASE(i)                (0x60000000ul + (i)*0xf00)
//version value:32'h062000

#define UART_FIFO(i)                    (REG_UART_BASE(i) + 0x0)
#define UART_RXFIFO_RD_BYTE                 0x000000FF
#define UART_RXFIFO_RD_BYTE_S               0

#define UART_INT_RAW(i)                 (REG_UART_BASE(i) + 0x4)
#define UART_RXFIFO_TOUT_INT_RAW            (BIT(8))
#define UART_BRK_DET_INT_RAW                (BIT(7))
#define UART_CTS_CHG_INT_RAW                (BIT(6))
#define UART_DSR_CHG_INT_RAW                (BIT(5))
#define UART_RXFIFO_OVF_INT_RAW             (BIT(4))
#define UART_FRM_ERR_INT_RAW                (BIT(3))
#define UART_PARITY_ERR_INT_RAW             (BIT(2))
#define UART_TXFIFO_EMPTY_INT_RAW           (BIT(1))
#define UART_RXFIFO_FULL_INT_RAW            (BIT(0))

#define UART_INT_ST(i)                  (REG_UART_BASE(i) + 0x8)
#define UART_RXFIFO_TOUT_INT_ST             (BIT(8))
#define UART_BRK_DET_INT_ST                 (BIT(7))
#define UART_CTS_CHG_INT_ST                 (BIT(6))
#define UART_DSR_CHG_INT_ST                 (BIT(5))
#define UART_RXFIFO_OVF_INT_ST              (BIT(4))
#define UART_FRM_ERR_INT_ST                 (BIT(3))
#define UART_PARITY_ERR_INT_ST              (BIT(2))
#define UART_TXFIFO_EMPTY_INT_ST            (BIT(1))
#define UART_RXFIFO_FULL_INT_ST             (BIT(0))

#define UART_INT_ENA(i)                 (REG_UART_BASE(i) + 0xC)
#define UART_RXFIFO_TOUT_INT_ENA            (BIT(8))
#define UART_BRK_DET_INT_ENA                (BIT(7))
#define UART_CTS_CHG_INT_ENA                (BIT(6))
#define UART_DSR_CHG_INT_ENA                (BIT(5))
#define UART_RXFIFO_OVF_INT_ENA             (BIT(4))
#define UART_FRM_ERR_INT_ENA                (BIT(3))
#define UART_PARITY_ERR_INT_ENA             (BIT(2))
#define UART_TXFIFO_EMPTY_INT_ENA           (BIT(1))
#define UART_RXFIFO_FULL_INT_ENA            (BIT(0))

#define UART_INT_CLR(i)                 (REG_UART_BASE(i) + 0x10)
#define UART_RXFIFO_TOUT_INT_CLR            (BIT(8))
#define UART_BRK_DET_INT_CLR                (BIT(7))
#define UART_CTS_CHG_INT_CLR                (BIT(6))
#define UART_DSR_CHG_INT_CLR                (BIT(5))
#define UART_RXFIFO_OVF_INT_CLR             (BIT(4))
#define UART_FRM_ERR_INT_CLR                (BIT(3))
#define UART_PARITY_ERR_INT_CLR             (BIT(2))
#define UART_TXFIFO_EMPTY_INT_CLR           (BIT(1))
#define UART_RXFIFO_FULL_INT_CLR            (BIT(0))

#define UART_CLKDIV(i)                  (REG_UART_BASE(i) + 0x14)
#define UART_CLKDIV_CNT                     0x000FFFFF
#define UART_CLKDIV_S                       0

#define UART_AUTOBAUD(i)                (REG_UART_BASE(i) + 0x18)
#define UART_GLITCH_FILT                    0x000000FF
#define UART_GLITCH_FILT_S                  8
#define UART_AUTOBAUD_EN                    (BIT(0))

#define UART_STATUS(i)                  (REG_UART_BASE(i) + 0x1C)
#define UART_TXD                            (BIT(31))
#define UART_RTSN                           (BIT(30))
#define UART_DTRN                           (BIT(29))
#define UART_TXFIFO_CNT                     0x000000FF
#define UART_TXFIFO_CNT_S                   16
#define UART_RXD                            (BIT(15))
#define UART_CTSN                           (BIT(14))
#define UART_DSRN                           (BIT(13))
#define UART_RXFIFO_CNT                     0x000000FF
#define UART_RXFIFO_CNT_S                   0

#define UART_CONF0(i)                   (REG_UART_BASE(i) + 0x20)
#define UART_DTR_INV                        (BIT(24))
#define UART_RTS_INV                        (BIT(23))
#define UART_TXD_INV                        (BIT(22))
#define UART_DSR_INV                        (BIT(21))
#define UART_CTS_INV                        (BIT(20))
#define UART_RXD_INV                        (BIT(19))
#define UART_TXFIFO_RST                     (BIT(18))
#define UART_RXFIFO_RST                     (BIT(17))
#define UART_IRDA_EN                        (BIT(16))
#define UART_TX_FLOW_EN                     (BIT(15))
#define UART_LOOPBACK                       (BIT(14))
#define UART_IRDA_RX_INV                    (BIT(13))
#define UART_IRDA_TX_INV                    (BIT(12))
#define UART_IRDA_WCTL                      (BIT(11))
#define UART_IRDA_TX_EN                     (BIT(10))
#define UART_IRDA_DPLX                      (BIT(9))
#define UART_TXD_BRK                        (BIT(8))
#define UART_SW_DTR                         (BIT(7))
#define UART_SW_RTS                         (BIT(6))
#define UART_STOP_BIT_NUM                   0x00000003
#define UART_STOP_BIT_NUM_S                 4
#define UART_BIT_NUM                        0x00000003
#define UART_BIT_NUM_S                      2
#define UART_PARITY_EN                      (BIT(1))
#define UART_PARITY                         (BIT(0))

#define UART_CONF1(i)                   (REG_UART_BASE(i) + 0x24)
#define UART_RX_TOUT_EN                     (BIT(31))
#define UART_RX_TOUT_THRHD                  0x0000007F
#define UART_RX_TOUT_THRHD_S                24
#define UART_RX_FLOW_EN                     (BIT(23))
#define UART_RX_FLOW_THRHD                  0x0000007F
#define UART_RX_FLOW_THRHD_S                16
#define UART_TXFIFO_EMPTY_THRHD             0x0000007F
#define UART_TXFIFO_EMPTY_THRHD_S           8
#define UART_RXFIFO_FULL_THRHD              0x0000007F
#define UART_RXFIFO_FULL_THRHD_S            0

#define UART_LOWPULSE(i)                (REG_UART_BASE(i) + 0x28)
#define UART_LOWPULSE_MIN_CNT               0x000FFFFF
#define UART_LOWPULSE_MIN_CNT_S             0

#define UART_HIGHPULSE(i)               (REG_UART_BASE(i) + 0x2C)
#define UART_HIGHPULSE_MIN_CNT              0x000FFFFF
#define UART_HIGHPULSE_MIN_CNT_S            0

#define UART_PULSE_NUM(i)               (REG_UART_BASE(i) + 0x30)
#define UART_PULSE_NUM_CNT                  0x0003FF
#define UART_PULSE_NUM_CNT_S                0

#define UART_DATE(i)                    (REG_UART_BASE(i) + 0x78)
#define UART_ID(i)                      (REG_UART_BASE(i) + 0x7C)

#endif // UART_REGISTER_H_INCLUDED



drvuart.h
/******************************************************************************
 * Copyright 2013-2014 Espressif Systems
 *
 * FileName: uart.h
 *
 * Description: entry file of user application
 *
 * Modification history:
 *     2015/9/24, v1.0 create this file.
*******************************************************************************/
#ifndef UART_APP_H
#define UART_APP_H

#include "drvuart_register.h"
#include <eagle_soc.h>
#include <c_types.h>

#define UART0   0
#define UART1   1

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;    // chip size in byte
    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);
///////////////////////////////////////
#define UART_FIFO_LEN  128  //define the tx fifo length
//
#define UART_TX_EMPTY_THRESH_VAL 0x10
#define UART_TX_BUFFER_SIZE 8192
#define URAT_TX_LOWER_SIZE 1024*7
#define URAT_TX_UPPER_SIZE  8000*1

#define UART_RX_BUFFER_SIZE  (10*1024) //201

//#define UART_TX_DEBUG
#define DBG(...)
#define DBG1(...) //uart1_sendStr_no_wait
#define DBG2(...) //os_printf

struct UartBuffer {
    uint16     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
} ;

void tx_buff_enq(const char *pdata, uint16 data_len, bool force);
uint16 rx_buff_deq(char *pdata, uint16 data_len);
//==============================================
#define FUNC_UART0_CTS 4
#define UART_LINE_INV_MASK  (0x3f<<19)

#endif



drvuart.c
/******************************************************************************
 * Copyright 2013-2014 Espressif Systems
 *
 * FileName: uart.c
 *
 * Description: entry file of user application
 *
 * Modification history:
 *     2015/9/24, v1.0 create this file.
*******************************************************************************/
#include <ets_sys.h>
#include <osapi.h>
#include <mem.h>
#include "drvuart.h"
#include "drvuart_register.h"
#include "user_interface.h"

#include <espconn.h>

#define FUNC_U1TXD_BK 2
#define FUNC_U0CTS 4
extern UartDevice UartDev;

static struct UartBuffer *pTxBuffer = NULL;
static struct UartBuffer *pRxBuffer = NULL;

LOCAL void uart0_rx_intr_handler(void *para);

void uart1_sendStr_no_wait(const char *str);
struct UartBuffer * Uart_Buf_Init(uint32 buf_size);
void rx_buff_enq(void);
void tx_start_uart_buffer(uint8 uart_no);
void uart_rx_intr_disable(uint8 uart_no);
void uart_rx_intr_enable(uint8 uart_no);
/******************************************************************************
 * 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)
{
    if (uart_no == UART1) {
        PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK);
    } else {
        /* rcv_buff size if 0x100 */
        ETS_UART_INTR_ATTACH(uart0_rx_intr_handler,  &(UartDev.rcv_buff));
        PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
        PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS);
        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_U0CTS);
        PIN_PULLUP_DIS(PERIPHS_IO_MUX_MTCK_U);
    }

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

    WRITE_PERI_REG(UART_CONF0(uart_no), (uint32)UartDev.exist_parity
            | (uint32)UartDev.parity
            | (((uint8)UartDev.stop_bits) << UART_STOP_BIT_NUM_S)
            | (((uint8)UartDev.data_bits) << UART_BIT_NUM_S));

    //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);

    if (uart_no == UART0) {
        //set rx fifo trigger
        WRITE_PERI_REG(UART_CONF1(uart_no),
                ((100 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) |
                ((110 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) |
                UART_RX_FLOW_EN |
                (0x02 & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S |
                UART_RX_TOUT_EN |

                ((0x10 & UART_TXFIFO_EMPTY_THRHD) << UART_TXFIFO_EMPTY_THRHD_S)); //wjl
                //SET_PERI_REG_MASK( UART_CONF0(uart_no),UART_TX_FLOW_EN);  //add this sentense to add a tx flow control via MTCK( CTS )

        SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_TOUT_INT_ENA |
                UART_FRM_ERR_INT_ENA);
    } else {
        WRITE_PERI_REG(UART_CONF1(uart_no),
                ((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S));
    }

    //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 | UART_RXFIFO_OVF_INT_ENA);
}

/******************************************************************************
 * FunctionName : uart1_tx_one_char
 * Description  : Internal used function
 *                Use uart1 interface to transfer one char
 * Parameters   : uint8 TxChar - character to tx
 * Returns      : OK
 *******************************************************************************/
STATUS
uart_tx_one_char(uint8 uart, uint8 TxChar)
{
    for(;;) {
        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') {
        (void)uart_tx_one_char(UART1, '\r');
        (void)uart_tx_one_char(UART1, '\n');
    } else if (c == '\r') {
    } else {
        (void)uart_tx_one_char(UART1, (uint8)c);
    }
}

/******************************************************************************
 * 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
 *******************************************************************************/
LOCAL void
uart0_rx_intr_handler(void *para)
{
    uint8 uart_no = UART0;
    if (UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST)) {
        uart1_sendStr_no_wait("FRM_ERR\r\n");
        WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR);
    }

    if (UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)) {
        uart_rx_intr_disable(uart_no);
        rx_buff_enq();
    } else if (UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST)) {
        uart_rx_intr_disable(uart_no);
        rx_buff_enq();
    } else if (UART_TXFIFO_EMPTY_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_TXFIFO_EMPTY_INT_ST)) {
        CLEAR_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_TXFIFO_EMPTY_INT_ENA);
        tx_start_uart_buffer(uart_no);
        WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_TXFIFO_EMPTY_INT_CLR);
   } else if (UART_RXFIFO_OVF_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_OVF_INT_ST)) {
        uart1_sendStr_no_wait("RX OVF!\r\n");
        WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_OVF_INT_CLR);
    }
}

/******************************************************************************
 * 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)
{
    UartDev.baut_rate = uart0_br;
    uart_config(UART0);
    UartDev.baut_rate = BIT_RATE_115200;
    uart_config(UART1);
    ETS_UART_INTR_ENABLE();

    os_install_putc1(uart1_write_char);

    pTxBuffer = Uart_Buf_Init(UART_TX_BUFFER_SIZE);
    pRxBuffer = Uart_Buf_Init(UART_RX_BUFFER_SIZE);
}

/******************************************************************************
 * FunctionName : uart_tx_one_char_no_wait
 * Description  : uart tx a single char without waiting for fifo
 * Parameters   : uint8 uart - uart port
 *                uint8 TxChar - char to tx
 * Returns      : STATUS
 *******************************************************************************/
STATUS
uart_tx_one_char_no_wait(uint8 uart, uint8 TxChar)
{
    uint8 fifo_cnt = ((READ_PERI_REG(UART_STATUS(uart)) >> UART_TXFIFO_CNT_S)& UART_TXFIFO_CNT);

    if (fifo_cnt < 126) {
        WRITE_PERI_REG(UART_FIFO(uart) , TxChar);
    }

    return OK;
}

/******************************************************************************
 * FunctionName : uart1_sendStr_no_wait
 * Description  : uart tx a string without waiting for every char, used for print debug info which can be lost
 * Parameters   : const char *str - string to be sent
 * Returns      : NONE
 *******************************************************************************/
void
uart1_sendStr_no_wait(const char *str)
{
    if(str == NULL) {
        return;
    }

    while (*str) {
        (void)uart_tx_one_char_no_wait(UART1, (uint8)*str);
        str++;
    }
}
/******************************************************************************
 * FunctionName : Uart_Buf_Init
 * Description  : tx buffer enqueue: fill a first linked buffer
 * Parameters   : char *pdata - data point  to be enqueue
 * Returns      : NONE
 *******************************************************************************/
struct UartBuffer *ICACHE_FLASH_ATTR
Uart_Buf_Init(uint32 buf_size)
{
    uint32 heap_size = system_get_free_heap_size();

    if(buf_size > 65535) { // now not support
        DBG1("no buf for uart\n\r");
        return NULL;
    }
    if (heap_size <= buf_size) {
        DBG1("no buf for uart\n\r");
        return NULL;
    } else {
        DBG("test heap size: %d\n\r", heap_size);
        struct UartBuffer *pBuff = (struct UartBuffer *)os_malloc((uint32)sizeof(struct UartBuffer));
        pBuff->UartBuffSize = (uint16)buf_size; // THIS OK
        pBuff->pUartBuff = (uint8 *)os_malloc(pBuff->UartBuffSize);
        pBuff->pInPos = pBuff->pUartBuff;
        pBuff->pOutPos = pBuff->pUartBuff;
        pBuff->Space = pBuff->UartBuffSize;
        pBuff->BuffState = OK;
        pBuff->nextBuff = NULL;
        //        pBuff->TcpControl = RUN;
        return pBuff;
    }
}

LOCAL void
Uart_Buf_Cpy(struct UartBuffer *pCur, const char *pdata , uint16 data_len)
{
    if ((pCur == NULL) || (pdata == NULL) || (data_len == 0)) {
        return ;
    }

    uint16 tail_len = (uint16)(pCur->pUartBuff + pCur->UartBuffSize - pCur->pInPos); // THIS OK

    if (tail_len >= data_len) { //do not need to loop back  the queue
        os_memcpy(pCur->pInPos , pdata , data_len);
        pCur->pInPos += (data_len);
        pCur->pInPos = (pCur->pUartBuff + (pCur->pInPos - pCur->pUartBuff) % pCur->UartBuffSize);
        pCur->Space -= data_len;
    } else {
        os_memcpy(pCur->pInPos, pdata, tail_len);
        pCur->pInPos += (tail_len);
        pCur->pInPos = (pCur->pUartBuff + (pCur->pInPos - pCur->pUartBuff) % pCur->UartBuffSize);
        pCur->Space -= tail_len;
        os_memcpy(pCur->pInPos, pdata + tail_len , data_len - tail_len);
        pCur->pInPos += (data_len - tail_len);
        pCur->pInPos = (pCur->pUartBuff + (pCur->pInPos - pCur->pUartBuff) % pCur->UartBuffSize);
        pCur->Space -= (data_len - tail_len);
    }

}

/******************************************************************************
 * FunctionName : uart_buf_free
 * Description  : deinit of the tx buffer
 * Parameters   : struct UartBuffer* pTxBuff - tx buffer struct pointer
 * Returns      : NONE
 *******************************************************************************/
void ICACHE_FLASH_ATTR
uart_buf_free(struct UartBuffer *pBuff)
{
    if(pBuff != NULL) {
        if(pBuff->pUartBuff != NULL) {
            os_free(pBuff->pUartBuff);
        }
        os_free(pBuff);
    }
}

uint16 ICACHE_FLASH_ATTR
rx_buff_get_data_len(void)
{
	uint16 buf_len = pRxBuffer->UartBuffSize - pRxBuffer->Space;
	return buf_len;
}

uint16 ICACHE_FLASH_ATTR
rx_buff_deq(char *pdata, uint16 data_len)
{
    uint16 len_tmp = 0;

    uint16 buf_len = pRxBuffer->UartBuffSize - pRxBuffer->Space;
    uint16 tail_len = (uint16)(pRxBuffer->pUartBuff + pRxBuffer->UartBuffSize - pRxBuffer->pOutPos); // THIS OK
    len_tmp = ((data_len > buf_len) ? buf_len : data_len);

    if (pRxBuffer->pOutPos <= pRxBuffer->pInPos) {
        if(pdata != NULL) {
            os_memcpy(pdata, pRxBuffer->pOutPos, len_tmp);
        }
        pRxBuffer->pOutPos += len_tmp;
        pRxBuffer->Space += len_tmp;
    } else {
        if (len_tmp > tail_len) {
            if(pdata != NULL) {
                os_memcpy(pdata, pRxBuffer->pOutPos, tail_len);
            }
            pRxBuffer->pOutPos += tail_len;
            pRxBuffer->pOutPos = (pRxBuffer->pUartBuff + (pRxBuffer->pOutPos - pRxBuffer->pUartBuff) % pRxBuffer->UartBuffSize);
            pRxBuffer->Space += tail_len;

            if(pdata != NULL) {
                os_memcpy(pdata + tail_len , pRxBuffer->pOutPos, len_tmp - tail_len);
            }
            pRxBuffer->pOutPos += (len_tmp - tail_len);
            pRxBuffer->pOutPos = (pRxBuffer->pUartBuff + (pRxBuffer->pOutPos - pRxBuffer->pUartBuff) % pRxBuffer->UartBuffSize);
            pRxBuffer->Space += (len_tmp - tail_len);
        } else {
            if(pdata != NULL) {
                os_memcpy(pdata, pRxBuffer->pOutPos, len_tmp);
            }
            pRxBuffer->pOutPos += len_tmp;
            pRxBuffer->pOutPos = (pRxBuffer->pUartBuff + (pRxBuffer->pOutPos - pRxBuffer->pUartBuff) % pRxBuffer->UartBuffSize);
            pRxBuffer->Space += len_tmp;
        }
    }

    // os_printf("recv:%d\r\n",pRxBuffer->Space);
    return len_tmp;
}

void
rx_buff_enq(void)
{
    uint8 fifo_len = 0, buf_idx = 0,loop;
    ETSParam par = 0;
    uint8 fifo_data;
    uint8* tail = (pRxBuffer->pUartBuff + pRxBuffer->UartBuffSize);
    fifo_len = (READ_PERI_REG(UART_STATUS(UART0)) >> UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;

    if(fifo_len > pRxBuffer->Space) {
        buf_idx = pRxBuffer->Space;
    } else {
        buf_idx = fifo_len;
    }

    loop = buf_idx;
    while (loop--) {
        *(pRxBuffer->pInPos++) = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF;
        if (pRxBuffer->pInPos == tail) {
            pRxBuffer->pInPos = pRxBuffer->pUartBuff;
        }
    }

    fifo_len -= buf_idx;

    while (fifo_len--) {
        fifo_data = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF; // discard data
    }

    pRxBuffer->Space -= buf_idx ;
    par = buf_idx;
    if(system_os_post(EVENT_QUEUE_ID,(ETSSignal)EVENT_UART_RECEIVED_DATA, par) != TRUE) {
        os_printf("post fail!!!\n\r");
    }
    WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR | UART_RXFIFO_TOUT_INT_CLR);
    uart_rx_intr_enable(UART0);
}

void ICACHE_FLASH_ATTR
tx_buff_enq(const char *pdata, uint16 data_len, bool force)
{
    CLEAR_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
    //DBG2("len:%d\n\r",data_len);
    if(pdata != NULL) {
        if (pTxBuffer == NULL) {
            DBG1("\n\rnull, create buffer struct\n\r");
            pTxBuffer = Uart_Buf_Init(UART_TX_BUFFER_SIZE);

            if (pTxBuffer != NULL) {
                Uart_Buf_Cpy(pTxBuffer ,  pdata,  data_len);
            } else {
                DBG1("uart tx MALLOC no buf \n\r");
            }
        } else {
            if (data_len <= pTxBuffer->Space) {
                Uart_Buf_Cpy(pTxBuffer ,  pdata,  data_len);
            } else if (force) {
                for(;;) {
                    tx_start_uart_buffer(UART0);
                    CLEAR_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
                    if (data_len <= pTxBuffer->Space) {
                        Uart_Buf_Cpy(pTxBuffer ,  pdata,  data_len);
                        break;
                    }
                    ets_delay_us(70);
                    WRITE_PERI_REG(0X60000914, 0x73);
                };
            } else {
                DBG1("UART TX BUF FULL!!!!\n\r");
            }
        }

        if ((pTxBuffer != NULL) && (pTxBuffer->Space <= URAT_TX_LOWER_SIZE))
        {
        //set_tcp_block();
        }
    }

    SET_PERI_REG_MASK(UART_CONF1(UART0), (UART_TX_EMPTY_THRESH_VAL & UART_TXFIFO_EMPTY_THRHD) << UART_TXFIFO_EMPTY_THRHD_S);
    SET_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
}

//--------------------------------
LOCAL void tx_fifo_insert(struct UartBuffer *pTxBuff, uint8 data_len,  uint8 uart_no)
{
    uint8 i;

    if(pTxBuff == NULL) {
        return;
    }

    for (i = 0; i < data_len; i++) {
        WRITE_PERI_REG(UART_FIFO(uart_no) , *(pTxBuff->pOutPos++));

        if (pTxBuff->pOutPos == (pTxBuff->pUartBuff + pTxBuff->UartBuffSize)) {
            pTxBuff->pOutPos = pTxBuff->pUartBuff;
        }
    }

    pTxBuff->pOutPos = (pTxBuff->pUartBuff + (pTxBuff->pOutPos - pTxBuff->pUartBuff) % pTxBuff->UartBuffSize);
    pTxBuff->Space += data_len;
}

/******************************************************************************
 * FunctionName : tx_start_uart_buffer
 * Description  : get data from the tx buffer and fill the uart tx fifo, co-work with the uart fifo empty interrupt
 * Parameters   : uint8 uart_no - uart port num
 * Returns      : NONE
 *******************************************************************************/
void tx_start_uart_buffer(uint8 uart_no)
{
    uint8 tx_fifo_len = (READ_PERI_REG(UART_STATUS(uart_no)) >> UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT;
    uint8 fifo_remain = UART_FIFO_LEN - tx_fifo_len ;
    uint8 len_tmp;
    uint32 data_len;

    if (pTxBuffer) {
        data_len = (pTxBuffer->UartBuffSize - pTxBuffer->Space);

        if (data_len > fifo_remain) {
            len_tmp = fifo_remain;
            tx_fifo_insert(pTxBuffer, len_tmp, uart_no);
            SET_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
        } else {
            len_tmp = (uint8)data_len; // THIS OK
            tx_fifo_insert(pTxBuffer, len_tmp, uart_no);

        }

        if (pTxBuffer->Space >= URAT_TX_UPPER_SIZE) {
            (void)system_os_post(EVENT_QUEUE_ID,(ETSSignal)EVENT_UART_SEND_DONE,(ETSParam)0);
        }
    }
}

void uart_rx_intr_disable(uint8 uart_no)
{
    CLEAR_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_TOUT_INT_ENA);
}

void uart_rx_intr_enable(uint8 uart_no)
{
    SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_TOUT_INT_ENA);
}
//========================================================

Используя функции Lua C API, предназначенные для манипуляции с данными получаемыми/передаваемыми из внешних библиотек, теоретически возможно все это серьезно заоптимизировать. Но это (на мой взгляд) подобно сексу в гамаке стоя. Ибо зачем так извращаться, когда можно просто написать нужное на C/C++.

Насколько я помню работу с Lua C API, написание сишной библиотеки для использования человеческих сишных массивов из lua займет строк 20-50 на С. Там всё очень близко к С. Разве это не так?

Я имел в виду не написание C-библиотеки (подозреваю, что для NodeMCU это не невозможно, но несколько сложнее того, ради чего используют NodeMCU), а использования функционала C API для более эффективного преобразования структур данных: сначала преобразуем входной "массив" в userdata, как будто бы мы хотели отправлять его в C, затем эту userdata преобразуем в string. Скорее всего это получится сделать гораздо эффективнее, чем прикладными методами.

Хм, надо попробовать аппроксимацию простой нейросетью с ReLU.

А что будет с картинкой, если пи принять равным 4?

Подскажите, возможно есть русскоязычные ссылки как на STM32 реализовать DMA с участием внешней микросхемы статической или динамической ОЗУ? Задача стоит связать STM32+ SRAM 32Kx8 + АЦП 20мегавыборок/сек с параллельной шиной данных + вывод результатов из SRAM 32Кх8 в режиме DMA на ЖК экран (128х160 или 240х320 и подобный из диапазона 150-200/шт). Как реализуемо впринципе такое?

На русском… сомневаюсь.


Смотрите в сторону FSMC функционала. Как раз для работы с SRAM и для вывода на экран в через параллельную шину.
Я такое делал.
https://github.com/mmMikeKn/CNC/tree/master/src/liblcd

А надо ли тут DMA? Если не ошибаюсь, у некоторых контроллеров есть аппаратный интерфейс специально для микросхема памяти, FSMC.
То, что вы описали про АЦП, память и дисплей похоже на цифровой осциллограф, но тут хорошо бы начать с приблизительной оценки — а потянет ли контроллер столько? Что он с этими данными делать будет? Если просто отобразить на дисплее, так там 32 кБ не нужно, хватит тех же 320 байт. Ну пусть 640 если по 2 байта на отсчет. Если передавать в компьютер, то по какому интерфейсу? USB тоже не потянет.
Да даже если АЦП будет выдавать по 20 мегасемплов в секунду, сколько тактов у контроллера уйдет чтобы их забрать и хотя бы сложить в память, не говоря уж об обработке?

Эпично.


Я правильно понимаю, что у вас сцена рисуется построчно, по 240 раз на кадр?


А вы не хотите заморочиться и далее, релиазовав поддержку чтения формата Binary GLTF? Этот формат более дружелюбен к современным графическим api, чем obj.

Не совсем. То есть сцена действительно рисуется построчно и строк 240, но на каждую строку рисуется только та строка примитива, которая в нее попадает. В отличие от «нормальной» графики, где примитив рисуется сразу целиком, потом другой примитив, тоже целиком. Тут в чем-то даже похоже на трассировку лучей. Хотя скорее даже «трассировка веера» если так можно сказать.
На счет glTF, то до вашего вопроса даже не знал что это такое :) Как бы то ни было, развивать именно трехмерку на stm32 я не планирую. Но не исключено, что воспользуюсь в более «взрослой» графике. Спасибо что упомянули про такой формат.
Этот формат дружелюбен к современным графическим api

Он дружелюбен (прибит гвоздями) к OpenGL, а не к современным графическим API. JSON-часть этого формата не выглядит хорошим решением для микроконтроллеров. Если выкинуть JSON, то остаётся просто блоб, который загружать даже проще, чем Wavefront OBJ. Достаточно memcpy или аналога, идентичного натуральному.


OpenGL к современным графическим API я не отношу в силу того, что архитектура OpenGL идёт в разрез с тем, как устроенны современные GPU.

Спасибо. Если добавить акселерометр-гироскоп-магнитомер, то возможно было бы получить прикольное управление моделью — как если ее через некое окошко рассматриваешь с разных сторон.
Ну в чем-то да :)
Правда, чтобы рассмотреть модель снизу придется встать в очень интересную позу
НЛО прилетело и опубликовало эту надпись здесь
Раз уж есть расчёт освещения, можно отбрасывать все полигоны, у которых вектор нормали направлен от экрана — их всё равно не видно. Примерно вполовину количество полигонов для отрисовки уменьшится.
Файл src/gl.c, строка 282 именно это и делает. Но это вообще стандартный метод удаления невидимых граней при обходе по часовой стрелке или против, тут вообще нет специфики применения контроллера.
Спасибо за статью, прочиталось запоем до последней точки. Ну и для себя надо взять на заметку такую искусную работу с младшей STM32, как пример «Вижу цель, не вижу препятствия!» ;)
Залез в код, ожидал сначала увидеть ужасный калокуб… Но увидел отличные исходники!
Спасибо!!! Хоть немного людей в этом мире еще не превратились в хомячков…
Люблю воинственные заявления, спасибо. Только в вашем же журнале вы регулярно жалуетесь на то, что бьётесь-бьётесь, а в итоге железо было неправильно инициализировано…
Спасибо за статью!
Хороший и показательный пример использования ресурсов.

От себя добавлю:
По сравнению с AVR характеристики камня довольно приличные: 72 МГц тактовой (на практике можно разогнать до 100 МГц, а то и больше, но только на свой страх и риск!), 20 кБ оперативки и 64 кБ флеша.

Разгоняется до 144 МГц (из периферии становится недоступным только USB), в работе на такой частоте — чуть теплый.
А флеша у этого чипа 128кб. :) (Для демки — самое то).
144 МГц и 128 кБ это все же как повезет. То есть производитель не только из жадности промаркировал камень меньшим номиналом, что-то на предельных режимах работает недостаточно устойчиво. А значит, в серьезной разработке полагаться на эти возможности нельзя. Для себя же, когда проверил конкретный камень — почему бы и нет, на свой страх и риск.
Частота официальна, не заявлена ввиду отсутствия делителя для USB.
И само-собой, это не «в продакшн».
Хотя все протестированные экземпляры пилюль, показали полную работоспособность флеша выше 64кб.
Но я не настаиваю, на нет и суда нет ;)
Просто для такой задачи, это «самое оно».
Забавно, я пишу сейчас как раз собственный 3д движок под stm32f103 на том же железе. Чтобы прыгнуть выше 15 фпс надо отказаться от z-буффера в пользу сортировки полигонов. Ну и да, я извратился с числами с фиксированной точкой, чтобы избежать флоатов. Модельки пока не грузил. Пока как-то так, на кубах, есть куда оптимизировать. Пилю ещё серию видео на эту тему для ютубчика. ФПС где-то под 30 на глаз, бодро работает.

image
Оставлю на всякий случай это здесь


Если вы обратили внимание, в моей демке при выводе пересекающихся квадратов довольно ярко горит красный светодиод, то есть узкое место не в математике, а в пересылке по SPI. Вот на модельках из 200 треугольников (если вычесть отброшенные по отрицательной нормали) там да, проблема в обсчете. Но и то только из-за того что я не заморачивался с оптимизацией. Точки пересечения со строкой считаются в лоб, через умножения, глубина тоже. По-хорошему, стоило бы применить алгоритм Брезенхема и проводить расчет итеративно, за одно сложение и одно сравнение.
Z-координату вообще можно вытянуть из уравнения плоскости:
Z = (D — x*nx — y*ny)/nz,
D = px*nx + py*ny + pz*nz,
где nx,ny,nz — нормаль
pz,py,pz — опорная точка (скажем, любая вершина), но она пересчитывается в одну скалярную константу D
x,y — координаты на плоскости, z — глубина
— Но в целом необходимости в этом немного: в моем варианте память контроллера кончилась ненамного позже запаса быстродействия, выигрыш будет хорошо если в 2 раза на сложных модельках
SPI у него тоже разгоняется до 195/2 MHz, и работает без нареканий. (Неофициально, само-собой)
Ловите фаната gothic — использованы модельки шныга и кровавой мухи :)
Там еще на превьюшке третья моделька
А вообще, ловите второго фаната Готики — он узнал эти модельки :)

не подскажите как дать второе дыхание старому китайскому планшету? к примеру - как использовать экран с тачскрином в связке с малинкой

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории