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

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

pvvx

Активный участник сообщества
Ещё раз напомню мою задачу - фиксировать разность по времени с точностью 5мкс (20мкс) срабатывание 2-х сенсоров(пъезо+RC trigger) на 2-х ЕСПках, которые подключены к GPIO прерыванию.
Как тама дела?
Подарите Nicolz iPerf - iPerf3 and iPerf2 user documentation - пусть наслаждается... :) Он умеет вычислять джиттер и прочее на UDP/TCP...

Arduino ESP. Джиттер программного Таймера.
Снимок1114.gif
Скетч:

Код:
#include <ESP8266WiFi.h>
#include <myAP.h>
//const char* ssid     = "your-ssid";
//const char* password = "your-password";

extern "C" {
#include "user_interface.h"
}

uint32_t time_us;
ETSTimer timer;

void TimerFunc(void *timer_arg) {
  time_us = system_get_time();
}


void setup() {
  Serial.begin(38400);
  Serial.println();
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  os_timer_setfn(&timer, TimerFunc, NULL);
  os_timer_arm(&timer, 111, 1);
}

uint32_t time_old;

void loop() {
  if (time_old == time_us) delay(50);
  else {
    time_old = time_us;
    Serial.println(time_old);
  }
}
Максимальное отклонение за время теста 1895866 us. Т.е. 1.8 секунды не было вызова процедуры таймера.
Приписка volatile к переменной time_us не меняет показания, но желательна...
 
Последнее редактирование:

pvvx

Активный участник сообщества
Отклонения вывода в analogWrite().
По умолчанию период ШИМ ~1.003ms.
Считываем первые попавшие 4 периода в осциллограф с дискретизацией 2Gs/s и децимируем в 125 MHz, чтобы обработать в Exel.
Получаем джиттер периода:
Снимок1115.gif
Скетч:
Код:
#include <ESP8266WiFi.h>
#include <myAP.h>
//const char* ssid     = "your-ssid";
//const char* password = "your-password";
void setup() {
  Serial.begin(38400);
  Serial.println();
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  pinMode( 12, OUTPUT );
  analogWrite( 12,33 );
}

void loop() {
  delay(1000);
}
Хоть что-нибудь могли китайцы из Espressif сделать нормально?
 

nikolz

Well-known member
Как тама дела?
Подарите Nicolz iPerf - iPerf3 and iPerf2 user documentation - пусть наслаждается... :) Он умеет вычислять джиттер и прочее на UDP/TCP...
идя на встречу вашим пожеланиям, сделал тест на вашем "оригинальном решении"
тест элементарный.
поясняю для тех кто в танке
В ESP1 по прерываниям таймера каждую секунду читаю значение вашей функции
T1=get_tsf_station(); и передаю его по UDP ESP2
В eSP2 читаю значение T3=get_tsf_station();
При получении первого значения T1, запоминаю это значение и значение T3 для этого момента для приведения к единой базе.
Все последующие значения времени T1 и T2 вычисляются за вычетом начальных значений.
Далее вычисляем Ваш любимый джиттер DT=T3-T1.
вот Вам и получаемая точность синхронизации:
T1=0 T3=0 DT=0
T1=1000002 T3=1000005 DT=3
T1=2000000 T3=1999551 DT=-449
T1=3000002 T3=3002084 DT=2082
T1=4000000 T3=3999456 DT=-544
T1=5000002 T3=4999368 DT=-634
T1=6000002 T3=5999935 DT=-67
T1=7000002 T3=6999694 DT=-308
T1=8000000 T3=8001098 DT=1098
T1=9000002 T3=9000678 DT=676
T1=10000000 T3=10000180 DT=180
T1=11000002 T3=10999782 DT=-220
T1=12000000 T3=12074536 DT=74536
T1=13000002 T3=13000969 DT=967
T1=14000000 T3=14018757 DT=18757
T1=15000002 T3=15000870 DT=868
upload_2017-1-3_23-40-21.png
Как видим результат еще тот. Бывает...
 
Последнее редактирование:

pvvx

