ADC on H7

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderators: barthess, RoccoMarco

hybridA
Posts: 40
Joined: Wed Jan 12, 2022 7:15 am
Has thanked: 10 times
Been thanked: 5 times

ADC on H7

Postby hybridA » Sat Mar 01, 2025 4:31 am

I need all 3 ADCs (ADC1, ADC2 and ADC3) for new project.
Currently, I can really only ADC1 work reliably. Once I switch to dual mode (for ADC2) I'm getting garbage data in my buffer. Switching to dual mode also messes with ADC3 readings.
I'm trying to read a total of 13 channels:
ADC1: 4 channels
ADC2: 2 channels
ADC3: 7 channels

Code: Select all

#if CACHE_LINE_SIZE > 0
CC_ALIGN_DATA(CACHE_LINE_SIZE)
#endif
CC_SECTION(".nocache") adcsample_t adcBuffer[ADC12_GRP_NUM_CHANNELS * ADC_OVERSAMPLE];

// ADC3 uses BDMA, which only has RAM4 access
CC_SECTION(".ram4_clear") adcsample_t adc3Buffer[CACHE_SIZE_ALIGN(adcsample_t, ADC3_GRP_NUM_CHANNELS * ADC_OVERSAMPLE)];

const ADCConfig adccfg = {.difsel = 0U, .calibration = 0U};

static constexpr ADCConversionGroup adc12grpcfg = {
      .circular = false,
      .num_channels = ADC12_GRP_NUM_CHANNELS,
      .end_cb = nullptr,
      .error_cb = nullptr,
      .cfgr = ADC_CFGR_CONT,
      .cfgr2 = 0U,
      .ccr = ADC_CCR_DUAL_REG_INTERL,
      .pcsel = ADC_SELMASK_IN2 | ADC_SELMASK_IN3 | ADC_SELMASK_IN5 | ADC_SELMASK_IN6 | ADC_SELMASK_IN9 | ADC_SELMASK_IN15,
      .ltr1 = 0U,
      .htr1 = 0U,
      .ltr2 = 0U,
      .htr2 = 0U,
      .ltr3 = 0U,
      .htr3 = 0U,
      .awd2cr = 0U,
      .awd3cr = 0U,
      .smpr = {   ADC_SMPR1_SMP_AN3(ADC_SMPR_SMP_32P5) | ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_32P5) |
                ADC_SMPR1_SMP_AN9(ADC_SMPR_SMP_32P5),
                ADC_SMPR2_SMP_AN15(ADC_SMPR_SMP_32P5)},
      .sqr = {    ADC_SQR1_SQ1_N(ADC_CHANNEL_IN3) | ADC_SQR1_SQ2_N(ADC_CHANNEL_IN5) |
               ADC_SQR1_SQ3_N(ADC_CHANNEL_IN9) | ADC_SQR1_SQ4_N(ADC_CHANNEL_IN15),
               0U,
               0U,
               0U},
      .ssmpr = {   ADC_SMPR1_SMP_AN2(ADC_SMPR_SMP_32P5) | ADC_SMPR1_SMP_AN6(ADC_SMPR_SMP_32P5),
               0U},
      .ssqr = {   ADC_SQR1_SQ1_N(ADC_CHANNEL_IN2) | ADC_SQR1_SQ2_N(ADC_CHANNEL_IN6),
               0U,
               0U,
               0U}
};

static const ADCConversionGroup adc3grpcfg = {
      .circular = false,
      .num_channels = ADC3_GRP_NUM_CHANNELS,
      .end_cb = nullptr,
      .error_cb = nullptr,
      .cfgr = ADC_CFGR_CONT,
      .cfgr2 = 0U,
      .ccr = ADC_CCR_DUAL_INDEPENDENT,
      .pcsel = ADC_SELMASK_IN0 | ADC_SELMASK_IN3 | ADC_SELMASK_IN4 | ADC_SELMASK_IN5 | ADC_SELMASK_IN6 | ADC_SELMASK_IN8 |
                   ADC_SELMASK_IN9,
      .ltr1 = 0U,
      .htr1 = 0U,
      .ltr2 = 0U,
      .htr2 = 0U,
      .ltr3 = 0U,
      .htr3 = 0U,
      .awd2cr = 0U,
      .awd3cr = 0U,
      .smpr = { ADC_SMPR1_SMP_AN0(ADC_SMPR_SMP_810P5) | ADC_SMPR1_SMP_AN3(ADC_SMPR_SMP_810P5) |
              ADC_SMPR1_SMP_AN4(ADC_SMPR_SMP_810P5) | ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_810P5) |
              ADC_SMPR1_SMP_AN6(ADC_SMPR_SMP_810P5) | ADC_SMPR1_SMP_AN8(ADC_SMPR_SMP_810P5) |
              ADC_SMPR1_SMP_AN9(ADC_SMPR_SMP_810P5),
              0U},
      .sqr =   { ADC_SQR1_SQ1_N(ADC_CHANNEL_IN0) | ADC_SQR1_SQ2_N(ADC_CHANNEL_IN3) | ADC_SQR1_SQ3_N(ADC_CHANNEL_IN4) |
              ADC_SQR1_SQ4_N(ADC_CHANNEL_IN5),
              ADC_SQR2_SQ5_N(ADC_CHANNEL_IN6) | ADC_SQR2_SQ6_N(ADC_CHANNEL_IN8) | ADC_SQR2_SQ7_N(ADC_CHANNEL_IN9),
              0U,
              0U},
      .ssmpr = {0U, 0U},
      .ssqr =  {0U, 0U, 0U, 0U}
};


