main a837f633a6ad cached
24 files
85.8 KB
23.1k tokens
56 symbols
1 requests
Download .txt
Repository: ArmDeveloperEcosystem/microphone-library-for-pico
Branch: main
Commit: a837f633a6ad
Files: 24
Total size: 85.8 KB

Directory structure:
gitextract_j80jyxyx/

├── .github/
│   └── stale.yml
├── .gitignore
├── CMakeLists.txt
├── LICENSE
├── README.md
├── examples/
│   ├── hello_analog_microphone/
│   │   ├── CMakeLists.txt
│   │   └── main.c
│   ├── hello_pdm_microphone/
│   │   ├── CMakeLists.txt
│   │   └── main.c
│   └── usb_microphone/
│       ├── CMakeLists.txt
│       ├── main.c
│       ├── tusb_config.h
│       ├── usb_descriptors.c
│       ├── usb_microphone.c
│       └── usb_microphone.h
├── pico_sdk_import.cmake
└── src/
    ├── OpenPDM2PCM/
    │   ├── LICENSE.txt
    │   ├── OpenPDMFilter.c
    │   └── OpenPDMFilter.h
    ├── analog_microphone.c
    ├── include/
    │   └── pico/
    │       ├── analog_microphone.h
    │       └── pdm_microphone.h
    ├── pdm_microphone.c
    └── pdm_microphone.pio

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/stale.yml
================================================
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
  - pinned
  - security
  - help wanted
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
  This issue has been automatically marked as stale because it has not had
  recent activity. It will be closed if no further activity occurs. Thank you
  for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
# Never stale pull requests
only: issues

================================================
FILE: .gitignore
================================================
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps

build/



================================================
FILE: CMakeLists.txt
================================================
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_pdm_microphone INTERFACE)

target_sources(pico_pdm_microphone INTERFACE
    ${CMAKE_CURRENT_LIST_DIR}/src/pdm_microphone.c
    ${CMAKE_CURRENT_LIST_DIR}/src/OpenPDM2PCM/OpenPDMFilter.c
)

target_include_directories(pico_pdm_microphone INTERFACE
    ${CMAKE_CURRENT_LIST_DIR}/src/include
)

pico_generate_pio_header(pico_pdm_microphone ${CMAKE_CURRENT_LIST_DIR}/src/pdm_microphone.pio)

target_link_libraries(pico_pdm_microphone INTERFACE pico_stdlib hardware_dma hardware_pio)


add_library(pico_analog_microphone INTERFACE)

target_sources(pico_analog_microphone INTERFACE
    ${CMAKE_CURRENT_LIST_DIR}/src/analog_microphone.c
)

target_include_directories(pico_analog_microphone INTERFACE
    ${CMAKE_CURRENT_LIST_DIR}/src/include
)

target_link_libraries(pico_analog_microphone INTERFACE pico_stdlib hardware_adc hardware_dma)

add_subdirectory("examples/hello_analog_microphone")
add_subdirectory("examples/hello_pdm_microphone")
add_subdirectory("examples/usb_microphone")


================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
# Microphone Library for Pico

