Forum: Mikrocontroller und Digitale Elektronik STM32F103 und ADC DMA mehrere Kanäle


von Christoph K. (chriskuku)


Lesenswert?

Ich versuche gerade, 4 ADC-Kanäle IN04-IN07 auf PA04-PA07 eines 
STM32F103C8T6 einzulesen. Wenn ich mir das DMA-Zielarray in einer 
Schleife im Programm anschaue, so springen die Werte auf ihren Plätzen. 
(an PA4 habe ich ein Poti und das auf 0 gedreht). Ich würde ja erwarten, 
daß nur der eine Wert am festen Platz modifiziert wird.
1
uint16_t adc_value[4];
2
static void MX_ADC1_Init(void)
3
{
4
5
  ADC_ChannelConfTypeDef sConfig = {0};
6
7
  /** Common config */
8
  hadc1.Instance = ADC1;
9
  hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
10
  hadc1.Init.ContinuousConvMode = ENABLE;
11
  hadc1.Init.DiscontinuousConvMode = DISABLE;
12
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
13
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
14
  hadc1.Init.NbrOfConversion = 4;
15
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
16
  {
17
    Error_Handler();
18
  }
19
  /** Configure Regular Channel */
20
  sConfig.Channel = ADC_CHANNEL_4;
21
  sConfig.Rank = ADC_REGULAR_RANK_1;
22
  sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
23
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
24
  {
25
    Error_Handler();
26
  }
27
  /** Configure Regular Channel */
28
  sConfig.Channel = ADC_CHANNEL_5;
29
  sConfig.Rank = ADC_REGULAR_RANK_2;
30
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
31
  {
32
    Error_Handler();
33
  }
34
  /** Configure Regular Channel */
35
  sConfig.Channel = ADC_CHANNEL_6;
36
  sConfig.Rank = ADC_REGULAR_RANK_3;
37
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
38
  {
39
    Error_Handler();
40
  }
41
  /** Configure Regular Channel */
42
  sConfig.Channel = ADC_CHANNEL_7;
43
  sConfig.Rank = ADC_REGULAR_RANK_4;
44
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
45
  {
46
    Error_Handler();
47
  }
48
}
49
50
void StartTask03(void *argument)
51
{
52
 
53
  // ADC CAlibration
54
55
  HAL_ADCEx_Calibration_Start(&hadc1);
56
  osDelay(50);
57
58
  /* Infinite loop */
59
  for(;;)
60
  {
61
      char str[32];
62
      HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc_value, 4);
63
64
    sprintf(str,"ADC: %d %d %d %d\n",adc_value[0],adc_value[1],adc_value[2],adc_value[3]);
65
    uart1_print(str);
66
67
    osDelay(5000);
68
69
  }
70
}

Aber das Ergebnis sieht merkwürdig aus (habe die Ausgänge A5-A7 jetzt 
mal auf +3.3V gelegt):
1
ADC: 3 4095 4095 4095 
2
ADC: 0 4095 4095 4095 
3
ADC: 4095 0 4095 4095 
4
ADC: 4095 0 4095 4095 
5
ADC: 4095 4095 2 4095
Was mache ich falsch?
Anm.: habe gerade gesehen, daß ich den
1
 HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc_value, 4);
nur einmal machen sollte, wenn ich continous mode wähle. Aber auch, wenn 
ich den Start vor die Schleife lege, bringt es nichts.

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?


von Christoph K. (chriskuku)


Lesenswert?

Harry L. schrieb:
> Schau dir das mal an:
> https://www.youtube.com/watch?v=0jKtgP4OYvU

War heute schon meine Morgenlektüre. Und die Behauptung dort, WORD statt 
HALF WORD sei erforderlich für 12bit ADC-Konversion, ist falsch. Ich 
habe HALF WORD genommen und mein DMA-Buffer sind 4 16bit Worte.

Und nach diesem Video habe ich meine Anwedung auch erstellt. Habe jetzt 
auch noch mal mit WORD statt HALFWORD probiert. Keine Änderung. Mit 2 
blue pills (beides cheapo chinese) probiert.

Werde es jetzt noch mal auf einem STM32407G DISC1 probieren.

: Bearbeitet durch User
von Christian (christiankpunkt)


Angehängte Dateien:

Lesenswert?

Hier ein Auszug aus meiner Library, ich verende keine HAL-Funktionen.

