|
本帖最后由 tomzbj 于 2022-6-22 10:43 编辑
大约10年前, 某次看到一个用AVR做的DDS信号源, 记得作者是Jasper Hansen, 感觉挺不错.
搜了一下, 链接居然还在:
http://www.radanpro.com/Radan2400/mikrokontroleri/Jesper's%20AVR%20pages%20-%20MiniDDS.htm
大概的原理:
用单片机的一组8位GPIO搭成R-2R DAC
建立一个256点的正弦波形表
执行这个累加器循环, 就可以输出任意频率的正弦波了.
- void cloop(uint16_t step)
- {
- registeruint16_t counter = 0;
- while(1){
- counter += step;
- PORTC = waveform[counter >> 8];
- }
- return;
- }
复制代码
这个循环大概需要11个时钟周期, 用20M主频的ATTiny2313可以做到的最高DDS时钟是是20M/11=1.82MHz左右, 最高输出频率要再除以2, 不到0.91MHz. 把这个循环写成汇编的话可以优化到7个时钟周期, 最高能输出1.43MHz左右.
缺点么, 也很明显, CPU占用率是100%, 完全干不了别的了, 想加个屏幕加个按键什么的, 基本不可能.
从那之后我陆续用AVR和STM32各做了几次, STM32虽然比AVR快得多, 但在这个场合也没有太大优势, 循环体需要12个时钟周期, 72M的STM32F103也只能做到6M的DDS时钟.
某天突然想到, GD32F30x/F3x0能超频到280MHz, 用来做DDS岂不是很有优势? 最好不要用死循环的形式, 这样可以把屏幕按键都加上了.
先试试GPIO输出到底能有多快, 在开发板上用DMA按M2M方式直接写GPIO, 实测可以做到大约6.5个时钟周期更新一次, 果然不错. 不过更新周期不确定, 大概是因为DMA用M2M方式需要竞争总线, 能不能抢到要看运气. 看来得另想办法.
先画个小板, 原理图如下, GD32F350G8U6的PA0-PA7接成R2R DAC, 用高速运放GS8092缓冲输出(输出端忘了串50欧电阻了). 电荷泵SGM3204用于给运放提供负压. 此外就是128*32的OLED屏和两个按键, 没了.
支持国货, 除了不重要的AMS1117-3.3, 其他都是国产.
这个累加器循环怎么改呢? 先用定时器中断试试, 在中断服务程序里更新DAC. 结果呢, 不太理想, 中断服务程序需要37个时钟周期, 如果还要屏幕/按键/串口能响应,即使超频到240M,DDS时钟只能做到240M/50=4.8M左右, 不太实用.
另一个办法就是用DMA了, 用定时器触发DMA写GPIOA, 在DMA的半满和全满中断里重写波形数据表. 实测了一下, 刷新半张表也就是128个点, 需要1000个时钟周期多点, 这样可以做到每10个时钟周期输出一次, 同样超频240M, 可以做到24M的DDS时钟.
不过实测发现剩余200多个时钟周期不太够, 处理串口屏幕按键还是卡顿, 怎么办呢? 把中断这里的循环展开试试, 再测, 只需要700多个时钟周期, 这次操作比较流畅了.
操作么, 就俩按键, 短按上键切换输出幅度, 长按上键切换波形, 短按下键切换频率(可以预设4个频率), 长按下键进入设置菜单.
实测输出2M/3.58M/7.023M的频谱, 还可以吧? 7M时能看到右边17M的镜像峰了, sunzx给了个好办法, 后面缓冲级用自带6阶10M LPF的视频放大器即可.
原理图及程序见github链接:
https://github.com/tomzbj/diy/tree/master/2022/gd32_dds
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
阿莫论坛20周年了!感谢大家的支持与爱护!!
一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。
|