Capture audio from a microphone on your [Raspberry Pi Pico](https://www.raspberrypi.org/products/raspberry-pi-pico/) or any [RP2040](https://www.raspberrypi.org/products/rp2040/) based board. 🎤


## Hardware

 * RP2040 board
   * [Raspberry Pi Pico](https://www.raspberrypi.org/products/raspberry-pi-pico/)
 * Microphones
   * Analog
     * [Electret Microphone Amplifier - MAX9814 with Auto Gain Control](https://www.adafruit.com/product/1713) 
   * PDM
     * [Adafruit PDM MEMS Microphone Breakout](https://www.adafruit.com/product/3492)

### Default Pinout

#### Analog Microphone

| Raspberry Pi Pico / RP2040 | Analog Microphone |
| -------------------------- | ----------------- |
| 3.3V | VCC |
| GND | GND |
| GPIO 26 | OUT |

#### PDM Microphone

| Raspberry Pi Pico / RP2040 | PDM Microphone |
| -------------------------- | ----------------- |
| 3.3V | VCC |
| GND | GND |
| GND | SEL |
| GPIO 2 | DAT |
| GPIO 3 | CLK |

GPIO pins are configurable in examples or API.

## Examples

See [examples](examples/) folder.


## Cloning

```sh
git clone https://github.com/ArmDeveloperEcosystem/microphone-library-for-pico.git 
```

## Building

1. [Set up the Pico C/C++ SDK](https://datasheets.raspberrypi.org/pico/getting-started-with-pico.pdf)
2. Set `PICO_SDK_PATH`
```sh
export PICO_SDK_PATH=/path/to/pico-sdk
```
3. Create `build` dir, run `cmake` and `make`:
```
mkdir build
cd build
cmake .. -DPICO_BOARD=pico
make
```
4. Copy example `.uf2` to Pico when in BOOT mode.

## License

[Apache-2.0 License](LICENSE)

## Acknowledgements

This project was created on behalf of the [Arm Software Developers](https://developer.arm.com/) team, follow them on Twitter: [@ArmSoftwareDev](https://twitter.com/armsoftwaredev) and YouTube: [Arm Software Developers](https://www.youtube.com/channel/UCHUAckhCfRom2EHDGxwhfOg) for more resources!

The [OpenPDM2PCM](https://os.mbed.com/teams/ST/code/X_NUCLEO_CCA02M1//file/53f8b511f2a1/Middlewares/OpenPDM2PCM/) library is used to filter raw PDM data into PCM. The [TinyUSB](https://github.com/hathach/tinyusb) library is used in the `usb_microphone` example.

---

Disclaimer: This is not an official Arm product.


================================================
FILE: examples/hello_analog_microphone/CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.12)

# rest of your project
add_executable(hello_analog_microphone
    main.c
)

target_link_libraries(hello_analog_microphone pico_analog_microphone)

# enable usb output, disable uart output
pico_enable_stdio_usb(hello_analog_microphone 1)
pico_enable_stdio_uart(hello_analog_microphone 0)

# create map/bin/hex/uf2 file in addition to ELF.
pico_add_extra_outputs(hello_analog_microphone)


================================================
FILE: examples/hello_analog_microphone/main.c
================================================
/*
 * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 * 
 * 
 * This examples captures data from an analog microphone using a sample
 * rate of 8 kHz and prints the sample values over the USB serial
 * connection.
 */

#include <stdio.h>

#include "pico/stdlib.h"
#include "pico/analog_microphone.h"
#include "tusb.h"

// configuration
const struct analog_microphone_config config = {
    // GPIO to use for input, must be ADC compatible (GPIO 26 - 28)
    .gpio = 26,

    // bias voltage of microphone in volts
    .bias_voltage = 1.25,

    // sample rate in Hz
    .sample_rate = 8000,

    // number of samples to buffer
    .sample_buffer_size = 256,
};

// variables
int16_t sample_buffer[256];
volatile int samples_read = 0;

void on_analog_samples_ready()
{
    // callback from library when all the samples in the library
    // internal sample buffer are ready for reading 
    samples_read = analog_microphone_read(sample_buffer, 256);
}

int main( void )
{
    // initialize stdio and wait for USB CDC connect
    stdio_init_all();
    while (!tud_cdc_connected()) {
        tight_loop_contents();
    }

    printf("hello analog microphone\n");

    // initialize the analog microphone
    if (analog_microphone_init(&config) < 0) {
        printf("analog microphone initialization failed!\n");
        while (1) { tight_loop_contents(); }
    }

    // set callback that is called when all the samples in the library
    // internal sample buffer are ready for reading
    analog_microphone_set_samples_ready_handler(on_analog_samples_ready);
    
    // start capturing data from the analog microphone
    if (analog_microphone_start() < 0) {
        printf("PDM microphone start failed!\n");
        while (1) { tight_loop_contents();  }
    }

    while (1) {
        // wait for new samples
        while (samples_read == 0) { tight_loop_contents(); }

        // store and clear the samples read from the callback
        int sample_count = samples_read;
        samples_read = 0;
        
        // loop through any new collected samples
        for (int i = 0; i < sample_count; i++) {
            printf("%d\n", sample_buffer[i]);
        }
    }

    return 0;
}


================================================
FILE: examples/hello_pdm_microphone/CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.12)

# rest of your project
add_executable(hello_pdm_microphone
    main.c
)

target_link_libraries(hello_pdm_microphone pico_pdm_microphone)

# enable usb output, disable uart output
pico_enable_stdio_usb(hello_pdm_microphone 1)
pico_enable_stdio_uart(hello_pdm_microphone 0)

# create map/bin/hex/uf2 file in addition to ELF.
pico_add_extra_outputs(hello_pdm_microphone)


================================================
FILE: examples/hello_pdm_microphone/main.c
================================================
/*
 * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 * 
 * This examples captures data from a PDM microphone using a sample
 * rate of 8 kHz and prints the sample values over the USB serial
 * connection.
 */

#include <stdio.h>
#include <string.h>

#include "pico/stdlib.h"
#include "pico/pdm_microphone.h"
#include "tusb.h"

// configuration
const struct pdm_microphone_config config = {
    // GPIO pin for the PDM DAT signal
    .gpio_data = 2,

    // GPIO pin for the PDM CLK signal
    .gpio_clk = 3,

    // PIO instance to use
    .pio = pio0,

    // PIO State Machine instance to use
    .pio_sm = 0,

    // sample rate in Hz
    .sample_rate = 8000,

    // number of samples to buffer
    .sample_buffer_size = 256,
};

// variables
int16_t sample_buffer[256];
volatile int samples_read = 0;

void on_pdm_samples_ready()
{
    // callback from library when all the samples in the library
    // internal sample buffer are ready for reading 
    samples_read = pdm_microphone_read(sample_buffer, 256);
}

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");

    // initialize the PDM microphone
    if (pdm_microphone_init(&config) < 0) {
        printf("PDM microphone initialization failed!\n");
        while (1) { tight_loop_contents(); }
    }

    // set callback that is called when all the samples in the library
    // internal sample buffer are ready for reading
    pdm_microphone_set_samples_ready_handler(on_pdm_samples_ready);
    
     // start capturing data from the PDM microphone
    if (pdm_microphone_start() < 0) {
        printf("PDM microphone start failed!\n");
        while (1) { tight_loop_contents(); }
    }

    while (1) {
        // wait for new samples
        while (samples_read == 0) { tight_loop_contents(); }

        // store and clear the samples read from the callback
        int sample_count = samples_read;
        samples_read = 0;
        
        // loop through any new collected samples
        for (int i = 0; i < sample_count; i++) {
            printf("%d\n", sample_buffer[i]);
        }
    }

    return 0;
}


================================================
FILE: examples/usb_microphone/CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.12)

# rest of your project
add_executable(usb_microphone
    main.c
    usb_descriptors.c
    usb_microphone.c
)

target_include_directories(usb_microphone PRIVATE ${CMAKE_CURRENT_LIST_DIR})

target_link_libraries(usb_microphone PRIVATE tinyusb_device tinyusb_board pico_pdm_microphone)

# create map/bin/hex/uf2 file in addition to ELF.
pico_add_extra_outputs(usb_microphone)


================================================
FILE: examples/usb_microphone/main.c
================================================
/*
 * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 * 
 * This examples creates a USB Microphone device using the TinyUSB
 * library and captures data from a PDM microphone using a sample
 * rate of 16 kHz, to be sent the to PC.
 * 
 * The USB microphone code is based on the TinyUSB audio_test example.
 * 
 * https://github.com/hathach/tinyusb/tree/master/examples/device/audio_test
 */

#include "pico/pdm_microphone.h"

#include "usb_microphone.h"

// configuration
const struct pdm_microphone_config config = {
  .gpio_data = 2,
  .gpio_clk = 3,
  .pio = pio0,
  .pio_sm = 0,
  .sample_rate = SAMPLE_RATE,
  .sample_buffer_size = SAMPLE_BUFFER_SIZE,
};

// variables
uint16_t sample_buffer[SAMPLE_BUFFER_SIZE];

// callback functions
void on_pdm_samples_ready();
void on_usb_microphone_tx_ready();

int main(void)
{
  // initialize and start the PDM microphone
  pdm_microphone_init(&config);
  pdm_microphone_set_samples_ready_handler(on_pdm_samples_ready);
  pdm_microphone_start();

  // initialize the USB microphone interface
  usb_microphone_init();
  usb_microphone_set_tx_ready_handler(on_usb_microphone_tx_ready);

  while (1) {
    // run the USB microphone task continuously
    usb_microphone_task();
  }

  return 0;
}

void on_pdm_samples_ready()
{
  // Callback from library when all the samples in the library
  // internal sample buffer are ready for reading.
  //
  // Read new samples into local buffer.
  pdm_microphone_read(sample_buffer, SAMPLE_BUFFER_SIZE);
}

void on_usb_microphone_tx_ready()
{
  // Callback from TinyUSB library when all data is ready
  // to be transmitted.
  //
  // Write local buffer to the USB microphone
  usb_microphone_write(sample_buffer, sizeof(sample_buffer));
}


================================================
FILE: examples/usb_microphone/tusb_config.h
================================================
/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2019 Ha Thach (tinyusb.org)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */

#ifndef _TUSB_CONFIG_H_
#define _TUSB_CONFIG_H_

#ifdef __cplusplus
extern "C" {
#endif

//--------------------------------------------------------------------
// COMMON CONFIGURATION
//--------------------------------------------------------------------

// defined by compiler flags for flexibility
#ifndef CFG_TUSB_MCU
#error CFG_TUSB_MCU must be defined
#endif

#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
#define CFG_TUSB_RHPORT0_MODE       (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED)
#else
#define CFG_TUSB_RHPORT0_MODE       OPT_MODE_DEVICE
#endif

#ifndef CFG_TUSB_OS
#define CFG_TUSB_OS                 OPT_OS_NONE
#endif

#ifndef CFG_TUSB_DEBUG
#define CFG_TUSB_DEBUG              0
#endif

// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
// #define CFG_TUSB_DEBUG           0

/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
 * Tinyusb use follows macros to declare transferring memory so that they can be put
 * into those specific section.
 * e.g
 * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
 * - CFG_TUSB_MEM_ALIGN   : __attribute__ ((aligned(4)))
 */
#ifndef CFG_TUSB_MEM_SECTION
#define CFG_TUSB_MEM_SECTION
#endif

#ifndef CFG_TUSB_MEM_ALIGN
#define CFG_TUSB_MEM_ALIGN          __attribute__ ((aligned(4)))
#endif

//--------------------------------------------------------------------
// DEVICE CONFIGURATION
//--------------------------------------------------------------------

#ifndef CFG_TUD_ENDPOINT0_SIZE
#define CFG_TUD_ENDPOINT0_SIZE    64
#endif

//------------- CLASS -------------//
#define CFG_TUD_CDC               0
#define CFG_TUD_MSC               0
#define CFG_TUD_HID               0
#define CFG_TUD_MIDI              0
#define CFG_TUD_AUDIO             1
#define CFG_TUD_VENDOR            0

//--------------------------------------------------------------------
// AUDIO CLASS DRIVER CONFIGURATION
//--------------------------------------------------------------------

// Have a look into audio_device.h for all configurations

#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN                                 TUD_AUDIO_MIC_ONE_CH_DESC_LEN
#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT                                 1                                       // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ                              64                                      // Size of control request buffer

#define CFG_TUD_AUDIO_ENABLE_EP_IN                                    1
#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX                    2                                       // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below
#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX                            1                                       // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below - be aware: for different number of channels you need another descriptor!
#define CFG_TUD_AUDIO_EP_SZ_IN                                        (16 + 1) * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX      // 16 Samples (16 kHz) x 2 Bytes/Sample x 1 Channel
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX                             CFG_TUD_AUDIO_EP_SZ_IN                  // Maximum EP IN size for all AS alternate settings used
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ                          CFG_TUD_AUDIO_EP_SZ_IN

#ifdef __cplusplus
}
#endif

#endif /* _TUSB_CONFIG_H_ */


================================================
FILE: examples/usb_microphone/usb_descriptors.c
================================================
/* 
 * The MIT License (MIT)
 *
 * Copyright (c) 2019 Ha Thach (tinyusb.org)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */

#include "tusb.h"

/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
 * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
 *
 * Auto ProductID layout's Bitmap:
 *   [MSB]     AUDIO | MIDI | HID | MSC | CDC          [LSB]
 */
#define _PID_MAP(itf, n)  ( (CFG_TUD_##itf) << (n) )
#define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
    _PID_MAP(MIDI, 3) | _PID_MAP(AUDIO, 4) | _PID_MAP(VENDOR, 5) )

//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
    .bLength            = sizeof(tusb_desc_device_t),
    .bDescriptorType    = TUSB_DESC_DEVICE,
    .bcdUSB             = 0x0200,

    // Use Interface Association Descriptor (IAD) for CDC
    // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
    .bDeviceClass       = TUSB_CLASS_MISC,
    .bDeviceSubClass    = MISC_SUBCLASS_COMMON,
    .bDeviceProtocol    = MISC_PROTOCOL_IAD,
    .bMaxPacketSize0    = CFG_TUD_ENDPOINT0_SIZE,

    .idVendor           = 0xCafe,
    .idProduct          = USB_PID,
    .bcdDevice          = 0x0100,

    .iManufacturer      = 0x01,
    .iProduct           = 0x02,
    .iSerialNumber      = 0x03,

    .bNumConfigurations = 0x01
};

// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const * tud_descriptor_device_cb(void)
{
  return (uint8_t const *) &desc_device;
}

//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
enum
{
  ITF_NUM_AUDIO_CONTROL = 0,
  ITF_NUM_AUDIO_STREAMING,
  ITF_NUM_TOTAL
};

#define CONFIG_TOTAL_LEN    	(TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO_MIC_ONE_CH_DESC_LEN)

#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
#define EPNUM_AUDIO   0x03
#else
#define EPNUM_AUDIO   0x01
#endif

uint8_t const desc_configuration[] =
{
    // Interface count, string index, total length, attribute, power in mA
    TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),

    // Interface number, string index, EP Out & EP In address, EP size
    TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, /*_nBitsUsedPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX*8, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EP_SZ_IN)
};

// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
  (void) index; // for multiple configurations
  return desc_configuration;
}

//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+

// array of pointer to string descriptors
char const* string_desc_arr [] =
{
    (const char[]) { 0x09, 0x04 }, 	// 0: is supported language is English (0x0409)
    "PaniRCorp",                   	// 1: Manufacturer
    "MicNode",              		// 2: Product
    "123456",                      	// 3: Serials, should use chip ID
    "UAC2",                 	 	// 4: Audio Interface
};

static uint16_t _desc_str[32];

// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
{
  (void) langid;

  uint8_t chr_count;

  if ( index == 0)
  {
    memcpy(&_desc_str[1], string_desc_arr[0], 2);
    chr_count = 1;
  }else
  {
    // Convert ASCII string into UTF-16

    if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;

    const char* str = string_desc_arr[index];

    // Cap at max char
    chr_count = strlen(str);
    if ( chr_count > 31 ) chr_count = 31;

    for(uint8_t i=0; i<chr_count; i++)
    {
      _desc_str[1+i] = str[i];
    }
  }

  // first byte is length (including header), second byte is string type
  _desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);

  return _desc_str;
}


================================================
FILE: examples/usb_microphone/usb_microphone.c
================================================
/* 
 * The MIT License (MIT)
 *
 * Copyright (c) 2020 Reinhard Panhuber
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */

#include "usb_microphone.h"

// Audio controls
// Current states
bool mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; 						// +1 for master channel 0
uint16_t volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; 					// +1 for master channel 0
uint32_t sampFreq;
uint8_t clkValid;

// Range states
audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX+1]; 			// Volume range state
audio_control_range_4_n_t(1) sampleFreqRng; 						// Sample frequency range state

