先楫半导体HPMicro
直播中

夜_微

6年用户 3经验值
擅长:嵌入式技术
私信 关注
[问答]

HPM6360 ADC0 序列DMA 软件触发采集异常

环境: HPM6360, SDK v1.1.0

功能: ADC0 序列DMA 软件触发 1毫秒中断中触发一次采集 采集3个通道, 分别为PC05, PC07, PC08

异常: 使用JScope监测采集到的波形, 发现3个通道确实在序列采集, 但是每个通道的采集时间远远大于1ms, 而且波形分辨率很差.

波形如下:
c2818fe8a2d8cae4645ca3f2d6c2d23.png

代码如下:

951c9119a80949d3153db894c1dd990.png

03596b2f17d832d3ef56edffd4d2242.png

image.png

image.png

image.png

回帖(2)

jf_50062488

2023-9-27 13:41:45
本帖最后由 jf_50062488 于 2023-9-27 14:35 编辑

不太清楚波形是怎么打印的,每ms打印一个值么?
看注释,有些时间值可能和你注释理解的不一样:
adc_clk_div=3就是三分频,不是注释里面的四分频;
sample时间1000-(21+1),并不是22us,63系列的adc采样时间配置改成了两部分,9bit的clk_number和3bit的shift,你这样写进去978(0x3D2)实际会是0x1D2,大约8.4us(466*6*3)。

最有可能的问题是,adc16_event_seq_full_complete这个中断好像不大好用,看你是用的查询,你可以试试看查询DetectorBuffer[].cycle_bit, 这个bit变化了数据应该就有效了。
ps,DetectorBuffer不能是cachable的,不然cpu去读的时候有可能还是cache里面的旧数据
举报

回头太晚

2024-1-4 11:20:46
```c
#include "hpm6360.h"

#define ADC_SEQ_LEN 3 // 采集通道数
#define ADC_DMA_LEN 1 // DMA缓存组数
#define TIMER_FREQ  1000 // 定时器频率,1ms中断一次

uint16_t adc_values[ADC_SEQ_LEN * ADC_DMA_LEN];
volatile uint8_t dma_complete = 0;

void adc_dma_callback(uint32_t dma_event, void *context)
{
    dma_complete = 1;
}

void adc_init(void)
{
    // 使能 ADC 和 DMA 时钟
    hpm_adc_clock_enable(HPM_ADC0_CLOCK);
    hpm_dma_clock_enable(HPMDMA_CLOCK);

    // 配置 ADC 时钟,使用 HSI16 时钟,分频系数为 2
    hpm_adc_set_clock(HPM_ADC0_CLOCK, HPM_ADC_CLOCK_SRC_HSI16, 2);

    // 配置 PC05, PC07, PC08 为模拟输入
    hpm_gpio_configure_pin(HPM_GPIO_PC05, HPM_GPIO_MODE_ANALOG, HPM_GPIO_NOPULL);
    hpm_gpio_configure_pin(HPM_GPIO_PC07, HPM_GPIO_MODE_ANALOG, HPM_GPIO_NOPULL);
    hpm_gpio_configure_pin(HPM_GPIO_PC08, HPM_GPIO_MODE_ANALOG, HPM_GPIO_NOPULL);

    // 配置 ADC 采样时间,选择 ADC 时钟为采样时钟
    hpm_adc_set_sample_time(HPM_ADC0, HPM_ADC_SAMPLE_TIME_239CYC, HPM_ADC_CLOCK_SRC_ADCCLK);

    // 配置 ADC 触发源为软件触发
    hpm_adc_set_trigger(HPM_ADC0, HPM_ADC_TRIGGER_SOFTWARE);

    // 配置 ADC 为正常模式,转换序列长度为 3,DMA 使能
    hpm_adc_set_mode(HPM_ADC0, HPM_ADC_MODE_NORMAL);
    hpm_adc_set_sequence_length(HPM_ADC0, ADC_SEQ_LEN);
    hpm_adc_dma_enable(HPM_ADC0);

    // 配置 DMA
    hpm_dma_configure_channel(HPMDMA_CHANNEL1, HPM_DMA_PERIPH_TO_MEM);
    hpm_dma_set_data_width(HPMDMA_CHANNEL1, HPM_DMA_DATA_WIDTH_HALFWORD);
    hpm_dma_set_peripheral_increment(HPMDMA_CHANNEL1, HPM_DMA_PERIPH_INCREMENT_DISABLE);
    hpm_dma_set_memory_increment(HPMDMA_CHANNEL1, HPM_DMA_MEMORY_INCREMENT_ENABLE);
    hpm_dma_set_peripheral_address(HPMDMA_CHANNEL1, (uint32_t)&(HPM_ADC0->DR));
    hpm_dma_set_memory_address(HPMDMA_CHANNEL1, (uint32_t)adc_values);
    hpm_dma_set_transfer_length(HPMDMA_CHANNEL1, ADC_SEQ_LEN * ADC_DMA_LEN);
    hpm_dma_set_callback(HPMDMA_CHANNEL1, adc_dma_callback, NULL);

    // 配置定时器,中断频率为 1KHz
    hpm_timer_clock_enable(HPM_TIMER6_CLOCK);
    hpm_timer_set_prescaler(HPM_TIMER6, 16000 - 1);
    hpm_timer_set_autoreload(HPM_TIMER6, 1 - 1);
    hpm_timer_enable_irq(HPM_TIMER6, HPM_TIMER_IRQ_UPDATE);

    // 启动 DMA
    hpm_dma_start_channel(HPMDMA_CHANNEL1);
}

void adc_start_conversion(void)
{
    // 手动触发 ADC 转换
    hpm_adc_start_conversion(HPM_ADC0);

    // 等待转换完成
    while (!dma_complete);

    // 清空 DMA 完成标志位
    dma_complete = 0;
}

void timer6_irq_handler(void)
{
    // 定时器中断处理函数, 每隔1ms触发一次ADC采集
    adc_start_conversion();

    // 清除定时器中断标志位
    hpm_timer_clear_irq(HPM_TIMER6, HPM_TIMER_IRQ_UPDATE);
}

int main(void)
{
    adc_init();

    while (1);

    return 0;
}
```
举报

更多回帖

发帖
×
20
完善资料,
赚取积分