arduino / ArduinoCore-mbed

347 stars 203 forks source link

Undefined references in audio.c #416

Closed NilLlisterri closed 2 years ago

NilLlisterri commented 2 years ago

Hi, when including the PDM library and compiling the project, this error appears:

C:\Users\nilll\AppData\Local\Temp\arduino_build_278108\libraries\PDM\stm32\audio.c.o: In function `HAL_SAI_RxHalfCpltCallback':
C:\Users\nilll\AppData\Local\Arduino15\packages\arduino\hardware\mbed_portenta\2.7.2\libraries\PDM\src\stm32/audio.c:63: undefined reference to `SCB_InvalidateDCache_by_Addr'
C:\Users\nilll\AppData\Local\Temp\arduino_build_278108\libraries\PDM\stm32\audio.c.o: In function `HAL_SAI_RxCpltCallback':
C:\Users\nilll\AppData\Local\Arduino15\packages\arduino\hardware\mbed_portenta\2.7.2\libraries\PDM\src\stm32/audio.c:70: undefined reference to `SCB_InvalidateDCache_by_Addr'
C:\Users\nilll\AppData\Local\Temp\arduino_build_278108\libraries\PDM\stm32\audio.c.o: In function `py_audio_init':
C:\Users\nilll\AppData\Local\Arduino15\packages\arduino\hardware\mbed_portenta\2.7.2\libraries\PDM\src\stm32/audio.c:299: undefined reference to `PDM_Filter_Init'
C:\Users\nilll\AppData\Local\Arduino15\packages\arduino\hardware\mbed_portenta\2.7.2\libraries\PDM\src\stm32/audio.c:304: undefined reference to `PDM_Filter_setConfig'
C:\Users\nilll\AppData\Local\Temp\arduino_build_278108\libraries\PDM\stm32\audio.c.o: In function `audio_pendsv_callback':
C:\Users\nilll\AppData\Local\Arduino15\packages\arduino\hardware\mbed_portenta\2.7.2\libraries\PDM\src\stm32/audio.c:363: undefined reference to `PDM_Filter'
C:\Users\nilll\AppData\Local\Arduino15\packages\arduino\hardware\mbed_portenta\2.7.2\libraries\PDM\src\stm32/audio.c:371: undefined reference to `PDM_Filter'
collect2.exe: error: ld returned 1 exit status
Using library PDM at version 1.0 in folder: C:\Users\nilll\AppData\Local\Arduino15\packages\arduino\hardware\mbed_portenta\2.7.2\libraries\PDM 
Using library Portenta_Audio at version 1.0.0 in folder: C:\Users\nilll\AppData\Local\Arduino15\packages\arduino\hardware\mbed_portenta\2.7.2\libraries\Portenta_Audio 
exit status 1
Error compiling for board Arduino Portenta H7 (M4 core).

I tested it in the example sketch for the Arduino Portenta H7 (PDMSerialPlotter) and it also fails. I am using the latest Portenta MbedOS board version, 2.7.2 on the Arduino Desktop IDE. Does anyone else have this problem or can point me to any solution? I already reinstalled the IDE and the boards to no avail. Thanks!

facchinm commented 2 years ago

Hi @NilLlisterri , you are compiling for M4 core which is not supported at the moment for the PDM library. The biggest issue is this binary library provided by ST that works only on specific targets (namely, the M7). I'll ask to get a version for the M4 if it's really needed; let me know if it was intended or if you wanted to compile and run on the M7 (which should work, BTW) :wink:

NilLlisterri commented 2 years ago

Hi @facchinm, Thanks for the info, you saved me more headaches. We are working on an application that uses both cores. The less powerful M4 was intended to perform continuous sample recording and perhaps preprocessing, while the M7 should carry more CPU intensive tasks, like ML training. It would be very helpful to be able to use the PDM library on the M4 if possible, because we already tried to perform all the tasks on the M7 and hit a bottleneck. Let me know if I can help in anything. Thanks! :smile:

facchinm commented 2 years ago

@NilLlisterri very interesting project indeed! I tried to arrange something here https://github.com/arduino/ArduinoCore-mbed/pull/417, didn't test it though, so if you could give it a spin and report if it actually works I'd be very happy :slightly_smiling_face:

NilLlisterri commented 2 years ago

@facchinm woah that was fast, the compilation problems are gone, thanks!

To test it out, first I've run the demo program on the M7 and visualized the captured signal with the Serial Plotter, all good. Then I've tried to write a small dual-core program, where the M4 captures the audio and sends it to the M7 via RPC, and the M7 simply prints the messages to serial. Sadly, the signal does not seem to change as the audio changes, like as the first test did on the Serial Plotter. Also, the values are extremely high and low, making no sense.

This might be because of a bug in my program, but I tried to keep it as minimal and close to the demo program as I could.

#include "RPC.h"
#define SERIAL_FR 9600

//////////////////  M4 CORE //////////////////
#ifdef CORE_CM4

#include <PDM.h>