static usb_microphone_tx_ready_handler_t usb_microphone_tx_ready_handler = NULL;

/*------------- MAIN -------------*/
void usb_microphone_init()
{
  tusb_init();

  // Init values
  sampFreq = SAMPLE_RATE;
  clkValid = 1;

  sampleFreqRng.wNumSubRanges = 1;
  sampleFreqRng.subrange[0].bMin = SAMPLE_RATE;
  sampleFreqRng.subrange[0].bMax = SAMPLE_RATE;
  sampleFreqRng.subrange[0].bRes = 0;
}

void usb_microphone_set_tx_ready_handler(usb_microphone_tx_ready_handler_t handler)
{
  usb_microphone_tx_ready_handler = handler;
}

uint16_t usb_microphone_write(const void * data, uint16_t len)
{
  return tud_audio_write ((uint8_t *)data, len);
}

void usb_microphone_task()
{
  tud_task();
}

//--------------------------------------------------------------------+
// Application Callback API Implementations
//--------------------------------------------------------------------+

// Invoked when audio class specific set request received for an EP
bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)
{
  (void) rhport;
  (void) pBuff;

  // We do not support any set range requests here, only current value requests
  TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);

  // Page 91 in UAC2 specification
  uint8_t channelNum = TU_U16_LOW(p_request->wValue);
  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
  uint8_t ep = TU_U16_LOW(p_request->wIndex);

  (void) channelNum; (void) ctrlSel; (void) ep;

  return false; 	// Yet not implemented
}

// Invoked when audio class specific set request received for an interface
bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)
{
  (void) rhport;
  (void) pBuff;

  // We do not support any set range requests here, only current value requests
  TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);

  // Page 91 in UAC2 specification
  uint8_t channelNum = TU_U16_LOW(p_request->wValue);
  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
  uint8_t itf = TU_U16_LOW(p_request->wIndex);

  (void) channelNum; (void) ctrlSel; (void) itf;

  return false; 	// Yet not implemented
}

// Invoked when audio class specific set request received for an entity
bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)
{
  (void) rhport;

  // Page 91 in UAC2 specification
  uint8_t channelNum = TU_U16_LOW(p_request->wValue);
  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
  uint8_t itf = TU_U16_LOW(p_request->wIndex);
  uint8_t entityID = TU_U16_HIGH(p_request->wIndex);

  (void) itf;

  // We do not support any set range requests here, only current value requests
  TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);

  // If request is for our feature unit
  if ( entityID == 2 )
  {
    switch ( ctrlSel )
    {
      case AUDIO_FU_CTRL_MUTE:
        // Request uses format layout 1
        TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_1_t));

        mute[channelNum] = ((audio_control_cur_1_t*) pBuff)->bCur;

        TU_LOG2("    Set Mute: %d of channel: %u\r\n", mute[channelNum], channelNum);

      return true;

      case AUDIO_FU_CTRL_VOLUME:
        // Request uses format layout 2
        TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_2_t));

        volume[channelNum] = ((audio_control_cur_2_t*) pBuff)->bCur;

        TU_LOG2("    Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum);

     return true;

        // Unknown/Unsupported control
      default:
        TU_BREAKPOINT();
      return false;
    }
  }
  return false;    // Yet not implemented
}

// Invoked when audio class specific get request received for an EP
bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request)
{
  (void) rhport;

  // Page 91 in UAC2 specification
  uint8_t channelNum = TU_U16_LOW(p_request->wValue);
  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
  uint8_t ep = TU_U16_LOW(p_request->wIndex);

  (void) channelNum; (void) ctrlSel; (void) ep;

  //	return tud_control_xfer(rhport, p_request, &tmp, 1);

  return false; 	// Yet not implemented
}

// Invoked when audio class specific get request received for an interface
bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request)
{
  (void) rhport;

  // Page 91 in UAC2 specification
  uint8_t channelNum = TU_U16_LOW(p_request->wValue);
  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
  uint8_t itf = TU_U16_LOW(p_request->wIndex);

  (void) channelNum; (void) ctrlSel; (void) itf;

  return false; 	// Yet not implemented
}

// Invoked when audio class specific get request received for an entity
bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request)
{
  (void) rhport;

  // Page 91 in UAC2 specification
  uint8_t channelNum = TU_U16_LOW(p_request->wValue);
  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
  // uint8_t itf = TU_U16_LOW(p_request->wIndex); 			// Since we have only one audio function implemented, we do not need the itf value
  uint8_t entityID = TU_U16_HIGH(p_request->wIndex);

  // Input terminal (Microphone input)
  if (entityID == 1)
  {
    switch (ctrlSel)
    {
      case AUDIO_TE_CTRL_CONNECTOR:;
      // The terminal connector control only has a get request with only the CUR attribute.

      audio_desc_channel_cluster_t ret;

      // Those are dummy values for now
      ret.bNrChannels = 1;
      ret.bmChannelConfig = 0;
      ret.iChannelNames = 0;

      TU_LOG2("    Get terminal connector\r\n");

      return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*)&ret, sizeof(ret));

      // Unknown/Unsupported control selector
      default: TU_BREAKPOINT(); return false;
    }
  }

  // Feature unit
  if (entityID == 2)
  {
    switch (ctrlSel)
    {
      case AUDIO_FU_CTRL_MUTE:
	// Audio control mute cur parameter block consists of only one byte - we thus can send it right away
	// There does not exist a range parameter block for mute
	TU_LOG2("    Get Mute of channel: %u\r\n", channelNum);
	return tud_control_xfer(rhport, p_request, &mute[channelNum], 1);

      case AUDIO_FU_CTRL_VOLUME:

	switch (p_request->bRequest)
	{
	  case AUDIO_CS_REQ_CUR:
	    TU_LOG2("    Get Volume of channel: %u\r\n", channelNum);
	    return tud_control_xfer(rhport, p_request, &volume[channelNum], sizeof(volume[channelNum]));
	  case AUDIO_CS_REQ_RANGE:
	    TU_LOG2("    Get Volume range of channel: %u\r\n", channelNum);

	    // Copy values - only for testing - better is version below
	    audio_control_range_2_n_t(1) ret;

	    ret.wNumSubRanges = 1;
	    ret.subrange[0].bMin = -90; 	// -90 dB
	    ret.subrange[0].bMax = 90;		// +90 dB
	    ret.subrange[0].bRes = 1; 		// 1 dB steps

	    return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*)&ret, sizeof(ret));

	    // Unknown/Unsupported control
	  default: TU_BREAKPOINT(); return false;
	}

	// Unknown/Unsupported control
	  default: TU_BREAKPOINT(); return false;
    }
  }

  // Clock Source unit
  if (entityID == 4)
  {
    switch (ctrlSel)
    {
      case AUDIO_CS_CTRL_SAM_FREQ:

	// channelNum is always zero in this case

	switch (p_request->bRequest)
	{
	  case AUDIO_CS_REQ_CUR:
	    TU_LOG2("    Get Sample Freq.\r\n");
	    return tud_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq));
	  case AUDIO_CS_REQ_RANGE:
	    TU_LOG2("    Get Sample Freq. range\r\n");
	    return tud_control_xfer(rhport, p_request, &sampleFreqRng, sizeof(sampleFreqRng));

	    // Unknown/Unsupported control
	  default: TU_BREAKPOINT(); return false;
	}

	  case AUDIO_CS_CTRL_CLK_VALID:
	    // Only cur attribute exists for this request
	    TU_LOG2("    Get Sample Freq. valid\r\n");
	    return tud_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid));

	    // Unknown/Unsupported control
	  default: TU_BREAKPOINT(); return false;
    }
  }

  TU_LOG2("  Unsupported entity: %d\r\n", entityID);
  return false; 	// Yet not implemented
}

bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting)
{
  (void) rhport;
  (void) itf;
  (void) ep_in;
  (void) cur_alt_setting;

  if (usb_microphone_tx_ready_handler)
  {
    usb_microphone_tx_ready_handler();
  }

  return true;
}

bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting)
{
  (void) rhport;
  (void) n_bytes_copied;
  (void) itf;
  (void) ep_in;
  (void) cur_alt_setting;

  return true;
}

bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request)
{
  (void) rhport;
  (void) p_request;

  return true;
}


================================================
FILE: examples/usb_microphone/usb_microphone.h
================================================
/*
 * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 * 
 */

#ifndef _USB_MICROPHONE_H_
#define _USB_MICROPHONE_H_

#include "tusb.h"

#ifndef SAMPLE_RATE
#define SAMPLE_RATE ((CFG_TUD_AUDIO_EP_SZ_IN / 2) - 1) * 1000
#endif

#ifndef SAMPLE_BUFFER_SIZE
#define SAMPLE_BUFFER_SIZE ((CFG_TUD_AUDIO_EP_SZ_IN/2) - 1)
#endif

typedef void (*usb_microphone_tx_ready_handler_t)(void);

void usb_microphone_init();
void usb_microphone_set_tx_ready_handler(usb_microphone_tx_ready_handler_t handler);
void usb_microphone_task();
uint16_t usb_microphone_write(const void * data, uint16_t len);

#endif


================================================
FILE: pico_sdk_import.cmake
================================================
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake

# This can be dropped into an external project to help locate this SDK
# It should be include()ed prior to project()

if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
    set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
    message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
endif ()

if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
    set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
    message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
endif ()

if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
    set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
    message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
endif ()

set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")

if (NOT PICO_SDK_PATH)
    if (PICO_SDK_FETCH_FROM_GIT)
        include(FetchContent)
        set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
        if (PICO_SDK_FETCH_FROM_GIT_PATH)
            get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
        endif ()
        FetchContent_Declare(
                pico_sdk
                GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
                GIT_TAG master
        )
        if (NOT pico_sdk)
            message("Downloading Raspberry Pi Pico SDK")
            FetchContent_Populate(pico_sdk)
            set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
        endif ()
        set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
    else ()
        message(FATAL_ERROR
                "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
                )
    endif ()
endif ()

get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${PICO_SDK_PATH})
    message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
endif ()

set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
    message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
endif ()

set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)

include(${PICO_SDK_INIT_CMAKE_FILE})


================================================
FILE: src/OpenPDM2PCM/LICENSE.txt
================================================
 
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/
 
   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 
   1. Definitions.
 
      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.
 
      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.
 
      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.
 
      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.
 
      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.
 
      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.
 
      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).
 
      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.
 
      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."
 
      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.
 
   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.
 
   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.
 
   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:
 
      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and
 
      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and
 
      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and
 
      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.
 
      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.
 
   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.
 
   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.
 
   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.
 
   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.
 
   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.
 
   END OF TERMS AND CONDITIONS
 
   APPENDIX: How to apply the Apache License to your work.
 
      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.
 
   Copyright [yyyy] [name of copyright owner]
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at
 
       http://www.apache.org/licenses/LICENSE-2.0
 
   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 
            
Repository toolbox
Import into Mbed Studio
 Export to desktop IDE
Repository details
Type:	 Library
Created:	27 Apr 2017
Imports:	 122
Forks:	 1
Commits:	 27
Dependents:	 4
Dependencies:	 3
Followers:	 387
The code in this repository is Apache licensed.
Components
 X-NUCLEO-CCA02M1 Digital MEMS Microphones Expansion Board.


================================================
FILE: src/OpenPDM2PCM/OpenPDMFilter.c
================================================
/**
 *******************************************************************************
 * @file    OpenPDMFilter.c
 * @author  CL
 * @version V1.0.0
 * @date    9-September-2015
 * @brief   Open PDM audio software decoding Library.   
 *          This Library is used to decode and reconstruct the audio signal
 *          produced by ST MEMS microphone (MP45Dxxx, MP34Dxxx). 
 *******************************************************************************
 * @attention
 *
 * <h2><center>&copy; COPYRIGHT 2018 STMicroelectronics</center></h2>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************
 */
 
 
/* Includes ------------------------------------------------------------------*/
 
#include "OpenPDMFilter.h"
 
 
/* Variables -----------------------------------------------------------------*/
 
uint32_t div_const = 0;
int64_t sub_const = 0;
uint32_t sinc[DECIMATION_MAX * SINCN];
uint32_t sinc1[DECIMATION_MAX];
uint32_t sinc2[DECIMATION_MAX * 2];
uint32_t coef[SINCN][DECIMATION_MAX];
#ifdef USE_LUT
int32_t lut[256][DECIMATION_MAX / 8][SINCN];
#endif
 
 
/* Functions -----------------------------------------------------------------*/
 
#ifdef USE_LUT
int32_t filter_table_mono_64(uint8_t *data, uint8_t sincn)
{
  return (int32_t)
    lut[data[0]][0][sincn] +
    lut[data[1]][1][sincn] +
    lut[data[2]][2][sincn] +
    lut[data[3]][3][sincn] +
    lut[data[4]][4][sincn] +
    lut[data[5]][5][sincn] +
    lut[data[6]][6][sincn] +
    lut[data[7]][7][sincn];
}
int32_t filter_table_stereo_64(uint8_t *data, uint8_t sincn)
{
  return (int32_t)
    lut[data[0]][0][sincn] +
    lut[data[2]][1][sincn] +
    lut[data[4]][2][sincn] +
    lut[data[6]][3][sincn] +
    lut[data[8]][4][sincn] +
    lut[data[10]][5][sincn] +
    lut[data[12]][6][sincn] +
    lut[data[14]][7][sincn];
}
int32_t filter_table_mono_128(uint8_t *data, uint8_t sincn)
{
  return (int32_t)
    lut[data[0]][0][sincn] +
    lut[data[1]][1][sincn] +
    lut[data[2]][2][sincn] +
    lut[data[3]][3][sincn] +
    lut[data[4]][4][sincn] +
    lut[data[5]][5][sincn] +
    lut[data[6]][6][sincn] +
    lut[data[7]][7][sincn] +
    lut[data[8]][8][sincn] +
    lut[data[9]][9][sincn] +
    lut[data[10]][10][sincn] +
    lut[data[11]][11][sincn] +
    lut[data[12]][12][sincn] +
    lut[data[13]][13][sincn] +
    lut[data[14]][14][sincn] +
    lut[data[15]][15][sincn];
}
int32_t filter_table_stereo_128(uint8_t *data, uint8_t sincn)
{
  return (int32_t)
    lut[data[0]][0][sincn] +
    lut[data[2]][1][sincn] +
    lut[data[4]][2][sincn] +
    lut[data[6]][3][sincn] +
    lut[data[8]][4][sincn] +
    lut[data[10]][5][sincn] +
    lut[data[12]][6][sincn] +
    lut[data[14]][7][sincn] +
    lut[data[16]][8][sincn] +
    lut[data[18]][9][sincn] +
    lut[data[20]][10][sincn] +
    lut[data[22]][11][sincn] +
    lut[data[24]][12][sincn] +
    lut[data[26]][13][sincn] +
    lut[data[28]][14][sincn] +
    lut[data[30]][15][sincn];
}
int32_t (* filter_tables_64[2]) (uint8_t *data, uint8_t sincn) = {filter_table_mono_64, filter_table_stereo_64};
int32_t (* filter_tables_128[2]) (uint8_t *data, uint8_t sincn) = {filter_table_mono_128, filter_table_stereo_128};
#else
int32_t filter_table(uint8_t *data, uint8_t sincn, TPDMFilter_InitStruct *param)
{
  uint8_t c, i;
  uint16_t data_index = 0;
  uint32_t *coef_p = &coef[sincn][0];
  int32_t F = 0;
  uint8_t decimation = param->Decimation;
  uint8_t channels = param->In_MicChannels;
 
  for (i = 0; i < decimation; i += 8) {
    c = data[data_index];
    F += ((c >> 7)       ) * coef_p[i    ] +
         ((c >> 6) & 0x01) * coef_p[i + 1] +
         ((c >> 5) & 0x01) * coef_p[i + 2] +
         ((c >> 4) & 0x01) * coef_p[i + 3] +
         ((c >> 3) & 0x01) * coef_p[i + 4] +
         ((c >> 2) & 0x01) * coef_p[i + 5] +
         ((c >> 1) & 0x01) * coef_p[i + 6] +
         ((c     ) & 0x01) * coef_p[i + 7];
    data_index += channels;
  }
  return F;
}
#endif
 
void convolve(uint32_t Signal[/* SignalLen */], unsigned short SignalLen,
              uint32_t Kernel[/* KernelLen */], unsigned short KernelLen,
              uint32_t Result[/* SignalLen + KernelLen - 1 */])
{
  uint16_t n;
 
  for (n = 0; n < SignalLen + KernelLen - 1; n++)
  {
    unsigned short kmin, kmax, k;
    
    Result[n] = 0;
    
    kmin = (n >= KernelLen - 1) ? n - (KernelLen - 1) : 0;
    kmax = (n < SignalLen - 1) ? n : SignalLen - 1;
    
    for (k = kmin; k <= kmax; k++) {
      Result[n] += Signal[k] * Kernel[n - k];
    }
  }
}
 
