stm32开发之wm8978驱动记录(rt-thread)

2024-03-12 00:44

本文主要是介绍stm32开发之wm8978驱动记录(rt-thread),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

头文件

//
// Created by shchl on 2024/3/11.
//#ifndef F4_OS_AUDIO_WM8978_H
#define F4_OS_AUDIO_WM8978_H#include "rtdevice.h"#define WM8978_ADDR        0X1A    //WM8978的器件地址,固定为0X1A(7bit 地址)
struct audio_wm8978 {struct rt_i2c_bus_device *bus; /*总线指针*/uint8_t addr; /*地址*/rt_mutex_t lock; /*互斥锁*/
};typedef struct audio_wm8978 *audio_wm8978_t;audio_wm8978_t wm8978_init(char *bus_name, uint8_t addr);rt_err_t wm8978_cnf_init();void wm8978_deInit(audio_wm8978_t wm8978);rt_err_t wm8978_set_reg(audio_wm8978_t wm8978, uint8_t reg, uint16_t val);uint16_t wm8978_read_reg(uint8_t reg);void wm8978_ADDA_Cfg(uint8_t dacen, uint8_t adcen);void wm8978_Input_Cfg(uint8_t micen, uint8_t lineinen, uint8_t auxen);void wm8978_Output_Cfg(uint8_t dacen, uint8_t bpsen);void wm8978_MIC_Gain(uint8_t gain);void wm8978_LINEIN_Gain(uint8_t gain);void wm8978_AUX_Gain(uint8_t gain);void wm8978_I2S_Cfg(uint8_t fmt, uint8_t len);void wm8978_HPvol_Set(uint8_t voll, uint8_t volr);void wm8978_SPKvol_Set(uint8_t volx);void wm8978_3D_Set(uint8_t depth);void wm8978_EQ_3D_Dir(uint8_t dir);void wm8978_EQ1_Set(uint8_t cfreq, uint8_t gain);void wm8978_EQ2_Set(uint8_t cfreq, uint8_t gain);void wm8978_EQ3_Set(uint8_t cfreq, uint8_t gain);void wm8978_EQ4_Set(uint8_t cfreq, uint8_t gain);void wm8978_EQ5_Set(uint8_t cfreq, uint8_t gain);#endif //F4_OS_AUDIO_WM8978_H

源文件