Активный участник сообщества
идя на встречу вашим пожеланиям, сделал тест на вашем "оригинальном решении"
тест элементарный.
поясняю для тех кто в танке
В ESP1 по прерываниям таймера каждую секунду читаю значение вашей функции
T1=get_tsf_station(); и передаю его по UDP ESP2
В eSP2 читаю значение T3=get_tsf_station();
При получении первого значения T1, запоминаю это значение и значение T3 для этого момента для приведения к единой базе.
Все последующие значения времени T1 и T2 вычисляются за вычетом начальных значений.
Далее вычисляем Ваш любимый джиттер DT=T3-T1.
вот Вам и получаемая точность синхронизации:
T1=0 T3=0 DT=0
T1=1000002 T3=1000005 DT=3
T1=2000000 T3=1999551 DT=-449
T1=3000002 T3=3002084 DT=2082
T1=4000000 T3=3999456 DT=-544
T1=5000002 T3=4999368 DT=-634
T1=6000002 T3=5999935 DT=-67
T1=7000002 T3=6999694 DT=-308
T1=8000000 T3=8001098 DT=1098
T1=9000002 T3=9000678 DT=676
T1=10000000 T3=10000180 DT=180
T1=11000002 T3=10999782 DT=-220
T1=12000000 T3=12074536 DT=74536
T1=13000002 T3=13000969 DT=967
T1=14000000 T3=14018757 DT=18757
T1=15000002 T3=15000870 DT=868
Посмотреть вложение 2957
Как видим результат еще тот. Бывает...
Где код :) Нарисовали сами :)
Читать то умеете или только рисовать? :)
Как видим, даже по вашему графику, что точность моей get_tsf_station превышает точность хода вашей единой базы.
Уже хорошо. Теперь учтите что писалось далее, после выдачи кода get_tsf_station(). Тут вам надо прочитать что писалось... Попробуйте... :p Пересильте себя и поймете, по чему ваш тест некорректен.
А так замечательный график - показывает что в вашем варианте SDK от Espressif запреты прерывания достигают 74 ms.
Припаивайте дополнительный MCU и передавайте из него время с привязкой событий хоть по UART в ESP. Тогда, приняв достоверные данные и передав, задержка пересылки по WiFi и всякие кривости китайского-бредо-SDK не повлияют. В функцию cnx_update_bss_mor_() втавляете передачу счетчика TSF по AURT внешнему микроконтроллеру и получаете ждиттер в +-1us.
 
Последнее редактирование:

pvvx

Активный участник сообщества
При старте модуля настраиваете UART на максимальный baud, который примет внешний MCU.
Далее в wifi_tsf.c меняете и/или добавляете:
Код:
//===============================================================================
// save_tsf_station()
//-------------------------------------------------------------------------------
void ICACHE_FLASH_ATTR cnx_update_bss_more(int a2,  struct ieee80211_scanparams *scnp, void *a4)
{
#if 0 // external MCU
    //ets_intr_lock();
    recv_tsf_time = *((volatile uint32 *)MAC_TIMER64BIT_COUNT_ADDR);
    os_memcpy((void *)&recv_tsf, (void *)scnp->tstamp, 8);
#else
    UART1_FIFO = 0x55; // ID
    UART1_FIFO = scnp->tstamp[0];
    UART1_FIFO = scnp->tstamp[1];
    UART1_FIFO = scnp->tstamp[2];
    UART1_FIFO = scnp->tstamp[3];
#endif
    //ets_intr_unlock();
    cnx_update_bss_mor_(a2, scnp, a4);
}
Пока только так можно исправить ситуацию в ESP8266 созданную бессознательными программерами из Espressif :mad:
Да и кому он нужен этот кривой и древний ESP8266
 
Последнее редактирование:

pvvx

Активный участник сообщества
В RTL871x есть системная функция в wifi_ind.c:
void wifi_indication( WIFI_EVENT_INDICATE event, char *buf, int buf_len, int flags)
Она вызывается сразу после приема каждого baecon от AP после установки соединения - WIFI_EVENT_BEACON_AFTER_DHCP.
Её джиттер около +-10us и время после фронта конца beacon около 150 us, т.к. она не рассчитана на передачу TSF - служит для информационных целей. Но можно запросить значение уже установленного таймера - там джиттер меньше...
Снимок1116.gif
Вставка в функцию wifi_indication() использованная в тесте:
Код:
        case WIFI_EVENT_BEACON_AFTER_DHCP:
#if(WIFI_INDICATE_MSG>1)
            printf("%s(): WIFI_EVENT_BEACON_AFTER_DHCP\n", __func__);
#endif
#if 1 // test beacon
            gpio_write(&gpio_led, 1);
            gpio_write(&gpio_led, 0);
#endif       
            break;
Т.е. опять наблюдается различие в ПО от Espressif и Realtek. В Realtek даже думать не требуется - всё уже есть готовое... :(
Задание приоритетов прерываний и задач - это обязательное условие работы RTOS... :( Можно задать и приоритет исполнения драйвера WiFi...
Как я понимаю принятый TSF сидит в структуре mlme_ext_priv
Код:
struct __attribute__((aligned(2))) mlme_ext_priv
{
  _adapter *padapter;
  uint8_t mlmeext_init;
  atomic_t event_seq;
  uint16_t mgnt_seq;
  uint8_t cur_channel;
  uint8_t cur_bwmode;
  uint8_t cur_ch_offset;
  uint8_t cur_wireless_mode;
  uint8_t max_chan_nums;
  RT_CHANNEL_INFO channel_set[14];
  uint8_t basicrate[13];
  uint8_t datarate[13];
  ss_res sitesurvey_res;
  mlme_ext_info mlmext_info;
  _timer survey_timer;
  _timer link_timer;
  uint16_t chan_scan_time;
  uint8_t scan_abort;
  uint8_t tx_rate;
  uint8_t retry;
  uint64_t TSFValue; <-------- тут?
  unsigned __int8 bstart_bss;
  uint16_t action_public_rxseq;
  _timer reconnect_timer;
  uint8_t reconnect_deauth_filtered;
  uint8_t reconnect_times;
  uint8_t reconnect_cnt;
  uint16_t reconnect_timeout;
  uint8_t saved_alg;
  uint8_t saved_essid[33];
  uint8_t saved_key[32];
  uint16_t saved_key_len;
  uint8_t saved_key_idx;
  uint8_t saved_wpa_passphrase[65];
  uint8_t saved_eap_method;
  uint8_t auto_reconnect;
  uint8_t partial_scan;
  p_cus_ie cus_ven_ie;
  uint8_t ie_num;
  uint8_t bChDeauthDisabled;
  uint8_t bConcurrentFlushingSTA;
};
 
Последнее редактирование:

pvvx

Активный участник сообщества
Пока дальше не сдвинулся. Не понимаю где вставлять ets_intr_lock()/ets_intr_unlock()
Немного почищу свой код и выложу.
Пока думается, что просто так не справимся. Глушить WiFi мы не можем - она принимает beacon. Перенаправить прерывание от i/o на NMI тоже не может - нет описания регистров по данной теме. Переназначить приоритет прерываний - может и возможно, но как это сделать в Arduino :)
Espressif прогарммеры, имея все исходники, долго плясали чтобы сделать более менее ровный ШИМ вывод - перенаправили всю таблицу векторов CPU и вставили туда NMI. Но и он у них скачет, даже на звук слышно... :( Выходит, что вашу задачу проще решить используя дополнительный внешний MCU. В ESP нет никакой возможности получить дискретность внешнего события с точностью +-50us из-за кривизны в SDK.
 
Последнее редактирование:

sasasa

Member
Код:
//ESP8266
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <osapi.h>
//#define STA //STA mode, if commented - AP mode

extern "C" {
#include "user_interface.h"
  uint64_t get_tsf_station(void) ICACHE_FLASH_ATTR; // step 1 us
  uint64_t get_mac_time(void)ICACHE_FLASH_ATTR; // step 1 us
}

const char* ssid = "sensor_AP";
const char* password = "12345678";
int printed = 0;
int inPin = 2;// test button
float power = 0.0;//@param dBm max: +20.5dBm  min: 0dBm
volatile uint64_t get_time;
uint64_t prev = 0;
char packetBuffer[64]; //buffer to hold incoming packet,
#ifdef STA
//unsigned int listenPort = 8000;
unsigned int sendPort = 9000;
#else
unsigned int listenPort = 9000;
//unsigned int sendPort = 8000;
#endif
char bufChar[21];
WiFiUDP Udp;
IPAddress sendIP1(192, 168, 4 , 1);
//---------------------------
void IntToChar(uint64_t value) {
  const int NUM_DIGITS    = log10(value) + 1;
  bufChar[NUM_DIGITS + 1];
  bufChar[NUM_DIGITS] =  0;
  for ( size_t i = NUM_DIGITS; i--; value /= 10) {
    bufChar[i] = '0' + (value % 10);
  }
  //#ifdef STA
  Serial.print(bufChar);
  //#endif
}
//---------------------------
void ICACHE_FLASH_ATTR GetTime() {
#ifdef STA
  if (get_time == 0)get_time = get_tsf_station();
#else //AP
  if (get_time == 0) get_time = get_mac_time();
#endif
}
//---------------------------
int64_t charTo64bitNum(char *str) {
  int64_t result = 0; // Initialize result
  // Iterate through all characters of input string and update result
  for (int i = 0; str[i] != '\0'; ++i)
    result = result * 10 + str[i] - '0';
  return result;
}
//---------------------------
void setup() {
  Serial.begin(115200);
  delay(2000);
  Serial.println();
#ifdef STA
  Serial.println("---------STA  mode------------");
#else
  Serial.println  ("----------AP mode------------");
#endif

  WiFi.setOutputPower(power);
  Serial.print("WiFi output power: "); Serial.println(power);
  WiFi.disconnect();

#ifdef STA
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
#else //AP
  WiFi.softAP(ssid, password);
  while (!Udp.begin(listenPort)) {
    delay(5);
    Serial.print("-");
  }
#endif
  wifi_set_sleep_type(NONE_SLEEP_T);
  pinMode(inPin, INPUT_PULLUP);
  attachInterrupt(inPin, GetTime, FALLING);
  Serial.print("GPIO interrupt enabled at "); Serial.print(inPin); Serial.println(" pin");
  get_time = 0;
}

//---------------------------
void loop() {
  if (get_time > 0) {
    IntToChar(get_time);
    printed = 1;
    prev = get_time;
#ifdef STA
    Udp.beginPacket(sendIP1, sendPort);
    Udp.write(bufChar);
    Udp.endPacket();
    for (int i = 0; i < 20; i++) {
      bufChar[i] = '0';
    }
    Serial.println();
#else
    Serial.print("  ");
#endif
    delay(200);//button debounce
    get_time = 0;
  }
#ifndef STA
  uint8_t packetSize = Udp.parsePacket();
  if (packetSize) {
    Udp.read(packetBuffer, 64);
    uint64_t tt =  charTo64bitNum(packetBuffer);
    uint64_t dif = prev - tt;
    if (printed == 1) {
      Serial.write(packetBuffer, packetSize);
      Serial.print("  ");
      if (dif < 4294967295)Serial.print((long)dif);
      else
        Serial.print("ERROR"); Serial.println("");
      printed = 0;
    }
  }
#endif
  delay(2);
}
Тут код которым пробую. в нём надо тоже вставлять ets_intr_lock()/ets_intr_unlock()?

Пока думается, что просто так не справимся. Глушить WiFi мы не можем - она принимает beacon
Если в 20-25мкс уложится, то для начала будет нормально. Если нет, то придётся рядом Ардуинку ставить для обработки прерывания от GPIO
Или же вообще отказатся от ЕСПки и делать на nRF24 или SI4432
 
Последнее редактирование:

sasasa

Member
Какое то время разброс меньше, но через какое то время опять.

ap-sta_4.JPG
 

Вложения

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

sasasa

Member
Какие то странные скачки среднего значения сдвига если на какое то время не пересылать/незапрашивать тсф.
В графике (mac_ap - sta_tsf) -1200мкс
Перед тем участком, который подчёркнут, была пауза 5 минут, после опять пауза - после пика вниз, среднее значение графика подскачила в верх
ap-sta_5.JPG
 
Последнее редактирование:

nikolz

Well-known member
Где код :) Нарисовали сами :)
Читать то умеете или только рисовать? :)
Как видим, даже по вашему графику, что точность моей get_tsf_station превышает точность хода вашей единой базы.
Уже хорошо. Теперь учтите что писалось далее, после выдачи кода get_tsf_station(). Тут вам надо прочитать что писалось... Попробуйте... :p Пересильте себя и поймете, по чему ваш тест некорректен.
А так замечательный график - показывает что в вашем варианте SDK от Espressif запреты прерывания достигают 74 ms.
Припаивайте дополнительный MCU и передавайте из него время с привязкой событий хоть по UART в ESP. Тогда, приняв достоверные данные и передав, задержка пересылки по WiFi и всякие кривости китайского-бредо-SDK не повлияют. В функцию cnx_update_bss_mor_() втавляете передачу счетчика TSF по AURT внешнему микроконтроллеру и получаете ждиттер в +-1us.
-----------------------------------------------
Вы читать не умеете , я Вам написал весь алгоритм.
Для тех, кто в танке пишу основной код (Инициализацию полагаю можете написать )
====================
ESP1
код колбек функции для таймера с интервалом 1 секунда:

