• Система автоматизации с открытым исходным кодом на базе 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
 
Сверху Снизу