• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Синхронизация часов.

sasasa

Member
Пишите правильнее вывод 64-бит
Как это - правильнее? Что там не правильно?
Сколько проверял, именно Принт функцию, то никаких ошибок не было.
А уточнять адрес принятого TSF - это мне не по зубам. Наверное буду строить всё исходя из того что есть и что умею.
 

pvvx

Активный участник сообщества
Как это - правильнее? Что там не правильно?
Сколько проверял, именно Принт функцию, то никаких ошибок не было.
А уточнять адрес принятого TSF - это мне не по зубам. Наверное буду строить всё исходя из того что есть и что умею.
Проще всего это делается так: транслируете код. Берете заголовки из map файла. Смотрите память около указанной переменной в низ:
map файл:
Код:
 .bss           0x3ffed298      0x37e ../lib\libsdk.a(wl_cnx_patch.o)
                0x3ffed5f8                sta_con_timer
Включаем сканер - он показывает к примеру fixed.timestamp == 0x00000005B862D182
Смотрим память ESP:
Снимок27.gif
Потыкав перерисовку видим, что изменяется только эта переменная и совпадает со значением от сканера.
Находим смещение от sta_con_timer: 0x3ffed2b0 - 0x3ffed5f8 = -840(dec) = -0x384. Т.к. описываем массив в 8 байтах, то адрес выходит sta_con_timer[-840/8].
----
Но это всё уже глупости, т.к. вам указано где искать место для патча в либе...
----
А как вы описали вывод 64-х битной переменной в printf?
Я вот не наблюдаю ничего Google :)
Вики:
Значения типов:
d, i — десятичное знаковое число, размер по умолчанию, sizeof( int ).

64-ре бита - это не int, а long long.
u — десятичное беззнаковое число, размер по умолчанию sizeof( int );
Тоже не годится.

В либе для ESP8266 "Print.h" так-же не наблюдаю поддержку 64-ре бита - long long :)
 
Последнее редактирование:

sasasa

Member
А как вы описали вывод 64-х битной переменной в printf?
Я так выводил. Может и не самый удачный вариант, но вроде работает.
Код:
void Print(uint64_t value)
{
  const int NUM_DIGITS    = log10(value) + 1;
  char sz[NUM_DIGITS + 1];
  sz[NUM_DIGITS] =  0;
  for ( size_t i = NUM_DIGITS; i--; value /= 10)
  {
    sz[i] = '0' + (value % 10);
  }
  Serial.print(sz);
}
 

pvvx

Активный участник сообщества
Я так выводил. Может и не самый удачный вариант, но вроде работает.
Код:
void Print(uint64_t value)
{
  const int NUM_DIGITS    = log10(value) + 1;
  char sz[NUM_DIGITS + 1];
  sz[NUM_DIGITS] =  0;
  for ( size_t i = NUM_DIGITS; i--; value /= 10)
  {
    sz[i] = '0' + (value % 10);
  }
  Serial.print(sz);
}
А (value %) точно пашет или опять баги? Компилятор для ESP то редко используемый... Это не ARM...
 

sasasa

Member
Не скажу конкретно про (value %) , так как в Serial.print это работало.. Но сколько этой функцией тестовых цифр выводил пока всё правильно было.
Вот только как прибавить, убавить, умножать или делить uint64, я так и не понял :confused:
 
Последнее редактирование:

pvvx

Активный участник сообщества
Проверяйте (усё включено):
Перед использование не забываем вырубить все кривые китай-фичи типа WiFi-sleep = MODEM. Ставим NONE и т.д.
Исходники - по ранее объявленным условиям :)

Заголовки:
Код:
extern uint64 get_mac_time(void) ICACHE_FLASH_ATTR; // step 1 us
#define get_tsf_ap() get_mac_time()
extern uint64 get_tsf_station(void) ICACHE_FLASH_ATTR; // step 1 us
Либа для замены к SDK 1.5.4:
 

Вложения

Последнее редактирование:

pvvx

Активный участник сообщества
Спасибо. Буду пробовать.
C++ не желателен - он юзает alloc mem и прочее с долгими запретами прерываний. Прием WiFi будет дрожать...

Дельты в us между запросами (т.е. скорость обработки) через websocket wifi_st_tsf и wifi_ap_tsf (и их текущие значения):
Снимок36.gif
(вертикальная) millisPerLine = 2000
Тормозит javascript - менее 5 ms не тянет очередность обработки текстовых запросов...
Идут два чередующихся запроса wifi_st_tsf и wifi_ap_tsf, график заполняется историей и притормаживает javascript - стартует примерно на 3 ms (1.5 между запросами).
Arduino в пролете - это websocket из web-свалки...
Гуру Nikolz хотел узнать биения приема-передачи пакетов в WiFi (вашими руками) - это оно и есть :)
 
