Skip to content

概念先知道

  • DAC(数模转换):与 ADC 相反,把数字值变成模拟电压;常用它输出波形、音频或基准电压。
  • 采样率:DAC 每秒刷新输出的次数,例程 512KHz;输出一个周期的正弦波需要整张查找表。
  • DMA 连续输出:CPU 把正弦表交给 DMA,DMA 按采样率持续把数据喂给 DAC,CPU 全程不参与。

例程功能简介

本页对应博流官方 SDK 的 dac_dma 例程(examples/peripherals/dac/dac_dma),演示 DMA + DAC 输出模拟波形:

  • DAC 采样时钟 = 512K / 分频,例程 DAC_CLK_DIV_1 得到 512KHz,使能 A 通道并链接 TX DMA;
  • 内置一张正弦波查找表(16bit 幅值),DMA 把整张表写入 DAC 数据寄存器;
  • 传输完成后进入中断回调打印 tc done,DAC 持续输出正弦波形。
  • 同族例程examples/peripherals/dac/):dac_polling(轮询输出)。

操作步骤

1
硬件准备

DAC 输出引脚由 board_dac_gpio_init() 配置。用示波器/万用表测量该引脚电压,或用耳机/音频放大器听输出音调;也可以把输出接到 ADC 通道回读验证。

2
进入例程目录

在终端进入 SDK 的 DAC 例程目录(前提:已按快速开始(Linux)Windows搭建好环境):

cd examples/peripherals/dac/dac_dma
3
编译工程

执行编译命令。Ai-M62(BL616)与 Ai-M61(BL618)同属一个系列,统一填写引脚最少的 bl616 即可:

make CHIP=bl616 BOARD=bl616dk
4
烧录固件

用 USB 线连接开发板,按住 BOOT 键(Ai-M61-32S-Kit 为 IO2)不放、短按 EN/RST 进入下载模式,然后执行烧录(把串口号换成实际值):

make flash CHIP=bl616 COMX=/dev/ttyUSB0
5
运行验证

打开串口助手(波特率 2000000),DMA 搬运完成会打印一次 tc done。用示波器观察 DAC 引脚,应看到按正弦表循环输出的正弦波形(DMA 持续把正弦表数据写入 DAC)。

代码执行流程

例程从启动到运行的完整流程如下(图中的循环箭头表示反复执行):

例程调用的 API 介绍

bflb_device_get_by_name("dac")

获取 DAC 外设的设备句柄。

参数

  • name:外设名称,固定 "dac"

返回值struct bflb_device_s * 设备句柄

bflb_dac_init(dac, DAC_CLK_DIV_1)

初始化 DAC,第二个参数为时钟分频(DAC_CLK_DIV_1 → 512KHz 采样)。

参数

  • dac:DAC 设备句柄
  • div:时钟分频

返回值:成功返回 0;失败返回负值错误码

bflb_dac_channel_enable(dac, DAC_CHANNEL_A)

使能 DAC 输出通道(A/B)。

参数

  • dac:DAC 设备句柄
  • channel:通道,DAC_CHANNEL_A / DAC_CHANNEL_B

返回值:成功返回 0;失败返回负值错误码

把 DAC 发送方向链接到 DMA,由 DMA 自动喂数据。

参数

  • dac:DAC 设备句柄
  • enabletrue 链接 / false 断开

返回值:成功返回 0;失败返回负值错误码

bflb_dma_channel_lli_reload / start(...)

把正弦表地址装载到 DMA(目的地址为 DMA_ADDR_DAC_TDR)并启动;DMA 方向为 DMA_MEMORY_TO_PERIPH、请求源 DMA_REQUEST_DAC

参数:同 DMA 例程(通道配置、LLI 链表、启动)

返回值:成功返回 0;失败返回负值错误码

完整代码

以下为 dac_dma/main.c 完整源码,与官方示例(examples/peripherals/dac/dac_dma)一致;点灯引脚已适配 Ai-M61/62-32S-Kit 板载 RGB 灯,默认折叠,点击展开:

📜 点击展开 dac_dma/main.c 完整代码
c
#include "bflb_dac.h"
#include "bflb_mtimer.h"
#include "bflb_dma.h"
#include "bflb_l1c.h"
#include "board.h"

struct bflb_device_s *dac;
struct bflb_device_s *dma0_ch0;