Код:
void timer_cb(void *arg){
       uint64 X=get_tsf_station();  //это функция pvvx
    err=espconn_sendto(&espcon,(char *)&X,sizeof(X));  //посылка сообщения
    }
=========================
ESP2 код колбек функции приема сообщения:
Код:
uint64 T1,T2,T3,T4;
int32 DT;
void udp_recv_cb (void *arg,char *pdata,unsigned short _len){
    os_memcpy(&T1,pdata,_len);
    T1=T1-T2; if (T2==0 ){ T2=T1; T1=0; DT=0; T4=0;}
    T3=get_tsf_station(); //это функция pvvx 
    T3=T3-T4; if (T4==0 ) {T4=T3; T3=0; DT=0;}
    DT=T3-T1;
    itoa64(T1,sbuf); os_printf(" T1="); os_printf(sbuf); 
    itoa64(T3,sbuf);os_printf(" T3="); os_printf(sbuf);
}  //принять сообщение
================================
Теперь о грустном.
Вот график синхронизации часов с уравнением линии.
upload_2017-1-4_10-14-43.png
Как я написал ранее(без использования функции pvvx)имеем систематическую ошибку часов.
Ее уравнение y(мкс)=55.784*ч(сек);
Величина 1541 мкс - это задержка доставки UDP.
------------------------------
Т е использование TSF не устраняет систематическую ошибку, которая составляет 55 мкс на 1 секунду работы ESP
Устранить эту ошибку можно лишь предложенным мною ранее алгоритмом.
 