void Open_PDM_Filter_Init(TPDMFilter_InitStruct *Param)
{
  uint16_t i, j;
  int64_t sum = 0;
 
  uint8_t decimation = Param->Decimation;
 
  for (i = 0; i < SINCN; i++) {
    Param->Coef[i] = 0;
    Param->bit[i] = 0;
  }
  for (i = 0; i < decimation; i++) {
    sinc1[i] = 1;
  }
 
  Param->OldOut = Param->OldIn = Param->OldZ = 0;
  Param->LP_ALFA = (Param->LP_HZ != 0 ? (uint16_t) (Param->LP_HZ * 256 / (Param->LP_HZ + Param->Fs / (2 * 3.14159))) : 0);
  Param->HP_ALFA = (Param->HP_HZ != 0 ? (uint16_t) (Param->Fs * 256 / (2 * 3.14159 * Param->HP_HZ + Param->Fs)) : 0);
 
  Param->FilterLen = decimation * SINCN;       
  sinc[0] = 0;
  sinc[decimation * SINCN - 1] = 0;      
  convolve(sinc1, decimation, sinc1, decimation, sinc2);
  convolve(sinc2, decimation * 2 - 1, sinc1, decimation, &sinc[1]);     
  for(j = 0; j < SINCN; j++) {
    for (i = 0; i < decimation; i++) {
      coef[j][i] = sinc[j * decimation + i];
      sum += sinc[j * decimation + i];
    }
  }
 
  sub_const = sum >> 1;
  div_const = sub_const * Param->MaxVolume / 32768 / FILTER_GAIN;
  div_const = (div_const == 0 ? 1 : div_const);
 
#ifdef USE_LUT
  /* Look-Up Table. */
  uint16_t c, d, s;
  for (s = 0; s < SINCN; s++)
  {
    uint32_t *coef_p = &coef[s][0];
    for (c = 0; c < 256; c++)
      for (d = 0; d < decimation / 8; d++)
        lut[c][d][s] = ((c >> 7)       ) * coef_p[d * 8    ] +
                       ((c >> 6) & 0x01) * coef_p[d * 8 + 1] +
                       ((c >> 5) & 0x01) * coef_p[d * 8 + 2] +
                       ((c >> 4) & 0x01) * coef_p[d * 8 + 3] +
                       ((c >> 3) & 0x01) * coef_p[d * 8 + 4] +
                       ((c >> 2) & 0x01) * coef_p[d * 8 + 5] +
                       ((c >> 1) & 0x01) * coef_p[d * 8 + 6] +
                       ((c     ) & 0x01) * coef_p[d * 8 + 7];
  }
#endif
}
 
void Open_PDM_Filter_64(uint8_t* data, uint16_t* dataOut, uint16_t volume, TPDMFilter_InitStruct *Param)
{
  uint8_t i, data_out_index;
  uint8_t channels = Param->In_MicChannels;
  uint8_t data_inc = ((DECIMATION_MAX >> 4) * channels);
  int64_t Z, Z0, Z1, Z2;
  int64_t OldOut, OldIn, OldZ;
 
  OldOut = Param->OldOut;
  OldIn = Param->OldIn;
  OldZ = Param->OldZ;
 
#ifdef USE_LUT
  uint8_t j = channels - 1;
#endif
 
  for (i = 0, data_out_index = 0; i < Param->Fs / 1000; i++, data_out_index += channels) {
#ifdef USE_LUT
    Z0 = filter_tables_64[j](data, 0);
    Z1 = filter_tables_64[j](data, 1);
    Z2 = filter_tables_64[j](data, 2);
#else
    Z0 = filter_table(data, 0, Param);
    Z1 = filter_table(data, 1, Param);
    Z2 = filter_table(data, 2, Param);
#endif
 
    Z = Param->Coef[1] + Z2 - sub_const;
    Param->Coef[1] = Param->Coef[0] + Z1;
    Param->Coef[0] = Z0;
 
    OldOut = (Param->HP_ALFA * (OldOut + Z - OldIn)) >> 8;
    OldIn = Z;
    OldZ = ((256 - Param->LP_ALFA) * OldZ + Param->LP_ALFA * OldOut) >> 8;
 
    Z = OldZ * volume;
    Z = RoundDiv(Z, div_const);
    Z = SaturaLH(Z, -32700, 32700);
 
    dataOut[data_out_index] = Z;
    data += data_inc;
  }
 
  Param->OldOut = OldOut;
  Param->OldIn = OldIn;
  Param->OldZ = OldZ;
}
 
void Open_PDM_Filter_128(uint8_t* data, uint16_t* dataOut, uint16_t volume, TPDMFilter_InitStruct *Param)
{
  uint8_t i, data_out_index;
  uint8_t channels = Param->In_MicChannels;
  uint8_t data_inc = ((DECIMATION_MAX >> 3) * channels);
  int64_t Z, Z0, Z1, Z2;
  int64_t OldOut, OldIn, OldZ;
 
  OldOut = Param->OldOut;
  OldIn = Param->OldIn;
  OldZ = Param->OldZ;
 
#ifdef USE_LUT
  uint8_t j = channels - 1;
#endif
 
  for (i = 0, data_out_index = 0; i < Param->Fs / 1000; i++, data_out_index += channels) {
#ifdef USE_LUT
    Z0 = filter_tables_128[j](data, 0);
    Z1 = filter_tables_128[j](data, 1);
    Z2 = filter_tables_128[j](data, 2);
#else
    Z0 = filter_table(data, 0, Param);
    Z1 = filter_table(data, 1, Param);
    Z2 = filter_table(data, 2, Param);
#endif
 
    Z = Param->Coef[1] + Z2 - sub_const;
    Param->Coef[1] = Param->Coef[0] + Z1;
    Param->Coef[0] = Z0;
 
    OldOut = (Param->HP_ALFA * (OldOut + Z - OldIn)) >> 8;
    OldIn = Z;
    OldZ = ((256 - Param->LP_ALFA) * OldZ + Param->LP_ALFA * OldOut) >> 8;
 
    Z = OldZ * volume;
    Z = RoundDiv(Z, div_const);
    Z = SaturaLH(Z, -32700, 32700);
 
    dataOut[data_out_index] = Z;
    data += data_inc;
  }
 
  Param->OldOut = OldOut;
  Param->OldIn = OldIn;
  Param->OldZ = OldZ;
}
 


================================================
FILE: src/OpenPDM2PCM/OpenPDMFilter.h
================================================
/**
 *******************************************************************************
 * @file    OpenPDMFilter.h
 * @author  CL
 * @version V1.0.0
 * @date    9-September-2015
 * @brief   Header file for Open PDM audio software decoding Library.   
 *          This Library is used to decode and reconstruct the audio signal
 *          produced by ST MEMS microphone (MP45Dxxx, MP34Dxxx). 
 *******************************************************************************
 * @attention
 *
 * <h2><center>&copy; COPYRIGHT 2018 STMicroelectronics</center></h2>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************
 */
 
 
/* Define to prevent recursive inclusion -------------------------------------*/
 
#ifndef __OPENPDMFILTER_H
#define __OPENPDMFILTER_H
 
#ifdef __cplusplus
  extern "C" {
#endif
 
 
/* Includes ------------------------------------------------------------------*/
 
#include <stdint.h>
 
 
/* Definitions ---------------------------------------------------------------*/
 
/*
 * Enable to use a Look-Up Table to improve performances while using more FLASH
 * and RAM memory.
 * Note: Without Look-Up Table up to stereo@16KHz configuration is supported.
 */
#define USE_LUT
 
#define SINCN            3
#define DECIMATION_MAX 128
#ifdef PICO_BUILD
#define FILTER_GAIN     Param->Gain
#else
#define FILTER_GAIN     16
#endif
 
#define HTONS(A) ((((uint16_t)(A) & 0xff00) >> 8) | \
                 (((uint16_t)(A) & 0x00ff) << 8))
#define RoundDiv(a, b)    (((a)>0)?(((a)+(b)/2)/(b)):(((a)-(b)/2)/(b)))
#define SaturaLH(N, L, H) (((N)<(L))?(L):(((N)>(H))?(H):(N)))
 
 
/* Types ---------------------------------------------------------------------*/
 
typedef struct {
  /* Public */
  float LP_HZ;
  float HP_HZ;
  uint16_t Fs;
  uint8_t In_MicChannels;
  uint8_t Out_MicChannels;
  uint8_t Decimation;
  uint8_t MaxVolume;
#ifdef PICO_BUILD
  uint8_t Gain;
#endif
  /* Private */
  uint32_t Coef[SINCN];
  uint16_t FilterLen;
  int64_t OldOut, OldIn, OldZ;
  uint16_t LP_ALFA;
  uint16_t HP_ALFA;
  uint16_t bit[5];
  uint16_t byte;
} TPDMFilter_InitStruct;
 
 
/* Exported functions ------------------------------------------------------- */
 
void Open_PDM_Filter_Init(TPDMFilter_InitStruct *init_struct);
void Open_PDM_Filter_64(uint8_t* data, uint16_t* data_out, uint16_t mic_gain, TPDMFilter_InitStruct *init_struct);
void Open_PDM_Filter_128(uint8_t* data, uint16_t* data_out, uint16_t mic_gain, TPDMFilter_InitStruct *init_struct);
 
#ifdef __cplusplus
}
#endif
 
#endif // __OPENPDMFILTER_H
 
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
 


================================================
FILE: src/analog_microphone.c
================================================
/*
 * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 * 
 */

#include <stdlib.h>
#include <string.h>

#include "hardware/adc.h"
#include "hardware/clocks.h"
#include "hardware/dma.h"
#include "hardware/irq.h"