mcuconf.h:

Code: Select all

/*
 * ADC driver system settings.
 */
#define STM32_ADC_DUAL_MODE                 TRUE
#define STM32_ADC_SAMPLES_SIZE              32
#define STM32_ADC_USE_ADC12                 TRUE
#define STM32_ADC_ADC12_DMA_STREAM          STM32_DMA_STREAM_ID_ANY
#define STM32_ADC_ADC12_DMA_PRIORITY        2
#define STM32_ADC_ADC12_IRQ_PRIORITY        5
#define STM32_ADC_ADC12_CLOCK_MODE          ADC_CCR_CKMODE_ADCCK
#define STM32_ADC_USE_ADC3                  TRUE
#define STM32_ADC_ADC3_BDMA_STREAM          STM32_BDMA_STREAM_ID_ANY
#define STM32_ADC_ADC3_BDMA_PRIORITY        2
#define STM32_ADC_ADC3_IRQ_PRIORITY         5
#define STM32_ADC_ADC3_CLOCK_MODE           ADC_CCR_CKMODE_ADCCK


Doing this in a loop at around 500hz:

Code: Select all

adcConvert(&ADCD1, &adc12grpcfg, adcBuffer, ADC_OVERSAMPLE);
adcConvert(&ADCD3, &adc3grpcfg, adc3Buffer, ADC_OVERSAMPLE);
cacheBufferInvalidate(adc3Buffer, sizeof (adc3Buffer) / sizeof (adcsample_t));

User avatar
Giovanni
Site Admin
Posts: 14584
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1118 times
Been thanked: 938 times

Re: ADC on H7

Postby Giovanni » Sat Mar 01, 2025 6:24 am

Hi,

Are you sure this is not cache-related? try to disable cache globally and see if you get the same problems.

Giovanni

hybridA
Posts: 40
Joined: Wed Jan 12, 2022 7:15 am
Has thanked: 10 times
Been thanked: 5 times

Re: ADC on H7

Postby hybridA » Sat Mar 01, 2025 6:55 am

Getting the same results by disabling cache with

Code: Select all

SCB_DisableICache();
SCB_DisableDCache();


The ADC3 readings appear all to be garbage, first 42-entries in the buffer are all number much larger than 12-bit. rest is all zeros.

When I change the sampling depth to 1, I can see that all the ADC1 readings in the ADC1/2 buffer are correct, but all ADC2 values are garbage and much larger than 16-bit.

hybridA
Posts: 40
Joined: Wed Jan 12, 2022 7:15 am
Has thanked: 10 times
Been thanked: 5 times

Re: ADC on H7

Postby hybridA » Sun Mar 02, 2025 9:19 pm

Some additional test results:

ADC12
For testing, I changed oversampling to 1, just to make reading the buffer a little easier during debugging.
Goal is to read from these pins:

Code: Select all

ADC12_INP3    PA6
ADC12_INP5    PB1
ADC12_INP9    PB0
ADC12_INP15   PA3
ADC2_INP2     PF13
ADC2_INP6     PF14


ADCConfig:

Code: Select all