const uint16_t SIN_LIST[] = {
    500, 506, 513, 519, 525, 531, 538, 544, 550, 556,
    563, 569, 575, 581, 587, 594, 600, 606, 612, 618,
    624, 630, 636, 642, 648, 654, 660, 666, 672, 678,
    684, 690, 696, 701, 707, 713, 718, 724, 730, 735,
    741, 746, 752, 757, 762, 768, 773, 778, 784, 789,
    794, 799, 804, 809, 814, 819, 823, 828, 833, 838,
    842, 847, 851, 856, 860, 864, 869, 873, 877, 881,
    885, 889, 893, 897, 901, 904, 908, 912, 915, 919,
    922, 925, 929, 932, 935, 938, 941, 944, 947, 950,
    952, 955, 958, 960, 962, 965, 967, 969, 971, 973,
    975, 977, 979, 981, 983, 984, 986, 987, 989, 990,
    991, 992, 993, 994, 995, 996, 997, 997, 998, 999,
    999, 999, 1000, 1000, 1000, 1000, 1000, 1000, 1000,
    999, 999, 999, 998, 998, 997, 996, 995, 994, 993,
    992, 991, 990, 989, 987, 986, 984, 983, 981, 979,
    978, 976, 974, 972, 970, 967, 965, 963, 960, 958, 955, 953, 950, 947, 944, 941, 938, 935,
    932, 929, 926, 922, 919, 916, 912, 908, 905, 901, 897, 893, 890, 886, 882, 878, 873, 869,
    865, 861, 856, 852, 847, 843, 838, 833, 829, 824, 819, 814, 809, 804, 799, 794, 789, 784,
    779, 774, 768, 763, 758, 752, 747, 741, 736, 730, 725, 719, 714, 708, 702, 696, 691, 685, 679,
    673, 667, 661, 655, 649, 643, 637, 631, 625, 619, 613, 607, 601, 594, 588, 582, 576, 570, 563,
    557, 551, 545, 538, 532, 526, 520, 513, 507, 501, 495, 488, 482, 476, 469, 463, 457, 451, 444,
    438, 432, 426, 420, 413, 407, 401, 395, 389, 383, 376, 370, 364, 358, 352, 346, 340, 334, 329,
    323, 317, 311, 305, 299, 294, 288, 282, 277, 271, 265, 260, 254, 249, 244, 238, 233, 228, 222,
    217, 212, 207, 202, 197, 192, 187, 182, 177, 172, 168, 163, 158, 154, 149, 145, 141, 136, 132, 128, 124,
    119, 115, 111, 107, 104, 100, 96, 92, 89, 85, 82, 78, 75, 72, 69, 65, 62, 59, 56, 54, 51, 48, 45, 43, 40, 38,
    36, 33, 31, 29, 27, 25, 23, 21, 19, 18, 16, 14, 13, 12, 10, 9, 8, 7, 6, 5, 4, 3, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 8, 9, 10, 11,
    12, 14, 15, 17, 19, 20, 22, 24, 26, 28, 30, 32, 35, 37, 39, 42, 44, 47, 50, 52, 55, 58, 61, 64, 67, 71, 74, 77, 81, 84, 87, 91, 95, 98, 102, 106, 110, 114, 118, 122,
    126, 130, 135, 139, 143, 148, 152, 157, 161, 166, 171, 175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 226, 231, 236, 242, 247, 252, 258, 263, 269, 274, 280, 286,
    291, 297, 303, 309, 315, 320, 326, 332, 338, 344, 350, 356, 362, 368, 374, 380, 386, 392, 399, 405, 411, 417, 423, 430, 436, 442, 448, 455, 461, 467, 473, 480, 486, 492
};

static uint8_t dma_tc_flag0 = 0;

struct bflb_dma_channel_lli_pool_s lli[1]; /* max trasnfer size 4064 * 1 */

void dma0_ch0_isr(void *arg)
{
    dma_tc_flag0++;
    printf("tc done\r\n");
}

int main(void)
{
    board_init();
    board_dac_gpio_init();

    dac = bflb_device_get_by_name("dac");
    dma0_ch0 = bflb_device_get_by_name("dma0_ch0");

    struct bflb_dma_channel_config_s config;

    config.direction = DMA_MEMORY_TO_PERIPH;
    config.src_req = DMA_REQUEST_NONE;
    config.dst_req = DMA_REQUEST_DAC;
    config.src_addr_inc = DMA_ADDR_INCREMENT_ENABLE;
    config.dst_addr_inc = DMA_ADDR_INCREMENT_DISABLE;
    config.src_burst_count = DMA_BURST_INCR1;
    config.dst_burst_count = DMA_BURST_INCR1;
    config.src_width = DMA_DATA_WIDTH_16BIT;
    config.dst_width = DMA_DATA_WIDTH_16BIT;
    bflb_dma_channel_init(dma0_ch0, &config);

    bflb_dma_channel_irq_attach(dma0_ch0, dma0_ch0_isr, NULL);

    /* 512K / 1 = 512K */
    bflb_dac_init(dac, DAC_CLK_DIV_1);
    bflb_dac_channel_enable(dac, DAC_CHANNEL_A);
    //bflb_dac_channel_enable(dac, DAC_CHANNEL_B);
    bflb_dac_link_txdma(dac, true);

    struct bflb_dma_channel_lli_transfer_s transfers[1];

    transfers[0].src_addr = (uint32_t)SIN_LIST;
    transfers[0].dst_addr = (uint32_t)DMA_ADDR_DAC_TDR;
    transfers[0].nbytes = sizeof(SIN_LIST);
    bflb_l1c_dcache_clean_range((void*)SIN_LIST,sizeof(SIN_LIST));

    bflb_dma_channel_lli_reload(dma0_ch0, lli, 1, transfers, 1);
    bflb_dma_channel_start(dma0_ch0);

    while (dma_tc_flag0 != 1) {
        bflb_mtimer_delay_ms(1);
    }

    while (1) {
    }
}

FAQ

DAC 引脚没有波形

确认使能了输出通道(DAC_CHANNEL_A)并调用 bflb_dac_link_txdma(dac, true);用示波器接 DAC 引脚并共地。

波形频率不对

正弦表一个周期 512 点,输出频率 = 512K / 512 ≈ 1kHz。修改分频或正弦表点数可改变频率;注意不要超过 DAC 最高采样率。

只打印一次 tc done 后没有持续波形

例程只用单次 LLI 传输,DMA 完成后波形停在正弦表末尾。要做连续输出,可配置 LLI 循环或使用 DMA 循环模式。

遇到问题?

如有其他问题,请到统一的提问与讨论区:Ai-Thinker Discussions

Released under the MIT License. Build Time 2026-09-11 14:52:23