tomzbj 发表于 2022-6-21 23:58:25

[原创] 用GD32做了个迷你DDS信号发生器

本帖最后由 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;
    }
    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

tomzbj 发表于 2022-6-22 00:00:16

操作视频

Rabbitoose 发表于 2022-6-22 00:07:07

本帖最后由 Rabbitoose 于 2022-6-22 00:22 编辑

所以说你的工作经常要用到信号发生器吗?我一直想买一个信号发生器但是一直没有认真了解过。

以前翻帖子就看到过R2R,这次趁机学习一下

cne53102 发表于 2022-6-22 01:30:13

这是超了2.6倍吗。。有点狠啊。。不过24M的话很有诱惑力了,差不多五百块机器的频率了

tomzbj 发表于 2022-6-22 09:42:18

cne53102 发表于 2022-6-22 01:30
这是超了2.6倍吗。。有点狠啊。。不过24M的话很有诱惑力了,差不多五百块机器的频率了 ...
(引用自4楼)

以前测试的极限, GD32F350, F303, FFPR都是336M左右, 不太稳定, 280M就很稳了.
GD32F103可以超到192M.
GD32F450ZET6可以超到400M.

见我的测试 https://github.com/tomzbj/dhrystone_score

上面这几个, 除了F450, 超频后性能基本都是STC8的100倍以上, 价格也就是10元上下, 真不知道STC那伙人有什么好吹的

cloudboy 发表于 2022-6-22 10:00:01

GD的flash是有一块SRAM模拟区的,这一点确实非常有利于超频

kitten 发表于 2022-6-22 10:03:24

tomzbj 发表于 2022-6-22 09:42
以前测试的极限, GD32F350, F303, FFPR都是336M左右, 不太稳定, 280M就很稳了.
GD32F103可以超到192M.
GD ...
(引用自5楼)

都是国货,人家有大火炉加持,你这个没有。{:titter:}

tomzbj 发表于 2022-6-22 10:05:31

cne53102 发表于 2022-6-22 01:30
这是超了2.6倍吗。。有点狠啊。。不过24M的话很有诱惑力了,差不多五百块机器的频率了 ...
(引用自4楼)

DDS时钟24M, 实际输出频率能到10M左右吧... 不加LPF的话, 频谱看着还好, 用示波器看波形已经很杂乱了.

liyang121316 发表于 2022-6-22 10:36:17

楼主位第一个链接需要爱国吗?我点开就是404

tomzbj 发表于 2022-6-22 10:43:44

liyang121316 发表于 2022-6-22 10:36
楼主位第一个链接需要爱国吗?我点开就是404
(引用自9楼)

奇怪, 我再粘贴一个

http://www.radanpro.com/Radan2400/mikrokontroleri/Jesper's%20AVR%20pages%20-%20MiniDDS.htm

tomzbj 发表于 2022-6-22 10:44:27

tomzbj 发表于 2022-6-22 10:43
奇怪, 我再粘贴一个

http://www.radanpro.com/Radan2400/mikrokontroleri/Jesper's%20AVR%20pages%20-%2 ...
(引用自10楼)

点开不行, 复制粘贴到地址栏可以...是老莫的bug么

pcl 发表于 2022-6-22 10:47:12

网址没错, 应该是论坛的问题, 帖子外连断在 ' 符号, 可以手动复制去看

wowangru 发表于 2022-6-22 11:57:35

用DMA是最好的竞争总线的问题如何解决或者降低影响呢

pspice 发表于 2022-6-22 12:03:20

用FSMC来实现会不会快很多?

tomzbj 发表于 2022-6-22 12:07:10

wowangru 发表于 2022-6-22 11:57
用DMA是最好的竞争总线的问题如何解决或者降低影响呢
(引用自13楼)

不用M2M呗
其实是移花接木了一下, 用TIMER触发DMA写DAC, 但是没有真的写到DAC, 而是写到了GPIOA
不然没法实现用TIMER触发写GPIO

GD32本身的DAC虽然比STM32快, 但和GPIO+R2R比还是太慢了

tomzbj 发表于 2022-6-22 12:08:01

pspice 发表于 2022-6-22 12:03
用FSMC来实现会不会快很多?
(引用自14楼)

FSMC应该也是6个周期输出一次吧? 我忘了
关键是重写查找表,这个时间没法省

wowangru 发表于 2022-6-22 12:44:30

tomzbj 发表于 2022-6-22 12:07
不用M2M呗
其实是移花接木了一下, 用TIMER触发DMA写DAC, 但是没有真的写到DAC, 而是写到了GPIOA
不然没法 ...
(引用自15楼)

