Concepts First
- DAC (digital-to-analog): the reverse of ADC — turns digital values into analog voltage, used for waveforms, audio, and reference voltages.
- Sample rate: how often the DAC updates its output per second (512 kHz in the example); a full sine period needs a whole lookup table.
- Continuous DMA output: the CPU hands the sine table to DMA, which keeps feeding the DAC at the sample rate while the CPU stays free.
Example Overview
This page is based on the dac_dma example in the official Bouffalo SDK (examples/peripherals/dac/dac_dma), which demonstrates DMA + DAC analog waveform output:
- DAC sample clock = 512K / divider; the example uses
DAC_CLK_DIV_1(512 kHz), enables channel A, and links TX DMA; - A built-in sine lookup table (16-bit amplitude) is written into the DAC data register by DMA;
- When the transfer completes, the ISR prints
tc done; the DAC continuously outputs the sine wave. - Sibling examples (
examples/peripherals/dac/):dac_polling(polling output).
Operation Steps
The DAC output pin is configured by board_dac_gpio_init(). Measure the pin with an oscilloscope/multimeter, or listen through headphones/an audio amplifier; you can also route it to an ADC channel to read it back.
Open a terminal and enter the DAC example directory (prerequisite: set up the environment as in Quick Start (Linux) or Windows):
cd examples/peripherals/dac/dac_dmaRun the build command. The Ai-M62 (BL616) and Ai-M61 (BL618) belong to the same series, so both use bl616:
make CHIP=bl616 BOARD=bl616dkConnect the board with a USB cable, hold the BOOT button (IO2 on the Ai-M61-32S-Kit), briefly press EN/RST to enter download mode, then flash (replace the serial port with the one on your computer):
make flash CHIP=bl616 COMX=/dev/ttyUSB0Open a serial tool (baud rate 2000000); a tc done is printed when the DMA transfer completes. On an oscilloscope you should see a sine wave on the DAC pin (DMA continuously writes the sine table to the DAC).
Code Execution Flow
The complete execution flow from startup to running is shown below (loop arrows mean repeated execution):
APIs Used by the Example
bflb_device_get_by_name("dac")
Gets the DAC device handle.
Parameters:
name: device name, always"dac"
Return: struct bflb_device_s * device handle
bflb_dac_init(dac, DAC_CLK_DIV_1)
Initializes the DAC; the second argument is the clock divider (DAC_CLK_DIV_1 → 512 kHz sampling).
Parameters:
dac: DAC device handlediv: clock divider
Return: 0 on success; negative error code on failure
bflb_dac_channel_enable(dac, DAC_CHANNEL_A)
Enables a DAC output channel (A/B).
Parameters:
dac: DAC device handlechannel:DAC_CHANNEL_A/DAC_CHANNEL_B
Return: 0 on success; negative error code on failure
bflb_dac_link_txdma(dac, true)
Links the DAC TX direction to DMA so DMA feeds the data automatically.
Parameters:
dac: DAC device handleenable:truelink /falseunlink
Return: 0 on success; negative error code on failure
bflb_dma_channel_lli_reload / start(...)
Loads the sine table into the DMA channel (destination DMA_ADDR_DAC_TDR) and starts it; direction is DMA_MEMORY_TO_PERIPH with request DMA_REQUEST_DAC.
Parameters: same as the DMA example
Return: 0 on success; negative error code on failure
Complete Code
The complete source below matches the effect described on this page. It is based on the official example (examples/peripherals/dac/dac_dma); the LED pins are adapted to the Ai-M61/62-32S-Kit onboard RGB LED. Collapsed by default, click to expand:
📜 Click to expand dac_dma/main.c full code
#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
No waveform on the DAC pin
Make sure the output channel is enabled (DAC_CHANNEL_A) and bflb_dac_link_txdma(dac, true) was called; probe the DAC pin with a shared ground.
The waveform frequency is wrong
The sine table has 512 points per cycle, so the output frequency ≈ 512K / 512 ≈ 1 kHz. Change the divider or table size to adjust; do not exceed the DAC maximum sample rate.
Only one tc done, then no continuous wave
The example uses a single LLI transfer, so the waveform stops at the end of the table. For continuous output, configure LLI looping or the DMA cycle mode.
Have questions?
For any other questions, visit the unified Q&A and discussion board: Ai-Thinker Discussions