nikolz

Well-known member
поясняю источник ошибки.
При привязке к базе (это либо TSF либо системное время третьей ESP) у сенсеров имеем значение времени системных часов состоящее из двух слагаемых:
1 слагаемое - это константа базы на интервале 100 мс
2 слагаемое - *((volatile uint32 *)MAC_TIMER64BIT_COUNT_ADDR) - это переменное значение счетчика часов ESP.
второе слагаемое и дает систематическую ошибку( у меня это 55.4 мкс на секунду) на других ESP может быть и иное.
 

pvvx

Активный участник сообщества
поясняю источник ошибки.
При привязке к базе (это либо TSF либо системное время третьей ESP) у сенсеров имеем значение времени системных часов состоящее из двух слагаемых:
1 слагаемое - это константа базы на интервале 100 мс
2 слагаемое - *((volatile uint32 *)MAC_TIMER64BIT_COUNT_ADDR) - это переменное значение счетчика часов ESP.
второе слагаемое и дает систематическую ошибку( у меня это 55.4 мкс на секунду) на других ESP может быть и иное.
Это известно и если разница хода в "55.4 мкс на секунду", то при следовании beacon в 0.1 секунду получаем максимальное отклонение 5.54 мкс.
За десять beacon-ов вполне нормально рассчитывается коррекция разности хода часов и отметаются выпадения (т.е. суммируются и участвуют в расчете и коррекции ухода таймера).
 

pvvx

