硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1037|回复: 6
收起左侧

[ADC] stmh743 adc 连续转换 和 软件单次采集值相差较大是怎么回事

[复制链接]

1

主题

6

回帖

9

积分

新手上路

积分
9
发表于 2024-10-29 17:42:38 | 显示全部楼层 |阅读模式
1、自动连续采集 dma多通道


static FunctionalState bContinueConvert = ENABLE;



/*******************************************************************************
* 函数名  : Bsp_Adc1Init
* 描  述  : ADC1采样初始化
* 输  入  : 无
* 输  出  : 无
* 返回值  : OSA_SOK   : 成功
*         OSA_EFAIL: 失败
*******************************************************************************/
Int32 Bsp_Adc1Init(void)
{
        ADC_ChannelConfTypeDef                  sConfig = {0};
       
        __HAL_RCC_ADC12_CLK_ENABLE();
        /* ADC Periph interface clock configuration */
        __HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP);
       
        s_adc1Handle.Instance                        = ADC1;
        if (HAL_ADC_DeInit(&s_adc1Handle) != HAL_OK)
        {
          /* ADC de-initialization Error */
                printf("Adc1Init DeInit error!!!\r\n");
        }
       
        memset((void*)&s_ADC1ConvertedData[0],0xff,sizeof(s_ADC1ConvertedData));
        if (s_ValidAdc1ChnNum <= 0)
        {
                printf("Adc1Init adc chn no config error!!!\r\n");
            return OSA_EFAIL;
        }
       
        __HAL_RCC_DMA1_CLK_ENABLE();
        s_hdma_adc1.Instance = DMA1_Stream1;
        s_hdma_adc1.Init.Request = DMA_REQUEST_ADC1;
        s_hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
        s_hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
        s_hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
        s_hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
        s_hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
        //连续转换模式需要开启循环模式
        if (ENABLE == bContinueConvert)
        {
                s_hdma_adc1.Init.Mode = DMA_CIRCULAR;
        }
        else
        {
                s_hdma_adc1.Init.Mode = DMA_NORMAL;
        }
        s_hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
        s_hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        /* Deinitialize  & Initialize the DMA for new transfer */
        HAL_DMA_DeInit(&s_hdma_adc1);
        if (HAL_DMA_Init(&s_hdma_adc1)!= HAL_OK)
        {
                printf("Adc1Init adc DMA init error!!!\r\n");
                return OSA_EFAIL;
        }
        __HAL_LINKDMA(&s_adc1Handle,DMA_Handle,s_hdma_adc1);
        /* NVIC configuration for DMA Input data interrupt */
        HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 1, 0);
        HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
       
        s_adc1Handle.Init.ClockPrescaler           = ADC_CLOCK_ASYNC_DIV4;        /* Asynchronous clock mode, input ADC clock divided by 2*/
        s_adc1Handle.Init.Resolution               = ADC_RESOLUTION_12B;            /* 16-bit resolution for converted data */
        s_adc1Handle.Init.ScanConvMode             = ENABLE;                       /* Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) */
        s_adc1Handle.Init.EOCSelection             = ADC_EOC_SINGLE_CONV;           /* EOC flag picked-up to indicate conversion end */
        s_adc1Handle.Init.LowPowerAutoWait         = DISABLE;                       /* Auto-delayed conversion feature disabled */
        s_adc1Handle.Init.ContinuousConvMode       = bContinueConvert;              /* Continuous mode enabled (automatic conversion restart after each conversion) */
        s_adc1Handle.Init.NbrOfConversion          = s_ValidAdc1ChnNum;             /* Parameter discarded because sequencer is disabled */
        s_adc1Handle.Init.DiscontinuousConvMode    = DISABLE;                       /* Parameter discarded because sequencer is disabled */
        s_adc1Handle.Init.NbrOfDiscConversion      = s_ValidAdc1ChnNum;             /* Parameter discarded because sequencer is disabled */
        s_adc1Handle.Init.ExternalTrigConv         = ADC_SOFTWARE_START;            /* Software start to trig the 1st conversion manually, without external event */
        s_adc1Handle.Init.ExternalTrigConvEdge     = ADC_EXTERNALTRIGCONVEDGE_NONE; /* Parameter discarded because software trigger chosen */
        if (ENABLE == bContinueConvert)
        {
                s_adc1Handle.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR; /* DMA circular mode selected */
        }
        else
        {
                s_adc1Handle.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_ONESHOT; /* DMA one shot mode selected */
        }
        s_adc1Handle.Init.Overrun                  = ADC_OVR_DATA_OVERWRITTEN;      /* DR register is overwritten with the last conversion result in case of overrun */
        s_adc1Handle.Init.OversamplingMode         = DISABLE;                       /* No oversampling */

        /* Initialize ADC peripheral according to the passed parameters */
        if (HAL_ADC_Init(&s_adc1Handle) != HAL_OK)
        {
                printf("Adc1Init error!!!\r\n");
                return OSA_EFAIL;
        }
       
        /* ### - 2 - Start calibration ############################################ */
        if (HAL_ADCEx_Calibration_Start(&s_adc1Handle, ADC_CALIB_OFFSET_LINEARITY, ADC_SINGLE_ENDED) != HAL_OK)
        {
                printf("Adc1Init Calibration error!!!\r\n");
        }
       
        /* ### - 3 - Channel configuration ######################################## */
        for (Int32 chn = 0; chn < BSP_ADC_MAX_CHN && chn < s_ValidAdc1ChnNum; chn++)
        {
                if (s_LogicMapAdc1Chn[chn] == 0xFFFFFFFF)
                {
                        continue;
                }
               
                sConfig.Channel      = s_LogicMapAdc1Chn[chn];       /* Sampled channel number */
                sConfig.Rank         = s_LogicMapAdc1RankNo[chn];    /* Rank of sampled channel number ADCx_CHANNEL */
                sConfig.SamplingTime = ADC_SAMPLETIME_64CYCLES_5;   /* Sampling time (number of clock cycles unit) */
                sConfig.SingleDiff   = ADC_SINGLE_ENDED;            /* Single-ended input channel */
                sConfig.OffsetNumber = ADC_OFFSET_NONE;             /* No offset subtraction */
                sConfig.Offset = 0;                                 /* Parameter discarded because offset correction is disabled */
               
                if (HAL_ADC_ConfigChannel(&s_adc1Handle, &sConfig) != HAL_OK)
                {
                        printf("Adc1Init Calibration logicchn:%d,adcChn:%d,error!!!\r\n",chn,s_LogicMapAdc1Chn[chn]);
                }
        }
       
    //使能ADC1
    ADC_Enable(&s_adc1Handle);
        if (ENABLE == bContinueConvert)
        {
                HAL_ADC_Start_DMA(&s_adc1Handle, (Uint32 *)s_ADC1ConvertedData, s_ValidAdc1ChnNum);
        }
        printf("Adc1Init ChnNum=%d ok!!!\r\n",s_ValidAdc1ChnNum);
       
    return OSA_SOK;
}

采集的值

[16_35_07_982]adc1 chn0 adcVaule:00072,0.052368 V
[16_35_07_993]adc1 chn1 adcVaule:00078,0.057202 V
[16_35_07_993]adc1 chn2 adcVaule:00133,0.097485 V
[16_35_07_993]adc1 chn3 adcVaule:00004,0.000000 V


2、单次采集 dma 多通道
static FunctionalState bContinueConvert = DISABLE;


/*******************************************************************************
* 函数名  : Bsp_Adc1Init
* 描  述  : ADC1采样初始化
* 输  入  : 无
* 输  出  : 无
* 返回值  : OSA_SOK   : 成功
*         OSA_EFAIL: 失败
*******************************************************************************/
Int32 Bsp_Adc1Init(void)
{
        ADC_ChannelConfTypeDef                  sConfig = {0};
       
        __HAL_RCC_ADC12_CLK_ENABLE();
        /* ADC Periph interface clock configuration */
        __HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP);
       
        s_adc1Handle.Instance                        = ADC1;
        if (HAL_ADC_DeInit(&s_adc1Handle) != HAL_OK)
        {
          /* ADC de-initialization Error */
                printf("Adc1Init DeInit error!!!\r\n");
        }
       
        memset((void*)&s_ADC1ConvertedData[0],0xff,sizeof(s_ADC1ConvertedData));
        if (s_ValidAdc1ChnNum <= 0)
        {
                printf("Adc1Init adc chn no config error!!!\r\n");
            return OSA_EFAIL;
        }
       
        __HAL_RCC_DMA1_CLK_ENABLE();
        s_hdma_adc1.Instance = DMA1_Stream1;
        s_hdma_adc1.Init.Request = DMA_REQUEST_ADC1;
        s_hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
        s_hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
        s_hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
        s_hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
        s_hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
        //连续转换模式需要开启循环模式
        if (ENABLE == bContinueConvert)
        {
                s_hdma_adc1.Init.Mode = DMA_CIRCULAR;
        }
        else
        {
                s_hdma_adc1.Init.Mode = DMA_NORMAL;
        }
        s_hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
        s_hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        /* Deinitialize  & Initialize the DMA for new transfer */
        HAL_DMA_DeInit(&s_hdma_adc1);
        if (HAL_DMA_Init(&s_hdma_adc1)!= HAL_OK)
        {
                printf("Adc1Init adc DMA init error!!!\r\n");
                return OSA_EFAIL;
        }
        __HAL_LINKDMA(&s_adc1Handle,DMA_Handle,s_hdma_adc1);
        /* NVIC configuration for DMA Input data interrupt */
        HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 1, 0);
        HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
       
        s_adc1Handle.Init.ClockPrescaler           = ADC_CLOCK_ASYNC_DIV4;        /* Asynchronous clock mode, input ADC clock divided by 2*/
        s_adc1Handle.Init.Resolution               = ADC_RESOLUTION_12B;            /* 16-bit resolution for converted data */
        s_adc1Handle.Init.ScanConvMode             = ENABLE;                       /* Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) */
        s_adc1Handle.Init.EOCSelection             = ADC_EOC_SINGLE_CONV;           /* EOC flag picked-up to indicate conversion end */
        s_adc1Handle.Init.LowPowerAutoWait         = DISABLE;                       /* Auto-delayed conversion feature disabled */
        s_adc1Handle.Init.ContinuousConvMode       = bContinueConvert;              /* Continuous mode enabled (automatic conversion restart after each conversion) */
        s_adc1Handle.Init.NbrOfConversion          = s_ValidAdc1ChnNum;             /* Parameter discarded because sequencer is disabled */
        s_adc1Handle.Init.DiscontinuousConvMode    = DISABLE;                       /* Parameter discarded because sequencer is disabled */
        s_adc1Handle.Init.NbrOfDiscConversion      = s_ValidAdc1ChnNum;             /* Parameter discarded because sequencer is disabled */
        s_adc1Handle.Init.ExternalTrigConv         = ADC_SOFTWARE_START;            /* Software start to trig the 1st conversion manually, without external event */
        s_adc1Handle.Init.ExternalTrigConvEdge     = ADC_EXTERNALTRIGCONVEDGE_NONE; /* Parameter discarded because software trigger chosen */
        if (ENABLE == bContinueConvert)
        {
                s_adc1Handle.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR; /* DMA circular mode selected */
        }
        else
        {
                s_adc1Handle.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_ONESHOT; /* DMA one shot mode selected */
        }
        s_adc1Handle.Init.Overrun                  = ADC_OVR_DATA_OVERWRITTEN;      /* DR register is overwritten with the last conversion result in case of overrun */
        s_adc1Handle.Init.OversamplingMode         = DISABLE;                       /* No oversampling */

        /* Initialize ADC peripheral according to the passed parameters */
        if (HAL_ADC_Init(&s_adc1Handle) != HAL_OK)
        {
                printf("Adc1Init error!!!\r\n");
                return OSA_EFAIL;
        }
       
        /* ### - 2 - Start calibration ############################################ */
        if (HAL_ADCEx_Calibration_Start(&s_adc1Handle, ADC_CALIB_OFFSET_LINEARITY, ADC_SINGLE_ENDED) != HAL_OK)
        {
                printf("Adc1Init Calibration error!!!\r\n");
        }
       
        /* ### - 3 - Channel configuration ######################################## */
        for (Int32 chn = 0; chn < BSP_ADC_MAX_CHN && chn < s_ValidAdc1ChnNum; chn++)
        {
                if (s_LogicMapAdc1Chn[chn] == 0xFFFFFFFF)
                {
                        continue;
                }
               
                sConfig.Channel      = s_LogicMapAdc1Chn[chn];       /* Sampled channel number */
                sConfig.Rank         = s_LogicMapAdc1RankNo[chn];    /* Rank of sampled channel number ADCx_CHANNEL */
                sConfig.SamplingTime = ADC_SAMPLETIME_64CYCLES_5;   /* Sampling time (number of clock cycles unit) */
                sConfig.SingleDiff   = ADC_SINGLE_ENDED;            /* Single-ended input channel */
                sConfig.OffsetNumber = ADC_OFFSET_NONE;             /* No offset subtraction */
                sConfig.Offset = 0;                                 /* Parameter discarded because offset correction is disabled */
               
                if (HAL_ADC_ConfigChannel(&s_adc1Handle, &sConfig) != HAL_OK)
                {
                        printf("Adc1Init Calibration logicchn:%d,adcChn:%d,error!!!\r\n",chn,s_LogicMapAdc1Chn[chn]);
                }
        }
       
    //使能ADC1
    ADC_Enable(&s_adc1Handle);
        if (ENABLE == bContinueConvert)
        {
                HAL_ADC_Start_DMA(&s_adc1Handle, (Uint32 *)s_ADC1ConvertedData, s_ValidAdc1ChnNum);
        }
        printf("Adc1Init ChnNum=%d ok!!!\r\n",s_ValidAdc1ChnNum);
       
    return OSA_SOK;
}

任务重 1秒执行一次 转换

/*******************************************************************************
* 函数名  : Bsp_Adc1StartConvert
* 描  述  : ADC1 转化 (软件手动执行转换)
* 输  入  : 无
* 输  出  : 无
* 返回值  : OSA_SOK   : 成功
*         OSA_EFAIL: 失败
*******************************************************************************/
Int32 Bsp_Adc1StartConvert(void)
{
        HAL_StatusTypeDef tmp_hal_status = HAL_OK;
        static Int32 convertFlag = 0;

        if (s_ValidAdc1ChnNum <= 0)
        {
                printf("Adc1 no Init!!!\r\n");
            return OSA_EFAIL;
        }
       
        /*自动连续模式 直接退出*/
        if (ENABLE == bContinueConvert)
        {
            return OSA_SOK;
        }
       
        Bsp_Adc1DebugInfo();
       
        //软件触发ADC采样
        tmp_hal_status = HAL_ADC_Start_DMA(&s_adc1Handle, (Uint32 *)s_ADC1ConvertedData, s_ValidAdc1ChnNum);
       
        printf("Adc1 Convert ret=%d!!!\r\n",tmp_hal_status);
       
    return OSA_SOK;
}

转换结果

[16_32_08_201]adc1 chn0 adcVaule:00355,0.286011 V
[16_32_08_201]adc1 chn1 adcVaule:00352,0.283594 V
[16_32_08_212]adc1 chn2 adcVaule:00820,0.660645 V
[16_32_08_212]adc1 chn3 adcVaule:00000,0.000000 V