Последнее редактирование:

pvvx

Активный участник сообщества
У двух модулей соединены GPIO0 входы и по прерыванию изменения они записывают значение get_tsf_station() (данные ячеек 83,84,85,86) + увеличивают счетчик (ячейка 82):
Снимок37.gif
В modbus ячейки 16-ти битные.
Разница штампа времени доходит до 100 us, но чаще совпадает. Причина известна - запрет прерываний на данный промежуток с копошением в китай-либе. Подробнее про подобные китай-фичи тут: Вопрос - Почему тормозит контроллер?
Так-же одновременно работает web-сервер - у него опрашивается таблица, показанная на картинке - 100 ячеек через Ajax. А он использует alloc/free - эти функции запрещают прерывание и часто долго отрабатывают (по этому и не рекомендуется C++ - там это бесконтрольно).
На всякий случай код использованного оверлея для web-свалки
Код:
/*
 *     gpio_isr.c
 *    По просьбе трудящихся.
 *      Author: pvvx
 */
#include "user_config.h"
#include "bios.h"
#include "hw/esp8266.h"
#include "hw/eagle_soc.h"
#include "user_interface.h"
#include "flash_eep.h"
#include "web_iohw.h"
#include "gpios_intr.h"

#include "ovl_sys.h"

#define GPIO_TEST1 mdb_buf.ubuf[80] // по умолчанию GPIO4
#define GPIO_INTR_INIT mdb_buf.ubuf[81] // флаг =1 - драйвер работает, =0 остановлен
#define GPIO_INT_Count1 mdb_buf.ubuf[82]
#define GPIO_TFS0 mdb_buf.ubuf[83] // время последнего INT
#define GPIO_TFS1 mdb_buf.ubuf[84] // время последнего INT
#define GPIO_TFS2 mdb_buf.ubuf[85] // время последнего INT
#define GPIO_TFS3 mdb_buf.ubuf[86] // время последнего INT


uint32 GPIO_INT_init_flg DATA_IRAM_ATTR;


static void GPIOs_intr_handler(void)
{
    uint32 gpio_status = GPIO_STATUS;
    GPIO_STATUS_W1TC = gpio_status;
    if(gpio_status & (1<<GPIO_TEST1)) {
        union {
            uint8 b[8];
            uint16 w[4];
            uint32 d[2];
            uint64 q;
        }x;
        x.q = get_tsf_station();
        GPIO_TFS0 = x.w[0];
        GPIO_TFS1 = x.w[1];
        GPIO_TFS2 = x.w[2];
        GPIO_TFS3 = x.w[3];
        GPIO_INT_Count1++;
       gpio_pin_intr_state_set(GPIO_TEST1, GPIO_PIN_INTR_ANYEDGE); // GPIO_PIN_INTR_POSEDGE | GPIO_PIN_INTR_NEGEDGE ?
    }
}


void ICACHE_FLASH_ATTR init_GPIOs_intr(void)
{
    if(GPIO_TEST1 > 15) {
        GPIO_TEST1 = 4;
    }
    uint32 pins_mask = (1<<GPIO_TEST1);
    gpio_output_set(0,0,0, pins_mask); // настроить GPIOx на ввод
    set_gpiox_mux_func_ioport(GPIO_TEST1); // установить функцию GPIOx в режим порта i/o
    ets_isr_attach(ETS_GPIO_INUM, GPIOs_intr_handler, NULL);
    gpio_pin_intr_state_set(GPIO_TEST1, GPIO_PIN_INTR_ANYEDGE); // GPIO_PIN_INTR_POSEDGE | GPIO_PIN_INTR_NEGEDGE ?
    // разрешить прерывания GPIOs
    GPIO_STATUS_W1TC = pins_mask;
    ets_isr_unmask(1 << ETS_GPIO_INUM);
    GPIO_INTR_INIT = 1;
    GPIO_INT_init_flg = 1;
    os_printf("GPIOs_intr init (%d) ", GPIO_TEST1);
}

void ICACHE_FLASH_ATTR deinit_GPIOs_intr(void)
{
    if(GPIO_INT_init_flg) {
        ets_isr_mask(1 << ETS_GPIO_INUM); // запрет прерываний GPIOs
       gpio_pin_intr_state_set(GPIO_TEST1, GPIO_PIN_INTR_DISABLE);
        GPIO_INTR_INIT = 0;
        GPIO_INT_init_flg = 0;
        os_printf("GPIOs_intr deinit (%d) ", GPIO_TEST1);
    }
}
//=============================================================================
//=============================================================================
int ovl_init(int flg)
{
    if(flg == 1) {
        if(GPIO_INT_init_flg) deinit_GPIOs_intr();
        init_GPIOs_intr();
        return 0;
    }
    else {
        deinit_GPIOs_intr();
        return 0;
    }
}
 