#include "pico/analog_microphone.h"

#define ANALOG_RAW_BUFFER_COUNT 2

static struct {
    struct analog_microphone_config config;
    int dma_channel;
    uint16_t* raw_buffer[ANALOG_RAW_BUFFER_COUNT];
    volatile int raw_buffer_write_index;
    volatile int raw_buffer_read_index;
    uint buffer_size;
    int16_t bias;
    uint dma_irq;
    analog_samples_ready_handler_t samples_ready_handler;
} analog_mic;

static void analog_dma_handler();

int analog_microphone_init(const struct analog_microphone_config* config) {
    memset(&analog_mic, 0x00, sizeof(analog_mic));
    memcpy(&analog_mic.config, config, sizeof(analog_mic.config));

    if (config->gpio < 26 || config->gpio > 29) {
        return -1;
    }

    size_t raw_buffer_size = config->sample_buffer_size * sizeof(analog_mic.raw_buffer[0][0]);

    analog_mic.buffer_size = config->sample_buffer_size;
    analog_mic.bias = ((int16_t)((config->bias_voltage * 4095) / 3.3));

    for (int i = 0; i < ANALOG_RAW_BUFFER_COUNT; i++) {
        analog_mic.raw_buffer[i] = malloc(raw_buffer_size);
        if (analog_mic.raw_buffer[i] == NULL) {
            analog_microphone_deinit();

            return -1;   
        }
    }

    analog_mic.dma_channel = dma_claim_unused_channel(true);
    if (analog_mic.dma_channel < 0) {
        analog_microphone_deinit();

        return -1;
    }

    float clk_div = (clock_get_hz(clk_adc) / (1.0 * config->sample_rate)) - 1;

    dma_channel_config dma_channel_cfg = dma_channel_get_default_config(analog_mic.dma_channel);

    channel_config_set_transfer_data_size(&dma_channel_cfg, DMA_SIZE_16);
    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, DREQ_ADC);

    analog_mic.dma_irq = DMA_IRQ_0;

    dma_channel_configure(
        analog_mic.dma_channel,
        &dma_channel_cfg,
        analog_mic.raw_buffer[0],
        &adc_hw->fifo,
        analog_mic.buffer_size,
        false
    );

    adc_gpio_init(config->gpio);

    adc_init();
    adc_select_input(config->gpio - 26);
    adc_fifo_setup(
        true,    // Write each completed conversion to the sample FIFO
        true,    // Enable DMA data request (DREQ)
        1,       // DREQ (and IRQ) asserted when at least 1 sample present
        false,   // We won't see the ERR bit because of 8 bit reads; disable.
        false    // Don't shift each sample to 8 bits when pushing to FIFO
    );

    adc_set_clkdiv(clk_div);
}

void analog_microphone_deinit() {
    for (int i = 0; i < ANALOG_RAW_BUFFER_COUNT; i++) {
        if (analog_mic.raw_buffer[i]) {
            free(analog_mic.raw_buffer[i]);

            analog_mic.raw_buffer[i] = NULL;
        }
    }

    if (analog_mic.dma_channel > -1) {
        dma_channel_unclaim(analog_mic.dma_channel);

        analog_mic.dma_channel = -1;
    }
}

int analog_microphone_start() {
    irq_set_enabled(analog_mic.dma_irq, true);
    irq_set_exclusive_handler(analog_mic.dma_irq, analog_dma_handler);

    if (analog_mic.dma_irq == DMA_IRQ_0) {
        dma_channel_set_irq0_enabled(analog_mic.dma_channel, true);
    } else if (analog_mic.dma_irq == DMA_IRQ_1) {
        dma_channel_set_irq1_enabled(analog_mic.dma_channel, true);
    } else {
        return -1;
    }

    analog_mic.raw_buffer_write_index = 0;
    analog_mic.raw_buffer_read_index = 0;

    dma_channel_transfer_to_buffer_now(
        analog_mic.dma_channel,
        analog_mic.raw_buffer[0],
        analog_mic.buffer_size
    );

    adc_run(true); // start running the adc
}

void analog_microphone_stop() {
    adc_run(false); // stop running the adc

    dma_channel_abort(analog_mic.dma_channel);

    if (analog_mic.dma_irq == DMA_IRQ_0) {
        dma_channel_set_irq0_enabled(analog_mic.dma_channel, false);
    } else if (analog_mic.dma_irq == DMA_IRQ_1) {
        dma_channel_set_irq1_enabled(analog_mic.dma_channel, false);
    }

    irq_set_enabled(analog_mic.dma_irq, false);
}

static void analog_dma_handler() {
    // clear IRQ
    if (analog_mic.dma_irq == DMA_IRQ_0) {
        dma_hw->ints0 = (1u << analog_mic.dma_channel);
    } else if (analog_mic.dma_irq == DMA_IRQ_1) {
        dma_hw->ints1 = (1u << analog_mic.dma_channel);
    }

    // get the current buffer index
    analog_mic.raw_buffer_read_index = analog_mic.raw_buffer_write_index;

    // get the next capture index to send the dma to start
    analog_mic.raw_buffer_write_index = (analog_mic.raw_buffer_write_index + 1) % ANALOG_RAW_BUFFER_COUNT;

    // give the channel a new buffer to write to and re-trigger it
    dma_channel_transfer_to_buffer_now(
        analog_mic.dma_channel,
        analog_mic.raw_buffer[analog_mic.raw_buffer_write_index],
        analog_mic.buffer_size
    );

    if (analog_mic.samples_ready_handler) {
        analog_mic.samples_ready_handler();
    }
}

void analog_microphone_set_samples_ready_handler(analog_samples_ready_handler_t handler) {
    analog_mic.samples_ready_handler = handler;
}

int analog_microphone_read(int16_t* buffer, size_t samples) {
    if (samples > analog_mic.config.sample_buffer_size) {
        samples = analog_mic.config.sample_buffer_size;
    }

    if (analog_mic.raw_buffer_write_index == analog_mic.raw_buffer_read_index) {
        return 0;
    }

    uint16_t* in = analog_mic.raw_buffer[analog_mic.raw_buffer_read_index];
    int16_t* out = buffer;
    int16_t bias = analog_mic.bias;

    analog_mic.raw_buffer_read_index++;

    for (int i = 0; i < samples; i++) {
        *out++ = *in++ - bias;
    }

    return samples;
}


================================================
FILE: src/include/pico/analog_microphone.h
================================================
/*
 * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 * 
 */

#ifndef _PICO_ANALOG_MICROPHONE_H_
#define _PICO_ANALOG_MICROPHONE_H_

typedef void (*analog_samples_ready_handler_t)(void);

struct analog_microphone_config {
    uint gpio;
    float bias_voltage;
    uint sample_rate;
    uint sample_buffer_size;
};

int analog_microphone_init(const struct analog_microphone_config* config);
void analog_microphone_deinit();

int analog_microphone_start();
void analog_microphone_stop();

void analog_microphone_set_samples_ready_handler(analog_samples_ready_handler_t handler);

int analog_microphone_read(int16_t* buffer, size_t samples);

#endif


================================================
FILE: src/include/pico/pdm_microphone.h
================================================
/*
 * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 * 
 */

#ifndef _PICO_PDM_MICROPHONE_H_
#define _PICO_PDM_MICROPHONE_H_

#include "hardware/pio.h"

typedef void (*pdm_samples_ready_handler_t)(void);

struct pdm_microphone_config {
    uint gpio_data;
    uint gpio_clk;
    PIO pio;
    uint pio_sm;
    uint sample_rate;
    uint sample_buffer_size;
};

int pdm_microphone_init(const struct pdm_microphone_config* config);
void pdm_microphone_deinit();

int pdm_microphone_start();
void pdm_microphone_stop();

void pdm_microphone_set_samples_ready_handler(pdm_samples_ready_handler_t handler);
void pdm_microphone_set_filter_max_volume(uint8_t max_volume);
void pdm_microphone_set_filter_gain(uint8_t gain);
void pdm_microphone_set_filter_volume(uint16_t volume);

int pdm_microphone_read(int16_t* buffer, size_t samples);

#endif


================================================
FILE: src/pdm_microphone.c
================================================
/*
 * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 * 
 */

#include <stdlib.h>
#include <string.h>

#include "hardware/clocks.h"
#include "hardware/dma.h"
#include "hardware/irq.h"

#include "OpenPDM2PCM/OpenPDMFilter.h"

#include "pdm_microphone.pio.h"

#include "pico/pdm_microphone.h"

#define PDM_DECIMATION       64
#define PDM_RAW_BUFFER_COUNT 2

static struct {
    struct pdm_microphone_config config;
    int dma_channel;
    uint8_t* raw_buffer[PDM_RAW_BUFFER_COUNT];
    volatile int raw_buffer_write_index;
    volatile int raw_buffer_read_index;
    uint raw_buffer_size;
    uint dma_irq;
    TPDMFilter_InitStruct filter;
    uint16_t filter_volume;
    pdm_samples_ready_handler_t samples_ready_handler;
} pdm_mic;

static void pdm_dma_handler();