//
// Created by shchl on 2024/3/11.
//
#include "audio_wm8978.h"
#include <rtthread.h>#define DBG_ENABLE
#define DBG_TAG "wm8978"
#define DBG_LVL DBG_LOG#include <rtdbg.h>static audio_wm8978_t device = NULL;
//WM8978寄存器值缓存区(总共58个寄存器,0~57),占用116字节内存
//因为WM8978的IIC操作不支持读操作,所以在本地保存所有寄存器值
//写WM8978寄存器时,同步更新到本地寄存器值,读寄存器时,直接返回本地保存的寄存器值.
//注意:WM8978的寄存器值是9位的,所以要用uint16_t来存储.
static uint16_t wm8978_REGVAL_TBL[58] ={0X0000, 0X0000, 0X0000, 0X0000, 0X0050, 0X0000, 0X0140, 0X0000,0X0000, 0X0000, 0X0000, 0X00FF, 0X00FF, 0X0000, 0X0100, 0X00FF,0X00FF, 0X0000, 0X012C, 0X002C, 0X002C, 0X002C, 0X002C, 0X0000,0X0032, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000,0X0038, 0X000B, 0X0032, 0X0000, 0X0008, 0X000C, 0X0093, 0X00E9,0X0000, 0X0000, 0X0000, 0X0000, 0X0003, 0X0010, 0X0010, 0X0100,0X0100, 0X0002, 0X0001, 0X0001, 0X0039, 0X0039, 0X0039, 0X0039,0X0001, 0X0001};static rt_err_t write_reg(uint8_t reg, uint16_t val) {return wm8978_set_reg(device, reg, val);
}rt_err_t wm8978_set_reg(audio_wm8978_t wm8978, uint8_t reg, uint16_t val) {rt_uint8_t buf[2];buf[0] = (reg << 1) | ((val >> 8) & 0X01);buf[1] = val & 0XFF;if (wm8978 == NULL) {LOG_E("请先执行 wm8978_init");return RT_ERROR;}if (rt_i2c_master_send(wm8978->bus, wm8978->addr, RT_I2C_WR, buf, 2) != 2) {return RT_ERROR;}wm8978_REGVAL_TBL[reg] = val;    //保存寄存器值到本地return RT_EOK;
}/*** 初始化 wm8978* @param bus_name 总线名* @param addr 地址(7位地址)* @return*/
audio_wm8978_t wm8978_init(char *bus_name, uint8_t addr) {RT_ASSERT(bus_name);device = rt_calloc(1, sizeof(struct audio_wm8978));if (device == RT_NULL) {LOG_E("Can't allocate memory for audio_wm8978 device on '%s' ", bus_name);return RT_NULL;}device->bus = rt_i2c_bus_device_find(bus_name);if (device->bus == RT_NULL) {LOG_E("Can't find audio_wm8978 device on '%s' ", bus_name);rt_free(device);return RT_NULL;}device->lock = rt_mutex_create("mutex_wm8978", RT_IPC_FLAG_FIFO);if (device->lock == RT_NULL) {LOG_E("Can't create mutex for audio_wm8978 device on '%s' ", bus_name);rt_free(device);return RT_NULL;}{device->bus->timeout = 3;/*尝试3次*/device->addr = addr;}return device;
}void wm8978_deInit(audio_wm8978_t wm8978) {if (wm8978 != NULL) {if (wm8978 == device) {rt_free(wm8978);}}
}/*** 配置初始化* @param wm8978*/
rt_err_t wm8978_cnf_init() {if (write_reg(0, 0) != RT_EOK) return RT_ERROR;            //软复位WM8978发送指令失败,WM8978异常//以下为通用设置write_reg(1, 0X1B);    //R1,MICEN设置为1(MIC使能),BIASEN设置为1(模拟器工作),VMIDSEL[1:0]设置为:11(5K)write_reg(2, 0X1B0);    //R2,ROUT1,LOUT1输出使能(耳机可以工作),BOOSTENR,BOOSTENL使能write_reg(3, 0X6C);    //R3,LOUT2,ROUT2输出使能(喇叭工作),RMIX,LMIX使能write_reg(6, 0);        //R6,MCLK由外部提供write_reg(43, 1 << 4);    //R43,INVROUT2反向,驱动喇叭write_reg(47, 1 << 8);    //R47设置,PGABOOSTL,左通道MIC获得20倍增益write_reg(48, 1 << 8);    //R48设置,PGABOOSTR,右通道MIC获得20倍增益write_reg(49, 1 << 1);    //R49,TSDEN,开启过热保护write_reg(49, 1 << 2);    //R49,SPEAKER BOOST,1.5xwrite_reg(10, 1 << 3);    //R10,SOFTMUTE关闭,128x采样,最佳SNRwrite_reg(14, 1 << 3);    //R14,ADC 128x采样率return RT_EOK;
}//WM8978读寄存器
//就是读取本地寄存器值缓冲区内的对应值
//reg:寄存器地址 
//返回值:寄存器值
uint16_t wm8978_read_reg(uint8_t reg) {return wm8978_REGVAL_TBL[reg];
}//WM8978 DAC/ADC配置
//adcen:adc使能(1)/关闭(0)
//dacen:dac使能(1)/关闭(0)
void wm8978_ADDA_Cfg(uint8_t dacen, uint8_t adcen) {uint16_t regval;regval = wm8978_read_reg(3);   //读取R3if (dacen)regval |= 3 << 0;        //R3最低2个位设置为1,开启DACR&DACLelse regval &= ~(3 << 0);           //R3最低2个位清零,关闭DACR&DACL.write_reg(3, regval);       //设置R3regval = wm8978_read_reg(2);    //读取R2if (adcen)regval |= 3 << 0;         //R2最低2个位设置为1,开启ADCR&ADCLelse regval &= ~(3 << 0);           //R2最低2个位清零,关闭ADCR&ADCL.write_reg(2, regval);       //设置R2
}//WM8978 输入通道配置
//micen:MIC开启(1)/关闭(0)
//lineinen:Line In开启(1)/关闭(0)
//auxen:aux开启(1)/关闭(0) 
void wm8978_Input_Cfg(uint8_t micen, uint8_t lineinen, uint8_t auxen) {uint16_t regval;regval = wm8978_read_reg(2);    //读取R2if (micen)regval |= 3 << 2;        //开启INPPGAENR,INPPGAENL(MIC的PGA放大)else regval &= ~(3 << 2);        //关闭INPPGAENR,INPPGAENL.write_reg(2, regval);    //设置R2regval = wm8978_read_reg(44);    //读取R44if (micen)regval |= 3 << 4 | 3 << 0;    //开启LIN2INPPGA,LIP2INPGA,RIN2INPPGA,RIP2INPGA.else regval &= ~(3 << 4 | 3 << 0);    //关闭LIN2INPPGA,LIP2INPGA,RIN2INPPGA,RIP2INPGA.write_reg(44, regval);//设置R44if (lineinen)wm8978_LINEIN_Gain(5);//LINE IN 0dB增益else wm8978_LINEIN_Gain(0);    //关闭LINE INif (auxen)wm8978_AUX_Gain(7);//AUX 6dB增益else wm8978_AUX_Gain(0);    //关闭AUX输入
}//WM8978 输出配置
//dacen:DAC输出(放音)开启(1)/关闭(0)
//bpsen:Bypass输出(录音,包括MIC,LINE IN,AUX等)开启(1)/关闭(0) 
void wm8978_Output_Cfg(uint8_t dacen, uint8_t bpsen) {uint16_t regval = 0;if (dacen)regval |= 1 << 0;    //DAC输出使能if (bpsen) {regval |= 1 << 1;        //BYPASS使能regval |= 5 << 2;        //0dB增益}write_reg(50, regval);//R50设置write_reg(51, regval);//R51设置
}//WM8978 MIC增益设置(不包括BOOST的20dB,MIC-->ADC输入部分的增益)
//gain:0~63,对应-12dB~35.25dB,0.75dB/Step
void wm8978_MIC_Gain(uint8_t gain) {gain &= 0X3F;write_reg(45, gain);        //R45,左通道PGA设置write_reg(46, gain | 1 << 8);    //R46,右通道PGA设置
}//WM8978 L2/R2(也就是Line In)增益设置(L2/R2-->ADC输入部分的增益)
//gain:0~7,0表示通道禁止,1~7,对应-12dB~6dB,3dB/Step
void wm8978_LINEIN_Gain(uint8_t gain) {uint16_t regval;gain &= 0X07;regval = wm8978_read_reg(47);    //读取R47regval &= ~(7 << 4);            //清除原来的设置write_reg(47, regval | gain << 4);//设置R47regval = wm8978_read_reg(48);    //读取R48regval &= ~(7 << 4);            //清除原来的设置write_reg(48, regval | gain << 4);//设置R48
}//WM8978 AUXR,AUXL(PWM音频部分)增益设置(AUXR/L-->ADC输入部分的增益)
//gain:0~7,0表示通道禁止,1~7,对应-12dB~6dB,3dB/Step
void wm8978_AUX_Gain(uint8_t gain) {uint16_t regval;gain &= 0X07;regval = wm8978_read_reg(47);    //读取R47regval &= ~(7 << 0);            //清除原来的设置write_reg(47, regval | gain << 0);//设置R47regval = wm8978_read_reg(48);    //读取R48regval &= ~(7 << 0);            //清除原来的设置write_reg(48, regval | gain << 0);//设置R48
}//设置I2S工作模式
//fmt:0,LSB(右对齐);1,MSB(左对齐);2,飞利浦标准I2S;3,PCM/DSP;
//len:0,16位;1,20位;2,24位;3,32位;  
void wm8978_I2S_Cfg(uint8_t fmt, uint8_t len) {fmt &= 0X03;len &= 0X03;//限定范围write_reg(4, (fmt << 3) | (len << 5));    //R4,WM8978工作模式设置
}//设置耳机左右声道音量
//voll:左声道音量(0~63)
//volr:右声道音量(0~63)
void wm8978_HPvol_Set(uint8_t voll, uint8_t volr) {voll &= 0X3F;volr &= 0X3F;//限定范围if (voll == 0)voll |= 1 << 6;//音量为0时,直接muteif (volr == 0)volr |= 1 << 6;//音量为0时,直接mutewrite_reg(52, voll);            //R52,耳机左声道音量设置write_reg(53, volr | (1 << 8));    //R53,耳机右声道音量设置,同步更新(HPVU=1)
}//设置喇叭音量
//voll:左声道音量(0~63) 
void wm8978_SPKvol_Set(uint8_t volx) {volx &= 0X3F;//限定范围if (volx == 0)volx |= 1 << 6;//音量为0时,直接mutewrite_reg(54, volx);            //R54,喇叭左声道音量设置write_reg(55, volx | (1 << 8));    //R55,喇叭右声道音量设置,同步更新(SPKVU=1)
}//设置3D环绕声
//depth:0~15(3D强度,0最弱,15最强)
void wm8978_3D_Set(uint8_t depth) {depth &= 0XF;//限定范围write_reg(41, depth);    //R41,3D环绕设置
}//设置EQ/3D作用方向
//dir:0,在ADC起作用
//    1,在DAC起作用(默认)
void wm8978_EQ_3D_Dir(uint8_t dir) {uint16_t regval;regval = wm8978_read_reg(0X12);if (dir)regval |= 1 << 8;else regval &= ~(1 << 8);write_reg(18, regval);//R18,EQ1的第9位控制EQ/3D方向
}//设置EQ1
//cfreq:截止频率,0~3,分别对应:80/105/135/175Hz
//gain:增益,0~24,对应-12~+12dB
void wm8978_EQ1_Set(uint8_t cfreq, uint8_t gain) {uint16_t regval;cfreq &= 0X3;//限定范围if (gain > 24)gain = 24;gain = 24 - gain;regval = wm8978_read_reg(18);regval &= 0X100;regval |= cfreq << 5;    //设置截止频率regval |= gain;        //设置增益write_reg(18, regval);//R18,EQ1设置
}//设置EQ2
//cfreq:中心频率,0~3,分别对应:230/300/385/500Hz
//gain:增益,0~24,对应-12~+12dB
void wm8978_EQ2_Set(uint8_t cfreq, uint8_t gain) {uint16_t regval = 0;cfreq &= 0X3;//限定范围if (gain > 24)gain = 24;gain = 24 - gain;regval |= cfreq << 5;    //设置截止频率regval |= gain;        //设置增益write_reg(19, regval);//R19,EQ2设置
}//设置EQ3
//cfreq:中心频率,0~3,分别对应:650/850/1100/1400Hz
//gain:增益,0~24,对应-12~+12dB
void wm8978_EQ3_Set(uint8_t cfreq, uint8_t gain) {uint16_t regval = 0;cfreq &= 0X3;//限定范围if (gain > 24)gain = 24;gain = 24 - gain;regval |= cfreq << 5;    //设置截止频率regval |= gain;        //设置增益write_reg(20, regval);//R20,EQ3设置
}//设置EQ4
//cfreq:中心频率,0~3,分别对应:1800/2400/3200/4100Hz
//gain:增益,0~24,对应-12~+12dB
void wm8978_EQ4_Set(uint8_t cfreq, uint8_t gain) {uint16_t regval = 0;cfreq &= 0X3;//限定范围if (gain > 24)gain = 24;gain = 24 - gain;regval |= cfreq << 5;    //设置截止频率regval |= gain;        //设置增益write_reg(21, regval);//R21,EQ4设置
}//设置EQ5
//cfreq:中心频率,0~3,分别对应:5300/6900/9000/11700Hz
//gain:增益,0~24,对应-12~+12dB
void wm8978_EQ5_Set(uint8_t cfreq, uint8_t gain) {uint16_t regval = 0;cfreq &= 0X3;//限定范围if (gain > 24)gain = 24;gain = 24 - gain;regval |= cfreq << 5;    //设置截止频率regval |= gain;        //设置增益write_reg(22, regval);//R22,EQ5设置
}

