基于MM32F0140制作的音频合成器
本项目实现了一个基于MM32F0140的音频合成器。模仿stylophone实现了一个手掌大小的乐器,有20个琴键,可以发出20个不同音高的声音。
标签
嵌入式
DAC
WeDesign
MM32
I2S
乐器
hucuyuu
更新2023-05-29
421

内容介绍

基于MM32F0140制作的音频合成器

一、项目介绍

本项目实现了一个基于MM32F0140的音频合成器。模仿stylophone实现了一个手掌大小的乐器,有20个琴键,可以发出20个不同音高的声音。用PCB开窗当作键盘,每块裸铜都与上拉的GPIO连接,用一根接地的杜邦线在裸铜上左右滑动,单片机接收到音高的信息,并计算出波形表,发出相对应音高的声音。有四个按键可以调节音色,分别是:正弦波、三角波、方波和锯齿波。显示屏可以显示目前选择的音色和相对应键盘的音高。

二、搜集素材思路

在一些汽车混剪的视频中看到过这个乐器,觉得这个东西很酷。B站搜Stylophone可以看到很多相关的视频,在BV1Bz4y1Q7eV中一个老外就拿两个Stylophone演奏了Metallica乐队的Enter Sandman。没有看到Stylophone的拆解视频,初步猜测是纯模拟方案,于是在WeDesign的本次活动中,正好做这个新项目来挑战一下用单片机方案完成Stylophone大部分功能的复刻。结果来看我认为是成功地完成了一个雏形,弯音Tremble和调整音域的功能没有实现。

三、项目设计思路

硬件

单片机的选型采用题目规定的MM32F0140。

焊盘裸铜是现在Fusion360中按照比例画出了一个CAD矢量图,再截图导入PS中上色和缩进画出分界线。在附件中给出了PS处理后的psd文件和一张导出的png图。这里导出一定要选png而不是jpg,png格式有alpha通道,可以显示透明背景。ps处理后得到的png图片在导入KiCAD中图片转换器(Image Converter)获得焊盘,png中黑色的部分就是MASK层,Image Converter中Border Layer For Outline选择Solder Mask层,Output Format选择footprint(.kicad_mod file)。

CAN部分选择了官方参考设计中的TJA1042,考虑以后还可外接几个20个开窗的键盘,通过CAN总线传输到主机,主机发出声音,总线上的从机只负责读取按键的数据,但是后来考虑到CAN收发芯片价格比较贵,这样挂载键盘在CAN总线上违背了节省成本的初衷。PCB就留了一块没有焊接,偷了个懒。

屏幕选择了大家都很熟悉的SSD1306模块,可以显示128*64个点。

I2S芯片原先选择的是ES7145LV,但是PCB到了之后才发现这颗芯片哪里都没有货,于是替换成了仙童半导体的CS4345,这两颗芯片可以pin-to-pin替换。D类功放采用国产的屹晶微EG8305。音频部分的电路完全参考datasheet中的typical design,typical design中几个电容电阻只知道是用来滤波,但是不知道用来滤什么波,也不是到滤波器的参数是怎么设计,于是中间加了一颗RS8551用来做阻抗变换以实现datasheet中的理想条件。喇叭就选择了一个普通的4ohm 2w喇叭。

软件

由于MM32F0140的IO口比较少,在项目中,采用了两个MM32F0140用I2C通信,从机只负责读取20个焊盘中哪些被接地的杜邦线拉低。在主机发送读取请求后,从机读取20个焊盘的高低电平,组合成三个8bit的数据返回给主机。

主机轮询从机,如果有被杜邦线接地的焊盘,于是计算这个焊盘对应的音高的波表,再使用DMA将这个波表发送给SPI/I2S外设。单片机主频设置为72MHz,为了实现CS4345非标准的采样率,单片机需要提供一个主时钟给CS4345。根据单片机User Manual 21.4.7中设置分频系数3,CS4345采样率为93.75kHz,也就是10.667us输出一次数据。各个音高的频率可以搜索一下,是固定算出来的,A4就是440Hz,这里A4的周期也就是2272.727us,2272.727/10.667=213,也就是说I2S外设要再213个点中输出一个周期正弦波。波表的长度就如这样获得,但是I2S再DMA中是左右声道交替传输,这里把213*2=426,于是计算426长度的一个周期的正弦波波表。其他频率的音高的波表也是类似的计算方法。实际效果下正弦波输出的声音有些失真,估计是这里波表计算的方法有些问题。

因为使用的单片机内部振荡频率为8MHz,无法通过整数倍频和分频获得48kHz采样率,如果要使用48kHz或其他标准的采样率,应该使用特殊的如12.288MHz或者其他的晶振,可以看下图CS4345手册中截出来的图。