两种方式的结果 差别比较大  不知道为什么?
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117546
QQ
发表于 2024-10-30 09:58:01 | 显示全部楼层
对比了下
[16_35_07_982]adc1 chn0 adcVaule:00072,0.052368 V
[16_35_07_993]adc1 chn1 adcVaule:00078,0.057202 V
[16_35_07_993]adc1 chn2 adcVaule:00133,0.097485 V
[16_35_07_993]adc1 chn3 adcVaule:00004,0.000000 V

[16_32_08_201]adc1 chn0 adcVaule:00355,0.286011 V
[16_32_08_201]adc1 chn1 adcVaule:00352,0.283594 V
[16_32_08_212]adc1 chn2 adcVaule:00820,0.660645 V
[16_32_08_212]adc1 chn3 adcVaule:00000,0.000000 V

这两组区别太大了,是不是ADC DMA所使用缓冲的MPU/Cache没有配置。
回复

使用道具 举报

1

主题

6

回帖

9

积分

新手上路

积分
9
 楼主| 发表于 2025-1-13 17:08:23 | 显示全部楼层
eric2013 发表于 2024-10-30 09:58
对比了下
[16_35_07_982]adc1 chn0 adcVaule:00072,0.052368 V
[16_35_07_993]adc1 chn1 adcVaule:00078, ...

开启cahe了,但是 不清楚为什么,adc的pin脚 没有接 是悬空的
回复

使用道具 举报

1

主题

6

回帖

9

积分

新手上路

积分
9
 楼主| 发表于 2025-1-13 17:10:51 | 显示全部楼层
eric2013 发表于 2024-10-30 09:58
对比了下
[16_35_07_982]adc1 chn0 adcVaule:00072,0.052368 V
[16_35_07_993]adc1 chn1 adcVaule:00078, ...

感谢  回复;h7 cahe 挺难搞的
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117546
QQ
发表于 2025-1-14 10:59:31 | 显示全部楼层
ljl391137 发表于 2025-1-13 17:10
感谢  回复;h7 cahe 挺难搞的

测试阶段,可以先SCB_DisableDCache
回复

使用道具 举报

7

主题

24

回帖

50

积分

初级会员

积分
50
发表于 2025-1-15 09:50:41 | 显示全部楼层
ljl391137 发表于 2025-1-13 17:08
开启cahe了,但是 不清楚为什么,adc的pin脚 没有接 是悬空的

悬空不行,ADC输入是高阻态,上面感应到噪声。接上确定的电压再试试
回复

使用道具 举报

4

主题

100

回帖

112

积分

初级会员

积分
112
发表于 2025-1-15 10:38:25 | 显示全部楼层
regsofweb 发表于 2025-1-15 09:50
悬空不行,ADC输入是高阻态,上面感应到噪声。接上确定的电压再试试

是的,不能悬空,悬空的话会对隔壁通道有影响,不用的接地就行了,要不不配置
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-8-14 06:33 , Processed in 0.040407 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表