LD.ехе:linker_script.ЛД:138 не может двигаться счетчика назад | ArduinoFFT об ошибке

Плате: Ардуино Нано 33 Бле смысле

Я потянув данные PCM из встроенного микрофона и запустить ее через библиотеку arduinoFFT (версия 1.5.6), чтобы получить спектрограмму. Поскольку библиотека arduinoFFT требует, чтобы данные были массивом двойников, я преобразовал данные из нескольких дважды, и начал процесс БПФ. БПФ.Многооконность() функция работает нормально, но я получаю ошибку в БПФ.Вычислить() вызов функции (строка 77). Ошибка исчезает, когда я удалить вызов функции. Ошибка:

Found 25 compatible libraries
Scanning dependencies...
Dependency Graph
|-- <arduinoFFT> 1.5.6
|-- <PDM> 1.0
Building in release mode
Linking .pio\build\nano33ble\firmware.elf
c:/users/benlu/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none- 
eabi/8.2.1/../../../../arm-none-eabi/bin/ld.exe:linker_script.ld:138 cannot move location counter 
backwards (from 000000002004a470 t
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\nano33ble\firmware.elf] Error 1

И код:

#include "Mic.h"
#include <arduinoFFT.h>



// FFT

arduinoFFT FFT = arduinoFFT(); /* Create FFT object */
/*
These values can be changed in order to evaluate the functions
*/
const uint16_t samples = 16128; //This value MUST ALWAYS be a power of 2
const double signalFrequency = 16000;
const double samplingFrequency = 16000;
const uint8_t amplitude = 100;
/*
These are the input and output vectors
Input vectors receive computed results from FFT
*/
double vImag[samples] = {0};


// buffer to read samples into, each sample is 16-bits
short* sample_buffer;

// number of samples read, read from Mic class on loop
volatile int samples_read;

// The length of the buffer to use. Currently set to 4 seconds.
int buffer_size = 16000;
double double_buffer[16384] = {};

// Instantiate
Mic mic;

// DO NOT PRINT INSIDE THIS FUNCTION - Causes it to hang.
void onPDMdata() {
  mic.sample();
}

void setup() {
  Serial.begin(115200);
  while (!Serial);
  PDM.onReceive(onPDMdata);
  PDM.setBufferSize(16128);

  Serial.println("3...");
  delay(1000); 
  Serial.println("2...");
  delay(1000);
  Serial.println("1...");
  delay(1000);  
  Serial.println("Listening!");               

  mic.begin();
}

