In my last post I have complained that my sine wave test sketch was producing just noise. So I am trying now to investigate where the issue is coming from.
Using Basic APIs
So first, I try an Arduino Sketch which is just using the low level API of my libraries: This
- configures the codec using the driver API,
- sets up I2S using the STM32 I2S library and just
- uses the sine generator from the AudioKit to fill the data in the callback.
#include "AudioTools.h"
#include "stm32-i2s.h"
#include "AudioBoard.h"
using namespace stm32_i2s;
SineWaveGenerator<int16_t> sineWave(32000);
int sample_rate = 8000;
int channels = 2;
void getData(uint8_t *buffer, uint16_t byteCount, void*) {
uint16_t samples = byteCount / sizeof(int16_t);
int16_t *buffer_16 = (int16_t*) buffer;
for (uint j = 0; j < samples; j+=2) {
buffer_16[j] = sineWave.readSample();
buffer_16[j+1] = buffer_16[j];
}
}
void setup() {
Serial.begin(115200);
// setup sine wave
sineWave.begin(channels, sample_rate, N_B1);
// setup codec
CodecConfig cfg;
cfg.i2s.rate = RATE_8K;
STM32F411Disco.begin(cfg);
// setup i2s
I2SSettingsSTM32 i2s_settings;
i2s_settings.sample_rate = I2S_AUDIOFREQ_8K;
I2S.beginWriteDMA(i2s_settings, getData);
}
// Arduino loop - copy sound to out
void loop() {
delay(1000);
}
This is working much better. So the issue must be in my STM32 driver in the AudioTools and indeed, after adding some more error messages I was getting plenty of buffer under-runs.
Using the Regular API
In my original sketch I was expecting that the buffer is filled by the Arduino loop and consumed by the DMA. But it seems that this works only with very low sample rates.
As I kind of hack, I am calling the loop now in the DMA callback, if the buffer is empty and this seems to resolve this issue!
Using the Driver API
I thought that it might be also useful to have the functionality from my first sketch available via the driver API:
#include "AudioTools.h"
#include "AudioLibs/AudioBoardStream.h"
AudioInfo info(44100, 2, 16);
SineWaveGenerator<int16_t> sineWave(32000);
GeneratedSoundStream<int16_t> sound(sineWave);
AudioBoardStream out(STM32F411Disco);
// Arduino Setup
void setup(void) {
// Open Serial and set up logging
Serial.begin(115200);
while(!Serial);
AudioLogger::instance().begin(Serial, AudioLogger::Info);
// define the audio source stream
out.driver()->setDMAInputStream(sound);
// Setup sine wave
sineWave.begin(info, N_B1);
Serial.println("started...");
// start I2S
Serial.println("starting I2S...");
auto config = out.defaultConfig(TX_MODE);
config.buffer_size = 1024;
config.buffer_count = 2;
config.copyFrom(info);
if (!out.begin(config)){
Serial.println("error!");
stop();
}
// defines the output volume
out.setVolume(0.3);
}
// Arduino loop - do nothing
void loop() {}
By calling setDMAInputStream() we can make the input stream available to the DMA logic in the driver, so that the DMA can directly read from it.
2 Comments
Plouc68000 · 18. February 2024 at 15:55
has this a effect on software stability?
I am using your Audio-Tools with I2s output for a webradio code, because don’t need external mp3 decoder board VS1053 anymore, thanks 😉
but the software is a bit crashy….forcing me to use WDT TimeOut
pschatzmann · 18. February 2024 at 20:03
I just completed the development, so I don’t have any experience with this yet…