PDM library re-port (#1160)

See #1156
This commit is contained in:
TomKong666 2023-02-07 17:10:24 +01:00 committed by GitHub
parent b400897ca2
commit 7df080ee92
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 57 additions and 19 deletions

View file

@ -38,6 +38,7 @@ public:
//PORTENTA_H7 min -12 max 51
//NANO 33 BLE SENSe min 0 max 80
//NICLA_VISION min 0 max 8
void setGain(int gain);
void setBufferSize(int bufferSize);
size_t getBufferSize();
@ -56,6 +57,8 @@ private:
int _gain;
int _init;
int _cutSamples;
// Hardware peripherals used
uint _dmaChannel;
PIO _pio;

View file

@ -20,7 +20,7 @@ uint8_t rawBuffer1[RAW_BUFFER_SIZE];
uint8_t* rawBuffer[2] = {rawBuffer0, rawBuffer1};
volatile int rawBufferIndex = 0;
int decimation = 64;
int decimation = 128;
// final buffer is the one to be filled with PCM data
int16_t* volatile finalBuffer;
@ -45,6 +45,7 @@ PDMClass::PDMClass(int dinPin, int clkPin, int pwrPin) :
_channels(-1),
_samplerate(-1),
_init(-1),
_cutSamples(100),
_dmaChannel(0),
_pio(nullptr),
_smIdx(-1),
@ -55,6 +56,12 @@ PDMClass::~PDMClass() {
}
int PDMClass::begin(int channels, int sampleRate) {
if (_init == 1) {
//ERROR: please call end first
return 0;
}
//_channels = channels; // only one channel available
// clear the final buffers
@ -63,6 +70,18 @@ int PDMClass::begin(int channels, int sampleRate) {
int finalBufferLength = _doubleBuffer.availableForWrite() / sizeof(int16_t);
_doubleBuffer.swap(0);
// The mic accepts an input clock from 1.2 to 3.25 Mhz
// Setup the decimation factor accordingly
if ((sampleRate * decimation * 2) > 3250000) {
decimation = 64;
}
// Sanity check, abort if still over 3.25Mhz
if ((sampleRate * decimation * 2) > 3250000) {
//ERROR: Sample rate too high, the mic would glitch
return -1;
}
int rawBufferLength = RAW_BUFFER_SIZE / (decimation / 8);
// Saturate number of samples. Remaining bytes are dropped.
if (rawBufferLength > finalBufferLength) {
@ -71,6 +90,7 @@ int PDMClass::begin(int channels, int sampleRate) {
/* Initialize Open PDM library */
filter.Fs = sampleRate;
filter.MaxVolume = 1;
filter.nSamples = rawBufferLength;
filter.LP_HZ = sampleRate / 2;
filter.HP_HZ = 10;
@ -88,7 +108,7 @@ int PDMClass::begin(int channels, int sampleRate) {
if (!_pdmPgm.prepare(&_pio, &_smIdx, &_pgmOffset)) {
// ERROR, no free slots
return -1;
return 0;
}
pdm_pio_program_init(_pio, _smIdx, _pgmOffset, _clkPin, _dinPin, clkDiv);
@ -118,14 +138,29 @@ int PDMClass::begin(int channels, int sampleRate) {
true // Start immediately
);
_cutSamples = 100;
_init = 1;
return 1;
}
void PDMClass::end() {
if (_init != 1) {
return;
}
dma_channel_set_irq0_enabled(_dmaChannel, false);
dma_channel_abort(_dmaChannel);
dma_channel_unclaim(_dmaChannel);
irq_remove_handler(DMA_IRQ_0, dmaHandler);
pio_sm_unclaim(_pio, _smIdx);
pinMode(_clkPin, INPUT);
rawBufferIndex = 0;
_pgmOffset = -1;
_init = 0;
}
int PDMClass::available() {
@ -163,7 +198,6 @@ void PDMClass::setBufferSize(int bufferSize) {
}
void PDMClass::IrqHandler(bool halftranfer) {
static int cutSamples = 100;
// Clear the interrupt request.
dma_hw->ints0 = 1u << _dmaChannel;
@ -171,24 +205,25 @@ void PDMClass::IrqHandler(bool halftranfer) {
int shadowIndex = rawBufferIndex ^ 1;
dma_channel_set_write_addr(_dmaChannel, rawBuffer[shadowIndex], true);
if (_doubleBuffer.available()) {
// buffer overflow, stop
return end();
if (!_doubleBuffer.available()) {
// fill final buffer with PCM samples
if (filter.Decimation == 128) {
Open_PDM_Filter_128(rawBuffer[rawBufferIndex], finalBuffer, 1, &filter);
} else {
Open_PDM_Filter_64(rawBuffer[rawBufferIndex], finalBuffer, 1, &filter);
}
if (_cutSamples) {
memset(finalBuffer, 0, _cutSamples);
_cutSamples = 0;
}
// swap final buffer and raw buffers' indexes
finalBuffer = (int16_t*)_doubleBuffer.data();
_doubleBuffer.swap(filter.nSamples * sizeof(int16_t));
rawBufferIndex = shadowIndex;
}
// fill final buffer with PCM samples
Open_PDM_Filter_64(rawBuffer[rawBufferIndex], finalBuffer, 1, &filter);
if (cutSamples) {
memset(finalBuffer, 0, cutSamples);
cutSamples = 0;
}
// swap final buffer and raw buffers' indexes
finalBuffer = (int16_t*)_doubleBuffer.data();
_doubleBuffer.swap(filter.nSamples * sizeof(int16_t));
rawBufferIndex = shadowIndex;
if (_onReceive) {
_onReceive();
}