static const char channels = 1; // default number of output channels
static const int frequency = 16000; // default PCM output frequency
short sampleBuffer[512]; // Buffer to read samples into, each sample is 16-bits

volatile int samplesRead; // Number of audio samples read

void setup() {
  RPC.begin();
  Serial.begin(SERIAL_FR);
  while (!Serial);

  PDM.onReceive(onPDMdata); // Configure the data receive callback

  // Initialize PDM with:
  // - one channel (mono mode)
  // - a 16 kHz sample rate for the Arduino Nano 33 BLE Sense
  // - a 32 kHz or 64 kHz sample rate for the Arduino Portenta Vision Shield
  if (!PDM.begin(channels, frequency)) {
    RPC.println("Failed to start PDM!");
    while (1);
  }
}

void loop() {
  if (samplesRead) { // Wait for samples to be read
    // Print samples to the serial monitor or plotter
    for (int i = 0; i < samplesRead; i++) {
      RPC.println(sampleBuffer[i]);
    }
    samplesRead = 0; // Clear the read count
  }
}

/**
   Callback function to process the data from the PDM microphone.
   NOTE: This callback is executed as part of an ISR.
   Therefore using `Serial` to print messages inside this function isn't supported.
 **/
void onPDMdata() {
  int bytesAvailable = PDM.available(); // Query the number of available bytes
  PDM.read(sampleBuffer, bytesAvailable); // Read into the sample buffer
  samplesRead = bytesAvailable / 2; // 16-bit, 2 bytes per sample
}
#endif

//////////////////  M7 CORE //////////////////

#ifdef CORE_CM7
void setup() {
  RPC.begin();
  Serial.begin(SERIAL_FR);
}

void loop() {
  String buffer = "";
  while (RPC.available()) {
    buffer += (char)RPC.read(); // Fill the buffer with characters
  }
  if (buffer.length() > 0) {
    Serial.print(buffer);
  }
}
#endif

If there is a better way to test it out I can try 👍

giulcioffi commented 2 years ago

Hi @NilLlisterri, I adjusted a bit your sketch to properly handle data coming from the PDM and passing them via RPC with the right format. Would you like to try this sketch and let me know if it works for you?

#include "RPC.h"
#define SERIAL_FR 9600

//////////////////  M4 CORE //////////////////
#ifdef CORE_CM4

#include <PDM.h>

static const char channels = 1; // default number of output channels
static const int frequency = 16000; // default PCM output frequency
short sampleBuffer[512]; // Buffer to read samples into, each sample is 16-bits

volatile int samplesRead; // Number of audio samples read

void setup() {
  RPC.begin();
  Serial.begin(SERIAL_FR);
  while (!Serial);

  PDM.onReceive(onPDMdata); // Configure the data receive callback

  // Initialize PDM with:
  // - one channel (mono mode)
  // - a 16 kHz sample rate for the Arduino Nano 33 BLE Sense
  // - a 32 kHz or 64 kHz sample rate for the Arduino Portenta Vision Shield
  if (!PDM.begin(channels, frequency)) {
    RPC.println("Failed to start PDM!");
    while (1);
  }
}

int block_size = 32;

void loop() {
  if (samplesRead) { // Wait for samples to be read
    // Print samples to the serial monitor or plotter
    int i=0;

    while(i<samplesRead) {
      if ((samplesRead - i) < block_size) {
        block_size = samplesRead - i;
      }
      RPC.write((uint8_t*)(sampleBuffer+i),2*block_size);
      i = i + block_size;
      delay(1);
    }
    samplesRead = 0; // Clear the read count
    block_size = 32; // Restore block size
  }
}

/**
   Callback function to process the data from the PDM microphone.
   NOTE: This callback is executed as part of an ISR.
   Therefore using `Serial` to print messages inside this function isn't supported.
 **/
void onPDMdata() {
  int bytesAvailable = PDM.available(); // Query the number of available bytes
  PDM.read(sampleBuffer, bytesAvailable); // Read into the sample buffer
  samplesRead = bytesAvailable / 2; // 16-bit, 2 bytes per sample
}

#endif // CORE_CM4

//////////////////  M7 CORE //////////////////

#ifdef CORE_CM7
uint8_t buff[512];
void setup() {
  RPC.begin();
  Serial.begin(SERIAL_FR);
}

void loop() {
  int idx = 0;

  while (RPC.available()) {
    //Serial.println((uint8_t)RPC.read());
    buff[idx] = RPC.read();
    idx++;
  }

  // Print data to Serial Plotter
  int i=0;
  while(i<idx) {
    short data = buff[i] + (buff[i+1] << 8);
    Serial.println(data);
    i=i+2;
  }
  //OR
  // Write raw buffer to terminal as uint8_t* buff
  //Serial.write(buff, idx);

}
#endif
NilLlisterri commented 2 years ago

@giulcioffi It woked! The signal is as clear as the one recorded using the M7 core. Thank you so much for your help! :smile: