Skip to content

Commit 5a0d67f

Browse files
authored
PDM library: Update PIO and interrupt use (#496)
The PIO and state machine were hard wired, so this caused problems if they were not free. The approach used by the Servo library has been adopted so a free PIO and SM are searched. The DMA_IRQ_0 was grabbed exclusively, but this conflicts with SPI DMA use. The interrupt is now shared, but has been allocated the highest possible priority. Since the PDM PIO use is receive only, the PIO state machine RX FIFO's can be joined to reduce DMA interrupt load.
1 parent 03626e6 commit 5a0d67f

File tree

4 files changed

+32
-18
lines changed

4 files changed

+32
-18
lines changed

libraries/PDM/src/PDM.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ class PDMClass
5858
int _gain;
5959
int _init;
6060

61+
// Hardware peripherals used
62+
uint _dmaChannel;
63+
PIO _pio;
64+
int _smIdx;
65+
int _pgmOffset;
66+
6167
PDMDoubleBuffer _doubleBuffer;
6268

6369
void (*_onReceive)(void);

libraries/PDM/src/rp2040/PDM.cpp

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,7 @@ extern "C" {
1111
}
1212
#include "hardware/sync.h"
1313
#include "pdm.pio.h"
14-
15-
// Hardware peripherals used
16-
uint dmaChannel = 0;
17-
PIO pio = pio0;
18-
uint sm = 0;
14+
static PIOProgram _pdmPgm(&pdm_pio_program);
1915

2016
// raw buffers contain PDM data
2117
#define RAW_BUFFER_SIZE 512 // should be a multiple of (decimation / 8)
@@ -49,7 +45,11 @@ PDMClass::PDMClass(int dinPin, int clkPin, int pwrPin) :
4945
_gain(-1),
5046
_channels(-1),
5147
_samplerate(-1),
52-
_init(-1)
48+
_init(-1),
49+
_dmaChannel(0),
50+
_pio(nullptr),
51+
_smIdx(-1),
52+
_pgmOffset(-1)
5353
{
5454
}
5555

@@ -89,29 +89,35 @@ int PDMClass::begin(int channels, int sampleRate)
8989

9090
// Configure PIO state machine
9191
float clkDiv = (float)clock_get_hz(clk_sys) / sampleRate / decimation / 2;
92-
uint offset = pio_add_program(pio, &pdm_pio_program);
93-
pdm_pio_program_init(pio, sm, offset, _clkPin, _dinPin, clkDiv);
92+
93+
if (!_pdmPgm.prepare(&_pio, &_smIdx, &_pgmOffset)) {
94+
// ERROR, no free slots
95+
return -1;
96+
}
97+
pdm_pio_program_init(_pio, _smIdx, _pgmOffset, _clkPin, _dinPin, clkDiv);
9498

9599
// Wait for microphone
96100
delay(100);
97101

98102
// Configure DMA for transferring PIO rx buffer to raw buffers
99-
dma_channel_config c = dma_channel_get_default_config(dmaChannel);
103+
_dmaChannel = dma_claim_unused_channel(false);
104+
dma_channel_config c = dma_channel_get_default_config(_dmaChannel);
100105
channel_config_set_read_increment(&c, false);
101106
channel_config_set_write_increment(&c, true);
102-
channel_config_set_dreq(&c, pio_get_dreq(pio, sm, false));
107+
channel_config_set_dreq(&c, pio_get_dreq(_pio, _smIdx, false));
103108
channel_config_set_transfer_data_size(&c, DMA_SIZE_8);
104109

105110
// Clear DMA interrupts
106-
dma_hw->ints0 = 1u << dmaChannel;
111+
dma_hw->ints0 = 1u << _dmaChannel;
107112
// Enable DMA interrupts
108-
dma_channel_set_irq0_enabled(dmaChannel, true);
109-
irq_set_exclusive_handler(DMA_IRQ_0, dmaHandler);
113+
dma_channel_set_irq0_enabled(_dmaChannel, true);
114+
// Share but allocate a high priority to the interrupt
115+
irq_add_shared_handler(DMA_IRQ_0, dmaHandler, 0);
110116
irq_set_enabled(DMA_IRQ_0, true);
111117

112-
dma_channel_configure(dmaChannel, &c,
118+
dma_channel_configure(_dmaChannel, &c,
113119
rawBuffer[rawBufferIndex], // Destinatinon pointer
114-
&pio->rxf[sm], // Source pointer
120+
&_pio->rxf[_smIdx], // Source pointer
115121
RAW_BUFFER_SIZE, // Number of transfers
116122
true // Start immediately
117123
);
@@ -123,7 +129,7 @@ int PDMClass::begin(int channels, int sampleRate)
123129

124130
void PDMClass::end()
125131
{
126-
dma_channel_abort(dmaChannel);
132+
dma_channel_abort(_dmaChannel);
127133
pinMode(_clkPin, INPUT);
128134
}
129135

@@ -171,10 +177,10 @@ void PDMClass::IrqHandler(bool halftranfer)
171177
static int cutSamples = 100;
172178

173179
// Clear the interrupt request.
174-
dma_hw->ints0 = 1u << dmaChannel;
180+
dma_hw->ints0 = 1u << _dmaChannel;
175181
// Restart dma pointing to the other buffer
176182
int shadowIndex = rawBufferIndex ^ 1;
177-
dma_channel_set_write_addr(dmaChannel, rawBuffer[shadowIndex], true);
183+
dma_channel_set_write_addr(_dmaChannel, rawBuffer[shadowIndex], true);
178184

179185
if (_doubleBuffer.available()) {
180186
// buffer overflow, stop

libraries/PDM/src/rp2040/pdm.pio

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ static inline void pdm_pio_program_init(PIO pio, uint sm, uint offset, uint clkP
2626
sm_config_set_in_pins(&c, dataPin);
2727
sm_config_set_sideset_pins(&c, clkPin);
2828
sm_config_set_clkdiv(&c, clkDiv);
29+
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
2930

3031
pio_sm_set_consecutive_pindirs(pio, sm, dataPin, 1, false);
3132
pio_sm_set_consecutive_pindirs(pio, sm, clkPin, 1, true);

libraries/PDM/src/rp2040/pdm.pio.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ static inline void pdm_pio_program_init(PIO pio, uint sm, uint offset, uint clkP
4343
sm_config_set_in_pins(&c, dataPin);
4444
sm_config_set_sideset_pins(&c, clkPin);
4545
sm_config_set_clkdiv(&c, clkDiv);
46+
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
4647
pio_sm_set_consecutive_pindirs(pio, sm, dataPin, 1, false);
4748
pio_sm_set_consecutive_pindirs(pio, sm, clkPin, 1, true);
4849
pio_sm_set_pins_with_mask(pio, sm, 0, (1u << clkPin) );

0 commit comments

Comments
 (0)