PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

control_tlv320aic3206.cpp 30KB

vor 3 Jahren
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. /*
  2. control_tlv320aic3206
  3. Created: Brendan Flynn (http://www.flexvoltbiosensor.com/) for Tympan, Jan-Feb 2017
  4. Purpose: Control module for Texas Instruments TLV320AIC3206 compatible with Teensy Audio Library
  5. License: MIT License. Use at your own risk.
  6. */
  7. #include "control_tlv320aic3206.h"
  8. #include <Wire.h>
  9. //******************************** Constants *******************************//
  10. #define AIC3206_I2C_ADDR 0x18
  11. #ifndef AIC_FS
  12. # define AIC_FS 44100UL
  13. #endif
  14. #define AIC_BITS 16
  15. //#define AIC_BITS 32
  16. #define AIC_I2S_SLAVE 1
  17. #if AIC_I2S_SLAVE
  18. // Direction of BCLK and WCLK (reg 27) is input if a slave:
  19. # define AIC_CLK_DIR 0
  20. #else
  21. // If master, make outputs:
  22. # define AIC_CLK_DIR 0x0C
  23. #endif
  24. //#ifndef AIC_CODEC_CLKIN_BCLK
  25. //# define AIC_CODEC_CLKIN_BCLK 0
  26. //#endif
  27. //**************************** Clock Setup **********************************//
  28. //********************************** 44100 *********************************//
  29. #if AIC_FS == 44100
  30. // MCLK = 180000000 * 16 / 255 = 11.294117 MHz // FROM TEENSY, FIXED
  31. // PLL setup. PLL_OUT = MCLK * R * J.D / P
  32. //// J.D = 7.5264, P = 1, R = 1 => 90.32 MHz // FROM 12MHz CHA AND WHF //
  33. // J.D = 7.9968, P = 1, R = 1 => 90.3168 MHz // For 44.1kHz exact
  34. // J.D = 8.0000000002, P = 1, R = 1 => 9.35294117888MHz // for TEENSY 44.11764706kHz
  35. #define PLL_J 8
  36. #define PLL_D 0
  37. // Bitclock divisor.
  38. // BCLK = DAC_CLK/N = PLL_OUT/NDAC/N = 32*fs or 16*fs
  39. // PLL_OUT = fs*NDAC*MDAC*DOSR
  40. // BLCK = 32*fs = 1411200 = PLL
  41. #if AIC_BITS == 16
  42. #define BCLK_N 8
  43. #elif AIC_BITS == 32
  44. #define BCLK_N 4
  45. #endif
  46. // ADC/DAC FS setup.
  47. // ADC_MOD_CLK = CODEC_CLKIN / (NADC * MADC)
  48. // DAC_MOD_CLK = CODEC_CLKIN / (NDAC * MDAC)
  49. // ADC_FS = PLL_OUT / (NADC*MADC*AOSR)
  50. // DAC_FS = PLL_OUT / (NDAC*MDAC*DOSR)
  51. // FS = 90.3168MHz / (8*2*128) = 44100 Hz.
  52. // MOD = 90.3168MHz / (8*2) = 5644800 Hz
  53. // Actual from Teensy: 44117.64706Hz * 128 => 5647058.82368Hz * 8*2 => 90352941.17888Hz
  54. // DAC clock config.
  55. // Note: MDAC*DOSR/32 >= RC, where RC is 8 for the default filter.
  56. // See Table 2-21
  57. // http://www.ti.com/lit/an/slaa463b/slaa463b.pdf
  58. // PB1 - RC = 8. Use M8, N2
  59. // PB25 - RC = 12. Use M8, N2
  60. #define DOSR 128
  61. #define NDAC 2
  62. #define MDAC 8
  63. #define AOSR 128
  64. #define NADC 2
  65. #define MADC 8
  66. // Signal Processing Modes, Playback and Recording.
  67. #define PRB_P 1
  68. #define PRB_R 1
  69. #endif // end fs if block
  70. //**************************** Chip Setup **********************************//
  71. //******************* INPUT DEFINITIONS *****************************//
  72. // MIC routing registers
  73. #define AIC3206_MICPGA_LEFT_POSITIVE_REG 0x0134 // page 1 register 52
  74. #define AIC3206_MICPGA_LEFT_NEGATIVE_REG 0x0136 // page 1 register 54
  75. #define AIC3206_MICPGA_RIGHT_POSITIVE_REG 0x0137 // page 1 register 55
  76. #define AIC3206_MICPGA_RIGHT_NEGATIVE_REG 0x0139 // page 1 register 57
  77. #define AIC3206_MIC_ROUTING_POSITIVE_IN1 0b11000000 //
  78. #define AIC3206_MIC_ROUTING_POSITIVE_IN2 0b00110000 //
  79. #define AIC3206_MIC_ROUTING_POSITIVE_IN3 0b00001100 //
  80. #define AIC3206_MIC_ROUTING_POSITIVE_REVERSE 0b00000011 //
  81. #define AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L 0b11000000 //
  82. #define AIC3206_MIC_ROUTING_NEGATIVE_IN2_REVERSE 0b00110000 //
  83. #define AIC3206_MIC_ROUTING_NEGATIVE_IN3_REVERSE 0b00001100 //
  84. #define AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM2L 0b00000011 //
  85. #define AIC3206_MIC_ROUTING_RESISTANCE_10k 0b01010101
  86. #define AIC3206_MIC_ROUTING_RESISTANCE_20k 0b10101010
  87. #define AIC3206_MIC_ROUTING_RESISTANCE_40k 0b11111111
  88. #define AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT AIC3206_MIC_ROUTING_RESISTANCE_10k //datasheet (application notes) defaults to 20K...why?
  89. #define AIC3206_MICPGA_LEFT_VOLUME_REG 0x013B // page 1 register 59 // 0 to 47.5dB in 0.5dB steps
  90. #define AIC3206_MICPGA_RIGHT_VOLUME_REG 0x013C // page 1 register 60 // 0 to 47.5dB in 0.5dB steps
  91. #define AIC3206_MICPGA_VOLUME_ENABLE 0x00 // default is 0b11000000 - clear to 0 to enable
  92. #define AIC3206_MIC_BIAS_REG 0x0133 // page 1 reg 51
  93. #define AIC3206_MIC_BIAS_POWER_ON 0x40
  94. #define AIC3206_MIC_BIAS_POWER_OFF 0x00
  95. #define AIC3206_MIC_BIAS_OUTPUT_VOLTAGE_1_25 0x00
  96. #define AIC3206_MIC_BIAS_OUTPUT_VOLTAGE_1_7 0x01
  97. #define AIC3206_MIC_BIAS_OUTPUT_VOLTAGE_2_5 0x10
  98. #define AIC3206_MIC_BIAS_OUTPUT_VOLTAGE_VSUPPLY 0x11
  99. #define AIC3206_ADC_PROCESSING_BLOCK_REG 0x003d // page 0 register 61
  100. #define AIC3206_ADC_CHANNEL_POWER_REG 0x0051 // page 0 register81
  101. #define AIC3206_ADC_CHANNELS_ON 0b11000000 // power up left and right
  102. #define AIC3206_ADC_MUTE_REG 0x0052 // page 0, register 82
  103. #define AIC3206_ADC_UNMUTE 0x00
  104. bool AudioControlTLV320AIC3206::enable(void)
  105. {
  106. delay(100);
  107. // Setup for Master mode, pins 18/19, external pullups, 400kHz, 200ms default timeout
  108. Wire.begin();
  109. delay(5);
  110. //hard reset the AIC
  111. //Serial.println("Hardware reset of AIC...");
  112. //define RESET_PIN 21
  113. #define RESET_PIN (resetPinAIC)
  114. pinMode(RESET_PIN,OUTPUT);
  115. digitalWrite(RESET_PIN,HIGH);delay(50); //not reset
  116. digitalWrite(RESET_PIN,LOW);delay(50); //reset
  117. digitalWrite(RESET_PIN,HIGH);delay(50);//not reset
  118. aic_reset(); delay(100); //soft reset
  119. aic_init(); delay(100);
  120. aic_initADC(); delay(100);
  121. aic_initDAC(); delay(100);
  122. aic_readPage(0, 27); // check a specific register - a register read test
  123. if (debugToSerial) Serial.println("TLV320 enable done");
  124. return true;
  125. }
  126. bool AudioControlTLV320AIC3206::disable(void) {
  127. return true;
  128. }
  129. //dummy function to keep compatible with Teensy Audio Library
  130. bool AudioControlTLV320AIC3206::inputLevel(float volume) {
  131. return false;
  132. }
  133. bool AudioControlTLV320AIC3206::inputSelect(int n) {
  134. if (n == AIC3206_INPUT_IN1) {
  135. aic_writeAddress(AIC3206_MICPGA_LEFT_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN1 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  136. aic_writeAddress(AIC3206_MICPGA_LEFT_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  137. aic_writeAddress(AIC3206_MICPGA_RIGHT_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN1 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  138. aic_writeAddress(AIC3206_MICPGA_RIGHT_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  139. // BIAS OFF
  140. setMicBias(AIC3206_MIC_BIAS_OFF);
  141. if (debugToSerial) Serial.println("Set Audio Input to IN1");
  142. return true;
  143. } else if (n == AIC3206_INPUT_IN3_MICBIAS) {
  144. aic_writeAddress(AIC3206_MICPGA_LEFT_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN3 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  145. aic_writeAddress(AIC3206_MICPGA_LEFT_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  146. aic_writeAddress(AIC3206_MICPGA_RIGHT_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN3 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  147. aic_writeAddress(AIC3206_MICPGA_RIGHT_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  148. // BIAS on, using default
  149. setMicBias(AIC3206_DEFAULT_MIC_BIAS);
  150. if (debugToSerial) Serial.println("Set Audio Input to IN3, BIAS SET TO DEFAULT 2.5V");
  151. return true;
  152. } else if (n == AIC3206_INPUT_IN3) {
  153. aic_writeAddress(AIC3206_MICPGA_LEFT_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN3 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  154. aic_writeAddress(AIC3206_MICPGA_LEFT_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  155. aic_writeAddress(AIC3206_MICPGA_RIGHT_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN3 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  156. aic_writeAddress(AIC3206_MICPGA_RIGHT_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  157. // BIAS Off
  158. setMicBias(AIC3206_MIC_BIAS_OFF);
  159. if (debugToSerial) Serial.println("Set Audio Input to IN3, BIAS OFF");
  160. return true;
  161. } else if (n == AIC3206_INPUT_IN2) {
  162. aic_writeAddress(AIC3206_MICPGA_LEFT_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN2 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  163. aic_writeAddress(AIC3206_MICPGA_LEFT_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  164. aic_writeAddress(AIC3206_MICPGA_RIGHT_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN2 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  165. aic_writeAddress(AIC3206_MICPGA_RIGHT_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  166. // BIAS Off
  167. setMicBias(AIC3206_MIC_BIAS_OFF);
  168. if (debugToSerial) Serial.println("Set Audio Input to IN2, BIAS OFF");
  169. return true;
  170. }
  171. Serial.print("controlTLV320AIC3206: ERROR: Unable to Select Input - Value not supported: ");
  172. Serial.println(n);
  173. return false;
  174. }
  175. bool AudioControlTLV320AIC3206::setMicBias(int n) {
  176. if (n == AIC3206_MIC_BIAS_1_25) {
  177. aic_writeAddress(AIC3206_MIC_BIAS_REG, AIC3206_MIC_BIAS_POWER_ON | AIC3206_MIC_BIAS_OUTPUT_VOLTAGE_1_25); // power up mic bias
  178. return true;
  179. } else if (n == AIC3206_MIC_BIAS_1_7) {
  180. aic_writeAddress(AIC3206_MIC_BIAS_REG, AIC3206_MIC_BIAS_POWER_ON | AIC3206_MIC_BIAS_OUTPUT_VOLTAGE_1_7); // power up mic bias
  181. return true;
  182. } else if (n == AIC3206_MIC_BIAS_2_5) {
  183. aic_writeAddress(AIC3206_MIC_BIAS_REG, AIC3206_MIC_BIAS_POWER_ON | AIC3206_MIC_BIAS_OUTPUT_VOLTAGE_2_5); // power up mic bias
  184. return true;
  185. } else if (n == AIC3206_MIC_BIAS_VSUPPLY) {
  186. aic_writeAddress(AIC3206_MIC_BIAS_REG, AIC3206_MIC_BIAS_POWER_ON | AIC3206_MIC_BIAS_OUTPUT_VOLTAGE_VSUPPLY); // power up mic bias
  187. return true;
  188. } else if (n == AIC3206_MIC_BIAS_OFF) {
  189. aic_writeAddress(AIC3206_MIC_BIAS_REG, AIC3206_MIC_BIAS_POWER_OFF); // power up mic bias
  190. return true;
  191. }
  192. Serial.print("controlTLV320AIC3206: ERROR: Unable to set MIC BIAS - Value not supported: ");
  193. Serial.println(n);
  194. return false;
  195. }
  196. void AudioControlTLV320AIC3206::aic_reset() {
  197. if (debugToSerial) Serial.println("INFO: Reseting AIC");
  198. aic_writePage(0x00, 0x01, 0x01);
  199. // aic_writeAddress(0x0001, 0x01);
  200. delay(10);
  201. }
  202. // example - turn on IN3 - mic jack, with negatives routed to CM1L and with 10k resistance
  203. // aic_writeAddress(AIC3206_LEFT_MICPGA_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN3 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  204. // aic_writeAddress(AIC3206_LEFT_MICPGA_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  205. // aic_writeAddress(AIC3206_RIGHT_MICPGA_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN3 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  206. // aic_writeAddress(AIC3206_RIGHT_MICPGA_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  207. void AudioControlTLV320AIC3206::aic_initADC() {
  208. if (debugToSerial) Serial.println("INFO: Initializing AIC ADC");
  209. aic_writeAddress(AIC3206_ADC_PROCESSING_BLOCK_REG, PRB_R); // processing blocks - ADC
  210. aic_writePage(1, 61, 0); // 0x3D // Select ADC PTM_R4 Power Tune? (this line is from datasheet (application guide, Section 4.2)
  211. aic_writePage(1, 71, 0b00110001); // 0x47 // Set MicPGA startup delay to 3.1ms
  212. aic_writeAddress(AIC3206_MIC_BIAS_REG, AIC3206_MIC_BIAS_POWER_ON | AIC3206_MIC_BIAS_2_5); // power up mic bias
  213. aic_writeAddress(AIC3206_MICPGA_LEFT_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN2 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  214. aic_writeAddress(AIC3206_MICPGA_LEFT_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  215. aic_writeAddress(AIC3206_MICPGA_RIGHT_POSITIVE_REG, AIC3206_MIC_ROUTING_POSITIVE_IN2 & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  216. aic_writeAddress(AIC3206_MICPGA_RIGHT_NEGATIVE_REG, AIC3206_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & AIC3206_MIC_ROUTING_RESISTANCE_DEFAULT);
  217. aic_writeAddress(AIC3206_MICPGA_LEFT_VOLUME_REG, AIC3206_MICPGA_VOLUME_ENABLE); // enable Left MicPGA, set gain to 0 dB
  218. aic_writeAddress(AIC3206_MICPGA_RIGHT_VOLUME_REG, AIC3206_MICPGA_VOLUME_ENABLE); // enable Right MicPGA, set gain to 0 dB
  219. aic_writeAddress(AIC3206_ADC_MUTE_REG, AIC3206_ADC_UNMUTE); // Unmute Left and Right ADC Digital Volume Control
  220. aic_writeAddress(AIC3206_ADC_CHANNEL_POWER_REG, AIC3206_ADC_CHANNELS_ON); // Unmute Left and Right ADC Digital Volume Control
  221. }
  222. // set MICPGA volume, 0-47.5dB in 0.5dB setps
  223. bool AudioControlTLV320AIC3206::setInputGain_dB(float volume) {
  224. if (volume < 0.0) {
  225. volume = 0.0; // 0.0 dB
  226. Serial.println("controlTLV320AIC3206: WARNING: Attempting to set MIC volume outside range");
  227. }
  228. if (volume > 47.5) {
  229. volume = 47.5; // 47.5 dB
  230. Serial.println("controlTLV320AIC3206: WARNING: Attempting to set MIC volume outside range");
  231. }
  232. volume = volume * 2.0; // convert to value map (0.5 dB steps)
  233. int8_t volume_int = (int8_t) (round(volume)); // round
  234. if (debugToSerial) {
  235. Serial.print("INFO: Setting MIC volume to ");
  236. Serial.print(volume, 1);
  237. Serial.print(". Converted to volume map => ");
  238. Serial.println(volume_int);
  239. }
  240. aic_writeAddress(AIC3206_MICPGA_LEFT_VOLUME_REG, AIC3206_MICPGA_VOLUME_ENABLE | volume_int); // enable Left MicPGA, set gain to 0 dB
  241. aic_writeAddress(AIC3206_MICPGA_RIGHT_VOLUME_REG, AIC3206_MICPGA_VOLUME_ENABLE | volume_int); // enable Right MicPGA, set gain to 0 dB
  242. return true;
  243. }
  244. //******************* OUTPUT DEFINITIONS *****************************//
  245. #define AIC3206_DAC_PROCESSING_BLOCK_REG 0x003c // page 0 register 60
  246. #define AIC3206_DAC_VOLUME_LEFT_REG 0x0041 // page 0 reg 65
  247. #define AIC3206_DAC_VOLUME_RIGHT_REG 0x0042 // page 0 reg 66
  248. //volume control, similar to Teensy Audio Board
  249. // value between 0.0 and 1.0. Set to span -58 to +15 dB
  250. bool AudioControlTLV320AIC3206::volume(float volume) {
  251. volume = max(0.0, min(1.0, volume));
  252. float vol_dB = -58.f + (15.0 - (-58.0f)) * volume;
  253. volume_dB(vol_dB);
  254. return true;
  255. }
  256. bool AudioControlTLV320AIC3206::enableAutoMuteDAC(bool enable, uint8_t mute_delay_code=7) {
  257. if (enable) {
  258. mute_delay_code = max(0,min(mute_delay_code,7));
  259. if (mute_delay_code == 0) enable = false;
  260. } else {
  261. mute_delay_code = 0; //this disables the auto mute
  262. }
  263. uint8_t val = aic_readPage(0,64);
  264. val = val & 0b10001111; //clear these bits
  265. val = val | (mute_delay_code << 4); //set these bits
  266. aic_writePage(0,64,val);
  267. return enable;
  268. }
  269. // -63.6 to +24 dB in 0.5dB steps. uses signed 8-bit
  270. bool AudioControlTLV320AIC3206::volume_dB(float volume) {
  271. // Constrain to limits
  272. if (volume > 24.0) {
  273. volume = 24.0;
  274. Serial.println("controlTLV320AIC3206: WARNING: Attempting to set DAC Volume outside range");
  275. }
  276. if (volume < -63.5) {
  277. volume = -63.5;
  278. Serial.println("controlTLV320AIC3206: WARNING: Attempting to set DAC Volume outside range");
  279. }
  280. volume = volume * 2.0; // convert to value map (0.5 dB steps)
  281. int8_t volume_int = (int8_t) (round(volume)); // round
  282. if (debugToSerial) {
  283. Serial.print("controlTLV320AIC3206: Setting DAC volume to ");
  284. Serial.print(volume, 1);
  285. Serial.print(". Converted to volume map => ");
  286. Serial.println(volume_int);
  287. }
  288. aic_writeAddress(AIC3206_DAC_VOLUME_RIGHT_REG, volume_int);
  289. aic_writeAddress(AIC3206_DAC_VOLUME_LEFT_REG, volume_int);
  290. return true;
  291. }
  292. void AudioControlTLV320AIC3206::aic_initDAC() {
  293. if (debugToSerial) Serial.println("controlTLV320AIC3206: Initializing AIC DAC");
  294. outputSelect(AIC3206_OUTPUT_HEADPHONE_JACK_OUT); //default
  295. }
  296. bool AudioControlTLV320AIC3206::outputSelect(int n) {
  297. // PLAYBACK SETUP:
  298. // HPL/HPR are headphone output left and right
  299. // LOL/LOR are line output left and right
  300. aic_writeAddress(AIC3206_DAC_PROCESSING_BLOCK_REG, PRB_P); // processing blocks - DAC
  301. //mute, disable, then power-down everything
  302. aic_writePage(1, 16, 0b01000000); // mute HPL Driver, 0 gain
  303. aic_writePage(1, 17, 0b01000000); // mute HPR Driver, 0 gain
  304. aic_writePage(1, 18, 0b01000000); // mute LOL Driver, 0 gain
  305. aic_writePage(1, 19, 0b01000000); // mute LOR Driver, 0 gain
  306. aic_writePage(0, 63, 0); //disable LDAC/RDAC
  307. aic_writePage(1, 9, 0); // Power down HPL/HPR and LOL/LOR drivers
  308. aic_writePage(1,12,0); //unroute from HPL
  309. aic_writePage(1,13,0); //unroute from HPR
  310. aic_writePage(1,14,0); //unroute from LOL
  311. aic_writePage(1,15,0); //unroute from LOR
  312. if (n == AIC3206_OUTPUT_HEADPHONE_JACK_OUT) {
  313. //aic_writePage(1, 20, 0x25); // 0x14 De-Pop
  314. //aic_writePage(1, 12, 8); // route LDAC/RDAC to HPL/HPR
  315. //aic_writePage(1, 13, 8); // route LDAC/RDAC to HPL/HPR
  316. aic_writePage(1, 12, 0b00001000); // route LDAC/RDAC to HPL/HPR
  317. aic_writePage(1, 13, 0b00001000); // route LDAC/RDAC to HPL/HPR
  318. aic_writePage(0, 63, 0xD6); // 0x3F // Power up LDAC/RDAC
  319. aic_writePage(1, 16, 0); // unmute HPL Driver, 0 gain
  320. aic_writePage(1, 17, 0); // unmute HPR Driver, 0 gain
  321. aic_writePage(1, 9, 0x30); // Power up HPL/HPR drivers 0b00110000
  322. delay(100);
  323. aic_writeAddress(AIC3206_DAC_VOLUME_LEFT_REG, 0); // default to 0 dB
  324. aic_writeAddress(AIC3206_DAC_VOLUME_RIGHT_REG, 0); // default to 0 dB
  325. aic_writePage(0, 64, 0); // 0x40 // Unmute LDAC/RDAC
  326. if (debugToSerial) Serial.println("controlTLV320AIC3206: Set Audio Output to Headphone Jack");
  327. return true;
  328. } else if (n == AIC3206_OUTPUT_LINE_OUT) {
  329. //aic_writePage(1, 20, 0x25); // 0x14 De-Pop
  330. aic_writePage(1, 14, 0b00001000); // route LDAC/RDAC to LOL/LOR
  331. aic_writePage(1, 15, 0b00001000); // route LDAC/RDAC to LOL/LOR
  332. aic_writePage(0, 63, 0xD6); // 0x3F // Power up LDAC/RDAC
  333. aic_writePage(1, 18, 0); // unmute LOL Driver, 0 gain
  334. aic_writePage(1, 19, 0); // unmute LOR Driver, 0 gain
  335. aic_writePage(1, 9, 0b00001100); // Power up LOL/LOR drivers
  336. delay(100);
  337. aic_writeAddress(AIC3206_DAC_VOLUME_LEFT_REG, 0); // default to 0 dB
  338. aic_writeAddress(AIC3206_DAC_VOLUME_RIGHT_REG, 0); // default to 0 dB
  339. aic_writePage(0, 64, 0); // 0x40 // Unmute LDAC/RDAC
  340. if (debugToSerial) Serial.println("controlTLV320AIC3206: Set Audio Output to Line Out");
  341. return true;
  342. } else if (n == AIC3206_OUTPUT_HEADPHONE_AND_LINE_OUT) {
  343. aic_writePage(1, 12, 0b00001000); // route LDAC/RDAC to HPL/HPR
  344. aic_writePage(1, 13, 0b00001000); // route LDAC/RDAC to HPL/HPR
  345. aic_writePage(1, 14, 0b00001000); // route LDAC/RDAC to LOL/LOR
  346. aic_writePage(1, 15, 0b00001000); // route LDAC/RDAC to LOL/LOR
  347. aic_writePage(0, 63, 0xD6); // 0x3F // Power up LDAC/RDAC
  348. aic_writePage(1, 18, 0); // unmute LOL Driver, 0 gain
  349. aic_writePage(1, 19, 0); // unmute LOR Driver, 0 gain
  350. aic_writePage(1, 16, 0); // unmute HPL Driver, 0 gain
  351. aic_writePage(1, 17, 0); // unmute HPR Driver, 0 gain
  352. aic_writePage(1, 9, 0b00111100); // Power up both the HPL/HPR and the LOL/LOR drivers
  353. delay(100);
  354. aic_writeAddress(AIC3206_DAC_VOLUME_LEFT_REG, 0); // default to 0 dB
  355. aic_writeAddress(AIC3206_DAC_VOLUME_RIGHT_REG, 0); // default to 0 dB
  356. aic_writePage(0, 64, 0); // 0x40 // Unmute LDAC/RDAC
  357. if (debugToSerial) Serial.println("controlTLV320AIC3206: Set Audio Output to Headphone Jack and Line out");
  358. return true;
  359. }
  360. Serial.print("controlTLV320AIC3206: ERROR: Unable to Select Output - Value not supported: ");
  361. Serial.println(n);
  362. return false;
  363. }
  364. void AudioControlTLV320AIC3206::aic_init() {
  365. if (debugToSerial) Serial.println("controlTLV320AIC3206: Initializing AIC");
  366. // PLL
  367. aic_writePage(0, 4, 3); // 0x04 low PLL clock range, MCLK is PLL input, PLL_OUT is CODEC_CLKIN
  368. aic_writePage(0, 5, (PLL_J != 0 ? 0x91 : 0x11));
  369. aic_writePage(0, 6, PLL_J);
  370. aic_writePage(0, 7, PLL_D >> 8);
  371. aic_writePage(0, 8, PLL_D &0xFF);
  372. // CLOCKS
  373. aic_writePage(0, 11, 0x80 | NDAC); // 0x0B
  374. aic_writePage(0, 12, 0x80 | MDAC); // 0x0C
  375. aic_writePage(0, 13, 0); // 0x0D
  376. aic_writePage(0, 14, DOSR); // 0x0E
  377. // aic_writePage(0, 18, 0); // 0x12 // powered down, ADC_CLK same as DAC_CLK
  378. // aic_writePage(0, 19, 0); // 0x13 // powered down, ADC_MOD_CLK same as DAC_MOD_CLK
  379. aic_writePage(0, 18, 0x80 | NADC); // 0x12
  380. aic_writePage(0, 19, 0x80 | MADC); // 0x13
  381. aic_writePage(0, 20, AOSR);
  382. aic_writePage(0, 30, 0x80 | BCLK_N); // power up BLCK N Divider, default is 128
  383. // POWER
  384. aic_writePage(1, 0x01, 8); // Reg 1, Val = 8 = 0b00001000 = disable weak connection AVDD to DVDD. Keep headphone charge pump disabled.
  385. aic_writePage(1, 0x02, 0); // Reg 2, Val = 0 = 0b00000000 = Enable Master Analog Power Control
  386. aic_writePage(1, 0x7B, 1); // Reg 123, Val = 1 = 0b00000001 = Set reference to power up in 40ms when analog blocks are powered up
  387. aic_writePage(1, 0x7C, 6); // Reg 124, Val = 6 = 0b00000110 = Charge Pump, full peak current (000), clock divider (110) to Div 6 = 333 kHz
  388. aic_writePage(1, 0x01, 10); // Reg 1, Val = 10 = 0x0A = 0b00001010. Activate headphone charge pump.
  389. aic_writePage(1, 0x0A, 0); // Reg 10, Val = 0 = common mode 0.9 for full chip, HP, LO // from WHF/CHA
  390. aic_writePage(1, 0x47, 0x31); // Reg 71, val = 0x31 = 0b00110001 = Set input power-up time to 3.1ms (for ADC)
  391. aic_writePage(1, 0x7D, 0x53); // Reg 125, Val = 0x53 = 0b01010011 = 0 10 1 00 11: HPL is master gain, Enable ground-centered mode, 100% output power, DC offset correction // from WHF/CHA
  392. // !!!!!!!!! The below writes are from WHF/CHA - probably don't need?
  393. // aic_writePage(1, 1, 10); // 10 = 0b00001010 // weakly connect AVDD to DVDD. Activate charge pump
  394. aic_writePage(0, 27, 0x01 | AIC_CLK_DIR | (AIC_BITS == 32 ? 0x30 : 0)); // 0x1B
  395. // aic_writePage(0, 28, 0); // 0x1C
  396. }
  397. unsigned int AudioControlTLV320AIC3206::aic_readPage(uint8_t page, uint8_t reg)
  398. {
  399. unsigned int val;
  400. if (aic_goToPage(page)) {
  401. Wire.beginTransmission(AIC3206_I2C_ADDR);
  402. Wire.write(reg);
  403. unsigned int result = Wire.endTransmission();
  404. if (result != 0) {
  405. Serial.print("controlTLV320AIC3206: ERROR: Read Page. Page: ");Serial.print(page);
  406. Serial.print(" Reg: ");Serial.print(reg);
  407. Serial.print(". Received Error During Read Page: ");
  408. Serial.println(result);
  409. val = 300 + result;
  410. return val;
  411. }
  412. if (Wire.requestFrom(AIC3206_I2C_ADDR, 1) < 1) {
  413. Serial.print("controlTLV320AIC3206: ERROR: Read Page. Page: ");Serial.print(page);
  414. Serial.print(" Reg: ");Serial.print(reg);
  415. Serial.println(". Nothing to return");
  416. val = 400;
  417. return val;
  418. }
  419. if (Wire.available() >= 1) {
  420. uint16_t val = Wire.read();
  421. if (debugToSerial) {
  422. Serial.print("controlTLV320AIC3206: Read Page. Page: ");Serial.print(page);
  423. Serial.print(" Reg: ");Serial.print(reg);
  424. Serial.print(". Received: ");
  425. Serial.println(val, HEX);
  426. }
  427. return val;
  428. }
  429. } else {
  430. Serial.print("controlTLV320AIC3206: INFO: Read Page. Page: ");Serial.print(page);
  431. Serial.print(" Reg: ");Serial.print(reg);
  432. Serial.println(". Failed to go to read page. Could not go there.");
  433. val = 500;
  434. return val;
  435. }
  436. val = 600;
  437. return val;
  438. }
  439. bool AudioControlTLV320AIC3206::aic_writeAddress(uint16_t address, uint8_t val) {
  440. uint8_t reg = (uint8_t) (address & 0xFF);
  441. uint8_t page = (uint8_t) ((address >> 8) & 0xFF);
  442. return aic_writePage(page, reg, val);
  443. }
  444. bool AudioControlTLV320AIC3206::aic_writePage(uint8_t page, uint8_t reg, uint8_t val) {
  445. if (debugToSerial) {
  446. Serial.print("controlTLV320AIC3206: Write Page. Page: ");Serial.print(page);
  447. Serial.print(" Reg: ");Serial.print(reg);
  448. Serial.print(" Val: ");Serial.println(val);
  449. }
  450. if (aic_goToPage(page)) {
  451. Wire.beginTransmission(AIC3206_I2C_ADDR);
  452. Wire.write(reg);delay(10);
  453. Wire.write(val);delay(10);
  454. uint8_t result = Wire.endTransmission();
  455. if (result == 0) return true;
  456. else {
  457. Serial.print("controlTLV320AIC3206: Received Error During writePage(): Error = ");
  458. Serial.println(result);
  459. }
  460. }
  461. return false;
  462. }
  463. bool AudioControlTLV320AIC3206::aic_goToPage(byte page) {
  464. Wire.beginTransmission(AIC3206_I2C_ADDR);
  465. Wire.write(0x00); delay(10);// page register //was delay(10) from BPF
  466. Wire.write(page); delay(10);// go to page //was delay(10) from BPF
  467. byte result = Wire.endTransmission();
  468. if (result != 0) {
  469. Serial.print("controlTLV320AIC3206: Received Error During goToPage(): Error = ");
  470. Serial.println(result);
  471. if (result == 2) {
  472. // failed to transmit address
  473. //return aic_goToPage(page);
  474. } else if (result == 3) {
  475. // failed to transmit data
  476. //return aic_goToPage(page);
  477. }
  478. return false;
  479. }
  480. return true;
  481. }
  482. bool AudioControlTLV320AIC3206::updateInputBasedOnMicDetect(int setting) {
  483. //read current mic detect setting
  484. int curMicDetVal = readMicDetect();
  485. if (curMicDetVal != prevMicDetVal) {
  486. if (curMicDetVal) {
  487. //enable the microphone input jack as our input
  488. inputSelect(setting);
  489. } else {
  490. //switch back to the on-board mics
  491. inputSelect(AIC3206_INPUT_IN2);
  492. }
  493. }
  494. prevMicDetVal = curMicDetVal;
  495. return (bool)curMicDetVal;
  496. }
  497. bool AudioControlTLV320AIC3206::enableMicDetect(bool state) {
  498. //page 0, register 67
  499. byte curVal = aic_readPage(0,67);
  500. byte newVal = curVal;
  501. if (state) {
  502. //enable
  503. newVal = 0b111010111 & newVal; //set bits 4-2 to be 010 to set debounce to 64 msec
  504. newVal = 0b10000000 | curVal; //force bit 1 to 1 to enable headset to detect
  505. aic_writePage(0,67,newVal); //bit 7 (=1) enable headset detect, bits 4-2 (=010) debounce to 64ms
  506. } else {
  507. //disable
  508. newVal = 0b01111111 & newVal; //force bit 7 to zero to disable headset detect
  509. aic_writePage(0,67,newVal); //bit 7 (=1) enable headset detect, bits 4-2 (=010) debounce to 64ms
  510. }
  511. return state;
  512. }
  513. int AudioControlTLV320AIC3206::readMicDetect(void) {
  514. //page 0, register 46, bit D4 (for D7-D0)
  515. byte curVal = aic_readPage(0,46);
  516. curVal = (curVal & 0b00010000);
  517. curVal = (curVal != 0);
  518. return curVal;
  519. }
  520. void computeFirstOrderHPCoeff_F32(float cutoff_Hz, float fs_Hz, float *coeff) {
  521. //cutoff_Hz is the cutoff frequency in Hz
  522. //fs_Hz is the sample rate in Hz
  523. //First-order Butterworth IIR
  524. //From https://www.dsprelated.com/showcode/199.php
  525. const float pi = 3.141592653589793;
  526. float T = 1.0f/fs_Hz; //sample period
  527. float w = cutoff_Hz * 2.0 * pi;
  528. float A = 1.0f / (tan( (w*T) / 2.0));
  529. coeff[0] = A / (1.0 + A); // first b coefficient
  530. coeff[1] = -coeff[0]; // second b coefficient
  531. coeff[2] = (1.0 - A) / (1.0 + A); //second a coefficient (Matlab sign convention)
  532. coeff[2] = -coeff[2]; //flip to be TI sign convention
  533. }
  534. #define CONST_2_31_m1 (2147483647) //2^31 - 1
  535. void computeFirstOrderHPCoeff_i32(float cutoff_Hz, float fs_Hz, int32_t *coeff) {
  536. float coeff_f32[3];
  537. computeFirstOrderHPCoeff_F32(cutoff_Hz,fs_Hz,coeff_f32);
  538. for (int i=0; i<3; i++) {
  539. //scale
  540. coeff_f32[i] *= (float)CONST_2_31_m1;
  541. //truncate
  542. coeff[i] = (int32_t)coeff_f32[i];
  543. }
  544. }
  545. void AudioControlTLV320AIC3206::setHPFonADC(bool enable, float cutoff_Hz, float fs_Hz) { //fs_Hz is sample rate
  546. //see TI application guide Section 2.3.3.1.10.1: http://www.ti.com/lit/an/slaa463b/slaa463b.pdf
  547. uint32_t coeff[3];
  548. if (enable) {
  549. HP_cutoff_Hz = cutoff_Hz;
  550. sample_rate_Hz = fs_Hz;
  551. computeFirstOrderHPCoeff_i32(cutoff_Hz,fs_Hz,(int32_t *)coeff);
  552. //Serial.print("enableHPFonADC: coefficients, Hex: ");
  553. //Serial.print(coeff[0],HEX);
  554. //Serial.print(", ");
  555. //Serial.print(coeff[1],HEX);
  556. //Serial.print(", ");
  557. //Serial.print(coeff[2],HEX);
  558. //Serial.println();
  559. } else {
  560. //disable
  561. HP_cutoff_Hz = cutoff_Hz;
  562. //see Table 5-4 in TI application guide Coeff C4, C5, C6
  563. coeff[0] = 0x7FFFFFFF; coeff[1] = 0; coeff[2]=0;
  564. }
  565. setIIRCoeffOnADC(AIC3206_BOTH_CHAN, coeff); //needs twos-compliment
  566. }
  567. //set first-order IIR filter coefficients on ADC
  568. void AudioControlTLV320AIC3206::setIIRCoeffOnADC(int chan, uint32_t *coeff) {
  569. //power down the AIC to allow change in coefficients
  570. uint32_t prev_state = aic_readPage(0x00,0x51);
  571. aic_writePage(0x00,0x51,prev_state & (0b00111111)); //clear first two bits
  572. if (chan == AIC3206_BOTH_CHAN) {
  573. setIIRCoeffOnADC_Left(coeff);
  574. setIIRCoeffOnADC_Right(coeff);
  575. } else if (chan == AIC3206_LEFT_CHAN) {
  576. setIIRCoeffOnADC_Left(coeff);
  577. } else {
  578. setIIRCoeffOnADC_Right(coeff);
  579. }
  580. //power the ADC back up
  581. aic_writePage(0x00,0x51,prev_state); //clear first two bits
  582. }
  583. void AudioControlTLV320AIC3206::setIIRCoeffOnADC_Left(uint32_t *coeff) {
  584. int page;
  585. uint32_t c;
  586. //See TI AIC3206 Application Guide, Table 2-13: http://www.ti.com/lit/an/slaa463b/slaa463b.pdf
  587. //Coeff N0, Coeff C4
  588. page = 8;
  589. c = coeff[0];
  590. aic_writePage(page,24,(uint8_t)(c>>24));
  591. aic_writePage(page,25,(uint8_t)(c>>16));
  592. aic_writePage(page,26,(uint8_t)(c>>8));
  593. //int foo = aic_readPage(page,24); Serial.print("setIIRCoeffOnADC: first coefficient: "); Serial.println(foo);
  594. //Coeff N1, Coeff C5
  595. c = coeff[1];
  596. aic_writePage(page,28,(uint8_t)(c>>24));
  597. aic_writePage(page,29,(uint8_t)(c>>16));
  598. aic_writePage(page,30,(uint8_t)(c>>8));
  599. //Coeff N2, Coeff C6
  600. c = coeff[2];
  601. aic_writePage(page,32,(uint8_t)(c>>24));
  602. aic_writePage(page,33,(uint8_t)(c>>16));
  603. aic_writePage(page,34,(uint8_t)(c>>9));
  604. }
  605. void AudioControlTLV320AIC3206::setIIRCoeffOnADC_Right(uint32_t *coeff) {
  606. int page;
  607. uint32_t c;
  608. //See TI AIC3206 Application Guide, Table 2-13: http://www.ti.com/lit/an/slaa463b/slaa463b.pdf
  609. //Coeff N0, Coeff C36
  610. page = 9;
  611. c = coeff[0];
  612. aic_writePage(page,32,(uint8_t)(c>>24));
  613. aic_writePage(page,33,(uint8_t)(c>>16));
  614. aic_writePage(page,34,(uint8_t)(c>>8));
  615. //Coeff N1, Coeff C37
  616. c = coeff[1];
  617. aic_writePage(page,36,(uint8_t)(c>>24));
  618. aic_writePage(page,37,(uint8_t)(c>>16));
  619. aic_writePage(page,38,(uint8_t)(c>>8));
  620. //Coeff N2, Coeff C39
  621. c = coeff[2];;
  622. aic_writePage(page,40,(uint8_t)(c>>24));
  623. aic_writePage(page,41,(uint8_t)(c>>16));
  624. aic_writePage(page,42,(uint8_t)(c>>8));
  625. }