-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3867f6e
commit c947eb1
Showing
6 changed files
with
287 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
cmake_minimum_required(VERSION 3.12) | ||
|
||
# initialize pico_sdk from GIT | ||
# (note this can come from environment, CMake cache etc) | ||
# set(PICO_SDK_FETCH_FROM_GIT on) | ||
|
||
# pico_sdk_import.cmake is a single file copied from this SDK | ||
# note: this must happen before project() | ||
include(pico_sdk_import.cmake) | ||
|
||
project(pico_microphone) | ||
|
||
# initialize the Pico SDK | ||
pico_sdk_init() | ||
|
||
add_library(pico_microphone INTERFACE) | ||
|
||
target_sources(pico_microphone INTERFACE | ||
${CMAKE_CURRENT_LIST_DIR}/src/pdm-microphone.c | ||
${CMAKE_CURRENT_LIST_DIR}/src/OpenPDM2PCM/OpenPDMFilter.c | ||
) | ||
|
||
target_include_directories(pico_microphone INTERFACE | ||
${CMAKE_CURRENT_LIST_DIR}/src/include | ||
) | ||
|
||
pico_generate_pio_header(pico_microphone ${CMAKE_CURRENT_LIST_DIR}/src/pdm-microphone.pio) | ||
|
||
target_link_libraries(pico_microphone INTERFACE pico_stdlib hardware_dma hardware_pio) | ||
|
||
add_subdirectory("examples/hello_pdm") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
cmake_minimum_required(VERSION 3.12) | ||
|
||
# rest of your project | ||
add_executable(pico_microphone_hello_pdm | ||
main.c | ||
) | ||
|
||
target_link_libraries(pico_microphone_hello_pdm pico_microphone) | ||
|
||
# enable usb output, disable uart output | ||
pico_enable_stdio_usb(pico_microphone_hello_pdm 1) | ||
pico_enable_stdio_uart(pico_microphone_hello_pdm 0) | ||
|
||
# create map/bin/hex/uf2 file in addition to ELF. | ||
pico_add_extra_outputs(pico_microphone_hello_pdm) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/* | ||
* Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
#include <stdio.h> | ||
#include <string.h> | ||
|
||
#include "pico/stdlib.h" | ||
#include "pico/microphone/pdm.h" | ||
#include "tusb.h" | ||
|
||
struct pdm_microphone_config config = { | ||
.pio = pio0, | ||
.pio_sm = 0, | ||
.sample_rate = 8000, | ||
.gpio_clk = 2, | ||
.gpio_data = 3, | ||
}; | ||
|
||
int16_t sample_buffer[256]; | ||
volatile int samples_read = 0; | ||
|
||
void on_pdm_data(int16_t* samples, uint num_samples) | ||
{ | ||
memcpy(sample_buffer, samples, num_samples * sizeof(samples[0])); | ||
|
||
samples_read = num_samples; | ||
} | ||
|
||
int main( void ) | ||
{ | ||
// initialize stdio and wait for USB CDC connect | ||
stdio_init_all(); | ||
while (!tud_cdc_connected()) { | ||
tight_loop_contents(); | ||
} | ||
|
||
// printf("hello PDM microphone\n"); | ||
|
||
pdm_microphone_init(&config); | ||
pdm_microphone_start(on_pdm_data); | ||
|
||
while (1) { | ||
while (samples_read == 0) { | ||
tight_loop_contents(); | ||
} | ||
|
||
for (int i = 0; i < samples_read; i++) { | ||
printf("%d\n", sample_buffer[i]); | ||
} | ||
|
||
samples_read = 0; | ||
} | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/* | ||
* Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
#ifndef _PICO_MICROPHONE_PDM_H_ | ||
#define _PICO_MICROPHONE_PDM_H_ | ||
|
||
#include "hardware/pio.h" | ||
|
||
typedef void (*pdm_data_handler_t)(int16_t*, uint); | ||
|
||
struct pdm_microphone_config { | ||
PIO pio; | ||
uint pio_sm; | ||
uint sample_rate; | ||
uint gpio_clk; | ||
uint gpio_data; | ||
// TODO: pass in buffer??? | ||
}; | ||
|
||
int pdm_microphone_init(const struct pdm_microphone_config* config); | ||
int pdm_microphone_start(pdm_data_handler_t handler); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
/* | ||
* Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
#include "hardware/clocks.h" | ||
#include "hardware/dma.h" | ||
#include "hardware/irq.h" | ||
|
||
#include "OpenPDM2PCM/OpenPDMFilter.h" | ||
|
||
#include "pdm-microphone.pio.h" | ||
|
||
#include "pico/microphone/pdm.h" | ||
|
||
#define PDM_DECIMATION 64 | ||
#define PCM_BUFFER_SIZE 256 | ||
|
||
static int dma_channel = -1; | ||
static uint8_t pdm_buffer[2][PCM_BUFFER_SIZE * (PDM_DECIMATION / 8)]; | ||
static volatile int pdm_buffer_index = 0; | ||
static int16_t pcm_buffer[PCM_BUFFER_SIZE]; | ||
|
||
static TPDMFilter_InitStruct pdm_filter; | ||
static pdm_data_handler_t pdm_data_handler = NULL; | ||
|
||
static void dma_handler() | ||
{ | ||
// clear IRQ | ||
dma_hw->ints0 = 1u << dma_channel; | ||
|
||
// get the current buffer index | ||
int read_index = pdm_buffer_index; | ||
|
||
// get the next capture index to send the dma to start | ||
pdm_buffer_index = (pdm_buffer_index + 1) % 2; | ||
|
||
// give the channel a new buffer to write to and re-trigger it | ||
dma_channel_transfer_to_buffer_now(dma_channel, pdm_buffer[pdm_buffer_index], sizeof(pdm_buffer[0])); | ||
|
||
uint8_t* in = pdm_buffer[read_index]; | ||
int16_t* out = pcm_buffer; | ||
|
||
int filter_stride = (pdm_filter.Fs / 1000); | ||
|
||
for (int i = 0; i < (PCM_BUFFER_SIZE / filter_stride); i++) { | ||
#if PDM_DECIMATION == 64 | ||
Open_PDM_Filter_64(in, out, 1, &pdm_filter); | ||
#elif PDM_DECIMATION == 128 | ||
Open_PDM_Filter_128(in, out, 1, &pdm_filter); | ||
#else | ||
#error "Unsupported PDM_DECIMATION value!" | ||
#endif | ||
|
||
in += filter_stride * (PDM_DECIMATION / 8); | ||
out += filter_stride; | ||
} | ||
|
||
pdm_data_handler(pcm_buffer, PCM_BUFFER_SIZE); | ||
} | ||
|
||
int pdm_microphone_init(const struct pdm_microphone_config* config) | ||
{ | ||
uint pio_sm_offset = pio_add_program(config->pio, &pdm_microphone_data_program); | ||
|
||
float clk_div = clock_get_hz(clk_sys) / (config->sample_rate * PDM_DECIMATION * 2); | ||
|
||
pdm_microphone_data_init( | ||
config->pio, | ||
config->pio_sm, | ||
pio_sm_offset, | ||
clk_div, | ||
config->gpio_clk, | ||
config->gpio_data | ||
); | ||
|
||
dma_channel = dma_claim_unused_channel(true); | ||
|
||
// TODO: handle claim failure | ||
|
||
dma_channel_config dma_channel_cfg = dma_channel_get_default_config(dma_channel); | ||
|
||
channel_config_set_transfer_data_size(&dma_channel_cfg, DMA_SIZE_8); | ||
channel_config_set_read_increment(&dma_channel_cfg, false); | ||
channel_config_set_write_increment(&dma_channel_cfg, true); | ||
channel_config_set_dreq(&dma_channel_cfg, pio_get_dreq(config->pio, config->pio_sm, false)); | ||
|
||
irq_set_enabled(DMA_IRQ_0, true); | ||
irq_set_exclusive_handler(DMA_IRQ_0, dma_handler); | ||
|
||
dma_channel_set_irq0_enabled(dma_channel, true); | ||
|
||
dma_channel_configure(dma_channel, &dma_channel_cfg, NULL, &config->pio->rxf[config->pio_sm], sizeof(pdm_buffer[pdm_buffer_index]), false); | ||
|
||
pdm_filter.Fs = config->sample_rate; | ||
pdm_filter.LP_HZ = config->sample_rate / 2; | ||
pdm_filter.HP_HZ = 10; | ||
pdm_filter.In_MicChannels = 1; | ||
pdm_filter.Out_MicChannels = 1; | ||
pdm_filter.Decimation = PDM_DECIMATION; | ||
pdm_filter.MaxVolume = 0; | ||
|
||
Open_PDM_Filter_Init(&pdm_filter); | ||
|
||
return -1; | ||
} | ||
|
||
int pdm_microphone_start(pdm_data_handler_t handler) | ||
{ | ||
pdm_data_handler = handler; | ||
|
||
// give the channel a new buffer to write to and re-trigger it | ||
dma_channel_transfer_to_buffer_now(dma_channel, pdm_buffer[pdm_buffer_index], sizeof(pdm_buffer[0])); | ||
|
||
return -1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* | ||
* Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
*/ | ||
|
||
.program pdm_microphone_data | ||
.side_set 1 | ||
.wrap_target | ||
nop side 1 | ||
in pins, 1 side 0 | ||
.wrap | ||
|
||
% c-sdk { | ||
|
||
static inline void pdm_microphone_data_init(PIO pio, uint sm, uint offset, float clk_div, uint clk_pin, uint data_pin) { | ||
pio_sm_set_consecutive_pindirs(pio, sm, data_pin, 1, false); | ||
pio_sm_set_consecutive_pindirs(pio, sm, clk_pin, 1, true); | ||
|
||
pio_sm_config c = pdm_microphone_data_program_get_default_config(offset); | ||
|
||
sm_config_set_sideset_pins(&c, clk_pin); | ||
sm_config_set_in_pins(&c, data_pin); | ||
|
||
pio_gpio_init(pio, clk_pin); | ||
pio_gpio_init(pio, data_pin); | ||
|
||
sm_config_set_in_shift(&c, false, true, 8); | ||
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX); | ||
|
||
sm_config_set_clkdiv(&c, clk_div); | ||
|
||
pio_sm_init(pio, sm, offset, &c); | ||
pio_sm_set_enabled(pio, sm, true); | ||
} | ||
%} |