Mit "void STM32F1_ADC_init(void)" wird der ADC so konfiguriert, das er 
kontinuierlich die ersten 3 (ist über ein define anpassbar) Channels 
einliest und es über dem DMA im Ram ablegt.

Mit "uint16 STM32F1_ADC_getRegularGroupe1(uint8_fast channel)" kann man 
jeweils den letzten gemessenen ADC-Wert abfragen.

Läuft komplett im Hintergrund, und dank DMA ohne Interrupt Routinen.

von Bauform B. (bauformb)


Lesenswert?

Die meisten STM32-ADCs haben 4+1 Register für die Ergebnisse, also 
braucht man für max. 5 Kanäle kein DMA. Ob man die Daten aus dem RAM 
oder aus den ADC-Registern abholt, ist doch relativ egal.

von Christoph K. (chriskuku)


Lesenswert?

Danke an Christian(k.) für die Zurverfügungstellung seiner 
Library-Routinen. Es ist sicher gut, wenn man alles auf Low-Level 
versteht und nur damit kann man im Grunde das Funktionieren erzwingen. 
Denn das Manual ist schließlich sowas wie die "Bibel".
Ich werde versuchen, zu einem späteren Zeitpunkt da mich noch mal 
hineinzuknien, um es mit DMA zu lösen, weil das auch m.E. die 
flexibelste Methode ist und man einige Sachen leichter machen kann wie 
double buffering und Durchschnittswertbildung. Ich bin doch jetzt erst 
mal @(bauformb)s Rat gefolgt und habe es mit diskreten 
Konversionsaufrufen gelöst. Es ist wirklich manchmal zum Haareraufen, 
wenn man dann z.B. auf ein Tutorial, wie dieses- 
https://youtu.be/5l-b6lsubBE stößt und darin werden dann erst mal die 
HAL_Routinen zerpflückt und noch einige Parameter, die MX erzeugt hat, 
händisch geändert (wehe, man muß MX noch mal wegen was anderem 
aufrufen). Zum Schluß - nachdem ich erst noch meine blue pill mit 
STM32duino verifiziert habe (wieviel leichter kommt da ein 
analogRead(analogPin) daher) - funktionierte es irgendwie, daß meine 4 
Werte in den richtigen Töpfen landeten.

Danke jedenfalls noch mal.
1
/* USER CODE BEGIN 0 */
2
void ADC_Select_CH0(void) {
3
  ADC_ChannelConfTypeDef sConfig = {0};
4
   sConfig.Channel = ADC_CHANNEL_4;
5
    sConfig.Rank = 1;
6
    sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES_5;
7
    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
8
    {
9
      Error_Handler();
10
    }
11
}
12
 /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
13
 */
14
void ADC_Select_CH1(void) {
15
  ADC_ChannelConfTypeDef sConfig = {0};
16
  sConfig.Channel = ADC_CHANNEL_5;
17
    sConfig.Rank = 1;
18
    sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES_5;
19
    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
20
    {
21
      Error_Handler();
22
    }
23
24
}
25
 /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
26
 */
27
void ADC_Select_CH2(void) {
28
  ADC_ChannelConfTypeDef sConfig = {0};
29
  sConfig.Channel = ADC_CHANNEL_6;
30
  sConfig.Rank = 1;
31
  sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES_5;
32
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
33
  {
34
    Error_Handler();
35
  }
36
37
}
38
 /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
39
 */
