├── .github └── workflows │ └── add_issue_to_project.yml ├── LICENSE.md ├── README.md ├── examples ├── Example_01_Volume │ └── Example_01_Volume.ino ├── Example_02_INPUT2 │ └── Example_02_INPUT2.ino ├── Example_03_INPUT1 │ └── Example_03_INPUT1.ino ├── Example_04_Speaker │ └── Example_04_Speaker.ino ├── Example_05_Loopback │ └── Example_05_Loopback.ino ├── Example_06_3D_Enhance │ └── Example_06_3D_Enhance.ino ├── Example_07_MicBias │ └── Example_07_MicBias.ino ├── Example_08_I2S_Passthrough │ └── Example_08_I2S_Passthrough.ino ├── Example_09_I2S_Bluetooth │ └── Example_09_I2S_Bluetooth.ino ├── Example_10_AdcGain │ └── Example_10_AdcGain.ino ├── Example_11_VolumePlotter │ └── Example_11_VolumePlotter.ino ├── Example_12_AutomaticLevelControl │ └── Example_12_AutomaticLevelControl.ino ├── Example_13_DacGain │ └── Example_13_DacGain.ino ├── Example_14_ElectretMics │ └── Example_14_ElectretMics.ino ├── Example_15_VolumePlotter_MEMS_Mic_Differential │ └── Example_15_VolumePlotter_MEMS_Mic_Differential.ino └── Example_16_JackDetect │ └── Example_16_JackDetect.ino ├── keywords.txt ├── library.properties └── src ├── SparkFun_WM8960_Arduino_Library.cpp └── SparkFun_WM8960_Arduino_Library.h /.github/workflows/add_issue_to_project.yml: -------------------------------------------------------------------------------- 1 | name: Add new issue to our main project 2 | 3 | on: 4 | issues: 5 | types: 6 | - opened 7 | 8 | jobs: 9 | add-to-project: 10 | name: Add issue to project 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/add-to-project@main 14 | with: 15 | # You can target a project in a different organization 16 | # to the issue 17 | project-url: https://github.com/orgs/sparkfun/projects/19 18 | github-token: ${{ secrets.DEFECT_ADD_TO_PROJECT }} 19 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | SparkFun License Information 2 | ============================ 3 | 4 | SparkFun uses two different licenses for our files — one for hardware and one for code. 5 | 6 | Hardware 7 | --------- 8 | 9 | **SparkFun hardware is released under [Creative Commons Share-alike 4.0 International](http://creativecommons.org/licenses/by-sa/4.0/).** 10 | 11 | Note: This is a human-readable summary of (and not a substitute for) the [license](http://creativecommons.org/licenses/by-sa/4.0/legalcode). 12 | 13 | You are free to: 14 | 15 | Share — copy and redistribute the material in any medium or format 16 | Adapt — remix, transform, and build upon the material 17 | for any purpose, even commercially. 18 | The licensor cannot revoke these freedoms as long as you follow the license terms. 19 | Under the following terms: 20 | 21 | Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use. 22 | ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original. 23 | No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits. 24 | Notices: 25 | 26 | You do not have to comply with the license for elements of the material in the public domain or where your use is permitted by an applicable exception or limitation. 27 | No warranties are given. The license may not give you all of the permissions necessary for your intended use. For example, other rights such as publicity, privacy, or moral rights may limit how you use the material. 28 | 29 | 30 | Code 31 | -------- 32 | 33 | **SparkFun code, firmware, and software is released under the MIT License(http://opensource.org/licenses/MIT).** 34 | 35 | The MIT License (MIT) 36 | 37 | Copyright (c) 2016 SparkFun Electronics 38 | 39 | Permission is hereby granted, free of charge, to any person obtaining a copy 40 | of this software and associated documentation files (the "Software"), to deal 41 | in the Software without restriction, including without limitation the rights 42 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 43 | copies of the Software, and to permit persons to whom the Software is 44 | furnished to do so, subject to the following conditions: 45 | 46 | The above copyright notice and this permission notice shall be included in all 47 | copies or substantial portions of the Software. 48 | 49 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 50 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 51 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 52 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 53 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 54 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 55 | SOFTWARE. 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SparkFun WM8960 Arduino Library 2 | ======================================== 3 | 4 | [![SparkFun Audio Codec Breakout - WM8960](https://cdn.sparkfun.com/assets/parts/2/1/0/1/0/21250-_BOB_SparkFun_Audio_Codec_Breakout-_01.jpg)](https://www.sparkfun.com/products/21250) 5 | 6 | [*SparkFun Audio Codec Breakout - WM8960 (BOB-21250)*](https://www.sparkfun.com/products/21250) 7 | 8 | I2C control of WM8960 Stereo Codec with 1W Class-D Speaker Drivers and Headphone Drivers by Wolfson Microelectronics 9 | 10 | 11 | 12 | Repository Contents 13 | ------------------- 14 | 15 | * **/examples** - Example sketches for the library (.ino). Run these from the Arduino IDE. 16 | * **/extras** - Additional documentation for the user. These files are ignored by the IDE. 17 | * **/src** - Source files for the library (.cpp, .h). 18 | * **keywords.txt** - Keywords from this library that will be highlighted in the Arduino IDE. 19 | * **library.properties** - General library properties for the Arduino package manager. 20 | 21 | 22 | 23 | Documentation 24 | -------------- 25 | 26 | * **[Installing an Arduino Library Guide](https://learn.sparkfun.com/tutorials/installing-an-arduino-library)** - Basic information on how to install an Arduino library. 27 | * **[Product Repository](https://github.com/sparkfun/SparkFun_Audio_Codec_Breakout_WM8960)** - Main repository (including hardware files) for the Stereo Audio Codec Breakout - WM8960. 28 | * **[Hookup Guide](https://learn.sparkfun.com/tutorials/2761)** - Basic hookup guide for the Stereo Audio Codec Breakout - WM8960. 29 | 30 | 31 | 32 | Products that use this Library 33 | -------------- 34 | 35 | * [BOB-21250](https://www.sparkfun.com/products/21250) - Initial Release 36 | 37 | 38 | 39 | Version History 40 | --------------- 41 | * v1.0 - Initial Release 42 | 43 | 44 | 45 | License Information 46 | ------------------- 47 | 48 | This product is _**open source**_! 49 | 50 | Please review the LICENSE.md file for license information. 51 | 52 | If you have any questions or concerns on licensing, please contact technical support on our [SparkFun forums](https://forum.sparkfun.com/viewforum.php?f=152). 53 | 54 | Distributed as-is; no warranty is given. 55 | 56 | - Your friends at SparkFun. 57 | 58 | __ 59 | 60 | -------------------------------------------------------------------------------- /examples/Example_01_Volume/Example_01_Volume.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Example_01_Volume.ino 3 | Demonstrates analog audio input, volume control, and headphone output on the 4 | WM8960 Codec. 5 | 6 | Audio should be connected to both the left and right "INPUT3" inputs, 7 | they are labeled "RIN3" and "LIN3" on the board. 8 | 9 | This example will pass your audio source through the mixers and gain stages 10 | of the codec using all of the analog bypass paths. 11 | 12 | It will output the sound on the headphone outputs. 13 | It is setup to do a capless headphone setup, so connect your headphones ground 14 | to "OUT3"vand this provides a buffered VMID. 15 | 16 | You can now control the volume of the codecs built in headphone buffers using 17 | this function: 18 | 19 | codec.setHeadphoneVolumeDB(6.00); Valid inputs are -74.00 (MUTE) up to +6.00, 20 | (1.00dB steps). 21 | 22 | Development platform used: 23 | SparkFun ESP32 IoT RedBoard v10 24 | 25 | HARDWARE CONNECTIONS 26 | 27 | ********************** 28 | ESP32 ------- CODEC 29 | ********************** 30 | QWIIC ------- QWIIC *Note this connects GND/3.3V/SDA/SCL 31 | GND --------- GND *optional, but not a bad idea 32 | 5V ---------- VIN *needed to power codec's onboard AVDD (3.3V vreg) 33 | 34 | ********************** 35 | CODEC ------- AUDIO IN 36 | ********************** 37 | GND --------- TRS INPUT SLEEVE *ground for line level input 38 | LINPUT3 ----- TRS INPUT TIP *left audio 39 | RINPUT3 ----- TRS INPUT RING1 *right audio 40 | 41 | ********************** 42 | CODEC -------- AUDIO OUT 43 | ********************** 44 | OUT3 --------- TRS OUTPUT SLEEVE *buffered "vmid" (aka "HP GND") 45 | HPL ---------- TRS OUTPUT TIP *left HP output 46 | HPR ---------- TRS OUTPUT RING1 *right HP output 47 | 48 | Pete Lewis @ SparkFun Electronics 49 | October 14th, 2022 50 | https://github.com/sparkfun/SparkFun_WM8960_Arduino_Library 51 | 52 | This code was created using some code by Mike Grusin at SparkFun Electronics 53 | Included with the LilyPad MP3 example code found here: 54 | Revision history: version 1.0 2012/07/24 MDG Initial release 55 | https://github.com/sparkfun/LilyPad_MP3_Player 56 | 57 | Do you like this library? Help support SparkFun. Buy a board! 58 | 59 | SparkFun Audio Codec Breakout - WM8960 (QWIIC) 60 | https://www.sparkfun.com/products/21250 61 | 62 | All functions return 1 if the read/write was successful, and 0 63 | if there was a communications failure. You can ignore the return value 64 | if you just don't care anymore. 65 | 66 | For information on the data sent to and received from the CODEC, 67 | refer to the WM8960 datasheet at: 68 | https://github.com/sparkfun/SparkFun_Audio_Codec_Breakout_WM8960/blob/main/Documents/WM8960_datasheet_v4.2.pdf 69 | 70 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 71 | Please review the LICENSE.md file included with this example. If you have any questions 72 | or concerns with licensing, please contact techsupport@sparkfun.com. 73 | Distributed as-is; no warranty is given. 74 | ******************************************************************************/ 75 | 76 | #include 77 | #include 78 | // Click here to get the library: http://librarymanager/All#SparkFun_WM8960 79 | WM8960 codec; 80 | 81 | void setup() 82 | { 83 | Serial.begin(115200); 84 | Serial.println("Example 1 - Volume"); 85 | 86 | Wire.begin(); 87 | 88 | if (codec.begin() == false) //Begin communication over I2C 89 | { 90 | Serial.println("The device did not respond. Please check wiring."); 91 | while (1); // Freeze 92 | } 93 | Serial.println("Device is connected properly."); 94 | 95 | // General setup needed 96 | codec.enableVREF(); 97 | codec.enableVMID(); 98 | 99 | // Setup signal flow through the analog audio bypass connections 100 | 101 | // Enable left output mixer 102 | codec.enableLOMIX(); 103 | 104 | // Enable bypass connection from Left INPUT3 to Left output mixer, note, the 105 | // default gain on this input (LI2LOVOL) is -15dB 106 | codec.enableLI2LO(); 107 | 108 | // Sets volume control between "left input" to "left output mixer" 109 | codec.setLI2LOVOL(WM8960_OUTPUT_MIXER_GAIN_0DB); 110 | 111 | codec.enableROMIX(); // Now for the right channel of INPUT3 112 | codec.enableRI2RO(); 113 | codec.setRI2ROVOL(WM8960_OUTPUT_MIXER_GAIN_0DB); 114 | 115 | codec.enableHeadphones(); 116 | codec.enableOUT3MIX(); // Provides VMID as buffer for headphone ground 117 | 118 | Serial.println("Volume set to +6.00dB (max)"); 119 | codec.setHeadphoneVolumeDB(6.00); 120 | delay(5000); 121 | 122 | Serial.println("Volume set to +0.00dB"); 123 | codec.setHeadphoneVolumeDB(0.00); 124 | delay(5000); 125 | 126 | Serial.println("Volume set to -12.00dB"); 127 | codec.setHeadphoneVolumeDB(-12.00); 128 | delay(5000); 129 | 130 | Serial.println("Volume set to -74.00dB, aka MUTE"); 131 | codec.setHeadphoneVolumeDB(-74.00); 132 | delay(5000); 133 | 134 | Serial.println("Example complete. Hit Reset to try again."); 135 | } 136 | 137 | void loop() 138 | { 139 | // Nothing to see here. 140 | } 141 | -------------------------------------------------------------------------------- /examples/Example_02_INPUT2/Example_02_INPUT2.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Example_02_INPUT2.ino 3 | Demonstrates analog audio input (on INPUT2s), sets volume control, and 4 | headphone output on the WM8960 Codec. 5 | 6 | Audio should be connected to both the left and right "INPUT2" inputs, 7 | they are labeled "RIN2" and "LIN2" on the board. 8 | 9 | This example will pass your audio source through the mixers and gain stages of 10 | the codec using all of the analog bypass paths. 11 | 12 | It will output the sound on the headphone outputs. 13 | It is setup to do a capless headphone setup, so connect your headphones ground 14 | to "OUT3" and this provides a buffered VMID. 15 | 16 | You can now control the volume of the codecs built in headphone buffers using 17 | this function: 18 | 19 | codec.setHeadphoneVolumeDB(6.00); Valid inputs are -74.00 (MUTE) up to +6.00, 20 | (1.00dB steps). 21 | 22 | Development platform used: 23 | SparkFun ESP32 IoT RedBoard v10 24 | 25 | HARDWARE CONNECTIONS 26 | 27 | ********************** 28 | ESP32 ------- CODEC 29 | ********************** 30 | QWIIC ------- QWIIC *Note this connects GND/3.3V/SDA/SCL 31 | GND --------- GND *optional, but not a bad idea 32 | 5V ---------- VIN *needed to power codec's onboard AVDD (3.3V vreg) 33 | 34 | ********************** 35 | CODEC ------- AUDIO IN 36 | ********************** 37 | GND --------- TRS INPUT SLEEVE *ground for line level input 38 | LINPUT2 ----- TRS INPUT TIP *left audio 39 | RINPUT2 ----- TRS INPUT RING1 *right audio 40 | 41 | ********************** 42 | CODEC -------- AUDIO OUT 43 | ********************** 44 | OUT3 --------- TRS OUTPUT SLEEVE *buffered "vmid" (aka "HP GND") 45 | HPL ---------- TRS OUTPUT TIP *left HP output 46 | HPR ---------- TRS OUTPUT RING1 *right HP output 47 | 48 | Pete Lewis @ SparkFun Electronics 49 | October 14th, 2022 50 | https://github.com/sparkfun/SparkFun_WM8960_Arduino_Library 51 | 52 | This code was created using some code by Mike Grusin at SparkFun Electronics 53 | Included with the LilyPad MP3 example code found here: 54 | Revision history: version 1.0 2012/07/24 MDG Initial release 55 | https://github.com/sparkfun/LilyPad_MP3_Player 56 | 57 | Do you like this library? Help support SparkFun. Buy a board! 58 | 59 | SparkFun Audio Codec Breakout - WM8960 (QWIIC) 60 | https://www.sparkfun.com/products/21250 61 | 62 | All functions return 1 if the read/write was successful, and 0 63 | if there was a communications failure. You can ignore the return value 64 | if you just don't care anymore. 65 | 66 | For information on the data sent to and received from the CODEC, 67 | refer to the WM8960 datasheet at: 68 | https://github.com/sparkfun/SparkFun_Audio_Codec_Breakout_WM8960/blob/main/Documents/WM8960_datasheet_v4.2.pdf 69 | 70 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 71 | Please review the LICENSE.md file included with this example. If you have any questions 72 | or concerns with licensing, please contact techsupport@sparkfun.com. 73 | Distributed as-is; no warranty is given. 74 | ******************************************************************************/ 75 | 76 | #include 77 | #include 78 | // Click here to get the library: http://librarymanager/All#SparkFun_WM8960 79 | WM8960 codec; 80 | 81 | void setup() 82 | { 83 | Serial.begin(115200); 84 | Serial.println("Example 2 - INPUT2"); 85 | 86 | Wire.begin(); 87 | 88 | if (codec.begin() == false) //Begin communication over I2C 89 | { 90 | Serial.println("The device did not respond. Please check wiring."); 91 | while (1); // Freeze 92 | } 93 | Serial.println("Device is connected properly."); 94 | 95 | // General setup needed 96 | codec.enableVREF(); 97 | codec.enableVMID(); 98 | 99 | // Setup signal flow through the analog audio bypass connections 100 | 101 | // Set input boosts to get INPUT2 (both left and right) to the boost mixers 102 | codec.setLIN2BOOST(WM8960_BOOST_MIXER_GAIN_0DB); 103 | codec.setRIN2BOOST(WM8960_BOOST_MIXER_GAIN_0DB); 104 | 105 | // Enable input boost mixers 106 | codec.enableAINL(); 107 | codec.enableAINR(); 108 | 109 | // Connect LB2LO (booster to output mixer [aka analog bypass]) 110 | codec.enableLB2LO(); 111 | codec.enableRB2RO(); 112 | 113 | // Set gainstage between boost mixer and output mixers (analog bypass) 114 | codec.setLB2LOVOL(WM8960_OUTPUT_MIXER_GAIN_0DB); 115 | codec.setRB2ROVOL(WM8960_OUTPUT_MIXER_GAIN_0DB); 116 | 117 | // Enable output mixers 118 | codec.enableLOMIX(); 119 | codec.enableROMIX(); 120 | 121 | codec.enableHeadphones(); 122 | codec.enableOUT3MIX(); // Provides VMID as buffer for headphone ground 123 | 124 | Serial.println("Volume set to +0dB"); 125 | codec.setHeadphoneVolumeDB(0.00); 126 | 127 | Serial.println("Example complete. Listen to inputs 2 on headphone outputs."); 128 | } 129 | 130 | void loop() 131 | { 132 | // Nothing to see here. 133 | } 134 | -------------------------------------------------------------------------------- /examples/Example_03_INPUT1/Example_03_INPUT1.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Example_03_INPUT1.ino 3 | Demonstrates analog audio input (on INPUT1s), sets volume control, and 4 | headphone output on the WM8960 Codec. 5 | 6 | Audio should be connected to both the left and right "INPUT1" inputs, 7 | they are labeled "RIN1" and "LIN1" on the board. 8 | 9 | This example will pass your audio source through the mixers and gain stages of 10 | the codec using all of the analog bypass paths. 11 | 12 | It will output the sound on the headphone outputs. 13 | It is setup to do a capless headphone setup, so connect your headphones ground 14 | to "OUT3" and this provides a buffered VMID. 15 | 16 | You can now control the volume of the codecs built in headphone buffers using 17 | this function: 18 | 19 | codec.setHeadphoneVolumeDB(6.00); Valid inputs are -74.00 (MUTE) up to +6.00, 20 | (1.00dB steps). 21 | 22 | Development platform used: 23 | SparkFun ESP32 IoT RedBoard v10 24 | 25 | HARDWARE CONNECTIONS 26 | 27 | ********************** 28 | ESP32 ------- CODEC 29 | ********************** 30 | QWIIC ------- QWIIC *Note this connects GND/3.3V/SDA/SCL 31 | GND --------- GND *optional, but not a bad idea 32 | 5V ---------- VIN *needed to power codec's onboard AVDD (3.3V vreg) 33 | 34 | ********************** 35 | CODEC ------- AUDIO IN 36 | ********************** 37 | GND --------- TRS INPUT SLEEVE *ground for line level input 38 | LINPUT1 ----- TRS INPUT TIP *left audio 39 | RINPUT1 ----- TRS INPUT RING1 *right audio 40 | 41 | ********************** 42 | CODEC -------- AUDIO OUT 43 | ********************** 44 | OUT3 --------- TRS OUTPUT SLEEVE *buffered "vmid" (aka "HP GND") 45 | HPL ---------- TRS OUTPUT TIP *left HP output 46 | HPR ---------- TRS OUTPUT RING1 *right HP output 47 | 48 | Pete Lewis @ SparkFun Electronics 49 | October 14th, 2022 50 | https://github.com/sparkfun/SparkFun_WM8960_Arduino_Library 51 | 52 | This code was created using some code by Mike Grusin at SparkFun Electronics 53 | Included with the LilyPad MP3 example code found here: 54 | Revision history: version 1.0 2012/07/24 MDG Initial release 55 | https://github.com/sparkfun/LilyPad_MP3_Player 56 | 57 | Do you like this library? Help support SparkFun. Buy a board! 58 | 59 | SparkFun Audio Codec Breakout - WM8960 (QWIIC) 60 | https://www.sparkfun.com/products/21250 61 | 62 | All functions return 1 if the read/write was successful, and 0 63 | if there was a communications failure. You can ignore the return value 64 | if you just don't care anymore. 65 | 66 | For information on the data sent to and received from the CODEC, 67 | refer to the WM8960 datasheet at: 68 | https://github.com/sparkfun/SparkFun_Audio_Codec_Breakout_WM8960/blob/main/Documents/WM8960_datasheet_v4.2.pdf 69 | 70 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 71 | Please review the LICENSE.md file included with this example. If you have any questions 72 | or concerns with licensing, please contact techsupport@sparkfun.com. 73 | Distributed as-is; no warranty is given. 74 | ******************************************************************************/ 75 | 76 | #include 77 | #include 78 | // Click here to get the library: http://librarymanager/All#SparkFun_WM8960 79 | WM8960 codec; 80 | 81 | void setup() 82 | { 83 | Serial.begin(115200); 84 | Serial.println("Example 3 - INPUT1"); 85 | 86 | Wire.begin(); 87 | 88 | if (codec.begin() == false) //Begin communication over I2C 89 | { 90 | Serial.println("The device did not respond. Please check wiring."); 91 | while (1); // Freeze 92 | } 93 | Serial.println("Device is connected properly."); 94 | 95 | // General setup needed 96 | codec.enableVREF(); 97 | codec.enableVMID(); 98 | 99 | // Setup signal flow through the analog audio bypass connections 100 | 101 | codec.enableLMIC(); 102 | codec.enableRMIC(); 103 | 104 | // Connect from INPUT1 to "n" (aka inverting) inputs of PGAs. 105 | codec.connectLMN1(); 106 | codec.connectRMN1(); 107 | 108 | // Disable mutes on PGA inputs (aka INTPUT1) 109 | codec.disableLINMUTE(); 110 | codec.disableRINMUTE(); 111 | 112 | // Set input boosts to get inputs 1 to the boost mixers 113 | codec.setLMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 114 | codec.setRMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 115 | 116 | codec.connectLMIC2B(); 117 | codec.connectRMIC2B(); 118 | 119 | // Enable boost mixers 120 | codec.enableAINL(); 121 | codec.enableAINR(); 122 | 123 | // Connect LB2LO (booster to output mixer (analog bypass) 124 | codec.enableLB2LO(); 125 | codec.enableRB2RO(); 126 | 127 | // Set gainstage between booster mixer and output mixer 128 | codec.setLB2LOVOL(WM8960_OUTPUT_MIXER_GAIN_0DB); 129 | codec.setRB2ROVOL(WM8960_OUTPUT_MIXER_GAIN_0DB); 130 | 131 | // Enable output mixers 132 | codec.enableLOMIX(); 133 | codec.enableROMIX(); 134 | 135 | codec.enableHeadphones(); 136 | codec.enableOUT3MIX(); // Provides VMID as buffer for headphone ground 137 | 138 | Serial.println("Volume set to +0dB"); 139 | codec.setHeadphoneVolumeDB(0.00); 140 | 141 | Serial.println("Example complete. Listen to INPUT1 on headphone outputs."); 142 | } 143 | 144 | void loop() 145 | { 146 | // Nothing to see here. 147 | } 148 | -------------------------------------------------------------------------------- /examples/Example_04_Speaker/Example_04_Speaker.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Example_04_Speaker.ino 3 | Demonstrates analog audio input (on INPUT1s), sets volume control, and Speaker 4 | output on the WM8960 Codec. 5 | 6 | Audio should be connected to both the left and right "INPUT1" inputs, 7 | they are labeled "RIN1" and "LIN1" on the board. 8 | 9 | This example will pass your audio source through the mixers and gain stages of 10 | the codec using all of the analog bypass paths. 11 | 12 | It will output the sound on the Speaker outputs. 13 | 14 | You can now control the volume of the codecs built in class-d amp using this 15 | function: 16 | 17 | codec.setSpeakerVolumeDB(6.00); Valid inputs are -73.00 to 6.00 (1.00 dB steps) 18 | 19 | Development platform used: 20 | SparkFun ESP32 IoT RedBoard v10 21 | 22 | HARDWARE CONNECTIONS 23 | 24 | ********************** 25 | ESP32 ------- CODEC 26 | ********************** 27 | QWIIC ------- QWIIC *Note this connects GND/3.3V/SDA/SCL 28 | GND --------- GND *optional, but not a bad idea 29 | 5V ---------- VIN *needed to power codec's onboard AVDD (3.3V vreg) 30 | 31 | ********************** 32 | CODEC ------- AUDIO IN 33 | ********************** 34 | GND --------- TRS INPUT SLEEVE *ground for line level input 35 | LINPUT1 ----- TRS INPUT TIP *left audio 36 | RINPUT1 ----- TRS INPUT RING1 *right audio 37 | 38 | ********************** 39 | CODEC -------- AUDIO OUT 40 | ********************** 41 | SL+ --------- Left Speaker + 42 | SL- --------- Left Speaker - 43 | SR+ --------- Right Speaker + 44 | SR- --------- Right Speaker - 45 | 46 | *Note, with a class-d speaker amp like this, you need to connections like above. 47 | Each speaker must be connected to its correct + and -. 48 | You cannot connect the "-" side of the speaker to GND. 49 | You cannot share the "-" side of two speakers (like with common "TRS-wired" 50 | headphones). 51 | 52 | Pete Lewis @ SparkFun Electronics 53 | October 14th, 2022 54 | https://github.com/sparkfun/SparkFun_WM8960_Arduino_Library 55 | 56 | This code was created using some code by Mike Grusin at SparkFun Electronics 57 | Included with the LilyPad MP3 example code found here: 58 | Revision history: version 1.0 2012/07/24 MDG Initial release 59 | https://github.com/sparkfun/LilyPad_MP3_Player 60 | 61 | Do you like this library? Help support SparkFun. Buy a board! 62 | 63 | SparkFun Audio Codec Breakout - WM8960 (QWIIC) 64 | https://www.sparkfun.com/products/21250 65 | 66 | All functions return 1 if the read/write was successful, and 0 67 | if there was a communications failure. You can ignore the return value 68 | if you just don't care anymore. 69 | 70 | For information on the data sent to and received from the CODEC, 71 | refer to the WM8960 datasheet at: 72 | https://github.com/sparkfun/SparkFun_Audio_Codec_Breakout_WM8960/blob/main/Documents/WM8960_datasheet_v4.2.pdf 73 | 74 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 75 | Please review the LICENSE.md file included with this example. If you have any questions 76 | or concerns with licensing, please contact techsupport@sparkfun.com. 77 | Distributed as-is; no warranty is given. 78 | ******************************************************************************/ 79 | 80 | #include 81 | #include 82 | // Click here to get the library: http://librarymanager/All#SparkFun_WM8960 83 | WM8960 codec; 84 | 85 | void setup() 86 | { 87 | Serial.begin(115200); 88 | Serial.println("Example 4 - Speaker"); 89 | 90 | Wire.begin(); 91 | 92 | if (codec.begin() == false) //Begin communication over I2C 93 | { 94 | Serial.println("The device did not respond. Please check wiring."); 95 | while (1); // Freeze 96 | } 97 | Serial.println("Device is connected properly."); 98 | 99 | // General setup needed 100 | codec.enableVREF(); 101 | codec.enableVMID(); 102 | 103 | // Setup signal flow through the analog audio bypass connections 104 | 105 | codec.enableLMIC(); 106 | codec.enableRMIC(); 107 | 108 | // Connect from INPUT1 to "n" (aka inverting) inputs of PGAs. 109 | codec.connectLMN1(); 110 | codec.connectRMN1(); 111 | 112 | // Disable mutes on PGA inputs (aka INTPUT1) 113 | codec.disableLINMUTE(); 114 | codec.disableRINMUTE(); 115 | 116 | // Set input boosts to get inputs 1 to the boost mixers 117 | codec.setLMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 118 | codec.setRMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 119 | 120 | codec.connectLMIC2B(); 121 | codec.connectRMIC2B(); 122 | 123 | // Enable boost mixers 124 | codec.enableAINL(); 125 | codec.enableAINR(); 126 | 127 | // Connect LB2LO (booster to output mixer (analog bypass) 128 | codec.enableLB2LO(); 129 | codec.enableRB2RO(); 130 | 131 | // Set gainstage between booster mixer and output mixer 132 | codec.setLB2LOVOL(WM8960_OUTPUT_MIXER_GAIN_0DB); 133 | codec.setRB2ROVOL(WM8960_OUTPUT_MIXER_GAIN_0DB); 134 | 135 | // Enable output mixers 136 | codec.enableLOMIX(); 137 | codec.enableROMIX(); 138 | 139 | // CLOCK STUFF, These settings will get you 44.1KHz sample rate, and class-d 140 | // freq at 705.6kHz 141 | codec.enablePLL(); // Needed for class-d amp clock 142 | codec.setPLLPRESCALE(WM8960_PLLPRESCALE_DIV_2); 143 | codec.setSMD(WM8960_PLL_MODE_FRACTIONAL); 144 | codec.setCLKSEL(WM8960_CLKSEL_PLL); 145 | codec.setSYSCLKDIV(WM8960_SYSCLK_DIV_BY_2); 146 | codec.setDCLKDIV(WM8960_DCLKDIV_16); 147 | codec.setPLLN(7); 148 | codec.setPLLK(0x86, 0xC2, 0x26); // PLLK=86C226h 149 | 150 | codec.enableSpeakers(); 151 | 152 | Serial.println("Volume set to +0dB"); 153 | codec.setSpeakerVolumeDB(0.00); 154 | 155 | Serial.println("Example complete. Listen to left/right INPUT1 on Speaker outputs."); 156 | } 157 | 158 | void loop() 159 | { 160 | // Nothing to see here. 161 | } -------------------------------------------------------------------------------- /examples/Example_05_Loopback/Example_05_Loopback.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Example_05_Loopback.ino 3 | Demonstrates analog audio input (on INPUT1s), ADC/DAC Loopback, sets volume 4 | control, and Headphone output on the WM8960 Codec. 5 | 6 | Audio should be connected to both the left and right "INPUT1" inputs, 7 | they are labeled "RIN1" and "LIN1" on the board. 8 | 9 | This example will pass your audio source through the mixers and gain stages of 10 | the codec into the ADC. Turn on Loopback (so ADC is feed directly to DAC). 11 | Then send the output of the DAC to the headphone outs. 12 | 13 | You can now control the volume of the codecs built in headphone amp using this 14 | function: 15 | 16 | codec.setHeadphoneVolumeDB(6.00); Valid inputs are -74.00 (MUTE) up to +6.00, 17 | (1.00dB steps). 18 | 19 | Development platform used: 20 | SparkFun ESP32 IoT RedBoard v10 21 | 22 | HARDWARE CONNECTIONS 23 | 24 | ********************** 25 | ESP32 ------- CODEC 26 | ********************** 27 | QWIIC ------- QWIIC *Note this connects GND/3.3V/SDA/SCL 28 | GND --------- GND *optional, but not a bad idea 29 | 5V ---------- VIN *needed to power codec's onboard AVDD (3.3V vreg) 30 | 31 | ********************** 32 | CODEC ------- AUDIO IN 33 | ********************** 34 | GND --------- TRS INPUT SLEEVE *ground for line level input 35 | LINPUT1 ----- TRS INPUT TIP *left audio 36 | RINPUT1 ----- TRS INPUT RING1 *right audio 37 | 38 | ********************** 39 | CODEC -------- AUDIO OUT 40 | ********************** 41 | OUT3 --------- TRS OUTPUT SLEEVE *buffered "vmid" (aka "HP GND") 42 | HPL ---------- TRS OUTPUT TIP *left HP output 43 | HPR ---------- TRS OUTPUT RING1 *right HP output 44 | 45 | Pete Lewis @ SparkFun Electronics 46 | October 14th, 2022 47 | https://github.com/sparkfun/SparkFun_WM8960_Arduino_Library 48 | 49 | This code was created using some code by Mike Grusin at SparkFun Electronics 50 | Included with the LilyPad MP3 example code found here: 51 | Revision history: version 1.0 2012/07/24 MDG Initial release 52 | https://github.com/sparkfun/LilyPad_MP3_Player 53 | 54 | Do you like this library? Help support SparkFun. Buy a board! 55 | 56 | SparkFun Audio Codec Breakout - WM8960 (QWIIC) 57 | https://www.sparkfun.com/products/21250 58 | 59 | All functions return 1 if the read/write was successful, and 0 60 | if there was a communications failure. You can ignore the return value 61 | if you just don't care anymore. 62 | 63 | For information on the data sent to and received from the CODEC, 64 | refer to the WM8960 datasheet at: 65 | https://github.com/sparkfun/SparkFun_Audio_Codec_Breakout_WM8960/blob/main/Documents/WM8960_datasheet_v4.2.pdf 66 | 67 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 68 | Please review the LICENSE.md file included with this example. If you have any questions 69 | or concerns with licensing, please contact techsupport@sparkfun.com. 70 | Distributed as-is; no warranty is given. 71 | ******************************************************************************/ 72 | 73 | #include 74 | #include 75 | // Click here to get the library: http://librarymanager/All#SparkFun_WM8960 76 | WM8960 codec; 77 | 78 | void setup() 79 | { 80 | Serial.begin(115200); 81 | Serial.println("Example 5 - Loopback"); 82 | 83 | Wire.begin(); 84 | 85 | if (codec.begin() == false) //Begin communication over I2C 86 | { 87 | Serial.println("The device did not respond. Please check wiring."); 88 | while (1); // Freeze 89 | } 90 | Serial.println("Device is connected properly."); 91 | 92 | // General setup needed 93 | codec.enableVREF(); 94 | codec.enableVMID(); 95 | 96 | // Setup signal flow to the ADC 97 | 98 | codec.enableLMIC(); 99 | codec.enableRMIC(); 100 | 101 | // Connect from INPUT1 to "n" (aka inverting) inputs of PGAs. 102 | codec.connectLMN1(); 103 | codec.connectRMN1(); 104 | 105 | // Disable mutes on PGA inputs (aka INTPUT1) 106 | codec.disableLINMUTE(); 107 | codec.disableRINMUTE(); 108 | 109 | // Set input boosts to get inputs 1 to the boost mixers 110 | codec.setLMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 111 | codec.setRMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 112 | 113 | codec.connectLMIC2B(); 114 | codec.connectRMIC2B(); 115 | 116 | // Enable boost mixers 117 | codec.enableAINL(); 118 | codec.enableAINR(); 119 | 120 | // Disconnect LB2LO (booster to output mixer (analog bypass) 121 | // For this example, we are going to pass audio throught the ADC and DAC 122 | codec.disableLB2LO(); 123 | codec.disableRB2RO(); 124 | 125 | // Connect from DAC outputs to output mixer 126 | codec.enableLD2LO(); 127 | codec.enableRD2RO(); 128 | 129 | // Set gainstage between booster mixer and output mixer 130 | // For this loopback example, we are going to keep these as low as they go 131 | codec.setLB2LOVOL(WM8960_OUTPUT_MIXER_GAIN_NEG_21DB); 132 | codec.setRB2ROVOL(WM8960_OUTPUT_MIXER_GAIN_NEG_21DB); 133 | 134 | // Enable output mixers 135 | codec.enableLOMIX(); 136 | codec.enableROMIX(); 137 | 138 | // CLOCK STUFF, These settings will get you 44.1KHz sample rate, and class-d 139 | // freq at 705.6kHz 140 | codec.enablePLL(); // Needed for class-d amp clock 141 | codec.setPLLPRESCALE(WM8960_PLLPRESCALE_DIV_2); 142 | codec.setSMD(WM8960_PLL_MODE_FRACTIONAL); 143 | codec.setCLKSEL(WM8960_CLKSEL_PLL); 144 | codec.setSYSCLKDIV(WM8960_SYSCLK_DIV_BY_2); 145 | codec.setBCLKDIV(4); 146 | codec.setDCLKDIV(WM8960_DCLKDIV_16); 147 | codec.setPLLN(7); 148 | codec.setPLLK(0x86, 0xC2, 0x26); // PLLK=86C226h 149 | //codec.setADCDIV(0); // Default is 000 (what we need for 44.1KHz) 150 | //codec.setDACDIV(0); // Default is 000 (what we need for 44.1KHz) 151 | 152 | codec.enableMasterMode(); 153 | codec.setALRCGPIO(); // Note, should not be changed while ADC is enabled. 154 | 155 | // Enable ADCs and DACs 156 | codec.enableAdcLeft(); 157 | codec.enableAdcRight(); 158 | codec.enableDacLeft(); 159 | codec.enableDacRight(); 160 | codec.disableDacMute(); 161 | 162 | codec.enableLoopBack(); // Loopback sends ADC data directly into DAC 163 | 164 | // Default is "soft mute" on, so we must disable mute to make channels active 165 | codec.disableDacMute(); 166 | 167 | codec.enableHeadphones(); 168 | codec.enableOUT3MIX(); // Provides VMID as buffer for headphone ground 169 | 170 | Serial.println("Volume set to +0dB"); 171 | codec.setHeadphoneVolumeDB(0.00); 172 | 173 | Serial.println("Example complete. Listen to left/right INPUT1 on Headphone outputs."); 174 | } 175 | 176 | void loop() 177 | { 178 | // Nothing to see here. 179 | } -------------------------------------------------------------------------------- /examples/Example_06_3D_Enhance/Example_06_3D_Enhance.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Example_06_3D_Enhance.ino 3 | Demonstrates 3D Enhance feature of WM8960 Codec. 4 | 5 | Toggles on/off 3D Enhance every 5 seconds, so you can hear the difference. 6 | 7 | Note, it also sets the 3D enhance Depth setting to 15 (max). 8 | You can change this to your desired depth from 0-15. 9 | 10 | Note, this is very similar to the Loopback example, but also demos the 3D 11 | Enhance feature. 12 | 13 | Sets up analog audio input (on INPUT1s), ADC/DAC Loopback, sets volume 14 | control, and Headphone output on the WM8960 Codec. 15 | 16 | Audio should be connected to both the left and right "INPUT1" inputs, 17 | they are labeled "RIN1" and "LIN1" on the board. 18 | 19 | This example will pass your audio source through the mixers and gain stages of 20 | the codec into the ADC. Turn on Loopback (so ADC is feed directly to DAC). 21 | Then send the output of the DAC to the headphone outs. 22 | 23 | You can now control the volume of the codecs built in headphone amp using this 24 | function: 25 | 26 | codec.setHeadphoneVolumeDB(6.00); Valid inputs are -74.00 (MUTE) up to +6.00, 27 | (1.00dB steps). 28 | 29 | Development platform used: 30 | SparkFun ESP32 IoT RedBoard v10 31 | 32 | HARDWARE CONNECTIONS 33 | 34 | ********************** 35 | ESP32 ------- CODEC 36 | ********************** 37 | QWIIC ------- QWIIC *Note this connects GND/3.3V/SDA/SCL 38 | GND --------- GND *optional, but not a bad idea 39 | 5V ---------- VIN *needed to power codec's onboard AVDD (3.3V vreg) 40 | 41 | ********************** 42 | CODEC ------- AUDIO IN 43 | ********************** 44 | GND --------- TRS INPUT SLEEVE *ground for line level input 45 | LINPUT1 ----- TRS INPUT TIP *left audio 46 | RINPUT1 ----- TRS INPUT RING1 *right audio 47 | 48 | ********************** 49 | CODEC -------- AUDIO OUT 50 | ********************** 51 | OUT3 --------- TRS OUTPUT SLEEVE *buffered "vmid" (aka "HP GND") 52 | HPL ---------- TRS OUTPUT TIP *left HP output 53 | HPR ---------- TRS OUTPUT RING1 *right HP output 54 | 55 | Pete Lewis @ SparkFun Electronics 56 | October 14th, 2022 57 | https://github.com/sparkfun/SparkFun_WM8960_Arduino_Library 58 | 59 | This code was created using some code by Mike Grusin at SparkFun Electronics 60 | Included with the LilyPad MP3 example code found here: 61 | Revision history: version 1.0 2012/07/24 MDG Initial release 62 | https://github.com/sparkfun/LilyPad_MP3_Player 63 | 64 | Do you like this library? Help support SparkFun. Buy a board! 65 | 66 | SparkFun Audio Codec Breakout - WM8960 (QWIIC) 67 | https://www.sparkfun.com/products/21250 68 | 69 | All functions return 1 if the read/write was successful, and 0 70 | if there was a communications failure. You can ignore the return value 71 | if you just don't care anymore. 72 | 73 | For information on the data sent to and received from the CODEC, 74 | refer to the WM8960 datasheet at: 75 | https://github.com/sparkfun/SparkFun_Audio_Codec_Breakout_WM8960/blob/main/Documents/WM8960_datasheet_v4.2.pdf 76 | 77 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 78 | Please review the LICENSE.md file included with this example. If you have any questions 79 | or concerns with licensing, please contact techsupport@sparkfun.com. 80 | Distributed as-is; no warranty is given. 81 | ******************************************************************************/ 82 | 83 | #include 84 | #include 85 | // Click here to get the library: http://librarymanager/All#SparkFun_WM8960 86 | WM8960 codec; 87 | 88 | void setup() 89 | { 90 | Serial.begin(115200); 91 | Serial.println("Example 6 - 3D Enhance"); 92 | 93 | Wire.begin(); 94 | 95 | if (codec.begin() == false) //Begin communication over I2C 96 | { 97 | Serial.println("The device did not respond. Please check wiring."); 98 | while (1); // Freeze 99 | } 100 | Serial.println("Device is connected properly."); 101 | 102 | // General setup needed 103 | codec.enableVREF(); 104 | codec.enableVMID(); 105 | 106 | // Setup signal flow to the ADC 107 | 108 | codec.enableLMIC(); 109 | codec.enableRMIC(); 110 | 111 | // Connect from INPUT1 to "n" (aka inverting) inputs of PGAs. 112 | codec.connectLMN1(); 113 | codec.connectRMN1(); 114 | 115 | // Disable mutes on PGA inputs (aka INTPUT1) 116 | codec.disableLINMUTE(); 117 | codec.disableRINMUTE(); 118 | 119 | // Set input boosts to get inputs 1 to the boost mixers 120 | codec.setLMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 121 | codec.setRMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 122 | 123 | codec.connectLMIC2B(); 124 | codec.connectRMIC2B(); 125 | 126 | // Enable boost mixers 127 | codec.enableAINL(); 128 | codec.enableAINR(); 129 | 130 | // Disconnect LB2LO (booster to output mixer (analog bypass) 131 | // For this example, we are going to pass audio throught the ADC and DAC 132 | codec.disableLB2LO(); 133 | codec.disableRB2RO(); 134 | 135 | // Connect from DAC outputs to output mixer 136 | codec.enableLD2LO(); 137 | codec.enableRD2RO(); 138 | 139 | // Set gainstage between booster mixer and output mixer 140 | // For this loopback example, we are going to keep these as low as they go 141 | codec.setLB2LOVOL(WM8960_OUTPUT_MIXER_GAIN_NEG_21DB); 142 | codec.setRB2ROVOL(WM8960_OUTPUT_MIXER_GAIN_NEG_21DB); 143 | 144 | // Enable output mixers 145 | codec.enableLOMIX(); 146 | codec.enableROMIX(); 147 | 148 | // CLOCK STUFF, These settings will get you 44.1KHz sample rate, and class-d 149 | // freq at 705.6kHz 150 | codec.enablePLL(); // Needed for class-d amp clock 151 | codec.setPLLPRESCALE(WM8960_PLLPRESCALE_DIV_2); 152 | codec.setSMD(WM8960_PLL_MODE_FRACTIONAL); 153 | codec.setCLKSEL(WM8960_CLKSEL_PLL); 154 | codec.setSYSCLKDIV(WM8960_SYSCLK_DIV_BY_2); 155 | codec.setBCLKDIV(4); 156 | codec.setDCLKDIV(WM8960_DCLKDIV_16); 157 | codec.setPLLN(7); 158 | codec.setPLLK(0x86, 0xC2, 0x26); // PLLK=86C226h 159 | //codec.setADCDIV(0); // Default is 000 (what we need for 44.1KHz) 160 | //codec.setDACDIV(0); // Default is 000 (what we need for 44.1KHz) 161 | 162 | codec.enableMasterMode(); 163 | codec.setALRCGPIO(); // Note, should not be changed while ADC is enabled. 164 | 165 | // Enable ADCs and DACs 166 | codec.enableAdcLeft(); 167 | codec.enableAdcRight(); 168 | codec.enableDacLeft(); 169 | codec.enableDacRight(); 170 | codec.disableDacMute(); 171 | 172 | codec.enableLoopBack(); // Loopback sends ADC data directly into DAC 173 | 174 | // Default is "soft mute" on, so we must disable mute to make channels active 175 | codec.disableDacMute(); 176 | 177 | codec.enableHeadphones(); 178 | codec.enableOUT3MIX(); // Provides VMID as buffer for headphone ground 179 | 180 | Serial.println("Volume set to +0dB"); 181 | codec.setHeadphoneVolumeDB(0.00); 182 | Serial.println("3D Enhance Depth set to 15 (max)"); 183 | codec.set3dDepth(15); 184 | 185 | Serial.println("Listen to left/right INPUT1 on Headphone outputs with toggling 3D enhance!"); 186 | } 187 | 188 | void loop() 189 | { 190 | codec.enable3d(); 191 | Serial.println("3D Enhance enabled"); 192 | delay(5000); 193 | 194 | codec.disable3d(); 195 | Serial.println("3D Enhance disabled"); 196 | delay(5000); 197 | } -------------------------------------------------------------------------------- /examples/Example_07_MicBias/Example_07_MicBias.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Example_07_MicBias.ino 3 | This example demonstrates control of the mic bias feature of WM8960 Codec. 4 | 5 | Electret Mics are powered with a mic bias voltage applied to their signal 6 | line - usually with a 2.2K resistor in series. This Codec can provide a clean 7 | mic bias. 8 | 9 | This example turns on the mic bias, set's it to each available output voltage, 10 | and then turns it off to demonstrate disable. 11 | 12 | Measure the voltage with a multimeter to verfy you are getting the correct 13 | voltages you desire on mic bias. 14 | 15 | You can later use this mic bias voltage to power an electret mic in a more 16 | advanced example (example 14). 17 | 18 | Development platform used: 19 | SparkFun ESP32 IoT RedBoard v10 20 | 21 | HARDWARE CONNECTIONS 22 | 23 | ********************** 24 | ESP32 ------- CODEC 25 | ********************** 26 | QWIIC ------- QWIIC *Note this connects GND/3.3V/SDA/SCL 27 | GND --------- GND *optional, but not a bad idea 28 | 5V ---------- VIN *needed to power codec's onboard AVDD (3.3V vreg) 29 | 30 | Pete Lewis @ SparkFun Electronics 31 | October 14th, 2022 32 | https://github.com/sparkfun/SparkFun_WM8960_Arduino_Library 33 | 34 | This code was created using some code by Mike Grusin at SparkFun Electronics 35 | Included with the LilyPad MP3 example code found here: 36 | Revision history: version 1.0 2012/07/24 MDG Initial release 37 | https://github.com/sparkfun/LilyPad_MP3_Player 38 | 39 | Do you like this library? Help support SparkFun. Buy a board! 40 | 41 | SparkFun Audio Codec Breakout - WM8960 (QWIIC) 42 | https://www.sparkfun.com/products/21250 43 | 44 | All functions return 1 if the read/write was successful, and 0 45 | if there was a communications failure. You can ignore the return value 46 | if you just don't care anymore. 47 | 48 | For information on the data sent to and received from the CODEC, 49 | refer to the WM8960 datasheet at: 50 | https://github.com/sparkfun/SparkFun_Audio_Codec_Breakout_WM8960/blob/main/Documents/WM8960_datasheet_v4.2.pdf 51 | 52 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 53 | Please review the LICENSE.md file included with this example. If you have any questions 54 | or concerns with licensing, please contact techsupport@sparkfun.com. 55 | Distributed as-is; no warranty is given. 56 | ******************************************************************************/ 57 | 58 | #include 59 | #include 60 | // Click here to get the library: http://librarymanager/All#SparkFun_WM8960 61 | WM8960 codec; 62 | 63 | void setup() 64 | { 65 | Serial.begin(115200); 66 | Serial.println("Example 7 - MicBias Control"); 67 | 68 | Wire.begin(); 69 | 70 | if (codec.begin() == false) //Begin communication over I2C 71 | { 72 | Serial.println("The device did not respond. Please check wiring."); 73 | while (1); // Freeze 74 | } 75 | Serial.println("Device is connected properly."); 76 | 77 | // General setup needed 78 | codec.enableVREF(); 79 | codec.enableVMID(); 80 | 81 | codec.enableMicBias(); 82 | 83 | // WM8960_MIC_BIAS_VOLTAGE_0_9_AVDD (0.9*AVDD) or 84 | // WM8960_MIC_BIAS_VOLTAGE_0_65_AVDD (0.65*AVDD) 85 | codec.setMicBiasVoltage(WM8960_MIC_BIAS_VOLTAGE_0_9_AVDD); 86 | Serial.println("Mic Bias enabled (0.9*AVDD)"); 87 | delay(3000); 88 | 89 | // WM8960_MIC_BIAS_VOLTAGE_0_9_AVDD (0.9*AVDD) or 90 | // WM8960_MIC_BIAS_VOLTAGE_0_65_AVDD (0.65*AVDD) 91 | codec.setMicBiasVoltage(WM8960_MIC_BIAS_VOLTAGE_0_65_AVDD); 92 | Serial.println("Mic Bias enabled (0.65*AVDD)"); 93 | delay(3000); 94 | 95 | codec.disableMicBias(); 96 | Serial.println("Mic Bias disabled"); 97 | 98 | Serial.println("Example Complete. Hit reset to begin again."); 99 | } 100 | 101 | void loop() 102 | { 103 | // Nothing to see here 104 | } -------------------------------------------------------------------------------- /examples/Example_08_I2S_Passthrough/Example_08_I2S_Passthrough.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Example_08_I2S_Passthrough.ino 3 | Demonstrates reading I2S audio from the ADC, and passing that back to the DAC. 4 | 5 | This example sets up analog audio input (on INPUT1s), ADC/DAC enabled as I2S 6 | peripheral, sets volume control, and Headphone output on the WM8960 Codec. 7 | 8 | Audio should be connected to both the left and right "INPUT1" inputs, 9 | they are labeled "RIN1" and "LIN1" on the board. 10 | 11 | This example will pass your audio source through the mixers and gain stages of 12 | the codec into the ADC. Read the audio from the ADC via I2S. Then send audio 13 | immediately back to the DAC via I2S. Then send the output of the DAC to the 14 | headphone outs. 15 | 16 | Development platform used: 17 | SparkFun ESP32 IoT RedBoard v10 18 | 19 | HARDWARE CONNECTIONS 20 | 21 | ********************** 22 | ESP32 ------- CODEC 23 | ********************** 24 | QWIIC ------- QWIIC *Note this connects GND/3.3V/SDA/SCL 25 | GND --------- GND *optional, but not a bad idea 26 | 5V ---------- VIN *needed to power codec's onboard AVDD (3.3V vreg) 27 | 4 ----------- DDT *aka DAC_DATA/I2S_SDO/"serial data out", this carries the I2S audio data from ESP32 to codec DAC 28 | 16 ---------- BCK *aka BCLK/I2S_SCK/"bit clock", this is the clock for I2S audio, can be controlled via controller or peripheral. 29 | 17 ---------- ADAT *aka ADC_DATA/I2S_SD/"serial data in", this carries the I2S audio data from codec's ADC to ESP32 I2S bus. 30 | 25 ---------- DLRC *aka I2S_WS/LRC/"word select"/"left-right-channel", this toggles for left or right channel data. 31 | 25 ---------- ALR *for this example WS is shared for both the ADC WS (ALR) and the DAC WS (DLRC) 32 | 33 | ********************** 34 | CODEC ------- AUDIO IN 35 | ********************** 36 | GND --------- TRS INPUT SLEEVE *ground for line level input 37 | LINPUT1 ----- TRS INPUT TIP *left audio 38 | RINPUT1 ----- TRS INPUT RING1 *right audio 39 | 40 | ********************** 41 | CODEC -------- AUDIO OUT 42 | ********************** 43 | OUT3 --------- TRS OUTPUT SLEEVE *buffered "vmid" (aka "HP GND") 44 | HPL ---------- TRS OUTPUT TIP *left HP output 45 | HPR ---------- TRS OUTPUT RING1 *right HP output 46 | 47 | You can now control the volume of the codecs built in headphone amp using this 48 | fuction: 49 | 50 | codec.setHeadphoneVolumeDB(6.00); Valid inputs are -74.00 (MUTE) up to +6.00, 51 | (1.00dB steps). 52 | 53 | Pete Lewis @ SparkFun Electronics 54 | October 14th, 2022 55 | https://github.com/sparkfun/SparkFun_WM8960_Arduino_Library 56 | 57 | This code was created using some code by Mike Grusin at SparkFun Electronics 58 | Included with the LilyPad MP3 example code found here: 59 | Revision history: version 1.0 2012/07/24 MDG Initial release 60 | https://github.com/sparkfun/LilyPad_MP3_Player 61 | 62 | This code was created using some modified code from DroneBot Workshop. 63 | Specifically, the I2S configuration setup was super helpful to get I2S working. 64 | This example has a similar I2S config to what we are using here: Microphone to 65 | serial plotter example. Although, here we are doing a full duplex I2S port, in 66 | order to do reads and writes. To see the original Drone Workshop code and 67 | learn more about I2S in general, please visit: 68 | https://dronebotworkshop.com/esp32-i2s/ 69 | 70 | Do you like this library? Help support SparkFun. Buy a board! 71 | 72 | SparkFun Audio Codec Breakout - WM8960 (QWIIC) 73 | https://www.sparkfun.com/products/21250 74 | 75 | All functions return 1 if the read/write was successful, and 0 76 | if there was a communications failure. You can ignore the return value 77 | if you just don't care anymore. 78 | 79 | For information on the data sent to and received from the CODEC, 80 | refer to the WM8960 datasheet at: 81 | https://github.com/sparkfun/SparkFun_Audio_Codec_Breakout_WM8960/blob/main/Documents/WM8960_datasheet_v4.2.pdf 82 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 83 | Please review the LICENSE.md file included with this example. If you have any questions 84 | or concerns with licensing, please contact techsupport@sparkfun.com. 85 | Distributed as-is; no warranty is given. 86 | ******************************************************************************/ 87 | 88 | #include 89 | #include 90 | // Click here to get the library: http://librarymanager/All#SparkFun_WM8960 91 | WM8960 codec; 92 | 93 | // Include I2S driver 94 | #include 95 | 96 | // Connections to I2S 97 | #define I2S_WS 25 98 | #define I2S_SD 17 99 | #define I2S_SDO 4 100 | #define I2S_SCK 16 101 | 102 | // Use I2S Processor 0 103 | #define I2S_PORT I2S_NUM_0 104 | 105 | // Define input buffer length 106 | #define bufferLen 64 107 | int16_t sBuffer[bufferLen]; 108 | 109 | void setup() 110 | { 111 | Serial.begin(115200); 112 | Serial.println("Example 8 - I2S Passthough"); 113 | 114 | Wire.begin(); 115 | 116 | if (codec.begin() == false) //Begin communication over I2C 117 | { 118 | Serial.println("The device did not respond. Please check wiring."); 119 | while (1); // Freeze 120 | } 121 | Serial.println("Device is connected properly."); 122 | 123 | codec_setup(); 124 | 125 | // Set up I2S 126 | i2s_install(); 127 | i2s_setpin(); 128 | i2s_start(I2S_PORT); 129 | } 130 | 131 | void loop() 132 | { 133 | // Get I2S data and place in data buffer 134 | size_t bytesIn = 0; 135 | size_t bytesOut = 0; 136 | esp_err_t result = i2s_read(I2S_PORT, &sBuffer, bufferLen, &bytesIn, portMAX_DELAY); 137 | 138 | if (result == ESP_OK) 139 | { 140 | // Send what we just received back to the codec 141 | esp_err_t result_w = i2s_write(I2S_PORT, &sBuffer, bytesIn, &bytesOut, portMAX_DELAY); 142 | 143 | // If there was an I2S write error, let us know on the serial terminal 144 | if (result_w != ESP_OK) 145 | { 146 | Serial.print("I2S write error."); 147 | } 148 | } 149 | // DelayMicroseconds(300); // Only hear to demonstrate how much time you have 150 | // to do things. 151 | // Do not do much in this main loop, or the audio won't pass through correctly. 152 | // With default settings (64 samples in buffer), you can spend up to 300 153 | // microseconds doing something in between passing each buffer of data 154 | // You can tweak the buffer length to get more time if you need it. 155 | // When bufferlength is 64, then you get ~300 microseconds 156 | // When bufferlength is 128, then you get ~600 microseconds 157 | // Note, as you increase bufferlength, then you are increasing latency between 158 | // ADC input to DAC output. 159 | // Latency may or may not be desired, depending on the project. 160 | } 161 | 162 | void codec_setup() 163 | { 164 | // General setup needed 165 | codec.enableVREF(); 166 | codec.enableVMID(); 167 | 168 | // Setup signal flow to the ADC 169 | 170 | codec.enableLMIC(); 171 | codec.enableRMIC(); 172 | 173 | // Connect from INPUT1 to "n" (aka inverting) inputs of PGAs. 174 | codec.connectLMN1(); 175 | codec.connectRMN1(); 176 | 177 | // Disable mutes on PGA inputs (aka INTPUT1) 178 | codec.disableLINMUTE(); 179 | codec.disableRINMUTE(); 180 | 181 | // Set pga volumes 182 | codec.setLINVOLDB(0.00); // Valid options are -17.25dB to +30dB (0.75dB steps) 183 | codec.setRINVOLDB(0.00); // Valid options are -17.25dB to +30dB (0.75dB steps) 184 | 185 | // Set input boosts to get inputs 1 to the boost mixers 186 | codec.setLMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 187 | codec.setRMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 188 | 189 | // Connect from MIC inputs (aka pga output) to boost mixers 190 | codec.connectLMIC2B(); 191 | codec.connectRMIC2B(); 192 | 193 | // Enable boost mixers 194 | codec.enableAINL(); 195 | codec.enableAINR(); 196 | 197 | // Disconnect LB2LO (booster to output mixer (analog bypass) 198 | // For this example, we are going to pass audio throught the ADC and DAC 199 | codec.disableLB2LO(); 200 | codec.disableRB2RO(); 201 | 202 | // Connect from DAC outputs to output mixer 203 | codec.enableLD2LO(); 204 | codec.enableRD2RO(); 205 | 206 | // Set gainstage between booster mixer and output mixer 207 | // For this loopback example, we are going to keep these as low as they go 208 | codec.setLB2LOVOL(WM8960_OUTPUT_MIXER_GAIN_NEG_21DB); 209 | codec.setRB2ROVOL(WM8960_OUTPUT_MIXER_GAIN_NEG_21DB); 210 | 211 | // Enable output mixers 212 | codec.enableLOMIX(); 213 | codec.enableROMIX(); 214 | 215 | // CLOCK STUFF, These settings will get you 44.1KHz sample rate, and class-d 216 | // freq at 705.6kHz 217 | codec.enablePLL(); // Needed for class-d amp clock 218 | codec.setPLLPRESCALE(WM8960_PLLPRESCALE_DIV_2); 219 | codec.setSMD(WM8960_PLL_MODE_FRACTIONAL); 220 | codec.setCLKSEL(WM8960_CLKSEL_PLL); 221 | codec.setSYSCLKDIV(WM8960_SYSCLK_DIV_BY_2); 222 | codec.setBCLKDIV(4); 223 | codec.setDCLKDIV(WM8960_DCLKDIV_16); 224 | codec.setPLLN(7); 225 | codec.setPLLK(0x86, 0xC2, 0x26); // PLLK=86C226h 226 | //codec.setADCDIV(0); // Default is 000 (what we need for 44.1KHz) 227 | //codec.setDACDIV(0); // Default is 000 (what we need for 44.1KHz) 228 | codec.setWL(WM8960_WL_16BIT); 229 | 230 | codec.enablePeripheralMode(); 231 | //codec.enableMasterMode(); 232 | //codec.setALRCGPIO(); // Note, should not be changed while ADC is enabled. 233 | 234 | // Enable ADCs and DACs 235 | codec.enableAdcLeft(); 236 | codec.enableAdcRight(); 237 | codec.enableDacLeft(); 238 | codec.enableDacRight(); 239 | codec.disableDacMute(); 240 | 241 | //codec.enableLoopBack(); // Loopback sends ADC data directly into DAC 242 | codec.disableLoopBack(); 243 | 244 | // Default is "soft mute" on, so we must disable mute to make channels active 245 | codec.disableDacMute(); 246 | 247 | codec.enableHeadphones(); 248 | codec.enableOUT3MIX(); // Provides VMID as buffer for headphone ground 249 | 250 | Serial.println("Volume set to +0dB"); 251 | codec.setHeadphoneVolumeDB(0.00); 252 | 253 | Serial.println("Codec Setup complete. Listen to left/right INPUT1 on Headphone outputs."); 254 | } 255 | 256 | void i2s_install() { 257 | // Set up I2S Processor configuration 258 | const i2s_driver_config_t i2s_config = { 259 | .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_TX), 260 | .sample_rate = 44100, 261 | .bits_per_sample = i2s_bits_per_sample_t(16), 262 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 263 | .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_MSB), 264 | .intr_alloc_flags = 0, 265 | .dma_buf_count = 8, 266 | .dma_buf_len = bufferLen, 267 | .use_apll = false, 268 | .tx_desc_auto_clear = false, 269 | .fixed_mclk = 0, 270 | .mclk_multiple = i2s_mclk_multiple_t(I2S_MCLK_MULTIPLE_512), 271 | .bits_per_chan = i2s_bits_per_chan_t(I2S_BITS_PER_CHAN_DEFAULT) 272 | }; 273 | 274 | i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL); 275 | } 276 | 277 | void i2s_setpin() { 278 | // Set I2S pin configuration 279 | const i2s_pin_config_t pin_config = { 280 | .mck_io_num = I2S_PIN_NO_CHANGE, 281 | .bck_io_num = I2S_SCK, 282 | .ws_io_num = I2S_WS, 283 | .data_out_num = I2S_SDO, 284 | .data_in_num = I2S_SD 285 | }; 286 | 287 | i2s_set_pin(I2S_PORT, &pin_config); 288 | } 289 | -------------------------------------------------------------------------------- /examples/Example_09_I2S_Bluetooth/Example_09_I2S_Bluetooth.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Example_09_I2S_Bluetooth.ino 3 | Demonstrates how to receive audio via Bluetooth and play it back via I2S to 4 | the codec DAC. 5 | 6 | This example sets up the ESP32 as a bluetooth sink device, with its output set 7 | to I2S audio. 8 | 9 | This example sets up the WM8960 codec as an I2S peripheral, sets volume 10 | control, and Headphone output. 11 | 12 | A bluetooth device, such as your phone or laptop, can connect to the ESP32 and 13 | then begin playing an audio file. 14 | 15 | The ESP32 will send the I2S audio to the DAC of the codec. The DAC is 16 | connected to the HP outputs. 17 | 18 | Development platform used: 19 | SparkFun ESP32 IoT RedBoard v10 20 | 21 | HARDWARE CONNECTIONS 22 | 23 | ********************** 24 | ESP32 ------- CODEC 25 | ********************** 26 | QWIIC ------- QWIIC *Note this connects GND/3.3V/SDA/SCL 27 | GND --------- GND *optional, but not a bad idea 28 | 5V ---------- VIN *needed to power codec's onboard AVDD (3.3V vreg) 29 | 4 ----------- DDT *aka DAC_DATA/I2S_SDO/"serial data out", this carries the I2S audio data from ESP32 to codec DAC 30 | 16 ---------- BCK *aka BCLK/I2S_SCK/"bit clock", this is the clock for I2S audio, can be controlled via controller or peripheral. 31 | 25 ---------- DLRC *aka I2S_WS/LRC/"word select"/"left-right-channel", this toggles for left or right channel data. 32 | 33 | ********************** 34 | CODEC -------- AUDIO OUT 35 | ********************** 36 | OUT3 --------- TRS OUTPUT SLEEVE *buffered "vmid" (aka "HP GND") 37 | HPL ---------- TRS OUTPUT TIP *left HP output 38 | HPR ---------- TRS OUTPUT RING1 *right HP output 39 | 40 | Note, once connected and playing a sound file, your bluetooth source device 41 | (i.e. your phone) can control volume with its own volume control. 42 | 43 | You can also control the volume of the codecs built in headphone amp using this 44 | fuction: 45 | 46 | codec.setHeadphoneVolumeDB(6.00); Valid inputs are -74.00 (MUTE) up to +6.00, 47 | (1.00dB steps). 48 | 49 | Pete Lewis @ SparkFun Electronics 50 | October 14th, 2022 51 | https://github.com/sparkfun/SparkFun_WM8960_Arduino_Library 52 | 53 | This code was created using some code by Mike Grusin at SparkFun Electronics 54 | Included with the LilyPad MP3 example code found here: 55 | Revision history: version 1.0 2012/07/24 MDG Initial release 56 | https://github.com/sparkfun/LilyPad_MP3_Player 57 | 58 | This code was created using some modified code from Phil Schatzmann's Arduino 59 | Library: https://github.com/pschatzmann/ESP32-A2DP 60 | The I2S configuration information about custom setups in the readme was super 61 | helpful to get I2S working: https://github.com/pschatzmann/ESP32-A2DP#readme 62 | This example is most similar to Phil Schatzmann's 63 | "bt_music_receiver_simple.ino" example. You can find that original code here: 64 | https://github.com/pschatzmann/ESP32-A2DP/blob/main/examples/bt_music_receiver_simple/bt_music_receiver_simple.ino" 65 | Although, here we are setting up custom I2S pins and I2S modes to work for our 66 | needs. And we are setting up the matching I2S configuration on the WM8960. 67 | 68 | Do you like this library? Help support SparkFun. Buy a board! 69 | 70 | SparkFun Audio Codec Breakout - WM8960 (QWIIC) 71 | https://www.sparkfun.com/products/21250 72 | 73 | All functions return 1 if the read/write was successful, and 0 74 | if there was a communications failure. You can ignore the return value 75 | if you just don't care anymore. 76 | 77 | For information on the data sent to and received from the CODEC, 78 | refer to the WM8960 datasheet at: 79 | https://github.com/sparkfun/SparkFun_Audio_Codec_Breakout_WM8960/blob/main/Documents/WM8960_datasheet_v4.2.pdf 80 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 81 | Please review the LICENSE.md file included with this example. If you have any questions 82 | or concerns with licensing, please contact techsupport@sparkfun.com. 83 | Distributed as-is; no warranty is given. 84 | ******************************************************************************/ 85 | 86 | #include 87 | #include 88 | // Click here to get the library: http://librarymanager/All#SparkFun_WM8960 89 | WM8960 codec; 90 | 91 | #include "BluetoothA2DPSink.h" // Download library here: https://github.com/pschatzmann/ESP32-A2DP 92 | BluetoothA2DPSink a2dp_sink; 93 | 94 | // Connections to I2S bus (on the IoT Redboard) 95 | #define I2S_WS 25 96 | #define I2S_SD 17 // Note, this is not needed for this example, as it only sends 97 | // data out to the codec's DAC (via I2S_SDO) 98 | #define I2S_SDO 4 99 | #define I2S_SCK 16 100 | 101 | void setup() 102 | { 103 | Serial.begin(115200); 104 | Serial.println("Example 9 - Bluetooth Audio"); 105 | 106 | Wire.begin(); 107 | 108 | if (codec.begin() == false) //Begin communication over I2C 109 | { 110 | Serial.println("The device did not respond. Please check wiring."); 111 | while (1); // Freeze 112 | } 113 | Serial.println("Device is connected properly."); 114 | 115 | codec_setup(); 116 | 117 | // Set up I2S 118 | i2s_install(); 119 | i2s_setpin(); 120 | 121 | a2dp_sink.start("myCodec"); // Note, you can give your device any name! 122 | } 123 | 124 | void loop() 125 | { 126 | // Nothing do do here, but you can add more code if you like! 127 | } 128 | 129 | void codec_setup() 130 | { 131 | // General setup needed 132 | codec.enableVREF(); 133 | codec.enableVMID(); 134 | 135 | // Connect from DAC outputs to output mixer 136 | codec.enableLD2LO(); 137 | codec.enableRD2RO(); 138 | 139 | // Set gainstage between booster mixer and output mixer 140 | // For this loopback example, we are going to keep these as low as they go 141 | codec.setLB2LOVOL(WM8960_OUTPUT_MIXER_GAIN_NEG_21DB); 142 | codec.setRB2ROVOL(WM8960_OUTPUT_MIXER_GAIN_NEG_21DB); 143 | 144 | // Enable output mixers 145 | codec.enableLOMIX(); 146 | codec.enableROMIX(); 147 | 148 | // CLOCK STUFF, These settings will get you 44.1KHz sample rate, and class-d 149 | // freq at 705.6kHz 150 | codec.enablePLL(); // Needed for class-d amp clock 151 | codec.setPLLPRESCALE(WM8960_PLLPRESCALE_DIV_2); 152 | codec.setSMD(WM8960_PLL_MODE_FRACTIONAL); 153 | codec.setCLKSEL(WM8960_CLKSEL_PLL); 154 | codec.setSYSCLKDIV(WM8960_SYSCLK_DIV_BY_2); 155 | codec.setBCLKDIV(4); 156 | codec.setDCLKDIV(WM8960_DCLKDIV_16); 157 | codec.setPLLN(7); 158 | codec.setPLLK(0x86, 0xC2, 0x26); // PLLK=86C226h 159 | //codec.setADCDIV(0); // Default is 000 (what we need for 44.1KHz) 160 | //codec.setDACDIV(0); // Default is 000 (what we need for 44.1KHz) 161 | codec.setWL(WM8960_WL_16BIT); 162 | 163 | codec.enablePeripheralMode(); 164 | //codec.enableMasterMode(); 165 | //codec.setALRCGPIO(); // Note, should not be changed while ADC is enabled. 166 | 167 | // Enable DACs 168 | codec.enableDacLeft(); 169 | codec.enableDacRight(); 170 | 171 | //codec.enableLoopBack(); // Loopback sends ADC data directly into DAC 172 | codec.disableLoopBack(); 173 | 174 | // Default is "soft mute" on, so we must disable mute to make channels active 175 | codec.disableDacMute(); 176 | 177 | codec.enableHeadphones(); 178 | codec.enableOUT3MIX(); // Provides VMID as buffer for headphone ground 179 | 180 | Serial.println("Volume set to +0dB"); 181 | codec.setHeadphoneVolumeDB(0.00); 182 | 183 | Serial.println("Codec Setup complete. Connect via Bluetooth, play music, and listen on Headphone outputs."); 184 | } 185 | 186 | void i2s_install() { 187 | // Set up I2S Processor configuration 188 | static i2s_config_t i2s_config = { 189 | .mode = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_TX), 190 | .sample_rate = 44100, // Updated automatically by A2DP 191 | .bits_per_sample = (i2s_bits_per_sample_t)16, 192 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 193 | .communication_format = (i2s_comm_format_t) (I2S_COMM_FORMAT_STAND_I2S), 194 | .intr_alloc_flags = 0, // Default interrupt priority 195 | .dma_buf_count = 8, 196 | .dma_buf_len = 64, 197 | .use_apll = true, 198 | .tx_desc_auto_clear = true // Avoiding noise in case of data unavailability 199 | }; 200 | 201 | a2dp_sink.set_i2s_config(i2s_config); 202 | } 203 | 204 | void i2s_setpin() { 205 | // Set I2S pin configuration 206 | i2s_pin_config_t my_pin_config = { 207 | .bck_io_num = I2S_SCK, 208 | .ws_io_num = I2S_WS, 209 | .data_out_num = I2S_SDO, 210 | .data_in_num = I2S_PIN_NO_CHANGE 211 | }; 212 | 213 | a2dp_sink.set_pin_config(my_pin_config); 214 | } 215 | -------------------------------------------------------------------------------- /examples/Example_10_AdcGain/Example_10_AdcGain.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Example_10_AdcGain.ino 3 | Demonstrates how to control the volume using the codec's ADC digital volume 4 | control. 5 | 6 | Attach a potentiomenter to GND/A0/3V3 to actively adjust the setting. 7 | 8 | This example sets up the codec for analog audio input (on INPUT1s), ADC/DAC 9 | Loopback, sets hp volume, and Headphone output on the WM8960 Codec. 10 | 11 | Audio should be connected to both the left and right "INPUT1" inputs, 12 | they are labeled "RIN1" and "LIN1" on the board. 13 | 14 | This example will pass your audio source through the mixers and gain stages 15 | of the codec into the ADC. Turn on Loopback (so ADC is feed directly to DAC). 16 | Then send the output of the DAC to the headphone outs. 17 | 18 | We will use the gain stage at the ADC to control the volume of the signal. 19 | This is capable of more precision, with 255 available settings. 20 | 21 | ** ADC digital volume 22 | ** Valid dB settings are -97.00 up to +30.0 (0.5dB steps) 23 | ** -97.50 (or lower) = MUTE 24 | ** -97.00 = -97.00dB (MIN) 25 | ** ... 0.5dB steps ... 26 | ** 30.00 = +30.00dB (MAX) 27 | 28 | You can also control the volume of the codecs built in headphone amp using 29 | this function: 30 | 31 | codec.setHeadphoneVolumeDB(6.00); Valid inputs are -74.00 (MUTE) up to +6.00, 32 | (1.00dB steps). 33 | 34 | Development platform used: 35 | SparkFun ESP32 IoT RedBoard v10 36 | 37 | HARDWARE CONNECTIONS 38 | 39 | ********************** 40 | ESP32 ------- CODEC 41 | ********************** 42 | QWIIC ------- QWIIC *Note this connects GND/3.3V/SDA/SCL 43 | GND --------- GND *optional, but not a bad idea 44 | 5V ---------- VIN *needed to power codec's onboard AVDD (3.3V vreg) 45 | 46 | ********************** 47 | ESP32 -------- POTENTIOMTER (aka blue little trimpot) 48 | ********************** 49 | GND ---------- "right-side pin" 50 | A0 ----------- center pin *aka center tap connection 51 | 3V3 ---------- "left-side pin" 52 | 53 | ********************** 54 | CODEC ------- AUDIO IN 55 | ********************** 56 | GND --------- TRS INPUT SLEEVE *ground for line level input 57 | LINPUT1 ----- TRS INPUT TIP *left audio 58 | RINPUT1 ----- TRS INPUT RING1 *right audio 59 | 60 | ********************** 61 | CODEC -------- AUDIO OUT 62 | ********************** 63 | OUT3 --------- TRS OUTPUT SLEEVE 64 | HPL ---------- TRS OUTPUT TIP *left HP output 65 | HPR ---------- TRS OUTPUT RING1 *right HP output 66 | 67 | Pete Lewis @ SparkFun Electronics 68 | October 14th, 2022 69 | https://github.com/sparkfun/SparkFun_WM8960_Arduino_Library 70 | 71 | This code was created using some code by Mike Grusin at SparkFun Electronics 72 | Included with the LilyPad MP3 example code found here: 73 | Revision history: version 1.0 2012/07/24 MDG Initial release 74 | https://github.com/sparkfun/LilyPad_MP3_Player 75 | 76 | Do you like this library? Help support SparkFun. Buy a board! 77 | 78 | SparkFun Audio Codec Breakout - WM8960 (QWIIC) 79 | https://www.sparkfun.com/products/21250 80 | 81 | All functions return 1 if the read/write was successful, and 0 82 | if there was a communications failure. You can ignore the return value 83 | if you just don't care anymore. 84 | 85 | For information on the data sent to and received from the CODEC, 86 | refer to the WM8960 datasheet at: 87 | https://github.com/sparkfun/SparkFun_Audio_Codec_Breakout_WM8960/blob/main/Documents/WM8960_datasheet_v4.2.pdf 88 | 89 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 90 | Please review the LICENSE.md file included with this example. If you have any questions 91 | or concerns with licensing, please contact techsupport@sparkfun.com. 92 | Distributed as-is; no warranty is given. 93 | ******************************************************************************/ 94 | 95 | #include 96 | #include 97 | // Click here to get the library: http://librarymanager/All#SparkFun_WM8960 98 | WM8960 codec; 99 | 100 | // Used to store incoming potentiometer settings to set ADC digital volume 101 | // setting 102 | long userInputA0 = 0; 103 | 104 | void setup() 105 | { 106 | Serial.begin(115200); 107 | Serial.println("Example 10 - ADC Digital Volume Control"); 108 | 109 | Wire.begin(); 110 | 111 | if (codec.begin() == false) //Begin communication over I2C 112 | { 113 | Serial.println("The device did not respond. Please check wiring."); 114 | while (1); // Freeze 115 | } 116 | Serial.println("Device is connected properly."); 117 | 118 | codec_setup(); 119 | } 120 | 121 | void loop() 122 | { 123 | // Take a bunch of readings and average them, to smooth out the value 124 | for (int i = 0 ; i < 250 ; i ++) 125 | { 126 | userInputA0 += analogRead(A0); 127 | delay(1); 128 | } 129 | 130 | // After taking a bunch of samples, divide down to the average single reading 131 | userInputA0 /= 250; 132 | 133 | // Map it from 0-4096, to a dB value that is acceptable in the ADC digital 134 | // volume control (-97.50 [MUTE] to +30dB) 135 | float adcVolumeDB = mapFloats((float)userInputA0, 0.00, 4096.00, 30.00, -97.50); 136 | 137 | Serial.print("adcVolumeDB: "); 138 | Serial.println(adcVolumeDB); 139 | 140 | codec.setAdcLeftDigitalVolumeDB(adcVolumeDB); // -97.50 to +30.00dB 141 | codec.setAdcRightDigitalVolumeDB(adcVolumeDB); // -97.50 to +30.00dB 142 | 143 | delay(50); 144 | } 145 | 146 | void codec_setup() 147 | { 148 | // General setup needed 149 | codec.enableVREF(); 150 | codec.enableVMID(); 151 | 152 | // Setup signal flow to the ADC 153 | 154 | codec.enableLMIC(); 155 | codec.enableRMIC(); 156 | 157 | // Connect from INPUT1 to "n" (aka inverting) inputs of PGAs. 158 | codec.connectLMN1(); 159 | codec.connectRMN1(); 160 | 161 | // Disable mutes on PGA inputs (aka INTPUT1) 162 | codec.disableLINMUTE(); 163 | codec.disableRINMUTE(); 164 | 165 | // Set input boosts to get inputs 1 to the boost mixers 166 | codec.setLMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 167 | codec.setRMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 168 | 169 | codec.connectLMIC2B(); 170 | codec.connectRMIC2B(); 171 | 172 | // Enable boost mixers 173 | codec.enableAINL(); 174 | codec.enableAINR(); 175 | 176 | // Disconnect LB2LO (booster to output mixer (analog bypass) 177 | // For this example, we are going to pass audio throught the ADC and DAC 178 | codec.disableLB2LO(); 179 | codec.disableRB2RO(); 180 | 181 | // Connect from DAC outputs to output mixer 182 | codec.enableLD2LO(); 183 | codec.enableRD2RO(); 184 | 185 | // Set gainstage between booster mixer and output mixer 186 | // For this loopback example, we are going to keep these as low as they go 187 | codec.setLB2LOVOL(WM8960_OUTPUT_MIXER_GAIN_NEG_21DB); 188 | codec.setRB2ROVOL(WM8960_OUTPUT_MIXER_GAIN_NEG_21DB); 189 | 190 | // Enable output mixers 191 | codec.enableLOMIX(); 192 | codec.enableROMIX(); 193 | 194 | // CLOCK STUFF, These settings will get you 44.1KHz sample rate, and class-d 195 | // freq at 705.6kHz 196 | codec.enablePLL(); // Needed for class-d amp clock 197 | codec.setPLLPRESCALE(WM8960_PLLPRESCALE_DIV_2); 198 | codec.setSMD(WM8960_PLL_MODE_FRACTIONAL); 199 | codec.setCLKSEL(WM8960_CLKSEL_PLL); 200 | codec.setSYSCLKDIV(WM8960_SYSCLK_DIV_BY_2); 201 | codec.setBCLKDIV(4); 202 | codec.setDCLKDIV(WM8960_DCLKDIV_16); 203 | codec.setPLLN(7); 204 | codec.setPLLK(0x86, 0xC2, 0x26); // PLLK=86C226h 205 | //codec.setADCDIV(0); // Default is 000 (what we need for 44.1KHz) 206 | //codec.setDACDIV(0); // Default is 000 (what we need for 44.1KHz) 207 | 208 | codec.enableMasterMode(); 209 | codec.setALRCGPIO(); // Note, should not be changed while ADC is enabled. 210 | 211 | // Enable ADCs and DACs 212 | codec.enableAdcLeft(); 213 | codec.enableAdcRight(); 214 | codec.enableDacLeft(); 215 | codec.enableDacRight(); 216 | codec.disableDacMute(); 217 | 218 | codec.enableLoopBack(); // Loopback sends ADC data directly into DAC 219 | 220 | // Default is "soft mute" on, so we must disable mute to make channels active 221 | codec.disableDacMute(); 222 | 223 | codec.enableHeadphones(); 224 | codec.enableOUT3MIX(); // Provides VMID as buffer for headphone ground 225 | 226 | Serial.println("Headphone Amp Volume set to +0dB"); 227 | codec.setHeadphoneVolumeDB(0.00); 228 | 229 | Serial.println("Codec setup complete. Listen to left/right INPUT1 on Headphone outputs."); 230 | } 231 | 232 | // mapFloat 233 | // This function is the same as the Arduino map() function, but it can accept 234 | // and return float values. We need this to handle dB values which are floats 235 | // 236 | // value: the number to map. 237 | // 238 | // fromLow: the lower bound of the value’s current range. 239 | // 240 | // fromHigh: the upper bound of the value’s current range. 241 | // 242 | // toLow: the lower bound of the value’s target range. 243 | // 244 | // toHigh: the upper bound of the value’s target range. 245 | 246 | float mapFloats(float value, float fromLow, float fromHigh, float toLow, float toHigh) 247 | { 248 | return (value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow) + toLow; 249 | } 250 | -------------------------------------------------------------------------------- /examples/Example_11_VolumePlotter/Example_11_VolumePlotter.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Example_11_VolumePlotter.ino 3 | Demonstrates reading I2S audio from the ADC, and plotting the audio samples on 4 | the Arduino Serial Plotter. 5 | 6 | This example sets up analog audio input (on INPUT1s), ADC enabled as I2S 7 | peripheral, sets volume control, and Headphone output on the WM8960 Codec. 8 | 9 | Audio should be connected to both the left and right "INPUT1" inputs, 10 | they are labeled "RIN1" and "LIN1" on the board. 11 | 12 | This example will pass your audio source through the mixers and gain stages of 13 | the codec into the ADC. Read the audio from the ADC via I2S. 14 | 15 | The analog bypass paths is also setup, so your audio will pass through the 16 | codec and playback on HP outs. 17 | 18 | Development platform used: 19 | SparkFun ESP32 IoT RedBoard v10 20 | 21 | HARDWARE CONNECTIONS 22 | 23 | ********************** 24 | ESP32 ------- CODEC 25 | ********************** 26 | QWIIC ------- QWIIC *Note this connects GND/3.3V/SDA/SCL 27 | GND --------- GND *optional, but not a bad idea 28 | 5V ---------- VIN *needed to power codec's onboard AVDD (3.3V vreg) 29 | 16 ---------- BCK *aka BCLK/I2S_SCK/"bit clock", this is the clock for I2S audio, can be controlled via controller or peripheral. 30 | 17 ---------- ADAT *aka ADC_DATA/I2S_SD/"serial data in", this carries the I2S audio data from codec's ADC to ESP32 I2S bus. 31 | 25 ---------- ALR *aka I2S_WS/LRC/"word select"/"left-right-channel", this toggles for left or right channel data. 32 | 33 | ********************** 34 | CODEC ------- AUDIO IN 35 | ********************** 36 | GND --------- TRS INPUT SLEEVE *ground for line level input 37 | LINPUT1 ----- TRS INPUT TIP *left audio 38 | RINPUT1 ----- TRS INPUT RING1 *right audio 39 | 40 | ********************** 41 | CODEC -------- AUDIO OUT 42 | ********************** 43 | OUT3 --------- TRS OUTPUT SLEEVE *buffered "vmid" (aka "HP GND") 44 | HPL ---------- TRS OUTPUT TIP *left HP output 45 | HPR ---------- TRS OUTPUT RING1 *right HP output 46 | 47 | You can now control the volume of the codecs built in headphone amp using this 48 | fuction: 49 | 50 | codec.setHeadphoneVolumeDB(6.00); Valid inputs are -74.00 (MUTE) up to +6.00, 51 | (1.00dB steps). 52 | 53 | Pete Lewis @ SparkFun Electronics 54 | October 14th, 2022 55 | https://github.com/sparkfun/SparkFun_WM8960_Arduino_Library 56 | 57 | This code was created using some code by Mike Grusin at SparkFun Electronics 58 | Included with the LilyPad MP3 example code found here: 59 | Revision history: version 1.0 2012/07/24 MDG Initial release 60 | https://github.com/sparkfun/LilyPad_MP3_Player 61 | 62 | This code was created using some modified code from DroneBot Workshop. 63 | Specifically, the I2S configuration setup was super helpful to get I2S working. 64 | This example has a similar I2S config to what we are using here: Microphone to 65 | serial plotter example. Although, here we are doing a line level TRS audio 66 | input into the codec. To see the original Drone Workshop code and learn more 67 | about I2S in general, please visit: https://dronebotworkshop.com/esp32-i2s/ 68 | 69 | Do you like this library? Help support SparkFun. Buy a board! 70 | 71 | SparkFun Audio Codec Breakout - WM8960 (QWIIC) 72 | https://www.sparkfun.com/products/21250 73 | 74 | All functions return 1 if the read/write was successful, and 0 75 | if there was a communications failure. You can ignore the return value 76 | if you just don't care anymore. 77 | 78 | For information on the data sent to and received from the CODEC, 79 | refer to the WM8960 datasheet at: 80 | https://github.com/sparkfun/SparkFun_Audio_Codec_Breakout_WM8960/blob/main/Documents/WM8960_datasheet_v4.2.pdf 81 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 82 | Please review the LICENSE.md file included with this example. If you have any questions 83 | or concerns with licensing, please contact techsupport@sparkfun.com. 84 | Distributed as-is; no warranty is given. 85 | ******************************************************************************/ 86 | 87 | #include 88 | #include 89 | // Click here to get the library: http://librarymanager/All#SparkFun_WM8960 90 | WM8960 codec; 91 | 92 | // Include I2S driver 93 | #include 94 | 95 | // Connections to I2S 96 | #define I2S_WS 25 97 | #define I2S_SD 17 98 | #define I2S_SDO 4 // Not used for this example 99 | #define I2S_SCK 16 100 | 101 | // Use I2S Processor 0 102 | #define I2S_PORT I2S_NUM_0 103 | 104 | // Define input buffer length 105 | #define bufferLen 64 106 | int16_t sBuffer[bufferLen]; 107 | 108 | void setup() 109 | { 110 | Serial.begin(115200); 111 | 112 | Wire.begin(); 113 | 114 | if (codec.begin() == false) //Begin communication over I2C 115 | { 116 | Serial.println("The device did not respond. Please check wiring."); 117 | while (1); // Freeze 118 | } 119 | 120 | codec_setup(); 121 | 122 | // Set up I2S 123 | i2s_install(); 124 | i2s_setpin(); 125 | i2s_start(I2S_PORT); 126 | } 127 | 128 | void loop() 129 | { 130 | 131 | // False print statements to "lock range" on serial plotter display 132 | // Change rangelimit value to adjust "sensitivity" 133 | int rangelimit = 3000; 134 | Serial.print(rangelimit * -1); 135 | Serial.print(" "); 136 | Serial.print(rangelimit); 137 | Serial.print(" "); 138 | 139 | // Get I2S data and place in data buffer 140 | size_t bytesIn = 0; 141 | esp_err_t result = i2s_read(I2S_PORT, &sBuffer, bufferLen, &bytesIn, portMAX_DELAY); 142 | 143 | if (result == ESP_OK) 144 | { 145 | // Read I2S data buffer 146 | int16_t samples_read = bytesIn / 8; 147 | if (samples_read > 0) { 148 | float mean = 0; 149 | for (int16_t i = 0; i < samples_read; ++i) { 150 | mean += (sBuffer[i]); 151 | } 152 | 153 | // Average the data reading 154 | mean /= samples_read; 155 | 156 | // Print to serial plotter 157 | Serial.println(mean); 158 | } 159 | } 160 | } 161 | 162 | void codec_setup() 163 | { 164 | // General setup needed 165 | codec.enableVREF(); 166 | codec.enableVMID(); 167 | 168 | // Setup signal flow to the ADC 169 | 170 | codec.enableLMIC(); 171 | codec.enableRMIC(); 172 | 173 | // Connect from INPUT1 to "n" (aka inverting) inputs of PGAs. 174 | codec.connectLMN1(); 175 | codec.connectRMN1(); 176 | 177 | // Disable mutes on PGA inputs (aka INTPUT1) 178 | codec.disableLINMUTE(); 179 | codec.disableRINMUTE(); 180 | 181 | // Set pga volumes 182 | codec.setLINVOLDB(0.00); // Valid options are -17.25dB to +30dB (0.75dB steps) 183 | codec.setRINVOLDB(0.00); // Valid options are -17.25dB to +30dB (0.75dB steps) 184 | 185 | // Set input boosts to get inputs 1 to the boost mixers 186 | codec.setLMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 187 | codec.setRMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 188 | 189 | // Connect from MIC inputs (aka pga output) to boost mixers 190 | codec.connectLMIC2B(); 191 | codec.connectRMIC2B(); 192 | 193 | // Enable boost mixers 194 | codec.enableAINL(); 195 | codec.enableAINR(); 196 | 197 | // Connect LB2LO (booster to output mixer (analog bypass) 198 | codec.enableLB2LO(); 199 | codec.enableRB2RO(); 200 | 201 | // Disconnect from DAC outputs to output mixer 202 | codec.disableLD2LO(); 203 | codec.disableRD2RO(); 204 | 205 | // Set gainstage between booster mixer and output mixer 206 | codec.setLB2LOVOL(WM8960_OUTPUT_MIXER_GAIN_0DB); 207 | codec.setRB2ROVOL(WM8960_OUTPUT_MIXER_GAIN_0DB); 208 | 209 | // Enable output mixers 210 | codec.enableLOMIX(); 211 | codec.enableROMIX(); 212 | 213 | // CLOCK STUFF, These settings will get you 44.1KHz sample rate, and class-d 214 | // freq at 705.6kHz 215 | codec.enablePLL(); // Needed for class-d amp clock 216 | codec.setPLLPRESCALE(WM8960_PLLPRESCALE_DIV_2); 217 | codec.setSMD(WM8960_PLL_MODE_FRACTIONAL); 218 | codec.setCLKSEL(WM8960_CLKSEL_PLL); 219 | codec.setSYSCLKDIV(WM8960_SYSCLK_DIV_BY_2); 220 | codec.setBCLKDIV(4); 221 | codec.setDCLKDIV(WM8960_DCLKDIV_16); 222 | codec.setPLLN(7); 223 | codec.setPLLK(0x86, 0xC2, 0x26); // PLLK=86C226h 224 | //codec.setADCDIV(0); // Default is 000 (what we need for 44.1KHz) 225 | //codec.setDACDIV(0); // Default is 000 (what we need for 44.1KHz) 226 | codec.setWL(WM8960_WL_16BIT); 227 | 228 | codec.enablePeripheralMode(); 229 | //codec.enableMasterMode(); 230 | //codec.setALRCGPIO(); // Note, should not be changed while ADC is enabled. 231 | 232 | // Enable ADCs, and disable DACs 233 | codec.enableAdcLeft(); 234 | codec.enableAdcRight(); 235 | codec.disableDacLeft(); 236 | codec.disableDacRight(); 237 | codec.disableDacMute(); 238 | 239 | //codec.enableLoopBack(); // Loopback sends ADC data directly into DAC 240 | codec.disableLoopBack(); 241 | 242 | // Default is "soft mute" on, so we must disable mute to make channels active 243 | codec.enableDacMute(); 244 | 245 | codec.enableHeadphones(); 246 | codec.enableOUT3MIX(); // Provides VMID as buffer for headphone ground 247 | 248 | codec.setHeadphoneVolumeDB(0.00); 249 | } 250 | 251 | void i2s_install() { 252 | // Set up I2S Processor configuration 253 | const i2s_driver_config_t i2s_config = { 254 | .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX), 255 | .sample_rate = 44100, 256 | .bits_per_sample = i2s_bits_per_sample_t(16), 257 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 258 | .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_I2S), 259 | .intr_alloc_flags = 0, 260 | .dma_buf_count = 8, 261 | .dma_buf_len = bufferLen, 262 | .use_apll = false, 263 | .tx_desc_auto_clear = false, 264 | .fixed_mclk = 0, 265 | .mclk_multiple = i2s_mclk_multiple_t(I2S_MCLK_MULTIPLE_512), 266 | .bits_per_chan = i2s_bits_per_chan_t(I2S_BITS_PER_CHAN_DEFAULT) 267 | }; 268 | 269 | i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL); 270 | } 271 | 272 | void i2s_setpin() { 273 | // Set I2S pin configuration 274 | const i2s_pin_config_t pin_config = { 275 | .mck_io_num = I2S_PIN_NO_CHANGE, 276 | .bck_io_num = I2S_SCK, 277 | .ws_io_num = I2S_WS, 278 | .data_out_num = I2S_SDO, 279 | .data_in_num = I2S_SD 280 | }; 281 | 282 | i2s_set_pin(I2S_PORT, &pin_config); 283 | } 284 | -------------------------------------------------------------------------------- /examples/Example_12_AutomaticLevelControl/Example_12_AutomaticLevelControl.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Example_12_AutomaticLevelControl.ino 3 | Demonstrates how to use the automatic level control feature of the WM8960 4 | Codec. 5 | 6 | Attach a potentiomenter to GND/A0/3V3 to actively adjust the ALC target 7 | setting. 8 | 9 | This example sets up the codec for analog audio input (on INPUT1s), ADC/DAC 10 | Loopback, sets hp volume, and Headphone output on the WM8960 Codec. 11 | 12 | Audio should be connected to both the left and right "INPUT1" inputs, 13 | they are labeled "RIN1" and "LIN1" on the board. 14 | 15 | This example will pass your audio source through the mixers and gain stages of 16 | the codec 17 | into the ADC. Turn on Loopback (so ADC is feed directly to DAC). 18 | Then send the output of the DAC to the headphone outs. 19 | 20 | We will use the user input via potentiometer on A0 to set the ALC target 21 | value. The ALC will adjust the gain of the pga input buffer to try and keep 22 | the signal level at the target. 23 | 24 | Development platform used: 25 | SparkFun ESP32 IoT RedBoard v10 26 | 27 | HARDWARE CONNECTIONS 28 | 29 | ********************** 30 | ESP32 ------- CODEC 31 | ********************** 32 | QWIIC ------- QWIIC *Note this connects GND/3.3V/SDA/SCL 33 | GND --------- GND *optional, but not a bad idea 34 | 5V ---------- VIN *needed to power codec's onboard AVDD (3.3V vreg) 35 | 36 | ********************** 37 | ESP32 -------- POTENTIOMTER (aka blue little trimpot) 38 | ********************** 39 | GND ---------- "right-side pin" 40 | A0 ----------- center pin *aka center tap connection 41 | 3V3 ---------- "left-side pin" 42 | 43 | ********************** 44 | CODEC ------- AUDIO IN 45 | ********************** 46 | GND --------- TRS INPUT SLEEVE *ground for line level input 47 | LINPUT1 ----- TRS INPUT TIP *left audio 48 | RINPUT1 ----- TRS INPUT RING1 *right audio 49 | 50 | ********************** 51 | CODEC -------- AUDIO OUT 52 | ********************** 53 | OUT3 --------- TRS OUTPUT SLEEVE *buffered "vmid" (aka "HP GND") 54 | HPL ---------- TRS OUTPUT TIP *left HP output 55 | HPR ---------- TRS OUTPUT RING1 *right HP output 56 | 57 | Pete Lewis @ SparkFun Electronics 58 | October 14th, 2022 59 | https://github.com/sparkfun/SparkFun_WM8960_Arduino_Library 60 | 61 | This code was created using some code by Mike Grusin at SparkFun Electronics 62 | Included with the LilyPad MP3 example code found here: 63 | Revision history: version 1.0 2012/07/24 MDG Initial release 64 | https://github.com/sparkfun/LilyPad_MP3_Player 65 | 66 | Do you like this library? Help support SparkFun. Buy a board! 67 | 68 | SparkFun Audio Codec Breakout - WM8960 (QWIIC) 69 | https://www.sparkfun.com/products/21250 70 | 71 | All functions return 1 if the read/write was successful, and 0 72 | if there was a communications failure. You can ignore the return value 73 | if you just don't care anymore. 74 | 75 | For information on the data sent to and received from the CODEC, 76 | refer to the WM8960 datasheet at: 77 | https://github.com/sparkfun/SparkFun_Audio_Codec_Breakout_WM8960/blob/main/Documents/WM8960_datasheet_v4.2.pdf 78 | 79 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 80 | Please review the LICENSE.md file included with this example. If you have any questions 81 | or concerns with licensing, please contact techsupport@sparkfun.com. 82 | Distributed as-is; no warranty is given. 83 | ******************************************************************************/ 84 | 85 | #include 86 | #include 87 | // Click here to get the library: http://librarymanager/All#SparkFun_WM8960 88 | WM8960 codec; 89 | 90 | // Used to store incoming potentiometer settings to set ADC digital volume 91 | // setting 92 | long userInputA0 = 0; 93 | 94 | void setup() 95 | { 96 | Serial.begin(115200); 97 | Serial.println("Example 12 - Automatic Level Control"); 98 | 99 | Wire.begin(); 100 | 101 | if (codec.begin() == false) //Begin communication over I2C 102 | { 103 | Serial.println("The device did not respond. Please check wiring."); 104 | while (1); // Freeze 105 | } 106 | Serial.println("Device is connected properly."); 107 | 108 | codec_setup(); 109 | } 110 | 111 | void loop() 112 | { 113 | // Take a bunch of readings and average them, to smooth out the value 114 | for (int i = 0 ; i < 250 ; i ++) 115 | { 116 | userInputA0 += analogRead(A0); 117 | delay(1); 118 | } 119 | userInputA0 /= 250; 120 | 121 | // Map it from 0-4096, to a value that is acceptable for the setting 122 | int alcTarget = map(userInputA0, 0, 4096, 15, 0); 123 | 124 | Serial.print("alcTarget: "); 125 | Serial.println(alcTarget); 126 | 127 | codec.setAlcTarget(alcTarget); // Valid inputs are 0-15, 0 = -22.5dB FS, ... 1.5dB steps ... , 15 = -1.5dB FS 128 | 129 | delay(1000); 130 | } 131 | 132 | void codec_setup() 133 | { 134 | // General setup needed 135 | codec.enableVREF(); 136 | codec.enableVMID(); 137 | 138 | // Setup signal flow to the ADC 139 | 140 | codec.enableLMIC(); 141 | codec.enableRMIC(); 142 | 143 | // Connect from INPUT1 to "n" (aka inverting) inputs of PGAs. 144 | codec.connectLMN1(); 145 | codec.connectRMN1(); 146 | 147 | // Disable mutes on PGA inputs (aka INTPUT1) 148 | codec.disableLINMUTE(); 149 | codec.disableRINMUTE(); 150 | 151 | // Set input boosts to get inputs 1 to the boost mixers 152 | codec.setLMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 153 | codec.setRMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 154 | 155 | codec.connectLMIC2B(); 156 | codec.connectRMIC2B(); 157 | 158 | // Enable boost mixers 159 | codec.enableAINL(); 160 | codec.enableAINR(); 161 | 162 | // Disconnect LB2LO (booster to output mixer (analog bypass) 163 | // For this example, we are going to pass audio throught the ADC and DAC 164 | codec.disableLB2LO(); 165 | codec.disableRB2RO(); 166 | 167 | // Connect from DAC outputs to output mixer 168 | codec.enableLD2LO(); 169 | codec.enableRD2RO(); 170 | 171 | // Set gainstage between booster mixer and output mixer 172 | // For this loopback example, we are going to keep these as low as they go 173 | codec.setLB2LOVOL(WM8960_OUTPUT_MIXER_GAIN_NEG_21DB); 174 | codec.setRB2ROVOL(WM8960_OUTPUT_MIXER_GAIN_NEG_21DB); 175 | 176 | // Enable output mixers 177 | codec.enableLOMIX(); 178 | codec.enableROMIX(); 179 | 180 | // CLOCK STUFF, These settings will get you 44.1KHz sample rate, and class-d 181 | // freq at 705.6kHz 182 | codec.enablePLL(); // Needed for class-d amp clock 183 | codec.setPLLPRESCALE(WM8960_PLLPRESCALE_DIV_2); 184 | codec.setSMD(WM8960_PLL_MODE_FRACTIONAL); 185 | codec.setCLKSEL(WM8960_CLKSEL_PLL); 186 | codec.setSYSCLKDIV(WM8960_SYSCLK_DIV_BY_2); 187 | codec.setBCLKDIV(4); 188 | codec.setDCLKDIV(WM8960_DCLKDIV_16); 189 | codec.setPLLN(7); 190 | codec.setPLLK(0x86, 0xC2, 0x26); // PLLK=86C226h 191 | //codec.setADCDIV(0); // Default is 000 (what we need for 44.1KHz) 192 | //codec.setDACDIV(0); // Default is 000 (what we need for 44.1KHz) 193 | 194 | codec.enableMasterMode(); 195 | codec.setALRCGPIO(); // Note, should not be changed while ADC is enabled. 196 | 197 | // Enable ADCs and DACs 198 | codec.enableAdcLeft(); 199 | codec.enableAdcRight(); 200 | codec.enableDacLeft(); 201 | codec.enableDacRight(); 202 | codec.disableDacMute(); 203 | 204 | codec.enableLoopBack(); // Loopback sends ADC data directly into DAC 205 | 206 | // Default is "soft mute" on, so we must disable mute to make channels active 207 | codec.disableDacMute(); 208 | 209 | codec.enableHeadphones(); 210 | codec.enableOUT3MIX(); // Provides VMID as buffer for headphone ground 211 | 212 | // Automatic Level control stuff 213 | 214 | // Only allows pga gain stages at a "zero crossover" point in audio stream. 215 | // Minimizes "zipper" noise when chaning gains. 216 | codec.enablePgaZeroCross(); 217 | 218 | codec.enableAlc(WM8960_ALC_MODE_STEREO); 219 | codec.setAlcTarget(WM8960_ALC_TARGET_LEVEL_NEG_6DB); 220 | codec.setAlcDecay(WM8960_ALC_DECAY_TIME_192MS); 221 | codec.setAlcAttack(WM8960_ALC_ATTACK_TIME_24MS); 222 | codec.setAlcMaxGain(WM8960_ALC_MAX_GAIN_LEVEL_30DB); 223 | codec.setAlcMinGain(WM8960_ALC_MIN_GAIN_LEVEL_NEG_17_25DB); 224 | codec.setAlcHold(WM8960_ALC_HOLD_TIME_0MS); 225 | 226 | Serial.println("Headphopne Amp Volume set to +0dB"); 227 | codec.setHeadphoneVolumeDB(0.00); 228 | 229 | Serial.println("Codec setup complete. Listen to left/right INPUT1 on Headphone outputs."); 230 | } -------------------------------------------------------------------------------- /examples/Example_13_DacGain/Example_13_DacGain.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Example_13_DacGain.ino 3 | Demonstrates how to control the volume using the codec's DAC digital volume 4 | control. 5 | 6 | Attach a potentiomenter to GND/A0/3V3 to actively adjust the setting. 7 | 8 | This example sets up the codec for analog audio input (on INPUT1s), ADC/DAC 9 | Loopback, sets hp volume, and Headphone output on the WM8960 Codec. 10 | 11 | Audio should be connected to both the left and right "INPUT1" inputs, 12 | they are labeled "RIN1" and "LIN1" on the board. 13 | 14 | This example will pass your audio source through the mixers and gain stages 15 | of the codec into the ADC. Turn on Loopback (so ADC is feed directly to DAC). 16 | Then send the output of the DAC to the headphone outs. 17 | 18 | We will use the gain stage at the DAC to control the volume of the signal. 19 | This is capable of more precision, with 255 available settings. 20 | 21 | ** DAC digital volume 22 | ** Valid dB settings are -97.00 up to +30.0 (0.5dB steps) 23 | ** -97.50 (or lower) = MUTE 24 | ** -97.00 = -97.00dB (MIN) 25 | ** ... 0.5dB steps ... 26 | ** 30.00 = +30.00dB (MAX) 27 | 28 | You can also control the volume of the codecs built in headphone amp using 29 | this function: 30 | 31 | codec.setHeadphoneVolumeDB(6.00); Valid inputs are -74.00 (MUTE) up to +6.00, 32 | (1.00dB steps). 33 | 34 | Development platform used: 35 | SparkFun ESP32 IoT RedBoard v10 36 | 37 | HARDWARE CONNECTIONS 38 | 39 | ********************** 40 | ESP32 ------- CODEC 41 | ********************** 42 | QWIIC ------- QWIIC *Note this connects GND/3.3V/SDA/SCL 43 | GND --------- GND *optional, but not a bad idea 44 | 5V ---------- VIN *needed to power codec's onboard AVDD (3.3V vreg) 45 | 46 | ********************** 47 | ESP32 -------- POTENTIOMTER (aka blue little trimpot) 48 | ********************** 49 | GND ---------- "right-side pin" 50 | A0 ----------- center pin *aka center tap connection 51 | 3V3 ---------- "left-side pin" 52 | 53 | ********************** 54 | CODEC ------- AUDIO IN 55 | ********************** 56 | GND --------- TRS INPUT SLEEVE *ground for line level input 57 | LINPUT1 ----- TRS INPUT TIP *left audio 58 | RINPUT1 ----- TRS INPUT RING1 *right audio 59 | 60 | ********************** 61 | CODEC -------- AUDIO OUT 62 | ********************** 63 | OUT3 --------- TRS OUTPUT SLEEVE 64 | HPL ---------- TRS OUTPUT TIP *left HP output 65 | HPR ---------- TRS OUTPUT RING1 *right HP output 66 | 67 | Pete Lewis @ SparkFun Electronics 68 | October 14th, 2022 69 | https://github.com/sparkfun/SparkFun_WM8960_Arduino_Library 70 | 71 | This code was created using some code by Mike Grusin at SparkFun Electronics 72 | Included with the LilyPad MP3 example code found here: 73 | Revision history: version 1.0 2012/07/24 MDG Initial release 74 | https://github.com/sparkfun/LilyPad_MP3_Player 75 | 76 | Do you like this library? Help support SparkFun. Buy a board! 77 | 78 | SparkFun Audio Codec Breakout - WM8960 (QWIIC) 79 | https://www.sparkfun.com/products/21250 80 | 81 | All functions return 1 if the read/write was successful, and 0 82 | if there was a communications failure. You can ignore the return value 83 | if you just don't care anymore. 84 | 85 | For information on the data sent to and received from the CODEC, 86 | refer to the WM8960 datasheet at: 87 | https://github.com/sparkfun/SparkFun_Audio_Codec_Breakout_WM8960/blob/main/Documents/WM8960_datasheet_v4.2.pdf 88 | 89 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 90 | Please review the LICENSE.md file included with this example. If you have any questions 91 | or concerns with licensing, please contact techsupport@sparkfun.com. 92 | Distributed as-is; no warranty is given. 93 | ******************************************************************************/ 94 | 95 | #include 96 | #include 97 | // Click here to get the library: http://librarymanager/All#SparkFun_WM8960 98 | WM8960 codec; 99 | 100 | // Used to store incoming potentiometer settings to set ADC digital volume 101 | // setting 102 | long userInputA0 = 0; 103 | 104 | void setup() 105 | { 106 | Serial.begin(115200); 107 | Serial.println("Example 13 - DAC Digital Volume Control"); 108 | 109 | Wire.begin(); 110 | 111 | if (codec.begin() == false) //Begin communication over I2C 112 | { 113 | Serial.println("The device did not respond. Please check wiring."); 114 | while (1); // Freeze 115 | } 116 | Serial.println("Device is connected properly."); 117 | 118 | codec_setup(); 119 | } 120 | 121 | void loop() 122 | { 123 | // Take a bunch of readings and average them, to smooth out the value 124 | for (int i = 0 ; i < 250 ; i ++) 125 | { 126 | userInputA0 += analogRead(A0); 127 | delay(1); 128 | } 129 | 130 | // After taking a bunch of samples, divide down to the average single reading 131 | userInputA0 /= 250; 132 | 133 | // Map it from 0-4096, to a dB value that is acceptable in the DAC digital 134 | // volume control (-97.50 [MUTE] to +30dB) 135 | float dacVolumeDB = mapFloats((float)userInputA0, 0.00, 4096.00, 30.00, -97.50); 136 | 137 | Serial.print("dacVolumeDB: "); 138 | Serial.println(dacVolumeDB); 139 | 140 | codec.setDacLeftDigitalVolumeDB(dacVolumeDB); // -97.50 to +30.00dB 141 | codec.setDacRightDigitalVolumeDB(dacVolumeDB); // -97.50 to +30.00dB 142 | 143 | delay(50); 144 | } 145 | 146 | void codec_setup() 147 | { 148 | // General setup needed 149 | codec.enableVREF(); 150 | codec.enableVMID(); 151 | 152 | // Setup signal flow to the ADC 153 | 154 | codec.enableLMIC(); 155 | codec.enableRMIC(); 156 | 157 | // Connect from INPUT1 to "n" (aka inverting) inputs of PGAs. 158 | codec.connectLMN1(); 159 | codec.connectRMN1(); 160 | 161 | // Disable mutes on PGA inputs (aka INTPUT1) 162 | codec.disableLINMUTE(); 163 | codec.disableRINMUTE(); 164 | 165 | // Set input boosts to get inputs 1 to the boost mixers 166 | codec.setLMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 167 | codec.setRMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 168 | 169 | codec.connectLMIC2B(); 170 | codec.connectRMIC2B(); 171 | 172 | // Enable boost mixers 173 | codec.enableAINL(); 174 | codec.enableAINR(); 175 | 176 | // Disconnect LB2LO (booster to output mixer (analog bypass) 177 | // For this example, we are going to pass audio throught the ADC and DAC 178 | codec.disableLB2LO(); 179 | codec.disableRB2RO(); 180 | 181 | // Connect from DAC outputs to output mixer 182 | codec.enableLD2LO(); 183 | codec.enableRD2RO(); 184 | 185 | // Set gainstage between booster mixer and output mixer 186 | // For this loopback example, we are going to keep these as low as they go 187 | codec.setLB2LOVOL(WM8960_OUTPUT_MIXER_GAIN_NEG_21DB); 188 | codec.setRB2ROVOL(WM8960_OUTPUT_MIXER_GAIN_NEG_21DB); 189 | 190 | // Enable output mixers 191 | codec.enableLOMIX(); 192 | codec.enableROMIX(); 193 | 194 | // CLOCK STUFF, These settings will get you 44.1KHz sample rate, and class-d 195 | // freq at 705.6kHz 196 | codec.enablePLL(); // Needed for class-d amp clock 197 | codec.setPLLPRESCALE(WM8960_PLLPRESCALE_DIV_2); 198 | codec.setSMD(WM8960_PLL_MODE_FRACTIONAL); 199 | codec.setCLKSEL(WM8960_CLKSEL_PLL); 200 | codec.setSYSCLKDIV(WM8960_SYSCLK_DIV_BY_2); 201 | codec.setBCLKDIV(4); 202 | codec.setDCLKDIV(WM8960_DCLKDIV_16); 203 | codec.setPLLN(7); 204 | codec.setPLLK(0x86, 0xC2, 0x26); // PLLK=86C226h 205 | //codec.setADCDIV(0); // Default is 000 (what we need for 44.1KHz) 206 | //codec.setDACDIV(0); // Default is 000 (what we need for 44.1KHz) 207 | 208 | codec.enableMasterMode(); 209 | codec.setALRCGPIO(); // Note, should not be changed while ADC is enabled. 210 | 211 | // Enable ADCs and DACs 212 | codec.enableAdcLeft(); 213 | codec.enableAdcRight(); 214 | codec.enableDacLeft(); 215 | codec.enableDacRight(); 216 | codec.disableDacMute(); 217 | 218 | codec.enableLoopBack(); // Loopback sends ADC data directly into DAC 219 | 220 | // Default is "soft mute" on, so we must disable mute to make channels active 221 | codec.disableDacMute(); 222 | 223 | codec.enableHeadphones(); 224 | codec.enableOUT3MIX(); // Provides VMID as buffer for headphone ground 225 | 226 | Serial.println("Headphopne Amp Volume set to +0dB"); 227 | codec.setHeadphoneVolumeDB(0.00); 228 | 229 | Serial.println("Codec setup complete. Listen to left/right INPUT1 on Headphone outputs."); 230 | } 231 | 232 | // mapFloat 233 | // This function is the same as the Arduino map() function, but it can accept 234 | // and return float values. We need this to handle dB values which are floats 235 | // 236 | // value: the number to map. 237 | // 238 | // fromLow: the lower bound of the value’s current range. 239 | // 240 | // fromHigh: the upper bound of the value’s current range. 241 | // 242 | // toLow: the lower bound of the value’s target range. 243 | // 244 | // toHigh: the upper bound of the value’s target range. 245 | 246 | float mapFloats(float value, float fromLow, float fromHigh, float toLow, float toHigh) 247 | { 248 | return (value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow) + toLow; 249 | } -------------------------------------------------------------------------------- /examples/Example_14_ElectretMics/Example_14_ElectretMics.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Example_14_ElectretMics.ino 3 | Demonstrates electret microphone analog audio input (on INPUT1/INPUT2 as 4 | "pseudo-differential MIC configuration"). Sets the PGA gain, sets the 5 | non-inverting pga input to INPUT2s, sets volume control, and headphone output 6 | on the WM8960 Codec. 7 | 8 | Note, most of the examples in this library set all gain stages at 0dB, but for 9 | this electret mic example, we need a bit more gain on the initial input stage 10 | (the PGA), so we set it to +24dB (aka "57" as the argument to the function). 11 | We are also bumping up the headphone output gainstage to max, +6dB (aka "127"). 12 | 13 | Electret mics should be connected to left and right inputs. 14 | 15 | MicBias should be provided to the "+" side of each mic via an in-series 2.2K 16 | resistor. 17 | 18 | The Mic "-" should be connected to each INPUT2. Note, this is also GND in this 19 | example, but enables a "psuedo-differential setup" 20 | 21 | This example will pass your audio source through the mixers and gain stages of 22 | the codec using all of the analog bypass paths. 23 | 24 | It will output the sound on the headphone outputs. 25 | It is setup to do a capless headphone setup, so connet your headphones ground 26 | to "OUT3" and this provides a buffered VMID. 27 | 28 | You can now control the volume of the codecs built in headphone buffers using 29 | this function: 30 | 31 | codec.setHeadphoneVolumeDB(6.00); Valid inputs are -74.00 (MUTE) up to +6.00, 32 | (1.00dB steps). 33 | 34 | Development platform used: 35 | SparkFun ESP32 IoT RedBoard v10 36 | 37 | HARDWARE CONNECTIONS 38 | See Datasheet page 25 for electret mic hardware hookup example diagrams. 39 | https://github.com/sparkfun/SparkFun_Audio_Codec_Breakout_WM8960/blob/main/Documents/WM8960_datasheet_v4.2.pdf 40 | 41 | ********************** 42 | ESP32 ------- CODEC 43 | ********************** 44 | QWIIC ------- QWIIC *Note this connects GND/3.3V/SDA/SCL 45 | GND --------- GND *optional, but not a bad idea 46 | 5V ---------- VIN *needed to power codec's onboard AVDD (3.3V vreg) 47 | 48 | ********************** 49 | CODEC ------- AUDIO IN (ELECTRET MICS) 50 | ********************** 51 | GND --------- LEFT MIC - 52 | LINPUT1 ----- LEFT MIC - 53 | LINPUT2 ----- LEFT MIC + 54 | MICBIAS ----- 2.2K RESISTOR ----- LEFT MIC+ 55 | GND --------- RIGHT MIC - 56 | RINPUT1 ----- RIGHT MIC - 57 | RINPUT2 ----- RIGHT MIC + 58 | MICBIAS ----- 2.2K RESISTOR ----- RIGHT MIC+ 59 | 60 | ********************** 61 | CODEC -------- AUDIO OUT 62 | ********************** 63 | OUT3 --------- TRS OUTPUT SLEEVE *buffered "vmid" (aka "HP GND") 64 | HPL ---------- TRS OUTPUT TIP *left HP output 65 | HPR ---------- TRS OUTPUT RING1 *right HP output 66 | 67 | Pete Lewis @ SparkFun Electronics 68 | October 14th, 2022 69 | https://github.com/sparkfun/SparkFun_WM8960_Arduino_Library 70 | 71 | This code was created using some code by Mike Grusin at SparkFun Electronics 72 | Included with the LilyPad MP3 example code found here: 73 | Revision history: version 1.0 2012/07/24 MDG Initial release 74 | https://github.com/sparkfun/LilyPad_MP3_Player 75 | 76 | Do you like this library? Help support SparkFun. Buy a board! 77 | 78 | SparkFun Audio Codec Breakout - WM8960 (QWIIC) 79 | https://www.sparkfun.com/products/21250 80 | 81 | All functions return 1 if the read/write was successful, and 0 82 | if there was a communications failure. You can ignore the return value 83 | if you just don't care anymore. 84 | 85 | For information on the data sent to and received from the CODEC, 86 | refer to the WM8960 datasheet at: 87 | https://github.com/sparkfun/SparkFun_Audio_Codec_Breakout_WM8960/blob/main/Documents/WM8960_datasheet_v4.2.pdf 88 | 89 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 90 | Please review the LICENSE.md file included with this example. If you have any questions 91 | or concerns with licensing, please contact techsupport@sparkfun.com. 92 | Distributed as-is; no warranty is given. 93 | ******************************************************************************/ 94 | 95 | #include 96 | #include 97 | // Click here to get the library: http://librarymanager/All#SparkFun_WM8960 98 | WM8960 codec; 99 | 100 | void setup() 101 | { 102 | Serial.begin(115200); 103 | Serial.println("Example 14 - Electret Mics"); 104 | 105 | Wire.begin(); 106 | 107 | if (codec.begin() == false) //Begin communication over I2C 108 | { 109 | Serial.println("The device did not respond. Please check wiring."); 110 | while (1); // Freeze 111 | } 112 | Serial.println("Device is connected properly."); 113 | 114 | // General setup needed 115 | codec.enableVREF(); 116 | codec.enableVMID(); 117 | 118 | codec.enableMicBias(); 119 | 120 | // WM8960_MIC_BIAS_VOLTAGE_0_9_AVDD (0.9*AVDD) or 121 | // WM8960_MIC_BIAS_VOLTAGE_0_65_AVDD (0.65*AVDD) 122 | codec.setMicBiasVoltage(WM8960_MIC_BIAS_VOLTAGE_0_9_AVDD); 123 | Serial.println("Mic Bias enabled (0.9*AVDD)"); 124 | 125 | // Setup signal flow through the analog audio bypass connections 126 | 127 | codec.enableLMIC(); 128 | codec.enableRMIC(); 129 | 130 | // Connect from INPUT1 to "n" (aka inverting) inputs of PGAs. 131 | codec.connectLMN1(); 132 | codec.connectRMN1(); 133 | 134 | // Disable mutes on PGA inputs (aka INTPUT1) 135 | codec.disableLINMUTE(); 136 | codec.disableRINMUTE(); 137 | 138 | // Set pga volumes 139 | codec.setLINVOLDB(24.00); // Valid options are -17.25dB to +30.00dB 140 | codec.setRINVOLDB(24.00); // Valid options are -17.25dB to +30.00dB 141 | Serial.println("PGA gain set to +24dB"); 142 | 143 | // Set input boosts to get inputs 1 to the boost mixers 144 | codec.setLMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 145 | codec.setRMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 146 | Serial.println("Mic boost stage set to 0dB"); 147 | 148 | // For MIC+ signal of differential mic signal 149 | codec.pgaLeftNonInvSignalSelect(WM8960_PGAL_LINPUT2); 150 | 151 | // For MIC+ signal of differential mic signal 152 | codec.pgaRightNonInvSignalSelect(WM8960_PGAR_RINPUT2); 153 | Serial.println("Pga non-inverting inputs set to INPUT2s"); 154 | 155 | codec.connectLMIC2B(); 156 | codec.connectRMIC2B(); 157 | 158 | // Enable boost mixers 159 | codec.enableAINL(); 160 | codec.enableAINR(); 161 | 162 | // Connect LB2LO (booster to output mixer (analog bypass) 163 | codec.enableLB2LO(); 164 | codec.enableRB2RO(); 165 | 166 | // Set gainstage between booster mixer and output mixer 167 | codec.setLB2LOVOL(WM8960_OUTPUT_MIXER_GAIN_0DB); 168 | codec.setRB2ROVOL(WM8960_OUTPUT_MIXER_GAIN_0DB); 169 | 170 | // Enable output mixers 171 | codec.enableLOMIX(); 172 | codec.enableROMIX(); 173 | 174 | codec.enableHeadphones(); 175 | codec.enableOUT3MIX(); // Provides VMID as buffer for headphone ground 176 | 177 | Serial.println("Headphone output buffer volume set to +6dB (max)"); 178 | codec.setHeadphoneVolumeDB(6.00); 179 | 180 | Serial.println("Example complete. Listen to Electret mics on headphone outputs."); 181 | } 182 | 183 | void loop() 184 | { 185 | // Nothing to see here. 186 | } -------------------------------------------------------------------------------- /examples/Example_15_VolumePlotter_MEMS_Mic_Differential/Example_15_VolumePlotter_MEMS_Mic_Differential.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Example_15_VolumePlotter_MEMS_Mic_Differential.ino 3 | This example is very similar to example 11, however it uses a MEMS mic with 4 | differential signal as the source of the sound. Here we are using just one of 5 | VM2020 Breakouts plugged into the left channel. 6 | 7 | Note, with this VM2020 differential mic signal, we are going to add much more 8 | gain than in previous examples. We are going to use a MICBOOST of 29dB (max), 9 | and set the PGA to +8.25dB. 10 | 11 | Demonstrates reading I2S audio from the ADC, and plotting the audio samples on 12 | the Arduino Serial Plotter. 13 | 14 | This example sets up differential analog audio input (on LINPUT1/LINPUT2), 15 | ADC enabled as I2S peripheral, sets volume control, and Headphone output on 16 | the WM8960 Codec. 17 | 18 | A MEMS mic should be connected to the left channel INPUT1 and INPUT2, they are 19 | labeled "LIN1" and "LIN2" on the board. These will provide the input 20 | connections for the positive and negative signals from the MEMS mic. 21 | 22 | This example will pass your audio source through the mixers and gain stages of 23 | the codec into the ADC. Read the audio from the ADC via I2S. 24 | 25 | The analog bypass paths is also setup, so your audio will pass through the 26 | codec and playback on HP outs. 27 | 28 | Development platform used: 29 | SparkFun ESP32 IoT RedBoard v10 30 | 31 | HARDWARE CONNECTIONS 32 | 33 | ********************** 34 | ESP32 ------- CODEC 35 | ********************** 36 | QWIIC ------- QWIIC *Note this connects GND/3.3V/SDA/SCL 37 | GND --------- GND *optional, but not a bad idea 38 | 5V ---------- VIN *needed to power codec's onboard AVDD (3.3V vreg) 39 | 16 ---------- BCK *aka BCLK/I2S_SCK/"bit clock", this is the clock for I2S audio, can be controlled via controller or peripheral. 40 | 17 ---------- ADAT *aka ADC_DATA/I2S_SD/"serial data in", this carries the I2S audio data from codec's ADC to ESP32 I2S bus. 41 | 25 ---------- ALR *aka I2S_WS/LRC/"word select"/"left-right-channel", this toggles for left or right channel data. 42 | 43 | ********************** 44 | CODEC ------- MIC IN 45 | ********************** 46 | GND --------- GND *Ground 47 | AVDD -------- VCC *3.3V (default on the Codec breakout) 48 | LINPUT1 ----- OUT- *Mic signal "-" 49 | LINPUT2 ----- OUT+ *Mic signal "+" 50 | 51 | ********************** 52 | CODEC -------- AUDIO OUT 53 | ********************** 54 | OUT3 --------- TRS OUTPUT SLEEVE *buffered "vmid" (aka "HP GND") 55 | HPL ---------- TRS OUTPUT TIP *left HP output 56 | HPR ---------- TRS OUTPUT RING1 *right HP output 57 | 58 | You can now control the volume of the codecs built in headphone amp using this 59 | fuction: 60 | 61 | codec.setHeadphoneVolumeDB(6.00); Valid inputs are -74.00 (MUTE) up to +6.00, 62 | (1.00dB steps). 63 | 64 | Pete Lewis @ SparkFun Electronics 65 | October 14th, 2022 66 | https://github.com/sparkfun/SparkFun_WM8960_Arduino_Library 67 | 68 | This code was created using some code by Mike Grusin at SparkFun Electronics 69 | Included with the LilyPad MP3 example code found here: 70 | Revision history: version 1.0 2012/07/24 MDG Initial release 71 | https://github.com/sparkfun/LilyPad_MP3_Player 72 | 73 | This code was created using some modified code from DroneBot Workshop. 74 | Specifically, the I2S configuration setup was super helpful to get I2S working. 75 | This example has a similar I2S config to what we are using here: Microphone to 76 | serial plotter example. Although, here we are doing a line level TRS audio 77 | input into the codec. To see the original Drone Workshop code and learn more 78 | about I2S in general, please visit: https://dronebotworkshop.com/esp32-i2s/ 79 | 80 | Do you like this library? Help support SparkFun. Buy a board! 81 | 82 | SparkFun Audio Codec Breakout - WM8960 (QWIIC) 83 | https://www.sparkfun.com/products/21250 84 | 85 | SparkFun Analog MEMS Microphone Breakout - VM2020 86 | https://www.sparkfun.com/products/21537 87 | 88 | All functions return 1 if the read/write was successful, and 0 89 | if there was a communications failure. You can ignore the return value 90 | if you just don't care anymore. 91 | 92 | For information on the data sent to and received from the CODEC, 93 | refer to the WM8960 datasheet at: 94 | https://github.com/sparkfun/SparkFun_Audio_Codec_Breakout_WM8960/blob/main/Documents/WM8960_datasheet_v4.2.pdf 95 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 96 | Please review the LICENSE.md file included with this example. If you have any questions 97 | or concerns with licensing, please contact techsupport@sparkfun.com. 98 | Distributed as-is; no warranty is given. 99 | ******************************************************************************/ 100 | 101 | #include 102 | #include 103 | // Click here to get the library: http://librarymanager/All#SparkFun_WM8960 104 | WM8960 codec; 105 | 106 | // Include I2S driver 107 | #include 108 | 109 | // Connections to I2S 110 | #define I2S_WS 25 111 | #define I2S_SD 17 112 | #define I2S_SDO 4 // Not used for this example 113 | #define I2S_SCK 16 114 | 115 | // Use I2S Processor 0 116 | #define I2S_PORT I2S_NUM_0 117 | 118 | // Define input buffer length 119 | #define bufferLen 64 120 | int16_t sBuffer[bufferLen]; 121 | 122 | void setup() 123 | { 124 | Serial.begin(115200); 125 | 126 | Wire.begin(); 127 | 128 | if (codec.begin() == false) //Begin communication over I2C 129 | { 130 | Serial.println("The device did not respond. Please check wiring."); 131 | while (1); // Freeze 132 | } 133 | 134 | codec_setup(); 135 | 136 | // Set up I2S 137 | i2s_install(); 138 | i2s_setpin(); 139 | i2s_start(I2S_PORT); 140 | } 141 | 142 | void loop() 143 | { 144 | 145 | // False print statements to "lock range" on serial plotter display 146 | // Change rangelimit value to adjust "sensitivity" 147 | int rangelimit = 3000; 148 | Serial.print(rangelimit * -1); 149 | Serial.print(" "); 150 | Serial.print(rangelimit); 151 | Serial.print(" "); 152 | 153 | // Get I2S data and place in data buffer 154 | size_t bytesIn = 0; 155 | esp_err_t result = i2s_read(I2S_PORT, &sBuffer, bufferLen, &bytesIn, portMAX_DELAY); 156 | 157 | if (result == ESP_OK) 158 | { 159 | // Read I2S data buffer 160 | int16_t samples_read = bytesIn / 8; 161 | if (samples_read > 0) { 162 | float mean = 0; 163 | // Only looking at left signal samples in the buffer (e.g. 0,2,4,6,8...) 164 | // Notice in our for loop here, we are incrementing the index by 2. 165 | for (int16_t i = 0; i < samples_read; i += 2) { 166 | mean += (sBuffer[i]); 167 | } 168 | 169 | // Average the data reading 170 | // We're only concerned with left input for this example. So we must 171 | // divide by "half of samples read" (because it is stereo I2S audio data) 172 | mean /= (samples_read / 2); 173 | 174 | // Print to serial plotter 175 | Serial.println(mean); 176 | } 177 | } 178 | } 179 | 180 | void codec_setup() 181 | { 182 | // General setup needed 183 | codec.enableVREF(); 184 | codec.enableVMID(); 185 | 186 | // Setup signal flow to the ADC 187 | 188 | codec.enableLMIC(); 189 | codec.enableRMIC(); 190 | 191 | // Connect from INPUT1 to "n" (aka inverting) inputs of PGAs. 192 | codec.connectLMN1(); 193 | codec.connectRMN1(); 194 | 195 | // Disable mutes on PGA inputs (aka INTPUT1) 196 | codec.disableLINMUTE(); 197 | codec.disableRINMUTE(); 198 | 199 | // Set pga volumes 200 | codec.setLINVOLDB(8.25); // Valid options are -17.25dB to +30dB (0.75dB steps) 201 | codec.setRINVOLDB(8.25); // Valid options are -17.25dB to +30dB (0.75dB steps) 202 | 203 | // Set input boosts to get inputs 1 to the boost mixers 204 | codec.setLMICBOOST(WM8960_MIC_BOOST_GAIN_29DB); 205 | codec.setRMICBOOST(WM8960_MIC_BOOST_GAIN_29DB); 206 | 207 | // For MIC+ signal of differential mic signal 208 | codec.pgaLeftNonInvSignalSelect(WM8960_PGAL_LINPUT2); 209 | 210 | // For MIC+ signal of differential mic signal 211 | codec.pgaRightNonInvSignalSelect(WM8960_PGAR_RINPUT2); 212 | 213 | // Connect from MIC inputs (aka pga output) to boost mixers 214 | codec.connectLMIC2B(); 215 | codec.connectRMIC2B(); 216 | 217 | // Enable boost mixers 218 | codec.enableAINL(); 219 | codec.enableAINR(); 220 | 221 | // Connect LB2LO (booster to output mixer (analog bypass) 222 | codec.enableLB2LO(); 223 | codec.enableRB2RO(); 224 | 225 | // Disconnect from DAC outputs to output mixer 226 | codec.disableLD2LO(); 227 | codec.disableRD2RO(); 228 | 229 | // Set gainstage between booster mixer and output mixer 230 | codec.setLB2LOVOL(WM8960_OUTPUT_MIXER_GAIN_0DB); 231 | codec.setRB2ROVOL(WM8960_OUTPUT_MIXER_GAIN_0DB); 232 | 233 | // Enable output mixers 234 | codec.enableLOMIX(); 235 | codec.enableROMIX(); 236 | 237 | // CLOCK STUFF, These settings will get you 44.1KHz sample rate, and class-d 238 | // freq at 705.6kHz 239 | codec.enablePLL(); // Needed for class-d amp clock 240 | codec.setPLLPRESCALE(WM8960_PLLPRESCALE_DIV_2); 241 | codec.setSMD(WM8960_PLL_MODE_FRACTIONAL); 242 | codec.setCLKSEL(WM8960_CLKSEL_PLL); 243 | codec.setSYSCLKDIV(WM8960_SYSCLK_DIV_BY_2); 244 | codec.setBCLKDIV(4); 245 | codec.setDCLKDIV(WM8960_DCLKDIV_16); 246 | codec.setPLLN(7); 247 | codec.setPLLK(0x86, 0xC2, 0x26); // PLLK=86C226h 248 | //codec.setADCDIV(0); // Default is 000 (what we need for 44.1KHz) 249 | //codec.setDACDIV(0); // Default is 000 (what we need for 44.1KHz) 250 | codec.setWL(WM8960_WL_16BIT); 251 | 252 | codec.enablePeripheralMode(); 253 | //codec.enableMasterMode(); 254 | //codec.setALRCGPIO(); // Note, should not be changed while ADC is enabled. 255 | 256 | // Enable ADCs, and disable DACs 257 | codec.enableAdcLeft(); 258 | codec.enableAdcRight(); 259 | codec.disableDacLeft(); 260 | codec.disableDacRight(); 261 | codec.disableDacMute(); 262 | 263 | //codec.enableLoopBack(); // Loopback sends ADC data directly into DAC 264 | codec.disableLoopBack(); 265 | 266 | // Default is "soft mute" on, so we must disable mute to make channels active 267 | codec.enableDacMute(); 268 | 269 | codec.enableHeadphones(); 270 | codec.enableOUT3MIX(); // Provides VMID as buffer for headphone ground 271 | 272 | codec.setHeadphoneVolumeDB(6.00); 273 | } 274 | 275 | void i2s_install() { 276 | // Set up I2S Processor configuration 277 | const i2s_driver_config_t i2s_config = { 278 | .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX), 279 | .sample_rate = 44100, 280 | .bits_per_sample = i2s_bits_per_sample_t(16), 281 | .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, 282 | .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_I2S), 283 | .intr_alloc_flags = 0, 284 | .dma_buf_count = 8, 285 | .dma_buf_len = bufferLen, 286 | .use_apll = false, 287 | .tx_desc_auto_clear = false, 288 | .fixed_mclk = 0, 289 | .mclk_multiple = i2s_mclk_multiple_t(I2S_MCLK_MULTIPLE_512), 290 | .bits_per_chan = i2s_bits_per_chan_t(I2S_BITS_PER_CHAN_DEFAULT) 291 | }; 292 | 293 | i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL); 294 | } 295 | 296 | void i2s_setpin() { 297 | // Set I2S pin configuration 298 | const i2s_pin_config_t pin_config = { 299 | .mck_io_num = I2S_PIN_NO_CHANGE, 300 | .bck_io_num = I2S_SCK, 301 | .ws_io_num = I2S_WS, 302 | .data_out_num = I2S_SDO, 303 | .data_in_num = I2S_SD 304 | }; 305 | 306 | i2s_set_pin(I2S_PORT, &pin_config); 307 | } 308 | -------------------------------------------------------------------------------- /examples/Example_16_JackDetect/Example_16_JackDetect.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | Example_16_JackDetect.ino 3 | Demonstrates Jack Detection Feature of the Codec. 4 | 5 | This example sets up analog audio input (on INPUT1s), and then uses jack detection 6 | to set the output to either the speakers or the headphones. 7 | 8 | Note, you will need a TRS connector that has a "shunt switch" on the ground sleeve. 9 | Something like the SparkFun Audio Jack - 1/4" Stereo (right angle) found here: 10 | https://www.sparkfun.com/products/11141 11 | 12 | When headphones are inserted into your TRS barrel jack input, this releases the 13 | SHUNT pin on the TRS breakout. We will setup the codec to detect when headphones 14 | are inserted watching the LEFT INPUT 3 pin. 15 | 16 | Audio should be connected to both the left and right "INPUT1" inputs, 17 | they are labeled "RIN1" and "LIN1" on the board. 18 | 19 | This example will pass your audio source through the mixers and gain stages of 20 | the codec using all of the analog bypass paths. 21 | 22 | It will output the sound on the Speakers or the headphone outputs. 23 | It is setup to do a capless headphone setup, so connect your headphones ground 24 | to "OUT3" and this provides a buffered VMID. 25 | 26 | You can now control the volume of the codecs built in headphone buffers using 27 | this function: 28 | 29 | codec.setHeadphoneVolumeDB(6.00); Valid inputs are -74.00 (MUTE) up to +6.00, 30 | (1.00dB steps). 31 | 32 | Development platform used: 33 | SparkFun ESP32 IoT RedBoard v10 34 | 35 | HARDWARE CONNECTIONS 36 | 37 | ********************** 38 | CODEC 39 | ********************** 40 | LINPUT3 ----- 33K Resistor ----- AVDD (3.3V) 41 | 42 | ********************** 43 | ESP32 ------- CODEC 44 | ********************** 45 | QWIIC ------- QWIIC *Note this connects GND/3.3V/SDA/SCL 46 | GND --------- GND *optional, but not a bad idea 47 | 5V ---------- VIN *needed to power codec's onboard AVDD (3.3V vreg) 48 | 49 | ********************** 50 | CODEC ------- AUDIO IN 51 | ********************** 52 | GND --------- TRS INPUT SLEEVE *ground for line level input 53 | LINPUT1 ----- TRS INPUT TIP *left audio 54 | RINPUT1 ----- TRS INPUT RING1 *right audio 55 | LINPUT3 ----- TRS INPUT GND SHUNT *GND shunt pin for headphone detect 56 | *Insertion of headphones will release this pin 57 | *from being connected to GND. 58 | 59 | ********************** 60 | CODEC -------- AUDIO OUT 61 | ********************** 62 | OUT3 --------- TRS OUTPUT SLEEVE *buffered "vmid" (aka "HP GND") 63 | HPL ---------- TRS OUTPUT TIP *left HP output 64 | HPR ---------- TRS OUTPUT RING1 *right HP output 65 | 66 | Pete Lewis @ SparkFun Electronics 67 | October 30th, 2024 68 | https://github.com/sparkfun/SparkFun_WM8960_Arduino_Library 69 | 70 | Support for the jack detect feature was contributed by Harald Klien (github @haklein) 71 | October 2024. https://github.com/sparkfun/SparkFun_WM8960_Arduino_Library/pull/9 72 | Thank you Harald!! 73 | 74 | This code was created using some code by Mike Grusin at SparkFun Electronics 75 | Included with the LilyPad MP3 example code found here: 76 | Revision history: version 1.0 2012/07/24 MDG Initial release 77 | https://github.com/sparkfun/LilyPad_MP3_Player 78 | 79 | Do you like this library? Help support SparkFun. Buy a board! 80 | 81 | SparkFun Audio Codec Breakout - WM8960 (QWIIC) 82 | https://www.sparkfun.com/products/21250 83 | 84 | All functions return 1 if the read/write was successful, and 0 85 | if there was a communications failure. You can ignore the return value 86 | if you just don't care anymore. 87 | 88 | For information on the data sent to and received from the CODEC, 89 | refer to the WM8960 datasheet at: 90 | https://github.com/sparkfun/SparkFun_Audio_Codec_Breakout_WM8960/blob/main/Documents/WM8960_datasheet_v4.2.pdf 91 | 92 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 93 | Please review the LICENSE.md file included with this example. If you have any questions 94 | or concerns with licensing, please contact techsupport@sparkfun.com. 95 | Distributed as-is; no warranty is given. 96 | ******************************************************************************/ 97 | 98 | #include 99 | #include 100 | // Click here to get the library: http://librarymanager/All#SparkFun_WM8960 101 | WM8960 codec; 102 | 103 | void setup() 104 | { 105 | Serial.begin(115200); 106 | Serial.println("Example 3 - INPUT1"); 107 | 108 | Wire.begin(); 109 | 110 | if (codec.begin() == false) //Begin communication over I2C 111 | { 112 | Serial.println("The device did not respond. Please check wiring."); 113 | while (1); // Freeze 114 | } 115 | Serial.println("Device is connected properly."); 116 | 117 | // General setup needed 118 | codec.enableVREF(); 119 | codec.enableVMID(); 120 | 121 | // Setup signal flow through the analog audio bypass connections 122 | 123 | codec.enableLMIC(); 124 | codec.enableRMIC(); 125 | 126 | // Connect from INPUT1 to "n" (aka inverting) inputs of PGAs. 127 | codec.connectLMN1(); 128 | codec.connectRMN1(); 129 | 130 | // Disable mutes on PGA inputs (aka INTPUT1) 131 | codec.disableLINMUTE(); 132 | codec.disableRINMUTE(); 133 | 134 | // Set input boosts to get inputs 1 to the boost mixers 135 | codec.setLMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 136 | codec.setRMICBOOST(WM8960_MIC_BOOST_GAIN_0DB); 137 | 138 | codec.connectLMIC2B(); 139 | codec.connectRMIC2B(); 140 | 141 | // Enable boost mixers 142 | codec.enableAINL(); 143 | codec.enableAINR(); 144 | 145 | // Connect LB2LO (booster to output mixer (analog bypass) 146 | codec.enableLB2LO(); 147 | codec.enableRB2RO(); 148 | 149 | // Set gainstage between booster mixer and output mixer 150 | codec.setLB2LOVOL(WM8960_OUTPUT_MIXER_GAIN_0DB); 151 | codec.setRB2ROVOL(WM8960_OUTPUT_MIXER_GAIN_0DB); 152 | 153 | // Enable output mixers 154 | codec.enableLOMIX(); 155 | codec.enableROMIX(); 156 | 157 | // Enable Speaker output 158 | // CLOCK STUFF, These settings will get you 44.1KHz sample rate, and class-d 159 | // freq at 705.6kHz 160 | codec.enablePLL(); // Needed for class-d amp clock 161 | codec.setPLLPRESCALE(WM8960_PLLPRESCALE_DIV_2); 162 | codec.setSMD(WM8960_PLL_MODE_FRACTIONAL); 163 | codec.setCLKSEL(WM8960_CLKSEL_PLL); 164 | codec.setSYSCLKDIV(WM8960_SYSCLK_DIV_BY_2); 165 | codec.setDCLKDIV(WM8960_DCLKDIV_16); 166 | codec.setPLLN(7); 167 | codec.setPLLK(0x86, 0xC2, 0x26); // PLLK=86C226h 168 | 169 | codec.enableSpeakers(); 170 | Serial.println("Speakers enabled."); 171 | codec.setSpeakerVolumeDB(0.00); 172 | Serial.println("Volume set to +0dB"); 173 | 174 | // Enable Headphone output 175 | codec.enableHeadphones(); 176 | codec.enableOUT3MIX(); // Provides VMID as buffer for headphone ground 177 | Serial.println("Headphones enabled."); 178 | codec.setHeadphoneVolumeDB(0.00); 179 | Serial.println("Volume set to +0dB"); 180 | 181 | // Enable Jack Detect 182 | codec.enableHeadphoneJackDetect(); 183 | Serial.println("Jack Detect enabled."); 184 | // Set input for Jack Detect input to LEFT INPUT 3 185 | codec.setHeadphoneJackDetectInput(WM8960_JACKDETECT_LINPUT3); 186 | Serial.println("Jack Detect input set to LEFT INPUT 3."); 187 | 188 | Serial.println("Example complete. Listen to INPUT1 on Speaker outputs."); 189 | Serial.println("Try plugging in headphones to switch to headphone output."); 190 | Serial.println("Unplug headphones to switch back to speakers."); 191 | } 192 | 193 | void loop() 194 | { 195 | // Do nothing. 196 | // Plugging in headphones will automatically switch the output to the headphones. 197 | // Unplugging headphones will automatically switch the output to the speakers. 198 | } 199 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map SFE_TPA2016D2 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | WM8960 KEYWORD1 9 | 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | begin KEYWORD2 15 | isConnected KEYWORD2 16 | enableVREF KEYWORD2 17 | disableVREF KEYWORD2 18 | enableAINL KEYWORD2 19 | disableAINL KEYWORD2 20 | enableAINR KEYWORD2 21 | disableAINR KEYWORD2 22 | enableLMIC KEYWORD2 23 | disableLMIC KEYWORD2 24 | enableRMIC KEYWORD2 25 | disableRMIC KEYWORD2 26 | enableLMICBOOST KEYWORD2 27 | disableLMICBOOST KEYWORD2 28 | enableRMICBOOST KEYWORD2 29 | disableRMICBOOST KEYWORD2 30 | pgaLeftNonInvSignalSelect KEYWORD2 31 | pgaRightNonInvSignalSelect KEYWORD2 32 | connectLMN1 KEYWORD2 33 | disconnectLMN1 KEYWORD2 34 | connectRMN1 KEYWORD2 35 | disconnectRMN1 KEYWORD2 36 | connectLMIC2B KEYWORD2 37 | disconnectLMIC2B KEYWORD2 38 | connectRMIC2B KEYWORD2 39 | disconnectRMIC2B KEYWORD2 40 | setLINVOL KEYWORD2 41 | setRINVOL KEYWORD2 42 | setLINVOLDB KEYWORD2 43 | setRINVOLDB KEYWORD2 44 | enablePgaZeroCross KEYWORD2 45 | disablePgaZeroCross KEYWORD2 46 | enableLINMUTE KEYWORD2 47 | disableLINMUTE KEYWORD2 48 | enableRINMUTE KEYWORD2 49 | disableRINMUTE KEYWORD2 50 | pgaLeftIPVUSet KEYWORD2 51 | pgaRightIPVUSet KEYWORD2 52 | setLMICBOOST KEYWORD2 53 | setRMICBOOST KEYWORD2 54 | setLIN3BOOST KEYWORD2 55 | setLIN2BOOST KEYWORD2 56 | setRIN3BOOST KEYWORD2 57 | setRIN2BOOST KEYWORD2 58 | enableMicBias KEYWORD2 59 | disableMicBias KEYWORD2 60 | setMicBiasVoltage KEYWORD2 61 | enableAdcLeft KEYWORD2 62 | disableAdcLeft KEYWORD2 63 | enableAdcRight KEYWORD2 64 | disableAdcRight KEYWORD2 65 | setAdcLeftDigitalVolume KEYWORD2 66 | setAdcRightDigitalVolume KEYWORD2 67 | setAdcLeftDigitalVolumeDB KEYWORD2 68 | setAdcRightDigitalVolumeDB KEYWORD2 69 | enableAlc KEYWORD2 70 | disableAlc KEYWORD2 71 | setAlcTarget KEYWORD2 72 | setAlcDecay KEYWORD2 73 | setAlcAttack KEYWORD2 74 | setAlcMaxGain KEYWORD2 75 | setAlcMinGain KEYWORD2 76 | setAlcHold KEYWORD2 77 | enablePeakLimiter KEYWORD2 78 | disablePeakLimiter KEYWORD2 79 | enableNoiseGate KEYWORD2 80 | disableNoiseGate KEYWORD2 81 | setNoiseGateThreshold KEYWORD2 82 | enableDacLeft KEYWORD2 83 | disableDacLeft KEYWORD2 84 | enableDacRight KEYWORD2 85 | disableDacRight KEYWORD2 86 | setDacLeftDigitalVolume KEYWORD2 87 | setDacRightDigitalVolume KEYWORD2 88 | setDacLeftDigitalVolumeDB KEYWORD2 89 | setDacRightDigitalVolumeDB KEYWORD2 90 | enableDacMute KEYWORD2 91 | disableDacMute KEYWORD2 92 | enable3d KEYWORD2 93 | disable3d KEYWORD2 94 | set3dDepth KEYWORD2 95 | enableDac6dbAttenuation KEYWORD2 96 | disableDac6dbAttentuation KEYWORD2 97 | enableLOMIX KEYWORD2 98 | disableLOMIX KEYWORD2 99 | enableROMIX KEYWORD2 100 | disableROMIX KEYWORD2 101 | enableOUT3MIX KEYWORD2 102 | disableOUT3MIX KEYWORD2 103 | enableLI2LO KEYWORD2 104 | disableLI2LO KEYWORD2 105 | setLI2LOVOL KEYWORD2 106 | enableLB2LO KEYWORD2 107 | disableLB2LO KEYWORD2 108 | setLB2LOVOL KEYWORD2 109 | enableLD2LO KEYWORD2 110 | disableLD2LO KEYWORD2 111 | enableRI2RO KEYWORD2 112 | disableRI2RO KEYWORD2 113 | setRI2ROVOL KEYWORD2 114 | enableRB2RO KEYWORD2 115 | disableRB2RO KEYWORD2 116 | setRB2ROVOL KEYWORD2 117 | enableRD2RO KEYWORD2 118 | disableRD2RO KEYWORD2 119 | enableLI2MO KEYWORD2 120 | disableLI2MO KEYWORD2 121 | enableRI2MO KEYWORD2 122 | disableRI2MO KEYWORD2 123 | enableOUT3asVMID KEYWORD2 124 | enableVMID KEYWORD2 125 | disableVMID KEYWORD2 126 | enableHeadphones KEYWORD2 127 | disableHeadphones KEYWORD2 128 | enableRightHeadphone KEYWORD2 129 | disableRightHeadphone KEYWORD2 130 | enableLeftHeadphone KEYWORD2 131 | disableLeftHeadphone KEYWORD2 132 | enableHeadphoneStandby KEYWORD2 133 | disableHeadphoneStandby KEYWORD2 134 | setHeadphoneVolume KEYWORD2 135 | setHeadphoneVolumeDB KEYWORD2 136 | enableHeadphoneZeroCross KEYWORD2 137 | disableHeadphoneZeroCross KEYWORD2 138 | enableSpeakers KEYWORD2 139 | disableSpeakers KEYWORD2 140 | enableRightSpeaker KEYWORD2 141 | disableRightSpeaker KEYWORD2 142 | enableLeftSpeaker KEYWORD2 143 | disableLeftSpeaker KEYWORD2 144 | setSpeakerVolume KEYWORD2 145 | setSpeakerVolumeDB KEYWORD2 146 | enableSpeakerZeroCross KEYWORD2 147 | disableSpeakerZeroCross KEYWORD2 148 | setSpeakerDcGain KEYWORD2 149 | setSpeakerAcGain KEYWORD2 150 | enableLoopBack KEYWORD2 151 | disableLoopBack KEYWORD2 152 | enablePLL KEYWORD2 153 | disablePLL KEYWORD2 154 | setPLLPRESCALE KEYWORD2 155 | setPLLN KEYWORD2 156 | setPLLK KEYWORD2 157 | setSMD KEYWORD2 158 | setCLKSEL KEYWORD2 159 | setSYSCLKDIV KEYWORD2 160 | setADCDIV KEYWORD2 161 | setDACDIV KEYWORD2 162 | setBCLKDIV KEYWORD2 163 | setDCLKDIV KEYWORD2 164 | setALRCGPIO KEYWORD2 165 | enableMasterMode KEYWORD2 166 | enablePeripheralMode KEYWORD2 167 | setWL KEYWORD2 168 | setLRP KEYWORD2 169 | setALRSWAP KEYWORD2 170 | setVROI KEYWORD2 171 | setVSEL KEYWORD2 172 | writeRegister KEYWORD2 173 | 174 | ####################################### 175 | # Constants (LITERAL1) 176 | ####################################### 177 | 178 | ## WM8960 register addresses 179 | WM8960_REG_LEFT_INPUT_VOLUME LITERAL1 180 | WM8960_REG_RIGHT_INPUT_VOLUME LITERAL1 181 | WM8960_REG_LOUT1_VOLUME LITERAL1 182 | WM8960_REG_ROUT1_VOLUME LITERAL1 183 | WM8960_REG_CLOCKING_1 LITERAL1 184 | WM8960_REG_ADC_DAC_CTRL_1 LITERAL1 185 | WM8960_REG_ADC_DAC_CTRL_2 LITERAL1 186 | WM8960_REG_AUDIO_INTERFACE_1 LITERAL1 187 | WM8960_REG_CLOCKING_2 LITERAL1 188 | WM8960_REG_AUDIO_INTERFACE_2 LITERAL1 189 | WM8960_REG_LEFT_DAC_VOLUME LITERAL1 190 | WM8960_REG_RIGHT_DAC_VOLUME LITERAL1 191 | WM8960_REG_RESET LITERAL1 192 | WM8960_REG_3D_CONTROL LITERAL1 193 | WM8960_REG_ALC1 LITERAL1 194 | WM8960_REG_ALC2 LITERAL1 195 | WM8960_REG_ALC3 LITERAL1 196 | WM8960_REG_NOISE_GATE LITERAL1 197 | WM8960_REG_LEFT_ADC_VOLUME LITERAL1 198 | WM8960_REG_RIGHT_ADC_VOLUME LITERAL1 199 | WM8960_REG_ADDITIONAL_CONTROL_1 LITERAL1 200 | WM8960_REG_ADDITIONAL_CONTROL_2 LITERAL1 201 | WM8960_REG_PWR_MGMT_1 LITERAL1 202 | WM8960_REG_PWR_MGMT_2 LITERAL1 203 | WM8960_REG_ADDITIONAL_CONTROL_3 LITERAL1 204 | WM8960_REG_ANTI_POP_1 LITERAL1 205 | WM8960_REG_ANTI_POP_2 LITERAL1 206 | WM8960_REG_ADCL_SIGNAL_PATH LITERAL1 207 | WM8960_REG_ADCR_SIGNAL_PATH LITERAL1 208 | WM8960_REG_LEFT_OUT_MIX_1 LITERAL1 209 | WM8960_REG_RIGHT_OUT_MIX_2 LITERAL1 210 | WM8960_REG_MONO_OUT_MIX_1 LITERAL1 211 | WM8960_REG_MONO_OUT_MIX_2 LITERAL1 212 | WM8960_REG_LOUT2_VOLUME LITERAL1 213 | WM8960_REG_ROUT2_VOLUME LITERAL1 214 | WM8960_REG_MONO_OUT_VOLUME LITERAL1 215 | WM8960_REG_INPUT_BOOST_MIXER_1 LITERAL1 216 | WM8960_REG_INPUT_BOOST_MIXER_2 LITERAL1 217 | WM8960_REG_BYPASS_1 LITERAL1 218 | WM8960_REG_BYPASS_2 LITERAL1 219 | WM8960_REG_PWR_MGMT_3 LITERAL1 220 | WM8960_REG_ADDITIONAL_CONTROL_4 LITERAL1 221 | WM8960_REG_CLASS_D_CONTROL_1 LITERAL1 222 | WM8960_REG_CLASS_D_CONTROL_3 LITERAL1 223 | WM8960_REG_PLL_N LITERAL1 224 | WM8960_REG_PLL_K_1 LITERAL1 225 | WM8960_REG_PLL_K_2 LITERAL1 226 | WM8960_REG_PLL_K_3 LITERAL1 227 | 228 | ## PGA input selections 229 | WM8960_PGAL_LINPUT2 LITERAL1 230 | WM8960_PGAL_LINPUT3 LITERAL1 231 | WM8960_PGAL_VMID LITERAL1 232 | WM8960_PGAR_RINPUT2 LITERAL1 233 | WM8960_PGAR_RINPUT3 LITERAL1 234 | WM8960_PGAR_VMID LITERAL1 235 | 236 | ## Mic (aka PGA) BOOST gain options 237 | WM8960_MIC_BOOST_GAIN_0DB LITERAL1 238 | WM8960_MIC_BOOST_GAIN_13DB LITERAL1 239 | WM8960_MIC_BOOST_GAIN_20DB LITERAL1 240 | WM8960_MIC_BOOST_GAIN_29DB LITERAL1 241 | 242 | ## Mixer 1 and 2 boost gain options 243 | WM8960_BOOST_MIXER_GAIN_MUTE LITERAL1 244 | WM8960_BOOST_MIXER_GAIN_NEG_12DB LITERAL1 245 | WM8960_BOOST_MIXER_GAIN_NEG_9DB LITERAL1 246 | WM8960_BOOST_MIXER_GAIN_NEG_6DB LITERAL1 247 | WM8960_BOOST_MIXER_GAIN_NEG_3DB LITERAL1 248 | WM8960_BOOST_MIXER_GAIN_0DB LITERAL1 249 | WM8960_BOOST_MIXER_GAIN_3DB LITERAL1 250 | WM8960_BOOST_MIXER_GAIN_6DB LITERAL1 251 | 252 | ## Output Mixer gain options 253 | WM8960_OUTPUT_MIXER_GAIN_0DB LITERAL1 254 | WM8960_OUTPUT_MIXER_GAIN_NEG_3DB LITERAL1 255 | WM8960_OUTPUT_MIXER_GAIN_NEG_6DB LITERAL1 256 | WM8960_OUTPUT_MIXER_GAIN_NEG_9DB LITERAL1 257 | WM8960_OUTPUT_MIXER_GAIN_NEG_12DB LITERAL1 258 | WM8960_OUTPUT_MIXER_GAIN_NEG_15DB LITERAL1 259 | WM8960_OUTPUT_MIXER_GAIN_NEG_18DB LITERAL1 260 | WM8960_OUTPUT_MIXER_GAIN_NEG_21DB LITERAL1 261 | 262 | ## Mic Bias voltage options 263 | WM8960_MIC_BIAS_VOLTAGE_0_9_AVDD LITERAL1 264 | WM8960_MIC_BIAS_VOLTAGE_0_65_AVDD LITERAL1 265 | 266 | ## Automatic Level Control Modes 267 | WM8960_ALC_MODE_OFF LITERAL1 268 | WM8960_ALC_MODE_RIGHT_ONLY LITERAL1 269 | WM8960_ALC_MODE_LEFT_ONLY LITERAL1 270 | WM8960_ALC_MODE_STEREO LITERAL1 271 | 272 | ## SYSCLK divide 273 | WM8960_SYSCLK_DIV_BY_1 LITERAL1 274 | WM8960_SYSCLK_DIV_BY_2 LITERAL1 275 | WM8960_CLKSEL_MCLK LITERAL1 276 | WM8960_CLKSEL_PLL LITERAL1 277 | WM8960_PLL_MODE_INTEGER LITERAL1 278 | WM8960_PLL_MODE_FRACTIONAL LITERAL1 279 | WM8960_PLLPRESCALE_DIV_1 LITERAL1 280 | WM8960_PLLPRESCALE_DIV_2 LITERAL1 281 | 282 | ## class d clock divide 283 | WM8960_DCLKDIV_16 LITERAL1 284 | 285 | ## word length settings (aka bits per sample) 286 | ## Audio Data Word Length 287 | WM8960_WL_16BIT LITERAL1 288 | WM8960_WL_20BIT LITERAL1 289 | WM8960_WL_24BIT LITERAL1 290 | WM8960_WL_32BIT LITERAL1 291 | 292 | WM8960_LR_POLARITY_NORMAL LITERAL1 293 | WM8960_LR_POLARITY_INVERT LITERAL1 294 | WM8960_ALRSWAP_NORMAL LITERAL1 295 | WM8960_ALRSWAP_SWAP LITERAL1 296 | 297 | WM8960_ALC_TARGET_LEVEL_NEG_22_5DB LITERAL1 298 | WM8960_ALC_TARGET_LEVEL_NEG_21DB LITERAL1 299 | WM8960_ALC_TARGET_LEVEL_NEG_19_5DB LITERAL1 300 | WM8960_ALC_TARGET_LEVEL_NEG_18DB LITERAL1 301 | WM8960_ALC_TARGET_LEVEL_NEG_16_5DB LITERAL1 302 | WM8960_ALC_TARGET_LEVEL_NEG_15DB LITERAL1 303 | WM8960_ALC_TARGET_LEVEL_NEG_13_5DB LITERAL1 304 | WM8960_ALC_TARGET_LEVEL_NEG_12DB LITERAL1 305 | WM8960_ALC_TARGET_LEVEL_NEG_10_5DB LITERAL1 306 | WM8960_ALC_TARGET_LEVEL_NEG_9DB LITERAL1 307 | WM8960_ALC_TARGET_LEVEL_NEG_7_5DB LITERAL1 308 | WM8960_ALC_TARGET_LEVEL_NEG_6DB LITERAL1 309 | WM8960_ALC_TARGET_LEVEL_NEG_4_5DB LITERAL1 310 | WM8960_ALC_TARGET_LEVEL_NEG_3DB LITERAL1 311 | WM8960_ALC_TARGET_LEVEL_NEG_1_5DB LITERAL1 312 | 313 | WM8960_ALC_MAX_GAIN_LEVEL_NEG_12DB LITERAL1 314 | WM8960_ALC_MAX_GAIN_LEVEL_NEG_6DB LITERAL1 315 | WM8960_ALC_MAX_GAIN_LEVEL_0DB LITERAL1 316 | WM8960_ALC_MAX_GAIN_LEVEL_6DB LITERAL1 317 | WM8960_ALC_MAX_GAIN_LEVEL_12DB LITERAL1 318 | WM8960_ALC_MAX_GAIN_LEVEL_18DB LITERAL1 319 | WM8960_ALC_MAX_GAIN_LEVEL_24DB LITERAL1 320 | WM8960_ALC_MAX_GAIN_LEVEL_30DB LITERAL1 321 | 322 | WM8960_ALC_MIN_GAIN_LEVEL_NEG_17_25DB LITERAL1 323 | WM8960_ALC_MIN_GAIN_LEVEL_NEG_11_25DB LITERAL1 324 | WM8960_ALC_MIN_GAIN_LEVEL_NEG_5_25DB LITERAL1 325 | WM8960_ALC_MIN_GAIN_LEVEL_0_75DB LITERAL1 326 | WM8960_ALC_MIN_GAIN_LEVEL_6_75DB LITERAL1 327 | WM8960_ALC_MIN_GAIN_LEVEL_12_75DB LITERAL1 328 | WM8960_ALC_MIN_GAIN_LEVEL_18_75DB LITERAL1 329 | WM8960_ALC_MIN_GAIN_LEVEL_24_75DB LITERAL1 330 | 331 | WM8960_ALC_HOLD_TIME_0MS LITERAL1 332 | WM8960_ALC_HOLD_TIME_3MS LITERAL1 333 | WM8960_ALC_HOLD_TIME_5MS LITERAL1 334 | WM8960_ALC_HOLD_TIME_11MS LITERAL1 335 | WM8960_ALC_HOLD_TIME_21MS LITERAL1 336 | WM8960_ALC_HOLD_TIME_43MS LITERAL1 337 | WM8960_ALC_HOLD_TIME_85MS LITERAL1 338 | WM8960_ALC_HOLD_TIME_170MS LITERAL1 339 | WM8960_ALC_HOLD_TIME_341MS LITERAL1 340 | WM8960_ALC_HOLD_TIME_682MS LITERAL1 341 | WM8960_ALC_HOLD_TIME_1365MS LITERAL1 342 | WM8960_ALC_HOLD_TIME_3SEC LITERAL1 343 | WM8960_ALC_HOLD_TIME_5SEC LITERAL1 344 | WM8960_ALC_HOLD_TIME_10SEC LITERAL1 345 | WM8960_ALC_HOLD_TIME_23SEC LITERAL1 346 | WM8960_ALC_HOLD_TIME_44SEC LITERAL1 347 | 348 | WM8960_ALC_DECAY_TIME_24MS LITERAL1 349 | WM8960_ALC_DECAY_TIME_48MS LITERAL1 350 | WM8960_ALC_DECAY_TIME_96MS LITERAL1 351 | WM8960_ALC_DECAY_TIME_192MS LITERAL1 352 | WM8960_ALC_DECAY_TIME_384MS LITERAL1 353 | WM8960_ALC_DECAY_TIME_768MS LITERAL1 354 | WM8960_ALC_DECAY_TIME_1536MS LITERAL1 355 | WM8960_ALC_DECAY_TIME_3SEC LITERAL1 356 | WM8960_ALC_DECAY_TIME_6SEC LITERAL1 357 | WM8960_ALC_DECAY_TIME_12SEC LITERAL1 358 | WM8960_ALC_DECAY_TIME_24SEC LITERAL1 359 | 360 | WM8960_ALC_ATTACK_TIME_6MS LITERAL1 361 | WM8960_ALC_ATTACK_TIME_12MS LITERAL1 362 | WM8960_ALC_ATTACK_TIME_24MS LITERAL1 363 | WM8960_ALC_ATTACK_TIME_482MS LITERAL1 364 | WM8960_ALC_ATTACK_TIME_964MS LITERAL1 365 | WM8960_ALC_ATTACK_TIME_1928MS LITERAL1 366 | WM8960_ALC_ATTACK_TIME_3846MS LITERAL1 367 | WM8960_ALC_ATTACK_TIME_768MS LITERAL1 368 | WM8960_ALC_ATTACK_TIME_1536MS LITERAL1 369 | WM8960_ALC_ATTACK_TIME_3SEC LITERAL1 370 | WM8960_ALC_ATTACK_TIME_6SEC LITERAL1 371 | 372 | WM8960_SPEAKER_BOOST_GAIN_0DB LITERAL1 373 | WM8960_SPEAKER_BOOST_GAIN_2_1DB LITERAL1 374 | WM8960_SPEAKER_BOOST_GAIN_2_9DB LITERAL1 375 | WM8960_SPEAKER_BOOST_GAIN_3_6DB LITERAL1 376 | WM8960_SPEAKER_BOOST_GAIN_4_5DB LITERAL1 377 | WM8960_SPEAKER_BOOST_GAIN_5_1DB LITERAL1 378 | 379 | WM8960_VROI_500 LITERAL1 380 | WM8960_VROI_20K LITERAL1 381 | 382 | WM8960_VSEL_INCREASED_BIAS_CURRENT LITERAL1 383 | WM8960_VSEL_LOWEST_BIAS_CURRENT LITERAL1 384 | 385 | WM8960_VMIDSEL_DISABLED LITERAL1 386 | WM8960_VMIDSEL_2X50KOHM LITERAL1 387 | WM8960_VMIDSEL_2X250KOHM LITERAL1 388 | WM8960_VMIDSEL_2X5KOHM LITERAL1 389 | 390 | ####################################### 391 | # Instances (KEYWORD3) 392 | ####################################### 393 | 394 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=SparkFun WM8960 Arduino Library 2 | version=1.0.6 3 | author=SparkFun Electronics 4 | maintainer=SparkFun Electronics 5 | sentence=Library for the WM8960 Codec Breakout Board 6 | paragraph=An Arduino Library for the SparkFun WM8960 Breakout. Connect to the CODEC via QWIIC, and easily adjust all of its available settings including volume and output audio level compression! 7 | category=Other 8 | url=https://github.com/sparkfun/SparkFun_WM8960_Arduino_Library 9 | architectures=* 10 | -------------------------------------------------------------------------------- /src/SparkFun_WM8960_Arduino_Library.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | SparkFun WM8960 Arduino Library 3 | 4 | This library provides a set of functions to control (via I2C) the Wolfson 5 | Microelectronics WM8960 Stereo CODEC with 1W Stereo Class D Speaker Drivers 6 | and Headphone Drivers. 7 | 8 | Pete Lewis @ SparkFun Electronics 9 | October 14th, 2022 10 | https://github.com/sparkfun/SparkFun_WM8960_Arduino_Library 11 | 12 | This code was created using some code by Mike Grusin at SparkFun Electronics 13 | Included with the LilyPad MP3 example code found here: 14 | Revision history: version 1.0 2012/07/24 MDG Initial release 15 | https://github.com/sparkfun/LilyPad_MP3_Player 16 | 17 | Do you like this library? Help support SparkFun. Buy a board! 18 | 19 | SparkFun Audio Codec Breakout - WM8960 (QWIIC) 20 | https://www.sparkfun.com/products/21250 21 | 22 | All functions return 1 if the read/write was successful, and 0 23 | if there was a communications failure. You can ignore the return value 24 | if you just don't care anymore. 25 | 26 | For information on the data sent to and received from the CODEC, 27 | refer to the WM8960 datasheet at: 28 | https://github.com/sparkfun/SparkFun_Audio_Codec_Breakout_WM8960/blob/main/Documents/WM8960_datasheet_v4.2.pdf 29 | 30 | This code is released under the [MIT License](http://opensource.org/licenses/MIT). 31 | Please review the LICENSE.md file included with this example. If you have any questions 32 | or concerns with licensing, please contact techsupport@sparkfun.com. 33 | Distributed as-is; no warranty is given. 34 | ******************************************************************************/ 35 | 36 | #ifndef __SPARKFUN_WM8960_H__ 37 | #define __SPARKFUN_WM8960_H__ 38 | 39 | #if (ARDUINO >= 100) 40 | #include "Arduino.h" 41 | #else 42 | #include "WProgram.h" 43 | #endif 44 | 45 | #include 46 | 47 | // I2C address (7-bit format for Wire library) 48 | #define WM8960_ADDR 0x1A 49 | 50 | // WM8960 register addresses 51 | #define WM8960_REG_LEFT_INPUT_VOLUME 0x00 52 | #define WM8960_REG_RIGHT_INPUT_VOLUME 0x01 53 | #define WM8960_REG_LOUT1_VOLUME 0x02 54 | #define WM8960_REG_ROUT1_VOLUME 0x03 55 | #define WM8960_REG_CLOCKING_1 0x04 56 | #define WM8960_REG_ADC_DAC_CTRL_1 0x05 57 | #define WM8960_REG_ADC_DAC_CTRL_2 0x06 58 | #define WM8960_REG_AUDIO_INTERFACE_1 0x07 59 | #define WM8960_REG_CLOCKING_2 0x08 60 | #define WM8960_REG_AUDIO_INTERFACE_2 0x09 61 | #define WM8960_REG_LEFT_DAC_VOLUME 0x0A 62 | #define WM8960_REG_RIGHT_DAC_VOLUME 0x0B 63 | #define WM8960_REG_RESET 0x0F 64 | #define WM8960_REG_3D_CONTROL 0x10 65 | #define WM8960_REG_ALC1 0x11 66 | #define WM8960_REG_ALC2 0x12 67 | #define WM8960_REG_ALC3 0x13 68 | #define WM8960_REG_NOISE_GATE 0x14 69 | #define WM8960_REG_LEFT_ADC_VOLUME 0x15 70 | #define WM8960_REG_RIGHT_ADC_VOLUME 0x16 71 | #define WM8960_REG_ADDITIONAL_CONTROL_1 0x17 72 | #define WM8960_REG_ADDITIONAL_CONTROL_2 0x18 73 | #define WM8960_REG_PWR_MGMT_1 0x19 74 | #define WM8960_REG_PWR_MGMT_2 0x1A 75 | #define WM8960_REG_ADDITIONAL_CONTROL_3 0x1B 76 | #define WM8960_REG_ANTI_POP_1 0x1C 77 | #define WM8960_REG_ANTI_POP_2 0x1D 78 | #define WM8960_REG_ADCL_SIGNAL_PATH 0x20 79 | #define WM8960_REG_ADCR_SIGNAL_PATH 0x21 80 | #define WM8960_REG_LEFT_OUT_MIX_1 0x22 81 | #define WM8960_REG_RIGHT_OUT_MIX_2 0x25 82 | #define WM8960_REG_MONO_OUT_MIX_1 0x26 83 | #define WM8960_REG_MONO_OUT_MIX_2 0x27 84 | #define WM8960_REG_LOUT2_VOLUME 0x28 85 | #define WM8960_REG_ROUT2_VOLUME 0x29 86 | #define WM8960_REG_MONO_OUT_VOLUME 0x2A 87 | #define WM8960_REG_INPUT_BOOST_MIXER_1 0x2B 88 | #define WM8960_REG_INPUT_BOOST_MIXER_2 0x2C 89 | #define WM8960_REG_BYPASS_1 0x2D 90 | #define WM8960_REG_BYPASS_2 0x2E 91 | #define WM8960_REG_PWR_MGMT_3 0x2F 92 | #define WM8960_REG_ADDITIONAL_CONTROL_4 0x30 93 | #define WM8960_REG_CLASS_D_CONTROL_1 0x31 94 | #define WM8960_REG_CLASS_D_CONTROL_3 0x33 95 | #define WM8960_REG_PLL_N 0x34 96 | #define WM8960_REG_PLL_K_1 0x35 97 | #define WM8960_REG_PLL_K_2 0x36 98 | #define WM8960_REG_PLL_K_3 0x37 99 | 100 | // PGA input selections 101 | #define WM8960_PGAL_LINPUT2 0 102 | #define WM8960_PGAL_LINPUT3 1 103 | #define WM8960_PGAL_VMID 2 104 | #define WM8960_PGAR_RINPUT2 0 105 | #define WM8960_PGAR_RINPUT3 1 106 | #define WM8960_PGAR_VMID 2 107 | 108 | // Mic (aka PGA) BOOST gain options 109 | #define WM8960_MIC_BOOST_GAIN_0DB 0 110 | #define WM8960_MIC_BOOST_GAIN_13DB 1 111 | #define WM8960_MIC_BOOST_GAIN_20DB 2 112 | #define WM8960_MIC_BOOST_GAIN_29DB 3 113 | 114 | // Boost Mixer gain options 115 | // These are used to control the gain (aka volume) at the following settings: 116 | // LIN2BOOST 117 | // LIN3BOOST 118 | // RIN2BOOST 119 | // RIN3BOOST 120 | #define WM8960_BOOST_MIXER_GAIN_MUTE 0 121 | #define WM8960_BOOST_MIXER_GAIN_NEG_12DB 1 122 | #define WM8960_BOOST_MIXER_GAIN_NEG_9DB 2 123 | #define WM8960_BOOST_MIXER_GAIN_NEG_6DB 3 124 | #define WM8960_BOOST_MIXER_GAIN_NEG_3DB 4 125 | #define WM8960_BOOST_MIXER_GAIN_0DB 5 126 | #define WM8960_BOOST_MIXER_GAIN_3DB 6 127 | #define WM8960_BOOST_MIXER_GAIN_6DB 7 128 | 129 | // Output Mixer gain options 130 | // These are used to control the gain (aka volume) at the following settings: 131 | // LI2LOVOL 132 | // LB2LOVOL 133 | // RI2LOVOL 134 | // RB2LOVOL 135 | // These are useful as analog bypass signal path options. 136 | #define WM8960_OUTPUT_MIXER_GAIN_0DB 0 137 | #define WM8960_OUTPUT_MIXER_GAIN_NEG_3DB 1 138 | #define WM8960_OUTPUT_MIXER_GAIN_NEG_6DB 2 139 | #define WM8960_OUTPUT_MIXER_GAIN_NEG_9DB 3 140 | #define WM8960_OUTPUT_MIXER_GAIN_NEG_12DB 4 141 | #define WM8960_OUTPUT_MIXER_GAIN_NEG_15DB 5 142 | #define WM8960_OUTPUT_MIXER_GAIN_NEG_18DB 6 143 | #define WM8960_OUTPUT_MIXER_GAIN_NEG_21DB 7 144 | 145 | // Mic Bias voltage options 146 | #define WM8960_MIC_BIAS_VOLTAGE_0_9_AVDD 0 147 | #define WM8960_MIC_BIAS_VOLTAGE_0_65_AVDD 1 148 | 149 | // SYSCLK divide 150 | #define WM8960_SYSCLK_DIV_BY_1 0 151 | #define WM8960_SYSCLK_DIV_BY_2 2 152 | #define WM8960_CLKSEL_MCLK 0 153 | #define WM8960_CLKSEL_PLL 1 154 | #define WM8960_PLL_MODE_INTEGER 0 155 | #define WM8960_PLL_MODE_FRACTIONAL 1 156 | #define WM8960_PLLPRESCALE_DIV_1 0 157 | #define WM8960_PLLPRESCALE_DIV_2 1 158 | 159 | // Class d clock divide 160 | #define WM8960_DCLKDIV_16 7 161 | 162 | // Word length settings (aka bits per sample) 163 | // Audio Data Word Length 164 | #define WM8960_WL_16BIT 0 165 | #define WM8960_WL_20BIT 1 166 | #define WM8960_WL_24BIT 2 167 | #define WM8960_WL_32BIT 3 168 | 169 | // Additional Digital Audio Interface controls 170 | // LRP (aka left-right-polarity) 171 | // Right, left and I2S modes – LRCLK polarity 172 | // 0 = normal LRCLK polarity 173 | // 1 = inverted LRCLK polarity 174 | #define WM8960_LR_POLARITY_NORMAL 0 175 | #define WM8960_LR_POLARITY_INVERT 1 176 | 177 | // ALRSWAP (aka ADC left/right swap) 178 | // Left/Right ADC channel swap 179 | // 1 = Swap left and right ADC data in audio interface 180 | // 0 = Output left and right data as normal 181 | #define WM8960_ALRSWAP_NORMAL 0 182 | #define WM8960_ALRSWAP_SWAP 1 183 | 184 | // Gain mins, maxes, offsets and step-sizes for all the amps within the codec. 185 | #define WM8960_PGA_GAIN_MIN -17.25 186 | #define WM8960_PGA_GAIN_MAX 30.00 187 | #define WM8960_PGA_GAIN_OFFSET 17.25 188 | #define WM8960_PGA_GAIN_STEPSIZE 0.75 189 | #define WM8960_HP_GAIN_MIN -73.00 190 | #define WM8960_HP_GAIN_MAX 6.00 191 | #define WM8960_HP_GAIN_OFFSET 121.00 192 | #define WM8960_HP_GAIN_STEPSIZE 1.00 193 | #define WM8960_SPEAKER_GAIN_MIN -73.00 194 | #define WM8960_SPEAKER_GAIN_MAX 6.00 195 | #define WM8960_SPEAKER_GAIN_OFFSET 121.00 196 | #define WM8960_SPEAKER_GAIN_STEPSIZE 1.00 197 | #define WM8960_ADC_GAIN_MIN -97.00 198 | #define WM8960_ADC_GAIN_MAX 30.00 199 | #define WM8960_ADC_GAIN_OFFSET 97.50 200 | #define WM8960_ADC_GAIN_STEPSIZE 0.50 201 | #define WM8960_DAC_GAIN_MIN -97.00 202 | #define WM8960_DAC_GAIN_MAX 30.00 203 | #define WM8960_DAC_GAIN_OFFSET 97.50 204 | #define WM8960_DAC_GAIN_STEPSIZE 0.50 205 | 206 | // Automatic Level Control Modes 207 | #define WM8960_ALC_MODE_OFF 0 208 | #define WM8960_ALC_MODE_RIGHT_ONLY 1 209 | #define WM8960_ALC_MODE_LEFT_ONLY 2 210 | #define WM8960_ALC_MODE_STEREO 3 211 | 212 | // Automatic Level Control Target Level dB 213 | #define WM8960_ALC_TARGET_LEVEL_NEG_22_5DB 0 214 | #define WM8960_ALC_TARGET_LEVEL_NEG_21DB 1 215 | #define WM8960_ALC_TARGET_LEVEL_NEG_19_5DB 2 216 | #define WM8960_ALC_TARGET_LEVEL_NEG_18DB 3 217 | #define WM8960_ALC_TARGET_LEVEL_NEG_16_5DB 4 218 | #define WM8960_ALC_TARGET_LEVEL_NEG_15DB 5 219 | #define WM8960_ALC_TARGET_LEVEL_NEG_13_5DB 6 220 | #define WM8960_ALC_TARGET_LEVEL_NEG_12DB 7 221 | #define WM8960_ALC_TARGET_LEVEL_NEG_10_5DB 8 222 | #define WM8960_ALC_TARGET_LEVEL_NEG_9DB 9 223 | #define WM8960_ALC_TARGET_LEVEL_NEG_7_5DB 10 224 | #define WM8960_ALC_TARGET_LEVEL_NEG_6DB 11 225 | #define WM8960_ALC_TARGET_LEVEL_NEG_4_5DB 12 226 | #define WM8960_ALC_TARGET_LEVEL_NEG_3DB 13 227 | #define WM8960_ALC_TARGET_LEVEL_NEG_1_5DB 14 228 | 229 | // Automatic Level Control Max Gain Level dB 230 | #define WM8960_ALC_MAX_GAIN_LEVEL_NEG_12DB 0 231 | #define WM8960_ALC_MAX_GAIN_LEVEL_NEG_6DB 1 232 | #define WM8960_ALC_MAX_GAIN_LEVEL_0DB 2 233 | #define WM8960_ALC_MAX_GAIN_LEVEL_6DB 3 234 | #define WM8960_ALC_MAX_GAIN_LEVEL_12DB 4 235 | #define WM8960_ALC_MAX_GAIN_LEVEL_18DB 5 236 | #define WM8960_ALC_MAX_GAIN_LEVEL_24DB 6 237 | #define WM8960_ALC_MAX_GAIN_LEVEL_30DB 7 238 | 239 | // Automatic Level Control Min Gain Level dB 240 | #define WM8960_ALC_MIN_GAIN_LEVEL_NEG_17_25DB 0 241 | #define WM8960_ALC_MIN_GAIN_LEVEL_NEG_11_25DB 1 242 | #define WM8960_ALC_MIN_GAIN_LEVEL_NEG_5_25DB 2 243 | #define WM8960_ALC_MIN_GAIN_LEVEL_0_75DB 3 244 | #define WM8960_ALC_MIN_GAIN_LEVEL_6_75DB 4 245 | #define WM8960_ALC_MIN_GAIN_LEVEL_12_75DB 5 246 | #define WM8960_ALC_MIN_GAIN_LEVEL_18_75DB 6 247 | #define WM8960_ALC_MIN_GAIN_LEVEL_24_75DB 7 248 | 249 | // Automatic Level Control Hold Time (MS and SEC) 250 | #define WM8960_ALC_HOLD_TIME_0MS 0 251 | #define WM8960_ALC_HOLD_TIME_3MS 1 252 | #define WM8960_ALC_HOLD_TIME_5MS 2 253 | #define WM8960_ALC_HOLD_TIME_11MS 3 254 | #define WM8960_ALC_HOLD_TIME_21MS 4 255 | #define WM8960_ALC_HOLD_TIME_43MS 5 256 | #define WM8960_ALC_HOLD_TIME_85MS 6 257 | #define WM8960_ALC_HOLD_TIME_170MS 7 258 | #define WM8960_ALC_HOLD_TIME_341MS 8 259 | #define WM8960_ALC_HOLD_TIME_682MS 9 260 | #define WM8960_ALC_HOLD_TIME_1365MS 10 261 | #define WM8960_ALC_HOLD_TIME_3SEC 11 262 | #define WM8960_ALC_HOLD_TIME_5SEC 12 263 | #define WM8960_ALC_HOLD_TIME_10SEC 13 264 | #define WM8960_ALC_HOLD_TIME_23SEC 14 265 | #define WM8960_ALC_HOLD_TIME_44SEC 15 266 | 267 | // Automatic Level Control Decay Time (MS and SEC) 268 | #define WM8960_ALC_DECAY_TIME_24MS 0 269 | #define WM8960_ALC_DECAY_TIME_48MS 1 270 | #define WM8960_ALC_DECAY_TIME_96MS 2 271 | #define WM8960_ALC_DECAY_TIME_192MS 3 272 | #define WM8960_ALC_DECAY_TIME_384MS 4 273 | #define WM8960_ALC_DECAY_TIME_768MS 5 274 | #define WM8960_ALC_DECAY_TIME_1536MS 6 275 | #define WM8960_ALC_DECAY_TIME_3SEC 7 276 | #define WM8960_ALC_DECAY_TIME_6SEC 8 277 | #define WM8960_ALC_DECAY_TIME_12SEC 9 278 | #define WM8960_ALC_DECAY_TIME_24SEC 10 279 | 280 | // Automatic Level Control Attack Time (MS and SEC) 281 | #define WM8960_ALC_ATTACK_TIME_6MS 0 282 | #define WM8960_ALC_ATTACK_TIME_12MS 1 283 | #define WM8960_ALC_ATTACK_TIME_24MS 2 284 | #define WM8960_ALC_ATTACK_TIME_482MS 3 285 | #define WM8960_ALC_ATTACK_TIME_964MS 4 286 | #define WM8960_ALC_ATTACK_TIME_1928MS 5 287 | #define WM8960_ALC_ATTACK_TIME_3846MS 6 288 | #define WM8960_ALC_ATTACK_TIME_768MS 7 289 | #define WM8960_ALC_ATTACK_TIME_1536MS 8 290 | #define WM8960_ALC_ATTACK_TIME_3SEC 9 291 | #define WM8960_ALC_ATTACK_TIME_6SEC 10 292 | 293 | // Speaker Boost Gains (DC and AC) 294 | #define WM8960_SPEAKER_BOOST_GAIN_0DB 0 295 | #define WM8960_SPEAKER_BOOST_GAIN_2_1DB 1 296 | #define WM8960_SPEAKER_BOOST_GAIN_2_9DB 2 297 | #define WM8960_SPEAKER_BOOST_GAIN_3_6DB 3 298 | #define WM8960_SPEAKER_BOOST_GAIN_4_5DB 4 299 | #define WM8960_SPEAKER_BOOST_GAIN_5_1DB 5 300 | 301 | // VMIDSEL settings 302 | #define WM8960_VMIDSEL_DISABLED 0 303 | #define WM8960_VMIDSEL_2X50KOHM 1 304 | #define WM8960_VMIDSEL_2X250KOHM 2 305 | #define WM8960_VMIDSEL_2X5KOHM 3 306 | 307 | // VREF to Analogue Output Resistance 308 | // (Disabled Outputs) 309 | // 0 = 500 VMID to output 310 | // 1 = 20k VMID to output 311 | #define WM8960_VROI_500 0 312 | #define WM8960_VROI_20K 1 313 | 314 | // Analogue Bias Optimisation 315 | // 00 = Reserved 316 | // 01 = Increased bias current optimized for 317 | // AVDD=2.7V 318 | // 1X = Lowest bias current, optimized for 319 | // AVDD=3.3V 320 | 321 | #define WM8960_VSEL_INCREASED_BIAS_CURRENT 1 322 | #define WM8960_VSEL_LOWEST_BIAS_CURRENT 3 323 | 324 | // JACK DETECT INPUT 325 | #define WM8960_JACKDETECT_GPIO1 0 326 | #define WM8960_JACKDETECT_LINPUT3 1 327 | #define WM8960_JACKDETECT_RINPUT3 2 328 | 329 | class WM8960 330 | { 331 | public: 332 | WM8960(); 333 | boolean begin(TwoWire &wirePort = Wire); 334 | boolean isConnected(); 335 | 336 | boolean enableVREF(); // Necessary for all other functions 337 | boolean disableVREF(); // Use for turning this off to save power 338 | 339 | boolean reset(); // Resets all registers to their default state 340 | 341 | ///////////////////////////////////////////////////////// 342 | ///////////////////////////////////////////////////////// PGA 343 | ///////////////////////////////////////////////////////// 344 | 345 | boolean enableAINL(); 346 | boolean disableAINL(); 347 | boolean enableAINR(); 348 | boolean disableAINR(); 349 | 350 | boolean enableLMIC(); 351 | boolean disableLMIC(); 352 | boolean enableRMIC(); 353 | boolean disableRMIC(); 354 | 355 | boolean enableLMICBOOST(); 356 | boolean disableLMICBOOST(); 357 | boolean enableRMICBOOST(); 358 | boolean disableRMICBOOST(); 359 | 360 | // PGA input signal select 361 | // Each PGA (left and right) has a switch on its non-inverting input. 362 | // On PGA_LEFT: 363 | // You can select between VMID, LINPUT2 or LINPUT3 364 | // Note, the inverting input of PGA_LEFT is perminantly connected to 365 | // LINPUT1 366 | // On PGA_RIGHT: 367 | // You can select between VMIN, RINPUT2 or RINPUT3 368 | // Note, the inverting input of PGA_RIGHT is perminantly connected to 369 | // RINPUT1 370 | 371 | // 3 options: WM8960_PGAL_LINPUT2, WM8960_PGAL_LINPUT3, WM8960_PGAL_VMID 372 | boolean pgaLeftNonInvSignalSelect(uint8_t signal); 373 | 374 | // 3 options: WM8960_PGAR_RINPUT2, WM8960_PGAR_RINPUT3, WM8960_PGAR_VMID 375 | boolean pgaRightNonInvSignalSelect(uint8_t signal); 376 | 377 | // Connections from each INPUT1 to the inverting input of its PGA 378 | 379 | // Connect LINPUT1 to inverting input of Left Input PGA 380 | boolean connectLMN1(); 381 | 382 | // Disconnect LINPUT1 from inverting input of Left Input PGA 383 | boolean disconnectLMN1(); 384 | 385 | // Connect RINPUT1 to inverting input of Right Input PGA 386 | boolean connectRMN1(); 387 | 388 | // Disconnect RINPUT1 from inverting input of Right Input PGA 389 | boolean disconnectRMN1(); 390 | 391 | // Connection from output of PGAs to downstream "boost mixers" 392 | 393 | // Connect Left Input PGA to Left Input Boost mixer 394 | boolean connectLMIC2B(); 395 | 396 | // Disconnect Left Input PGA to Left Input Boost mixer 397 | boolean disconnectLMIC2B(); 398 | 399 | // Connect Right Input PGA to Right Input Boost mixer 400 | boolean connectRMIC2B(); 401 | 402 | // Disconnect Right Input PGA to Right Input Boost mixer 403 | boolean disconnectRMIC2B(); 404 | 405 | // 0-63, (0 = -17.25dB) <<-- 0.75dB steps -->> (63 = +30dB) 406 | boolean setLINVOL(uint8_t volume); 407 | boolean setLINVOLDB(float dB); 408 | 409 | // 0-63, (0 = -17.25dB) <<-- 0.75dB steps -->> (63 = +30dB) 410 | boolean setRINVOL(uint8_t volume); 411 | boolean setRINVOLDB(float dB); 412 | 413 | // Zero Cross prevents zipper sounds on volume changes 414 | boolean enablePgaZeroCross(); // Sets both left and right PGAs 415 | boolean disablePgaZeroCross(); // Sets both left and right PGAs 416 | 417 | boolean enableLINMUTE(); 418 | boolean disableLINMUTE(); 419 | boolean enableRINMUTE(); 420 | boolean disableRINMUTE(); 421 | 422 | // Causes left and right input PGA volumes to be updated 423 | // (LINVOL and RINVOL) 424 | boolean pgaLeftIPVUSet(); 425 | 426 | // Causes left and right input PGA volumes to be updated 427 | // (LINVOL and RINVOL) 428 | boolean pgaRightIPVUSet(); 429 | 430 | // Boosts 431 | 432 | // WM8960_MIC_BOOST_GAIN_0DB or _13DB, _20DB, _29DB 433 | boolean setLMICBOOST(uint8_t boost_gain); 434 | 435 | // WM8960_MIC_BOOST_GAIN_0DB or _13DB, _20DB, _29DB 436 | boolean setRMICBOOST(uint8_t boost_gain); 437 | 438 | // WM8960_BOOST_MIXER_GAIN_MUTE, WM8960_BOOST_MIXER_GAIN_NEG_12DB, ... 439 | boolean setLIN3BOOST(uint8_t boost_gain); 440 | 441 | // WM8960_BOOST_MIXER_GAIN_MUTE, WM8960_BOOST_MIXER_GAIN_NEG_12DB, ... 442 | boolean setLIN2BOOST(uint8_t boost_gain); 443 | 444 | // WM8960_BOOST_MIXER_GAIN_MUTE, WM8960_BOOST_MIXER_GAIN_NEG_12DB, ... 445 | boolean setRIN3BOOST(uint8_t boost_gain); 446 | 447 | // WM8960_BOOST_MIXER_GAIN_MUTE, WM8960_BOOST_MIXER_GAIN_NEG_12DB, ... 448 | boolean setRIN2BOOST(uint8_t boost_gain); 449 | 450 | // Mic Bias control 451 | boolean enableMicBias(); 452 | boolean disableMicBias(); 453 | 454 | // WM8960_MIC_BIAS_VOLTAGE_0_9_AVDD (0.9*AVDD) 455 | // or WM8960_MIC_BIAS_VOLTAGE_0_65_AVDD (0.65*AVDD) 456 | boolean setMicBiasVoltage(boolean voltage); 457 | 458 | ///////////////////////////////////////////////////////// 459 | ///////////////////////////////////////////////////////// ADC 460 | ///////////////////////////////////////////////////////// 461 | 462 | boolean enableAdcLeft(); 463 | boolean disableAdcLeft(); 464 | boolean enableAdcRight(); 465 | boolean disableAdcRight(); 466 | 467 | // ADC digital volume 468 | // Note, also needs to handle control of the ADCVU bits (volume update). 469 | // Valid inputs are 0-255 470 | // 0 = mute 471 | // 1 = -97dB 472 | // ... 0.5dB steps up to 473 | // 195 = 0dB 474 | // 255 = +30dB 475 | boolean setAdcLeftDigitalVolume(uint8_t volume); 476 | boolean setAdcRightDigitalVolume(uint8_t volume); 477 | boolean setAdcLeftDigitalVolumeDB(float dB); 478 | boolean setAdcRightDigitalVolumeDB(float dB); 479 | 480 | // Causes left and right input ADC volumes to be updated 481 | boolean adcLeftADCVUSet(); 482 | 483 | // Causes left and right input ADC volumes to be updated 484 | boolean adcRightADCVUSet(); 485 | 486 | ///////////////////////////////////////////////////////// 487 | ///////////////////////////////////////////////////////// ALC 488 | ///////////////////////////////////////////////////////// 489 | 490 | // Automatic Level Control 491 | // Note that when the ALC function is enabled, the settings of 492 | // Registers 0 and 1 (LINVOL, IPVU, LIZC, LINMUTE, RINVOL, RIZC and 493 | // RINMUTE) are ignored. 494 | 495 | // Also sets alc sample rate to match global sample rate. 496 | boolean enableAlc(uint8_t mode = WM8960_ALC_MODE_STEREO); 497 | boolean disableAlc(); 498 | 499 | // Valid inputs are 0-15 500 | // 0 = -22.5dB FS ... 1.5dB steps ... 15 = -1.5dB FS 501 | boolean setAlcTarget(uint8_t target); 502 | 503 | // Valid inputs are 0-10, 0 = 24ms, 1 = 48ms ... 10 = 24.58seconds 504 | boolean setAlcDecay(uint8_t decay); 505 | 506 | // Valid inputs are 0-10, 0 = 6ms, 1 = 12ms, 2 = 24ms ... 507 | // 10 = 6.14seconds 508 | boolean setAlcAttack(uint8_t attack); 509 | 510 | // Valid inputs are 0-7, 0 = -12dB, ... 7 = +30dB 511 | boolean setAlcMaxGain(uint8_t maxGain); 512 | 513 | // Valid inputs are 0-7, 0 = -17.25dB, ... 7 = +24.75dB 514 | boolean setAlcMinGain(uint8_t attack); 515 | 516 | // Valid inputs are 0-15, 0 = 0ms, ... 15 = 43.691s 517 | boolean setAlcHold(uint8_t attack); 518 | 519 | // Peak Limiter 520 | boolean enablePeakLimiter(); 521 | boolean disablePeakLimiter(); 522 | 523 | // Noise Gate 524 | boolean enableNoiseGate(); 525 | boolean disableNoiseGate(); 526 | 527 | // 0-31, 0 = -76.5dBfs, 31 = -30dBfs 528 | boolean setNoiseGateThreshold(uint8_t threshold); 529 | 530 | ///////////////////////////////////////////////////////// 531 | ///////////////////////////////////////////////////////// DAC 532 | ///////////////////////////////////////////////////////// 533 | 534 | // Enable/disble each channel 535 | boolean enableDacLeft(); 536 | boolean disableDacLeft(); 537 | boolean enableDacRight(); 538 | boolean disableDacRight(); 539 | 540 | // DAC digital volume 541 | // Note, also needs to handle control of the DACVU bits (volume update). 542 | // Valid inputs are 0-255 543 | // 0 = mute 544 | // 1 = -127dB 545 | // ... 0.5dB steps up to 546 | // 255 = 0dB 547 | boolean setDacLeftDigitalVolume(uint8_t volume); 548 | boolean setDacRightDigitalVolume(uint8_t volume); 549 | boolean setDacLeftDigitalVolumeDB(float dB); 550 | boolean setDacRightDigitalVolumeDB(float dB); 551 | 552 | // Causes left and right input DAC volumes to be updated 553 | boolean dacLeftDACVUSet(); 554 | 555 | // Causes left and right input DAC volumes to be updated 556 | boolean dacRightDACVUSet(); 557 | 558 | // DAC mute 559 | boolean enableDacMute(); 560 | boolean disableDacMute(); 561 | 562 | // DE-Emphasis 563 | 564 | // 3D Stereo Enhancement 565 | // 3D enable/disable 566 | boolean enable3d(); 567 | boolean disable3d(); 568 | boolean set3dDepth(uint8_t depth); // 0 = 0%, 15 = 100% 569 | 570 | // 3D upper/lower cut-off frequencies. 571 | 572 | // DAC output -6dB attentuation enable/disable 573 | boolean enableDac6dbAttenuation(); 574 | boolean disableDac6dbAttentuation(); 575 | 576 | ////////////////////////////////////////////////////// 577 | ////////////////////////////////////////////////////// OUTPUT mixers 578 | ////////////////////////////////////////////////////// 579 | 580 | // What's connected to what? Oh so many options... 581 | // LOMIX Left Output Mixer 582 | // ROMIX Right Output Mixer 583 | // OUT3MIX Mono Output Mixer 584 | 585 | // Enable/disable left and right output mixers 586 | boolean enableLOMIX(); 587 | boolean disableLOMIX(); 588 | boolean enableROMIX(); 589 | boolean disableROMIX(); 590 | boolean enableOUT3MIX(); 591 | boolean disableOUT3MIX(); 592 | 593 | // Enable/disable audio path connections/vols to/from output mixers 594 | // See datasheet page 35 for a nice image of all the connections. 595 | 596 | boolean enableLI2LO(); 597 | boolean disableLI2LO(); 598 | 599 | // 0-7, 0 = 0dB, ... 3dB steps ... 7 = -21dB 600 | boolean setLI2LOVOL(uint8_t volume); 601 | 602 | boolean enableLB2LO(); 603 | boolean disableLB2LO(); 604 | 605 | // 0-7, 0 = 0dB, ... 3dB steps ... 7 = -21dB 606 | boolean setLB2LOVOL(uint8_t volume); 607 | 608 | boolean enableLD2LO(); 609 | boolean disableLD2LO(); 610 | 611 | boolean enableRI2RO(); 612 | boolean disableRI2RO(); 613 | 614 | // 0-7, 0 = 0dB, ... 3dB steps ... 7 = -21dB 615 | boolean setRI2ROVOL(uint8_t volume); 616 | 617 | boolean enableRB2RO(); 618 | boolean disableRB2RO(); 619 | 620 | // 0-7, 0 = 0dB, ... 3dB steps ... 7 = -21dB 621 | boolean setRB2ROVOL(uint8_t volume); 622 | 623 | boolean enableRD2RO(); 624 | boolean disableRD2RO(); 625 | 626 | // Mono Output mixer. 627 | // Note, for capless HPs, we'll want this to output a buffered VMID. 628 | // To do this, we need to disable both of these connections. 629 | boolean enableLI2MO(); 630 | boolean disableLI2MO(); 631 | boolean enableRI2MO(); 632 | boolean disableRI2MO(); 633 | 634 | // This will disable both connections, thus enable VMID on OUT3. Note, 635 | // to enable VMID, you also need to enable OUT3 in the 636 | // WM8960_REG_PWR_MGMT_2 [1] 637 | boolean enableOUT3asVMID(); 638 | 639 | // Enables VMID in the WM8960_REG_PWR_MGMT_1 register, and set's it to 640 | // playback/record settings of 2*50Kohm. 641 | boolean enableVMID(); 642 | boolean disableVMID(); 643 | boolean setVMID(uint8_t setting = WM8960_VMIDSEL_2X50KOHM); 644 | 645 | ///////////////////////////////////////////////////////// 646 | ///////////////////////////////////////////////////////// Headphones 647 | ///////////////////////////////////////////////////////// 648 | 649 | // Enable and disable headphones (mute) 650 | boolean enableHeadphones(); 651 | boolean disableHeadphones(); 652 | boolean enableRightHeadphone(); 653 | boolean disableRightHeadphone(); 654 | boolean enableLeftHeadphone(); 655 | boolean disableLeftHeadphone(); 656 | 657 | boolean enableHeadphoneStandby(); 658 | boolean disableHeadphoneStandby(); 659 | 660 | // Set headphone volume 661 | // Although you can control each headphone output independently, here 662 | // we are going to assume you want both left and right to do the same 663 | // thing. 664 | 665 | // Valid inputs are 47-127. 0-47 = mute, 48 = -73dB ... 1dB steps ... 666 | // 127 = +6dB 667 | boolean setHeadphoneVolume(uint8_t volume); 668 | // Updates both left and right channels 669 | // Handles the OUT1VU (volume update) bit control, so that it happens at 670 | // the same time on both channels. Note, we must also make sure that the 671 | // outputs are enabled in the WM8960_REG_PWR_MGMT_2 [6:5] 672 | 673 | // Zero Cross prevents zipper sounds on volume changes 674 | // Sets both left and right Headphone outputs 675 | boolean enableHeadphoneZeroCross(); 676 | boolean disableHeadphoneZeroCross(); 677 | 678 | // Set headphone volume dB 679 | // Sets the volume of the headphone output buffer amp to a speicified 680 | // dB value passed in as a float argument. 681 | // Valid dB settings are -74.0 up to +6.0 682 | // User input will be rounded to nearest whole integer 683 | // -74 (or lower) = MUTE 684 | // -73 = -73dB (MIN) 685 | // ... 1dB steps ... 686 | // 0 = 0dB 687 | // ... 1dB steps ... 688 | // 6 = +6dB (MAX) 689 | boolean setHeadphoneVolumeDB(float dB); 690 | 691 | boolean enableHeadphoneJackDetect(); 692 | boolean disableHeadphoneJackDetect(); 693 | boolean setHeadphoneJackDetectInput(uint8_t setting = WM8960_JACKDETECT_LINPUT3); 694 | 695 | ///////////////////////////////////////////////////////// 696 | ///////////////////////////////////////////////////////// Speakers 697 | ///////////////////////////////////////////////////////// 698 | 699 | // Enable and disable speakers (mute) 700 | boolean enableSpeakers(); 701 | boolean disableSpeakers(); 702 | boolean enableRightSpeaker(); 703 | boolean disableRightSpeaker(); 704 | boolean enableLeftSpeaker(); 705 | boolean disableLeftSpeaker(); 706 | 707 | // Set Speaker output volume 708 | // Although you can control each Speaker output independently, here we 709 | // are going to assume you want both left and right to do the same thing. 710 | // Valid inputs are 47-127. 0-47 = mute, 48 = -73dB ... 1dB steps ... 711 | // 127 = +6dB 712 | 713 | boolean setSpeakerVolume(uint8_t volume); 714 | // Updates both left and right channels 715 | // Handles the SPKVU (volume update) bit control, so that it happens at 716 | // the same time on both channels. Note, we must also make sure that the 717 | // outputs are enabled in the WM8960_REG_PWR_MGMT_2 [4:3] 718 | // And the class D control reg WM8960_REG_CLASS_D_CONTROL_1 [7:6] 719 | 720 | boolean setSpeakerVolumeDB(float dB); 721 | 722 | // Zero Cross prevents zipper sounds on volume changes 723 | // Sets both left and right Speaker outputs 724 | boolean enableSpeakerZeroCross(); 725 | boolean disableSpeakerZeroCross(); 726 | 727 | // DC and AC gain - allows signal to be higher than the DACs swing 728 | // (use only if your SPKVDD is high enough to handle a larger signal) 729 | // Valid inputs are 0-5 730 | // 0 = +0dB (1.0x boost) ... up to ... 5 = +5.1dB (1.8x boost) 731 | boolean setSpeakerDcGain(uint8_t gain); 732 | boolean setSpeakerAcGain(uint8_t gain); 733 | 734 | ////////////////////////////////////// 735 | ////////////////////////////////////// Digital audio interface control 736 | ////////////////////////////////////// 737 | 738 | // Defaults to I2S, peripheral-mode, 24-bit word length 739 | 740 | // Loopback 741 | // When enabled, the output data from the ADC audio interface is fed 742 | // directly into the DAC data input. 743 | boolean enableLoopBack(); 744 | boolean disableLoopBack(); 745 | 746 | /////////////////////////////////////////////////////// 747 | /////////////////////////////////////////////////////// Clock controls 748 | /////////////////////////////////////////////////////// 749 | 750 | // Getting the Frequency of SampleRate as we wish 751 | // Our MCLK (an external clock on the SFE breakout board) is 24.0MHz. 752 | // According to table 40 (DS pg 58), we want SYSCLK to be 11.2896 for a 753 | // SR of 44.1KHz. To get that Desired Output (SYSCLK), we need the 754 | // following settings on the PLL stuff: 755 | // As found on table 45 (ds pg 61). 756 | // PRESCALE DIVIDE (PLLPRESCALE): 2 757 | // POSTSCALE DVIDE (SYSCLKDIV[1:0]): 2 758 | // FIXED POST-DIVIDE: 4 759 | // R: 7.5264 760 | // N: 7h 761 | // K: 86C226h 762 | 763 | // Example at bottom of table 46, shows that we should be in fractional 764 | // mode for a 44.1KHz. 765 | 766 | // In terms of registers, this is what we want for 44.1KHz 767 | // PLLEN=1 (PLL enable) 768 | // PLLPRESCALE=1 (divide by 2) *This get's us from MCLK (24MHz) down 769 | // to 12MHZ for F2 770 | // PLLN=7h (PLL N value) *this is "int R" 771 | // PLLK=86C226h (PLL K value) *this is int ( 2^24 * (R- intR)) 772 | // SDM=1 (Fractional mode) 773 | // CLKSEL=1 (PLL select) 774 | // MS=0 (Peripheral mode) 775 | // WL=00 (16 bits) 776 | // SYSCLKDIV=2 (Divide by 2) 777 | // ADCDIV=000 (Divide by 1) = 44.1kHz 778 | // DACDIV=000 (Divide by 1) = 44.1kHz 779 | // BCLKDIV=0100 (Divide by 4) = 64fs 780 | // DCLKDIV=111 (Divide by 16) = 705.6kHz 781 | 782 | // And now for the functions that will set these registers... 783 | boolean enablePLL(); 784 | boolean disablePLL(); 785 | 786 | // Valid options are WM8960_PLLPRESCALE_DIV_1, WM8960_PLLPRESCALE_DIV_2 787 | boolean setPLLPRESCALE(boolean div); 788 | 789 | boolean setPLLN(uint8_t n); 790 | 791 | // Send each nibble of 24-bit value for value K 792 | boolean setPLLK(uint8_t one, uint8_t two, uint8_t three); 793 | 794 | boolean setSMD(boolean mode); // 0=integer, 1=fractional 795 | boolean setCLKSEL(boolean sel); // 0=MCLK, 1=PLL_output 796 | 797 | // (0=divide by 1), (2=div by 2) *1 and 3 are "reserved" 798 | boolean setSYSCLKDIV(uint8_t div); 799 | 800 | // 000 = SYSCLK / (1.0*256). See ds pg 57 for other options 801 | boolean setADCDIV(uint8_t div); 802 | 803 | // 000 = SYSCLK / (1.0*256). See ds pg 57 for other options 804 | boolean setDACDIV(uint8_t div); 805 | 806 | // 0100 (4) = sufficiently high for 24bit, div by 4 allows for max word 807 | // length of 32bit 808 | boolean setBCLKDIV(uint8_t div); 809 | 810 | // Class D amp, 111= SYSCLK/16, so 11.2896MHz/16 = 705.6KHz 811 | boolean setDCLKDIV(uint8_t div); 812 | 813 | // Set LR clock to be the same for ADC & DAC (needed for loopback mode) 814 | boolean setALRCGPIO(); 815 | 816 | boolean enableMasterMode(); 817 | boolean enablePeripheralMode(); 818 | 819 | boolean setWL(uint8_t word_length); 820 | 821 | boolean setLRP(boolean polarity); 822 | 823 | boolean setALRSWAP(boolean swap); 824 | 825 | boolean setVROI(boolean setting); 826 | 827 | boolean setVSEL(uint8_t setting); 828 | 829 | // General-purpose register write 830 | boolean writeRegister(uint8_t reg, uint16_t value); 831 | 832 | // **The WM8960 does not support reading registers!!! 833 | 834 | private: 835 | TwoWire *_i2cPort; 836 | uint8_t _deviceAddress = WM8960_ADDR; 837 | boolean _writeRegisterBit(uint8_t registerAddress, uint8_t bitNumber, boolean bitValue); 838 | boolean _writeRegisterMultiBits(uint8_t registerAddress, uint8_t settingMsbNum, uint8_t settingLsbNum, uint8_t setting); 839 | uint8_t convertDBtoSetting(float dB, float offset, float stepSize, float minDB, float maxDB); 840 | 841 | // The WM8960 does not support I2C reads 842 | // This means we must keep a local copy of all the register values 843 | // We will instantiate with default values 844 | // As we write to the device, we will also make sure 845 | // To update our local copy as well, stored here in this array. 846 | // Each register is 9-bits, so we will store them as a uint16_t 847 | // They are in order from R0-R55, and we even keep blank spots for the 848 | // "reserved" registers. This way we can use the register address macro 849 | // defines above to easiy access each local copy of each register. 850 | // Example: _registerLocalCopy[WM8960_REG_LEFT_INPUT_VOLUME] 851 | uint16_t _registerLocalCopy[56] = { 852 | 0x0097, // R0 (0x00) 853 | 0x0097, // R1 (0x01) 854 | 0x0000, // R2 (0x02) 855 | 0x0000, // R3 (0x03) 856 | 0x0000, // R4 (0x04) 857 | 0x0008, // F5 (0x05) 858 | 0x0000, // R6 (0x06) 859 | 0x000A, // R7 (0x07) 860 | 0x01C0, // R8 (0x08) 861 | 0x0000, // R9 (0x09) 862 | 0x00FF, // R10 (0x0a) 863 | 0x00FF, // R11 (0x0b) 864 | 0x0000, // R12 (0x0C) RESERVED 865 | 0x0000, // R13 (0x0D) RESERVED 866 | 0x0000, // R14 (0x0E) RESERVED 867 | 0x0000, // R15 (0x0F) RESERVED 868 | 0x0000, // R16 (0x10) 869 | 0x007B, // R17 (0x11) 870 | 0x0100, // R18 (0x12) 871 | 0x0032, // R19 (0x13) 872 | 0x0000, // R20 (0x14) 873 | 0x00C3, // R21 (0x15) 874 | 0x00C3, // R22 (0x16) 875 | 0x01C0, // R23 (0x17) 876 | 0x0000, // R24 (0x18) 877 | 0x0000, // R25 (0x19) 878 | 0x0000, // R26 (0x1A) 879 | 0x0000, // R27 (0x1B) 880 | 0x0000, // R28 (0x1C) 881 | 0x0000, // R29 (0x1D) 882 | 0x0000, // R30 (0x1E) RESERVED 883 | 0x0000, // R31 (0x1F) RESERVED 884 | 0x0100, // R32 (0x20) 885 | 0x0100, // R33 (0x21) 886 | 0x0050, // R34 (0x22) 887 | 0x0000, // R35 (0x23) RESERVED 888 | 0x0000, // R36 (0x24) RESERVED 889 | 0x0050, // R37 (0x25) 890 | 0x0000, // R38 (0x26) 891 | 0x0000, // R39 (0x27) 892 | 0x0000, // R40 (0x28) 893 | 0x0000, // R41 (0x29) 894 | 0x0040, // R42 (0x2A) 895 | 0x0000, // R43 (0x2B) 896 | 0x0000, // R44 (0x2C) 897 | 0x0050, // R45 (0x2D) 898 | 0x0050, // R46 (0x2E) 899 | 0x0000, // R47 (0x2F) 900 | 0x0002, // R48 (0x30) 901 | 0x0037, // R49 (0x31) 902 | 0x0000, // R50 (0x32) RESERVED 903 | 0x0080, // R51 (0x33) 904 | 0x0008, // R52 (0x34) 905 | 0x0031, // R53 (0x35) 906 | 0x0026, // R54 (0x36) 907 | 0x00e9, // R55 (0x37) 908 | }; 909 | 910 | const uint16_t _registerDefaults[56] = { 911 | 0x0097, // R0 (0x00) 912 | 0x0097, // R1 (0x01) 913 | 0x0000, // R2 (0x02) 914 | 0x0000, // R3 (0x03) 915 | 0x0000, // R4 (0x04) 916 | 0x0008, // F5 (0x05) 917 | 0x0000, // R6 (0x06) 918 | 0x000A, // R7 (0x07) 919 | 0x01C0, // R8 (0x08) 920 | 0x0000, // R9 (0x09) 921 | 0x00FF, // R10 (0x0a) 922 | 0x00FF, // R11 (0x0b) 923 | 0x0000, // R12 (0x0C) RESERVED 924 | 0x0000, // R13 (0x0D) RESERVED 925 | 0x0000, // R14 (0x0E) RESERVED 926 | 0x0000, // R15 (0x0F) RESERVED 927 | 0x0000, // R16 (0x10) 928 | 0x007B, // R17 (0x11) 929 | 0x0100, // R18 (0x12) 930 | 0x0032, // R19 (0x13) 931 | 0x0000, // R20 (0x14) 932 | 0x00C3, // R21 (0x15) 933 | 0x00C3, // R22 (0x16) 934 | 0x01C0, // R23 (0x17) 935 | 0x0000, // R24 (0x18) 936 | 0x0000, // R25 (0x19) 937 | 0x0000, // R26 (0x1A) 938 | 0x0000, // R27 (0x1B) 939 | 0x0000, // R28 (0x1C) 940 | 0x0000, // R29 (0x1D) 941 | 0x0000, // R30 (0x1E) RESERVED 942 | 0x0000, // R31 (0x1F) RESERVED 943 | 0x0100, // R32 (0x20) 944 | 0x0100, // R33 (0x21) 945 | 0x0050, // R34 (0x22) 946 | 0x0000, // R35 (0x23) RESERVED 947 | 0x0000, // R36 (0x24) RESERVED 948 | 0x0050, // R37 (0x25) 949 | 0x0000, // R38 (0x26) 950 | 0x0000, // R39 (0x27) 951 | 0x0000, // R40 (0x28) 952 | 0x0000, // R41 (0x29) 953 | 0x0040, // R42 (0x2A) 954 | 0x0000, // R43 (0x2B) 955 | 0x0000, // R44 (0x2C) 956 | 0x0050, // R45 (0x2D) 957 | 0x0050, // R46 (0x2E) 958 | 0x0000, // R47 (0x2F) 959 | 0x0002, // R48 (0x30) 960 | 0x0037, // R49 (0x31) 961 | 0x0000, // R50 (0x32) RESERVED 962 | 0x0080, // R51 (0x33) 963 | 0x0008, // R52 (0x34) 964 | 0x0031, // R53 (0x35) 965 | 0x0026, // R54 (0x36) 966 | 0x00e9, // R55 (0x37) 967 | }; 968 | }; 969 | #endif 970 | --------------------------------------------------------------------------------