[DAC] 做DAC?拥抱STM8单片机……吧

[复制链接] 查看: 20044|回复: 58

28

主题

1

好友

498

积分

业余侠客 当前离线

Rank: 4

UID
787724
帖子
435
精华
0
经验
498 点
金钱
406 ¥
注册时间
2015-3-20
发表于 2021-6-18 01:30 | 显示全部楼层
本帖最后由 丰年好大雪 于 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实在太简单,这个程序也没有需要用到中断、指针、数组之类的东西,所以大家利用业余时间搞起来吧。

评分

参与人数 5经验 +7 魅力 +9 收起 理由
fhc7867 + 2 很给力!
fwi297 + 3 + 3 感谢分享!!
浩浩 + 2 + 2 很给力!
lszyc + 2 很给力!
ls0001 + 2 给楼主无私贡献学识与劳动点赞.

查看全部评分

28

主题

1

好友

498

积分

业余侠客 当前离线

Rank: 4

UID
787724
帖子
435
精华
0
经验
498 点
金钱
406 ¥
注册时间
2015-3-20
 楼主| 发表于 2021-6-18 01:38 | 显示全部楼层
个别讲究的网友可能担心数字电路窜入的噪音,这个时候你就可以用STM8的低能耗关机功能,开启DAC后就自己关掉片载晶振,然后关机进入低能耗状态,或者使用IIC端口数字隔离器(推荐)彻底隔离掉数字电路。

2

主题

0

好友

87

积分

论坛游民 当前离线

Rank: 3Rank: 3

UID
25940
帖子
87
精华
0
经验
87 点
金钱
83 ¥
注册时间
2007-8-15
发表于 2021-6-18 03:03 来自手机端 | 显示全部楼层
好帖,对初入单片机编程的人挺有帮助的。感觉玩hifi的还是搞硬件的人偏多,对软件和编程比较陌生

42

主题

1

好友

1320

积分
     

侠之大者 当前离线

Rank: 6Rank: 6

UID
845147
帖子
1637
精华
0
经验
1320 点
金钱
1249 ¥
注册时间
2018-3-8
发表于 2021-6-18 07:37 | 显示全部楼层
老了,不想学了。

37

主题

7

好友

614

积分

职业侠客 当前离线

Rank: 5Rank: 5

UID
84032
帖子
671
精华
0
经验
614 点
金钱
530 ¥
注册时间
2009-2-27
发表于 2021-6-18 08:28 | 显示全部楼层
非常好!

55

主题

5

好友

1622

积分
     

侠之大者 当前离线

Rank: 6Rank: 6

UID
162187
帖子
1468
精华
1
经验
1622 点
金钱
1313 ¥
注册时间
2010-1-7
发表于 2021-6-18 08:38 | 显示全部楼层
楼主你可以出套件,大家用起来就简单了,很多人都会需要。

1

主题

0

好友

166

积分

论坛游民 当前离线

Rank: 3Rank: 3

UID
173125
帖子
181
精华
0
经验
166 点
金钱
166 ¥
注册时间
2010-2-11
发表于 2021-6-18 09:50 | 显示全部楼层
讲得非常好

228

主题

1

好友

2772

积分

罗宾汉 当前离线

Rank: 7Rank: 7Rank: 7

UID
803005
帖子
3323
精华
0
经验
2772 点
金钱
2399 ¥
注册时间
2015-10-29
发表于 2021-6-18 09:51 来自手机端 | 显示全部楼层
终于有人讲软控了,支持下

20

主题

2

好友

263

积分
     

业余侠客 当前离线

Rank: 4

UID
228527
帖子
249
精华
0
经验
263 点
金钱
223 ¥
注册时间
2010-8-10
发表于 2021-6-18 10:14 | 显示全部楼层
讲的很好,但是年纪大了真的学不动了

8

主题

0

好友

330

积分
     

业余侠客 当前离线

Rank: 4

UID
37395
帖子
409
精华
0
经验
330 点
金钱
372 ¥
注册时间
2008-3-14
发表于 2021-6-18 11:32 来自手机端 | 显示全部楼层
虽然不太懂程序,但还是为你的无私奉献点赞。

82

主题

0

好友

2449

积分

罗宾汉 当前离线

Rank: 7Rank: 7Rank: 7

UID
998
帖子
2834
精华
0
经验
2449 点
金钱
1870 ¥
注册时间
2004-7-9
发表于 2021-6-18 13:26 | 显示全部楼层
楼主辛苦了!

22

