├── README.md ├── ESP_DSP └── ESP32FIR │ ├── mix.wav │ ├── 400Hz2m.wav │ ├── BLEscan.png │ ├── ESP32_FIR.PNG │ ├── sineWAV.wav │ ├── firLibrary.zip │ ├── esp-dsp-master.zip │ ├── images │ ├── BLEscan.PNG │ ├── ESP32_FIR.PNG │ └── RealTimeAudioProcessor.png │ ├── design │ ├── ESP32_FIR.JPG │ ├── TTGO_T8_1_7.png │ ├── 400HzBandstopFilterGraph.png │ ├── HighPass400_850FilterGraph.png │ ├── RealTime Audio Processor.jpeg │ └── PM8403_Super Mini PAM8403 DC 5V 2 Channel USB Digital Audio Amplifier Board Module 2 3W Volume Control with Potentionmeter.pdf │ ├── RealTimeAudioProcessor.png │ ├── esp32-micro-sdcard-master.zip │ ├── dsp_err.h │ ├── dsps_fir_init_f32.c │ ├── dsp_err_codes.h │ ├── dsps_fir_f32_ansi.c │ ├── fdaHPcoefs.h │ ├── fdaBScoefs.h │ ├── README.md │ ├── dsps_fir.h │ ├── ESP32DACWaveforms │ ├── TwoCoreTalkThru │ │ └── TwoCoreTalkThru.ino │ ├── TwoCoreSweepESP32 │ │ └── TwoCoreSweepESP32.ino │ ├── TwoCoreTwoToneESP32 │ │ └── TwoCoreTwoToneESP32.ino │ └── TwoCoreSineESP32 │ │ └── TwoCoreSineESP32.ino │ ├── ESP32FIR.ino │ └── tmwtypes.h └── LICENSE /README.md: -------------------------------------------------------------------------------- 1 | # ESP_DSP 2 | Real-Time Digital Signal Processing on the ESP32 3 | -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/mix.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobh/ESP_DSP/HEAD/ESP_DSP/ESP32FIR/mix.wav -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/400Hz2m.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobh/ESP_DSP/HEAD/ESP_DSP/ESP32FIR/400Hz2m.wav -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/BLEscan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobh/ESP_DSP/HEAD/ESP_DSP/ESP32FIR/BLEscan.png -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/ESP32_FIR.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobh/ESP_DSP/HEAD/ESP_DSP/ESP32FIR/ESP32_FIR.PNG -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/sineWAV.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobh/ESP_DSP/HEAD/ESP_DSP/ESP32FIR/sineWAV.wav -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/firLibrary.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobh/ESP_DSP/HEAD/ESP_DSP/ESP32FIR/firLibrary.zip -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/esp-dsp-master.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobh/ESP_DSP/HEAD/ESP_DSP/ESP32FIR/esp-dsp-master.zip -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/images/BLEscan.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobh/ESP_DSP/HEAD/ESP_DSP/ESP32FIR/images/BLEscan.PNG -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/design/ESP32_FIR.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobh/ESP_DSP/HEAD/ESP_DSP/ESP32FIR/design/ESP32_FIR.JPG -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/images/ESP32_FIR.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobh/ESP_DSP/HEAD/ESP_DSP/ESP32FIR/images/ESP32_FIR.PNG -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/design/TTGO_T8_1_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobh/ESP_DSP/HEAD/ESP_DSP/ESP32FIR/design/TTGO_T8_1_7.png -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/RealTimeAudioProcessor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobh/ESP_DSP/HEAD/ESP_DSP/ESP32FIR/RealTimeAudioProcessor.png -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/esp32-micro-sdcard-master.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobh/ESP_DSP/HEAD/ESP_DSP/ESP32FIR/esp32-micro-sdcard-master.zip -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/images/RealTimeAudioProcessor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobh/ESP_DSP/HEAD/ESP_DSP/ESP32FIR/images/RealTimeAudioProcessor.png -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/design/400HzBandstopFilterGraph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobh/ESP_DSP/HEAD/ESP_DSP/ESP32FIR/design/400HzBandstopFilterGraph.png -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/design/HighPass400_850FilterGraph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobh/ESP_DSP/HEAD/ESP_DSP/ESP32FIR/design/HighPass400_850FilterGraph.png -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/design/RealTime Audio Processor.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobh/ESP_DSP/HEAD/ESP_DSP/ESP32FIR/design/RealTime Audio Processor.jpeg -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/design/PM8403_Super Mini PAM8403 DC 5V 2 Channel USB Digital Audio Amplifier Board Module 2 3W Volume Control with Potentionmeter.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobh/ESP_DSP/HEAD/ESP_DSP/ESP32FIR/design/PM8403_Super Mini PAM8403 DC 5V 2 Channel USB Digital Audio Amplifier Board Module 2 3W Volume Control with Potentionmeter.pdf -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/dsp_err.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | #ifndef _DSP_ERR_H_ 17 | #define _DSP_ERR_H_ 18 | 19 | #include "stdint.h" 20 | #include "esp_err.h" 21 | #include "dsp_err_codes.h" 22 | 23 | #endif // _DSP_ERR_H_ -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/dsps_fir_init_f32.c: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "dsps_fir.h" 16 | 17 | 18 | esp_err_t dsps_fir_init_f32(fir_f32_t *fir, float *coeffs, float *delay, int N) 19 | { 20 | fir->coeffs = coeffs; 21 | fir->delay = delay; 22 | fir->N = N; 23 | fir->pos = 0; 24 | 25 | for (int i = 0 ; i < N; i++) { 26 | fir->delay[i] = 0; 27 | } 28 | return ESP_OK; 29 | } 30 | -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/dsp_err_codes.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef _dsp_error_codes_H_ 16 | #define _dsp_error_codes_H_ 17 | 18 | #define DSP_OK 0 // For internal use only. Please use ESP_OK instead 19 | #define ESP_ERR_DSP_BASE 0x70000 20 | #define ESP_ERR_DSP_INVALID_LENGTH (ESP_ERR_DSP_BASE + 1) 21 | #define ESP_ERR_DSP_INVALID_PARAM (ESP_ERR_DSP_BASE + 2) 22 | #define ESP_ERR_DSP_PARAM_OUTOFRANGE (ESP_ERR_DSP_BASE + 3) 23 | #define ESP_ERR_DSP_UNINITIALIZED (ESP_ERR_DSP_BASE + 4) 24 | #define ESP_ERR_DSP_REINITIALIZED (ESP_ERR_DSP_BASE + 5) 25 | 26 | 27 | #endif // _dsp_error_codes_H_ -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/dsps_fir_f32_ansi.c: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "dsps_fir.h" 16 | 17 | esp_err_t dsps_fir_f32_ansi(fir_f32_t *fir, const float *input, float *output, int len) 18 | { 19 | for (int i = 0 ; i < len ; i++) { 20 | float acc = 0; 21 | int coeff_pos = fir->N - 1; 22 | fir->delay[fir->pos] = input[i]; 23 | fir->pos++; 24 | if (fir->pos >= fir->N) { 25 | fir->pos = 0; 26 | } 27 | for (int n = fir->pos; n < fir->N ; n++) { 28 | acc += fir->coeffs[coeff_pos--] * fir->delay[n]; 29 | } 30 | for (int n = 0; n < fir->pos ; n++) { 31 | acc += fir->coeffs[coeff_pos--] * fir->delay[n]; 32 | } 33 | output[i] = acc; 34 | } 35 | return ESP_OK; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/fdaHPcoefs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Filter Coefficients (C Source) generated by the Filter Design and Analysis Tool 3 | * Generated by MATLAB(R) 9.4 and Signal Processing Toolbox 8.0. 4 | * Generated on: 26-Jan-2020 13:57:49 5 | */ 6 | 7 | /* 8 | * Discrete-Time FIR Filter (real) 9 | * ------------------------------- 10 | * Filter Structure : Direct-Form FIR 11 | * Filter Length : 51 12 | * Stable : Yes 13 | * Linear Phase : Yes (Type 1) 14 | */ 15 | 16 | /* General type conversion for MATLAB generated C-code */ 17 | #include "tmwtypes.h" 18 | /* 19 | * Expected path to tmwtypes.h 20 | * /Applications/MATLAB_R2018a.app/extern/include/tmwtypes.h 21 | */ 22 | /* 23 | * Warning - Filter coefficients were truncated to fit specified data type. 24 | * The resulting response may not match generated theoretical response. 25 | * Use the Filter Design & Analysis Tool to design accurate 26 | * single-precision filter coefficients. 27 | */ 28 | const int BL = 51; 29 | const real32_T B[51] = { 30 | 0.00756539451, -0.01149180066,-0.004271964077,0.0003535575815, 0.003802435007, 31 | 0.006187047344, 0.006911808625, 0.005282577127, 0.001192335272,-0.004611292854, 32 | -0.01044458337, -0.01406532526, -0.01344149839,-0.007485062815, 0.003263459308, 33 | 0.01636486501, 0.0277939178, 0.0328727141, 0.02743673138, 0.009163923562, 34 | -0.02150698006, -0.06104771048, -0.1033860892, -0.1411015838, -0.1671450883, 35 | 0.8235622644, -0.1671450883, -0.1411015838, -0.1033860892, -0.06104771048, 36 | -0.02150698006, 0.009163923562, 0.02743673138, 0.0328727141, 0.0277939178, 37 | 0.01636486501, 0.003263459308,-0.007485062815, -0.01344149839, -0.01406532526, 38 | -0.01044458337,-0.004611292854, 0.001192335272, 0.005282577127, 0.006911808625, 39 | 0.006187047344, 0.003802435007,0.0003535575815,-0.004271964077, -0.01149180066, 40 | 0.00756539451 41 | }; 42 | -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/fdaBScoefs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Filter Coefficients (C Source) generated by the Filter Design and Analysis Tool 3 | * Generated by MATLAB(R) 9.4 and Signal Processing Toolbox 8.0. 4 | * Generated on: 25-Jan-2020 10:24:49 5 | */ 6 | 7 | /* 8 | * Discrete-Time FIR Filter (real) 9 | * ------------------------------- 10 | * Filter Structure : Direct-Form FIR 11 | * Filter Length : 121 12 | * Stable : Yes 13 | * Linear Phase : Yes (Type 1) 14 | */ 15 | 16 | /* General type conversion for MATLAB generated C-code */ 17 | #include "tmwtypes.h" 18 | /* 19 | * Expected path to tmwtypes.h 20 | * /Applications/MATLAB_R2018a.app/extern/include/tmwtypes.h 21 | */ 22 | /* 23 | * Warning - Filter coefficients were truncated to fit specified data type. 24 | * The resulting response may not match generated theoretical response. 25 | * Use the Filter Design & Analysis Tool to design accurate 26 | * single-precision filter coefficients. 27 | */ 28 | const int BL = 121; 29 | const real32_T B[121] = { 30 | -0.02191321366,-0.001977184555,-0.001466839924,-0.0006470786757,0.0003265612177, 31 | 0.001247174107, 0.001927313744, 0.002221651841, 0.002069424139, 0.001525712316, 32 | 0.0007507968694,-1.337562662e-05,-0.0004856224696,-0.0004075112811,0.0003994250437, 33 | 0.001983487047, 0.004231323488, 0.006872389, 0.009512691759, 0.01169616915, 34 | 0.0129874507, 0.01305404957, 0.01173774991, 0.009101052769, 0.005431375466, 35 | 0.001205577399,-0.002984318649,-0.006536464673,-0.008948790841,-0.009918907657, 36 | -0.009416198358,-0.007701143157, -0.00529480027,-0.002893649507,-0.001230120892, 37 | -0.0009249171126,-0.002346839057,-0.005496154539,-0.009985642508, -0.01508209947, 38 | -0.01964506879, -0.02255456336, -0.02270268835, -0.0192877762, -0.01202154532, 39 | -0.001184959547, 0.01229436789, 0.0269222986, 0.04082841799, 0.05200551823, 40 | 0.05860314518, 0.05922214314, 0.05315371603, 0.0405389443, 0.02240726165, 41 | 0.0005799630308, -0.02254076116, -0.04427792877, -0.06203589961, -0.07365033031, 42 | 0.9223114252, -0.07365033031, -0.06203589961, -0.04427792877, -0.02254076116, 43 | 0.0005799630308, 0.02240726165, 0.0405389443, 0.05315371603, 0.05922214314, 44 | 0.05860314518, 0.05200551823, 0.04082841799, 0.0269222986, 0.01229436789, 45 | -0.001184959547, -0.01202154532, -0.0192877762, -0.02270268835, -0.02255456336, 46 | -0.01964506879, -0.01508209947,-0.009985642508,-0.005496154539,-0.002346839057, 47 | -0.0009249171126,-0.001230120892,-0.002893649507, -0.00529480027,-0.007701143157, 48 | -0.009416198358,-0.009918907657,-0.008948790841,-0.006536464673,-0.002984318649, 49 | 0.001205577399, 0.005431375466, 0.009101052769, 0.01173774991, 0.01305404957, 50 | 0.0129874507, 0.01169616915, 0.009512691759, 0.006872389, 0.004231323488, 51 | 0.001983487047,0.0003994250437,-0.0004075112811,-0.0004856224696,-1.337562662e-05, 52 | 0.0007507968694, 0.001525712316, 0.002069424139, 0.002221651841, 0.001927313744, 53 | 0.001247174107,0.0003265612177,-0.0006470786757,-0.001466839924,-0.001977184555, 54 | -0.02191321366 55 | }; 56 | -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/README.md: -------------------------------------------------------------------------------- 1 |

Dual Core FIR Filter for the ESP32

