Advertisement
Guest User

Untitled

a guest
Sep 11th, 2024
65
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 10.67 KB | None | 0 0
  1. /*
  2.  * wm8960.c
  3.  */
  4.  
  5. #include "wm8960.h"
  6. #include "stm32f4xx_hal_def.h"
  7. #include "stm32f4xx_hal_i2c.h"
  8. #include <stdint.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11.  
  12. // Copied from
  13. // https://github.com/sparkfun/SparkFun_WM8960_Arduino_Library/blob/main/src/SparkFun_WM8960_Arduino_Library.h
  14. // {{{
  15. // The WM8960 does not support I2C reads This means we must keep a local
  16. // copy of all the register values We will instantiate with default values As we
  17. // write to the device, we will also make sure To update our local copy as well,
  18. // stored here in this array. Each register is 9-bits, so we will store them as
  19. // a uint16_t They are in order from R0-R55, and we even keep blank spots for
  20. // the "reserved" registers. This way we can use the register address macro
  21. // defines above to easily access each local copy of each register.
  22. // Example: _registerLocalCopy[WM8960_REG_LEFT_INPUT_VOLUME]
  23. const uint16_t REGISTER_DEFAULTS[56] = {
  24.     0x0097, // R0 (0x00)
  25.     0x0097, // R1 (0x01)
  26.     0x0000, // R2 (0x02)
  27.     0x0000, // R3 (0x03)
  28.     0x0000, // R4 (0x04)
  29.     0x0008, // F5 (0x05)
  30.     0x0000, // R6 (0x06)
  31.     0x000A, // R7 (0x07)
  32.     0x01C0, // R8 (0x08)
  33.     0x0000, // R9 (0x09)
  34.     0x00FF, // R10 (0x0a)
  35.     0x00FF, // R11 (0x0b)
  36.     0x0000, // R12 (0x0C) RESERVED
  37.     0x0000, // R13 (0x0D) RESERVED
  38.     0x0000, // R14 (0x0E) RESERVED
  39.     0x0000, // R15 (0x0F) RESERVED
  40.     0x0000, // R16 (0x10)
  41.     0x007B, // R17 (0x11)
  42.     0x0100, // R18 (0x12)
  43.     0x0032, // R19 (0x13)
  44.     0x0000, // R20 (0x14)
  45.     0x00C3, // R21 (0x15)
  46.     0x00C3, // R22 (0x16)
  47.     0x01C0, // R23 (0x17)
  48.     0x0000, // R24 (0x18)
  49.     0x0000, // R25 (0x19)
  50.     0x0000, // R26 (0x1A)
  51.     0x0000, // R27 (0x1B)
  52.     0x0000, // R28 (0x1C)
  53.     0x0000, // R29 (0x1D)
  54.     0x0000, // R30 (0x1E) RESERVED
  55.     0x0000, // R31 (0x1F) RESERVED
  56.     0x0100, // R32 (0x20)
  57.     0x0100, // R33 (0x21)
  58.     0x0050, // R34 (0x22)
  59.     0x0000, // R35 (0x23) RESERVED
  60.     0x0000, // R36 (0x24) RESERVED
  61.     0x0050, // R37 (0x25)
  62.     0x0000, // R38 (0x26)
  63.     0x0000, // R39 (0x27)
  64.     0x0000, // R40 (0x28)
  65.     0x0000, // R41 (0x29)
  66.     0x0040, // R42 (0x2A)
  67.     0x0000, // R43 (0x2B)
  68.     0x0000, // R44 (0x2C)
  69.     0x0050, // R45 (0x2D)
  70.     0x0050, // R46 (0x2E)
  71.     0x0000, // R47 (0x2F)
  72.     0x0002, // R48 (0x30)
  73.     0x0037, // R49 (0x31)
  74.     0x0000, // R50 (0x32) RESERVED
  75.     0x0080, // R51 (0x33)
  76.     0x0008, // R52 (0x34)
  77.     0x0031, // R53 (0x35)
  78.     0x0026, // R54 (0x36)
  79.     0x00e9, // R55 (0x37)
  80. };
  81. // }}}
  82.  
  83. // Private API {{{
  84. HAL_StatusTypeDef _writeRegister(WM8960_t *dev, uint16_t address, uint8_t data,
  85.                                  uint16_t dataSize) {
  86.   return HAL_I2C_Mem_Write(dev->i2cHandle, WM8960_I2C_ADDR, address,
  87.                            I2C_MEMADD_SIZE_8BIT, &data, dataSize,
  88.                            HAL_MAX_DELAY);
  89. }
  90.  
  91. HAL_StatusTypeDef _writeBit(WM8960_t *dev, uint8_t registerAddress,
  92.                             uint8_t bitNumber, uint8_t bitValue) {
  93.   uint8_t currentRegisterValue = dev->registerState[registerAddress];
  94.  
  95.   if (bitValue == 1) {
  96.     currentRegisterValue |= (1 << bitNumber); // Set only the bit we want
  97.   } else {
  98.     currentRegisterValue &= ~(1 << bitNumber); // Clear only the bit we want
  99.   }
  100.  
  101.   HAL_StatusTypeDef ret =
  102.       _writeRegister(dev, registerAddress, currentRegisterValue, 1);
  103.   if (ret == HAL_OK) {
  104.     dev->registerState[registerAddress] = currentRegisterValue;
  105.   }
  106.   return ret;
  107. }
  108.  
  109. HAL_StatusTypeDef _writeMultiBits(WM8960_t *dev, uint8_t registerAddress,
  110.                                   uint8_t settingMsbNum, uint8_t settingLsbNum,
  111.                                   uint8_t setting) {
  112.   uint8_t numOfBits = (settingMsbNum - settingLsbNum) + 1;
  113.  
  114.   // Get the local copy of the register
  115.   uint16_t regvalue = dev->registerState[registerAddress];
  116.  
  117.   for (int i = 0; i < numOfBits; i++) {
  118.     regvalue &= ~(1 << (settingLsbNum + i)); // Clear bits we care about
  119.   }
  120.  
  121.   // Shift and set the bits from in incoming desired setting value
  122.   regvalue |= (setting << settingLsbNum);
  123.  
  124.   // Write modified value to device
  125.   // If successful, update local copy
  126.   HAL_StatusTypeDef ret = _writeRegister(dev, registerAddress, regvalue, 1);
  127.   if (ret == HAL_OK) {
  128.     dev->registerState[registerAddress] = regvalue;
  129.   }
  130.   return ret;
  131. }
  132.  
  133. HAL_StatusTypeDef _RESET(WM8960_t *dev) {
  134.   // Writing any bit to this register will cause a reset, (1,1) was chosen at
  135.   // random
  136.   return _writeBit(dev, WM8960_REG_RESET, 1, 1);
  137. }
  138.  
  139. /**
  140.  * This enables the whole chip.
  141.  * It defaults to 0 when the chip powers up, and can be set to 0 to save power.
  142.  * See P. 64.
  143.  */
  144. HAL_StatusTypeDef _VREF(WM8960_t *dev) {
  145.   return _writeBit(dev, WM8960_REG_PWR_MGMT_1, 6, 1);
  146. }
  147.  
  148. HAL_StatusTypeDef _VMIDSEL(WM8960_t *dev) {
  149.   return _writeMultiBits(dev, WM8960_REG_PWR_MGMT_1, 8, 7,
  150.                          WM8960_SETTING_VMIDSEL_2X50KOHM);
  151. }
  152.  
  153. /** Enable Left Output mixer */
  154. HAL_StatusTypeDef _LOMIX(WM8960_t *dev) {
  155.   return _writeBit(dev, WM8960_REG_PWR_MGMT_3, 3, 1);
  156. }
  157.  
  158. /** Enable Right Output mixer */
  159. HAL_StatusTypeDef _ROMIX(WM8960_t *dev) {
  160.   return _writeBit(dev, WM8960_REG_PWR_MGMT_3, 4, 1);
  161. }
  162.  
  163. /** Enable Left ADC */
  164. HAL_StatusTypeDef _ADCL(WM8960_t *dev) {
  165.   return _writeBit(dev, WM8960_REG_PWR_MGMT_2, 3, 1);
  166. }
  167.  
  168. /** Enable Right ADC */
  169. HAL_StatusTypeDef _ADCR(WM8960_t *dev) {
  170.   return _writeBit(dev, WM8960_REG_PWR_MGMT_2, 2, 1);
  171. }
  172.  
  173. // P.23
  174. HAL_StatusTypeDef _LMICBOOST(WM8960_t *dev) {
  175.   return _writeMultiBits(dev, WM8960_REG_ADCL_SIGNAL_PATH, 5, 4,
  176.                          WM8960_SETTING_MIC_BOOST_GAIN_0DB);
  177. }
  178.  
  179. HAL_StatusTypeDef _AINL(WM8960_t *dev) {
  180.   return _writeBit(dev, WM8960_REG_PWR_MGMT_1, 5, 1);
  181. }
  182.  
  183. HAL_StatusTypeDef _AINR(WM8960_t *dev) {
  184.   return _writeBit(dev, WM8960_REG_PWR_MGMT_1, 4, 1);
  185. }
  186.  
  187. HAL_StatusTypeDef _CLKSEL(WM8960_t *dev) {
  188.   // P.57 - MCLK
  189.   return _writeBit(dev, WM8960_REG_CLOCKING_1, 0, 0);
  190. }
  191.  
  192. HAL_StatusTypeDef _SYSCLKDIV(WM8960_t *dev) {
  193.   // P.57 - MCLK is 24mhz, dividing by 2 gives 12mhz ~
  194.   // BCLK output from STM32 is 3mhz
  195.   // Like in that table P.57
  196.   return _writeMultiBits(dev, WM8960_REG_CLOCKING_1, 2, 1,
  197.                          WM8960_SYSCLK_DIV_BY_2);
  198. }
  199.  
  200. /*
  201.  *   codec.enablePLL(); // Needed for class-d amp clock
  202.   codec.setPLLPRESCALE(WM8960_PLLPRESCALE_DIV_2);
  203.   codec.setSMD(WM8960_PLL_MODE_FRACTIONAL);
  204.   codec.setCLKSEL(WM8960_CLKSEL_PLL);
  205.   codec.setSYSCLKDIV(WM8960_SYSCLK_DIV_BY_2);
  206.   codec.setBCLKDIV(4);
  207.   codec.setDCLKDIV(WM8960_DCLKDIV_16);
  208.   codec.setPLLN(7);
  209.   codec.setPLLK(0x86, 0xC2, 0x26); // PLLK=86C226h
  210.   //codec.setADCDIV(0); // Default is 000 (what we need for 44.1KHz)
  211.   //codec.setDACDIV(0); // Default is 000 (what we need for 44.1KHz)
  212.   codec.setWL(WM8960_WL_16BIT);
  213.  
  214.  */
  215.  
  216. HAL_StatusTypeDef _clockConfiguration(WM8960_t *dev) {
  217.   // P.61
  218.   // The breakout board has a 24mhz crystal supplying MCLK.
  219.   // Use the values from Table 45 to
  220.   return _writeBit(dev, WM8960_REG_PLL_N, 4, WM8960_PLLPRESCALE_DIV_2) +
  221.          _writeMultiBits(dev, WM8960_REG_PLL_N, 3, 0, 0x07) +
  222.          // 0x86C226 See table 45
  223.          _writeMultiBits(dev, WM8960_REG_PLL_K_1, 5, 0, 0x86) +
  224.          _writeMultiBits(dev, WM8960_REG_PLL_K_2, 8, 0, 0xC2) +
  225.          _writeMultiBits(dev, WM8960_REG_PLL_K_3, 8, 0, 0x26) + _CLKSEL(dev) +
  226.          _SYSCLKDIV(dev);
  227. }
  228.  
  229. // P.23
  230. HAL_StatusTypeDef _RMICBOOST(WM8960_t *dev) {
  231.   return _writeMultiBits(dev, WM8960_REG_ADCR_SIGNAL_PATH, 5, 4,
  232.                          WM8960_SETTING_MIC_BOOST_GAIN_0DB);
  233. }
  234.  
  235. HAL_StatusTypeDef _LIN2BOOST(WM8960_t *dev) {
  236.   return _writeMultiBits(dev, WM8960_REG_INPUT_BOOST_MIXER_1, 3, 1,
  237.                          WM8960_SETTING_LINBOOST_GAIN_0DB);
  238. }
  239.  
  240. HAL_StatusTypeDef _RMIC(WM8960_t *dev) {
  241.   return _writeBit(dev, WM8960_REG_PWR_MGMT_3, 5, 1);
  242. }
  243.  
  244. HAL_StatusTypeDef _LMIC2B(WM8960_t *dev) {
  245.   return _writeBit(dev, WM8960_REG_ADCL_SIGNAL_PATH, 3, 1);
  246. }
  247.  
  248. HAL_StatusTypeDef _RMIC2B(WM8960_t *dev) {
  249.   return _writeBit(dev, WM8960_REG_ADCR_SIGNAL_PATH, 3, 1);
  250. }
  251.  
  252. HAL_StatusTypeDef _LMIC(WM8960_t *dev) {
  253.   return _writeBit(dev, WM8960_REG_PWR_MGMT_3, 4, 1);
  254. }
  255.  
  256. HAL_StatusTypeDef _LINMUTE(WM8960_t *dev) {
  257.   return _writeBit(dev, WM8960_REG_LEFT_INPUT_VOLUME, 7, 0) +
  258.  
  259.          // Input PGA Volume Update
  260.          // Writing a 1 to this bit will cause left and right input PGA volumes
  261.          // to be updated (LINVOL and RINVOL)
  262.          _writeBit(dev, WM8960_REG_LEFT_INPUT_VOLUME, 8, 1);
  263. }
  264.  
  265. HAL_StatusTypeDef _RINMUTE(WM8960_t *dev) {
  266.   return _writeBit(dev, WM8960_REG_RIGHT_INPUT_VOLUME, 7, 0) +
  267.          // Input PGA Volume Update
  268.          // Writing a 1 to this bit will cause left and right input PGA volumes
  269.          // to be updated (LINVOL and RINVOL)
  270.          _writeBit(dev, WM8960_REG_RIGHT_INPUT_VOLUME, 8, 1);
  271. }
  272.  
  273. HAL_StatusTypeDef _RIN2BOOST(WM8960_t *dev) {
  274.   return _writeMultiBits(dev, WM8960_REG_INPUT_BOOST_MIXER_2, 3, 1,
  275.                          WM8960_SETTING_LINBOOST_GAIN_0DB);
  276. }
  277.  
  278. /** Set the codec in Master mode, slave by default */
  279. HAL_StatusTypeDef _MS_setMaster(WM8960_t *dev) {
  280.   return _writeBit(dev, WM8960_REG_AUDIO_INTERFACE_1, 6, 1);
  281. }
  282.  
  283. HAL_StatusTypeDef _MS_setSlave(WM8960_t *dev) {
  284.   return _writeBit(dev, WM8960_REG_AUDIO_INTERFACE_1, 6, 0);
  285. }
  286.  
  287. // }}}
  288.  
  289. // Public API {{{
  290.  
  291. bool WM8960_isReady(I2C_HandleTypeDef *hi2c) {
  292.   return HAL_I2C_IsDeviceReady(hi2c, WM8960_I2C_ADDR, 5, 100) == HAL_OK;
  293. }
  294.  
  295. HAL_StatusTypeDef WM8960_init(I2C_HandleTypeDef *hi2c, WM8960_t **o_dev) {
  296.   *o_dev = malloc(sizeof(WM8960_t));
  297.  
  298.   (*o_dev)->i2cHandle = hi2c;
  299.  
  300.   memcpy((*o_dev)->registerState, REGISTER_DEFAULTS, sizeof(REGISTER_DEFAULTS));
  301.  
  302.   HAL_StatusTypeDef halReturnStatus = HAL_OK;
  303.  
  304.   halReturnStatus += _RESET(*o_dev);
  305.  
  306.   halReturnStatus += _AINL((*o_dev));
  307.   halReturnStatus += _AINR((*o_dev));
  308.  
  309.   halReturnStatus += _LMIC2B((*o_dev));
  310.   halReturnStatus += _RMIC2B((*o_dev));
  311.  
  312.   halReturnStatus += _VREF((*o_dev));
  313.   halReturnStatus += _VMIDSEL((*o_dev));
  314.   halReturnStatus += _LOMIX((*o_dev));
  315.   halReturnStatus += _ROMIX((*o_dev));
  316.   halReturnStatus += _LMICBOOST((*o_dev));
  317.   halReturnStatus += _RMICBOOST((*o_dev));
  318.   halReturnStatus += _LIN2BOOST((*o_dev));
  319.   halReturnStatus += _RIN2BOOST((*o_dev));
  320.   halReturnStatus += _RMIC((*o_dev));
  321.   halReturnStatus += _LMIC((*o_dev));
  322.   halReturnStatus += _RINMUTE((*o_dev));
  323.   halReturnStatus += _LINMUTE((*o_dev));
  324.   // halReturnStatus += _MS_setMaster(*o_dev);
  325.   halReturnStatus += _clockConfiguration(*o_dev);
  326.  
  327.   halReturnStatus += _MS_setSlave((*o_dev));
  328.  
  329.   halReturnStatus += _ADCL((*o_dev));
  330.   halReturnStatus += _ADCR((*o_dev));
  331.  
  332.   if (halReturnStatus != HAL_OK) {
  333.     free((*o_dev));
  334.     (*o_dev) = NULL;
  335.     return halReturnStatus;
  336.   }
  337.  
  338.   return halReturnStatus;
  339. }
  340.  
  341. // }}}
  342.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement