цифровая электроника
вычислительная техника
встраиваемые системы

 
» » » Как обрабатывать часто используемые функции с использованием Arduino Uno R3 и R4



Как обрабатывать часто используемые функции с использованием Arduino Uno R3 и R4

Автор: Mike(admin) от 5-02-2024, 03:55

Чтобы получить более быстрый доступ к значениям математических функций, вы часто предпочитаете хранить заранее рассчитанные значения в ОЗУ или ПЗУ. Можно ли это ускорить в Arduino Uno R4 по сравнению с версией R3?


Как обрабатывать часто используемые функции с использованием Arduino Uno R3 и R4

Вы можете часто видеть скетчи, которые начинаются с таких строк:


const PROGMEM char sine256[] = {128,130,133,136,139,143,146,149,152,


Они могут включать длинную таблицу значений синуса. Это очень полезно, поскольку вычисления во время выполнения возможны, но при использовании 8-битных контроллеров они выполняются очень медленно. Быстрый доступ к синусоидальным значениям может иметь решающее значение в аудиопроектах, когда вы не хотите выводить раздражающие прямоугольные звуки. Чтобы сэкономить драгоценное пространство в SRAM, лучше хранить эти константы во флэш-памяти с помощью PROGMEM.


Давайте сравним, что может предложить новый Arduino Uno R4 с контроллером RA4M1. Для этого теста мы реализовали две таблицы синусоидальных значений: одна рассчитывается во время компиляции (компилятором внутри ПК), загружается и сохраняется во флэш-памяти, а другая рассчитывается во время установки и сохраняется в SRAM. Оба сравнивались со значениями, рассчитанными во время выполнения.


Следующее изображение получено с помощью Arduino Uno R3.


Как обрабатывать часто используемые функции с использованием Arduino Uno R3 и R4

А следующий график получили уже с помощью Arduino Uno R4.


Как обрабатывать часто используемые функции с использованием Arduino Uno R3 и R4

Слева вы видите график синусоидальной функции от 0 до 360 градусов (от 0 до 2*PI). На графике отображено только 180 значений. Они были немного сдвинуты друг относительно друга, иначе вы бы увидели только один график.


Справа вы видите гистограмму времени, необходимого для доступа к значениям во FLASH, SRAM и их расчета. Как и ожидалось, вычисления требуют гораздо больше времени, чем чтение значений из памяти, но это соотношение намного ниже при использовании нового R4, поскольку внутри него имеется встроенный модуль вычислений с плавающей запятой. Можно увидеть еще одно отличие: при использовании R3 доступ к данным, хранящимся во флэш-памяти, происходит немного медленнее, чем доступ к данным в SRAM, тогда как при использовании R4 доступ к данным во флэш-памяти происходит значительно быстрее, чем чтение данных из SRAM.


Для проверки был использован следующий код:



#define M 360
#define RAD TWO_PI / M
#ifdef __AVR__
PROGMEM const
#endif
double sinCt[] = {
#include "sin.h"
};
const int N = M / 2;
const float rad2 = RAD * 2;

double sinSu[N];

void setup() {
  Serial.begin(9600);
  while (!Serial);
  Serial.println(__FILE__);
  for (int i = 0; i < N; i++)
    sinSu[i] = sin(i * rad2);
  Serial.println("compile-time setup run-time");
#ifdef __AVR__
  int F = 20000;
  int G = 500;
#else
  int F = 1000;
  int G = 20;
#endif
  for (int i = 0; i < N; i++) {
    /*
      Serial.print(i * RAD);
      Serial.print(" ");
    */
#ifdef __AVR__
    Serial.print(F * pgm_read_float(&sinCt[i]));
#else
    Serial.print(F * sinCt[i]);
#endif
    Serial.print(" ");
    Serial.print(F * sinSu[i] + G);
    Serial.print(" ");
    Serial.print(F * sin(i * rad2) - G);
    Serial.println(" 0");
  }
  int t0 = getValue(0, 0) * N;
  for (byte i = 1; i <= 3; i++) {
    int t = getTime(i) - t0;
    for (int j = 0; j < 105; j++) {
      for (byte k = 1; k <= 3; k++)
        if (k == i) Serial.print(t);
        else Serial.print(" 0 ");
      Serial.println(" 0");
    }
  }
  Serial.println("0 0 0 0\n0 0 0 0");
}

void loop() {}

int getTime(byte s) {
  long t1, t2;
  float dummy1 = 0;
  float dummy2;
  t1 = micros();
  for (int i = 0; i < N; i++)
    dummy1 = dummy1 + getValue(s, i);
  t2 = micros();
  if (dummy1 > 1) Serial.println("error");
  return t2 - t1;
}

float getValue(byte s, int i) {
  switch (s) {
    case 0: return 0;
    case 1: return pgm_read_float(&sinCt[i]);
    case 2: return sinSu[i];
    case 3: return sin(i * rad2);
  }
}

Файл sin.h:



sin(__COUNTER__ * RAD),
#if __COUNTER__ < M
#include __FILE__
#endif



© digitrode.ru


Теги: Arduino




Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

Комментарии:

Оставить комментарий