2 | 3 | This Arduino IDE compatible program uses the FIR filter library funtion in ANSI C from [Espressif DSP Library](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-library.html#espressif-dsp-library) to perform Real-Time Digital Signal Processing. 4 | 5 | The goal of this project is to evaluate the ESP32 processor and gain experience with the Espressif Digital Signal Processing Library of functions. 6 | The inexpensive hardware approach coupled with the familiar Arduino IDE simplifies experimenting and facilitates learning to code DSP applications. 7 | 8 | 9 | 10 | The single-precision floating point filter coefficients are created in MATLAB or [on-line](http://t-filter.engineerjs.com) and examples are included for BandStop and HighPass filtering. 11 | Sample test input signal files are also included. 12 | 13 | 14 | NOTE: The micro-sdcard interface library must be installed manually in the Arduino IDE. 15 | 16 | [Installing Additional Arduino Libraries](https://www.arduino.cc/en/guide/libraries) 17 | 18 | Sketch->Include Library->Add .ZIP Library esp32-micro-sdcard-master.zip -- Check include library menu 19 | 20 | Input test signals for processing may be created in the PC program [Audacity](https://www.audacityteam.org), transferred to a micro-sdcard, and installed in the ESP32 board. 21 | Samples are then read by the ESP32 from a file on the micro-sdcard as if they came from an ADC (Analog to Digital Converter), 22 | filtered by the DSP algorithm, and then output in Real-Time through the ESP32's DAC (Digital to Analog Converter) and heard on the speaker. 23 | 24 | Format for Audacity export: WAV format, 25 | 8000 sps, single-track mono, WAV (Microsoft) signed 16-bit PCM. The SD card is formatted as FAT32. 26 | REMEMBER to actually move the wav file to the micro-sdcard from the PC. 27 | 28 | The ESP32 development hardware is the LILYGO® TTGO T8 V1.7 [ESP32 Module](https://www.tindie.com/products/ttgo/lilygor-ttgo-t8-v17-esp32-module/) 29 | 30 | Real-Time Samples at 8Ksps for voice audio range (< 4KHz) and computer game (tune style) low fidelity music. Not for high fidelity music. 31 | 32 | To keep cost and complexity down, no switches or displays are included with the hardware design. Instead, program interfacing is accomplished over a BLE (Bluetooth Low Energy) wireless link. 33 | Free phone apps from LightBlue or Nordic nRF Connect (iOS and Google play stores) are used to "Peak and Poke" program options to the filter program running on the ESP32. **See details below**. 34 | 35 | Time permitting, I will demonstrate more of the Espressif DSP Library functions and also multi-rate filters from the Orfanidis book. These will be documented on my blog [dspobjects.com](https://www.dspobjects.com) 36 | 37 | __________________________________________________________________ 38 | 39 | ![Screenshot](ESP32_FIR.PNG) 40 | 41 | 42 | 43 | __________________________________________________________________ 44 |

45 | 46 | 47 | 48 | 49 | 50 |

DSP Done Dirt Cheap

51 | __________________________________________________________________ 52 |

53 | 54 | 55 | 56 | **BLE Scan** 57 | The filter is switched in/out programmatically over a 58 | Bluetooth Low Energy (BLE) wireless link. 59 | A write of a value to characteristic 60 | "beb5483e-36e1-4688-b7f5-ea07361b26a8" toggles the filter in/out 61 | Use free phone apps from LightBlue or nRF Connect (Nordic) to 62 | write values over BLE to the ESP32. 63 | 64 | From either app, connect to BLE peripheral advertising name "DSP_FILTER" 65 | 66 | 67 | **LightBlue** app: Upper Right--Change "Hex" to "UTF-8 String"--Write new value--then any character entered and written toggles the 400 Hz Bandstop/LowPass filter On/Off 68 | 69 | **nRF Connect** app: After connect, slide to "Advertised Services" Window--tap the UP arrow--select UTF-8 Tab--enter any character--tap write 70 | 71 | In the /ESP32DACWaveforms/TwoCoreSineESP32 program enter a positive integer frequency between 300 and 2000 to switch sine wave frequency. 72 | 73 | 74 | [700 Hz Bandpass Filter Demo] (https://www.youtube.com/watch?v=p_xYwLlHv3Y&feature=youtu.be) 75 | 76 | __________________________________________________________________ 77 |

78 | ref: 79 | 80 | [Espressif DSP Library](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-library.html#espressif-dsp-library) 81 | 82 | [How to use Arduino ESP32 I2S (external DAC and built-in DAC) to play wav music file from sdcard](http://www.iotsharing.com/2017/07/how-to-use-arduino-esp32-i2s-to-play-wav-music-from-sdcard.html) 83 | 84 | [Installing Additional Arduino Libraries](https://www.arduino.cc/en/guide/libraries) 85 | 86 | [esp32 arduino ide](https://github.com/espressif/arduino-esp32) 87 | 88 | [DSP library for ESP-IDF](https://github.com/espressif/esp-dsp) 89 | 90 | 91 | [dspobjects.com](https://www.dspobjects.com) 92 | -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/dsps_fir.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef _dsps_fir_H_ 16 | #define _dsps_fir_H_ 17 | 18 | 19 | #include "dsp_err.h" 20 | 21 | 22 | #ifdef __cplusplus 23 | extern "C" 24 | { 25 | #endif 26 | 27 | /** 28 | * @brief Data struct of f32 fir filter 29 | * 30 | * This structure used by filter internally. User should access this structure only in case of 31 | * extensions for the DSP Library. 32 | * All fields of this structure initialized by dsps_fir_init_f32(...) function. 33 | */ 34 | typedef struct fir_f32_s { 35 | float *coeffs; /*!< Pointer to the coefficient buffer.*/ 36 | float *delay; /*!< Pointer to the delay line buffer.*/ 37 | int N; /*!< FIR filter coefficients amount.*/ 38 | int pos; /*!< Position in delay line.*/ 39 | int decim; /*!< Decimation factor.*/ 40 | int d_pos; /*!< Actual decimation counter.*/ 41 | } fir_f32_t; 42 | 43 | /** 44 | * @brief initialize structure for 32 bit FIR filter 45 | * 46 | * Function initialize structure for 32 bit floating point FIR filter 47 | * The implementation use ANSI C and could be compiled and run on any platform 48 | * 49 | * @param fir: pointer to fir filter structure, that must be preallocated 50 | * @param coeffs: array with FIR filter coefficients. Must be length N 51 | * @param delay: array for FIR filter delay line. Must be length N 52 | * @param N: FIR filter length. Length of coeffs and delay arrays. 53 | * 54 | * @return 55 | * - ESP_OK on success 56 | * - One of the error codes from DSP library 57 | */ 58 | esp_err_t dsps_fir_init_f32(fir_f32_t *fir, float *coeffs, float *delay, int N); 59 | 60 | /** 61 | * @brief initialize structure for 32 bit Decimation FIR filter 62 | * Function initialize structure for 32 bit floating point FIR filter with decimation 63 | * The implementation use ANSI C and could be compiled and run on any platform 64 | * 65 | * @param fir: pointer to fir filter structure, that must be preallocated 66 | * @param coeffs: array with FIR filter coefficients. Must be length N 67 | * @param delay: array for FIR filter delay line. Must be length N 68 | * @param N: FIR filter length. Length of coeffs and delay arrays. 69 | * @param decim: decimation factor. 70 | * @param start_pos: initial value of decimation counter. Must be [0..d) 71 | * 72 | * @return 73 | * - ESP_OK on success 74 | * - One of the error codes from DSP library 75 | */ 76 | esp_err_t dsps_fird_init_f32(fir_f32_t *fir, float *coeffs, float *delay, int N, int decim, int start_pos); 77 | 78 | 79 | /**@{*/ 80 | /** 81 | * @brief FIR filter 82 | * 83 | * Function implements FIR filter 84 | * The extension (_ansi) use ANSI C and could be compiled and run on any platform. 85 | * The extension (_ae32) is optimized for ESP32 chip. 86 | * 87 | * @param fir: pointer to fir filter structure, that must be initialized before 88 | * @param[in] input: input array 89 | * @param[out] output: array with result of FIR filter 90 | * @param[in] len: length of input and result arrays 91 | * 92 | * @return 93 | * - ESP_OK on success 94 | * - One of the error codes from DSP library 95 | */ 96 | esp_err_t dsps_fir_f32_ansi(fir_f32_t *fir, const float *input, float *output, int len); 97 | esp_err_t dsps_fir_f32_ae32(fir_f32_t *fir, const float *input, float *output, int len); 98 | /**@}*/ 99 | 100 | /**@{*/ 101 | /** 102 | * @brief Decimation FIR filter 103 | * 104 | * Function implements FIR filter with decimation 105 | * The extension (_ansi) use ANSI C and could be compiled and run on any platform. 106 | * The extension (_ae32) is optimized for ESP32 chip. 107 | * 108 | * @param fir: pointer to fir filter structure, that must be initialized before 109 | * @param input: input array 110 | * @param output: array with result of FIR filter 111 | * @param len: length of input and result arrays 112 | * 113 | * @return: function returns amount of samples stored to the output array 114 | * depends on the previous state value could be [0..len/decimation] 115 | */ 116 | int dsps_fird_f32_ansi(fir_f32_t *fir, const float *input, float *output, int len); 117 | int dsps_fird_f32_ae32(fir_f32_t *fir, const float *input, float *output, int len); 118 | /**@}*/ 119 | 120 | 121 | #ifdef __cplusplus 122 | } 123 | #endif 124 | 125 | #ifdef CONFIG_DSP_OPTIMIZED 126 | #define dsps_fir_f32 dsps_fir_f32_ae32 127 | #define dsps_fird_f32 dsps_fird_f32_ae32 128 | #endif 129 | #ifdef CONFIG_DSP_ANSI 130 | #define dsps_fir_f32 dsps_fir_f32_ansi 131 | #define dsps_fird_f32 dsps_fird_f32_ansi 132 | #endif 133 | 134 | #endif // _dsps_fir_H_ -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/ESP32DACWaveforms/TwoCoreTalkThru/TwoCoreTalkThru.ino: -------------------------------------------------------------------------------- 1 | 2 | // Created by bobolink 3 | // twitter: @wm6h 4 | // rev: 20180304 5 | 6 | /* 7 | Two core ESP-32 Arduino real-time audio demo. 8 | Tested on Espressif ESP32 Dev board 9 | Rev. 1 silicon 10 | Real-Time Samples at 8Ksps for voice audio range (< 4KHz). 11 | Not for music. 12 | Compatible with Arduino IDE 13 | 14 | talk through 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | //int LED_BUILTIN = 5; 21 | int LED_BUILTIN_TTGO = 21; 22 | 23 | 24 | const uint16_t N = 1024; // should be a power of 2 for FFTs 25 | // Determines how long the Application Processor can run for 26 | // real-time applications 27 | // or how long the Application has to write the samples to 28 | // a ring buffer for non-real time applications. 29 | // Latency, analog input to output, is a function of N. 30 | 31 | // we create complex numbers here for convenience 32 | // could be done in frame processing 33 | volatile double realPing[N]; 34 | volatile double imagPing[N]; 35 | volatile double realPong[N]; 36 | volatile double imagPong[N]; 37 | 38 | // Do frame processing in floats for better dynamic range. 39 | // At last stage, scale floats to range -1.0 to +1.0 40 | // then convert to unsigned char. Mult by 127 and 41 | // adding 128 to map +1.0 -- -1.0 to 0-255 for 42 | // output to 8-bit unsigned DAC 43 | 44 | // we create analytic IQ input samples 45 | // but we only output real numbers! 46 | volatile unsigned char outRealPing[N]; 47 | volatile unsigned char outRealPong[N]; 48 | 49 | 50 | float volume = 1.0; 51 | int frameCNT = 0; 52 | 53 | portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; 54 | 55 | // this is Core 1's variable. 56 | // Core 0 will operate on the other buffer 57 | volatile boolean pingCore1 = true; 58 | 59 | volatile boolean sampling = false; 60 | volatile boolean outputEnable = true; 61 | 62 | TaskHandle_t Task1; 63 | SemaphoreHandle_t newFrame; 64 | 65 | esp_err_t result; 66 | 67 | 68 | void IRAM_ATTR onTimer() 69 | { 70 | 71 | portENTER_CRITICAL_ISR(&timerMux); 72 | sampling = true; 73 | portEXIT_CRITICAL_ISR(&timerMux); 74 | 75 | } 76 | 77 | void setup() 78 | { 79 | 80 | // initialize digital pin LED_BUILTIN as an output. 81 | pinMode(LED_BUILTIN_TTGO, OUTPUT); 82 | 83 | Serial.begin(115200); 84 | 85 | newFrame = xSemaphoreCreateMutex(); 86 | 87 | 88 | xTaskCreatePinnedToCore( 89 | frameProcessing, 90 | "FrameProcessing", 91 | 1000, 92 | NULL, 93 | 1, 94 | &Task1, 95 | 0); 96 | 97 | delay(500); // needed to start-up task1 98 | 99 | 100 | // zero the DAC buffers 101 | for (int i = 0; i < N; ++i) 102 | { 103 | outRealPing[i] = 0; 104 | outRealPong[i] = 0; 105 | 106 | } 107 | 108 | // this almost matches the output resolution 109 | // all channels are GPIOs 32-39 110 | result = adc1_config_width(ADC_WIDTH_9Bit); 111 | // complete with Apple type error message 112 | if (result != ESP_OK) 113 | { 114 | Serial.println("Error, an unknown error occurred"); 115 | } 116 | 117 | // this might allow 3.3VDC on the mic 118 | // pin 34 119 | result = adc1_config_channel_atten( ADC1_CHANNEL_6, ADC_ATTEN_11db); 120 | if (result != ESP_OK) 121 | { 122 | Serial.println("Error, an unknown error occurred"); 123 | } 124 | 125 | Serial.print("Setup: Executing on core "); 126 | Serial.println(xPortGetCoreID()); 127 | 128 | 129 | hw_timer_t* timer = timerBegin(0, 80, true); 130 | timerAttachInterrupt(timer, &onTimer, true); 131 | timerAlarmWrite(timer, 125, true); // sampling frequency 8kHz 132 | timerAlarmEnable(timer); 133 | 134 | } 135 | 136 | // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 137 | // Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1 138 | // This Task runs on Core: 1 139 | // Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1 140 | // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 141 | 142 | // |||||||||||||||||| 143 | // Sample Service 144 | // |||||||||||||||||| 145 | void loop() 146 | { 147 | for (int i = 0; i < N; ++i) 148 | { 149 | while (!sampling); 150 | 151 | portENTER_CRITICAL(&timerMux); 152 | sampling = false; 153 | portEXIT_CRITICAL(&timerMux); 154 | 155 | digitalWrite(LED_BUILTIN_TTGO, HIGH); 156 | if (pingCore1 == true) 157 | { 158 | // configured for 9 bits with an 11 dB pad 159 | // drop one bit to give 8 to match the output 160 | realPing[i] = (float) (((byte)((adc1_get_voltage(ADC1_CHANNEL_6) >> 1) & 0xFF)) - 128.0); 161 | imagPing[i] = 0.0; 162 | // DAC output is 8-bit unsigned. Maximum (255) corresponds 163 | // for VDD_A 3.3V, to 2.59V 164 | if (outputEnable == true) 165 | { // GPIO pin 25 of the ESP32. 166 | // This is the output of DAC1 167 | //dacWrite(25, outRealPing[i]); 168 | dacWrite(26, outRealPing[i]);// pin 26 on TTGO T8 169 | } 170 | } 171 | else 172 | { 173 | // drop one bit to give 8 to match the output 174 | realPong[i] = (float) (((byte)((adc1_get_voltage(ADC1_CHANNEL_6) >> 1) & 0xFF)) - 128.0); 175 | imagPong[i] = 0.0; 176 | // DAC output is 8-bit unsigned. Maximum (255) corresponds 177 | // for VDD_A 3.3V, to 2.59V 178 | if (outputEnable == true) 179 | { // for VDD_A 3.3V, to 2.59V 180 | //dacWrite(25, outRealPong[i]); 181 | dacWrite(26, outRealPong[i]);// pin 26 on TTGO T8 182 | } 183 | } // end single sample processing 184 | digitalWrite(LED_BUILTIN_TTGO, LOW); 185 | } // end N samples processing 186 | 187 | // swap working buffer 188 | pingCore1 = !pingCore1; 189 | // give the old buffer to frame processing 190 | xSemaphoreGive(newFrame); 191 | } // end sample service task 192 | 193 | // /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ 194 | // 1111111111111111111111111111111111111111111111111111111111111 195 | // /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ 196 | 197 | 198 | 199 | // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 200 | // Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0 201 | // This Task runs on Core: 0 202 | // Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0 203 | // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 204 | // Frame processing 205 | // Runs every N samples 206 | 207 | void frameProcessing( void* parameter ) 208 | { 209 | Serial.print("Frame Processing: Executing on core "); 210 | Serial.println(xPortGetCoreID()); 211 | 212 | for (;;) // this is required, normally put in by 213 | { // Arduino IDE 214 | 215 | float outVal; 216 | int lm; 217 | 218 | outputEnable = true; 219 | 220 | // "Arf! Arf!" 221 | // pet the watchdog. 222 | vTaskDelay(10); 223 | 224 | // wait for the ping-pong buffer swap 225 | // indicating frame processing should begin 226 | // Core 1 has the timer resolution and is in charge of buffers 227 | xSemaphoreTake(newFrame, portMAX_DELAY); 228 | 229 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++ 230 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++ 231 | // frame processing takes place here: 232 | for (int i = 0; i < N; ++i) 233 | { 234 | // NOTE: 235 | // this variable belongs to core 1 -- use the other buffer 236 | // If core 1 is ping, we are pong 237 | if (pingCore1 == true) 238 | { 239 | outVal = realPong[i] * 0.008; // scale float to +/- 1.0 240 | outRealPong[i] = (unsigned char) (outVal * 127.0 + 128.0); 241 | } 242 | else 243 | { 244 | outVal = realPing[i] * 0.008; // scale float to +/- 1.0 245 | outRealPing[i] = (unsigned char) (outVal * 127.0 + 128.0); 246 | } 247 | }// end frame processing of N samples 248 | } // end Arduino task loop 249 | } 250 | // /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ 251 | // 0000000000000000000000000000000000000000000000000000000000000 252 | // /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ 253 | -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/ESP32DACWaveforms/TwoCoreSweepESP32/TwoCoreSweepESP32.ino: -------------------------------------------------------------------------------- 1 | 2 | // Created by bobolink 3 | // twitter: @wm6h 4 | // rev: 20180304 5 | 6 | 7 | /* 8 | Two core ESP-32 Arduino real-time audio demo. 9 | Tested on Espressif ESP32 Dev board 10 | Rev. 1 silicon 11 | Real-Time Samples at 8Ksps for voice audio range (< 4KHz). 12 | Not for music. 13 | Compatible with Arduino IDE 14 | 15 | Continuous phase frequency sweep test signal 16 | (300--3000 Hz in 5 sec., repeated) 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | //int LED_BUILTIN = 5; 23 | 24 | const uint16_t N = 1024; // should be a power of 2 for FFTs 25 | // Determines how long the Application Processor can run for 26 | // real-time applications 27 | // or how long the Application has to write the samples to 28 | // a ring buffer for non-real time applications. 29 | // Latency, input to output, is a function of N. 30 | 31 | // we create complex numbers here for convenience 32 | // could be done in frame processing 33 | volatile double realPing[N]; 34 | volatile double imagPing[N]; 35 | volatile double realPong[N]; 36 | volatile double imagPong[N]; 37 | 38 | // Do frame processing in floats for better dynamic range. 39 | // At last stage, scale floats to range -1.0 to +1.0 40 | // then convert to unsigned char. Mult by 127 and 41 | // adding 128 to map +1.0 -- -1.0 to 0-255 for 42 | // output to 8-bit unsigned DAC 43 | 44 | // we create analytic IQ input samples 45 | // but we only output real numbers 46 | volatile unsigned char outRealPing[N]; 47 | volatile unsigned char outRealPong[N]; 48 | 49 | const float Pi = 3.14159; 50 | float fangle = 0.0; 51 | float sampleRateHz = 8000.0; 52 | float testFreqHz = 300.0; 53 | // phase increment per sample 54 | const float phase = 2.0 * Pi * (testFreqHz / sampleRateHz); 55 | 56 | float phi = 0; 57 | float f0 = 300; //initial frequency (Hz) 58 | float f1 = 3000; // final frequency (Hz)--keep below 4KHz 59 | float tSweep = 5; //duration of sweep (s) 60 | float f = f0; 61 | 62 | // how long do divides take? 63 | // should we multiple by reciprocal in Frame processing? 64 | float fDelta = (f1 - f0) / (sampleRateHz * tSweep); 65 | float delta = 2.0 * Pi * (f / sampleRateHz); 66 | float t = 1/sampleRateHz; 67 | 68 | float volume = 0.5; 69 | 70 | portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; 71 | 72 | // this is Core 1's variable. 73 | // Core 0 will operate on the other buffer 74 | volatile boolean pingCore1 = true; 75 | 76 | volatile boolean sampling = false; 77 | volatile boolean outputEnable = true; 78 | 79 | TaskHandle_t Task1; 80 | SemaphoreHandle_t newFrame; 81 | 82 | esp_err_t result; 83 | 84 | void IRAM_ATTR onTimer() 85 | { 86 | 87 | portENTER_CRITICAL_ISR(&timerMux); 88 | sampling = true; 89 | portEXIT_CRITICAL_ISR(&timerMux); 90 | 91 | } 92 | 93 | void setup() 94 | { 95 | 96 | // initialize digital pin LED_BUILTIN as an output. 97 | //pinMode(LED_BUILTIN, OUTPUT); 98 | 99 | // Serial.begin(115200); 100 | 101 | newFrame = xSemaphoreCreateMutex(); 102 | 103 | 104 | xTaskCreatePinnedToCore( 105 | frameProcessing, 106 | "FrameProcessing", 107 | 1000, 108 | NULL, 109 | 1, 110 | &Task1, 111 | 0); 112 | 113 | delay(500); // needed to start-up task1 114 | 115 | 116 | // zero the DAC buffers 117 | for (int i = 0; i < N; ++i) 118 | { 119 | outRealPing[i] = 0; 120 | outRealPong[i] = 0; 121 | 122 | } 123 | 124 | // this almost matches the output resolution 125 | // all channels GPIOs 32-39 126 | result = adc1_config_width(ADC_WIDTH_9Bit); 127 | // complete with Apple type error message 128 | if (result != ESP_OK) 129 | { 130 | Serial.println("Error, an unknown error occurred"); 131 | } 132 | 133 | // this might allow 3.3VDC on the mic 134 | // pin 34 135 | result = adc1_config_channel_atten( ADC1_CHANNEL_6, ADC_ATTEN_11db); 136 | if (result != ESP_OK) 137 | { 138 | Serial.println("Error, an unknown error occurred"); 139 | } 140 | 141 | hw_timer_t* timer = timerBegin(0, 80, true); 142 | timerAttachInterrupt(timer, &onTimer, true); 143 | timerAlarmWrite(timer, 125, true); // sampling frequency 8kHz 144 | timerAlarmEnable(timer); 145 | 146 | } 147 | 148 | // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 149 | // Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1 150 | // This Task runs on Core: 1 151 | // Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1 152 | // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 153 | 154 | // |||||||||||||||||| 155 | // Sample Service 156 | // |||||||||||||||||| 157 | void loop() 158 | { 159 | for (int i = 0; i < N; ++i) 160 | { 161 | while (!sampling); 162 | 163 | portENTER_CRITICAL(&timerMux); 164 | sampling = false; 165 | portEXIT_CRITICAL(&timerMux); 166 | 167 | //digitalWrite(LED_BUILTIN, HIGH); 168 | if (pingCore1 == true) 169 | { 170 | // configured for 9 bits with an 11 dB pad 171 | // drop one bit to give 8 to match the output 172 | realPing[i] = (float) (((byte)((adc1_get_voltage(ADC1_CHANNEL_6) >> 1) & 0xFF)) - 128.0); 173 | imagPing[i] = 0.0; 174 | // DAC output is 8-bit unsigned. Maximum (255) corresponds 175 | // for VDD_A 3.3V, to 2.59V 176 | if (outputEnable == true) 177 | { // GPIO pin 25 of the ESP32. 178 | // This is the output of DAC1 179 | dacWrite(26, outRealPing[i]); 180 | } 181 | } 182 | else 183 | { 184 | // drop one bit to give 8 to match the output 185 | realPong[i] = (float) (((byte)((adc1_get_voltage(ADC1_CHANNEL_6) >> 1) & 0xFF)) - 128.0); 186 | imagPong[i] = 0.0; 187 | // DAC output is 8-bit unsigned. Maximum (255) corresponds 188 | // for VDD_A 3.3V, to 2.59V 189 | if (outputEnable == true) 190 | { // for VDD_A 3.3V, to 2.59V 191 | dacWrite(26, outRealPong[i]); 192 | } 193 | } // end single sample processing 194 | //digitalWrite(LED_BUILTIN, LOW); 195 | 196 | } // end N samples processing 197 | 198 | // swap working buffer 199 | pingCore1 = !pingCore1; 200 | // give the old buffer to frame processing 201 | xSemaphoreGive(newFrame); 202 | } // end sample service task 203 | 204 | // /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ 205 | // 1111111111111111111111111111111111111111111111111111111111111 206 | // /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ 207 | 208 | 209 | 210 | // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 211 | // Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0 212 | // This Task runs on Core: 0 213 | // Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0 214 | // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 215 | // Frame processing 216 | // Runs every N samples 217 | 218 | void frameProcessing( void* parameter ) 219 | { 220 | for (;;) // this is required, normally put in by 221 | { // Arduino IDE 222 | 223 | float outVal; 224 | 225 | outputEnable = true; 226 | 227 | // "Arf! Arf!" 228 | // pet the watchdog. 229 | vTaskDelay(10); 230 | // wait for the ping-pong buffer swap 231 | // indicating frame processing should begin 232 | // Core 1 has the timer resolution and is in charge of buffers 233 | xSemaphoreTake(newFrame, portMAX_DELAY); 234 | 235 | // frame processing takes place here: 236 | for (int i = 0; i < N; ++i) 237 | { 238 | phi = 0; 239 | outVal = sinf(phi) * volume; 240 | 241 | 242 | phi += delta; 243 | 244 | 245 | f += fDelta; 246 | if(f >= f1) 247 | { 248 | f = f0; 249 | phi = 0; 250 | } 251 | 252 | // multiply instead of divide 253 | // for speed? 254 | delta = 2 * Pi * f * t; 255 | 256 | // NOTE: 257 | // this variable belongs to core 1 -- use the other buffer 258 | // If core 1 is ping, we are pong 259 | if (pingCore1 == true) 260 | { 261 | outRealPong[i] = (unsigned char) (outVal * 127.0 + 128.0); 262 | 263 | } 264 | else 265 | { 266 | outRealPing[i] = (unsigned char) (outVal * 127.0 + 128.0); 267 | 268 | } 269 | 270 | }// end frame processing of N samples 271 | 272 | } // end Arduino task loop 273 | } 274 | // /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ 275 | // 0000000000000000000000000000000000000000000000000000000000000 276 | // /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ 277 | -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/ESP32DACWaveforms/TwoCoreTwoToneESP32/TwoCoreTwoToneESP32.ino: -------------------------------------------------------------------------------- 1 | 2 | // Created by bobolink 3 | // twitter: @wm6h 4 | // rev: 20180304 5 | 6 | /* 7 | Two core ESP-32 Arduino real-time audio demo. 8 | Tested on Espressif ESP32 Dev board 9 | Rev. 1 silicon 10 | Real-Time Samples at 8Ksps for voice audio range (< 4KHz). 11 | Not for music. 12 | Compatible with Arduino IDE 13 | */ 14 | 15 | /* 16 | * Generates an old-time telephone dial tone 17 | * With two tones (350 and 440 Hz). 18 | * 19 | * this example points out that 20 | * a computed value must be scaled properly to stay within the 21 | * +0.1 to -0.1 range as to not overload the 8-bit DAC. 22 | * When the two numbers within range are added, 23 | * they will exceed +/- 1.0 and must be divided by two. 24 | * Three numbers added must be divided by 3, etc. 25 | */ 26 | 27 | #include 28 | #include 29 | 30 | //int LED_BUILTIN = 5; 31 | 32 | const uint16_t N = 1024; // should be a power of 2 for FFTs 33 | // Determines how long the Application Processor can run for 34 | // real-time applications 35 | // or how long the Application has to write the samples to 36 | // a ring buffer for non-real time applications. 37 | // Latency, input to output, is a function of N. 38 | 39 | // we create complex numbers here for convenience 40 | // could be done in frame processing 41 | volatile double realPing[N]; 42 | volatile double imagPing[N]; 43 | volatile double realPong[N]; 44 | volatile double imagPong[N]; 45 | 46 | // Do frame processing in floats for better dynamic range. 47 | // At last stage, scale floats to range -1.0 to +1.0 48 | // then convert to unsigned char. Mult by 127 and 49 | // adding 128 to map +1.0 -- -1.0 to 0-255 for 50 | // output to 8-bit unsigned DAC 51 | 52 | // we create analytic IQ input samples 53 | // but we only output real numbers 54 | volatile unsigned char outRealPing[N]; 55 | volatile unsigned char outRealPong[N]; 56 | 57 | const float Pi = 3.14159; 58 | float theta1 = 0.0; 59 | float theta2 = 0.0; 60 | float sampleRateHz = 8000.0; 61 | float testFreqHz1 = 350.0; 62 | float testFreqHz2 = 440.0; 63 | const float theta_increment1 = 2.0 * Pi * (testFreqHz1 / sampleRateHz); 64 | const float theta_increment2 = 2.0 * Pi * (testFreqHz2 / sampleRateHz); 65 | 66 | float volume = 1.0; 67 | 68 | portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; 69 | 70 | // this is Core 1's variable. 71 | // Core 0 will operate on the other buffer 72 | volatile boolean pingCore1 = true; 73 | 74 | volatile boolean sampling = false; 75 | volatile boolean outputEnable = true; 76 | 77 | TaskHandle_t Task1; 78 | SemaphoreHandle_t newFrame; 79 | 80 | esp_err_t result; 81 | 82 | void IRAM_ATTR onTimer() 83 | { 84 | 85 | portENTER_CRITICAL_ISR(&timerMux); 86 | sampling = true; 87 | portEXIT_CRITICAL_ISR(&timerMux); 88 | 89 | } 90 | 91 | void setup() 92 | { 93 | 94 | // initialize digital pin LED_BUILTIN as an output. 95 | pinMode(LED_BUILTIN, OUTPUT); 96 | 97 | Serial.begin(115200); 98 | 99 | newFrame = xSemaphoreCreateMutex(); 100 | 101 | 102 | xTaskCreatePinnedToCore( 103 | frameProcessing, 104 | "FrameProcessing", 105 | 1000, 106 | NULL, 107 | 1, 108 | &Task1, 109 | 0); 110 | 111 | delay(500); // needed to start-up task1 112 | 113 | 114 | // zero the DAC buffers 115 | for (int i = 0; i < N; ++i) 116 | { 117 | outRealPing[i] = 0; 118 | outRealPong[i] = 0; 119 | 120 | } 121 | 122 | // this almost matches the output resolution 123 | // all channels GPIOs 32-39 124 | result = adc1_config_width(ADC_WIDTH_9Bit); 125 | // complete with Apple type error message 126 | if (result != ESP_OK) 127 | { 128 | Serial.println("Error, an unknown error occurred"); 129 | } 130 | 131 | // this might allow 3.3VDC on the mic 132 | // pin 34 133 | result = adc1_config_channel_atten( ADC1_CHANNEL_6, ADC_ATTEN_11db); 134 | if (result != ESP_OK) 135 | { 136 | Serial.println("Error, an unknown error occurred"); 137 | } 138 | 139 | hw_timer_t* timer = timerBegin(0, 80, true); 140 | timerAttachInterrupt(timer, &onTimer, true); 141 | timerAlarmWrite(timer, 125, true); // sampling frequency 8kHz 142 | timerAlarmEnable(timer); 143 | 144 | } 145 | 146 | // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 147 | // Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1 148 | // This Task runs on Core: 1 149 | // Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1 150 | // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 151 | 152 | // |||||||||||||||||| 153 | // Sample Service 154 | // |||||||||||||||||| 155 | void loop() 156 | { 157 | for (int i = 0; i < N; ++i) 158 | { 159 | while (!sampling); 160 | 161 | portENTER_CRITICAL(&timerMux); 162 | sampling = false; 163 | portEXIT_CRITICAL(&timerMux); 164 | 165 | digitalWrite(LED_BUILTIN, HIGH); 166 | if (pingCore1 == true) 167 | { 168 | // configured for 9 bits with an 11 dB pad 169 | // drop one bit to give 8 to match the output 170 | realPing[i] = (float) (((byte)((adc1_get_voltage(ADC1_CHANNEL_6) >> 1) & 0xFF)) - 128.0); 171 | imagPing[i] = 0.0; 172 | // DAC output is 8-bit unsigned. Maximum (255) corresponds 173 | // for VDD_A 3.3V, to 2.59V 174 | if (outputEnable == true) 175 | { // GPIO pin 25 of the ESP32. 176 | // This is the output of DAC1 177 | dacWrite(26, outRealPing[i]); 178 | } 179 | } 180 | else 181 | { 182 | // drop one bit to give 8 to match the output 183 | realPong[i] = (float) (((byte)((adc1_get_voltage(ADC1_CHANNEL_6) >> 1) & 0xFF)) - 128.0); 184 | imagPong[i] = 0.0; 185 | // DAC output is 8-bit unsigned. Maximum (255) corresponds 186 | // for VDD_A 3.3V, to 2.59V 187 | if (outputEnable == true) 188 | { // for VDD_A 3.3V, to 2.59V 189 | dacWrite(26, outRealPong[i]); 190 | } 191 | } // end single sample processing 192 | digitalWrite(LED_BUILTIN, LOW); 193 | } // end N samples processing 194 | 195 | // swap working buffer 196 | pingCore1 = !pingCore1; 197 | // give the old buffer to frame processing 198 | xSemaphoreGive(newFrame); 199 | } // end sample service task 200 | 201 | // /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ 202 | // 1111111111111111111111111111111111111111111111111111111111111 203 | // /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ 204 | 205 | 206 | 207 | // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 208 | // Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0 209 | // This Task runs on Core: 0 210 | // Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0 211 | // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 212 | // Frame processing 213 | // Runs every N samples 214 | 215 | void frameProcessing( void* parameter ) 216 | { 217 | for (;;) // this is required, normally put in by 218 | { // Arduino IDE 219 | 220 | float outVal; 221 | 222 | outputEnable = true; 223 | 224 | // "Arf! Arf!" 225 | // pet the watchdog. 226 | vTaskDelay(10); 227 | 228 | // wait for the ping-pong buffer swap 229 | // indicating frame processing should begin 230 | // Core 1 has the timer resolution and is in charge of buffers 231 | xSemaphoreTake(newFrame, portMAX_DELAY); 232 | 233 | // frame processing takes place here: 234 | for (int i = 0; i < N; ++i) 235 | { 236 | // the point of this example is to point out that 237 | // a computed value must be scaled properly to stay within the 238 | // +0.1 to -0.1 range to not overload the 8-bit DAC. 239 | // When the two numbers are added, they exceed +/- 1.0 240 | // and must be divided by two (mult by 0.5). Three numbers added must 241 | // be divided by 3, etc. 242 | outVal = (sinf(theta1) + sinf(theta2)) * 0.5 * volume; 243 | 244 | theta1 += theta_increment1; 245 | if (theta1 > 2.0 * Pi) 246 | { 247 | theta1 -= 2.0 * Pi; 248 | } 249 | 250 | theta2 += theta_increment2; 251 | if (theta2 > 2.0 * Pi) 252 | { 253 | theta2 -= 2.0 * Pi; 254 | } 255 | // NOTE: 256 | // this variable belongs to core 1 -- use the other buffer 257 | // If core 1 is ping, we are pong 258 | if (pingCore1 == true) 259 | { 260 | outRealPong[i] = (unsigned char) (outVal * 127.0 + 128.0); 261 | } 262 | else 263 | { 264 | outRealPing[i] = (unsigned char) (outVal * 127.0 + 128.0); 265 | } 266 | 267 | }// end frame processing of N samples 268 | 269 | } // end Arduino task loop 270 | } 271 | // /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ 272 | // 0000000000000000000000000000000000000000000000000000000000000 273 | // /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ 274 | -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/ESP32DACWaveforms/TwoCoreSineESP32/TwoCoreSineESP32.ino: -------------------------------------------------------------------------------- 1 | 2 | // Created by bobolink 3 | // twitter: @wm6h 4 | // rev: 20180304 5 | 6 | /* 7 | Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleWrite.cpp 8 | Ported to Arduino ESP32 by Evandro Copercini 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | /* 16 | Two core ESP-32 Arduino real-time audio demo. 17 | Tested on Espressif ESP32 Dev board 18 | Rev. 1 silicon 19 | Real-Time Samples at 8Ksps for voice audio range (< 4KHz). 20 | Not for music. 21 | Compatible with Arduino IDE 22 | 23 | Generates a sine wave 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | 30 | #define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" 31 | #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" 32 | 33 | //int LED_BUILTIN = 5; 34 | int LED_BUILTIN_TTGO = 21; 35 | 36 | const uint16_t N = 1024; // should be a power of 2 for FFTs 37 | // Determines how long the Application Processor can run for 38 | // real-time applications 39 | // or how long the Application has to write the samples to 40 | // a ring buffer for non-real time applications. 41 | // Latency, input to output, is a function of N. 42 | 43 | 44 | // we create complex numbers here for convenience 45 | // could be done in frame processing 46 | volatile double realPing[N]; 47 | volatile double imagPing[N]; 48 | volatile double realPong[N]; 49 | volatile double imagPong[N]; 50 | 51 | // Do frame processing in floats for better dynamic range. 52 | // At last stage, scale floats to range -1.0 to +1.0 53 | // then convert to unsigned char. Mult by 127 and 54 | // adding 128 to map +1.0 -- -1.0 to 0-255 for 55 | // output to 8-bit unsigned DAC 56 | 57 | // we create analytic IQ input samples 58 | // but we only output real numbers 59 | volatile unsigned char outRealPing[N]; 60 | volatile unsigned char outRealPong[N]; 61 | 62 | const float Pi = 3.14159; 63 | float theta = 0.0; 64 | float sampleRateHz = 8000.0; 65 | float testFreqHz = 1000.0; 66 | //const float theta_increment = 2.0 * Pi * (testFreqHz / sampleRateHz); 67 | float theta_increment; 68 | 69 | 70 | float volume = 0.5; 71 | 72 | portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; 73 | 74 | // this is Core 1's variable. 75 | // Core 0 will operate on the other buffer 76 | volatile boolean pingCore1 = true; 77 | 78 | volatile boolean sampling = false; 79 | volatile boolean outputEnable = true; 80 | 81 | 82 | TaskHandle_t Task1; 83 | SemaphoreHandle_t newFrame; 84 | 85 | esp_err_t result; 86 | 87 | void IRAM_ATTR onTimer() 88 | { 89 | 90 | portENTER_CRITICAL_ISR(&timerMux); 91 | sampling = true; 92 | portEXIT_CRITICAL_ISR(&timerMux); 93 | 94 | } 95 | 96 | class MyCallbacks: public BLECharacteristicCallbacks { 97 | void onWrite(BLECharacteristic *pCharacteristic) { 98 | std::string value = pCharacteristic->getValue(); 99 | 100 | // not very safe code 101 | char tempc[4]; 102 | 103 | 104 | if (value.length() > 0) { 105 | Serial.println("*********"); 106 | Serial.print("New value: "); 107 | for (int i = 0; i < value.length(); i++) 108 | { 109 | //Serial.print(value[i]); 110 | tempc[i] = value[i]; 111 | } 112 | 113 | //float f = (float) atof(tempc); 114 | float f = strtod(tempc,NULL); 115 | if( (f>30) && (f<=3000) ) 116 | testFreqHz = f; 117 | 118 | Serial.println(f); 119 | Serial.println("*********"); 120 | } 121 | } 122 | }; 123 | 124 | 125 | void setup() 126 | { 127 | 128 | // initialize digital pin LED_BUILTIN as an output. 129 | pinMode(LED_BUILTIN_TTGO, OUTPUT); 130 | 131 | Serial.begin(115200); 132 | 133 | newFrame = xSemaphoreCreateMutex(); 134 | 135 | 136 | xTaskCreatePinnedToCore( 137 | frameProcessing, 138 | "FrameProcessing", 139 | 1000, 140 | NULL, 141 | 1, 142 | &Task1, 143 | 0); 144 | 145 | delay(500); // needed to start-up task1 146 | // from Mr. Spiess' video 147 | 148 | // zero the DAC buffers 149 | for (int i = 0; i < N; ++i) 150 | { 151 | outRealPing[i] = 0; 152 | outRealPong[i] = 0; 153 | 154 | } 155 | 156 | // this almost matches the output resolution 157 | // all channels GPIOs 32-39 158 | result = adc1_config_width(ADC_WIDTH_9Bit); 159 | // complete with Apple type error message 160 | if (result != ESP_OK) 161 | { 162 | Serial.println("Error, an unknown error occurred"); 163 | } 164 | 165 | // this might allow 3.3VDC on the mic 166 | // pin 34 167 | result = adc1_config_channel_atten( ADC1_CHANNEL_6, ADC_ATTEN_11db); 168 | if (result != ESP_OK) 169 | { 170 | Serial.println("Error, an unknown error occurred"); 171 | } 172 | 173 | 174 | 175 | 176 | BLEDevice::init("MyESP32"); 177 | BLEServer *pServer = BLEDevice::createServer(); 178 | 179 | BLEService *pService = pServer->createService(SERVICE_UUID); 180 | 181 | BLECharacteristic *pCharacteristic = pService->createCharacteristic( 182 | CHARACTERISTIC_UUID, 183 | BLECharacteristic::PROPERTY_READ | 184 | BLECharacteristic::PROPERTY_WRITE 185 | ); 186 | 187 | pCharacteristic->setCallbacks(new MyCallbacks()); 188 | 189 | pCharacteristic->setValue("Hello World"); 190 | pService->start(); 191 | 192 | BLEAdvertising *pAdvertising = pServer->getAdvertising(); 193 | pAdvertising->start(); 194 | 195 | 196 | 197 | 198 | Serial.print("Setup: Executing on core "); 199 | Serial.println(xPortGetCoreID()); 200 | 201 | hw_timer_t* timer = timerBegin(0, 80, true); 202 | timerAttachInterrupt(timer, &onTimer, true); 203 | timerAlarmWrite(timer, 125, true); // sampling frequency 8kHz 204 | timerAlarmEnable(timer); 205 | 206 | } 207 | 208 | // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 209 | // Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1 210 | // This Task runs on Core: 1 211 | // Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1 212 | // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 213 | 214 | // |||||||||||||||||| 215 | // Sample Service 216 | // |||||||||||||||||| 217 | void loop() 218 | { 219 | for (int i = 0; i < N; ++i) 220 | { 221 | while (!sampling); 222 | 223 | portENTER_CRITICAL(&timerMux); 224 | sampling = false; 225 | portEXIT_CRITICAL(&timerMux); 226 | 227 | //digitalWrite(LED_BUILTIN_TTGO, HIGH); 228 | if (pingCore1 == true) 229 | { 230 | // configured for 9 bits with an 11 dB pad 231 | // drop one bit to give 8 to match the output 232 | realPing[i] = (float) (((byte)((adc1_get_voltage(ADC1_CHANNEL_6) >> 1) & 0xFF)) - 128.0); 233 | imagPing[i] = 0.0; 234 | // DAC output is 8-bit unsigned. Maximum (255) corresponds 235 | // for VDD_A 3.3V, to 2.59V 236 | if (outputEnable == true) 237 | { // GPIO pin 25 of the ESP32. 238 | // This is the output of DAC1 239 | //dacWrite(25, outRealPing[i]); 240 | dacWrite(26, outRealPing[i]);//pin 26 TTGO T8 241 | } 242 | } 243 | else 244 | { 245 | // drop one bit to give 8 to match the output 246 | realPong[i] = (float) (((byte)((adc1_get_voltage(ADC1_CHANNEL_6) >> 1) & 0xFF)) - 128.0); 247 | imagPong[i] = 0.0; 248 | // DAC output is 8-bit unsigned. Maximum (255) corresponds 249 | // for VDD_A 3.3V, to 2.59V 250 | if (outputEnable == true) 251 | { // for VDD_A 3.3V, to 2.59V 252 | //dacWrite(25, outRealPong[i]); 253 | dacWrite(26, outRealPong[i]);//pin 26 TTGO T8 254 | } 255 | } // end single sample processing 256 | //digitalWrite(LED_BUILTIN_TTGO, LOW); 257 | } // end N samples processing 258 | 259 | // swap working buffer 260 | pingCore1 = !pingCore1; 261 | // give the old buffer to frame processing 262 | xSemaphoreGive(newFrame); 263 | } // end sample service task 264 | 265 | // /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ 266 | // 1111111111111111111111111111111111111111111111111111111111111 267 | // /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ 268 | 269 | 270 | 271 | // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 272 | // Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0 273 | // This Task runs on Core: 0 274 | // Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0 275 | // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 276 | // Frame processing 277 | // Runs every N samples 278 | 279 | void frameProcessing( void* parameter ) 280 | { 281 | Serial.print("Frame Processing: Executing on core "); 282 | Serial.println(xPortGetCoreID()); 283 | 284 | for (;;) // this is required, normally put in by 285 | { // Arduino IDE 286 | 287 | float outVal; 288 | 289 | outputEnable = true; 290 | 291 | // "Arf! Arf!" 292 | // pet the watchdog. 293 | vTaskDelay(10); 294 | 295 | // wait for the ping-pong buffer swap 296 | // indicating frame processing should begin 297 | // Core 1 has the timer resolution and is in charge of buffers 298 | xSemaphoreTake(newFrame, portMAX_DELAY); 299 | 300 | digitalWrite(LED_BUILTIN_TTGO, HIGH); 301 | // don't need to give it back 302 | //xSemaphoreGive(newFrame); 303 | theta_increment = 2.0 * Pi * (testFreqHz * 0.000125); 304 | 305 | // frame processing takes place here: 306 | for (int i = 0; i < N; ++i) 307 | { 308 | outVal = sinf(theta) * volume; 309 | theta += theta_increment; 310 | if (theta > 2.0 * Pi) 311 | { 312 | theta -= 2.0 * Pi; 313 | } 314 | // NOTE: 315 | // this variable belongs to core 1 -- use the other buffer 316 | // If core 1 is ping, we are pong 317 | if (pingCore1 == true) 318 | { 319 | outRealPong[i] = (unsigned char) (outVal * 127.0 + 128.0); 320 | } 321 | else 322 | { 323 | outRealPing[i] = (unsigned char) (outVal * 127.0 + 128.0); 324 | } 325 | 326 | }// end frame processing of N samples 327 | 328 | digitalWrite(LED_BUILTIN_TTGO, LOW); 329 | // this processing takes 2.24 msec. 330 | // out of 128 msec. available to the Frame 331 | // 125 usec * 1024 = 128 msec. 332 | // 1.75% loaded 333 | // 334 | } // end Arduino task loop 335 | } 336 | // /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ 337 | // 0000000000000000000000000000000000000000000000000000000000000 338 | // /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ 339 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/ESP32FIR.ino: -------------------------------------------------------------------------------- 1 | 2 | // Created by bobolink 3 | // twitter: @wm6h 4 | // rev: 20200126 5 | 6 | // Copyright 2020 WM6H 7 | // 8 | // Licensed under the Apache License, Version 2.0 (the "License"); 9 | // you may not use this file except in compliance with the License. 10 | // You may obtain a copy of the License at 11 | // 12 | // http://www.apache.org/licenses/LICENSE-2.0 13 | // 14 | // Unless required by applicable law or agreed to in writing, software 15 | // distributed under the License is distributed on an "AS IS" BASIS, 16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | // See the License for the specific language governing permissions and 18 | // limitations under the License. 19 | 20 | /* NOTE: 21 | * You need to specify the file name of the wav file on the SD card 22 | * you want to pass through the FIR filter 23 | * Also, which 400 Hz filter you want to use-- the bandstop or high pass filter-- 24 | * by including the desired filer coefficient file. 25 | * See STEP 1 and STEP 2 below 26 | */ 27 | 28 | /* 29 | Two core ESP-32 Arduino real-time audio demo. 30 | Tested on Espressif ESP32 Dev board 31 | Rev. 1 silicon 32 | Real-Time Samples at 8Ksps for voice audio range (< 4KHz). 33 | Not for high fidelity music. 34 | Compatible with Arduino IDE 35 | 36 | Updated to read input test signals from sd card on a 37 | TTGO T8 Development card 38 | Added FIR filter 39 | SD card file is: 8Ksps, mono, WAV (Microsoft) signed 16-bit PCM 40 | FAT32 formatted SD Card 41 | 42 | http://www.iotsharing.com/2017/07/how-to-use-arduino-esp32-i2s-to-play-wav-music-from-sdcard.html 43 | 44 | NOTE: 45 | SDCARD interface library must be installed manually. 46 | 47 | Installing Additional Arduino Libraries 48 | https://www.arduino.cc/en/guide/libraries 49 | 50 | Found in top directory 51 | Sketch->Include Library->Add .ZIP Library “esp32-micro-sdcard-master.zip” 52 | #include 53 | 54 | */ 55 | 56 | #include 57 | #include 58 | 59 | //STEP 1 60 | //******************************************************************* 61 | // Initialize "SDcardFileName" with the SD Card file you want to play 62 | // Uncomment one of these: 63 | 64 | // a 30 sec 1000 Hz tone 65 | // String SDcardFileName = "sineWAV.wav"; 66 | 67 | // 2 min of 400 Hz plus 1000Hz 68 | // enable 400Hz filter to eliminate interference 69 | String SDcardFileName = "mix.wav"; 70 | 71 | // 400Hz tone for 2 minutes 72 | // if the 400Hz StopBand or HighPass filter is in, 73 | // no sound should be heard 74 | //String SDcardFileName = "400Hz2m.wav"; 75 | 76 | //******************************************************************* 77 | /* 78 | Based on Neil Kolban example for IDF: 79 | https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleWrite.cpp 80 | Ported to Arduino ESP32 by Evandro Copercini 81 | */ 82 | 83 | #include 84 | #include 85 | #include 86 | 87 | //\|||||||||||||||||||||||||| 88 | #include 89 | 90 | // minimum library includes for the FIR filter 91 | #include "dsp_err.h" 92 | #include "dsp_err_codes.h" 93 | 94 | #include "dsps_fir.h" 95 | 96 | //STEP 2 97 | //******************************************************************* 98 | // Include only one of these FIR filters 99 | // Bandstop or HighPass 100 | // see ./design/ directory for filter frequency plots 101 | 102 | // 400Hz filters: 103 | //#include "fdaBScoefs.h"//(length 121) 40 dB attenuation BandStop 104 | #include "fdaHPcoefs.h" //(length 51) 60 dB attenuation HighPass 105 | 106 | // filter is switched in/out programmatically over a 107 | // Bluetooth Low Energy (BLE) wireless link. 108 | // A write of a value to characteristic 109 | // "beb5483e-36e1-4688-b7f5-ea07361b26a8" toggles the filter in/out 110 | // Use free phone app from LightBlue or nRF Connect (Nordic) to 111 | // write values. 112 | 113 | // Connect to BLE peripheral advertising name "DSP_FILTER" 114 | 115 | //******************************************************************* 116 | 117 | 118 | // BL is the coefficient name Matlab gives 119 | #define NTAPS BL-1 120 | 121 | #define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" 122 | #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" 123 | //\|||||||||||||||||||||||||| 124 | 125 | //#include "driver/i2s.h" 126 | //#include "freertos/queue.h" 127 | 128 | /* variables hold file, state of process wav file and wav file properties */ 129 | File root; 130 | bool wavPlaying = false; 131 | bool LoopBack = true;//start with input copied to output to hear tone 132 | // then switch in the filter over BLE 133 | 134 | 135 | 136 | #define CCCC(c1, c2, c3, c4) ((c4 << 24) | (c3 << 16) | (c2 << 8) | c1) 137 | 138 | /* these are data structures to process wav file */ 139 | typedef enum headerState_e { 140 | HEADER_RIFF, HEADER_FMT, HEADER_DATA, DATA, OUT_OF_DATA 141 | } headerState_t; 142 | 143 | typedef struct wavRiff_s { 144 | uint32_t chunkID; 145 | uint32_t chunkSize; 146 | uint32_t format; 147 | } wavRiff_t; 148 | 149 | typedef struct wavProperties_s { 150 | uint32_t chunkID; 151 | uint32_t chunkSize; 152 | uint16_t audioFormat; 153 | uint16_t numChannels; 154 | uint32_t sampleRate; 155 | uint32_t byteRate; 156 | uint16_t blockAlign; 157 | uint16_t bitsPerSample; 158 | } wavProperties_t; 159 | 160 | headerState_t state = HEADER_RIFF; 161 | wavProperties_t wavProps; 162 | // convert little endian to big endian 4 byte int 163 | uint32_t overall_size = 0; 164 | unsigned char buffer4[4]; 165 | 166 | 167 | const uint16_t N = 1024; // should be a power of 2 for FFTs 168 | // Determines how long the Application Processor can run for 169 | // real-time applications 170 | // or how long the Application has to write the samples to 171 | // a ring buffer for non-real time applications. 172 | // Latency, input to output, is a function of N. 173 | 174 | //\|||||||||||||||||||||||||| 175 | // x[] is input to the filter 176 | float x[N]; 177 | // y[] is output of the filter and routed to the DAC 178 | float y[N]; 179 | 180 | float coeffs[NTAPS]; 181 | float history[NTAPS]; 182 | int len; 183 | int fir_len; 184 | unsigned int startTEST = 0; 185 | unsigned int endTEST = 0; 186 | float totalTEST; 187 | 188 | fir_f32_t fir1; 189 | 190 | //\|||||||||||||||||||||||||| 191 | 192 | void debug(uint8_t *buf, int len) 193 | { 194 | for (int i = 0; i < len; i++) { 195 | Serial.print(buf[i], HEX); 196 | Serial.print("\t"); 197 | } 198 | Serial.println(); 199 | } 200 | 201 | /* read 4 bytes of data from wav file */ 202 | int read4bytes(File file, uint32_t *chunkId) { 203 | int n = file.read((uint8_t *)chunkId, sizeof(uint32_t)); 204 | return n; 205 | } 206 | 207 | int readbyte(File file, uint8_t *chunkId) { 208 | int n = file.read((uint8_t *)chunkId, sizeof(uint8_t)); 209 | return n; 210 | } 211 | 212 | /* these are function to process wav file */ 213 | int readRiff(File file, wavRiff_t *wavRiff) { 214 | int n = file.read((uint8_t *)wavRiff, sizeof(wavRiff_t)); 215 | return n; 216 | } 217 | int readProps(File file, wavProperties_t *wavProps) { 218 | int n = file.read((uint8_t *)wavProps, sizeof(wavProperties_t)); 219 | return n; 220 | } 221 | 222 | 223 | int LED_BUILTIN_TTGO = 21; 224 | 225 | // we create complex numbers here for convenience 226 | // could be done in frame processing 227 | volatile float realPing[N]; 228 | volatile float imagPing[N]; 229 | volatile float realPong[N]; 230 | volatile float imagPong[N]; 231 | 232 | // Do frame processing in floats for better dynamic range. 233 | // At last stage, scale floats to range -1.0 to +1.0 234 | // then convert to unsigned char. Mult by 127 and 235 | // adding 128 to map +1.0 -- -1.0 to 0-255 for 236 | // output to 8-bit unsigned DAC 237 | 238 | // we create analytic IQ input samples 239 | // but we only output real numbers because, well you know, 240 | // they're real 241 | volatile unsigned char outRealPing[N]; 242 | volatile unsigned char outRealPong[N]; 243 | 244 | float volume; 245 | 246 | portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; 247 | 248 | // this is Core 1's variable. 249 | // Core 0 will operate on the other buffer 250 | volatile boolean pingCore1 = true; 251 | 252 | volatile boolean sampling = false; 253 | volatile boolean outputEnable = true; 254 | 255 | 256 | TaskHandle_t Task1; 257 | SemaphoreHandle_t newFrame; 258 | 259 | esp_err_t result; 260 | 261 | unsigned char __Temp_wav[] = { 262 | 0x00, 0x00 263 | }; 264 | 265 | 266 | unsigned int sampleCNT = 0; 267 | 268 | void IRAM_ATTR onTimer() 269 | { 270 | 271 | portENTER_CRITICAL_ISR(&timerMux); 272 | sampling = true; 273 | portEXIT_CRITICAL_ISR(&timerMux); 274 | 275 | } 276 | 277 | class MyCallbacks: public BLECharacteristicCallbacks 278 | { 279 | void onWrite(BLECharacteristic *pCharacteristic) 280 | { 281 | std::string value = pCharacteristic->getValue(); 282 | 283 | if (value.length() > 0) 284 | { 285 | LoopBack = LoopBack ? false : true; 286 | } 287 | } 288 | }; 289 | 290 | 291 | void setup() 292 | { 293 | 294 | // initialize digital pin LED_BUILTIN as an output. 295 | pinMode(LED_BUILTIN_TTGO, OUTPUT);//it's green 296 | digitalWrite(LED_BUILTIN_TTGO, LOW); 297 | 298 | Serial.begin(115200); 299 | 300 | Serial.print("Initializing SD card..."); 301 | 302 | // if (!SD.begin(32, 14, 12, 27)) { 303 | if (!SD.begin(13, 15, 2, 14)) { // for TTGO T8 hardware 304 | Serial.println("initialization failed!"); 305 | return; 306 | } 307 | 308 | Serial.println("initialization done."); 309 | Serial.print("MOSI = "); Serial.println(MOSI); 310 | Serial.print("MISO = "); Serial.println(MISO); 311 | Serial.print("SCK = "); Serial.println(SCK); 312 | Serial.print("SS = "); Serial.println(SS); 313 | 314 | 315 | /* open specified wav file and process it */ 316 | root = SD.open(SDcardFileName.c_str ()); 317 | Serial.println(SDcardFileName.c_str ()); 318 | 319 | if (root) 320 | { // we found the file, is it mono wave format? 321 | int c = 0; 322 | int n; 323 | wavRiff_t wavRiff; 324 | n = readRiff(root, &wavRiff); 325 | if (n == sizeof(wavRiff_t)) { 326 | if (wavRiff.chunkID == CCCC('R', 'I', 'F', 'F') && wavRiff.format == CCCC('W', 'A', 'V', 'E')) { 327 | Serial.println("HEADER_RIFF"); 328 | } 329 | } 330 | 331 | n = readProps(root, &wavProps); 332 | if (n == sizeof(wavProperties_t)) { 333 | Serial.println("WAVE PROPERTIES"); 334 | } 335 | 336 | uint32_t chunkId, chunkSize; 337 | n = read4bytes(root, &chunkId); 338 | if (n == 4) { 339 | if (chunkId == CCCC('d', 'a', 't', 'a')) 340 | { 341 | Serial.println("HEADER_DATA"); 342 | } 343 | } 344 | //++++++++++++++++++++++++++++++++++++++++= 345 | // read the 4 bytes chunk size 346 | n = read4bytes(root, &chunkSize); 347 | if (n == 4) { 348 | 349 | Serial.println("chunkSize:"); 350 | Serial.println(chunkSize); 351 | Serial.println("prepare data"); 352 | wavPlaying = true; 353 | } 354 | //++++++++++++++++++++++++++++++++++++++++= 355 | /* after processing wav file, it is time to process audio data */ 356 | } 357 | else 358 | { 359 | Serial.println("error opening wav file"); 360 | wavPlaying = false; 361 | } 362 | 363 | 364 | //\|||||||||||||||||||||||||| 365 | len = sizeof(x) / sizeof(float); 366 | fir_len = (sizeof(B) / sizeof(float)) - 1; //order v.s. length 367 | // initialize the coefficients with the Matlab designed values 368 | for (int i = 0 ; i < fir_len ; i++) 369 | { 370 | coeffs[i] = B[i]; 371 | } 372 | 373 | // initialize the fir filter struct using library function 374 | dsps_fir_init_f32(&fir1, coeffs, history, fir_len); 375 | //\|||||||||||||||||||||||||| 376 | 377 | Serial.println("initialization done."); 378 | delay(1000); 379 | 380 | newFrame = xSemaphoreCreateMutex(); 381 | 382 | xTaskCreatePinnedToCore( 383 | frameProcessing, 384 | "FrameProcessing", 385 | 1000, 386 | NULL, 387 | 1, 388 | &Task1, 389 | 0); 390 | 391 | delay(500); // needed to start-up task1 392 | // from Mr. Spiess' video 393 | 394 | // zero the DAC buffers 395 | for (int i = 0; i < N; ++i) 396 | { 397 | outRealPing[i] = 0; 398 | outRealPong[i] = 0; 399 | 400 | } 401 | 402 | // this almost matches the output resolution 403 | // all channels GPIOs 32-39 404 | result = adc1_config_width(ADC_WIDTH_9Bit); 405 | // complete with Apple type error message 406 | if (result != ESP_OK) 407 | { 408 | Serial.println("Error, an unknown error occurred"); 409 | } 410 | 411 | // this might allow 3.3VDC on the mic 412 | // pin 34 413 | result = adc1_config_channel_atten( ADC1_CHANNEL_6, ADC_ATTEN_11db); 414 | if (result != ESP_OK) 415 | { 416 | Serial.println("Error, an unknown error occurred"); 417 | } 418 | 419 | //||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 420 | BLEDevice::init("DSP_FILTER"); 421 | BLEServer *pServer = BLEDevice::createServer(); 422 | 423 | BLEService *pService = pServer->createService(SERVICE_UUID); 424 | 425 | BLECharacteristic *pCharacteristic = pService->createCharacteristic( 426 | CHARACTERISTIC_UUID, 427 | BLECharacteristic::PROPERTY_READ | 428 | BLECharacteristic::PROPERTY_WRITE 429 | ); 430 | 431 | pCharacteristic->setCallbacks(new MyCallbacks()); 432 | 433 | pCharacteristic->setValue("Hello World"); 434 | pService->start(); 435 | 436 | BLEAdvertising *pAdvertising = pServer->getAdvertising(); 437 | pAdvertising->start(); 438 | //||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 439 | 440 | Serial.print("Arduino Loop(): Executing on core "); 441 | Serial.println(xPortGetCoreID()); 442 | 443 | //Sart the Sample Clock 444 | hw_timer_t* timer = timerBegin(0, 80, true); 445 | timerAttachInterrupt(timer, &onTimer, true); 446 | timerAlarmWrite(timer, 125, true); // sampling frequency 8kHz 447 | timerAlarmEnable(timer); 448 | 449 | } 450 | 451 | // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 452 | // Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1 453 | // This Task runs on Core: 1 454 | // Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1Core1 455 | // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 456 | 457 | // |||||||||||||||||| 458 | // Sample Service 459 | // |||||||||||||||||| 460 | void loop() 461 | { 462 | for (int i = 0; i < N; ++i) 463 | { 464 | while (!sampling); 465 | 466 | portENTER_CRITICAL(&timerMux); 467 | sampling = false; 468 | portEXIT_CRITICAL(&timerMux); 469 | 470 | if (pingCore1 == true) 471 | { 472 | // configured for 9 bits with an 11 dB pad 473 | // drop one bit to give 8 to match the output 474 | realPing[i] = (float) (((byte)((adc1_get_voltage(ADC1_CHANNEL_6) >> 1) & 0xFF)) - 128.0); 475 | imagPing[i] = 0.0; 476 | // DAC output is 8-bit unsigned. Maximum (255) corresponds 477 | // for VDD_A 3.3V, to 2.59V 478 | if (outputEnable == true) 479 | { // GPIO pin 25 of the ESP32. 480 | // This is the output of DAC1 481 | //dacWrite(25, outRealPing[i]); 482 | // DAC1 on the TTGO T8 is 26 483 | dacWrite(26, outRealPing[i]); 484 | } 485 | } 486 | else 487 | { 488 | // drop one bit to give 8 to match the output 489 | realPong[i] = (float) (((byte)((adc1_get_voltage(ADC1_CHANNEL_6) >> 1) & 0xFF)) - 128.0); 490 | imagPong[i] = 0.0; 491 | // DAC output is 8-bit unsigned. Maximum (255) corresponds 492 | // for VDD_A 3.3V, to 2.59V 493 | if (outputEnable == true) 494 | { // for VDD_A 3.3V, to 2.59V 495 | //dacWrite(25, outRealPong[i]); 496 | // DAC1 on the TTGO T8 497 | dacWrite(26, outRealPong[i]); 498 | } 499 | } // end single sample processing 500 | //digitalWrite(LED_BUILTIN_TTGO, LOW); 501 | } // end N samples processing 502 | 503 | // swap working buffer 504 | pingCore1 = !pingCore1; 505 | // give the old buffer to frame processing 506 | xSemaphoreGive(newFrame); 507 | } // end sample service task 508 | 509 | // /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ 510 | // 1111111111111111111111111111111111111111111111111111111111111 511 | // /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ 512 | 513 | 514 | 515 | // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 516 | // Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0 517 | // This Task runs on Core: 0 518 | // Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0Core0 519 | // ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 520 | // Frame processing 521 | // Runs every N samples 522 | 523 | void frameProcessing( void* parameter ) 524 | { 525 | int n; 526 | uint8_t data; 527 | 528 | Serial.print("Frame Processing: Executing on core "); 529 | Serial.println(xPortGetCoreID()); 530 | 531 | for (;;) // this is required, normally put in by 532 | { // Arduino IDE 533 | 534 | int16_t outVal; 535 | float outValf; 536 | uint16_t sample; 537 | 538 | //startTEST = xthal_get_ccount(); 539 | volume = 2.0; 540 | outputEnable = true; 541 | 542 | // "Arf! Arf!" 543 | // pet the watchdog. 544 | vTaskDelay(10); 545 | 546 | // wait for the ping-pong buffer swap 547 | // indicating frame processing should begin 548 | // Core 1 has the timer resolution and is in charge of buffers 549 | // We are Core 0 550 | xSemaphoreTake(newFrame, portMAX_DELAY); 551 | 552 | // start "wav playing" LED 553 | digitalWrite(LED_BUILTIN_TTGO, HIGH); 554 | 555 | //||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||\ 556 | //||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||\ 557 | 558 | int tempi; 559 | 560 | // copy/format PCM data from SD Card to filter input array 561 | // this simulates reading a buffered ADC in real time 562 | for (int i = 0; i < N; ++i) // read a frame of input signal 563 | { 564 | 565 | if (root.available()) 566 | { // some kind of byte swapped Intel Hex format 567 | tempi = readbyte(root, &data); 568 | __Temp_wav[0] = data; 569 | 570 | tempi = readbyte(root, &data); 571 | __Temp_wav[1] = data; 572 | 573 | outVal = (int16_t) ((__Temp_wav[0]) | (__Temp_wav[1] << 8)); 574 | x[i] = ((float)outVal * 0.000015259) * volume; 575 | } 576 | else 577 | { 578 | root.close(); 579 | wavPlaying = false; 580 | // stop "wav playing" LED 581 | digitalWrite(LED_BUILTIN_TTGO, LOW); 582 | } 583 | }// end frame processing of N samples 584 | 585 | // finished reading a frame of input samples 586 | 587 | // run the filter at the frame, update history 588 | if (LoopBack == false) 589 | { // no loopback. run the filter 590 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 591 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 592 | dsps_fir_f32_ansi(&fir1, x, y, len); 593 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 594 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 595 | } 596 | else 597 | { 598 | // loopback test 599 | // LoopBack variable controlled over BLE 600 | for (int i = 0; i < N; ++i) // copy input direct to output 601 | { // skip the filter 602 | y[i] = x[i]; 603 | } 604 | } 605 | //|||||||||||||||||||||||||||||||||| 606 | // Output to DAC 607 | // output a frame of filtered samples 608 | for (int i = 0; i < N; ++i) 609 | { 610 | // NOTE: 611 | // this variable belongs to core 1 -- use the other buffer 612 | // If core 1 is ping, we are pong 613 | if (pingCore1 == true) 614 | { // PING time 615 | //convert to DAC format 616 | if (wavPlaying == true) 617 | { 618 | outRealPong[i] = (unsigned char) ((y[i] * 127.0) + 128.0); 619 | } 620 | else 621 | { // not playing wav, output a zero 622 | outRealPong[i] = (unsigned char) 0; 623 | } 624 | } 625 | else 626 | { // PONG time 627 | //convert to DAC format 628 | if (wavPlaying == true) 629 | { 630 | outRealPing[i] = (unsigned char) ((y[i] * 127.0) + 128.0); 631 | } 632 | else 633 | { // not playing wav, output a zero 634 | outRealPing[i] = (unsigned char) 0; 635 | } 636 | } 637 | 638 | }// end frame processing of N samples 639 | 640 | // this processing takes x msec. 641 | // out of 128 msec. available to the Frame 642 | // 125 usec * 1024 = 128 msec. 643 | // y% loaded 644 | // 645 | //endTEST = xthal_get_ccount(); 646 | //totalTEST = endTEST - startTEST; 647 | //ESP_LOGI(TAG, "dsps_fir_f32_ansi - %f per sample for for %i coefficients, 648 | //%f per tap \n", cycles, fir_len, cycles / (float)fir_len); 649 | 650 | 651 | // end of frame processing 652 | } // end Arduino task loop 653 | } 654 | // /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ 655 | // 0000000000000000000000000000000000000000000000000000000000000 656 | // /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ 657 | -------------------------------------------------------------------------------- /ESP_DSP/ESP32FIR/tmwtypes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1984-2016 The MathWorks, Inc. 3 | * All Rights Reserved. 4 | */ 5 | 6 | #if defined(_MSC_VER) 7 | # pragma once 8 | #endif 9 | #if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)) 10 | # pragma once 11 | #endif 12 | 13 | #ifndef tmwtypes_h 14 | #define tmwtypes_h 15 | 16 | #ifndef __TMWTYPES__ 17 | #define __TMWTYPES__ 18 | /* 19 | * File : tmwtypes.h 20 | * Abstract: 21 | * Data types for use with MATLAB/SIMULINK and the Real-Time Workshop. 22 | * 23 | * When compiling stand-alone model code, data types can be overridden 24 | * via compiler switches. 25 | * 26 | * Define NO_FLOATS to eliminate reference to real_T, etc. 27 | */ 28 | 29 | #include 30 | 31 | #ifdef __APPLE_CC__ 32 | #include 33 | #endif 34 | 35 | #define LOGICAL_IS_A_TYPE 36 | #define SPARSE_GENERALIZATION 37 | 38 | #ifdef NO_FLOATS 39 | # define double double_not_allowed 40 | # define float float_not_allowed 41 | #endif /*NO_FLOATS*/ 42 | 43 | #ifndef NO_FLOATS 44 | 45 | #ifndef __MWERKS__ 46 | # ifdef __STDC__ 47 | # include 48 | # else 49 | # define FLT_MANT_DIG 24 50 | # define DBL_MANT_DIG 53 51 | # endif 52 | #endif 53 | 54 | #endif /*NO_FLOATS*/ 55 | 56 | /* 57 | * The following data types cannot be overridden when building MEX files. 58 | */ 59 | #ifdef MATLAB_MEX_FILE 60 | # undef CHARACTER_T 61 | # undef INTEGER_T 62 | # undef BOOLEAN_T 63 | # undef REAL_T 64 | # undef TIME_T 65 | #endif 66 | 67 | /* 68 | * The uchar_T, ushort_T and ulong_T types are needed for compilers which do 69 | * not allow defines to be specified, at the command line, with spaces in them. 70 | */ 71 | 72 | typedef unsigned char uchar_T; 73 | typedef unsigned short ushort_T; 74 | typedef unsigned long ulong_T; 75 | 76 | #if (defined(_MSC_VER) && _MSC_VER >= 1500) \ 77 | || defined(__x86_64__) || defined(__LP64__) \ 78 | || defined(__LCC64__) 79 | 80 | typedef unsigned long long ulonglong_T; 81 | #endif 82 | 83 | 84 | 85 | /*=======================================================================* 86 | * Fixed width word size data types: * 87 | * int8_T, int16_T, int32_T - signed 8, 16, or 32 bit integers * 88 | * uint8_T, uint16_T, uint32_T - unsigned 8, 16, or 32 bit integers * 89 | * real32_T, real64_T - 32 and 64 bit floating point numbers * 90 | *=======================================================================*/ 91 | 92 | /* When used with Real Time Workshop generated code, this 93 | * header file can be used with a variety of compilers. 94 | * 95 | * The compiler could be for an 8 bit embedded processor that 96 | * only had 8 bits per integer and 16 bits per long. 97 | * In that example, a 32 bit integer size is not even available. 98 | * This header file should be robust to that. 99 | * 100 | * For the case of an 8 bit processor, the preprocessor 101 | * may be limited to 16 bit math like its target. That limitation 102 | * would mean that 32 bit comparisons can't be done accurately. 103 | * To increase robustness to this, comparisons are done against 104 | * smaller values first. An inaccurate 32 bit comparison isn't 105 | * attempted if the 16 bit comparison has already succeeded. 106 | * 107 | * Limitations on preprocessor math can also be stricter than 108 | * for the target. There are known cases where a compiler 109 | * targeting processors with 64 bit longs can't do accurate 110 | * preprocessor comparisons on more than 32 bits. 111 | */ 112 | 113 | /* Determine the number of bits for int, long, short, and char. 114 | * If one fails to be determined, set the number of bits to -1 115 | */ 116 | 117 | #ifndef TMW_BITS_PER_INT 118 | # if INT_MAX == 0x7FL 119 | # define TMW_BITS_PER_INT 8 120 | # elif INT_MAX == 0x7FFFL 121 | # define TMW_BITS_PER_INT 16 122 | # elif INT_MAX == 0x7FFFFFFFL 123 | # define TMW_BITS_PER_INT 32 124 | # else 125 | # define TMW_BITS_PER_INT -1 126 | # endif 127 | #endif 128 | 129 | #ifndef TMW_BITS_PER_LONG 130 | # if LONG_MAX == 0x7FL 131 | # define TMW_BITS_PER_LONG 8 132 | # elif LONG_MAX == 0x7FFFL 133 | # define TMW_BITS_PER_LONG 16 134 | # elif LONG_MAX == 0x7FFFFFFFL 135 | # define TMW_BITS_PER_LONG 32 136 | # else 137 | # define TMW_BITS_PER_LONG -1 138 | # endif 139 | #endif 140 | 141 | #ifndef TMW_BITS_PER_SHRT 142 | # if SHRT_MAX == 0x7FL 143 | # define TMW_BITS_PER_SHRT 8 144 | # elif SHRT_MAX == 0x7FFFL 145 | # define TMW_BITS_PER_SHRT 16 146 | # elif SHRT_MAX == 0x7FFFFFFFL 147 | # define TMW_BITS_PER_SHRT 32 148 | # else 149 | # define TMW_BITS_PER_SHRT -1 150 | # endif 151 | #endif 152 | 153 | #ifndef TMW_BITS_PER_SCHAR 154 | # if SCHAR_MAX == 0x7FL 155 | # define TMW_BITS_PER_SCHAR 8 156 | # elif SCHAR_MAX == 0x7FFFL 157 | # define TMW_BITS_PER_SCHAR 16 158 | # elif SCHAR_MAX == 0x7FFFFFFFL 159 | # define TMW_BITS_PER_SCHAR 32 160 | # else 161 | # define TMW_BITS_PER_SCHAR -1 162 | # endif 163 | #endif 164 | 165 | #ifndef TMW_CHAR_SIGNED 166 | # if SCHAR_MAX == CHAR_MAX 167 | # define TMW_CHAR_SIGNED 1 168 | # else 169 | # define TMW_CHAR_SIGNED 0 170 | # endif 171 | #endif 172 | 173 | /* It is common for one or more of the integer types 174 | * to be the same size. For example, on many embedded 175 | * processors, both shorts and ints are 16 bits. On 176 | * processors used for workstations, it is quite common 177 | * for both int and long to be 32 bits. 178 | * When there is more than one choice for typdef'ing 179 | * a portable type like int16_T or uint32_T, in 180 | * concept, it should not matter which choice is made. 181 | * However, some style guides and some code checking 182 | * tools do identify and complain about seemingly 183 | * irrelevant differences. For example, a code 184 | * checking tool may complain about an implicit 185 | * conversion from int to short even though both 186 | * are 16 bits. To reduce these types of 187 | * complaints, it is best to make int the 188 | * preferred choice when more than one is available. 189 | */ 190 | 191 | #ifndef INT8_T 192 | # if TMW_BITS_PER_INT == 8 193 | # define INT8_T int 194 | # elif TMW_BITS_PER_LONG == 8 195 | # define INT8_T long 196 | # elif TMW_BITS_PER_SCHAR == 8 197 | # define INT8_T signed char 198 | # elif TMW_BITS_PER_SHRT == 8 199 | # define INT8_T short 200 | # endif 201 | #endif 202 | #ifdef INT8_T 203 | typedef INT8_T int8_T; 204 | #endif 205 | 206 | #ifndef UINT8_T 207 | # if TMW_BITS_PER_INT == 8 208 | # define UINT8_T unsigned int 209 | # elif TMW_BITS_PER_LONG == 8 210 | # define UINT8_T unsigned long 211 | # elif TMW_BITS_PER_SCHAR == 8 212 | # define UINT8_T unsigned char 213 | # elif TMW_BITS_PER_SHRT == 8 214 | # define UINT8_T unsigned short 215 | # endif 216 | #endif 217 | #ifdef UINT8_T 218 | typedef UINT8_T uint8_T; 219 | #endif 220 | 221 | 222 | #ifndef INT16_T 223 | # if TMW_BITS_PER_INT == 16 224 | # define INT16_T int 225 | # elif TMW_BITS_PER_LONG == 16 226 | # define INT16_T long 227 | # elif TMW_BITS_PER_SCHAR == 16 228 | # define INT16_T signed char 229 | # elif TMW_BITS_PER_SHRT == 16 230 | # define INT16_T short 231 | # endif 232 | #endif 233 | #ifdef INT16_T 234 | typedef INT16_T int16_T; 235 | #endif 236 | 237 | 238 | #ifndef UINT16_T 239 | # if TMW_BITS_PER_INT == 16 240 | # define UINT16_T unsigned int 241 | # elif TMW_BITS_PER_LONG == 16 242 | # define UINT16_T unsigned long 243 | # elif TMW_BITS_PER_SCHAR == 16 244 | # define UINT16_T unsigned char 245 | # elif TMW_BITS_PER_SHRT == 16 246 | # define UINT16_T unsigned short 247 | # endif 248 | #endif 249 | #ifdef UINT16_T 250 | typedef UINT16_T uint16_T; 251 | #endif 252 | 253 | 254 | #ifndef INT32_T 255 | # if TMW_BITS_PER_INT == 32 256 | # define INT32_T int 257 | # elif TMW_BITS_PER_LONG == 32 258 | # define INT32_T long 259 | # elif TMW_BITS_PER_SCHAR == 32 260 | # define INT32_T signed char 261 | # elif TMW_BITS_PER_SHRT == 32 262 | # define INT32_T short 263 | # endif 264 | #endif 265 | #ifdef INT32_T 266 | typedef INT32_T int32_T; 267 | #endif 268 | 269 | 270 | #ifndef UINT32_T 271 | # if TMW_BITS_PER_INT == 32 272 | # define UINT32_T unsigned int 273 | # elif TMW_BITS_PER_LONG == 32 274 | # define UINT32_T unsigned long 275 | # elif TMW_BITS_PER_SCHAR == 32 276 | # define UINT32_T unsigned char 277 | # elif TMW_BITS_PER_SHRT == 32 278 | # define UINT32_T unsigned short 279 | # endif 280 | #endif 281 | #ifdef UINT32_T 282 | typedef UINT32_T uint32_T; 283 | #endif 284 | 285 | /* The following is used to emulate smaller integer types when only 286 | * larger types are available. For example, compilers for TI C3x/C4x DSPs 287 | * define char and short to be 32 bits, so 8 and 16 bits are not directly 288 | * available. This target is commonly used with RTW rapid prototyping. 289 | * Other DSPs define char to be 16 bits, so 8 bits is not directly 290 | * available. 291 | */ 292 | #ifndef INT8_T 293 | # ifdef INT16_T 294 | # define INT8_T INT16_T 295 | typedef INT8_T int8_T; 296 | # else 297 | # ifdef INT32_T 298 | # define INT8_T INT32_T 299 | typedef INT8_T int8_T; 300 | # endif 301 | # endif 302 | #endif 303 | 304 | #ifndef UINT8_T 305 | # ifdef UINT16_T 306 | # define UINT8_T UINT16_T 307 | typedef UINT8_T uint8_T; 308 | # else 309 | # ifdef UINT32_T 310 | # define UINT8_T UINT32_T 311 | typedef UINT8_T uint8_T; 312 | # endif 313 | # endif 314 | #endif 315 | 316 | #ifndef INT16_T 317 | # ifdef INT32_T 318 | # define INT16_T INT32_T 319 | typedef INT16_T int16_T; 320 | # endif 321 | #endif 322 | 323 | #ifndef UINT16_T 324 | # ifdef UINT32_T 325 | # define UINT16_T UINT32_T 326 | typedef UINT16_T uint16_T; 327 | # endif 328 | #endif 329 | 330 | 331 | #ifndef NO_FLOATS 332 | 333 | #ifndef REAL32_T 334 | # ifndef __MWERKS__ 335 | # if FLT_MANT_DIG >= 23 336 | # define REAL32_T float 337 | # endif 338 | # else 339 | # define REAL32_T float 340 | # endif 341 | #endif 342 | #ifdef REAL32_T 343 | typedef REAL32_T real32_T; 344 | #endif 345 | 346 | 347 | #ifndef REAL64_T 348 | # ifndef __MWERKS__ 349 | # if DBL_MANT_DIG >= 52 350 | # define REAL64_T double 351 | # endif 352 | # else 353 | # define REAL64_T double 354 | # endif 355 | #endif 356 | #ifdef REAL64_T 357 | typedef REAL64_T real64_T; 358 | #endif 359 | 360 | #endif /* NO_FLOATS*/ 361 | 362 | /*=======================================================================* 363 | * Fixed width word size data types: * 364 | * int64_T - signed 64 bit integers * 365 | * uint64_T - unsigned 64 bit integers * 366 | *=======================================================================*/ 367 | 368 | 369 | 370 | #ifndef INT64_T 371 | # if defined(__APPLE__) 372 | # define INT64_T long long 373 | # define FMT64 "ll" 374 | # if defined(__LP64__) && !defined(INT_TYPE_64_IS_LONG) 375 | # define INT_TYPE_64_IS_LONG 376 | # endif 377 | # elif (defined(__x86_64__) || defined(__LP64__))&& !defined(__MINGW64__) 378 | # define INT64_T long 379 | # define FMT64 "l" 380 | # if !defined(INT_TYPE_64_IS_LONG) 381 | # define INT_TYPE_64_IS_LONG 382 | # endif 383 | # elif defined(_MSC_VER) || (defined(__BORLANDC__) && __BORLANDC__ >= 0x530) \ 384 | || (defined(__WATCOMC__) && __WATCOMC__ >= 1100) 385 | # define INT64_T __int64 386 | # define FMT64 "I64" 387 | # elif defined(__GNUC__) || defined(TMW_ENABLE_INT64) \ 388 | || defined(__LCC64__) 389 | # define INT64_T long long 390 | # define FMT64 "ll" 391 | # endif 392 | #endif 393 | 394 | 395 | 396 | #if defined(INT64_T) 397 | # if defined(__GNUC__) && \ 398 | ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >=9))) 399 | __extension__ 400 | # endif 401 | typedef INT64_T int64_T; 402 | #endif 403 | 404 | 405 | 406 | #ifndef UINT64_T 407 | # if defined(__APPLE__) 408 | # define UINT64_T unsigned long long 409 | # define FMT64 "ll" 410 | # if defined(__LP64__) && !defined(INT_TYPE_64_IS_LONG) 411 | # define INT_TYPE_64_IS_LONG 412 | # endif 413 | # elif (defined(__x86_64__) || defined(__LP64__))&& !defined(__MINGW64__) 414 | # define UINT64_T unsigned long 415 | # define FMT64 "l" 416 | # if !defined(INT_TYPE_64_IS_LONG) 417 | # define INT_TYPE_64_IS_LONG 418 | # endif 419 | # elif defined(_MSC_VER) || (defined(__BORLANDC__) && __BORLANDC__ >= 0x530) \ 420 | || (defined(__WATCOMC__) && __WATCOMC__ >= 1100) 421 | # define UINT64_T unsigned __int64 422 | # define FMT64 "I64" 423 | # elif defined(__GNUC__) || defined(TMW_ENABLE_INT64) \ 424 | || defined(__LCC64__) 425 | # define UINT64_T unsigned long long 426 | # define FMT64 "ll" 427 | # endif 428 | #endif 429 | 430 | #if defined(_WIN64) || (defined(__APPLE__) && defined(__LP64__)) \ 431 | || defined(__x86_64__) \ 432 | || defined(__LP64__) 433 | # define INT_TYPE_64_IS_SUPPORTED 434 | #endif 435 | 436 | #if defined(UINT64_T) 437 | # if defined(__GNUC__) && \ 438 | ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >=9))) 439 | __extension__ 440 | # endif 441 | typedef UINT64_T uint64_T; 442 | #endif 443 | 444 | /*===========================================================================* 445 | * Format string modifiers for using size_t variables in printf statements. * 446 | *===========================================================================*/ 447 | 448 | #ifndef FMT_SIZE_T 449 | # if (defined( __GNUC__ ) || defined(_STDC_C99))&& !defined(__MINGW64__) 450 | # define FMT_SIZE_T "z" 451 | # elif defined (__WATCOMC__) 452 | # define FMT_SIZE_T "l" 453 | # elif defined (_WIN32 ) 454 | # define FMT_SIZE_T "I" 455 | # else 456 | # define FMT_SIZE_T "l" 457 | # endif 458 | #endif 459 | 460 | #ifndef FMT_PTRDIFF_T 461 | # if defined(__APPLE__) 462 | # define FMT_PTRDIFF_T "l" 463 | # elif defined( __GNUC__ ) || defined(_STDC_C99) 464 | # define FMT_PTRDIFF_T "t" 465 | # elif defined (__WATCOMC__) 466 | # define FMT_PTRDIFF_T "l" 467 | # elif defined (_WIN32 ) 468 | # define FMT_PTRDIFF_T "I" 469 | # else 470 | # define FMT_PTRDIFF_T "l" 471 | # endif 472 | #endif 473 | 474 | /*===========================================================================* 475 | * General or logical data types where the word size is not guaranteed. * 476 | * real_T - possible settings include real32_T or real64_T * 477 | * time_T - possible settings include real32_T or real64_T * 478 | * boolean_T * 479 | * char_T * 480 | * int_T * 481 | * uint_T * 482 | * byte_T * 483 | *===========================================================================*/ 484 | 485 | #ifndef NO_FLOATS 486 | 487 | #ifndef REAL_T 488 | # ifdef REAL64_T 489 | # define REAL_T real64_T 490 | # else 491 | # ifdef REAL32_T 492 | # define REAL_T real32_T 493 | # endif 494 | # endif 495 | #endif 496 | #ifdef REAL_T 497 | typedef REAL_T real_T; 498 | #endif 499 | 500 | #ifndef TIME_T 501 | # ifdef REAL_T 502 | # define TIME_T real_T 503 | # endif 504 | #endif 505 | #ifdef TIME_T 506 | typedef TIME_T time_T; 507 | #endif 508 | 509 | #endif /* NO_FLOATS */ 510 | 511 | #ifndef BOOLEAN_T 512 | # if defined(UINT8_T) 513 | # define BOOLEAN_T UINT8_T 514 | # else 515 | # define BOOLEAN_T unsigned int 516 | # endif 517 | #endif 518 | typedef BOOLEAN_T boolean_T; 519 | 520 | 521 | #ifndef CHARACTER_T 522 | # define CHARACTER_T char 523 | #endif 524 | typedef CHARACTER_T char_T; 525 | 526 | 527 | #ifndef INTEGER_T 528 | # define INTEGER_T int 529 | #endif 530 | typedef INTEGER_T int_T; 531 | 532 | 533 | #ifndef UINTEGER_T 534 | # define UINTEGER_T unsigned 535 | #endif 536 | typedef UINTEGER_T uint_T; 537 | 538 | 539 | #ifndef BYTE_T 540 | # define BYTE_T unsigned char 541 | #endif 542 | typedef BYTE_T byte_T; 543 | 544 | 545 | /*===========================================================================* 546 | * Define Complex Structures * 547 | *===========================================================================*/ 548 | #ifndef NO_FLOATS 549 | 550 | #ifndef CREAL32_T 551 | # ifdef REAL32_T 552 | typedef struct { 553 | real32_T re, im; 554 | } creal32_T; 555 | # define CREAL32_T creal32_T 556 | # endif 557 | #endif 558 | 559 | #ifndef CREAL64_T 560 | # ifdef REAL64_T 561 | typedef struct { 562 | real64_T re, im; 563 | } creal64_T; 564 | # define CREAL64_T creal64_T 565 | # endif 566 | #endif 567 | 568 | #ifndef CREAL_T 569 | # ifdef REAL_T 570 | typedef struct { 571 | real_T re, im; 572 | } creal_T; 573 | # define CREAL_T creal_T 574 | # endif 575 | #endif 576 | 577 | #endif /* NO_FLOATS */ 578 | 579 | #ifndef CINT8_T 580 | # ifdef INT8_T 581 | typedef struct { 582 | int8_T re, im; 583 | } cint8_T; 584 | # define CINT8_T cint8_T 585 | # endif 586 | #endif 587 | 588 | #ifndef CUINT8_T 589 | # ifdef UINT8_T 590 | typedef struct { 591 | uint8_T re, im; 592 | } cuint8_T; 593 | # define CUINT8_T cuint8_T 594 | # endif 595 | #endif 596 | 597 | #ifndef CINT16_T 598 | # ifdef INT16_T 599 | typedef struct { 600 | int16_T re, im; 601 | } cint16_T; 602 | # define CINT16_T cint16_T 603 | # endif 604 | #endif 605 | 606 | #ifndef CUINT16_T 607 | # ifdef UINT16_T 608 | typedef struct { 609 | uint16_T re, im; 610 | } cuint16_T; 611 | # define CUINT16_T cuint16_T 612 | # endif 613 | #endif 614 | 615 | #ifndef CINT32_T 616 | # ifdef INT32_T 617 | typedef struct { 618 | int32_T re, im; 619 | } cint32_T; 620 | # define CINT32_T cint32_T 621 | # endif 622 | #endif 623 | 624 | #ifndef CUINT32_T 625 | # ifdef UINT32_T 626 | typedef struct { 627 | uint32_T re, im; 628 | } cuint32_T; 629 | # define CUINT32_T cuint32_T 630 | # endif 631 | #endif 632 | 633 | #ifndef CINT64_T 634 | # ifdef INT64_T 635 | typedef struct { 636 | int64_T re, im; 637 | } cint64_T; 638 | # define CINT64_T cint64_T 639 | # endif 640 | #endif 641 | 642 | #ifndef CUINT64_T 643 | # ifdef UINT64_T 644 | typedef struct { 645 | uint64_T re, im; 646 | } cuint64_T; 647 | # define CUINT64_T cuint64_T 648 | # endif 649 | #endif 650 | 651 | /*=======================================================================* 652 | * Min and Max: * 653 | * int8_T, int16_T, int32_T - signed 8, 16, or 32 bit integers * 654 | * uint8_T, uint16_T, uint32_T - unsigned 8, 16, or 32 bit integers * 655 | *=======================================================================*/ 656 | 657 | #define MAX_int8_T ((int8_T)(127)) /* 127 */ 658 | #define MIN_int8_T ((int8_T)(-128)) /* -128 */ 659 | #define MAX_uint8_T ((uint8_T)(255)) /* 255 */ 660 | #define MIN_uint8_T ((uint8_T)(0)) 661 | 662 | #define MAX_int16_T ((int16_T)(32767)) /* 32767 */ 663 | #define MIN_int16_T ((int16_T)(-32768)) /* -32768 */ 664 | #define MAX_uint16_T ((uint16_T)(65535)) /* 65535 */ 665 | #define MIN_uint16_T ((uint16_T)(0)) 666 | 667 | #define MAX_int32_T ((int32_T)(2147483647)) /* 2147483647 */ 668 | #define MIN_int32_T ((int32_T)(-2147483647-1)) /* -2147483648 */ 669 | #define MAX_uint32_T ((uint32_T)(0xFFFFFFFFU)) /* 4294967295 */ 670 | #define MIN_uint32_T ((uint32_T)(0)) 671 | 672 | #if defined(_MSC_VER) || (defined(__BORLANDC__) && __BORLANDC__ >= 0x530) \ 673 | || (defined(__WATCOMC__) && __WATCOMC__ >= 1100) \ 674 | || defined(__LCC64__) 675 | # ifdef INT64_T 676 | # define MAX_int64_T ((int64_T)(9223372036854775807LL)) 677 | # define MIN_int64_T ((int64_T)(-9223372036854775807LL-1LL)) 678 | # endif 679 | # ifdef UINT64_T 680 | # define MAX_uint64_T ((uint64_T)(0xFFFFFFFFFFFFFFFFULL)) 681 | # define MIN_uint64_T ((uint64_T)(0)) 682 | # endif 683 | #else 684 | # ifdef INT64_T 685 | # ifdef INT_TYPE_64_IS_LONG 686 | # define MAX_int64_T ((int64_T)(9223372036854775807L)) 687 | # define MIN_int64_T ((int64_T)(-9223372036854775807L-1L)) 688 | # else 689 | # define MAX_int64_T ((int64_T)(9223372036854775807LL)) 690 | # define MIN_int64_T ((int64_T)(-9223372036854775807LL-1LL)) 691 | # endif 692 | # endif 693 | # ifdef UINT64_T 694 | # ifdef INT_TYPE_64_IS_LONG 695 | # define MAX_uint64_T ((uint64_T)(0xFFFFFFFFFFFFFFFFUL)) 696 | # define MIN_uint64_T ((uint64_T)(0)) 697 | # else 698 | # define MAX_uint64_T ((uint64_T)(0xFFFFFFFFFFFFFFFFULL)) 699 | # define MIN_uint64_T ((uint64_T)(0)) 700 | # endif 701 | # endif 702 | #endif 703 | 704 | #ifdef _MSC_VER 705 | /* Conversion from unsigned __int64 to double is not implemented in windows 706 | * and results in a compile error, thus the value must first be cast to 707 | * signed __int64, and then to double. 708 | * 709 | * If the 64 bit int value is greater than 2^63-1, which is the signed int64 max, 710 | * the macro below provides a workaround for casting a uint64 value to a double 711 | * in windows. 712 | */ 713 | # define uint64_to_double(u) ( ((u) > _I64_MAX) ? \ 714 | (double)(__int64)((u) - _I64_MAX - 1) + (double)_I64_MAX + 1: \ 715 | (double)(__int64)(u) ) 716 | 717 | /* The following inline function should only be used in the macro double_to_uint64, 718 | * as it only handles the specfic range of double between 2^63 and 2^64-1 */ 719 | __forceinline 720 | uint64_T double_to_uint64_helper(double d) { 721 | union double_to_uint64_union_type { 722 | double dd; 723 | uint64_T i64; 724 | } di; 725 | di.dd = d; 726 | return (((di.i64 & 0x000fffffffffffff) | 0x0010000000000000) << 11); 727 | } 728 | 729 | /* The largest double value that can be cast to uint64 in windows is the 730 | * signed int64 max, which is 2^63-1. The macro below provides 731 | * a workaround for casting large double values to uint64 in windows. 732 | */ 733 | /* The magic number 18446744073709551616.0 is 2^64 */ 734 | /* The magic number 9223372036854775808.0 is 2^63 */ 735 | # define double_to_uint64(d) ( ((d) >= 18446744073709551616.0) ? \ 736 | 0xffffffffffffffffULL : \ 737 | ((d) >= 0.0) ? \ 738 | ((d) >= 9223372036854775808.0) ? \ 739 | double_to_uint64_helper(d) : \ 740 | (unsigned __int64)(d) : \ 741 | 0ULL ) 742 | #else 743 | # define uint64_to_double(u) ((double)(u)) 744 | # if defined(__BORLANDC__) || defined(__WATCOMC__) || defined(__TICCSC__) 745 | /* double_to_uint64 defined only for MSVC and UNIX */ 746 | # else 747 | # define double_to_uint64(d) ( ((d) >= 18446744073709551616.0) ? \ 748 | (unsigned long long) 0xffffffffffffffffULL : \ 749 | ((d) >= 0) ? (unsigned long long)(d) : (unsigned long long) 0 ) 750 | # endif 751 | #endif 752 | 753 | #if !defined(__cplusplus) && !defined(__bool_true_false_are_defined) 754 | 755 | #ifndef _bool_T 756 | #define _bool_T 757 | 758 | typedef boolean_T bool; 759 | 760 | #ifndef false 761 | #define false (0) 762 | #endif 763 | #ifndef true 764 | #define true (1) 765 | #endif 766 | 767 | #endif /* _bool_T */ 768 | 769 | #endif /* !__cplusplus */ 770 | 771 | /* 772 | * This software assumes that the code is being compiled on a target using a 773 | * 2's complement representation for signed integer values. 774 | */ 775 | #if ((SCHAR_MIN + 1) != -SCHAR_MAX) 776 | #error "This code must be compiled using a 2's complement representation for signed integer values" 777 | #endif 778 | 779 | /* 780 | * Maximum length of a MATLAB identifier (function/variable/model) 781 | * including the null-termination character. 782 | */ 783 | #define TMW_NAME_LENGTH_MAX 64 784 | 785 | /* 786 | * Maximum values for indices and dimensions 787 | */ 788 | #include 789 | 790 | #ifdef MX_COMPAT_32 791 | typedef int mwSize; 792 | typedef int mwIndex; 793 | typedef int mwSignedIndex; 794 | #else 795 | typedef size_t mwSize; /* unsigned pointer-width integer */ 796 | typedef size_t mwIndex; /* unsigned pointer-width integer */ 797 | typedef ptrdiff_t mwSignedIndex; /* a signed pointer-width integer */ 798 | #endif 799 | 800 | #if (defined(_LP64) || defined(_WIN64)) && !defined(MX_COMPAT_32) 801 | /* Currently 2^48 based on hardware limitations */ 802 | # define MWSIZE_MAX 281474976710655UL 803 | # define MWINDEX_MAX 281474976710655UL 804 | # define MWSINDEX_MAX 281474976710655L 805 | # define MWSINDEX_MIN -281474976710655L 806 | #else 807 | # define MWSIZE_MAX 2147483647UL 808 | # define MWINDEX_MAX 2147483647UL 809 | # define MWSINDEX_MAX 2147483647L 810 | # define MWSINDEX_MIN -2147483647L 811 | #endif 812 | #define MWSIZE_MIN 0UL 813 | #define MWINDEX_MIN 0UL 814 | 815 | /** UTF-16 character type */ 816 | 817 | #if (defined(__cplusplus) && (__cplusplus >= 201103L)) || (defined(_HAS_CHAR16_T_LANGUAGE_SUPPORT) && _HAS_CHAR16_T_LANGUAGE_SUPPORT) 818 | typedef char16_t CHAR16_T; 819 | #define U16_STRING_LITERAL_PREFIX u 820 | #elif defined(_MSC_VER) 821 | typedef wchar_t CHAR16_T; 822 | #define U16_STRING_LITERAL_PREFIX L 823 | #else 824 | typedef UINT16_T CHAR16_T; 825 | #endif 826 | 827 | #endif /* __TMWTYPES__ */ 828 | 829 | #endif /* tmwtypes_h */ 830 | --------------------------------------------------------------------------------