cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H745 ADC and DMA

jgauthier
Senior

I have read quite a few posts, reference, and KBs trying to get this to work - but I'm stuck.

Challenge: Trying to get STM32H745 working with ADC1 (and eventually ADC3) with DMA.

What I am experiencing: All my results are coming back as "65535" (even when there is not a 3.3V on the input)

What I've done/read:

I've referred to this KB quite a bit:

https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices

So I have an understanding of some of the challenges. I am using "Solution example 3: Use Cache maintenance functions" as my guide. However, it's unclear to me if I need to make an effort to move the memory locations as in "Solution example 1" and "Solution example 2".

Relevant code:

main.c

/* MPU Configuration--------------------------------------------------------*/
  MPU_Config();
 
  /* Enable I-Cache---------------------------------------------------------*/
  SCB_EnableICache();
 
  /* Enable D-Cache---------------------------------------------------------*/
  SCB_EnableDCache();

And further:

MX_GPIO_Init();
  MX_ADC1_Init();
  MX_ADC3_Init();
  MX_BDMA_Init();
  MX_DMA_Init();
  MX_FDCAN1_Init();
  MX_FDCAN2_Init();
  MX_USART3_UART_Init();

ADC:

hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  hadc1.Init.Resolution = ADC_RESOLUTION_16B;
  hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.NbrOfConversion = 4;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
 
[ channels are configured ]
  sConfig.Channel = ADC_CHANNEL_7;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  sConfig.OffsetSignedSaturation = DISABLE;
 
[DMA is configured]
 
    hdma_adc1.Instance = DMA1_Stream0;
    hdma_adc1.Init.Request = DMA_REQUEST_ADC1;
    hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
    hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_adc1.Init.Mode = DMA_CIRCULAR;
    hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
    hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
    {
      Error_Handler();
    }
 
    __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);
 
    /* ADC1 interrupt Init */
    HAL_NVIC_SetPriority(ADC_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(ADC_IRQn);

User code:

#define ADC1_CONVERTED_DATA_BUFFER_SIZE   ((uint32_t)  32)   /* Size of array aADCxConvertedData[] */
#define ADC3_CONVERTED_DATA_BUFFER_SIZE   ((uint32_t)  32)   /* Size of array aADCxConvertedData[] */
 
ALIGN_32BYTES (static uint16_t   aADC1ConvertedData[ADC1_CONVERTED_DATA_BUFFER_SIZE]);
ALIGN_32BYTES (static uint16_t   aADC3ConvertedData[ADC3_CONVERTED_DATA_BUFFER_SIZE]);
 
void calibrate_adc() {
 
  if (HAL_ADCEx_LinearCalibration_FactorLoad(&hadc1) != HAL_OK) {
    serprintf("Could not load linear calibration for adc1.");
  }
 
  if (HAL_ADCEx_LinearCalibration_FactorLoad(&hadc3) != HAL_OK) {
    serprintf("Could not load linear calibration for adc3.");
  }
 
  /* Run the ADC calibration in single-ended mode */
  if (HAL_ADCEx_Calibration_Start(&hadc1, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED) != HAL_OK) {
    /* Calibration Error */
    serprintf("ADC1 calibration error.");
    Error_Handler();
  }
  HAL_Delay(50);
  /* Run the ADC calibration in single-ended mode */
  if (HAL_ADCEx_Calibration_Start(&hadc3, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED) != HAL_OK) {
    /* Calibration Error */
    serprintf("ADC3 calibration error.");
    Error_Handler();
  }
  HAL_Delay(50);
 
  HAL_ADC_Start_DMA(&hadc1, (uint32_t*) aADC1ConvertedData, ADC1_CONVERTED_DATA_BUFFER_SIZE);
  //HAL_ADC_Start_DMA(&hadc3, (uint32_t*) aADC3ConvertedData, ADC3_CONVERTED_DATA_BUFFER_SIZE);
 
}
 
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
{
  /* Invalidate Data Cache to get the updated content of the SRAM on the first half of the ADC converted data buffer: 32 bytes */
  SCB_InvalidateDCache_by_Addr((uint32_t*)((uint32_t)aADC1ConvertedData), ADC1_CONVERTED_DATA_BUFFER_SIZE);
  SCB_InvalidateDCache_by_Addr((uint32_t*)((uint32_t)aADC3ConvertedData), ADC3_CONVERTED_DATA_BUFFER_SIZE);
 
}
 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
   /* Invalidate Data Cache to get the updated content of the SRAM on the second half of the ADC converted data buffer: 32 bytes */
  SCB_InvalidateDCache_by_Addr((uint32_t*)((uint32_t)aADC1ConvertedData), ADC1_CONVERTED_DATA_BUFFER_SIZE);
  SCB_InvalidateDCache_by_Addr((uint32_t*)((uint32_t)aADC3ConvertedData), ADC3_CONVERTED_DATA_BUFFER_SIZE);   
 
}

Linker script:

MEMORY
{
  RAM_D1 (xrw)   : ORIGIN = 0x24000000, LENGTH =  512K
  FLASH  (rx)    : ORIGIN = 0x08000000, LENGTH = 1024K    /* Memory is divided. Actual start is 0x08000000 and actual length is 2048K */
  DTCMRAM (xrw)  : ORIGIN = 0x20000000, LENGTH = 128K
  RAM_D2 (xrw)   : ORIGIN = 0x30000000, LENGTH = 288K
  RAM_D3 (xrw)   : ORIGIN = 0x38000000, LENGTH = 64K
  ITCMRAM (xrw)  : ORIGIN = 0x00000000, LENGTH = 64K
}

1 ACCEPTED SOLUTION

Accepted Solutions
jgauthier
Senior

Wanted to come back and indicate I solved this. This is a custom board and the designer used an analog reference IC (MCP1501) and I discovered that the shutdown pin was wired incorrectly, thus shutting it down.

View solution in original post

3 REPLIES 3
Foued_KH
ST Employee

Hello @Community member​ ,

When DMA is used, the MX_DMA_Init shall always be called before any other HAL_***_Init (where *** is any peripheral with a HW dependency on DMA init code).

So try to initiate DMA before the ADC :

MX_GPIO_Init();
 
MX_DMA_Init();
MX_BDMA_Init();
 
MX_ADC1_Init();
MX_ADC3_Init();
MX_FDCAN1_Init();
MX_FDCAN2_Init();
MX_USART3_UART_Init();

Foued

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

The code was generated by CubeMX, and I have read about the problem where they are initialized in the wrong order. I have manually swapped them but the problem still exists.

jgauthier
Senior

Wanted to come back and indicate I solved this. This is a custom board and the designer used an analog reference IC (MCP1501) and I discovered that the shutdown pin was wired incorrectly, thus shutting it down.