Forum: Mikrocontroller und Digitale Elektronik STM32F7 HAL DMA Interrupt Problem


von MFH (Gast)


Angehängte Dateien:

Lesenswert?

Liebe Mikrocontroller Gemeinde,

auf dem STM32F746 Discovery habe ich leider ein Problem mit dem DMA 
Interrupt. Der DMA ist an den ADC angebunden, welcher etwa im 
Sekundentakt von TIM2 getriggert wird. Das ganze läuft einwandfrei 
solange der Buffer nicht (halb)voll ist und somit der DMA Interrupt 
(DMA2_Stream0_IRQHandler) ausgelöst wird. Dann bleibt der Controller 
nämlich in dieser IRQ hängen, denn die HAL Funktion (HAL_DMA_IRQHandler) 
erkennt den Interrupt nicht. Setze ich das Flag TCIF0 (bzw. HTIF0 für 
Half-Transfer) mittels CTCIF0 (bzw. CHTIF0) im Debugger manuell zurück, 
läuft alles wie gewollt weiter bis zum nächsten Interrupt.

Der STM32 läuft mit SYSCLK = 216 MHz und APB2 = 108 MHz. Meine 
Funktionen lauten wie folgt (teilweise habe ich die (Define)Werte der 
Übersicht gleich eingesetzt):

Timer2 als Trigger für ADC1:
1
TIM_HandleTypeDef    htim;
2
3
/**
4
 * @brief  TIM configuration
5
 * @param  Period: value to be loaded into the active
6
 * @param  Prescaler: value used to divide the TIM clock
7
 * @retval None
8
 */
9
void TIM_Config(uint32_t Period, uint32_t Prescaler)
10
{
11
  TIM_MasterConfigTypeDef TIM_MasterConfigStruct;
12
13
  /*##-1- Configure the TMR peripheral #######################################*/
14
  htim.Instance         = TIM2;
15
16
  htim.Init.Period            = Period;
17
  htim.Init.Prescaler         = Prescaler;
18
  htim.Init.ClockDivision     = TIM_CLOCKDIVISION_DIV4;
19
  htim.Init.CounterMode       = TIM_COUNTERMODE_UP;
20
  htim.Init.RepetitionCounter = 0x0;
21
22
  if (HAL_TIM_Base_Init(&htim) != HAL_OK)
23
  {
24
    /* Timer initialization Error */
25
    Error_Handler();
26
  }
27
28
  /*##-2- Timer TRGO selection (p. 15, AN4676) ###############################*/
29
  TIM_MasterConfigStruct.MasterOutputTrigger = TIM_TRGO_UPDATE;
30
  TIM_MasterConfigStruct.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
31
32
  if (HAL_TIMEx_MasterConfigSynchronization(&htim, &TIM_MasterConfigStruct) != HAL_OK)
33
  {
34
    /* Timer TRGO selection Error */
35
    Error_Handler();
36
  }
37
}
38
39
/**
40
 * @brief  Start TMR
41
 * @param  None
42
 * @retval None
43
 */
44
void TMR_StartInterrupt(void)
45
{
46
  /*##-1- Enabled the DAC clock ##############################################*/
47
  __HAL_RCC_DAC_CLK_ENABLE(); /* @todo trouble issue: http://t i n y u r l.com/z9pflvk */
48
49
  /*##-2- TIM counter enable #################################################*/
50
  if (HAL_TIM_Base_Start_IT(&htim) != HAL_OK)
51
  {
52
    /* Starting Error */
53
    Error_Handler();
54
  }
55
}

ADC1 Channel 0 an PA0:
1
ADC_HandleTypeDef    hadcx;
2
3
uint32_t       AdcBuffer[8];
4
5
/**
6
  * @brief  Configure the ADC.
7
  * @param  None
8
  * @retval None
9
  */