40
void ADC_Select_CH3(void) {
41
  ADC_ChannelConfTypeDef sConfig = {0};
42
  sConfig.Channel = ADC_CHANNEL_7;
43
  sConfig.Rank = 1;
44
  sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES_5;
45
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
46
  {
47
    Error_Handler();
48
  }
49
}
50
/* USER CODE END 0 */
51
static void MX_ADC1_Init(void)
52
{
53
54
  /* USER CODE BEGIN ADC1_Init 0 */
55
  /* USER CODE END ADC1_Init 0 */
56
  //ADC_ChannelConfTypeDef sConfig = {0};
57
  /* USER CODE BEGIN ADC1_Init 1 */
58
  /* USER CODE END ADC1_Init 1 */
59
  /** Common config
60
  */
61
  hadc1.Instance = ADC1;
62
  hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
63
  hadc1.Init.ContinuousConvMode = DISABLE;
64
  hadc1.Init.DiscontinuousConvMode = DISABLE;
65
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
66
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
67
  hadc1.Init.NbrOfConversion = 1;
68
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
69
  {
70
    Error_Handler();
71
  }
72
 /* USER CODE BEGIN ADC1_Init 2 */
73
74
 /* USER CODE END ADC1_Init 2 */
75
}
76
void StartTask3(void *argument)
77
{
78
  /* USER CODE BEGIN StartTask3 */
79
    // ADC CAlibration
80
    HAL_ADCEx_Calibration_Start(&hadc1);
81
    osDelay(500);
82
      uart1_print("\nStart...\n");
83
    /* Infinite loop */
84
    for(;;)
85
   {
86
87
       char str[32];
88
       ADC_Select_CH0();
89
       HAL_ADC_Start(&hadc1);
90
       HAL_ADC_PollForConversion(&hadc1, 1000);
91
       adc_value[0] = HAL_ADC_GetValue(&hadc1);
92
       HAL_ADC_Stop(&hadc1);
93
94
       ADC_Select_CH1();
95
       HAL_ADC_Start(&hadc1);
96
       HAL_ADC_PollForConversion(&hadc1, 1000);
97
       adc_value[1] = HAL_ADC_GetValue(&hadc1);
98
       HAL_ADC_Stop(&hadc1);
99
100
       ADC_Select_CH2();
101
       HAL_ADC_Start(&hadc1);
102
       HAL_ADC_PollForConversion(&hadc1, 1000);
103
       adc_value[2] = HAL_ADC_GetValue(&hadc1);
104
       HAL_ADC_Stop(&hadc1);
105
106
       ADC_Select_CH3();
107
       HAL_ADC_PollForConversion(&hadc1, 1000);
108
       adc_value[3] = HAL_ADC_GetValue(&hadc1);
109
       HAL_ADC_Stop(&hadc1);
110
       osDelay(2000);;
111
       sprintf(str,"ADC: %d %d %d %d\n",adc_value[0],adc_value[1],adc_value[2],adc_value[3]);
112
       uart1_print(str);
113
    }

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

Genauso wenig wie du den sinnvollen Hinweis "Längeren Sourcecode nicht 
im Text einfügen, sondern als Dateianhang" verstanden hast, hast du die 
HAL und deren Benutzung verstanden, sonst würdest du so einen Blödsinn:

Christoph K. schrieb:
> und darin werden dann erst mal die
> HAL_Routinen zerpflückt und noch einige Parameter, die MX erzeugt hat,
> händisch geändert (wehe, man muß MX noch mal wegen was anderem
> aufrufen).
nicht schreiben.

CubeMX kannst du zu jeder Zeit deinen Code neu generieren lassen, ohne 
deinen eigenen Code zu kompromittieren - vorausgesetzt, du hälst dich an 
bestimmte Konventionen.

: Bearbeitet durch User
von Christoph K. (chriskuku)


Lesenswert?

Harry L. schrieb:
> Genauso wenig wie du den sinnvollen Hinweis "Längeren Sourcecode nicht
> im Text einfügen, sondern als Dateianhang" verstanden hast, hast du die
> HAL und deren Benutzung verstanden, sonst würdest du so einen Blödsinn:
>

Gut, gebe ich zu. Sollte man nicht machen und lasse ich in Zukunft.

> Christoph K. schrieb:
>> und darin werden dann erst mal die
>> HAL_Routinen zerpflückt und noch einige Parameter, die MX erzeugt hat,
>> händisch geändert (wehe, man muß MX noch mal wegen was anderem
>> aufrufen).
> nicht schreiben.
>
> CubeMX kannst du zu jeder Zeit deinen Code neu generieren lassen, ohne
> deinen eigenen Code zu kompromittieren - vorausgesetzt, du hälst dich an
> bestimmte Konventionen.

Zum Thema "Blödsinn": in dem Tutorial, auf das ich mich bezog, wurde 
nachträglich händisch noch ein Parameter in der MX_ADC1_Init() geändert.
Und genau bei dieser neuen Codegenerierung wird dann diese Routine 
wieder  überschrieben. Nichts anderes meinte ich. Daß der Usercode 
geschützt ist durch die Kommentarbereiche, ist klar.

: Bearbeitet durch User
von Rahul D. (rahul)


Lesenswert?

Christoph K. schrieb:
> Und genau bei dieser neuen Codegenerierung wird dann diese Routine
> wieder  überschrieben. Nichts anderes meinte ich.

Deswegen kann man die Parameter ja auch in CubeMX setzen, um zu 
verhindern, dass sie überschrieben werden.

von Christoph K. (chriskuku)


Lesenswert?

Rahul D. schrieb:
> Christoph K. schrieb:
>> Und genau bei dieser neuen Codegenerierung wird dann diese Routine
>> wieder  überschrieben. Nichts anderes meinte ich.
>
> Deswegen kann man die Parameter ja auch in CubeMX setzen, um zu
> verhindern, dass sie überschrieben werden.

Aber es schien mir hier - so wurde es im Tutorial vorgeführt -, daß 
zunächst die 4 eingegeben werden muß im MX, damit die 4 
Channelinitialisierungen generiert werden. Die wurden dann in der Init 
auskommentiert, daraus 4 einzelne gemacht und die 4 wurde dann wieder in 
eine 1 geändert.

von Rahul D. (rahul)


Lesenswert?

Christoph K. schrieb:
> Aber es schien mir hier - so wurde es im Tutorial vorgeführt -, daß
> zunächst die 4 eingegeben werden muß im MX, damit die 4
> Channelinitialisierungen generiert werden. Die wurden dann in der Init
> auskommentiert, daraus 4 einzelne gemacht und die 4 wurde dann wieder in
> eine 1 geändert.

Frei nach Hulk: "Mickriges Tutorial"
Wenn darin Sachen gemacht werden, ohne sie zu erklären.
Oder manb sie unhinterfragt einfach so übernimmt.

von Christoph K. (chriskuku)


Angehängte Dateien:

Lesenswert?

Ich komme noch mal auf den low level code von christiankpunkt zurück, 
nachdem ich mit allen Versuchen mit HAL und LL gescheitert bin. Ich 
kriege es einfach nicht hin, 4 ADC-Werte an PA4-PA7 auszulesen. Habe die 
Hardware (STM32F103C8T6, blue pill) noch mal mit STM32duino verifiziert. 
Aber mit STM32CubeIDE klappt es einfach nicht. Ich bekomme immer 4 
gleiche Werte. Jetzt habe ich Christians Code in ein 
STM32CubeIDE-Projekt (main.c) eingebaut. Funktioniert aber immer noch 
nicht. Immer 4 ähnliche Werte im Bereich um 2048. Sie müßten aber etwa 
sowas ergeben (nur ein Eingang an Poti, die anderen 3 an GND):
1
4086 2 0 0
2
4092 1 0 0
3
4092 0 8 0
4
4089 0 0 0

: Bearbeitet durch User
von Wastl (hartundweichware)


Lesenswert?

Christoph K. schrieb:
> Wie lade ich am besten das ganze Projekt als CubeIDE-Projekt hoch, daß
> sich das vielleicht mal jemand ansehen kann? Als ZIP?

Ganzen Projekt-Ordner zippen, vorher ein Clean Project auslösen.

von Christoph K. (chriskuku)


Lesenswert?

Wastl schrieb:
> Christoph K. schrieb:
>> Wie lade ich am besten das ganze Projekt als CubeIDE-Projekt hoch, daß
>> sich das vielleicht mal jemand ansehen kann? Als ZIP?
>
> Ganzen Projekt-Ordner zippen, vorher ein Clean Project auslösen.

Danke. Hatte ich dann auch so gemacht und meinen Beitrag editiert :)

von Christian (christiankpunkt)


Lesenswert?

Christoph K. schrieb:
> Ich komme noch mal auf den low level code von christiankpunkt zurück

STM32F1_DMA1_configChannel1ForADC1() und STM32F1_DMA1_startChannel1() 
werden von STM32F1_ADC_init() aufgerufen.
Ruf die STM32F1_ADC_init() erst nach dem STM32F1_DMA_init() Funktionen 
auf.

Bei STM32F1_ADC_getRegularGroupe1(...) hat der erste Channel den Index 0

Wenn du nicht die ADC0 bis 2 nimmst, must du den setSQR(...) Aufruf 
anpassen, also für ADC4 bis 7:
setSQR(ADC1, REGULAR_GROUP_COUNT - 1, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0);

Und setze das define REGULAR_GROUP_COUNT auf 4

: Bearbeitet durch User
von Christoph K. (chriskuku)


Lesenswert?

Christian schrieb:
...
> Bei STM32F1_ADC_getRegularGroupe1(...) hat der erste Channel den Index 0
>
> Wenn du nicht die ADC0 bis 2 nimmst, must du den setSQR(...) Aufruf
> anpassen, also für ADC4 bis 7:
> setSQR(ADC1, REGULAR_GROUP_COUNT - 1, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0,
> 0, 0, 0, 0, 0);
>
> Und setze das define REGULAR_GROUP_COUNT auf 4

Danke. Das hat schon viel gebracht. Der DMA-Puffer (adc_value[]) sieht 
nun gut aus. Die Rückgabewerte von STM32F1_ADC_getRegularGroupe1(...) 
sind allerdings noch nicht in Ordnung. Habe es mit uint16_t und uint32_t 
versucht.


Sehe gerade, daß in der STM32F1_ADC_init bereits ein
1
STM32F1_DMA1_configChannel1ForADC1(REGULAR_GROUP_COUNT, (uint16*) regularGroup1);
2
STM32F1_DMA1_startChannel1();


gemacht wird. Und außerhalb noch mal?

OK, läuft jetzt. Da gibt es ja schon den DMA-Puffer regularGroup1[]. Der 
war nur static und im main nicht bekannt. Jetzt nehme ich den Puffer und 
es funktioniert jetzt. Danke noch mal.

: Bearbeitet durch User
von Christoph K. (chriskuku)


Lesenswert?

Und noch was zum Verständnis: das Ganze läuft ohne DMA-Interrupt, 
richtig?

Kann man die Rate, mit der der DMA läuft, irgendwie steuern? Hängt ja 
mit der ADC-Samplerate zusammen, nehme ich an.

: Bearbeitet durch User
von Christian (christiankpunkt)


Lesenswert?

Läuft ohne Interrupt.
Der DMA wird automatisch vom ADC getriggert, wenn der mit dem Sampling 
fertig ist.

Mein Code ist halt sehr Hardware nah. Muss man dann natürlich ins 
Datenblatt schauen um zu wissen was die Parameter machen.

: Bearbeitet durch User
Beitrag #7385893 wurde vom Autor gelöscht.
von Harry L. (mysth)


Angehängte Dateien:

Lesenswert?

Probier das mal!

von Harry L. (mysth)


Lesenswert?

Achja...ich vergass:
* Zip  entpacken
* Im CubeIDE "Import existing projekt" und Verz. wählen
* .ioc-Datei öffen
* Code neu generieren

Danach sollte das vollständig sein.

: Bearbeitet durch User
von Christoph K. (chriskuku)


Lesenswert?

Harry L. schrieb:
> Achja...ich vergass:
> * Zip  entpacken
> * Im CubeIDE "Import existing projekt" und Verz. wählen
> * .ioc-Datei öffen
> * Code neu generieren
>
> Danach sollte das vollständig sein.

Krieg beim starten des Debug launchers:

/Applications/STM32CubeIDE.app/Contents/Eclipse/plugins/com.st.stm32cube 
.ide.mcu.externaltools.gnu-tools-for-stm32.10.3-2021.10.macos64_1.0.200. 
202301161003/tools/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-n 
one-eabi/bin/ld:  warning: cannot find entry symbol Reset_Handler; 
defaulting to 0000000008000000

Liegt's vielleicht daran, daß ich ein ST32F103C8T6 habe und das .ioc für 
R8Tx ist? Kann ich die MCU im .ioc umschalten, sozusagen "mitten im 
Strom die Pferde wechseln"?

von Harry L. (mysth)


Lesenswert?

Christoph K. schrieb:
> Kann ich die MCU im .ioc umschalten, sozusagen "mitten im
> Strom die Pferde wechseln"?

Nein, das geht leider nicht.

Dann hilft wohl nur ein neues Projekt anzulegen, und alle Einstellungen 
des ADC0 und TIM3 exakt zu übernehmen.
Die main.c solltest du verwenden können.

Das Einfachste wird es sein, aus dem .ioc-Projekt einen PDF-Report uzu 
generieren.
Da sollte alles Notwendige enthalten sein.

: Bearbeitet durch User
von Christoph K. (chriskuku)


Lesenswert?

PDF-Report. Ja, nützliche Sache. Kann man im Project-Manager ein Projekt 
kopieren/duplizieren (so, wie es in anderen Baumansichten möglich ist) ?

Geht wohl nicht so einfach. Habe im Filesystem den ganzen Baum kopiert, 
umbenannt und dann importiert.

: Bearbeitet durch User
von Christoph K. (chriskuku)


Lesenswert?

Habe noch ein kleines Verständnisproblem: in dem Projekt war ja nur eine 
main.c. Wer ruft die
1
 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
2
{
3
        /* Toggle LED */
4
        HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
5
        data_ready = 1;
6
}
auf? Muß die nicht in die DMA-IR? Und was ist mit der TIM3-IR? ADC 
global IR ist ja nicht aktiv.
Verstehe es jetzt so: TIM3 IR startet den
1
HAL_ADC_Start_DMA(&hadc1, (uint32_t*) &adc_buffer, 4);

jedesmal neu.

: Bearbeitet durch User
von Christoph K. (chriskuku)


Angehängte Dateien:

Lesenswert?

Hier ist jetzt meine Fassung für STM32F103C8T6 (blue pill).
Was mir nicht in den Kopf will: ich habe folgende Belegung an den 
Analogeingängen:
1
A4 - Poti Schleifer zwischen 3,3V und GND
2
A5 - GND
3
A6 - GND
4
A7 - GND
in dem Ergebnisarray stehen die Werte (Watchexpression) beim ersten Stop
in main.c, Zeile 112 (vor data_ready=0) wie folgt (also auch wie 
erwartet):
1
adc_buffer[0]   3899
2
adc_buffer[1]   0
3
adc_buffer[2]   0
4
adc_buffer[3]   0

Beim nächsten und allen weiteren Stops:
1
adc_buffer[0]   0
2
adc_buffer[1]   0
3
adc_buffer[2]   0
4
adc_buffer[3]   3959   <<<<<<<<< ????

Also, auf dem falschen Platz. Bug im HAL, CubeIDE?

(tut mir leid, daß der Name mit Rtos endet. Hat momentan noch nichts 
dmit zu tun)

von Harry L. (mysth)


Lesenswert?

Christoph K. schrieb:
> Habe noch ein kleines Verständnisproblem: in dem Projekt war ja nur eine
> main.c. Wer ruft die
>
>
1
>  void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
2
> {
3
>         /* Toggle LED */
4
>         HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
5
>         data_ready = 1;
6
> }
7
>
> auf? Muß die nicht in die DMA-IR? Und was ist mit der TIM3-IR? ADC
> global IR ist ja nicht aktiv.
> Verstehe es jetzt so: TIM3 IR startet den
>
>
1
> HAL_ADC_Start_DMA(&hadc1, (uint32_t*) &adc_buffer, 4);
2
>
>
> jedesmal neu.

Diese Callbacks wirst du in der HAL überall finden.
Die wersden aus den Interrupts heraus aufgerufen.

von Harry L. (mysth)


Lesenswert?

Offensichtlich hast du versäumt, die anzahl der DMA-Zyklen anzupassen.
1
  HAL_ADC_Start_DMA(&hadc1, (uint32_t*) &adc_buffer, 5);
2
                                                     ^
Für 4 Kanäle sollte da auch 4 stehen.

: Bearbeitet durch User
von Christoph K. (chriskuku)


Lesenswert?

Harry L. schrieb:
> Christoph K. schrieb:
>...

> Diese Callbacks wirst du in der HAL überall finden.
> Die wersden aus den Interrupts heraus aufgerufen.

Z.T. muß man die aber auch händisch dort eintragen oder nicht?

von Christoph K. (chriskuku)


Lesenswert?

Harry L. schrieb:
> Offensichtlich hast du versäumt, die anzahl der DMA-Zyklen anzupassen.
>
1
>   HAL_ADC_Start_DMA(&hadc1, (uint32_t*) &adc_buffer, 5);
2
>                                                      ^
3
>
> Für 4 Kanäle sollte da auch 4 stehen.

Wo stand der denn jetzt noch? Ich hatte das schon gesehen und 
korrigiert. Steht das jetzt in dem hochgeladenen Projekt noch so?

von Harry L. (mysth)


Lesenswert?

Christoph K. schrieb:
> Harry L. schrieb:
>> Christoph K. schrieb:
>>...
>
>> Diese Callbacks wirst du in der HAL überall finden.
>> Die wersden aus den Interrupts heraus aufgerufen.
>
> Z.T. muß man die aber auch händisch dort eintragen oder nicht?

Nein, muß man nicht.
Die Funktionen gibt es bereits mit einer __weak-Deklaration