Активный участник сообщества
При подаче с внешнего генератора сигнала с периодом 55.555555 ms :
Снимок114.gif
По спаду фронта сигнала на пине ESP, в прерывании, смотрим разницу счетчика TSF с прошлого и передаем её для процедуры вывода в UART:
Код:
uint32 cur_tsf = recv_tsf + *((volatile uint32 *)MAC_TIMER64BIT_COUNT_ADDR);
        system_os_post(GPIOs_intr_TASK_PRIO, GPIOs_intr_SIG_DELTA, cur_tsf - old_tsf);
        old_tsf = cur_tsf;
Снимок1118.gif
Итоговая дисперсия 2-тысяч замеров - расхождение каждого замера от 55555.5 us
Снимок1117.gif
График без обрезки, но стоит примитивная коррекция в процедуре приема TSF - ограничение на +-6 us поправки счета TSF за период 102.4 ms. Более 5 us за период beacon часы у моей ESP не уходят от AP ASUS-RT-N56U, но тормозят примерно на 5 us в 0.1 сек. На графике
среднее значение отклонения -0,42556222 us для периода в 55555.5 us.
Период 55.. выбран для не кратности коррекции и приема TSF - для вылавливания максимума разброса.

Итого: при использовании нормальной коррекции в процедуре приема tsf и отдачи приложению получаем точность к +-1 us. Для такой точности так-же необходимо учитывать кривизну китай-SDK по описанным ранее бедам - прерываниям любых процессов с запретом прерываний до сотен ms.

PS: @sasasa- окончательного кода с нормальной коррекцией счетчика от меня наверно не будет. Подробные примеры даны и математика там не сложная. Но, необходимо дать возможность другим проявить свои соображения – среди Arduin-щиков существует масса любителей поставить свой (c). Таким образом я избегу соучастие в бардаке. :p
Если у вас сложности с заменой obj в либах, то вписав:
extern "C" volatile uint64 recv_tsf; // принятый TSF от внешней AP
extern "C" volatile uint32 recv_tsf_time; // время приема TSF (младшие 32 бита)
вы можете получить всю необходимую информацию для программного фильтра TSF.
 
Последнее редактирование:

nikolz

Well-known member
При подаче с внешнего генератора сигнала с периодом 55.555555 ms :

PS: @sasasa- окончательного кода с нормальной коррекцией счетчика от меня наверно не будет. Подробные примеры даны и математика там не сложная. Но, необходимо дать возможность другим проявить свои соображения – среди Arduin-щиков существует масса любителей поставить свой (c). Таким образом я избегу соучастие в бардаке. :p
Если у вас сложности с заменой obj в либах, то вписав:
extern "C" volatile uint64 recv_tsf; // принятый TSF от внешней AP
extern "C" volatile uint32 recv_tsf_time; // время приема TSF (младшие 32 бита)
вы можете получить всю необходимую информацию для программного фильтра TSF.
Это Вы измерили уход частоты кварцевого генератора роутера .
Ну и что же получили? Кварцевый генератор работает стабильно? Надо же!!!
 

nikolz

Well-known member
Если у Вас получается погрешность 5 мкс, то как Вы объясните такие результаты эксперимента
-------------------------
На ESP 1 каждую секунду измеряем get_tsf_station() и отсылаем на ESP2; по UDP
Код:
void timer_cb(void *arg){
        T1=get_tsf_station();
  espconn_sendto(&espcon,(char *)&T1,sizeof(T1));  //посылка сообщения
    }
}  //колбек функция программного таймера
------------------------
На ESP2 принимаем время ESP1 и вычисляем разность DT -т е запаздывание времени ESP2 относительно ESP1
Мы ожидаем, что это запаздывание будет всегда положительным
---------------------
Код:
void udp_recv_cb (void *arg,char *pdata,unsigned short _len){
    T3=get_tsf_station();
    os_memcpy(&T1,pdata,_len);
    T1=T1-T2; if (T2==0 ){ T2=T1; T1=0; T4=0; }
    T3=T3-T4; if (T4==0 ) {T4=T3; T3=0; DT=0;  DX=0; }
    float DT=(float)T3-(float)T1;    int iDT=DT;
     itoa64(T1,sbuf); os_printf(" T1="); os_printf(sbuf);
    os_printf(" %d",iDT);    ets_uart_printf("\n");}  //принять сообщение
-------------------------------
upload_2017-1-5_12-37-51.png