Последнее редактирование:

sasasa

Member
После старта STA MAC таймер меньше чем принятый TSF - MAC не синхронизируется по принятому TSF таймеру.
После рестарта АP принятое TSF время меньше чем STA MAC, но - STA MAC не синхронизируется с TSF.
Что то явно не так как бы хотелось :oops:
Ещё парочка вопросов:
КОТОРЫЙ из таймеров должен синхронизироваться по пришедшему TSF?
MacTim (0x3ff21004/08) и MacTim1 (0x3ff21048/4c) - кто есть кто? os_timer, hw_timer, frc_timer..
Что такое 0x3ff21058 - Там не надо ничего вкл/выкл чтобы происходила синхронизация таймеров?
 

Вложения

pvvx

Активный участник сообщества
После старта STA MAC таймер меньше чем принятый TSF - MAC не синхронизируется по принятому TSF таймеру.
После рестарта АP принятое TSF время меньше чем STA MAC, но - STA MAC не синхронизируется с TSF.
А какого фига они должны быть одинаковы?
Что то явно не так как бы хотелось :oops:
Ну не Московское время они показывают :) А именно то, что требуется для синхронизации.
Ещё парочка вопросов:
КОТОРЫЙ из таймеров должен синхронизироваться по пришедшему TSF?
MacTim (0x3ff21004/08) и MacTim1 (0x3ff21048/4c) - кто есть кто? os_timer, hw_timer, frc_timer..
Что такое 0x3ff21058 - Там не надо ничего вкл/выкл чтобы происходила синхронизация таймеров?
Берете нормальную AP - у неё время идет точно. Это не ESP. Получаете с неё get_tsf_station().
Местный аппаратный счетчик на ESP - это get_mac_time() от него берут начала другие таймеры в SDK - берут младшие 32 бита.

Если не нравиться - покупайте GPS с выводом времени. Только вы его на ESP считаете с меньшей точностью (с большим джиттером), чем вам уже выдано.

Проводом выйдет аналогичная точность - не более чем в два раза. Причины в самом ESP - его ПО. Думаю, что с поставленной в первом сообщении задачей вы не справитесь на Arduino. Проблемы не в счетчиках...
 
Последнее редактирование:

sasasa

Member
А какого фига они должны быть одинаковы?
After receiving the beacon frame all the stations change their local clocks to this time. (c) wiki
а который то таймер синхронизируется??
Местный аппаратный счетчик на ESP - это get_mac_time()
а что это - 0x3ff21004/08
 

pvvx

Активный участник сообщества
After receiving the beacon frame all the stations change their local clocks to this time. (c) wiki
а который то таймер синхронизируется??
Значение полученное по get_tsf_station().
а что это - 0x3ff21004/08
Тоже самое, но обрезанное на 32 бита и регистры управления данным аппаратным таймером. Там ещё есть регистры "будильника", когда главный счетчик будет равен записанному значению - произойдет прерывание...
Берете модуль в руки и прошиваете прошивкой из web-свалки.
Вбиваете адрес, смотрите и больше не пристаете с глупыми вопросами :)
Снимок39.gif
 
Последнее редактирование:

sasasa

Member
А можно как то выловить время (Mac таймера или в тиках со старта) записи очередного TSF от принятого beacon? Или прерывание по по нему получить?

Тоже самое, но обрезанное на 32 бита
там 64 бит - Low 32 bits 0x3ff21004, High 32bits 0x3ff21008
 
Последнее редактирование:

pvvx

