- 积分
- 498
- 在线时间
- 214 小时
- 最后登录
- 2024-6-13
- 阅读权限
- 50
- 精华
- 0
- UID
- 787724
- 帖子
- 435
- 精华
- 0
- 经验
- 498 点
- 金钱
- 406 ¥
- 注册时间
- 2015-3-20
|
本帖最后由 丰年好大雪 于 2021-6-18 01:46 编辑
好多眼下新型的DAC总有奇奇怪怪的功能需要一个软控去做,洒家因为业余时间设计这玩意一直用软控,已经习惯了,从早年用8051折腾DF1706、PMD200和CS4398这些老古董,到现在的STM8折腾AK4499、ES9038。
我一直觉得这些厂家没做出什么像样的好东西,音质没见好听到哪里去,功能倒是越来越复杂。前不久知道一个音响行业的朋友设计新品,光控制DAC的解决方案,就让深圳的山寨团队骗了5万多,就用一个国产51。我都惊呆了,我说你早没认识我,认识我把这钱给我多好……。
所以呢,我觉得做音响、做功放,和编程开发单片机之间确实有个大鸿沟,对许多朋友是个门槛。我推荐个单片机好了,STM8,这个ST意法半导体做的8位单片机非常好用,虽然没有51那么多例程,但开发的套件都非常便宜,入门也不难,下面就告诉大家怎么玩。
首先你需要买STM8,我个人习惯用STM8S103或003,103高端一点,几块钱一个,内存多几K,固件刷写无限次,003就便宜,一块多一个,内存少,据说刷写有次数,有点类似冈本003,一次性的。其实003我用了那么多个,2014年做的板子现在继续刷写也没遇上什么问题。
然后你需要一个ST-Link的USB Dongle,这个东西淘宝买国产仿制品没问题的,也很便宜,几十块钱。
这就齐活了,下面就是做板子。如果这是你首个板子,我建议你做10x10以内的,用一两个类似CS4398、AK4490这种老古董做DAC,做坏了也不心疼。DAC版图配置成软件控制模式,然后把SPI或IIC接口接两个10k上拉电阻,直接接到STM8的SPI或IIC接口上去。STM8这东西好用就好用在芯片上已经设置了这些硬件接口,编程时可以直接使用STM8的官方驱动套料,就是那个STM8S Standard Peripherals Driver,这东西其实就是一堆现成的库文件和相关的外设、中断要用到的c语言组件。有这些东西,然后你自己写一个主程序,调用哪些功能,就把Lib库文件加进去,然后把相关的c组件加进程序的project里面就行了。
STM8这东西虽然小,功能非常全,官方驱动外设有:GPIO端口设置、片载ADC、自动唤醒、蜂鸣器驱动、Can总线、IIC总线、SPI总线、各种片载时钟的中断、各种看门狗、UART总线、读写外置FLASH这些东西。如果你仅仅纯粹是为了折腾DAC,基本上只需要这里面的GPIO端口设置(比如外接按钮、旋转编码器、电位器)、SPI或IIC总线(读写DAC或显示屏、其他芯片的状态)、初级的时钟设置(配置STM8自己的运行频率),再高端一点的朋友可以使用中断,STM8的中断配置略微复杂,以后再说,但中断很有用,比如可以外接按钮、旋转编码器什么的。
举个例子,我要控制AK4497这个DAC,那整个工程是这样的:
1·开机上电后,单片机初始化一下自己的内部时钟,同时可以配置一下外围GPIO端口(单片机的引脚都是可以设置功能的),懒惰的可以不管,我自己习惯用一根引脚去驱动DAC芯片的复位脚,一根引脚去控制一个NPN三极管控制静音继电器。开机后所有引脚默认是内部开路,如果你都外接了10K电阻到3.3V或5V,那这根引脚开机后就是高电位,控制DAC复位的可以不管他,控制静音继电器的需要考虑一下逻辑,需要多加一个三极管去把继电器控制三极管的基极给短路到地。
2·写一个延时小程序,让单片机延时0.3-0.5秒就行,这时基本上模拟电路、数字电路的上电都完成了。
3·然后把那根控制DAC复位脚的引脚给下拉,再上拉一下,因为DAC芯片上电后,复位脚都需要有一个上拉的动作才行,否则随着上电过程,复位脚和供电脚一起电位升上去,大多数DAC会没反应,我们有了单片机,就不需要用笨拙的RC延时电路了。
4·DAC就可以开始往寄存器里写东西了。这里如果你用IIC控制,就先发送IIC开始位,IIC用两线控制,通知目标芯片我要写你的方式是时钟线下拉,数据线再下拉。AK449X系列的DAC的IIC识别码都是00100,然后后边接XXX三位,这三位数字前两位对应芯片上的硬件编码脚位,接地是0,接3.3V数字电就是1,00-11可以设置成4个,也就是说一个IIC总线上你可以同时控制4个AK4497,通常情况下做两片的mono模式,分别设计成00和01就行,最后一位是读写位,0是写,1是读取。如果AK4497只使用一片,那这个握手码就是00100000,写成16进制就是0x20。
SPI端口通过三线控制,其中有一个latch下拉信号脚位通知目标芯片“我要写你了”,所以直接写寄存器号+设置bit位就行。
5.握手之后,写寄存器。AK4497因为有自动识别解析度功能,比如16-32bit,44-768khz,都可以自动识别,虽然开了这个功能会降低3db的信噪比吧……,但鉴于100db以上信噪比都是信仰,还是开了省事。于是你写入:
0x01号寄存器写0x02,功能是打开4497的Fast sharp滤波器,这个位也可以不写,那样就是使用4497默认的短延迟快切滤波器。
0x08号寄存器写0x0C,功能是打开4497的重负载模式,使用这个模式的原因是4497可以在这个模式下驱动低达100欧的负载,我自己做的电流负反馈分立放大器输入阻抗不高,打开了好一点。然后打开Sound Setting的bit2,据谣言说这个位音质好,我反正没听出来。
前两个寄存器都可以不写,看个人爱好。
最重要的就是写0x00号寄存器,AK4497软件模式开机后默认是在软挂起状态的,这个寄存器负责开启芯片。这个寄存器写0x9F,功能是开启主时钟MCLK自动识别、采样率自动识别、输入格式32bit IIS格式、芯片启动。
至此,芯片运转了,出声了。
6·然后STM8控制继电器的那个腿子设置成开漏输出,并在那根脚的ODR寄存器(输出数据寄存器)里写1,这样那根脚就接地了。这根脚接地,控制的那个NPN管集电极、射极就不通了,集电极上连接的上拉电位就升上去了,它一上升,就让控制继电器的NPN管导通,形成回路,继电器“咯”的一声就导通了。
在不搞什么通过DAC内置音量、指示灯、外置按钮的幺蛾子情况下,基本这个DAC板就能正常播放PCM了。而且各种码率都通。
播放DSD还是需要设置一下。AK4497不像AK4499、ES9038能具备自动识别DSD信号的能力,这个时候你就需要从DAC前端的ASRC或USB界面上引一个DSD触发信号过来,利用高级一点的中断功能,检测到DSD触发信号变化,立刻断开静音继电器(PCM/DSD切换会有可怕的噪音),然后写AK4497的0x02寄存器的bit7就是DSD Play位,开启DSD功能,然后0x06寄存器的DDM位打开,这个位是DSD无信号自动静音,很有用,然后DSDD位是旁路掉AK4497的DSD音量控制功能,如果你做纯解码器,或者做一体机,前级放大电路有外置的电位器,可以打开这个功能,提高一丁点儿性能,然后DSDSEL位要写入你DSD信号的码率,可惜AK4497不能自动识别DSD码率,写错了声音会变渣。然后再把0x00寄存器的Reset位写一下0,再写一下1(AK4497切换DSD需要重启一下)。
然后再把静音继电器接通,OK了。
main程序源码给大家看看。
#define stm8s003
#include <stm8s.h>
#include <stm8s003f3p.h>
#include <stm8s_i2c.h>
#include <stm8s_clk.h>
#include <stm8s_gpio.h>
#define AK4497AD 0x20
void delay_100ms(void)
{
unsigned char i,j;
for(i=0;i<255;i++)//2*255个指令周期
for(j=0;j<255;j++);//2*255个指令周期
}
void Mute_release(void)
{
//PD_ODR_ODR4 = 1;
PD_ODR = 0xFF;
}
uint8_t I2C_Write(uint8_t address,uint8_t data)
{
while(I2C_GetFlagStatus( I2C_FLAG_BUSBUSY));
I2C_GenerateSTART( ENABLE);//开启I2C1
while(!I2C_CheckEvent( I2C_EVENT_MASTER_MODE_SELECT));/*EV5,主模式*/
I2C_Send7bitAddress(AK4497AD, I2C_DIRECTION_TX );//器件地址 -- 默认0xD0
while(!I2C_CheckEvent( I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(address);//寄存器地址
while (!I2C_CheckEvent( I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_SendData(data);//发送数据
while (!I2C_CheckEvent( I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_AcknowledgeConfig(ENABLE);
I2C_GenerateSTOP( ENABLE);//关闭I2C1总线
}
void Sys_Init(void)
{
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);
I2C_Cmd(DISABLE);
GPIO_Init(GPIOD, GPIO_PIN_4, GPIO_MODE_OUT_OD_LOW_FAST);
I2C_Init(100000, 0xA0, I2C_DUTYCYCLE_2, I2C_ACK_CURR, I2C_ADDMODE_7BIT, 0x08);
I2C_Cmd(ENABLE);
}
int main( void )
{
Sys_Init();
delay_100ms();
delay_100ms();
delay_100ms();
delay_100ms();
delay_100ms();
I2C_Write(0x01,0x02);//CS4398替换成0x02,0x10 --IIS 24bit;
I2C_Write(0x08,0x0C);//CS4398替换成0x08,0x00 --清零开始工作;
I2C_Write(0x00,0x9F);
delay_100ms();
Mute_release();
while(1);
}
#ifdef USE_FULL_ASSERT
void assert_failed(u8* file, u32 line)
{
while (1)
{
}
}
#endif
这是一个很简单的应用,希望大家都能对自己有点信心,C语言并不难,有两个月就能掌握,因为控制DAC实在太简单,这个程序也没有需要用到中断、指针、数组之类的东西,所以大家利用业余时间搞起来吧。 |
评分
-
查看全部评分
|