Но в результате получаем и отрицательную задержку до 2200 мкс.
Это указывает на ошибку синхронности часов ESP примерно 4 мс(учитывая время прохождения пакета UDP), т е на три порядка больше.
--------------
Хочу обратить Ваше внимание, что проблема синхронизации беспроводных сетей существует и ее решение не такое тривиальное как Вы пытаетесь представить.
Посмотрите хотя бы патенты по методам решения этой проблемы и различные ухищрения в стандартах.
 
Последнее редактирование:

pvvx

Активный участник сообщества
Если у Вас получается погрешность 5 мкс, то как Вы объясните такие результаты эксперимента
-------------------------
На ESP 1 каждую секунду измеряем get_tsf_station() и отсылаем на ESP2; по UDP
Очень просто - нарушение атомарности в привязке времени считывания значения и привязки к событию. Так, как вы никто, кроме китайцев из Espressif не пишет. :)
 

pvvx

Активный участник сообщества
Это Вы измерили уход частоты кварцевого генератора роутера .
Ну и что же получили? Кварцевый генератор работает стабильно? Надо же!!!
Угу - стабильно дает отсчеты времени для всех участников сети. Это называется - синхронизация. Как итог, все события принятые с датчиков в сети привязаны к одному как вы выразились "кварцу" - к единому ходу времени. Что и требовалось получить. :p

Заскорузлось в мышлении не позволяет вам понять, что описание времени, хоть в микросекундах, для привязки к московскому требует применения математической функции :)

Если вы хотите узнать расхождение любых часов, то надо получить два числа – смотрите решение линейного уравнения. Тут я уже не могу вам помочь – пока не имею машинки времени с возможностью обработки обратных процессов над вашим организмом, чтобы отправить вас в ваши дошкольные времена... :)

Произведите перевод из одних единиц исчисления в другие, а не гудите, что TSF неверная. В предоставленном от Espressif кривом SDK нет возможности получения отсчета внешнего события менее средней точности в +-50 us с выпадениями до сотен ms. Это не моя заслуга, а ваша :)

Т.к. прерывания WiFi приоритетнее многих процессов, get_tsf_station() и дает показания точнее, чем пытаетесь получить в неправильно описанном и сформированном примере, демонстрируя это. Сами прерываете свои вычисления в любом месте кода, задавая систему работать по неверным алгоритмам. Пересылка пакета прерывает ваш код и другую отработку на указанные на вашем графике расхождения. Итог вашего измерения = кривости китай-SDK от Espressif + ваше разгильдяйство, а не значения TSF. :)
Хочу обратить Ваше внимание, что проблема синхронизации беспроводных сетей существует и ее решение не такое тривиальное как Вы пытаетесь представить.
Посмотрите хотя бы патенты по методам решения этой проблемы и различные ухищрения в стандартах.
Что и требовалось доказать - после влезания и ввода в систему таких кривых реализаций как ваши или от Espressif, починка требует коллосальных действий.
Изначальный стандарт (имеет тип “промышленный”) описывает достаточную для нас точность. Но он не реализован у Espressif, а введена кривизна и всё сделано кое-как. По этой причине Espressif нет в коалиции стандартизации WiFi. А блоггеров и почих, желающих ввести свой стандарт всегда достаточно. Они и опираются на кривые исполнения стандартов у других. :)
 
Последнее редактирование:

pvvx

Активный участник сообщества
В результате Вы получили погрешность 5 мкс для отдельно взятой собственной кухни.
А это и требовалось получить в задаче. Сколько страниц и исписанного текста, как вы это осознали.
Ваше то решение дало +-0.5 сек :) и даже применение Фильтр Калмана не помогает.
И не понятно, чем вас не устраивает синхронизация с точностью сравнимой с расхождением "кварцев" установленных на модулях?
Надо больше? Тогда дуплекс и Фильтры Калмана + эмуляция ФАПЧ.
Но тогда придется покопаться в приоритетах прерываний. Для этого вам надо изучить это:
Снимок1127.gif Снимок1128.gif
Это процедура из основного цикла NON_OS_SDK (функция из ets_run() в ROM-BIOS)
Надеюсь через пару лет освоите. :)
PS: на счет "снобизма"
 
Последнее редактирование:
Сверху Снизу