ESP8266 CCLOCK Странное поведение

Я пытаюсь написать очень быстрый код для ESP8266, поэтому я пытаюсь понять, как рассчитать время. Я обнаружил CCLOCK, регистр, который отражает количество тактов с момента запуска. (https://github.com/esp8266/Arduino/issues/4632#issuecomment-380632906 и другие ссылки.) Однако при тестировании я столкнулся с некоторым странным поведением. Рассмотрим следующий код:

static inline volatile uint32_t asm_ccount(void) {
    uint32_t r;
    asm volatile ("rsr %0, ccount" : "=r"(r));
    return r;
}

char outgoingPacket[4];

...

void loop() {

  // ... некоторые вещи ...

  uint32_t startTime = asm_ccount();
  uint32_t stopTime = asm_ccount();
  uint32_t elapsed = stopTime-startTime;
  
  outgoingPacket[0] = (elapsed >> 24) & 0xff;
  outgoingPacket[1] = (elapsed >> 16) & 0xff;
  outgoingPacket[2] = (elapsed >> 8) & 0xff;
  outgoingPacket[3] = elapsed & 0xff;
  Udp.beginPacket(targetUdpIp, targetUdpPort);
  Udp.write(outgoingPacket, 4);
  Udp.endPacket();
}

(На моем компьютере для получения этих сообщений запущен в основном следующий код Java:)

    while (true) {
      DatagramPacket packet = new DatagramPacket(buf, buf.length);
      socket.receive(packet);

      byte[] data = packet.getData();
      StringBuilder sb1 = new StringBuilder();
      StringBuilder sb2 = new StringBuilder();
      for (int i = 0; i < packet.getLength(); i++) {
        sb1.append(String.format("%8s", Integer.toString(((int) data[i]) & 0xFF, 2)).replace(' ', '0'));
        sb2.append(String.format("%2s", Integer.toString(((int) data[i]) & 0xFF, 16)).replace(' ', '0'));
      }
      System.out.println(sb1 + " " + Integer.parseInt(sb2.toString(), 16));
    }

(Да, я знаю, это немного хакерски, но результаты кажутся правильными.)

Теперь в большинстве случаев результат выглядит так

00000000000000000000000000000001 1
00000000000000000000000000000001 1
00000000000000000000000000000001 1
00000000000000000000000000000001 1
00000000000000000000000000000001 1
00000000000000000000000000000001 1

Но примерно в 5 разах из 77 000 я получу такие строки, как

00000000000000000000000000000001 1
00000000000000000000000000000001 1
00000000000000000000000110101000 424
00000000000000000000000000000001 1
00000000000000000000000000000001 1
...
00000000000000000000000000000001 1
00000000000000000000000000000001 1
00000000000000000000010010100001 1185
00000000000000000000000000000001 1
00000000000000000000000000000001 1
...
00000000000000000000000000000001 1
00000000000000000000000000000001 1
00000000000000000000010001001100 1100
00000000000000000000000000000001 1
00000000000000000000000000000001 1

Я выполнял код в течение 1 минуты 4 секунд и получил 3 счета из 424, 1 из 1100 и 1 из 1185. Кажется особенно странным, что 424 появляется три раза.

Учитывая, что, насколько я понимаю, соответствующие строки кода (два вызова asm_ccount) должны были быть скомпилированы с заданным набором инструкций, я ожидал, что это займет каждый раз точно такое же количество циклов.

Почему этого не происходит?

Это прерывает? Что-то кэширует? Этот регистр на самом деле не работает, как заявлено или как я понимаю? Я сделал что-то глупое в коде передачи или регистрации? Что-то еще?

, 👍0

Обсуждение

У вас есть прерывания, которые прерывают ваш код. Для их запуска требуется несколько циклов., @Delta_G

Ах ах! Я думаю ты прав. Когда я отключаю прерывания вокруг критического кода, его синхронизация становится почти идеально стабильной. ...Но затем он перестает работать после нескольких десятков циклов, так что я не могу этого сделать, ха-ха. Если вы хотите сделать свой комментарий ответом, я приму его., @Erhannis


1 ответ


Лучший ответ:

1

У вас есть прерывания, которые прерывают ваш код. Для их выполнения требуется несколько циклов.

,