Forum: Mikrocontroller und Digitale Elektronik STM32 ADC->DMA Continous mode lässt sich nicht aktivieren


von Solocan Z. (solocan)


Lesenswert?

Hallo zusammen,

ich stehe gerade auf dem Schlauch und brauche Inputs. Ich möchte, dass 
die ADC Werte per DMA kontinuierlich im Hintergrund auf eine 
Speicheradresse geschrieben werden. Doch DMA wird nur 1 mal getriggert 
und hört dann auf. Im Polling mode kriege ich Updates, im DMA nicht. 
Scheint so, dass ich DMA irgendwie falsch konfiguriert habe aber finde 
meinen Fehler einfach nicht. Alles mit "continuous" und "discontinuous" 
bereits erfolglos versucht.

Hier ist der relevante Auszug ausm Code:

main.c
1
int main(void)
2
{
3
 
4
  HAL_Init();
5
  SystemClock_Config();
6
  MX_GPIO_Init();
7
  MX_DMA_Init();
8
  MX_USART3_UART_Init();
9
  MX_USB_OTG_FS_PCD_Init();
10
  MX_ADC1_Init();
11
12
  uint16_t ADC_buf=0;
13
  uint16_t ADC_poll=0;
14
15
  //Start DMA stream
16
  HAL_ADC_Start_DMA(&hadc1,(uint32_t*) &ADC_buf,2);
17
18
  while(1){
19
20
    HAL_ADC_Start(&hadc1);
21
    HAL_ADC_PollForConversion(&hadc1,10);
22
    ADC_poll=HAL_ADC_GetValue(&hadc1);
23
    printf("DMA: %d \t Poll: %d\n",(int) ADC_buf, (int)ADC_poll);
24
25
    HAL_ADC_Stop(&hadc1);
26
    HAL_Delay(100);
27
.
28
.
29
.
30
static void MX_ADC1_Init(void)
31
{
32
33
  ADC_ChannelConfTypeDef sConfig;
34
35
    /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
36
    */
37
  hadc1.Instance = ADC1;
38
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
39
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
40
  hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
41
  hadc1.Init.ContinuousConvMode = ENABLE;
42
  hadc1.Init.DiscontinuousConvMode = DISABLE;
43
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
44
  hadc1.Init.ExternalTrigConv =ADC_SOFTWARE_START ;
45
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
46
  hadc1.Init.NbrOfConversion = 2;
47
  hadc1.Init.DMAContinuousRequests = ENABLE;
48
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
49
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
50
  {
51
    _Error_Handler(__FILE__, __LINE__);
52
  }
53
54
    /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
55
    */
56
  sConfig.Channel = ADC_CHANNEL_0;
57
  sConfig.Rank = ADC_REGULAR_RANK_1;
58
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
59
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
60
  {
61
    _Error_Handler(__FILE__, __LINE__);
62
  }
63
64
}
65
66
static void MX_DMA_Init(void) 
67
{
68
  /* DMA controller clock enable */
69
  __HAL_RCC_DMA2_CLK_ENABLE();
70
71
  /* DMA interrupt init */
72
  hdma_adc1.Instance=DMA2_Stream0;
73
  hdma_adc1.Init.Channel = DMA_CHANNEL_0;// Channel 0, Stream 0
74
  hdma_adc1.Init.Direction=DMA_PERIPH_TO_MEMORY;
75
  hdma_adc1.Init.PeriphInc=DMA_PINC_DISABLE;
76
  hdma_adc1.Init.MemInc=DMA_MINC_DISABLE;
77
  hdma_adc1.Init.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD;
78
  hdma_adc1.Init.MemDataAlignment=DMA_MDATAALIGN_HALFWORD;
79
  hdma_adc1.Init.Mode=DMA_CIRCULAR;
80
  hdma_adc1.Init.Priority=DMA_PRIORITY_HIGH;
81
  hdma_adc1.Init.FIFOMode=DMA_FIFOMODE_DISABLE;
82
  hdma_adc1.Init.FIFOThreshold=DMA_FIFO_THRESHOLD_HALFFULL;
83
  hdma_adc1.Init.MemBurst=DMA_MBURST_SINGLE;
84
  hdma_adc1.Init.PeriphBurst=DMA_PBURST_SINGLE;
85
86
  //Initialize DMA
87
  if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)    {      _Error_Handler(__FILE__, __LINE__);    }  ;
88
89
  /* DMA2_Stream0_IRQn interrupt configuration */
90
  HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
91
  HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
92
93
94
}


stm32f7xx_it.c
1
void DMA2_Stream0_IRQHandler(void)
2
{
3
4
  printf("Interrupted\n");
5
  HAL_DMA_IRQHandler(&hdma_adc1);
6
}

printf-Ausgabe ist:

Initializing
Interrupted
DMA: 4095    Poll: 4034
DMA: 4095    Poll: 4032
DMA: 4095    Poll: 4095
DMA: 4095    Poll: 4041
DMA: 4095    Poll: 4095
DMA: 4095    Poll: 4048
DMA: 4095    Poll: 4095
DMA: 4095    Poll: 4052
DMA: 4095    Poll: 4095
DMA: 4095    Poll: 4041

Also DMA bzw. interrupt nur 1x getriggert. Was konfiguriere ich denn 
hier falsch?

Bin nur hier nicht sicher:
1
hadc1.Init.ExternalTrigConv =ADC_SOFTWARE_START ;

Hier kann man auch verschiedene Timer wählen aber es half auch nichts.

Bin dankbar für jeden Tipp.

: Bearbeitet durch User
von Solocan Z. (solocan)


Angehängte Dateien:

Lesenswert?

Ich entnehme dem Datenblatt, dass es auf jeden Fall mit 
"ExternalTrigConv =ADC_SOFTWARE_START" und "ContinuousConvMode = ENABLE" 
in kontinuierlichen Modus wechseln soll. Also sobald eine Konvertierung 
durch ist, startet die nächste. Da bin ich mir eigentlich doch ziemlich 
sicher, dass ich ADC richtig konfiguriert habe.

Aber ich sehe auch, dass in der Beschreibung von der Funktion 
HAL_ADC_Start_DMA nur der "Single mode" steht. Es ist wahrscheinlich so, 
dass HAL für ADC-DMA Modus nur den Single mode unterstützt. (Ich habe 
versucht, die HAL-Funktion zu analysieren und es sieht tatsächlich so 
aus, dass HAL_ADC_Start_DMA jedes mal von außen getriggert werden muss.) 
Ich brauche aber einen kontinuierlichen Stream und möchte dass DMA im 
Hintergrund läuft und ich nicht per Software triggern muss. Hat das 
schon jemand gemacht? Muss ich da unbedingt einen Timer einstellen?

: Bearbeitet durch User
von geb (Gast)


Lesenswert?

Hier der Code, wie ich es für ADC3 getriggert durch Timer 3 gemacht 
habe. Vergiss nicht die Clocks einzuschalten und den DMA Interrupt zu 
konfigurieren.

void init_ADC(void)
{
#define ADC1_DR_Address    ((u32)0x4001244C)
#define ADC3_DR_Address    ((u32)0x40013C4C)
DMA_InitTypeDef DMA_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;
TIM_OCInitTypeDef         TIM_OCInitStructure;

 /* TIM3CC1 configuration 
------------------------------------------------------*/
  /* Time Base configuration*/
  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  TIM_TimeBaseStructure.TIM_Period = 36000;
  TIM_TimeBaseStructure.TIM_Prescaler = 0x1;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 0x3F;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
  TIM_OC1Init(TIM3, &TIM_OCInitStructure);
  TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);



  ADC_buf_wr_ptr = ADC_buf_A;
  ADC_buf_rd_ptr = ADC_buf_B;
  DevStatus.TCmux =0;
  DevStatus.num_avg=0;


 //Mbox ADC3 DMA
  DMA_DeInit(DMA2_Channel5);
  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC3_DR_Address;
  DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC_buf_wr_ptr;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  DMA_InitStructure.DMA_BufferSize = 12;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = 
DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  DMA_Init(DMA2_Channel5, &DMA_InitStructure);
  DMA_ITConfig(DMA2_Channel5, DMA_IT_TC, ENABLE);

   DMA_Cmd(DMA2_Channel1, DISABLE);
  DMA_Cmd(DMA2_Channel2, DISABLE);
  DMA_Cmd(DMA2_Channel3, DISABLE);
  DMA_Cmd(DMA2_Channel4, DISABLE);
  DMA_Cmd(DMA2_Channel5, ENABLE);

  /* ADC3 configuration 
------------------------------------------------------*/
  ADC_DeInit( ADC3);
  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
//  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_CC1;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfChannel = 12;
  ADC_Init(ADC3, &ADC_InitStructure);
  /* ADC3 regular channel configuration */
  ADC_RegularChannelConfig(ADC3, ADC_Channel_4, 1, 
ADC_SampleTime_239Cycles5);//AIN_T_KK
  ADC_RegularChannelConfig(ADC3, ADC_Channel_7, 2, 
ADC_SampleTime_239Cycles5);//AIN420_1
  ADC_RegularChannelConfig(ADC3, ADC_Channel_8, 3, 
ADC_SampleTime_239Cycles5);//AIN420_2
  ADC_RegularChannelConfig(ADC3, ADC_Channel_10, 4, 
ADC_SampleTime_239Cycles5);//AIN420_3
  ADC_RegularChannelConfig(ADC3, ADC_Channel_11, 5, 
ADC_SampleTime_239Cycles5);//AIN420_4
  ADC_RegularChannelConfig(ADC3, ADC_Channel_12, 6, 
ADC_SampleTime_239Cycles5);//AIN420_5
  ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 7, 
ADC_SampleTime_239Cycles5);//AIN420_6
  ADC_RegularChannelConfig(ADC3, ADC_Channel_5, 8, 
ADC_SampleTime_239Cycles5);//AIN_T_TC1
  ADC_RegularChannelConfig(ADC3, ADC_Channel_6, 9, 
ADC_SampleTime_239Cycles5);//AIN_T_TC2
  ADC_RegularChannelConfig(ADC3, ADC_Channel_0, 10, 
ADC_SampleTime_239Cycles5);//AIN_T_TC3
  ADC_RegularChannelConfig(ADC3, ADC_Channel_1, 11, 
ADC_SampleTime_239Cycles5);//AIN_T_TC4
  ADC_RegularChannelConfig(ADC3, ADC_Channel_3, 12, 
ADC_SampleTime_239Cycles5);//AIN_T_TC5
 //Init TC MUX
              CLR_TC1_A0;
              CLR_TC2_A0;
              CLR_TC1_A1;
              CLR_TC2_A1;
 DevStatus.TCmux=0;

  /* Enable ADC3 DMA */
  ADC_DMACmd(ADC3, ENABLE);
  /* Enable ADC3 */
  ADC_Cmd(ADC3, ENABLE);

 /* Enable ADC1 reset calibaration register */
  ADC_ResetCalibration(ADC3);
  /* Check the end of ADC1 reset calibration register */
      while(ADC_GetResetCalibrationStatus(ADC3));
  /* Start ADC1 calibaration */
  ADC_StartCalibration(ADC3);
  /* Check the end of ADC1 calibration */
  while(ADC_GetCalibrationStatus(ADC3));
  /* Enable ADC1 reset calibaration register */
TIM_Cmd(TIM3, ENABLE);//ADC startet noch nicht, erst durch Ext. Trigger 
command
}

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.