10
void ADC_Config(void)
11
{
12
  ADC_ChannelConfTypeDef ADC_ChannelConfStruct;
13
14
  /*##-1- Configure the ADCx peripheral ######################################*/
15
  hadcx.Instance              = ADC1;
16
17
  hadcx.Init.ClockPrescaler     = ADC_CLOCKPRESCALER_PCLK_DIV4;
18
  hadcx.Init.Resolution     = ADC_RESOLUTION_12B;
19
  hadcx.Init.ScanConvMode     = DISABLE;
20
  hadcx.Init.ContinuousConvMode   = DISABLE;
21
  hadcx.Init.DiscontinuousConvMode   = DISABLE;
22
  hadcx.Init.NbrOfDiscConversion   = 0;
23
  hadcx.Init.ExternalTrigConvEdge   = ADC_EXTERNALTRIGCONVEDGE_RISING;
24
  hadcx.Init.ExternalTrigConv     = ADC_EXTERNALTRIGCONV_T2_TRGO;
25
  hadcx.Init.DataAlign       = ADC_DATAALIGN_RIGHT;
26
  hadcx.Init.NbrOfConversion     = 1;
27
  hadcx.Init.DMAContinuousRequests   = ENABLE;
28
  hadcx.Init.EOCSelection     = ADC_EOC_SEQ_CONV;
29
30
  if (HAL_ADC_Init(&hadcx) != HAL_OK)
31
  {
32
    /* Initialization Error */
33
    Error_Handler();
34
  }
35
36
  /*##-2- Configure ADCx regular channel ######################################*/
37
  ADC_ChannelConfStruct.Channel        = ADC_CHANNEL_0;
38
  ADC_ChannelConfStruct.Rank           = 1;
39
  ADC_ChannelConfStruct.SamplingTime   = ADC_SAMPLETIME_480CYCLES;
40
  ADC_ChannelConfStruct.Offset         = 0;
41
42
  if (HAL_ADC_ConfigChannel(&hadcx, &ADC_ChannelConfStruct) != HAL_OK)
43
  {
44
    /* Channel Configuration Error */
45
    Error_Handler();
46
  }
47
}
48
49
50
/**
51
 * @brief  Start ADC and write values with DMA
52
 * @param  None
53
 * @retval None
54
 */
55
void ADC_StartDma(void)
56
{
57
  /*##-1- Start DMA conversion process #######################################*/
58
  if(HAL_ADC_Start_DMA(&hadcx, (uint32_t *)&AdcBuffer, 8) != HAL_OK)
59
  {
60
    /* Start Conversation Error */
61
    Error_Handler();
62
  }
63
64
  /* Disable all IRQ except Transfer Complete */
65
//  hadcx.DMA_Handle->Instance->CR &= ((uint32_t)~(DMA_IT_HT | DMA_IT_TE | DMA_IT_DME));
66
}

Die Init des DMA sowie des GPIO und die TMR Clock habe ich in der HAL 
MSP module integriert.
1
/**
2
  * @brief ADC MSP Initialization
3
  *        This function configures the hardware resources used in this example:
4
  *           - Peripheral's clock enable
5
  *           - Peripheral's GPIO Configuration
6
  * @param hadc: ADC handle pointer
7
  * @retval None
8
  */
9
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
10
{
11
  GPIO_InitTypeDef GPIO_InitStruct;
12
  DMA_HandleTypeDef hdma_adc;
13
14
  /*##-1- Enable peripherals and GPIO Clocks #################################*/
15
  /* Enable GPIO clock */
16
  __HAL_RCC_GPIOA_CLK_ENABLE();
17
  /* ADCx Periph clock enable */
18
  __HAL_RCC_ADC1_CLK_ENABLE();
19
  /* Enable DMA clock */
20
  __HAL_RCC_DMA2_CLK_ENABLE();
21
22
  /*##-2- Configure peripheral GPIO ##########################################*/
23
  /* ADC Channel GPIO pin configuration */
24
  GPIO_InitStruct.Pin = GPIO_PIN_0;
25
  GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
26
  GPIO_InitStruct.Pull = GPIO_NOPULL;
27
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
28
29
  /*##-3- Configure the DMA streams ##########################################*/
30
  /* Set the parameters to be configured */
31
  hdma_adc.Instance       = DMA2_Stream0;
32
33
  hdma_adc.Init.Channel     = DMA_CHANNEL_0;
34
  hdma_adc.Init.Direction     = DMA_PERIPH_TO_MEMORY;
35
  hdma_adc.Init.PeriphInc     = DMA_PINC_DISABLE;
36
  hdma_adc.Init.MemInc       = DMA_MINC_ENABLE;
37
  hdma_adc.Init.PeriphDataAlignment   = DMA_PDATAALIGN_WORD;
38
  hdma_adc.Init.MemDataAlignment   = DMA_MDATAALIGN_WORD;
39
  hdma_adc.Init.Mode       = DMA_CIRCULAR;
40
  hdma_adc.Init.Priority     = DMA_PRIORITY_HIGH;
41
  hdma_adc.Init.FIFOMode     = DMA_FIFOMODE_DISABLE;
42
  hdma_adc.Init.FIFOThreshold     = DMA_FIFO_THRESHOLD_HALFFULL;
43
  hdma_adc.Init.MemBurst     = DMA_MBURST_SINGLE;
44
  hdma_adc.Init.PeriphBurst     = DMA_PBURST_SINGLE;
45
46
  if(HAL_DMA_Init(&hdma_adc) != HAL_OK)
47
  {
48
    /* DMA Init Error */
49
    Error_Handler();
50
  }
51
52
  /* Associate the initialized DMA handle to the ADC handle */
53
  __HAL_LINKDMA(hadc, DMA_Handle, hdma_adc);
54
55
  /*##-4- Configure the NVIC for DMA #########################################*/
56
  /* NVIC configuration for DMA transfer complete interrupt */
57
  HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
58
  HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
59
}
60
61
/**
62
  * @brief TIM MSP Initialization
63
  *        This function configures the hardware resources used in this example:
64
  *           - Peripheral's clock enable
65
  *           - Peripheral's GPIO Configuration
66
  * @param htim: TIM handle pointer
67
  * @retval None
68
  */
