ADC - dma

本 demo 主要演示 adc dma 单端模式下读取电压值。默认扫描通道 0 ~ 通道10。 需要注意,有些芯片不一定支持全部通道

硬件连接

本 demo 使用到的 gpio 参考 board_adc_gpio_init

软件实现

更详细的代码请参考 examples/peripherals/adc/adc_dma

1board_init();
  • board_init 中会开启 ADC IP 时钟,并选择 ADC 时钟源和分频(ADC 时钟必须小于等于 500K)。

1board_adc_gpio_init();
  • 配置相关引脚为 ADC 功能

 1adc = bflb_device_get_by_name("adc");
 2
 3/* adc clock = XCLK / 2 / 32 */
 4struct bflb_adc_config_s cfg;
 5cfg.clk_div = ADC_CLK_DIV_32;
 6cfg.scan_conv_mode = true;
 7cfg.continuous_conv_mode = true;
 8cfg.differential_mode = false;
 9cfg.resolution = ADC_RESOLUTION_16B;
10cfg.vref = ADC_VREF_3P2V;
11
12bflb_adc_init(adc, &cfg);
  • 获取 adc 句柄,并初始化 adc 配置,设置 adc 采样频率为 500K

1bflb_adc_channel_config(adc, chan, TEST_ADC_CHANNELS);
  • 配置 adc 通道信息,使用的通道数通过 TEST_ADC_CHANNELS 可配,默认开启通道 0 ~ 10,根据 board_adc_gpio_init 需要选择性关闭其他通道。

1bflb_adc_link_rxdma(adc, true);
  • 使能 adc rx dma 功能

 1dma0_ch0 = bflb_device_get_by_name("dma0_ch0");
 2
 3struct bflb_dma_channel_config_s config;
 4
 5config.direction = DMA_PERIPH_TO_MEMORY;
 6config.src_req = DMA_REQUEST_ADC;
 7config.dst_req = DMA_REQUEST_NONE;
 8config.src_addr_inc = DMA_ADDR_INCREMENT_DISABLE;
 9config.dst_addr_inc = DMA_ADDR_INCREMENT_ENABLE;
10config.src_burst_count = DMA_BURST_INCR1;
11config.dst_burst_count = DMA_BURST_INCR1;
12config.src_width = DMA_DATA_WIDTH_32BIT;
13config.dst_width = DMA_DATA_WIDTH_32BIT;
14bflb_dma_channel_init(dma0_ch0, &config);
15
16bflb_dma_channel_irq_attach(dma0_ch0, dma0_ch0_isr, NULL);
  • 配置 DMA CH0ADC RX

  • 注册 dma 通道中断

 1struct bflb_dma_channel_lli_pool_s lli[1]; /* max trasnfer size 4064 * 1 */
 2struct bflb_dma_channel_lli_transfer_s transfers[1];
 3
 4memset(raw_data, 0, sizeof(raw_data));
 5
 6transfers[0].src_addr = (uint32_t)DMA_ADDR_ADC_RDR;
 7transfers[0].dst_addr = (uint32_t)raw_data;
 8transfers[0].nbytes = sizeof(raw_data);
 9
10bflb_dma_channel_lli_reload(dma0_ch0, lli, 1, transfers, 1);
11bflb_dma_channel_start(dma0_ch0);
12
13bflb_adc_start_conversion(adc);
14
15while (dma_tc_flag0 != 1) {
16    bflb_mtimer_delay_ms(1);
17}
18
19bflb_adc_stop_conversion(adc);
  • 分配一块 lli 内存池,个数为1,最多可以传输 4064 * 1 字节

  • 配置一块内存进行传输

  • 调用 bflb_dma_channel_lli_reload 初始化

  • 调用 bflb_dma_channel_start 启动传输

  • 调用 bflb_adc_start_conversion 启用 adc 的转换

  • 等待传输完成并进入中断

  • 调用 bflb_adc_stop_conversion 停止 adc 转换

1for (size_t j = 0; j < TEST_ADC_CHANNELS * TEST_COUNT; j++) {
2    struct bflb_adc_result_s result;
3    printf("raw data:%08x\r\n", raw_data[j]);
4    bflb_adc_parse_result(adc, &raw_data[j], &result, 1);
5    printf("pos chan %d,%d mv \r\n", result.pos_chan, result.millivolt);
6}
  • 调用 bflb_adc_parse_result 对 adc 的转换结果进行解析,解析的值保存到 result 结构体中

  • 打印通道号和电压值

编译和烧录

参考 环境搭建

实验现象

打印 raw data,通道号以及通道对应的电压值。