stm32h743_player/User/bsp/bsp_wm8904.c
2024-03-03 22:46:44 +08:00

318 lines
8.3 KiB
C

#include "bsp_wm8904.h"
#include <stdio.h>
#include <string.h>
#include "FreeRTOS.h"
#include "task.h"
#include "elog.h"
static const char *TAG = "bsp_wm8904";
#define BSP_WM8904_I2C_ADDR 0x34
/*******************************************************************************
* Definitions
******************************************************************************/
#define WM8904_RESET (0x00)
#define WM8904_ANALOG_ADC_0 (0x0A)
#define WM8904_POWER_MGMT_0 (0x0C)
#define WM8904_POWER_MGMT_2 (0x0E)
#define WM8904_POWER_MGMT_6 (0x12)
#define WM8904_CLK_RATES_0 (0x14)
#define WM8904_CLK_RATES_1 (0x15)
#define WM8904_CLK_RATES_2 (0x16)
#define WM8904_AUDIO_IF_0 (0x18)
#define WM8904_AUDIO_IF_1 (0x19)
#define WM8904_AUDIO_IF_2 (0x1A)
#define WM8904_AUDIO_IF_3 (0x1B)
#define WM8904_DAC_DIG_1 (0x21)
#define WM8904_ANALOG_LEFT_IN_0 (0x2C)
#define WM8904_ANALOG_RIGHT_IN_0 (0x2D)
#define WM8904_ANALOG_LEFT_IN_1 (0x2E)
#define WM8904_ANALOG_RIGHT_IN_1 (0x2F)
#define WM8904_ANALOG_OUT1_LEFT (0x39)
#define WM8904_ANALOG_OUT1_RIGHT (0x3A)
#define WM8904_ANALOG_OUT2_LEFT (0x3B)
#define WM8904_ANALOG_OUT2_RIGHT (0x3C)
#define WM8904_ANALOG_OUT12_ZC (0x3D)
#define WM8904_DC_SERVO_0 (0x43)
#define WM8904_DC_SERVO_1 (0x44)
#define WM8904_ANALOG_HP_0 (0x5A)
#define WM8904_CHRG_PUMP_0 (0x62)
#define WM8904_CLS_W_0 (0x68)
#define WM8904_WRT_SEQUENCER_0 (0x6C)
#define WM8904_WRT_SEQUENCER_3 (0x6F)
#define WM8904_WRT_SEQUENCER_4 (0x70)
/*******************************************************************************
* Code
******************************************************************************/
HAL_StatusTypeDef WM8904_WriteRegister(I2C_HandleTypeDef *hi2c, uint8_t reg_addr, uint16_t reg_value)
{
HAL_StatusTypeDef status;
uint8_t reg_bytes[2] = { reg_value >> 8, reg_value & 0xFF };
uint8_t retries = 0;
while (1) {
status = HAL_I2C_Mem_Write(hi2c, BSP_WM8904_I2C_ADDR, reg_addr, 1, reg_bytes, sizeof(reg_bytes), 100);
if (status == HAL_OK) {
elog_debug(TAG, "write register@0x%02X success, value=0x%04X", reg_addr, reg_value);
break;
} else {
elog_error(TAG, "write register@0x%02X failed", reg_addr);
I2C_RESET_CR2(hi2c);
retries ++;
if (retries > 10) {
break;
}
vTaskDelay(pdMS_TO_TICKS(10));
}
}
return status;
}
HAL_StatusTypeDef WM8904_ReadRegister(I2C_HandleTypeDef *hi2c, uint8_t reg_addr, uint16_t *reg_value_out)
{
HAL_StatusTypeDef status;
uint8_t reg_bytes[2] = { 0 };
uint8_t retries = 0;
while (1) {
status = HAL_I2C_Mem_Read(hi2c, BSP_WM8904_I2C_ADDR, reg_addr, 1, reg_bytes, sizeof(reg_bytes), 100);
*reg_value_out = (reg_bytes[0] << 8) | reg_bytes[1];
if (status == HAL_OK) {
elog_debug(TAG, "read register@0x%02X success, value=0x%04X", reg_addr, *reg_value_out);
break;
} else {
elog_error(TAG, "read register@0x%02X failed", reg_addr);
I2C_RESET_CR2(hi2c);
retries ++;
if (retries > 10) {
break;
}
vTaskDelay(pdMS_TO_TICKS(10));
}
}
return status;
}
HAL_StatusTypeDef WM8904_ModifyRegister(I2C_HandleTypeDef *hi2c, uint8_t reg, uint16_t mask, uint16_t value)
{
uint16_t reg_value;
HAL_StatusTypeDef ret;
ret = WM8904_ReadRegister(hi2c, reg, &reg_value);
if(ret != HAL_OK) {
return ret;
}
reg_value &= (uint16_t)~mask;
reg_value |= value;
return WM8904_WriteRegister(hi2c, reg, reg_value);
}
HAL_StatusTypeDef WM8904_WaitOnWriteSequencer(I2C_HandleTypeDef *hi2c)
{
HAL_StatusTypeDef result;
uint16_t value;
do {
vTaskDelay(pdMS_TO_TICKS(20));
result = WM8904_ReadRegister(hi2c, WM8904_WRT_SEQUENCER_4, &value);
} while ((result == HAL_OK) && (value & 0x0001));
return result;
}
HAL_StatusTypeDef WM8904_Init(I2C_HandleTypeDef *hi2c)
{
HAL_StatusTypeDef result;
elog_info(TAG, "configuring codec");
/* reset */
result = WM8904_WriteRegister(hi2c, WM8904_RESET, 0x0000);
if (result != HAL_OK) {
return result;
}
/* MCLK_INV=0, SYSCLK_SRC=0, TOCLK_RATE=1, OPCLK_ENA=0,
* CLK_SYS_ENA=1, CLK_DSP_ENA=1, TOCLK_ENA=1 */
result = WM8904_WriteRegister(hi2c, WM8904_CLK_RATES_2, 0x1007);
if (result != HAL_OK) {
return result;
}
/* Set Clock ratio and sample rate */
result = WM8904_WriteRegister(hi2c, WM8904_CLK_RATES_1, 0x0C05); //sysclk/fs=256, sample_rate=44-48khz
if (result != HAL_OK) {
return result;
}
/* WSEQ_ENA=1, WSEQ_WRITE_INDEX=0_0000 */
result = WM8904_WriteRegister(hi2c, WM8904_WRT_SEQUENCER_0, 0x0100);
if (result != HAL_OK) {
return result;
}
/* WSEQ_ABORT=0, WSEQ_START=1, WSEQ_START_INDEX=00_0000 */
result = WM8904_WriteRegister(hi2c, WM8904_WRT_SEQUENCER_3, 0x0100);
if (result != HAL_OK) {
return result;
}
result = WM8904_WaitOnWriteSequencer(hi2c);
if (result != HAL_OK) {
return result;
}
/* TOCLK_RATE_DIV16=0, TOCLK_RATE_x4=0, SR_MODE=0, MCLK_DIV=0
* (Required for MMCs: SGY, KRT see erratum CE000546) */
result = WM8904_WriteRegister(hi2c, WM8904_CLK_RATES_0, 0x845E);
if (result != HAL_OK) {
return result;
}
/* HPL_PGA_ENA=1, HPR_PGA_ENA=1 */
// result = WM8904_WriteRegister(hi2c, WM8904_POWER_MGMT_2, 0x0003);
// if (result != HAL_OK) {
// return result;
// }
/* DACL_ENA=1, DACR_ENA=1 */
// result = WM8904_WriteRegister(hi2c, WM8904_POWER_MGMT_6, 0x000C);
// if (result != HAL_OK) {
// return result;
// }
/* BCLK_DIR=1 (output), AIF_WL=00 (16-bits) */
result = WM8904_WriteRegister(hi2c, WM8904_AUDIO_IF_1, 0x0002 | (1ul << 6)); //16bits, I2S
if (result != HAL_OK) {
return result;
}
/* BCLK_DIV=(sysclk/8) */
result = WM8904_WriteRegister(hi2c, WM8904_AUDIO_IF_2, 0x0008);
if (result != HAL_OK) {
return result;
}
/* LRCLK_DIR=1 (output), LRCLK_RATE=(BCLK/32) */
result = WM8904_WriteRegister(hi2c, WM8904_AUDIO_IF_3, 0x0020 | (1ul << 11));
if (result != HAL_OK) {
return result;
}
/* FLL_FRACN_EN=1 */
result = WM8904_WriteRegister(hi2c, 0x74, (1ul << 2));
if (result != HAL_OK) {
return result;
}
/* FLL_OUTDIV=000111 (divice by 8), FLL_CTRL_RATE=000 (FVCO/1), FLL_FRATIO=000 (divide by 1) */
result = WM8904_WriteRegister(hi2c, 0x75, (7ul << 8));
if (result != HAL_OK) {
return result;
}
/* FLL_K=0.35 */
result = WM8904_WriteRegister(hi2c, 0x76, 0x599A);
if (result != HAL_OK) {
return result;
}
/* FLL_N=7 */
result = WM8904_WriteRegister(hi2c, 0x77, 7ul << 5);
if (result != HAL_OK) {
return result;
}
/* MCLK_INV=0, SYSCLK_SRC=1, TOCLK_RATE=1, OPCLK_ENA=0,
* CLK_SYS_ENA=1, CLK_DSP_ENA=1, TOCLK_ENA=1 */
result = WM8904_WriteRegister(hi2c, WM8904_CLK_RATES_2, 0x1007 | (1ul << 14)); //sysclk connects to fll output
if (result != HAL_OK) {
return result;
}
/* FLL_FRACN_EN=1, FLL_ENA=1 */
result = WM8904_WriteRegister(hi2c, 0x74, (1ul << 2) | (1ul << 0));
if (result != HAL_OK) {
return result;
}
vTaskDelay(pdMS_TO_TICKS(100));
/* DAC_MONO=0, DAC_SB_FILT-0, DAC_MUTERATE=0, DAC_UNMUTE RAMP=0,
* DAC_OSR128=1, DAC_MUTE=0, DEEMPH=0 (none) */
result = WM8904_WriteRegister(hi2c, WM8904_DAC_DIG_1, 0x0040); //unmute DAC
if (result != HAL_OK) {
return result;
}
/* HPL_RMV_SHORT=1, HPL_ENA_OUTP=1, HPL_ENA_DLY=1, HPL_ENA=1,
* HPR_RMV_SHORT=1, HPR_ENA_OUTP=1, HPR_ENA_DLY=1, HPR_ENA=1 */
result = WM8904_WriteRegister(hi2c, WM8904_ANALOG_HP_0, 0x00FF);
if (result != HAL_OK) {
return result;
}
/* CP_DYN_PWR=1 */
result = WM8904_WriteRegister(hi2c, WM8904_CLS_W_0, 0x0001);
if (result != HAL_OK) {
return result;
}
/* CP_ENA=1 */
// result = WM8904_WriteRegister(hi2c, WM8904_CHRG_PUMP_0, 0x0001);
// if (result != HAL_OK) {
// return result;
// }
result = WM8904_SetVolume(&hi2c1, 30);
if (result != HAL_OK) {
return result;
}
return HAL_OK;
}
HAL_StatusTypeDef WM8904_SetVolume(I2C_HandleTypeDef *hi2c, uint16_t volume)
{
HAL_StatusTypeDef result;
result = WM8904_WriteRegister(hi2c, WM8904_ANALOG_OUT1_LEFT, volume);
if (result != HAL_OK) {
return result;
}
result = WM8904_WriteRegister(hi2c, WM8904_ANALOG_OUT1_RIGHT, volume | 1ul << 7);
if (result != HAL_OK) {
return result;
}
result = WM8904_WriteRegister(hi2c, WM8904_ANALOG_OUT2_LEFT, volume);
if (result != HAL_OK) {
return result;
}
result = WM8904_WriteRegister(hi2c, WM8904_ANALOG_OUT2_RIGHT, volume | 1ul << 7);
if (result != HAL_OK) {
return result;
}
return HAL_OK;
}