69
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
70
{
71
  /*##-1- Enable timer Clock #################################################*/
72
  __HAL_RCC_TIM2_CLK_ENABLE();
73
74
  /*##-2- Configure the NVIC for TIMx ########################################*/
75
  /* Set the TIMx priority */
76
  HAL_NVIC_SetPriority(TIM2_IRQn, 2, 0);
77
  HAL_NVIC_EnableIRQ(TIM2_IRQn);
78
}

Die Interrupt Handlers sehen wie folgt aus:
1
/**
2
* @brief  This function handles DMA interrupt request.
3
* @param  None
4
* @retval None
5
*/
6
void DMA2_Stream0_IRQHandler(void)
7
{
8
  HAL_DMA_IRQHandler(hadcx.DMA_Handle);
9
}
10
11
/**
12
  * @brief  This function handles TIM interrupt request.
13
  * @param  None
14
  * @retval None
15
  */
16
void TIM2_IRQHandler(void)
17
{
18
  HAL_TIM_IRQHandler(&htim);
19
}

Die relevanten Ausschnitte der main.c lauten:
1
/**
2
  * @brief  Main program.
3
  * @param  None
4
  * @retval None
5
  */
6
int main(void)
7
{
8
  /* Configure the MPU attributes as Write Through */
9
//  MPU_Config();
10
11
  /* Enable the CPU Cache */
12
  CPU_CACHE_Enable();
13
14
  /* STM32F7xx HAL library initialization:
15
       - Configure the Flash prefetch
16
       - Systick timer is configured by default as source of time base, but user
17
         can eventually implement his proper time base source (a general purpose
18
         timer for example or other time source), keeping in mind that Time base
19
         duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and
20
         handled in milliseconds basis.
21
       - Set NVIC Group Priority to 4
22
       - Low Level Initialization
23
     */
24
  HAL_Init();
25
26
  /* Configure the system clock to 216 MHz */
27
  SystemClock_Config();
28
29
  /* Configure LED1 */
30
  BSP_LED_Init(LED1);
31
32
  /* Configure the LCD peripheral */
33
  LCD_Config();
34
35
  /* Configure the ADC peripheral */
36
  TIM_Config(1999, 49999);
37
38
  /* Configure the ADC peripheral */
39
  ADC_Config();
40
41
  /* Start ADC with TMR based conversion process and enable DMA */
42
  ADC_StartDma();
43
44
  /* Start TMR */
45
  TMR_StartInterrupt();
46
47
  /* Infinite loop */
48
  while (1)
49
  {
50
    /* Display the TMR value */
51
    LCD_ShowValue(htim.Instance->CNT, 0, "TMR");
52
53
    /* Display the ADC value */
54
    LCD_ShowValue(AdcBuffer[0], 2, "ADC0");
55
    LCD_ShowValue(AdcBuffer[1], 3, "ADC1");
56
    LCD_ShowValue(AdcBuffer[2], 4, "ADC2");
57
    LCD_ShowValue(AdcBuffer[3], 5, "ADC3");
58
    LCD_ShowValue(AdcBuffer[4], 6, "ADC4");
59
    LCD_ShowValue(AdcBuffer[5], 7, "ADC5");
60
    LCD_ShowValue(AdcBuffer[6], 8, "ADC6");
61
    LCD_ShowValue(AdcBuffer[7], 9, "ADC7");
62
63
    LCD_ShowValue(AdcValue, 11, "VAL");
64
  }
65
}
66
67
/**
68
  * @brief  Period elapsed callback in non blocking mode
69
  * @param  htim : TIM handle
70
  * @retval None
71
  */
