• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе 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: на счет "снобизма"
 
Последнее редактирование:
Сверху Снизу