static constexpr ADCConversionGroup adc12grpcfg = {
   .circular = false,
   .num_channels = ADC12_GRP_NUM_CHANNELS,
   .end_cb = nullptr,
   .error_cb = nullptr,
   .cfgr = ADC_CFGR_CONT,
   .cfgr2 = 0U,
   .ccr = ADC_CCR_DUAL_REG_INTERL,
   .pcsel = ADC_SELMASK_IN2 | ADC_SELMASK_IN3 | ADC_SELMASK_IN5 | ADC_SELMASK_IN6 | ADC_SELMASK_IN9 | ADC_SELMASK_IN15,
   .ltr1 = 0U,
   .htr1 = 0U,
   .ltr2 = 0U,
   .htr2 = 0U,
   .ltr3 = 0U,
   .htr3 = 0U,
   .awd2cr = 0U,
   .awd3cr = 0U,
   .smpr = {   ADC_SMPR1_SMP_AN3(ADC_SMPR_SMP_32P5) | ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_32P5) |
           ADC_SMPR1_SMP_AN9(ADC_SMPR_SMP_32P5),
           ADC_SMPR2_SMP_AN15(ADC_SMPR_SMP_32P5)},
   .sqr = {    ADC_SQR1_SQ1_N(ADC_CHANNEL_IN3) | ADC_SQR1_SQ2_N(ADC_CHANNEL_IN5) |
          ADC_SQR1_SQ3_N(ADC_CHANNEL_IN9) | ADC_SQR1_SQ4_N(ADC_CHANNEL_IN15),
          0U,
          0U,
          0U},
   .ssmpr = {   ADC_SMPR1_SMP_AN2(ADC_SMPR_SMP_32P5) | ADC_SMPR1_SMP_AN6(ADC_SMPR_SMP_32P5),
          0U},
   .ssqr = {   ADC_SQR1_SQ1_N(ADC_CHANNEL_IN2) | ADC_SQR1_SQ2_N(ADC_CHANNEL_IN6),
          0U,
          0U,
          0U}
};


Applying test-signal (0-3V3) to pin PF13 which should be adcBuffer[0], but doesn't change the value in array at all.
However, applying voltage to pin PA6 does change adcBuffer[0] and it goes full scale 0-16-bit with 0-3V3 input.
I'm also noticing adcBuffer[3] and adcBuffer[4] at a very high number [3] = 0xc1000000 and [4] = 0x2400121c which never changes. adcBuffer[5] is static at 0.

When turning off dual mode in mcuconf.h
#define STM32_ADC_DUAL_MODE FALSE

and using this ADCConfig:

Code: Select all

static constexpr ADCConversionGroup adc12grpcfg = {
      .circular = false,
      .num_channels = ADC12_GRP_NUM_CHANNELS,
      .end_cb = nullptr,
      .error_cb = nullptr,
      .cfgr = ADC_CFGR_CONT,
      .cfgr2 = 0U,
      .ccr = 0U,
      .pcsel = ADC_SELMASK_IN2 | ADC_SELMASK_IN3 | ADC_SELMASK_IN5 | ADC_SELMASK_IN6 | ADC_SELMASK_IN9 | ADC_SELMASK_IN15,
      .ltr1 = 0U,
      .htr1 = 0U,
      .ltr2 = 0U,
      .htr2 = 0U,
      .ltr3 = 0U,
      .htr3 = 0U,
      .awd2cr = 0U,
      .awd3cr = 0U,
      .smpr = {ADC_SMPR1_SMP_AN2(ADC_SMPR_SMP_32P5) | ADC_SMPR1_SMP_AN3(ADC_SMPR_SMP_32P5) | ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_32P5) |
             ADC_SMPR1_SMP_AN6(ADC_SMPR_SMP_32P5) | ADC_SMPR1_SMP_AN9(ADC_SMPR_SMP_32P5),
             ADC_SMPR2_SMP_AN15(ADC_SMPR_SMP_32P5)},
      .sqr = {ADC_SQR1_SQ1_N(ADC_CHANNEL_IN2) | ADC_SQR1_SQ2_N(ADC_CHANNEL_IN3) |
            ADC_SQR1_SQ3_N(ADC_CHANNEL_IN5) | ADC_SQR1_SQ4_N(ADC_CHANNEL_IN6),
            ADC_SQR2_SQ5_N(ADC_CHANNEL_IN9) | ADC_SQR2_SQ6_N(ADC_CHANNEL_IN15),
            0U,
            0U},
};


All ADC1 inputs are read in correctly, even at oversampling of 12.


ADC3
ADC3 works fine, but only if using oversampling of 1, e.g.

Code: Select all

adcConvert(&ADCD3, &adc3grpcfg, adc3Buffer, 1);


Does dual mode need to be explicitly turned off for ADC3?
if enabled via mcuconf.h, all readings on ADC3 are garbage, even without any oversampling.


Return to “STM32 Support”

Who is online

Users browsing this forum: No registered users and 12 guests