这篇关于stm32开发之wm8978驱动记录(rt-thread)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/799622

相关文章

Go语言开发实现查询IP信息的MCP服务器

《Go语言开发实现查询IP信息的MCP服务器》随着MCP的快速普及和广泛应用,MCP服务器也层出不穷,本文将详细介绍如何在Go语言中使用go-mcp库来开发一个查询IP信息的MCP... 目录前言mcp-ip-geo 服务器目录结构说明查询 IP 信息功能实现工具实现工具管理查询单个 IP 信息工具的实现服

usb接口驱动异常问题常用解决方案

《usb接口驱动异常问题常用解决方案》当遇到USB接口驱动异常时,可以通过多种方法来解决,其中主要就包括重装USB控制器、禁用USB选择性暂停设置、更新或安装新的主板驱动等... usb接口驱动异常怎么办,USB接口驱动异常是常见问题,通常由驱动损坏、系统更新冲突、硬件故障或电源管理设置导致。以下是常用解决

Java使用SLF4J记录不同级别日志的示例详解

《Java使用SLF4J记录不同级别日志的示例详解》SLF4J是一个简单的日志门面,它允许在运行时选择不同的日志实现,这篇文章主要为大家详细介绍了如何使用SLF4J记录不同级别日志,感兴趣的可以了解下... 目录一、SLF4J简介二、添加依赖三、配置Logback四、记录不同级别的日志五、总结一、SLF4J