int pdm_microphone_init(const struct pdm_microphone_config* config) {
    memset(&pdm_mic, 0x00, sizeof(pdm_mic));
    memcpy(&pdm_mic.config, config, sizeof(pdm_mic.config));

    if (config->sample_buffer_size % (config->sample_rate / 1000)) {
        return -1;
    }

    pdm_mic.raw_buffer_size = config->sample_buffer_size * (PDM_DECIMATION / 8);

    for (int i = 0; i < PDM_RAW_BUFFER_COUNT; i++) {
        pdm_mic.raw_buffer[i] = malloc(pdm_mic.raw_buffer_size);
        if (pdm_mic.raw_buffer[i] == NULL) {
            pdm_microphone_deinit();

            return -1;   
        }
    }

    pdm_mic.dma_channel = dma_claim_unused_channel(true);
    if (pdm_mic.dma_channel < 0) {
        pdm_microphone_deinit();

        return -1;
    }

    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 * 4.0);

    pdm_microphone_data_init(
        config->pio,
        config->pio_sm,
        pio_sm_offset,
        clk_div,
        config->gpio_data,
        config->gpio_clk
    );

    dma_channel_config dma_channel_cfg = dma_channel_get_default_config(pdm_mic.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));

    pdm_mic.dma_irq = DMA_IRQ_0;

    dma_channel_configure(
        pdm_mic.dma_channel,
        &dma_channel_cfg,
        pdm_mic.raw_buffer[0],
        &config->pio->rxf[config->pio_sm],
        pdm_mic.raw_buffer_size,
        false
    );

    pdm_mic.filter.Fs = config->sample_rate;
    pdm_mic.filter.LP_HZ = config->sample_rate / 2;
    pdm_mic.filter.HP_HZ = 10;
    pdm_mic.filter.In_MicChannels = 1;
    pdm_mic.filter.Out_MicChannels = 1;
    pdm_mic.filter.Decimation = PDM_DECIMATION;
    pdm_mic.filter.MaxVolume = 64;
    pdm_mic.filter.Gain = 16;

    pdm_mic.filter_volume = pdm_mic.filter.MaxVolume;
}

void pdm_microphone_deinit() {
    for (int i = 0; i < PDM_RAW_BUFFER_COUNT; i++) {
        if (pdm_mic.raw_buffer[i]) {
            free(pdm_mic.raw_buffer[i]);

            pdm_mic.raw_buffer[i] = NULL;
        }
    }

    if (pdm_mic.dma_channel > -1) {
        dma_channel_unclaim(pdm_mic.dma_channel);

        pdm_mic.dma_channel = -1;
    }
}

int pdm_microphone_start() {
    irq_set_enabled(pdm_mic.dma_irq, true);
    irq_set_exclusive_handler(pdm_mic.dma_irq, pdm_dma_handler);

    if (pdm_mic.dma_irq == DMA_IRQ_0) {
        dma_channel_set_irq0_enabled(pdm_mic.dma_channel, true);
    } else if (pdm_mic.dma_irq == DMA_IRQ_1) {
        dma_channel_set_irq1_enabled(pdm_mic.dma_channel, true);
    } else {
        return -1;
    }

    Open_PDM_Filter_Init(&pdm_mic.filter);

    pio_sm_set_enabled(
        pdm_mic.config.pio,
        pdm_mic.config.pio_sm,
        true
    );

    pdm_mic.raw_buffer_write_index = 0;
    pdm_mic.raw_buffer_read_index = 0;

    dma_channel_transfer_to_buffer_now(
        pdm_mic.dma_channel,
        pdm_mic.raw_buffer[0],
        pdm_mic.raw_buffer_size
    );

    pio_sm_set_enabled(
        pdm_mic.config.pio,
        pdm_mic.config.pio_sm,
        true
    );
}

void pdm_microphone_stop() {
    pio_sm_set_enabled(
        pdm_mic.config.pio,
        pdm_mic.config.pio_sm,
        false
    );

    dma_channel_abort(pdm_mic.dma_channel);

    if (pdm_mic.dma_irq == DMA_IRQ_0) {
        dma_channel_set_irq0_enabled(pdm_mic.dma_channel, false);
    } else if (pdm_mic.dma_irq == DMA_IRQ_1) {
        dma_channel_set_irq1_enabled(pdm_mic.dma_channel, false);
    }

    irq_set_enabled(pdm_mic.dma_irq, false);
}

static void pdm_dma_handler() {
    // clear IRQ
    if (pdm_mic.dma_irq == DMA_IRQ_0) {
        dma_hw->ints0 = (1u << pdm_mic.dma_channel);
    } else if (pdm_mic.dma_irq == DMA_IRQ_1) {
        dma_hw->ints1 = (1u << pdm_mic.dma_channel);
    }

    // get the current buffer index
    pdm_mic.raw_buffer_read_index = pdm_mic.raw_buffer_write_index;

    // get the next capture index to send the dma to start
    pdm_mic.raw_buffer_write_index = (pdm_mic.raw_buffer_write_index + 1) % PDM_RAW_BUFFER_COUNT;

    // give the channel a new buffer to write to and re-trigger it
    dma_channel_transfer_to_buffer_now(
        pdm_mic.dma_channel,
        pdm_mic.raw_buffer[pdm_mic.raw_buffer_write_index],
        pdm_mic.raw_buffer_size
    );

    if (pdm_mic.samples_ready_handler) {
        pdm_mic.samples_ready_handler();
    }
}

void pdm_microphone_set_samples_ready_handler(pdm_samples_ready_handler_t handler) {
    pdm_mic.samples_ready_handler = handler;
}

void pdm_microphone_set_filter_max_volume(uint8_t max_volume) {
    pdm_mic.filter.MaxVolume = max_volume;
}

void pdm_microphone_set_filter_gain(uint8_t gain) {
    pdm_mic.filter.Gain = gain;
}

void pdm_microphone_set_filter_volume(uint16_t volume) {
    pdm_mic.filter_volume = volume;
}

int pdm_microphone_read(int16_t* buffer, size_t samples) {
    int filter_stride = (pdm_mic.filter.Fs / 1000);
    samples = (samples / filter_stride) * filter_stride;

    if (samples > pdm_mic.config.sample_buffer_size) {
        samples = pdm_mic.config.sample_buffer_size;
    }

    if (pdm_mic.raw_buffer_write_index == pdm_mic.raw_buffer_read_index) {
        return 0;
    }

    uint8_t* in = pdm_mic.raw_buffer[pdm_mic.raw_buffer_read_index];
    int16_t* out = buffer;

    pdm_mic.raw_buffer_read_index++;

    for (int i = 0; i < samples; i += filter_stride) {
#if PDM_DECIMATION == 64
        Open_PDM_Filter_64(in, out, pdm_mic.filter_volume, &pdm_mic.filter);
#elif PDM_DECIMATION == 128
        Open_PDM_Filter_128(in, out, pdm_mic.filter_volume, &pdm_mic.filter);
#else
        #error "Unsupported PDM_DECIMATION value!"
#endif

        in += filter_stride * (PDM_DECIMATION / 8);
        out += filter_stride;
    }

    return samples;
}


