• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Не работают ets_printf и os_printf

Алексей.

Active member
при выводе форматных строк делает ошибки с выводом чисел
Смотреть без слёз нельзя ESP8266 Non-OS SDK API Reference


Prototype: os_printf(const char *s)
декларирована функция с одним аргументом, совсем не переменным числом, а с одним
Example: os_printf("SDK version: %s \n", system_get_sdk_version());
пример как бы уже с двумя
ничего удивительного что в коде масса ошибок, это традиция, ардуина-иде популяризирует это "изделие" тем самым обеспечивает определенный спрос на него, в ретейл такое вряд ли пройдет, а вот для "поиграть" сгодится.
 
Последнее редактирование:

valerivp

Member
всем спасибо!

проблема решается так:
Код:
#include "user_interface.h"

void setup() {
  Serial.begin(115200);
  Serial.println();
  uart_set_debug(UART0);
  os_printf("I'm os_printf\n");
}
 

Алексей.

Active member
valerivp, Объясните пожалуйста для чего Вы используете Serial.begin(115200); если и без него напрямую пользуетесь api из uart.h
uart_set_debug Вы согласны вызывать, а uart_init Вам вызывать не хочется?
Пусть в Serial.begin сначала заблокируется вывод лога и вызовет uart_init, а мы уж сами вывод лога разблокируем.
Очень странный подход.
 

valerivp

Member
valerivp, Объясните пожалуйста для чего Вы используете Serial.begin(115200); если и без него напрямую пользуетесь api из uart.h
uart_set_debug Вы согласны вызывать, а uart_init Вам вызывать не хочется?
Пусть в Serial.begin сначала заблокируется вывод лога и вызовется uart_init, а мы уж сами вывод лога разблокируем.
Очень странный подход.
Код:
Serial.begin()
я использую для:
  • установки скорости порта
  • прочей инициализации объекта Serial (потому что в своем проекте я использую Serial.print)

функция os_printf мне понадобилась исключительно для того, чтобы выводились отладочные сообщения SDK / Ардуино
 

Алексей.

Active member
В трех строках кода
void HardwareSerial::begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin)
{
if(uart_get_debug() == _uart_nr) {
uart_set_debug(UART_NO);
}
if (_uart) {
free(_uart);
}
_uart = uart_init(_uart_nr, baud, (int) config, (int) mode, tx_pin);
_peek_char = -1;
}
Выполняется блокировка вывода лога, если уарт совпадает
и выполняется тот самый uart_init для заданной скорости, конфига SERIAL_8N1, режима SERIAL_8N1, и номера пина 1
Больше никаких инициализаций не выполняется :)
os_printf Вы вызывать не хотите, вместо нее вызываете Serial.print так что ли, типа os_printf не кошерная.
Тогда всё становится на свои места, чем больше обёрток, тем пухлее код (бинарный), круто.
 

valerivp

Member
Алексей., я считаю, что для использования каких либо библиотек, я не должен в совершенстве знать, как они устроены.
Для Serial положено вызвать begin - я его и вызываю.
Serial.print и os_printf обеспечивают похожий, но совершенно разный функционал.

Лично мне гораздо удобнее писать
Код:
Serial << F("value:") << value << F(",info:") << info ...
чем
Код:
os_printf("value:%????")
- я даже не хочу думать, какие буквы мне надо написать в форматной строке.

и меня очень мало волнует объем и производительность кода, пока эти показатели укладываются в рамки которые меня устраивают.
мое время мне дороже байтов и тактов.
 

Алексей.

Active member
Говорите про Serial.print а сами используете потоковый вывод Serial << "some text"
Сначала утверждаете "я не должен в совершенстве знать, как они устроены" а потом когда код выходит из под контроля обращаетесь за помощью, ну конечно, за Вас другие уж точно разобрались, а Вы не верите.
А как в SDK работает Serial.begin и Serial.print ? Таких функций в SDK нет.
Это функции из Arduino и там UART-ы переназначены.
 

valerivp

Member
Говорите про Serial.print а сами используете потоковый вывод Serial << "some text"
Сначала утверждаете "я не должен в совершенстве знать, как они устроены" а потом когда код выходит из под контроля обращаетесь за помощью, ну конечно, за Вас другие уж точно разобрались, а Вы не верите.
Мне кажется, что для использования потокового вывода (Serial << ) объект Serial должен быть корректно инициализирован. Именно поэтому я вызываю begin