72
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
73
{
74
  /* Increase ADC cycle counter */
75
  AdcCycleNumber += 1;
76
  LCD_ShowValue(AdcCycleNumber, 1, "CYC");
77
}
78
79
/**
80
  * @brief  Conversion complete callback in non blocking mode
81
  * @param  hadc: hadc handle
82
  * @retval None
83
  */
84
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
85
{
86
  uint32_t DmaOffsetBefore = 0, DmaOffsetAfter = 0;
87
88
  /* DMA timings by saving the value of the NDTR (remaining amount of values) */
89
  DmaOffsetBefore = ADC_BUFFER_SIZE - ADCxyz_DMA_STREAM->NDTR;
90
91
  /* Do something */
92
93
  /* DMA timings, BUFFER_SIZE can be adjusted, otherwise use HAL_ADC_ConvHalfCpltCallback() */
94
  DmaOffsetAfter = ADC_BUFFER_SIZE - ADCxyz_DMA_STREAM->NDTR;
95
96
  LCD_ShowValue(DmaOffsetBefore-DmaOffsetAfter, 13, "DMA");
97
}
98
99
/**
100
 * @brief  Regular conversion half DMA transfer callback in non blocking mode
101
 * @param  hadc: pointer to a ADC_HandleTypeDef structure that contains
102
 *         the configuration information for the specified ADC.
103
 * @retval None
104
 */
105
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
106
{
107
  uint32_t DmaOffsetBefore = 0, DmaOffsetAfter = 0;
108
109
  /* DMA timings by saving the value of the NDTR (remaining amount of values) */
110
  DmaOffsetBefore = ADC_BUFFER_SIZE - ADCxyz_DMA_STREAM->NDTR;
111
112
  /* Do something */
113
114
  /* DMA timings, BUFFER_SIZE can be adjusted, otherwise use HAL_ADC_ConvHalfCpltCallback() */
115
  DmaOffsetAfter = ADC_BUFFER_SIZE - ADCxyz_DMA_STREAM->NDTR;
116
117
  LCD_ShowValue(DmaOffsetBefore-DmaOffsetAfter, 13, "DMA");
118
}

Im ST-Forum 
(https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https%3a%2f%2fmy%2est%2ecom%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fcortex%5fmx%5fstm32%2fHAL%20DMA%20ADC%20Interrupt%20stuck%20in%20IRQ%20Handler&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&currentviews=2329) 
habe ich einen ähnlichen Beitrag gefunden, leider wird hierzu keine 
Lösung angeboten. Die genannten Vorschläge haben bei mir leider nicht 
geholfen...

Ich bin über jeden Ratschlag dankbar, ansonsten helfen die Init 
Funktionen vielleicht dem nächsten, ansich laufen diese!

Vielen Dank im Voraus, Grüße
MFH

PS: Im Anhang noch ein Bild während des Half-Transfer Interrupt 
(Breakpoint in DMA2_Stream0_IRQHandler), der Buffer ist also nur halb 
voll und wird im Hintergrund fleißig weiter befüllt. Außerdem das 
entsprechende Register des DMA2 und die gesetzen Interrupt Flags (TCIF0 
wurde durch die Aktuallisierung gesetzt).

von ewqtrwetqrwrtwq (Gast)


Lesenswert?

hi

ich vervollständige das hier mal ... rein aus Interesse
Weil ich seit 2 tagen vor ähnlichem Problem saß  und durch zufall auch 
hierüber gestolpert bin.

Es gibt einen Workaround für das dingen

bei TIM1 oder TIM8 MUSS bei verwendung von TRGO_UPDATE immer die 
RISINGFALLING   flanke genutzt werden

bei TIM2 bis TIM6 MUSS immer der _RCC_DAC_CLK  enabled  werden!!
AUch wenn der DAC nicht genutzt wird.

nur dann funktioniert der TRGO mit dem ADC

achso ..
der TIMx muss den NVICInterupt enablen ( sonst kommt das event nicht zum 
NVIC )
aber darf nur die HAL_TIM_Base_Start(x); aufrufen
Nicht die ISR funktionen

habe das  ADC / DAC DMA TIM_triggered heute endlich zum laufen bekommen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.