================================================
FILE: src/pdm_microphone.pio
================================================
/*
 * 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 0
    in pins, 1 side 0
    push iffull noblock side 1
    nop side 1
.wrap

% c-sdk {

static inline void pdm_microphone_data_init(PIO pio, uint sm, uint offset, float clk_div, uint data_pin, uint clk_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, false, 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);
}
%}
Download .txt
gitextract_j80jyxyx/

├── .github/
│   └── stale.yml
├── .gitignore
├── CMakeLists.txt
├── LICENSE
├── README.md
├── examples/
│   ├── hello_analog_microphone/
│   │   ├── CMakeLists.txt
│   │   └── main.c
│   ├── hello_pdm_microphone/
│   │   ├── CMakeLists.txt
│   │   └── main.c
│   └── usb_microphone/
│       ├── CMakeLists.txt
│       ├── main.c
│       ├── tusb_config.h
│       ├── usb_descriptors.c
│       ├── usb_microphone.c
│       └── usb_microphone.h
├── pico_sdk_import.cmake
└── src/
    ├── OpenPDM2PCM/
    │   ├── LICENSE.txt
    │   ├── OpenPDMFilter.c
    │   └── OpenPDMFilter.h
    ├── analog_microphone.c
    ├── include/
    │   └── pico/
    │       ├── analog_microphone.h
    │       └── pdm_microphone.h
    ├── pdm_microphone.c
    └── pdm_microphone.pio
Download .txt
SYMBOL INDEX (56 symbols across 10 files)

FILE: examples/hello_analog_microphone/main.c
  type analog_microphone_config (line 19) | struct analog_microphone_config
  function on_analog_samples_ready (line 37) | void on_analog_samples_ready()
  function main (line 44) | int main( void )

FILE: examples/hello_pdm_microphone/main.c
  type pdm_microphone_config (line 19) | struct pdm_microphone_config
  function on_pdm_samples_ready (line 43) | void on_pdm_samples_ready()
  function main (line 50) | int main( void )

FILE: examples/usb_microphone/main.c
  type pdm_microphone_config (line 20) | struct pdm_microphone_config
  function main (line 36) | int main(void)
  function on_pdm_samples_ready (line 55) | void on_pdm_samples_ready()
  function on_usb_microphone_tx_ready (line 64) | void on_usb_microphone_tx_ready()

FILE: examples/usb_microphone/usb_microphone.c
  function usb_microphone_init (line 42) | void usb_microphone_init()
  function usb_microphone_set_tx_ready_handler (line 56) | void usb_microphone_set_tx_ready_handler(usb_microphone_tx_ready_handler...
  function usb_microphone_write (line 61) | uint16_t usb_microphone_write(const void * data, uint16_t len)
  function usb_microphone_task (line 66) | void usb_microphone_task()
  function tud_audio_set_req_ep_cb (line 76) | bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t cons...
  function tud_audio_set_req_itf_cb (line 95) | bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t con...
  function tud_audio_set_req_entity_cb (line 114) | bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t ...
  function tud_audio_get_req_ep_cb (line 164) | bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t cons...
  function tud_audio_get_req_itf_cb (line 181) | bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t con...
  function tud_audio_get_req_entity_cb (line 196) | bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t ...
  function tud_audio_tx_done_pre_load_cb (line 306) | bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ...
  function tud_audio_tx_done_post_load_cb (line 321) | bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_cop...
  function tud_audio_set_itf_close_EP_cb (line 332) | bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_...

FILE: src/OpenPDM2PCM/OpenPDMFilter.c
  function filter_table_mono_64 (line 51) | int32_t filter_table_mono_64(uint8_t *data, uint8_t sincn)
  function filter_table_stereo_64 (line 63) | int32_t filter_table_stereo_64(uint8_t *data, uint8_t sincn)
  function filter_table_mono_128 (line 75) | int32_t filter_table_mono_128(uint8_t *data, uint8_t sincn)
  function filter_table_stereo_128 (line 95) | int32_t filter_table_stereo_128(uint8_t *data, uint8_t sincn)
  function filter_table (line 118) | int32_t filter_table(uint8_t *data, uint8_t sincn, TPDMFilter_InitStruct...
  function convolve (line 143) | void convolve(uint32_t Signal[/* SignalLen */], unsigned short SignalLen,
  function Open_PDM_Filter_Init (line 164) | void Open_PDM_Filter_Init(TPDMFilter_InitStruct *Param)
  function Open_PDM_Filter_64 (line 219) | void Open_PDM_Filter_64(uint8_t* data, uint16_t* dataOut, uint16_t volum...
  function Open_PDM_Filter_128 (line 267) | void Open_PDM_Filter_128(uint8_t* data, uint16_t* dataOut, uint16_t volu...

FILE: src/OpenPDM2PCM/OpenPDMFilter.h
  type TPDMFilter_InitStruct (line 70) | typedef struct {

FILE: src/analog_microphone.c
  type analog_microphone_config (line 21) | struct analog_microphone_config
  function analog_microphone_init (line 34) | int analog_microphone_init(const struct analog_microphone_config* config) {
  function analog_microphone_deinit (line 98) | void analog_microphone_deinit() {
  function analog_microphone_start (line 114) | int analog_microphone_start() {
  function analog_microphone_stop (line 138) | void analog_microphone_stop() {
  function analog_dma_handler (line 152) | static void analog_dma_handler() {
  function analog_microphone_set_samples_ready_handler (line 178) | void analog_microphone_set_samples_ready_handler(analog_samples_ready_ha...
  function analog_microphone_read (line 182) | int analog_microphone_read(int16_t* buffer, size_t samples) {

FILE: src/include/pico/analog_microphone.h
  type analog_microphone_config (line 13) | struct analog_microphone_config {
  type analog_microphone_config (line 20) | struct analog_microphone_config

FILE: src/include/pico/pdm_microphone.h
  type pdm_microphone_config (line 15) | struct pdm_microphone_config {
  type pdm_microphone_config (line 24) | struct pdm_microphone_config

FILE: src/pdm_microphone.c
  type pdm_microphone_config (line 25) | struct pdm_microphone_config
  function pdm_microphone_init (line 39) | int pdm_microphone_init(const struct pdm_microphone_config* config) {
  function pdm_microphone_deinit (line 108) | void pdm_microphone_deinit() {
  function pdm_microphone_start (line 124) | int pdm_microphone_start() {
  function pdm_microphone_stop (line 160) | void pdm_microphone_stop() {
  function pdm_dma_handler (line 178) | static void pdm_dma_handler() {
  function pdm_microphone_set_samples_ready_handler (line 204) | void pdm_microphone_set_samples_ready_handler(pdm_samples_ready_handler_...
  function pdm_microphone_set_filter_max_volume (line 208) | void pdm_microphone_set_filter_max_volume(uint8_t max_volume) {
  function pdm_microphone_set_filter_gain (line 212) | void pdm_microphone_set_filter_gain(uint8_t gain) {
  function pdm_microphone_set_filter_volume (line 216) | void pdm_microphone_set_filter_volume(uint16_t volume) {
  function pdm_microphone_read (line 220) | int pdm_microphone_read(int16_t* buffer, size_t samples) {
Condensed preview — 24 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (92K chars).
[
  {
    "path": ".github/stale.yml",
    "chars": 738,
    "preview": "# Number of days of inactivity before an issue becomes stale\ndaysUntilStale: 60\n# Number of days of inactivity before a "
  },
  {
    "path": ".gitignore",
    "chars": 174,
    "preview": "CMakeLists.txt.user\nCMakeCache.txt\nCMakeFiles\nCMakeScripts\nTesting\nMakefile\ncmake_install.cmake\ninstall_manifest.txt\ncom"
  },
  {
    "path": "CMakeLists.txt",
    "chars": 1361,
    "preview": "cmake_minimum_required(VERSION 3.12)\n\n# initialize pico_sdk from GIT\n# (note this can come from environment, CMake cache"
  },
  {
    "path": "LICENSE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 2194,
    "preview": "# Microphone Library for Pico\n\nCapture audio from a microphone on your [Raspberry Pi Pico](https://www.raspberrypi.org/p"
  },
  {
    "path": "examples/hello_analog_microphone/CMakeLists.txt",
    "chars": 424,
    "preview": "cmake_minimum_required(VERSION 3.12)\n\n# rest of your project\nadd_executable(hello_analog_microphone\n    main.c\n)\n\ntarget"
  },
  {
    "path": "examples/hello_analog_microphone/main.c",
    "chars": 2253,
    "preview": "/*\n * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *"
  },
  {
    "path": "examples/hello_pdm_microphone/CMakeLists.txt",
    "chars": 406,
    "preview": "cmake_minimum_required(VERSION 3.12)\n\n# rest of your project\nadd_executable(hello_pdm_microphone\n    main.c\n)\n\ntarget_li"
  },
  {
    "path": "examples/hello_pdm_microphone/main.c",
    "chars": 2297,
    "preview": "/*\n * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *"
  },
  {
    "path": "examples/usb_microphone/CMakeLists.txt",
    "chars": 411,
    "preview": "cmake_minimum_required(VERSION 3.12)\n\n# rest of your project\nadd_executable(usb_microphone\n    main.c\n    usb_descriptor"
  },
  {
    "path": "examples/usb_microphone/main.c",
    "chars": 1789,
    "preview": "/*\n * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *"
  },
  {
    "path": "examples/usb_microphone/tusb_config.h",
    "chars": 5209,
    "preview": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 Ha Thach (tinyusb.org)\n *\n * Permission is hereby granted, free of "
  },
  {
    "path": "examples/usb_microphone/usb_descriptors.c",
    "chars": 5850,
    "preview": "/* \n * The MIT License (MIT)\n *\n * Copyright (c) 2019 Ha Thach (tinyusb.org)\n *\n * Permission is hereby granted, free of"
  },
  {
    "path": "examples/usb_microphone/usb_microphone.c",
    "chars": 10337,
    "preview": "/* \n * The MIT License (MIT)\n *\n * Copyright (c) 2020 Reinhard Panhuber\n *\n * Permission is hereby granted, free of char"
  },
  {
    "path": "examples/usb_microphone/usb_microphone.h",
    "chars": 657,
    "preview": "/*\n * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *"
  },
  {
    "path": "pico_sdk_import.cmake",
    "chars": 2763,
    "preview": "# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake\n\n# This can be dropped into an external project to he"
  },
  {
    "path": "src/OpenPDM2PCM/LICENSE.txt",
    "chars": 11731,
    "preview": " \n                                 Apache License\n                           Version 2.0, January 2004\n                 "
  },
  {
    "path": "src/OpenPDM2PCM/OpenPDMFilter.c",
    "chars": 9419,
    "preview": "/**\n *******************************************************************************\n * @file    OpenPDMFilter.c\n * @aut"
  },
  {
    "path": "src/OpenPDM2PCM/OpenPDMFilter.h",
    "chars": 3187,
    "preview": "/**\n *******************************************************************************\n * @file    OpenPDMFilter.h\n * @aut"
  },
  {
    "path": "src/analog_microphone.c",
    "chars": 5888,
    "preview": "/*\n * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *"
  },
  {
    "path": "src/include/pico/analog_microphone.h",
    "chars": 713,
    "preview": "/*\n * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *"
  },
  {
    "path": "src/include/pico/pdm_microphone.h",
    "chars": 904,
    "preview": "/*\n * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *"
  },
  {
    "path": "src/pdm_microphone.c",
    "chars": 6849,
    "preview": "/*\n * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *"
  },
  {
    "path": "src/pdm_microphone.pio",
    "chars": 962,
    "preview": "/*\n * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.\n *\n * SPDX-License-Identifier: Apache-2.0\n *"
  }
]

About this extraction

This page contains the full source code of the ArmDeveloperEcosystem/microphone-library-for-pico GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 24 files (85.8 KB), approximately 23.1k tokens, and a symbol index with 56 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!