А когда поведение системы отличается от ожидаемого, только тогда я начинаю думать - "почему же он так?"
и мыслительный процесс у меня выдает порядок действий:
  • Спросить у Яндекса - он много знает
  • Спросить на форуме - может кто наступал на эти грабли
  • Прикинуть что проще/более приемлемо - разобраться или обойти
  • Разобраться или обойти
 

valerivp

Member
А как в SDK работает Serial.begin и Serial.print ? Таких функций в SDK нет.
Это функции из Arduino и там UART-ы переназначены.
Лично мне глубоко все равно, где кончается SDK и начинается Adruino и сторонние библиотеки. Я привык быть неразборчивым в средствах, лишь бы они приводили к нужному результату с минимальными трудозатратами.
 

pvvx

Активный участник сообщества
Смотреть без слёз нельзя ESP8266 Non-OS SDK API Reference


Prototype: os_printf(const char *s)
декларирована функция с одним аргументом, совсем не переменным числом, а с одним
Example: os_printf("SDK version: %s \n", system_get_sdk_version());
пример как бы уже с двумя
ничего удивительного что в коде масса ошибок, это традиция, ардуина-иде популяризирует это "изделие" тем самым обеспечивает определенный спрос на него, в ретейл такое вряд ли пройдет, а вот для "поиграть" сгодится.
Там в самом коде процедуры ets_printf ошибки (она находиться в ROM), а не в описаниях в Arduino к ней.
При вызове коротких форматных строк типа ets_printf("%u", x) или подобных (счас точно уже не помню, т.к. не вожусь с ESP8266 более), она ничего не выводит или режет вывод, показывает меньше цифр и и прочие глюки. Не говоря уже о том, что не поддерживает float и массу стандартных форматов.
 

pvvx

Активный участник сообщества
и меня очень мало волнует объем и производительность кода, пока эти показатели укладываются в рамки которые меня устраивают.
мое время мне дороже байтов и тактов.
<< дает увеличение кода на 100 килобайт и тормоз. Т.е. вам придется взять другой чип.
Я вижу время у вас много - подождете ещё пяток или пятьдесят лет, когда появятся чипы, удовлетворяющие ваши требования (c учетом потребления уже имеющихся устройств при работе с ними в обычном СИ).

#include <iostream>
using namespace std;
void setup() { cout << "std: Hello, world!" << endl; }
void loop() {}
Скетч использует 158260 байт

void setup() { printf("Printf: Hello, world!\r\n"); }
void loop() {}
Скетч использует 28592 байт (там инициализация чипа + RTOS + барахло Arduino + стандартный printf + их данные и буфера, т.е. включая bss)

PS: Мой совет вам - не тратьте на это вообще время - наймите программиста :)
 
Последнее редактирование:

valerivp

Member
Скетч использует 28592 байт (там инициализация чипа + RTOS + барахло Arduino + стандартный printf + их данные и буфера, т.е. включая bss)
а когда я добавил нужные мне библиотеки стало еще больше! ужас!
326 755 bytes (used 31% of a 1 044 464 byte maximum)

целых 31%

надо срочно нанять программиста, который запихнет в 25%.
За 50000$
Потом скажет - для этого устройства ESP8266 избыточна. И глючна. И ему не нравится. И надо все переписать. И вообще он просто хочет еще 50000$.

А мне глубоко пофигу, сколько байт занимает программа 22% или 50%. Важно только что меньше 100%. Хотя в данном чипе - нужно меньше 50% - чтобы на OTA осталось.

Для моих задач чипа хватает с головой. Не будет хватать - возьму ESP32. И я ожидаю, что код Ардуино будет работать в другом чипе с минимальными изменениями. А если писать на чистом железе - очень много переделывать придется.
 

pvvx

Активный участник сообщества
а когда я добавил нужные мне библиотеки стало еще больше! ужас!
Вам же уже сказал, что у вас вагон времени на ожидание заливки больших объемов через COM порт в чип :)
Та и зачем вам скорость и вообще все эти С++ прибамбасы "<<" - чтобы мигать светодиодом? :)
На большее ESP8266 не годится. А примеры я приводил на другом чипе... т.к. на ESP в Arduino ничего не работает из типа такого [inline]cout << "std: Hello, world!" << endl;[/inline]
Да и вообще там проблем немерено. Пример - не распечатать uint64_t никаким методом :)
И если добить до поддержки C++ либ, то прошивка не лезет в простые модули ESP8266. Его XIP в 1 МБ не хватает + Flash для OTA нужна увеличенная.
 