主题

2

好友

338

积分
     

业余侠客 当前离线

Rank: 4

UID
859641
帖子
314
精华
0
经验
338 点
金钱
291 ¥
注册时间
2019-2-28
发表于 2021-6-18 14:21 | 显示全部楼层
逻辑清晰,好文章,有点心动想折腾了!

10

主题

0

好友

328

积分

业余侠客 当前离线

Rank: 4

UID
7460
帖子
302
精华
0
经验
328 点
金钱
178 ¥
注册时间
2006-2-3
发表于 2021-6-18 14:57 来自手机端 | 显示全部楼层
做软件的非常多 但做音频方面又是发烧友的比较少  我曾经也想找人帮我做一个相关简单的软控 但一听报价就算了 比较佩服楼主

7

主题

1

好友

408

积分

业余侠客 当前离线

Rank: 4

UID
585925
帖子
414
精华
0
经验
408 点
金钱
394 ¥
注册时间
2013-4-23
发表于 2021-6-18 15:26 | 显示全部楼层
这种io口隔离 ,i2c隔离,就是,世上本无事,庸人自扰之。

32

主题

1

好友

419

积分
     

业余侠客 当前离线

Rank: 4

UID
697939
帖子
414
精华
0
经验
419 点
金钱
342 ¥
注册时间
2014-5-11
发表于 2021-6-18 17:00 | 显示全部楼层
这个得支持,单一功能确实不是太难,有点基础的完全可以自学。

18

主题

0

好友

250

积分
     

业余侠客 当前离线

Rank: 4

UID
764319
帖子
234
精华
0
经验
250 点
金钱
215 ¥
注册时间
2014-10-24
发表于 2021-6-18 17:38 | 显示全部楼层
LZ,我想玩下STM32数播,就WAV、APE、FLAC就行,用哪个型号好?

102

主题

1

好友

2665

积分

罗宾汉 当前离线

Rank: 7Rank: 7Rank: 7

UID
229399
帖子
1389
精华
0
经验
2665 点
金钱
2505 ¥
注册时间
2010-8-13
发表于 2021-6-18 18:50 | 显示全部楼层
说的很详细,门外汉看了都有了大概的思路方向。

0

主题

0

好友

59

积分

论坛游民 当前离线

Rank: 3Rank: 3

UID
489164
帖子
84
精华
0
经验
59 点
金钱
59 ¥
注册时间
2012-4-14
发表于 2021-6-18 23:23 来自手机端 | 显示全部楼层
无私!点赞!学习!

35

主题

2

好友

3079

积分

罗宾汉 当前离线

Rank: 7Rank: 7Rank: 7

UID
27774
帖子
3054
精华
0
经验
3079 点
金钱
3027 ¥
注册时间
2007-9-27
发表于 2021-6-19 02:24 | 显示全部楼层
考虑DIR,代码复杂度增加3倍,考虑UI,代码再复杂5倍,5w是略高了,如果是全套方案,确保指标能排在同芯片TOP10的话也不算太离谱,
当年跟着视频学AD画PCB也就一个月,真到实操的时候,每布一条线都觉得不对劲,简单板子都能改个N个版,
跟着原子哥学STM32也是1个月,然后自己写代码要跟着PCB调整,来回还要四五次,意思PCB打样没4~5次自己都看不过去,大概这个样子

28

主题

1

好友

498

积分

业余侠客 当前离线

Rank: 4

UID
787724
帖子
435
精华
0
经验
498 点
金钱
406 ¥
注册时间
2015-3-20
 楼主| 发表于 2021-6-19 03:19 | 显示全部楼层
本帖最后由 丰年好大雪 于 2021-6-19 03:20 编辑
TABK 发表于 2021-6-18 15:26
这种io口隔离 ,i2c隔离,就是,世上本无事,庸人自扰之。


传统解码器多数接收的是SPDIF信号,本质上是单一频率的高频数字信号,使用地线分割就基本可以防止噪音窜入了。但现在的新型DAC大多数都有USB、蓝牙界面,这些新前端的问题就是噪音或从电脑USB口地线窜入,或者本身就是一个射频干扰源,如果不使用数字隔离器,单纯地线分割是不够的,板上任意一点都能测到顺着地线或信号线爬来的大量高频噪音。

当然你可以说,这些高频噪音是听不到的,但带宽动辄几百Mhz的电子元器件可以听到,这就比较糟糕了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Powered by Discuz! X3.4

© 2001-2012 Comsenz Inc.

返回顶部