一、 项目介绍
本项目基于十二指神探平台实现R2R-DAC,通过ui、以及制作外围电路使得十二指神探平台可实现输出任意信号。
由于RP2040不集成DAC,无法输出模拟信号,但得益于高速的pio输出,可通过R2R-DAC实现高速高采样率的信号输出。本项目通过DMA、pio使信号输出速度最大化。
二、 设计思路
1. R2R-DAC
R2R-DAC, 全称为R-2R电阻网络数字模拟转换器,是一种通过一个特定电阻网络,将并行数字信号转换为模拟信号的结构。一个n位R2R-DAC由n-1个R电阻与n+1个2R电阻组成。该架构每个数字输入都会由其权重对模拟输出做出贡献,由于电阻阻值决定各数字位权重,电阻精度会影响输出精度,引入误差,因此R电阻采用2个2R电阻并联减小误差。
2. DMA
DMA(Direct Memory Access,直接内存访问)是一种可以让硬件子系统在不经过CPU的情况下,直接读写系统内存的技术。通过DMA可以在不占用CPU资源的情况下,进行数据传输,从而提高系统的整体性能。在本项目中,为进一步提高设备输出性能,采用采用DMA传输波形信号至IO,从而提高输出频率。
3. PIO
PIO(Programmable I/O,可编程I/O),是一种单片机类似于FPGA的可编程输入输出功能,通过此功能可实现时钟频率为系统时钟的时序逻辑,是的IO输入输出速度最大化。
三、 硬件框图
该系统整体十分简单,主要包括Rp2040主控、St7789屏幕、按键、拨轮编码器、以及R2R-DAC电阻网络即可实现。根据原理图,在洞洞板上焊接原件,并连接至十二指神探,即可完成硬件设计。
主控简介:
- 双核 Arm Cortex-M0 + @ 133MHz
- 芯片内置 264KB SRAM 和 2MB 的板载闪存
- 通过专用 QSPI 总线支持最高 16MB 的片外闪存
- DMA 控制器
- 30 个 GPIO 引脚,其中 4 个可用作模拟输入
- 2 个 UART、2 个 SPI 控制器和 2 个 I2C 控制器
- 16 个 PWM 通道
- USB 1.1 主机和设备支持
- 8 个树莓派可编程 I/O(PIO)状态机,用于自定义外围设备支持
- 支持 UF2 的 USB 大容量存储启动模式,用于拖放式编程
四、 软件流程图
软件设计为,通过修改AWG模块波形信息,AWG模块计算对应电压值大小,通过DMA将数据传送至pio输出信号。
五、 实现结果
输出结果见附录,可见输出正弦波频谱非常纯净,这表明该系统信号输出性能客观。除正弦波以外,还可输出方波、sinc、噪声等简单波形。
通过编写代码还可实现输出各种调制信号,如FM、AM、FSK、ASK等。
六、 主要代码
1. 数据收集和存储:
用户输入被收集并存储在名为 “wave” 的字典中。这个字典包含与波形生成相关的参数,例如频率、幅度、波形类型等。
2. 状态显示:
UI 显示波形发生器的当前状态。可能的状态包括 “init”、“calc wave”、“running” 或 “stopped”。
3. 波形选择和默认值:
用户可以从下拉菜单中选择波形类型(例如正弦、方波、三角波)。选择波形后,相关参数(例如频率、幅度)被设置为默认值。使用默认值按下 “setup generator” 按钮便生成波形。
4. 样本数和输出频率:
UI 显示用于波形生成的样本数。根据选择的参数,显示输出的实际频率。
5.主要代码
def setupwave(buf,f,w):
div=fclock/(f*maxnsamp) # required clock division for maximum buffer size
if div<1.0: #can't speed up clock, duplicate wave instead
dup=int(1.0/div)
nsamp=int((maxnsamp*div*dup+0.5)/4)*4 #force multiple of 4
clkdiv=1
else: #stick with integer clock division only
clkdiv=int(div)+1
nsamp=int((maxnsamp*div/clkdiv+0.5)/4)*4 #force multiple of 4
dup=1
#fill the buffer
for isamp in range(nsamp):
buf[isamp]=max(0,min(255,int(256*eval(w,dup*(isamp+0.5)/nsamp))))
#set the clock divider
clkdiv_int=min(clkdiv,65535)
clkdiv_frac=0 #fractional clock division results in jitter
mem32[PIO0_SM0_CLKDIV]=(clkdiv_int<<16)|(clkdiv_frac<<8)
#start DMA
startDMA(buf,int(nsamp/4))
1) 时钟频率:代码假定时钟频率为125 MHz。
2) DMA 配置:通道0执行实际数据传输。
通道1重新配置DMA。
DMA用于从数组传输数据到PIO(可编程I/O)状态机。
3) 状态机(PIO):
状态机(stream)将字节推送到指定的引脚。
sm状态机配置为125 MHz并处于活动状态。
七、 设计难题
1. 硬件连接和电路设计:
确定R2R电阻网络的比例,以便正确生成所需的模拟输出电压。确保电路连接正确,以避免电阻值不准确或电压失真。
2. MicroPython的限制:
MicroPython相对于原生C/C++的执行速度较慢,因此需要考虑性能问题。
3. DMA和PIO的编程:
理解DMA和PIO的工作原理,以便正确配置和使用它们。编写PIO程序来控制输出引脚,以便将数据传输到R2R电阻网络。使用DMA来从输入缓冲区复制数据到PIO。
八、 未来计划
1. R2R梯形DAC的精度受到电阻值的影响。使用更精确的电阻,以提高输出的精度。确保电阻网络的比例准确,以获得线性的输出。
2. 受电源噪声影响,信号输出底噪较大,可使用线性电源供电,以及设计滤波电路,减少噪声。
3. 添加自动校准功能,矫正电阻网络带来的误差。
九、 总结
通过本次寒假在家一起练项目,真正的投入到单片机开发中去,同时还了解到R2R-DAC这种有趣的输出结构。这些经历只是刚刚开始,这一项目仍然存在着很多不足之处以及可以提升的地方,相信在之后的学习中,可以将这一设计做的更加完善。