cancel
Showing results for 
Search instead for 
Did you mean: 

DMA issues ADC on stm32H743

JColl.5
Associate II

Im having some problems getting DMA to work, none of the interrupt routines are called, Simplified code below, hints appreciated

ADC_HandleTypeDef hadc1;

DMA_HandleTypeDef hdma_adc1;

static uint32_t HAL_RCC_ADC12_CLK_ENABLED = 0;

boolean ADC1_done = false;

uint16_t ADC1ConvertedValue[10240];

void setup() {

 Serial.begin(115200);

 Serial.println("start");

   SCB_DisableICache();

 SCB_DisableDCache();

 HAL_Init();

 Stm32_Clock_Init(120, 1, 2, 2);

 MX_DMA_Init();

 MX_ADC1_Init();

 MY_HAL_ADC_MspInit(&hadc1);

 HAL_ADC_Start_DMA(&hadc1,

          (uint32_t *)ADC1ConvertedValue,

          1024

          );

}

void loop() {

 if (ADC1_done) {

  Serial.println("adc done");

  ADC1_done = false;

  HAL_ADC_Start_DMA(&hadc1,

           (uint32_t *)ADC1ConvertedValue,

           1024

           );

 }

 Serial.println(ADC1ConvertedValue[0]);

}

void Stm32_Clock_Init(uint32_t plln, uint32_t pllm, uint32_t pllp, uint32_t pllq)

{

 HAL_StatusTypeDef ret = HAL_OK;

 RCC_ClkInitTypeDef RCC_ClkInitStruct;

 RCC_OscInitTypeDef RCC_OscInitStruct;

 MODIFY_REG(PWR->CR3, PWR_CR3_SCUEN, 0);

 __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

 while ((PWR->D3CR & (PWR_D3CR_VOSRDY)) != PWR_D3CR_VOSRDY) {}

 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;

 RCC_OscInitStruct.HSEState = RCC_HSE_ON;

 RCC_OscInitStruct.HSIState = RCC_HSI_OFF;

 RCC_OscInitStruct.CSIState = RCC_CSI_OFF;

 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;

 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;

 RCC_OscInitStruct.PLL.PLLN = plln;

 RCC_OscInitStruct.PLL.PLLM = pllm;

 RCC_OscInitStruct.PLL.PLLP = pllp;

 RCC_OscInitStruct.PLL.PLLQ = pllq;

 RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;

 RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;

 ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);

 RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | \

                 RCC_CLOCKTYPE_HCLK | \

                 RCC_CLOCKTYPE_D1PCLK1 | \

                 RCC_CLOCKTYPE_PCLK1 | \

                 RCC_CLOCKTYPE_PCLK2 | \

                 RCC_CLOCKTYPE_D3PCLK1);

 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;

 RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;

 RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;

 RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;

 RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;

 RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;

 RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV4;

 ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);

 if (ret != HAL_OK) while (1);

 __HAL_RCC_CSI_ENABLE() ;

 __HAL_RCC_SYSCFG_CLK_ENABLE() ;

 HAL_EnableCompensationCell();

 RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};

 /** Initializes the peripherals clock

 */

 PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_ADC;

 PeriphClkInitStruct.PLL2.PLL2M = 1;

 PeriphClkInitStruct.PLL2.PLL2N = 18;

 PeriphClkInitStruct.PLL2.PLL2P = 2;

 PeriphClkInitStruct.PLL2.PLL2Q = 2;

 PeriphClkInitStruct.PLL2.PLL2R = 2;

 PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_3;

 PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOMEDIUM;

 PeriphClkInitStruct.PLL2.PLL2FRACN = 6144;

 PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLL2;

 if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)

 {

  error1();

 }

}

void MX_DMA_Init(void)

{

 /* DMA controller clock enable */

 __HAL_RCC_DMA1_CLK_ENABLE();

 /* DMA interrupt init */

 /* DMA1_Stream0_IRQn interrupt configuration */

 HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);

 HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);

}

void MX_ADC1_Init(void)

{

 ADC_MultiModeTypeDef multimode = {0};

 ADC_ChannelConfTypeDef sConfig = {0};

 hadc1.Instance = ADC1;

 hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;

 hadc1.Init.Resolution = ADC_RESOLUTION_10B;

 hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;

 hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

 hadc1.Init.LowPowerAutoWait = DISABLE;

 hadc1.Init.ContinuousConvMode = DISABLE;

 hadc1.Init.NbrOfConversion = 1;

 hadc1.Init.DiscontinuousConvMode = DISABLE;

 hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;

 hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;

 hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_ONESHOT;

 //hadc1.Init.ConversionDataManagement =  ADC_CONVERSIONDATA_DMA_CIRCULAR;

 hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;

 hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;

 hadc1.Init.OversamplingMode = DISABLE;

 if (HAL_ADC_Init(&hadc1) != HAL_OK)

 {

  error1();

 }

 /** Configure the ADC multi-mode

 */

 multimode.Mode = ADC_MODE_INDEPENDENT;

 if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)

 {

  error1();

 }

 sConfig.Channel = ADC_CHANNEL_16;

 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;

 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)

 {

  error1();

 }

}

void MY_HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)

{

 GPIO_InitTypeDef GPIO_InitStruct = {0};

 if (adcHandle->Instance == ADC1)

 {

  /* ADC1 clock enable */

  HAL_RCC_ADC12_CLK_ENABLED++;

  if (HAL_RCC_ADC12_CLK_ENABLED == 1) {

   __HAL_RCC_ADC12_CLK_ENABLE();

  }

  __HAL_RCC_GPIOA_CLK_ENABLE();

  /**ADC1 GPIO Configuration

   PA0   ------> ADC1_INP16

  */

  GPIO_InitStruct.Pin = GPIO_PIN_0;

  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;

  GPIO_InitStruct.Pull = GPIO_NOPULL;

  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* ADC1 DMA Init */

  /* ADC1 Init */

  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_NORMAL;

  //hdma_adc1.Init.Mode = DMA_CIRCULAR;

  hdma_adc1.Init.Priority = DMA_PRIORITY_VERY_HIGH;

  hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;

  if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)

  {

   error1();

  }

  __HAL_LINKDMA(adcHandle, DMA_Handle, hdma_adc1);

 }

}

void DMA1_Stream0_IRQHandler(void)

{

 Serial.println("stream0");

 ADC1_done = true;

 /* USER CODE END DMA1_Stream0_IRQn 0 */

 HAL_DMA_IRQHandler(&hdma_adc1);

 }

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {

 Serial.println("call back");

 if (hadc->Instance == ADC1) {

  ADC1_done = true;

  HAL_ADC_Stop_DMA(hadc);

 }

}

void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc) {

 Serial.println("half call back");

 if (hadc->Instance == ADC1) {

  ADC1_done = true;

  HAL_ADC_Stop_DMA(hadc);

 }

}

void error1(void) {

 Serial.println("error 1");

}

5 REPLIES 5
JColl.5
Associate II

maybe a little more info on what i want to achieve... sampling 2 adc channels, say 500 samples each, on command, after completion processing and visualisation, then restart the sampling process.

input frequencies are fixed betwee 20Hz and 5KHz

arduino stm32duino platform

for simplicity i only use 1 channel but none of the interrupt subroutines are called

It may be related to default STM32H7xxx_FLASH.ld configuration.

Hint:

MEMORY
{
  FLASH (rx)     : ORIGIN = 0x08000000, LENGTH = 128K
  RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K // DTCM is inaccessible by DMA!
  RAM_D1 (xrw)   : ORIGIN = 0x24000000, LENGTH = 512K
  RAM_D2 (xrw)   : ORIGIN = 0x30000000, LENGTH = 288K
  RAM_D3 (xrw)   : ORIGIN = 0x38000000, LENGTH = 64K
  ITCMRAM (xrw)  : ORIGIN = 0x00000000, LENGTH = 64K
}
 
SECTIONS
{
...
.ram_d2_sram1 (NOLOAD):
{
  . = ALIGN(4);
  *(.ram_d2_sram1)
} >RAM_D2
...
 
uint16_t ADC1ConvertedValue[10240] __attribute__((section(".ram_d2_sram1"))); // put array at 0x30000000 instead

From reference manual: "The memory bus allows DMA data transfers between memories. Through the system bus matrices, the memory bus can access all internal memories except ITCM and DTCM, and external memories through the Quad-SPI controller and the FMC."

JColl.5
Associate II

I changed the var according to your tip but no luck, i get the start message on the serial monitor but nothing else, none of the callbacks are triggered but also no errors

JColl.5
Associate II

a little more detail..

if i check the variable address without any changes i get 0x00000078, clearly in the ITCMRAM section.

After applying the changes to program and linker script, check the address again and its 0x00000000 iow not assigned

i tried a few variations, including the solutions offered in DMA is not working on STM32H7 devices

solution 2, same result, tried to enable the ram clock, disable cache etc

the linker recognises the section attributes but does not assign to the D2 ram

no clue to as why this happened

JColl.5
Associate II

ok, i went back to the basics, isolating the variable issue, sorted out now, properly linked to 0x30000... , clk to ram is enabled but still no interrupts or messages from adc or dma, what am i missing here?