在Spring Boot中浅尝内存泄漏的实战记录

《在SpringBoot中浅尝内存泄漏的实战记录》本文给大家分享在SpringBoot中浅尝内存泄漏的实战记录,结合实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录使用静态集合持有对象引用,阻止GC回收关键点:可执行代码:验证:1,运行程序(启动时添加JVM参数限制堆大小):2,访问 htt

使用Python开发一个带EPUB转换功能的Markdown编辑器

《使用Python开发一个带EPUB转换功能的Markdown编辑器》Markdown因其简单易用和强大的格式支持,成为了写作者、开发者及内容创作者的首选格式,本文将通过Python开发一个Markd... 目录应用概览代码结构与核心组件1. 初始化与布局 (__init__)2. 工具栏 (setup_t

MySQL 中查询 VARCHAR 类型 JSON 数据的问题记录

《MySQL中查询VARCHAR类型JSON数据的问题记录》在数据库设计中,有时我们会将JSON数据存储在VARCHAR或TEXT类型字段中,本文将详细介绍如何在MySQL中有效查询存储为V... 目录一、问题背景二、mysql jsON 函数2.1 常用 JSON 函数三、查询示例3.1 基本查询3.2

Spring Shell 命令行实现交互式Shell应用开发

《SpringShell命令行实现交互式Shell应用开发》本文主要介绍了SpringShell命令行实现交互式Shell应用开发,能够帮助开发者快速构建功能丰富的命令行应用程序,具有一定的参考价... 目录引言一、Spring Shell概述二、创建命令类三、命令参数处理四、命令分组与帮助系统五、自定义S

Python通过模块化开发优化代码的技巧分享

《Python通过模块化开发优化代码的技巧分享》模块化开发就是把代码拆成一个个“零件”,该封装封装,该拆分拆分,下面小编就来和大家简单聊聊python如何用模块化开发进行代码优化吧... 目录什么是模块化开发如何拆分代码改进版:拆分成模块让模块更强大:使用 __init__.py你一定会遇到的问题模www.

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

使用Python开发一个简单的本地图片服务器

《使用Python开发一个简单的本地图片服务器》本文介绍了如何结合wxPython构建的图形用户界面GUI和Python内建的Web服务器功能,在本地网络中搭建一个私人的,即开即用的网页相册,文中的示... 目录项目目标核心技术栈代码深度解析完整代码工作流程主要功能与优势潜在改进与思考运行结果总结你是否曾经