├── .github └── stale.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── fritzing ├── diagram.fzz └── diagram_bb.png ├── pico_sdk_import.cmake └── src ├── audio_spectrogram.c └── color_map.h /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | - help wanted 10 | # Label to use when marking an issue as stale 11 | staleLabel: stale 12 | # Comment to post when marking an issue as stale. Set to `false` to disable 13 | markComment: > 14 | This issue has been automatically marked as stale because it has not had 15 | recent activity. It will be closed if no further activity occurs. Thank you 16 | for your contributions. 17 | # Comment to post when closing a stale issue. Set to `false` to disable 18 | closeComment: false 19 | # Never stale pull requests 20 | only: issues -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/microphone-library-for-pico"] 2 | path = lib/microphone-library-for-pico 3 | url = https://github.com/ArmDeveloperEcosystem/microphone-library-for-pico.git 4 | [submodule "lib/CMSIS_5"] 5 | path = lib/CMSIS_5 6 | url = https://github.com/ARM-software/CMSIS_5.git 7 | shallow = true 8 | [submodule "lib/st7789-library-for-pico"] 9 | path = lib/st7789-library-for-pico 10 | url = https://github.com/ArmDeveloperEcosystem/st7789-library-for-pico.git 11 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | # initialize pico_sdk from GIT 4 | # (note this can come from environment, CMake cache etc) 5 | # set(PICO_SDK_FETCH_FROM_GIT on) 6 | 7 | # pico_sdk_import.cmake is a single file copied from this SDK 8 | # note: this must happen before project() 9 | include(pico_sdk_import.cmake) 10 | 11 | project(pico_audio_spectogram) 12 | 13 | # initialize the Pico SDK 14 | pico_sdk_init() 15 | 16 | # Define ARM_CPU, CMSIS ROOT and DSP to use CMSIS-DSP 17 | set(ARM_CPU "cortex-m0plus") 18 | set(ROOT ${CMAKE_CURRENT_LIST_DIR}/lib/CMSIS_5) 19 | set(DSP ${ROOT}/CMSIS/DSP) 20 | 21 | # include CMSIS-DSP .cmake for GCC Toolchain 22 | include(${DSP}/Toolchain/GCC.cmake) 23 | 24 | # add CMSIS-DSP Source directory as subdirectory 25 | add_subdirectory(${DSP}/Source EXCLUDE_FROM_ALL) 26 | 27 | # rest of your project 28 | add_executable(audio_spectrogram 29 | ${CMAKE_CURRENT_LIST_DIR}/src/audio_spectrogram.c 30 | ) 31 | 32 | target_link_libraries(audio_spectrogram pico_stdlib pico_pdm_microphone CMSISDSPTransform CMSISDSPSupport CMSISDSPCommon CMSISDSPComplexMath CMSISDSPFastMath CMSISDSPBasicMath pico_st7789) 33 | 34 | # enable usb output, disable uart output 35 | pico_enable_stdio_usb(audio_spectrogram 1) 36 | pico_enable_stdio_uart(audio_spectrogram 0) 37 | 38 | # create map/bin/hex/uf2 file in addition to ELF. 39 | pico_add_extra_outputs(audio_spectrogram) 40 | 41 | add_subdirectory("lib/microphone-library-for-pico" EXCLUDE_FROM_ALL) 42 | add_subdirectory("lib/st7789-library-for-pico" EXCLUDE_FROM_ALL) 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Audio Spectrogram Example for Pico 2 | 3 | Example project showcasing how to use a [Raspberry Pi Pico](https://www.raspberrypi.org/products/raspberry-pi-pico/), [Adafruit's PDM MEMS Microphone Breakout](https://www.adafruit.com/product/3492), and [Adafruit's 2.0" 320x240 Color IPS TFT Display with microSD Card Breakout](https://www.adafruit.com/product/4311) to "See sound in real-time". 4 | 5 | This project also leverages Arm's [CMSIS-DSP](https://arm-software.github.io/CMSIS_5/DSP/html/index.html) library for optimized on-board digital signaling processing. 6 | 7 | ## Hardware 8 | 9 | * [Raspberry Pi Pico](https://www.raspberrypi.org/products/raspberry-pi-pico/) 10 | * [Adafruit's PDM MEMS Microphone Breakout](https://www.adafruit.com/product/3492) 11 | * [Adafruit's 2.0" 320x240 Color IPS TFT Display with microSD Card Breakout](https://www.adafruit.com/product/4311) 12 | 13 | 14 | ### Default Pinout 15 | 16 | ![Frizting Diagram](fritzing/diagram_bb.png) 17 | 18 | ``` 19 | +---------+-------------------+ +---------+-------------------+ 20 | | PDM Mic | Raspberry Pi Pico | | ST7789 | Raspberry Pi Pico | 21 | |---------+-------------------| |---------+-------------------| 22 | | 3V | 3V3 | | VIN | 3V3 | 23 | |---------+-------------------| |---------+-------------------| 24 | | GND | GND | | GND | GND | 25 | |---------+-------------------| |---------+-------------------| 26 | | SEL | GND | | SCK | GPIO18 | 27 | |---------+-------------------| |---------+-------------------| 28 | | DAT | GPIO2 | | MOSI | GPIO19 | 29 | |---------+-------------------| |---------+-------------------| 30 | | CLK | GPIO3 | | CS | GPIO17 | 31 | +---------+-------------------+ |---------+-------------------| 32 | | RST | GPIO21 | 33 | |---------+-------------------| 34 | | D/C | GPIO20 | 35 | +---------+-------------------+ 36 | ``` 37 | 38 | ## Cloning 39 | 40 | ```sh 41 | git clone --recurse-submodules https://github.com/ArmDeveloperEcosystem/audio-spectrogram-example-for-pico.git 42 | ``` 43 | 44 | ## Building 45 | 46 | 1. [Set up the Pico C/C++ SDK](https://datasheets.raspberrypi.org/pico/getting-started-with-pico.pdf) 47 | 2. Set `PICO_SDK_PATH` 48 | ```sh 49 | export PICO_SDK_PATH=/path/to/pico-sdk 50 | ``` 51 | 3. Change directories 52 | ``` 53 | cd audio-spectrogram-example-for-pico 54 | ``` 55 | 4. Create `build` dir, run `cmake` and `make`: 56 | ``` 57 | mkdir build 58 | cd build 59 | cmake .. -DPICO_BOARD=pico 60 | make -j 61 | ``` 62 | 4. Copy `audio_spectrogram.uf2` to Pico when in BOOT mode. 63 | 64 | ## License 65 | 66 | [Apache-2.0 License](LICENSE) 67 | 68 | --- 69 | 70 | Disclaimer: This is not an official Arm product. 71 | -------------------------------------------------------------------------------- /fritzing/diagram.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArmDeveloperEcosystem/audio-spectrogram-example-for-pico/e973efaa546348a86d9471eedf86a922f27311be/fritzing/diagram.fzz -------------------------------------------------------------------------------- /fritzing/diagram_bb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArmDeveloperEcosystem/audio-spectrogram-example-for-pico/e973efaa546348a86d9471eedf86a922f27311be/fritzing/diagram_bb.png -------------------------------------------------------------------------------- /pico_sdk_import.cmake: -------------------------------------------------------------------------------- 1 | # This is a copy of /external/pico_sdk_import.cmake 2 | 3 | # This can be dropped into an external project to help locate this SDK 4 | # It should be include()ed prior to project() 5 | 6 | if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) 7 | set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) 8 | message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") 9 | endif () 10 | 11 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) 12 | set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) 13 | message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") 14 | endif () 15 | 16 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) 17 | set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) 18 | message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") 19 | endif () 20 | 21 | set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") 22 | 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") 23 | set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") 24 | 25 | if (NOT PICO_SDK_PATH) 26 | if (PICO_SDK_FETCH_FROM_GIT) 27 | include(FetchContent) 28 | set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) 29 | if (PICO_SDK_FETCH_FROM_GIT_PATH) 30 | get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") 31 | endif () 32 | FetchContent_Declare( 33 | pico_sdk 34 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk 35 | GIT_TAG master 36 | ) 37 | if (NOT pico_sdk) 38 | message("Downloading Raspberry Pi Pico SDK") 39 | FetchContent_Populate(pico_sdk) 40 | set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) 41 | endif () 42 | set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) 43 | else () 44 | message(FATAL_ERROR 45 | "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." 46 | ) 47 | endif () 48 | endif () 49 | 50 | get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") 51 | if (NOT EXISTS ${PICO_SDK_PATH}) 52 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") 53 | endif () 54 | 55 | set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) 56 | if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) 57 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") 58 | endif () 59 | 60 | set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) 61 | 62 | include(${PICO_SDK_INIT_CMAKE_FILE}) 63 | -------------------------------------------------------------------------------- /src/audio_spectrogram.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | * 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | #include "pico/stdlib.h" 12 | 13 | #include "pico/pdm_microphone.h" 14 | #include "pico/st7789.h" 15 | 16 | #include "arm_math.h" 17 | 18 | #include "color_map.h" 19 | 20 | // constants 21 | #define SAMPLE_RATE 16000 22 | #define FFT_SIZE 256 23 | #define INPUT_BUFFER_SIZE 64 24 | #define INPUT_SHIFT 2 25 | 26 | #define LCD_WIDTH 240 27 | #define LCD_HEIGHT 320 28 | 29 | #define FFT_BINS_SKIP 5 30 | #define FFT_MAG_MAX 2000.0 31 | 32 | // lcd configuration 33 | const struct st7789_config lcd_config = { 34 | .spi = PICO_DEFAULT_SPI_INSTANCE, 35 | .gpio_din = PICO_DEFAULT_SPI_TX_PIN, 36 | .gpio_clk = PICO_DEFAULT_SPI_SCK_PIN, 37 | .gpio_cs = PICO_DEFAULT_SPI_CSN_PIN, 38 | .gpio_dc = 20, 39 | .gpio_rst = 21, 40 | .gpio_bl = 22, 41 | }; 42 | 43 | // microphone configuration 44 | const struct pdm_microphone_config pdm_config = { 45 | // GPIO pin for the PDM DAT signal 46 | .gpio_data = 2, 47 | 48 | // GPIO pin for the PDM CLK signal 49 | .gpio_clk = 3, 50 | 51 | // PIO instance to use 52 | .pio = pio0, 53 | 54 | // PIO State Machine instance to use 55 | .pio_sm = 0, 56 | 57 | // sample rate in Hz 58 | .sample_rate = SAMPLE_RATE, 59 | 60 | // number of samples to buffer 61 | .sample_buffer_size = INPUT_BUFFER_SIZE, 62 | }; 63 | 64 | q15_t capture_buffer_q15[INPUT_BUFFER_SIZE]; 65 | volatile int new_samples_captured = 0; 66 | 67 | q15_t input_q15[FFT_SIZE]; 68 | q15_t window_q15[FFT_SIZE]; 69 | q15_t windowed_input_q15[FFT_SIZE]; 70 | 71 | arm_rfft_instance_q15 S_q15; 72 | 73 | q15_t fft_q15[FFT_SIZE * 2]; 74 | q15_t fft_mag_q15[FFT_SIZE / 2]; 75 | 76 | uint16_t row_pixels[LCD_WIDTH]; 77 | 78 | void input_init_q15(); 79 | void hanning_window_init_q15(q15_t* window, size_t size); 80 | void on_pdm_samples_ready(); 81 | 82 | int main() { 83 | // initialize stdio 84 | stdio_init_all(); 85 | 86 | printf("pico audio spectrogram\n"); 87 | 88 | // initialize the LCD and fill the screen black 89 | st7789_init(&lcd_config, LCD_WIDTH, LCD_HEIGHT); 90 | st7789_fill(0x000); 91 | 92 | // initialize the hanning window and RFFT instance 93 | hanning_window_init_q15(window_q15, FFT_SIZE); 94 | arm_rfft_init_q15(&S_q15, FFT_SIZE, 0, 1); 95 | 96 | // initialize the PDM microphone 97 | if (pdm_microphone_init(&pdm_config) < 0) { 98 | printf("PDM microphone initialization failed!\n"); 99 | while (1) { tight_loop_contents(); } 100 | } 101 | 102 | // set callback that is called when all the samples in the library 103 | // internal sample buffer are ready for reading 104 | pdm_microphone_set_samples_ready_handler(on_pdm_samples_ready); 105 | 106 | // start capturing data from the PDM microphone 107 | if (pdm_microphone_start() < 0) { 108 | printf("PDM microphone start failed!\n"); 109 | while (1) { tight_loop_contents(); } 110 | } 111 | 112 | uint16_t row = 0; 113 | 114 | while (1) { 115 | // wait for new samples 116 | while (new_samples_captured == 0) { 117 | tight_loop_contents(); 118 | } 119 | new_samples_captured = 0; 120 | 121 | // move input buffer values over by INPUT_BUFFER_SIZE samples 122 | arm_copy_q15(input_q15 + INPUT_BUFFER_SIZE, input_q15, (FFT_SIZE - INPUT_BUFFER_SIZE)); 123 | 124 | // copy new samples to end of the input buffer with a bit shift of INPUT_SHIFT 125 | arm_shift_q15(capture_buffer_q15, INPUT_SHIFT, input_q15 + (FFT_SIZE - INPUT_BUFFER_SIZE), INPUT_BUFFER_SIZE); 126 | 127 | // apply the DSP pipeline: Hanning Window + FFT 128 | arm_mult_q15(window_q15, input_q15, windowed_input_q15, FFT_SIZE); 129 | arm_rfft_q15(&S_q15, windowed_input_q15, fft_q15); 130 | arm_cmplx_mag_q15(fft_q15, fft_mag_q15, FFT_SIZE / 2); 131 | 132 | // map the FFT magnitude values to pixel values 133 | for (int i = 0; i < (LCD_WIDTH / 2); i++) { 134 | // get the current FFT magnitude value 135 | q15_t magnitude = fft_mag_q15[i + FFT_BINS_SKIP]; 136 | 137 | // scale it between 0 to 255 to map, so we can map it to a color based on the color map 138 | int color_index = (magnitude / FFT_MAG_MAX) * 255; 139 | 140 | if (color_index > 255) { 141 | color_index = 255; 142 | } 143 | 144 | // cacluate the pixel color using the color map and color index 145 | uint16_t pixel = COLOR_MAP[color_index]; 146 | 147 | // set the pixel value for the next two rows 148 | row_pixels[LCD_WIDTH - 1 - (i * 2)] = pixel; 149 | row_pixels[LCD_WIDTH - 1 - (i * 2 + 1)] = pixel; 150 | } 151 | 152 | // update the cursor to the start of the current row 153 | st7789_set_cursor(0, row); 154 | 155 | // write the row value pixels 156 | st7789_write(row_pixels, sizeof(row_pixels)); 157 | 158 | // scroll to the new row 159 | st7789_vertical_scroll(row); 160 | 161 | // calculate the next row to update 162 | row = (row + 1) % LCD_HEIGHT; 163 | } 164 | 165 | return 0; 166 | } 167 | 168 | void hanning_window_init_q15(q15_t* window, size_t size) { 169 | for (size_t i = 0; i < size; i++) { 170 | float32_t f = 0.5 * (1.0 - arm_cos_f32(2 * PI * i / FFT_SIZE )); 171 | 172 | arm_float_to_q15(&f, &window_q15[i], 1); 173 | } 174 | } 175 | 176 | void on_pdm_samples_ready() 177 | { 178 | // callback from library when all the samples in the library 179 | // internal sample buffer are ready for reading 180 | new_samples_captured = pdm_microphone_read(capture_buffer_q15, FFT_SIZE / 2); 181 | } 182 | -------------------------------------------------------------------------------- /src/color_map.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | * 6 | */ 7 | 8 | #ifndef _COLOR_MAP_H_ 9 | #define _COLOR_MAP_H_ 10 | 11 | const uint16_t COLOR_MAP[] = { 12 | 0x400a, 13 | 0x402a, 14 | 0x402b, 15 | 0x402b, 16 | 0x404b, 17 | 0x404b, 18 | 0x484b, 19 | 0x486b, 20 | 0x486c, 21 | 0x488c, 22 | 0x488c, 23 | 0x488c, 24 | 0x48ac, 25 | 0x48ac, 26 | 0x48ad, 27 | 0x48cd, 28 | 0x48cd, 29 | 0x48cd, 30 | 0x48ed, 31 | 0x48ed, 32 | 0x48ee, 33 | 0x490e, 34 | 0x490e, 35 | 0x490e, 36 | 0x492e, 37 | 0x492e, 38 | 0x492e, 39 | 0x494e, 40 | 0x494f, 41 | 0x494f, 42 | 0x494f, 43 | 0x496f, 44 | 0x496f, 45 | 0x496f, 46 | 0x498f, 47 | 0x498f, 48 | 0x498f, 49 | 0x41af, 50 | 0x41b0, 51 | 0x41b0, 52 | 0x41b0, 53 | 0x41d0, 54 | 0x41d0, 55 | 0x41d0, 56 | 0x41f0, 57 | 0x41f0, 58 | 0x41f0, 59 | 0x4210, 60 | 0x4210, 61 | 0x4210, 62 | 0x4210, 63 | 0x4230, 64 | 0x4230, 65 | 0x4231, 66 | 0x4251, 67 | 0x4251, 68 | 0x4251, 69 | 0x4251, 70 | 0x3a71, 71 | 0x3a71, 72 | 0x3a71, 73 | 0x3a91, 74 | 0x3a91, 75 | 0x3a91, 76 | 0x3a91, 77 | 0x3ab1, 78 | 0x3ab1, 79 | 0x3ab1, 80 | 0x3ab1, 81 | 0x3ad1, 82 | 0x3ad1, 83 | 0x3ad1, 84 | 0x3ad1, 85 | 0x3af1, 86 | 0x3af1, 87 | 0x32f1, 88 | 0x32f1, 89 | 0x3311, 90 | 0x3311, 91 | 0x3311, 92 | 0x3311, 93 | 0x3331, 94 | 0x3331, 95 | 0x3331, 96 | 0x3331, 97 | 0x3351, 98 | 0x3351, 99 | 0x3351, 100 | 0x3351, 101 | 0x3371, 102 | 0x3371, 103 | 0x3371, 104 | 0x3371, 105 | 0x3391, 106 | 0x2b91, 107 | 0x2b91, 108 | 0x2b91, 109 | 0x2bb1, 110 | 0x2bb1, 111 | 0x2bb1, 112 | 0x2bb1, 113 | 0x2bb1, 114 | 0x2bd1, 115 | 0x2bd1, 116 | 0x2bd1, 117 | 0x2bd1, 118 | 0x2bf1, 119 | 0x2bf1, 120 | 0x2bf1, 121 | 0x2bf1, 122 | 0x2c11, 123 | 0x2c11, 124 | 0x2c11, 125 | 0x2c11, 126 | 0x2c11, 127 | 0x2431, 128 | 0x2431, 129 | 0x2431, 130 | 0x2431, 131 | 0x2451, 132 | 0x2451, 133 | 0x2451, 134 | 0x2451, 135 | 0x2471, 136 | 0x2471, 137 | 0x2471, 138 | 0x2471, 139 | 0x2471, 140 | 0x2491, 141 | 0x2491, 142 | 0x2491, 143 | 0x2491, 144 | 0x24b1, 145 | 0x24b1, 146 | 0x24b1, 147 | 0x24b1, 148 | 0x24d1, 149 | 0x24d1, 150 | 0x24d1, 151 | 0x24d1, 152 | 0x24f1, 153 | 0x24f1, 154 | 0x24f1, 155 | 0x24f1, 156 | 0x24f1, 157 | 0x2510, 158 | 0x2510, 159 | 0x2510, 160 | 0x2510, 161 | 0x2530, 162 | 0x2530, 163 | 0x2530, 164 | 0x2530, 165 | 0x2530, 166 | 0x2550, 167 | 0x2550, 168 | 0x2550, 169 | 0x2d50, 170 | 0x2d70, 171 | 0x2d70, 172 | 0x2d70, 173 | 0x2d6f, 174 | 0x2d8f, 175 | 0x2d8f, 176 | 0x2d8f, 177 | 0x358f, 178 | 0x358f, 179 | 0x35af, 180 | 0x35af, 181 | 0x35af, 182 | 0x35af, 183 | 0x3daf, 184 | 0x3dce, 185 | 0x3dce, 186 | 0x3dce, 187 | 0x3dce, 188 | 0x45ee, 189 | 0x45ee, 190 | 0x45ee, 191 | 0x45ee, 192 | 0x45ee, 193 | 0x4e0d, 194 | 0x4e0d, 195 | 0x4e0d, 196 | 0x4e0d, 197 | 0x560d, 198 | 0x562d, 199 | 0x562d, 200 | 0x562c, 201 | 0x5e2c, 202 | 0x5e2c, 203 | 0x5e4c, 204 | 0x5e4c, 205 | 0x664c, 206 | 0x664c, 207 | 0x664b, 208 | 0x6e4b, 209 | 0x6e6b, 210 | 0x6e6b, 211 | 0x6e6b, 212 | 0x766b, 213 | 0x766a, 214 | 0x766a, 215 | 0x7e8a, 216 | 0x7e8a, 217 | 0x7e8a, 218 | 0x7e89, 219 | 0x8689, 220 | 0x8689, 221 | 0x86a9, 222 | 0x8ea9, 223 | 0x8ea9, 224 | 0x8ea8, 225 | 0x96a8, 226 | 0x96a8, 227 | 0x96a8, 228 | 0x96a8, 229 | 0x9ec7, 230 | 0x9ec7, 231 | 0x9ec7, 232 | 0xa6c7, 233 | 0xa6c7, 234 | 0xa6c6, 235 | 0xaec6, 236 | 0xaec6, 237 | 0xaee6, 238 | 0xb6e5, 239 | 0xb6e5, 240 | 0xb6e5, 241 | 0xbee5, 242 | 0xbee5, 243 | 0xbee4, 244 | 0xc6e4, 245 | 0xc6e4, 246 | 0xc6e4, 247 | 0xcee4, 248 | 0xcf04, 249 | 0xcf03, 250 | 0xd703, 251 | 0xd703, 252 | 0xd703, 253 | 0xdf03, 254 | 0xdf03, 255 | 0xdf03, 256 | 0xdf03, 257 | 0xe703, 258 | 0xe703, 259 | 0xe703, 260 | 0xef23, 261 | 0xef23, 262 | 0xef23, 263 | 0xf724, 264 | 0xf724, 265 | 0xf724, 266 | 0xf724, 267 | 0xff24, 268 | }; 269 | 270 | #endif 271 | --------------------------------------------------------------------------------