还有另一种方法,可以先计算20个音高的波表,但是题目限定了单片机,MM32F0140有8k的SRAM,不足以存储这么多点,所以只能先判断按键,再计算音高。这样有个区别,就是当点比较多,也就是频率比较低的时候,按键被拉低到发出声音这一段的时间会变长,也就会感觉乐器不跟手。同样也解释了为什么采样率不是越高越好,明明手册里可以到200kHz,而且采样率越高,输出的声音越逼近标准的音高,在SRAM不足的情况下,计算时间加长,乐器不跟手显然是更不能接受的。

四、实验结果展示

这里用手机软件FFTWave测量了A6也就是第13个按键的音高。手机软件中设置44100Hz采样率,FFT点数选择8192个点,分辨率就是5.38Hz。截图显示基频率为441.4Hz,标准的A6为440Hz,所以认为发出的音高是准确的。其他音高的测试类似,找到基频后和标准的频率表对照就可以了,计算的表格我也会放在附件里。但是由于手机麦克风的频响特性,有些时候基频比泛音要小,在手机上有时候读不出来。测低频率的时候基频甚至淹没在噪声里,频谱中只能读出泛音的频率。这个测试方法是有待改进的。

五、遇到的问题

  • 选用的USB Type-C的座子不合适,焊接的时候锡膏的量没有控制好,焊接的时候不合适,测试的时候被我大力出奇迹,一不小心就登掉了,可以选择有通孔的Type-C座子,会更加牢靠。
  • 采用48kHz标准采样率来计算的时候频率偏差会比较大,甚至一个音差了几十个Hz。现在采用非标准的93.75kHz计算,精确度已经超过了仪器的最小分辨率。
  • 在不输出声音的时候喇叭会有轻微的电流声,猜测是运放后或者是功放芯片的问题,不会是程序的问题。这个问题不知道怎么解决,手头上也合适的仪器测一测。
  • 输出的标准正弦波音色会有些许失真。猜测是计算的波表不够还原正弦波。改16bit分辨率为24bit分辨率可能会改善。其他波形本来就是失真的,所以听起来效果还行。
  • 至少在官网上下载到了3个版本的SDK,一个最老的缺少I2S_Slave的初始化,一开始想要自己写初始化,后来在MM32的微信公众号里看到了新版本的I2S代码。于是改变了SDK重新移植其他文件。还有一个版本不使用systick定时器,也就是现在我使用的版本。我觉得灵动微在这方面是有待改进的,要么就删除不要给用户下载,要么就标明是老版本的SDK。还有就是希望能给出openOCD的配置文件,方便使用arm-gcc的用户调试芯片。后来选择了pyOCD,pyOCD可以直接根据cmsis-pack生成配置文件,比openOCD简单。
  • 还花了一个晚上改了SDK的一个bug,在hal_i2c.h中方结构体I2C_SlaveXfer_Type中一个成员的变量类型错了,I2C slave的时候发的数据是错的,没有对齐。
typedef struct
{
    uint32_t TxIdx;   /*!< Specify the number of data currently sent. */
    uint32_t RxIdx;   /*!< Specify the number of data currently receive. */
    uint32_t *XferBuf; /*!< Specify the buffer of I2C slave send and receive operation. */
    uint32_t BufLen;  /*!< Specifies the data transmission length of I2C slave mode. */
} I2C_SlaveXfer_Type;
typedef struct
{
    uint32_t TxIdx;   /*!< Specify the number of data currently sent. */
    uint32_t RxIdx;   /*!< Specify the number of data currently receive. */
    uint8_t *XferBuf; /*!< Specify the buffer of I2C slave send and receive operation. */
    uint32_t BufLen;  /*!< Specifies the data transmission length of I2C slave mode. */
} I2C_SlaveXfer_Type;

六、芯片的优势和局限

由于是不是专业从事单片机开发的工作人员,作为业余的DIY爱好者,这款单片机带给我最大的感受就是价格便宜。第二是支持arm-gcc工具链。由于不想使用其他付费的工具链条,提供了官方arg-gcc的支持是一大优势。第三是微信公众号提供了详细的教程,这对我快速了解某一个外设有很大的帮助。第四是提供了基于KiCAD的参考设计。劣势在于SRAM不够大,要想办法节约SRAM资源,在FreeRTOS中开一个u8g2显示的task,再开一个最简单的打印task,SRAM直接就爆了。不过作为低成本的单片机,这是可以接受的。还有的局限在于对SDK的支持不够好,MindSDK下载站的设计也不容易让人看懂,摸索了好一阵子才下载到了我需要的SDK。


附录

 

A3 220
A#3 233.082
B3 246.942
C4 261.626
C#4 277.183
D4 293.665
D#4 311.127
E4 329.628
F4 349.228
F#4 369.994
G4 391.995
G#4 415.305
A4 440
A#4 466.164
B4 493.883
C5 523.251
C#5 554.365
D5 587.33
D#5 622.254
E5 659.255

 

调试接口

 

 

物料清单

附件下载

mm32f0140_mcu0.zip
第0个MCU的程序
mm32f0140_mcu1.zip
第1个MCU的程序
mm32_synthesizer.zip
KiCAD7 工程文件 和 开窗键盘ps文件

团队介绍

hucuyuu

评论

0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号