Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * wm8960.c
- */
- #include "wm8960.h"
- #include "stm32f4xx_hal_def.h"
- #include "stm32f4xx_hal_i2c.h"
- #include <stdint.h>
- #include <stdlib.h>
- #include <string.h>
- // Copied from
- // https://github.com/sparkfun/SparkFun_WM8960_Arduino_Library/blob/main/src/SparkFun_WM8960_Arduino_Library.h
- // {{{
- // The WM8960 does not support I2C reads This means we must keep a local
- // copy of all the register values We will instantiate with default values As we
- // write to the device, we will also make sure To update our local copy as well,
- // stored here in this array. Each register is 9-bits, so we will store them as
- // a uint16_t They are in order from R0-R55, and we even keep blank spots for
- // the "reserved" registers. This way we can use the register address macro
- // defines above to easily access each local copy of each register.
- // Example: _registerLocalCopy[WM8960_REG_LEFT_INPUT_VOLUME]
- const uint16_t REGISTER_DEFAULTS[56] = {
- 0x0097, // R0 (0x00)
- 0x0097, // R1 (0x01)
- 0x0000, // R2 (0x02)
- 0x0000, // R3 (0x03)
- 0x0000, // R4 (0x04)
- 0x0008, // F5 (0x05)
- 0x0000, // R6 (0x06)
- 0x000A, // R7 (0x07)
- 0x01C0, // R8 (0x08)
- 0x0000, // R9 (0x09)
- 0x00FF, // R10 (0x0a)
- 0x00FF, // R11 (0x0b)
- 0x0000, // R12 (0x0C) RESERVED
- 0x0000, // R13 (0x0D) RESERVED
- 0x0000, // R14 (0x0E) RESERVED
- 0x0000, // R15 (0x0F) RESERVED
- 0x0000, // R16 (0x10)
- 0x007B, // R17 (0x11)
- 0x0100, // R18 (0x12)
- 0x0032, // R19 (0x13)
- 0x0000, // R20 (0x14)
- 0x00C3, // R21 (0x15)
- 0x00C3, // R22 (0x16)
- 0x01C0, // R23 (0x17)
- 0x0000, // R24 (0x18)
- 0x0000, // R25 (0x19)
- 0x0000, // R26 (0x1A)
- 0x0000, // R27 (0x1B)
- 0x0000, // R28 (0x1C)
- 0x0000, // R29 (0x1D)
- 0x0000, // R30 (0x1E) RESERVED
- 0x0000, // R31 (0x1F) RESERVED
- 0x0100, // R32 (0x20)
- 0x0100, // R33 (0x21)
- 0x0050, // R34 (0x22)
- 0x0000, // R35 (0x23) RESERVED
- 0x0000, // R36 (0x24) RESERVED
- 0x0050, // R37 (0x25)
- 0x0000, // R38 (0x26)
- 0x0000, // R39 (0x27)
- 0x0000, // R40 (0x28)
- 0x0000, // R41 (0x29)
- 0x0040, // R42 (0x2A)
- 0x0000, // R43 (0x2B)
- 0x0000, // R44 (0x2C)
- 0x0050, // R45 (0x2D)
- 0x0050, // R46 (0x2E)
- 0x0000, // R47 (0x2F)
- 0x0002, // R48 (0x30)
- 0x0037, // R49 (0x31)
- 0x0000, // R50 (0x32) RESERVED
- 0x0080, // R51 (0x33)
- 0x0008, // R52 (0x34)
- 0x0031, // R53 (0x35)
- 0x0026, // R54 (0x36)
- 0x00e9, // R55 (0x37)
- };
- // }}}
- // Private API {{{
- HAL_StatusTypeDef _writeRegister(WM8960_t *dev, uint16_t address, uint8_t data,
- uint16_t dataSize) {
- return HAL_I2C_Mem_Write(dev->i2cHandle, WM8960_I2C_ADDR, address,
- I2C_MEMADD_SIZE_8BIT, &data, dataSize,
- HAL_MAX_DELAY);
- }
- HAL_StatusTypeDef _writeBit(WM8960_t *dev, uint8_t registerAddress,
- uint8_t bitNumber, uint8_t bitValue) {
- uint8_t currentRegisterValue = dev->registerState[registerAddress];
- if (bitValue == 1) {
- currentRegisterValue |= (1 << bitNumber); // Set only the bit we want
- } else {
- currentRegisterValue &= ~(1 << bitNumber); // Clear only the bit we want
- }
- HAL_StatusTypeDef ret =
- _writeRegister(dev, registerAddress, currentRegisterValue, 1);
- if (ret == HAL_OK) {
- dev->registerState[registerAddress] = currentRegisterValue;
- }
- return ret;
- }
- HAL_StatusTypeDef _writeMultiBits(WM8960_t *dev, uint8_t registerAddress,
- uint8_t settingMsbNum, uint8_t settingLsbNum,
- uint8_t setting) {
- uint8_t numOfBits = (settingMsbNum - settingLsbNum) + 1;
- // Get the local copy of the register
- uint16_t regvalue = dev->registerState[registerAddress];
- for (int i = 0; i < numOfBits; i++) {
- regvalue &= ~(1 << (settingLsbNum + i)); // Clear bits we care about
- }
- // Shift and set the bits from in incoming desired setting value
- regvalue |= (setting << settingLsbNum);
- // Write modified value to device
- // If successful, update local copy
- HAL_StatusTypeDef ret = _writeRegister(dev, registerAddress, regvalue, 1);
- if (ret == HAL_OK) {
- dev->registerState[registerAddress] = regvalue;
- }
- return ret;
- }
- HAL_StatusTypeDef _RESET(WM8960_t *dev) {
- // Writing any bit to this register will cause a reset, (1,1) was chosen at
- // random
- return _writeBit(dev, WM8960_REG_RESET, 1, 1);
- }
- /**
- * This enables the whole chip.
- * It defaults to 0 when the chip powers up, and can be set to 0 to save power.
- * See P. 64.
- */
- HAL_StatusTypeDef _VREF(WM8960_t *dev) {
- return _writeBit(dev, WM8960_REG_PWR_MGMT_1, 6, 1);
- }
- HAL_StatusTypeDef _VMIDSEL(WM8960_t *dev) {
- return _writeMultiBits(dev, WM8960_REG_PWR_MGMT_1, 8, 7,
- WM8960_SETTING_VMIDSEL_2X50KOHM);
- }
- /** Enable Left Output mixer */
- HAL_StatusTypeDef _LOMIX(WM8960_t *dev) {
- return _writeBit(dev, WM8960_REG_PWR_MGMT_3, 3, 1);
- }
- /** Enable Right Output mixer */
- HAL_StatusTypeDef _ROMIX(WM8960_t *dev) {
- return _writeBit(dev, WM8960_REG_PWR_MGMT_3, 4, 1);
- }
- /** Enable Left ADC */
- HAL_StatusTypeDef _ADCL(WM8960_t *dev) {
- return _writeBit(dev, WM8960_REG_PWR_MGMT_2, 3, 1);
- }
- /** Enable Right ADC */
- HAL_StatusTypeDef _ADCR(WM8960_t *dev) {
- return _writeBit(dev, WM8960_REG_PWR_MGMT_2, 2, 1);
- }
- // P.23
- HAL_StatusTypeDef _LMICBOOST(WM8960_t *dev) {
- return _writeMultiBits(dev, WM8960_REG_ADCL_SIGNAL_PATH, 5, 4,
- WM8960_SETTING_MIC_BOOST_GAIN_0DB);
- }
- HAL_StatusTypeDef _AINL(WM8960_t *dev) {
- return _writeBit(dev, WM8960_REG_PWR_MGMT_1, 5, 1);
- }
- HAL_StatusTypeDef _AINR(WM8960_t *dev) {
- return _writeBit(dev, WM8960_REG_PWR_MGMT_1, 4, 1);
- }
- HAL_StatusTypeDef _CLKSEL(WM8960_t *dev) {
- // P.57 - MCLK
- return _writeBit(dev, WM8960_REG_CLOCKING_1, 0, 0);
- }
- HAL_StatusTypeDef _SYSCLKDIV(WM8960_t *dev) {
- // P.57 - MCLK is 24mhz, dividing by 2 gives 12mhz ~
- // BCLK output from STM32 is 3mhz
- // Like in that table P.57
- return _writeMultiBits(dev, WM8960_REG_CLOCKING_1, 2, 1,
- WM8960_SYSCLK_DIV_BY_2);
- }
- /*
- * codec.enablePLL(); // Needed for class-d amp clock
- codec.setPLLPRESCALE(WM8960_PLLPRESCALE_DIV_2);
- codec.setSMD(WM8960_PLL_MODE_FRACTIONAL);
- codec.setCLKSEL(WM8960_CLKSEL_PLL);
- codec.setSYSCLKDIV(WM8960_SYSCLK_DIV_BY_2);
- codec.setBCLKDIV(4);
- codec.setDCLKDIV(WM8960_DCLKDIV_16);
- codec.setPLLN(7);
- codec.setPLLK(0x86, 0xC2, 0x26); // PLLK=86C226h
- //codec.setADCDIV(0); // Default is 000 (what we need for 44.1KHz)
- //codec.setDACDIV(0); // Default is 000 (what we need for 44.1KHz)
- codec.setWL(WM8960_WL_16BIT);
- */
- HAL_StatusTypeDef _clockConfiguration(WM8960_t *dev) {
- // P.61
- // The breakout board has a 24mhz crystal supplying MCLK.
- // Use the values from Table 45 to
- return _writeBit(dev, WM8960_REG_PLL_N, 4, WM8960_PLLPRESCALE_DIV_2) +
- _writeMultiBits(dev, WM8960_REG_PLL_N, 3, 0, 0x07) +
- // 0x86C226 See table 45
- _writeMultiBits(dev, WM8960_REG_PLL_K_1, 5, 0, 0x86) +
- _writeMultiBits(dev, WM8960_REG_PLL_K_2, 8, 0, 0xC2) +
- _writeMultiBits(dev, WM8960_REG_PLL_K_3, 8, 0, 0x26) + _CLKSEL(dev) +
- _SYSCLKDIV(dev);
- }
- // P.23
- HAL_StatusTypeDef _RMICBOOST(WM8960_t *dev) {
- return _writeMultiBits(dev, WM8960_REG_ADCR_SIGNAL_PATH, 5, 4,
- WM8960_SETTING_MIC_BOOST_GAIN_0DB);
- }
- HAL_StatusTypeDef _LIN2BOOST(WM8960_t *dev) {
- return _writeMultiBits(dev, WM8960_REG_INPUT_BOOST_MIXER_1, 3, 1,
- WM8960_SETTING_LINBOOST_GAIN_0DB);
- }
- HAL_StatusTypeDef _RMIC(WM8960_t *dev) {
- return _writeBit(dev, WM8960_REG_PWR_MGMT_3, 5, 1);
- }
- HAL_StatusTypeDef _LMIC2B(WM8960_t *dev) {
- return _writeBit(dev, WM8960_REG_ADCL_SIGNAL_PATH, 3, 1);
- }
- HAL_StatusTypeDef _RMIC2B(WM8960_t *dev) {
- return _writeBit(dev, WM8960_REG_ADCR_SIGNAL_PATH, 3, 1);
- }
- HAL_StatusTypeDef _LMIC(WM8960_t *dev) {
- return _writeBit(dev, WM8960_REG_PWR_MGMT_3, 4, 1);
- }
- HAL_StatusTypeDef _LINMUTE(WM8960_t *dev) {
- return _writeBit(dev, WM8960_REG_LEFT_INPUT_VOLUME, 7, 0) +
- // Input PGA Volume Update
- // Writing a 1 to this bit will cause left and right input PGA volumes
- // to be updated (LINVOL and RINVOL)
- _writeBit(dev, WM8960_REG_LEFT_INPUT_VOLUME, 8, 1);
- }
- HAL_StatusTypeDef _RINMUTE(WM8960_t *dev) {
- return _writeBit(dev, WM8960_REG_RIGHT_INPUT_VOLUME, 7, 0) +
- // Input PGA Volume Update
- // Writing a 1 to this bit will cause left and right input PGA volumes
- // to be updated (LINVOL and RINVOL)
- _writeBit(dev, WM8960_REG_RIGHT_INPUT_VOLUME, 8, 1);
- }
- HAL_StatusTypeDef _RIN2BOOST(WM8960_t *dev) {
- return _writeMultiBits(dev, WM8960_REG_INPUT_BOOST_MIXER_2, 3, 1,
- WM8960_SETTING_LINBOOST_GAIN_0DB);
- }
- /** Set the codec in Master mode, slave by default */
- HAL_StatusTypeDef _MS_setMaster(WM8960_t *dev) {
- return _writeBit(dev, WM8960_REG_AUDIO_INTERFACE_1, 6, 1);
- }
- HAL_StatusTypeDef _MS_setSlave(WM8960_t *dev) {
- return _writeBit(dev, WM8960_REG_AUDIO_INTERFACE_1, 6, 0);
- }
- // }}}
- // Public API {{{
- bool WM8960_isReady(I2C_HandleTypeDef *hi2c) {
- return HAL_I2C_IsDeviceReady(hi2c, WM8960_I2C_ADDR, 5, 100) == HAL_OK;
- }
- HAL_StatusTypeDef WM8960_init(I2C_HandleTypeDef *hi2c, WM8960_t **o_dev) {
- *o_dev = malloc(sizeof(WM8960_t));
- (*o_dev)->i2cHandle = hi2c;
- memcpy((*o_dev)->registerState, REGISTER_DEFAULTS, sizeof(REGISTER_DEFAULTS));
- HAL_StatusTypeDef halReturnStatus = HAL_OK;
- halReturnStatus += _RESET(*o_dev);
- halReturnStatus += _AINL((*o_dev));
- halReturnStatus += _AINR((*o_dev));
- halReturnStatus += _LMIC2B((*o_dev));
- halReturnStatus += _RMIC2B((*o_dev));
- halReturnStatus += _VREF((*o_dev));
- halReturnStatus += _VMIDSEL((*o_dev));
- halReturnStatus += _LOMIX((*o_dev));
- halReturnStatus += _ROMIX((*o_dev));
- halReturnStatus += _LMICBOOST((*o_dev));
- halReturnStatus += _RMICBOOST((*o_dev));
- halReturnStatus += _LIN2BOOST((*o_dev));
- halReturnStatus += _RIN2BOOST((*o_dev));
- halReturnStatus += _RMIC((*o_dev));
- halReturnStatus += _LMIC((*o_dev));
- halReturnStatus += _RINMUTE((*o_dev));
- halReturnStatus += _LINMUTE((*o_dev));
- // halReturnStatus += _MS_setMaster(*o_dev);
- halReturnStatus += _clockConfiguration(*o_dev);
- halReturnStatus += _MS_setSlave((*o_dev));
- halReturnStatus += _ADCL((*o_dev));
- halReturnStatus += _ADCR((*o_dev));
- if (halReturnStatus != HAL_OK) {
- free((*o_dev));
- (*o_dev) = NULL;
- return halReturnStatus;
- }
- return halReturnStatus;
- }
- // }}}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement