Forum: Mikrocontroller und Digitale Elektronik 7 Kanäle ADC lesen - Übersprechen - STM32F407


von RainerZufall24 (Gast)


Lesenswert?

Hallo,
ich möchte für innerhalb eines größeren Projektes (Batterie Manager) 
analoge Daten mit einem STm32F407 Discovery einlesen.
Es geht dabei um die Pin's PA1 bis PA7.
Das einzlen lesen klappt schon problemlos mittels HAL_ADC_Start().
Nun möchte ich aber alle "parallel" lesen und in ein Array schreiben.
Dazu muss ich die DMA nutzen.

Leider klappt das nicht so einfach und ich komme einfach nicht drauf 
woran das liegt.
Könnte sich da jemand mal den Code anschauen und mir ggf. einen Tipp 
geben.
Ich nutze übrigens die STM32CubeIDE. Zur Ausgabe der Daten nutze ich den 
SWV / die ITM Console.

Momentan habe ich das Problem, dass die CH3 lesen kann, die anderen 
Kanäle sic aber auch verändern (Werte liegen jedoch im Auflösungsbreich 
-> 0...255). Der Kanal der angesteckt ist, zeigt aber die richtigen 
werte an.

Das sieht wie so eine Art übersprechen der Kanäle aus.
Die SampleTime habe ich nun schon auf 56 hochgesetzt. Gibs da noch 
andere Möglichkeiten...?

Hier der relevante Code:
1
/* USER CODE END Header */
2
3
/* Includes ------------------------------------------------------------------*/
4
#include "main.h"
5
6
/* Private includes ----------------------------------------------------------*/
7
/* USER CODE BEGIN Includes */
8
9
#include "stm32f4xx.h"
10
#include "stm32f4xx_hal.h"
11
#include "stm32f4xx_hal_conf.h"
12
#include "stm32f4xx_hal_adc.h"
13
#include "stm32f4xx_hal_gpio.h"
14
#include "stm32f4xx_hal_rcc.h"
15
#include "stm32f4xx_hal_tim.h"
16
#include "stm32f4xx_hal_can.h"
17
#include "stdint.h"
18
#include "string.h"
19
#include "stdio.h"
20
#include "inttypes.h"
21
22
int main(void)
23
{
24
  /* USER CODE BEGIN 1 */
25
26
  int test;
27
  int i;
28
  /* USER CODE END 1 */
29
  
30
31
  /* MCU Configuration--------------------------------------------------------*/
32
33
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
34
  HAL_Init();
35
36
  /* USER CODE BEGIN Init */
37
38
  /* USER CODE END Init */
39
40
  /* Configure the system clock */
41
  SystemClock_Config();
42
43
  /* USER CODE BEGIN SysInit */
44
  /* USER CODE END SysInit */
45
46
  /* Initialize all configured peripherals */
47
  MX_GPIO_Init();
48
  MX_DMA_Init();
49
  MX_ADC1_Init();
50
51
  /* USER CODE BEGIN 2 */
52
  __HAL_RCC_ADC1_CLK_ENABLE();
53
  __HAL_RCC_CAN1_CLK_ENABLE();
54
  __HAL_RCC_CAN2_CLK_ENABLE();
55
56
  GPIO_config();
57
  /* USER CODE END 2 */
58
59
60
   i=0;
61
   uint32_t Buffer[7];
62
  /* Infinite loop */
63
  /* USER CODE BEGIN WHILE */
64
  while (1)
65
  {
66
  
67
      HAL_ADC_Start_DMA(&hadc1, (uint32_t*)Buffer,6);
68
      HAL_Delay(10);
69
70
      HAL_ADC_Stop_DMA(&hadc1);
71
    
72
73
74
  
75
    printf("Buffer:%i   Buffer:%i   Buffer:%i   \n",Buffer[0], Buffer[1], Buffer[2]);
76
    printf("beat %i \n",i++);
77
  
78
79
    /* USER CODE END WHILE */
80
81
    /* USER CODE BEGIN 3 */
82
83
84
  /* USER CODE END 3 */
85
}
86
}

Hier die SystemClock_Config()
1
void SystemClock_Config(void)
2
{
3
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
4
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
5
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
6
7
  /** Configure the main internal regulator output voltage 
8
  */
9
  __HAL_RCC_PWR_CLK_ENABLE();
10
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
11
  /** Initializes the CPU, AHB and APB busses clocks 
12
  */
13
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_LSI;
14
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
15
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
16
  RCC_OscInitStruct.LSIState = RCC_LSI_ON;
17
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
18
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
19
  {
20
    Error_Handler();
21
  }
22
  /** Initializes the CPU, AHB and APB busses clocks 
23
  */
24
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
25
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
26
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
27
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
28
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
29
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
30
31
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
32
  {
33
    Error_Handler();
34
  }
35
  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
36
  PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
37
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
38
  {
39
    Error_Handler();
40
  }
41
}


Hier die MX_ADC1_Init()
1
static void MX_ADC1_Init(void)
2
{
3
4
  /* USER CODE BEGIN ADC1_Init 0 */
5
  __HAL_RCC_ADC1_CLK_ENABLE();
6
  __HAL_RCC_GPIOA_CLK_ENABLE();
7
  __HAL_RCC_DMA2_CLK_ENABLE();
8
9
10
  /* USER CODE END ADC1_Init 0 */
11
12
  ADC_ChannelConfTypeDef sConfig = {0};
13
14
  /* USER CODE BEGIN ADC1_Init 1 */
15
16
  /* USER CODE END ADC1_Init 1 */
17
  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 
18
  */
19
  hadc1.Instance = ADC1;
20
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
21
  hadc1.Init.Resolution = ADC_RESOLUTION_8B;
22
  hadc1.Init.ScanConvMode = ENABLE;
23
  hadc1.Init.ContinuousConvMode = ENABLE;
24
  hadc1.Init.DiscontinuousConvMode = DISABLE;
25
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
26
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
27
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
28
  hadc1.Init.NbrOfConversion = 1;
29
  hadc1.Init.DMAContinuousRequests = DISABLE;
30
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
31
32
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
33
  {
34
    Error_Handler();
35
  }
36
  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
37
  */
38
39
  sConfig.Channel = ADC_CHANNEL_1;
40
  sConfig.Rank = 1;
41
  sConfig.SamplingTime = ADC_SAMPLETIME_56CYCLES;
42
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
43
  {
44
    Error_Handler();
45
  }
46
  /*
47
  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
48
  */
49
  sConfig.Channel = ADC_CHANNEL_2;
50
  sConfig.SamplingTime = ADC_SAMPLETIME_56CYCLES;
51
  sConfig.Rank = 2;
52
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
53
  {
54
    Error_Handler();
55
  }
56
  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
57
*/
58
  sConfig.Channel = ADC_CHANNEL_3;
59
  sConfig.Rank = 3;
60
  sConfig.SamplingTime = ADC_SAMPLETIME_56CYCLES;
61
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
62
  {
63
    Error_Handler();
64
  }
65
  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
66
*/
67
  sConfig.Channel = ADC_CHANNEL_5;
68
  sConfig.Rank = 4;
69
  sConfig.SamplingTime = ADC_SAMPLETIME_56CYCLES;
70
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
71
  {
72
    Error_Handler();
73
  }
74
  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
75
*/
76
  sConfig.Channel = ADC_CHANNEL_6;
77
  sConfig.Rank = 5;
78
  sConfig.SamplingTime = ADC_SAMPLETIME_56CYCLES;
79
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
80
  {
81
    Error_Handler();
82
  }
83
  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
84
*/
85
  sConfig.Channel = ADC_CHANNEL_7;
86
  sConfig.Rank = 6;
87
  sConfig.SamplingTime = ADC_SAMPLETIME_56CYCLES;
88
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
89
  {
90
    Error_Handler();
91
  }
92
  /* USER CODE BEGIN ADC1_Init 2 */
93
  /* USER CODE END ADC1_Init 2 */
94
95
}

Hier die MX_DMA_Init():
1
static void MX_DMA_Init(void) 
2
{
3
4
  /* DMA controller clock enable */
5
  __HAL_RCC_DMA2_CLK_ENABLE();
6
  __DMA2_CLK_ENABLE();
7
  DMA_HandleTypeDef hdma_adc2;
8
9
  /* DMA interrupt init */
10
  /* DMA2_Stream0_IRQn interrupt configuration */
11
  HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
12
  HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
13
14
}

Hier die MX_GPIO_Config():
1
static void MX_GPIO_Init(void)
2
{
3
  GPIO_InitTypeDef GPIO_InitStruct = {0};
4
5
  /* GPIO Ports Clock Enable */
6
  __HAL_RCC_GPIOA_CLK_ENABLE();
7
  __HAL_RCC_GPIOB_CLK_ENABLE();
8
  __HAL_RCC_GPIOD_CLK_ENABLE();
9
  __HAL_RCC_GPIOC_CLK_ENABLE();
10
11
  /*Configure GPIO pin Output Level */
12
  HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|DisCon_Heater_Pin 
13
                          |DisCon_Cell_Pin|Enable_U12_Pin, GPIO_PIN_RESET);
14
15
  /*Configure GPIO pin : B_Blue_Pin */
16
  GPIO_InitStruct.Pin = B_Blue_Pin;
17
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
18
  GPIO_InitStruct.Pull = GPIO_NOPULL;
19
  HAL_GPIO_Init(B_Blue_GPIO_Port, &GPIO_InitStruct);
20
21
  /*Configure GPIO pins : PD12 PD13 PD14 DisCon_Heater_Pin 
22
                           DisCon_Cell_Pin Enable_U12_Pin */
23
  GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|DisCon_Heater_Pin 
24
                          |DisCon_Cell_Pin|Enable_U12_Pin;
25
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
26
  GPIO_InitStruct.Pull = GPIO_NOPULL;
27
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
28
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
29
30
  /*Configure GPIO pins : B_AlStDn_Pin B_PwStDn_Pin Enable_QSWR_Pin ReserveD6_Pin 
31
                           ReserveD7_Pin */
32
  GPIO_InitStruct.Pin = B_AlStDn_Pin|B_PwStDn_Pin|Enable_QSWR_Pin|ReserveD6_Pin 
33
                          |ReserveD7_Pin;
34
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
35
  GPIO_InitStruct.Pull = GPIO_NOPULL;
36
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
37
38
}
Hier die eigene GPIO Config Funktion
1
int GPIO_config(void)
2
  {  //__GPIOB_CLK_ENABLE();
3
4
    GPIOD -> MODER |= (1<<0);  // Set pin 0 (DisCon_Heater) to be general purpose output in GPIO port mode register
5
    GPIOD -> MODER |= (1<<2);  // Set pin 1 (DisCon_Cell) to be general purpose output in GPIO port mode register
6
    GPIOD -> MODER |= (1<<4);  // Set pin 2 (Enable_U12) to be general purpose output in GPIO port mode register
7
8
    //GPIOD -> MODER |= (1<<24);  // Set pin 12 (orange LED) to be general purpose output in GPIO port mode register
9
    GPIOD -> MODER |= (1<<26);  // Set pin 13 (green LED)to be general purpose output in GPIO port mode register
10
    //GPIOD -> MODER |= (1<<28);  // Set pin 14 (orange LED)to be general purpose output in GPIO port mode register
11
    //GPIOD -> MODER |= (1<<30);  // Set pin 15 (orange LED)to be general purpose output in GPIO port mode register
12
13
    // Configuration PORT D as Output
14
    GPIO_InitTypeDef GPIO_InitStruct; //Where GPIO_InitDef is variable to work with struct
15
    GPIO_InitStruct.Pin = GPIO_PIN_15;
16
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
17
    GPIO_InitStruct.Pull = GPIO_NOPULL;
18
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
19
    HAL_GPIO_Init(GPIOD,&GPIO_InitStruct);
20
    //  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
21
    printf("GPIO Port D config done \n");
22
/*
23
    // Configuration PORT D as Output
24
    GPIO_InitTypeDef GPIO_InitStruct; //Where GPIO_InitDef is variable to work with struct
25
    GPIO_InitStruct.Pin = GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14;
26
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
27
    GPIO_InitStruct.Pull = GPIO_PULLUP;
28
    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
29
    HAL_GPIO_Init(GPIOD,&GPIO_InitStruct);
30
    //  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
31
*/
32
33
 //GPIO Port A digital iN
34
    // Configuration PORT A as Input
35
    GPIO_InitStruct.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 ; //| GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
36
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
37
    GPIO_InitStruct.Pull = GPIO_NOPULL;
38
    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
39
    HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
40
41
    printf("GPIO Port A config done \n");
42
43
44
    /**CAN-Bus GPIO Configuration
45
     * PB8 ------> CAN-TX
46
     * PB9 ------> CAN-RX
47
     * */
48
49
    GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
50
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
51
    GPIO_InitStruct.Pull = GPIO_NOPULL;
52
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
53
    GPIO_InitStruct.Alternate = GPIO_AF9_CAN1;
54
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
55
56
57
    printf("GPIO Port B config (CAN) done \n");
58
/*
59
    //__HAL_RCC_GPIOE_CLK_ENABLE();
60
      // Configuration PORT A as Analog Input
61
      GPIO_InitStruct.Pin = GPIO_PIN_0;
62
      GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
63
      GPIO_InitStruct.Pull = GPIO_NOPULL;
64
      GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
65
      HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
66
      //  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
67
68
*/
69
70
  }

von RainerZufall24 (Gast)


Lesenswert?

Gleich noch ein Kommentar / Frage:
Warum werden die Werte nicht aktualisiert wenn ich das HAL_Delay(10) in 
der While-Schleife entferne?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

RainerZufall24 schrieb:
> Der Kanal der angesteckt ist
Was passiert dabei mit den anderen Kanälen? Sind die "ausgesteckt"? Und 
welchen Pegel haben sie, wenn sie das sind, was sie dann sind? Was 
passiert, wenn die anderen Kanäle auch "angesteckt" sind, aber z.B. auf 
GND? Wie sieht die Beschaltung der ADC-Pins aus?

Oder die Kurzform: lies mal deine Beschreibung und versuche zu 
verstehen, was da wann passiert und wie du die ADC Pins dabei 
verschaltet hast...


RainerZufall24 schrieb:
> Warum werden die Werte nicht aktualisiert wenn ich das HAL_Delay(10) in
> der While-Schleife entferne?
Weil vermutlich gar kein ADC-Transfer stattfindet, so wie du z.B. auch 
mit dem Auto nicht aus der Garage zur Arbeit kommst, wenn du ofort nach 
dem Anlassen den Motor wieder abstellst.
Wenn du den DMA startest, dann musst du irgendwie abfragen, ob der 
Transfer fertig ist. Und nicht einfach gleich danach wieder auf den 
Ausschalter drücken. Diese "Abfrage" geschieht z.B. über einen Interrupt 
bzw. Callback (Stichwort HAL_ADC_ConvCpltCallback), der aufgerufen wird, 
wenn der DMA-Transfer erledigt ist.


BTW:
Ein Auszug aus der Bedienungsanleitung:
"Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang"

von RainerZufall24 (Gast)


Lesenswert?

.... Hmm Mist.
Anfängerfehler.

Lothar M. schrieb:
> Wie sieht die Beschaltung der ADC-Pins aus?

Auf jeden Fall nicht gut genug. -> Hier lag der Hund begraben.
Wenn die ordentlich auf Potential liegen, dann geht es.

Grundsätzlich hätte ich mir die Fragen wohl sparen können.
Die 2. ist ebenso logisch.


Von daher -> Danke fürs Augenöffnen ;-)
Den Dateianhang werde ich das nächste Mal auch beherzigen.

VG
RainerZufall24

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.