Активный участник сообщества
А можно как то выловить время (Mac таймера или в тиках со старта) записи очередного TSF от принятого beacon? Или прерывание по по нему получить?
Ещё раз - get_tsf_station().
Всё включено - на выходе живые данные с шагом 1 us от хода TSF на AP пославшей beacon. Идут синхронно с TSF на AP.
там 64 бит - Low 32 bits 0x3ff21004, High 32bits 0x3ff21008
Это два значения одного и того-же. Пока читалось и ввыводилось прошло время... :)
Зачем вам регистры закрытого оборудования с неизвестными значениями и как управлять ими? :confused:
Вы просили счетчик с точностью +-1 us от центральной AP на модулях ESP. Это get_tsf_station(). На всех ESP подключенных к единой AP он будет одинаков в момент опроса на них, с указанными ранее расхождениями. Процессор тормоз и его работу прерывают разные процессы с запретами прерываний. Получить прерывание с внешнего устройства c точностью 1us у вас не выйдет. Для этого надо выключить все процессы, таймеры и прочее - использовать свой SDK. get_tsf_station(), дает максимальную точность при соблюдении нескольких условий - в своем приложении не вызываете из SDK процедуры с запретом прерываний (никаких работ C++ с любыми стрингами, запросов-освобождений памяти и т.д.) и постоянно отдаете управление распределителю процессов в ROM-BIOS - ets_run(). Тогда get_tsf_station() будет максимально точная.
Но у вас внешний датчик и обработка с него будет прерываться процессами WiFi на периоды более 100 us. Т.е. вы не сможете получить с датчика время сигнала точнее чем прерывающие ваш процесс процедуры. Get_tsf_station() дает значения точнее, чем вы сможете считать из неё и привязать к событию опроса своего датчика :)

Пример:
Вы установили прерывание на изменение I/O или приема символа по UART или SPI и т.д. В момент активности внешнего сигнала сработала обработка WiFi в SDK. Прерывание получения внешнего события выставилось, но у процессора они запрещены – он отрабатывает WiFi. Когда он закончит, (к примеру через 0..100 us – как совпало) то перейдет к вашей процедуре прерывания. И только тогда вы считаете get_tsf_station(), но внешний сигнал был до того… :) Работайте с приоритетами прерываний, но это уже не Arduino…
 
Последнее редактирование:

sasasa

Member
на выходе живые данные с шагом 1 us от хода TSF на AP пославшей beacon
Данные то живые но с обновлением 0.1сек. т.е. реальное разрешение всего 100000мкс. Получается у меня тут часы есть но секундная и минутная стрелки обломаны. :( Как только по часовой стрелке сказать точное время?
Чтобы получить синхронный таймер с точностью 5мкс, мне надо знать время прихода beacon или же прерывание от него. Иначе с какой опорной точки я буду отмерять время срабатывание сенсора и по каким признакам будет вычисляться коррекция? Сенсор то на STA находится, не на АP. Можно и ловить смену значения tsf, но это опят какие то погрешности. Разве нигде не фиксируется время прихода очередного beacon?
Может быт вы как то по другому это видите?
 

Вложения

Последнее редактирование:

pvvx

Активный участник сообщества
Данные то живые но с обновлением 0.1сек. т.е. реальное разрешение всего 100000мкс. Получается у меня тут часы есть но секундная и минутная стрелки обломаны. :( Как только по часовой стрелке сказать точное время?
Чтобы получить синхронный таймер с точностью 5мкс, мне надо знать время прихода beacon или же прерывание от него. Иначе с какой опорной точки я буду отмерять время срабатывание сенсора и по каким признакам будет вычисляться коррекция? Сенсор то на STA находится, не на АP. Можно и ловить смену значения tsf, но это опят какие то погрешности. Разве нигде не фиксируется время прихода очередного beacon?
Может быт вы как то по другому это видите?
Я не знаю что вы там пользуете. У меня никаких стрелок не обломано и шаг обновления вывода 1 us.
Данная вам функция уже всё фиксирует (определяет и фиксирует время прихода beacon + делает прибавку счетчика с частотой хода аппаратного таймера) - разрешение ответа 1 us.
Её ответ состоит из суммы 3-х значений: текущего времени - времени прихода beacon + значения TSF переданного в beacon.
 
Последнее редактирование:

pvvx

Активный участник сообщества
pvvx,
Ваши старания похожи на старания инженера NASA,
который пытается оказать помощь по телефону первокласснику,
который собирает на уроке труда ракету для полета на Марс.
---------------------------
Просвещение-дело благородное,
но результаты его будут лишь через десятилетия.
"А нам всё равно"... песня про зайцев :p
И вы опять ошиблись. Чел уже пишет, что врубился, что беаконы приходят каждые 100 ms, что надо фиксировать время его прихода и далее отсчитывать. Но пока не врубился, что ему всё это уже дали. А причина - Nikolz, не оплативший исходники. :p
 

pvvx

Активный участник сообщества
Я тоже рад Вас слышать.
Чувствуется, что у Вас хорошее настроение, так как китайцы не виноваты.
Виноваты - они не дают того, что я встроил в их либу путем патча их каки не поддерживающей никаких стандартов и посылающих людей с запросом такой вставки на годы. А так-же виноваты в распространении дерьма в виде ESP8266 не проходящего сертификацию и нарушающего все нормы в нашу страну. :p
 
Сверху Снизу