void loop() {
  
  // wait for samples to be read
  samples_read = mic.samples_read();

  // If desired buffer size is reached.
  if (samples_read >= buffer_size) {
    // Retrieves audio buffer
    sample_buffer = mic.sample_buffer();

      // print samples to the serial monitor or plotter
      for (int i = 0; i < samples_read; i++) {
        double_buffer[i] = (double)(sample_buffer[i]); 
        Serial.println(double_buffer[i]);   
      }
    
    Serial.println("---------- SAMPLE BREAK ----------");

    FFT.Windowing(double_buffer, samples, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
    FFT.Compute(double_buffer, vImag, samples, FFT_FORWARD); /* Compute FFT <--------------------- THIS LINE */
    // FFT.ComplexToMagnitude(double_buffer, vImag, samples); /* Compute magnitudes */

    // delay for data collection only, comment when not collecting
    delay(1000);
    Serial.println("Listening!");
    
    // clear the read count and resume recording
    mic.clear_buffer();
  }
}

Где я могу начать устранять эту проблему? Мне раньше не приходилось сталкиваться с ошибками компоновщика, так что любые указатели будут очень ценны. Заранее спасибо!

, 👍2

Обсуждение

`c:/users/benlu/.platformio-Из этого я заключаю, что вы используете platformio, что может иметь важное значение. Вы пробовали построить это с помощью официальных инструментов arduino-builder/arduino-cli (или, знаете, с помощью IDE)?, @timemage

samples = 16128; //Это значение ВСЕГДА должно быть степенью 2 - 16128 не является степенью двух. (вероятно, не имеет значения), @Mat

@Мат-ха-ха, ты прав! У меня это было установлено правильно, но я пошел на перенумеровку, пытаясь решить еще одну проблему... спасибо за улов!, @Ben L

@timemage Я только что попробовал его в Arduino IDE и столкнулся с той же самой точной ошибкой., @Ben L


1 ответ


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

2

Короткая Версия

Короткий ответ заключается в том, что вы исчерпали оперативную память.

Только эти два массива:

const uint16_t samples = 16128;
double vImag[samples] = {0};
double double_buffer[16384] = {};

...занимаете ли вы (16128 + 16384) * 8 == 260096 байты памяти. Всего в нем всего 262144 байта оперативной памяти.

Судя по тому, как настроен сценарий компоновщика, для стека зарезервировано не менее 1024 байт, и нет никаких сомнений в том, что где-то используется по крайней мере еще один кБайт. В файлах Mbed OS и Arduino core, если ничего больше.

Что касается того , почему он терпит неудачу только при вызове Compute, то все сводится к тому, что оптимизатор компилятора обнаруживает, что один (а возможно, и оба) ваших массива на самом деле не используются, и поэтому не входит в микс при запуске компоновщика.

Подробности

Теоретически вы должны были бы получить несколько более приятное и понятное сообщение от УТВЕРЖДЕНИЯ в скрипте компоновщика:

ASSERT(. <= (ORIGIN(RAM) + LENGTH(RAM) - 1024), "heap region overflowed into stack");

Таким образом, вместо этого вы должны были увидеть на своем экране ошибку "область кучи перетекла в стек", которую, возможно, не так просто расшифровать пользователю Arduino, но куча и стек-это термины, которые рано или поздно будут распознаны как связанные с памятью.

Однако исполняемый файл компоновщика, поставляемый вместе с текущей версией 1.3.2 ядра Arduino для Mbed, полностью игнорирует операторы ASSERT; я проверил это (и проверил свое понимание моего теста с помощью компоновщика amd64). Предположительно, есть опция сборки для компоновщика или опция командной строки или конфигурационного файла, которая управляет этим, но я ее еще не нашел. В любом случае он игнорирует полезное УТВЕРЖДЕНИЕ и вместо этого продолжает терпеть неудачу в строке 138, упомянутой в сообщении об ошибке:

 . = ORIGIN(RAM) + LENGTH(RAM) - 1024;

Вы можете видеть, что он включает в себя то же самое выражение, просто без полезного сообщения, если что-то пойдет не так. "счетчик местоположений" в сообщении-это термин, связанный с компоновщиком, который примерно означает "где будет помещена следующая вещь в память", поскольку он собирает ваш окончательный исполняемый файл из отдельно скомпилированных фрагментов. Вы использовали так много оперативной памяти в своей программе, что счетчик местоположения был перенесен мимо того места, где сценарий компоновщика хочет поместить символ __HeapLimit, на 1K от конца оперативной памяти MCU. Предполагается, что счетчик местоположения будет монотонно увеличиваться. Таким образом, вычисление этого выражения приводит к ошибочной попытке "переместить счетчик местоположения назад".

,

Ух ты, спасибо за исчерпывающий ответ! Я пытался поднять голос, но у меня недостаточно репутации, чтобы показать ха-ха, я хотел, чтобы вы знали, что я очень, очень ценю ваш ответ! Так что, похоже, я использовал слишком много памяти, и мне нужно найти новый подход. Спасибо!, @Ben L

Хорошая сделка. Я собирался просто сказать: "все в порядке" или что ты можешь вернуться, если вспомнишь. Я забыл, что для этого существует порог, но я также еще не поддержал ваш вопрос. Сделав это, вы должны иметь возможность озвучивать все, что вам нравится., @timemage