Skip to content

Commit

Permalink
Initial driver with basic example
Browse files Browse the repository at this point in the history
  • Loading branch information
sandeepmistry committed May 10, 2021
1 parent 3867f6e commit c947eb1
Show file tree
Hide file tree
Showing 6 changed files with 287 additions and 0 deletions.
31 changes: 31 additions & 0 deletions CMakeLists.txt
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")
15 changes: 15 additions & 0 deletions examples/hello_pdm/CMakeLists.txt
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)
59 changes: 59 additions & 0 deletions examples/hello_pdm/main.c
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;
}
27 changes: 27 additions & 0 deletions src/include/pico/microphone/pdm.h
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
118 changes: 118 additions & 0 deletions src/pdm-microphone.c
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;
}
37 changes: 37 additions & 0 deletions src/pdm-microphone.pio
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);
}
%}

0 comments on commit c947eb1

Please sign in to comment.