Последнее редактирование:

pvvx

Активный участник сообщества
ESP-32S.
Код:
#include <iostream>
using namespace std;

void setup() {
  cout << "cout: Hello, world!" << endl;
  cerr << "cerr: Hello, world!" << endl;
  uint64_t x = 0xffffffffffffffff;
  cout << "uint64 x = " << x << endl;
}
void loop() {}
"Скетч использует 347563 байт (33%) памяти устройства. Всего доступно 1044464 байт."
Код:
....
cout: Hello, world!
cerr: Hello, world!
uint64 x = 18446744073709551615
Но только так можно напечатать uint64, затратив 300 КБ на ESP-32 :)
 

Сергей_Ф

Moderator
Команда форума
@AndrF, компиляция идёт компилятором с той же скоростью. Просто Ардуино ИДЕ считает, что надо перекомпилировать все библиотеки заново по малейшему поводу, а зачастую и без повода. Вот и собирает весь проект по новой.
 

pvvx

Активный участник сообщества
@AndrF, компиляция идёт компилятором с той же скоростью. Просто Ардуино ИДЕ считает, что надо перекомпилировать все библиотеки заново по малейшему поводу, а зачастую и без повода. Вот и собирает весь проект по новой.
Это зависит от описания. Скрипта по сборке. Обычно там разделено на создание не менее 3-х библиотек разных частей разделов, которые потом линкуются в единый итого...
А перекомпиляция делается при смене настроек. По другому поводу пока не заметил. Если смените тип интерфейса программирования, то меняются опции идущие на вход компиляции и среда не знает - есть ли там у вас зависимость от этого и пересобирает от греха подальше :)
А в vMicro видимо ничего не меняется и надо вручную пересобирать, как это принято для мощных сред... Сменили внешние define - тыкаете "пересобрать всё" в ручную. :)

Возможно в vMicro у вас включена многопоточная сборка... Это ускоряет обычно, на современных истинных многоядерниках до 10..25 раз сборку.Больше 25 раз выдавить пока не удалось на 10 ядрах... Так-же ускорение сборки дает использование RAM-диска. Дает ускорение ещё в 2 раза, в отличии от NVMe на PCIE. Скорость сборки gcc в Windows что с NVMe в за 3 ГигаБайта трафиком, что с IDE со 100 Мегайбайт трансфером одинакова. Причина почему, пока не установлена :)
Полная сборка с нуля всего проекта типа Arduino для ESP при многопотоке и RAM диске должна занимать около 3..4 секунуд (с выводом бинарников - там не параллелится) .
 
Последнее редактирование:

valerivp

Member
Замеры vMicro (+-3сек):
сборка проекта ESP8266 полная - 1мин
то же, многопоточная - 15 сек

изменение одного файла - от нажатия F5 до старта ESP - 25сек

полная пересборка при изменении глобального define - автоматическая
 

pvvx

Активный участник сообщества
Замеры vMicro (+-3сек):
сборка проекта ESP8266 полная - 1мин
то же, многопоточная - 15 сек

изменение одного файла - от нажатия F5 до старта ESP - 25сек

полная пересборка при изменении глобального define - автоматическая
150..200 файлов (после clean) (не учитывая сотни хидеров) полных исходников SDK на RTL, а не куцый ESP8266 с закрытыми либами, занимает 5..6 сек на дешевом Ryzen 1700x (Win10, компиляция в среде WSL, типа-рам диск):
https://esp8266.ru/forum/threads/moj-sborschik-i-flesher.2268/page-12#post-43498
в одиночный поток - что-то к минуте... (там в SDK вообще более 1700 файлов *.c и *.h)
Заливка и запуск проекта (для теста - web-свалка) в модуль - Eclipse: Build Finished (took 4s.428ms)
Всё без разгонов и каких-то спец. извращений. Не нужны они на постоянно работающих (годами) компах...
Пытаюсь ещё ужать раза в два и есть на то резервы... Сегодня ещё один шаг оптимизации по сборке долепил... Выйдет на данном компе к 5 сек всё, если с нуля проект в первый раз собирать... SSD/NVMe не сильно помогают. На них к 10 сек сборка, как и на простом HDD. Причуда Windows по "кешированию" дисков...
 
Последнее редактирование:
Сверху Снизу