Sobald du die Funktion selbst definierst, überschreibst du die.

von Harry L. (mysth)


Lesenswert?

Christoph K. schrieb:
> Harry L. schrieb:
>> Offensichtlich hast du versäumt, die anzahl der DMA-Zyklen anzupassen.
>>>   HAL_ADC_Start_DMA(&hadc1, (uint32_t*) &adc_buffer, 5);
>>                                                      ^
>>
>> Für 4 Kanäle sollte da auch 4 stehen.
>
> Wo stand der denn jetzt noch? Ich hatte das schon gesehen und
> korrigiert. Steht das jetzt in dem hochgeladenen Projekt noch so?

Direkt vor der Loop in main()

: Bearbeitet durch User
von Christoph K. (chriskuku)


Lesenswert?

Harry L. schrieb:
> Christoph K. schrieb:
>> Harry L. schrieb:
>>> Offensichtlich hast du versäumt, die anzahl der DMA-Zyklen anzupassen.
>>>>   HAL_ADC_Start_DMA(&hadc1, (uint32_t*) &adc_buffer, 5);
>>>                                                      ^
>>>
>>> Für 4 Kanäle sollte da auch 4 stehen.
>>
>> Wo stand der denn jetzt noch? Ich hatte das schon gesehen und
>> korrigiert. Steht das jetzt in dem hochgeladenen Projekt noch so?
>
> Direkt vor der Loop in main()

Entschuldige, ich habe jetzt mein eigenes Projekt noch mal runtergeladen
und im main.c vor der while() loop nachgeguckt: da steht
1
  HAL_ADC_Start_DMA(&hadc1, (uint32_t*) &adc_buffer, 4);

: Bearbeitet durch User
von Harry L. (mysth)


Angehängte Dateien:

Lesenswert?

Dein Timer und ADC waren noch falsch konfiguriert.

von Christoph K. (chriskuku)


Lesenswert?

Harry L. schrieb:
> Dein Timer und ADC waren noch falsch konfiguriert.

Der Fehler mit dem springenden DMA-Bufferplatz besteht weiter. Zumindest 
im Debugger in der Expression View. Nein, auch im Programm selbst. Bei 
allen weiteren Zyklen landet der ADC-Wert im adc_buffer[3].
1
        while (1) {
2
                if (data_ready) {
3
                        // do something with adc-data
4
                  if(adc_buffer[0] > 100) {
5
 (bkpt)                   adc_buffer[1] = 555;
6
                  }
7
                        data_ready = 0;
8
                }
9
10
        }
Beim ersten Lauf stoppt das Programm bei bkpt. Danach kommt es nie mehr 
dahin. Schon sehr merkwürdig. Wird ja wohl nicht an meinem BMP GDB 
Debugger liegen?

: Bearbeitet durch User
von Gebhard R. (Firma: Raich Gerätebau & Entwicklung) (geb)


Lesenswert?

Christoph K. schrieb:
> Wird ja wohl nicht an meinem BMP GDB
> Debugger liegen?

Mit Debugger mußt du nach jedem Stop neu reseten, sonst kommt die 
Kanalzuordnung durcheinander.
Ich hab solche DMA Geschichten schon oft gemacht, allerdings nicht mit 
HAL.Dort hab ich aber den DMA Interrupt ausgewertet und musste den DMA 
Zähler und pointer für Wechselbuffer neu setzen. Weiss nicht ob dir das 
der HAL abnimmt.
Grüsse

von Christoph K. (chriskuku)


Lesenswert?

Gebhard R. schrieb:
> Christoph K. schrieb:
>> Wird ja wohl nicht an meinem BMP GDB
>> Debugger liegen?
>
> Mit Debugger mußt du nach jedem Stop neu reseten, sonst kommt die
> Kanalzuordnung durcheinander.
> Ich hab solche DMA Geschichten schon oft gemacht, allerdings nicht mit
> HAL.Dort hab ich aber den DMA Interrupt ausgewertet und musste den DMA
> Zähler und pointer für Wechselbuffer neu setzen. Weiss nicht ob dir das
> der HAL abnimmt.
> Grüsse

Danke für den Hinweis. Was genau meinst Du mit "resetten".

von Gebhard R. (Firma: Raich Gerätebau & Entwicklung) (geb)


Lesenswert?

Christoph K. schrieb:
> Was genau meinst Du mit "resetten".

Das Programm von Anfang an neu starten.

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.