我就是用的APB2的tim1触发 DMA输出GPIO   但是也不是很稳定, IO时间精度不稳定

        DMA_InitTypeDefDMA_InitStructure;   
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
       
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2ʱÖÓʹÄÜ
        DMA_DeInit(DMA2_Stream5);
        while (DMA_GetCmdStatus(DMA2_Stream5) != DISABLE){}
        DMA_InitStructure.DMA_Channel = DMA_Channel_6;
        DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(GPIOC->ODR);
        DMA_InitStructure.DMA_Memory0BaseAddr = (u32)g_EXC_DATA;
        DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
        DMA_InitStructure.DMA_BufferSize = POINT_NUM2;
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
        DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord;
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
        DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
        DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
        DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
        DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
        DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//
        DMA_Init(DMA2_Stream5, &DMA_InitStructure);//³õʼ»¯DMA Stream
        DMA_Cmd(DMA2_Stream5, ENABLE);

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
        TIM_TimeBaseInitStructure.TIM_Period=6;   //
        TIM_TimeBaseInitStructure.TIM_Prescaler=1;
        TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
        TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStructure);
        TIM_DMACmd(TIM1,TIM_DMA_Update,ENABLE);
TIM_Cmd(TIM1, ENABLE);

koon 发表于 2022-6-22 15:07:20

正弦波的最大输出频率是不是DDS时钟除以256?

tomzbj 发表于 2022-6-22 15:35:37

koon 发表于 2022-6-22 15:07
正弦波的最大输出频率是不是DDS时钟除以256?
(引用自18楼)

不是, DDS时钟除以2
不过这时波形基本没法看了

koon 发表于 2022-6-22 16:44:23

tomzbj 发表于 2022-6-22 15:35
不是, DDS时钟除以2
不过这时波形基本没法看了
(引用自19楼)

DDS时钟除以2,又没有滤波网络,这不是方波吗,这个正弦波不是256个点吗

chenchaoting 发表于 2022-6-22 16:53:57

tomzbj 发表于 2022-6-22 12:07
不用M2M呗
其实是移花接木了一下, 用TIMER触发DMA写DAC, 但是没有真的写到DAC, 而是写到了GPIOA
不然没法 ...
(引用自15楼)

那不还是存在DMA竞争总线吗

liang16888 发表于 2022-6-22 17:10:41

楼主厉害耶 thank you

tomzbj 发表于 2022-6-22 19:03:49

chenchaoting 发表于 2022-6-22 16:53
那不还是存在DMA竞争总线吗
(引用自21楼)

m2m的总线利用率低啊

不是m2m的话,别把总线全占完就行,输出频率是准的

NJ8888 发表于 2022-6-22 19:48:46

直接十块钱dds芯片不香?

tomzbj 发表于 2022-6-22 19:52:43

NJ8888 发表于 2022-6-22 19:48
直接十块钱dds芯片不香?
(引用自24楼)

AD9833? 现在10元也只能买拆机件了吧, 新的起码30+了吧...
不知道有没有国内厂家克隆?

tomzbj 发表于 2022-6-22 20:02:06

koon 发表于 2022-6-22 16:44
DDS时钟除以2,又没有滤波网络,这不是方波吗,这个正弦波不是256个点吗
(引用自20楼)

是啊, 不能刚好到2, 得稍微低点.
你看7M多的频谱不是还可以么, 右边17M的镜像也好办, 弄个12M左右的LPF就滤掉了.
用MS1651之类的视频放大器, 内置10M的6阶LPF, 刚合适.

矩阵时间 发表于 2022-6-22 20:02:58

koon 发表于 2022-6-22 16:44
DDS时钟除以2,又没有滤波网络,这不是方波吗,这个正弦波不是256个点吗
(引用自20楼)

三角波,就波峰波谷两个点

lyl520719 发表于 2022-6-23 02:17:28

还是用FPGA来做最好。

rube 发表于 2022-6-23 18:26:11

厉害,膜拜一下

chinaboy25 发表于 2022-6-27 09:31:01

lyl520719 发表于 2022-6-23 02:17
还是用FPGA来做最好。
(引用自28楼)

有个国产DAC模块就是FPGA外加R2R电阻网络来实现的;

sunliezhi 发表于 2022-6-27 18:15:29

打不开 github了,以前在早上这个时间段还可以打开的。
页: [1]
查看完整版本: [原创] 用GD32做了个迷你DDS信号发生器