Forum: Mikrocontroller und Digitale Elektronik STM32 HAL Timer Interrupts (STM32CubeF4)


von Christian (Gast)


Lesenswert?

hi, ich habe bereits viel mit 8-Bit AVRs gemacht,
und mache jetzt meine ersten Erfahrungen an einem STM32.

Habe hier ein "WaveShare Core 4171" mit einem STM32F407 auf einem 
"WaveShare Open 4171" Breakout-Board.

Toolchain mit GCC, Eclipse und JTAG-Debugger läuft.

Mein erstes Programm wo ich die GPIOs ansteuere funktioniert.

Jetzt wollte ich einen Timer-Interrupt haben der alle 8ms aufgerufen 
wird.

Aber die Interrupt-Callback-Funkltion wird nicht aufgerufen.

Hab ich irgendwas vergessen?
Timer mit Clock-Quelle verbinden.
Interrupts global erlauben?

Die Dokumentation der STM32CubeF4-HAL ist leider nicht so toll.

Der Aufruf von HAL_TIM_Base_GetState() gibt 1 (Peripheral Initialized 
and ready for use) zurück
1
#include <stm32f4xx_hal.h>
2
#include <diag/Trace.h>
3
4
TIM_HandleTypeDef hT4;
5
6
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
7
  HAL_GPIO_WritePin(GPIOH, 0b00000100, GPIO_PIN_RESET);
8
}
9
10
void init(void) {
11
  /* ### GPIO ####################################################################################### GPIO ### */
12
  __HAL_RCC_GPIOH_CLK_ENABLE();
13
  GPIO_InitTypeDef GPIO_InitStructure;
14
  GPIO_InitStructure.Pin = 0b00001100;
15
  GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
16
  GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
17
  GPIO_InitStructure.Pull = GPIO_PULLUP;
18
  HAL_GPIO_Init(GPIOH, &GPIO_InitStructure);
19
20
  // Start with leds turned on
21
  HAL_GPIO_WritePin(GPIOH, 0b00001100, GPIO_PIN_SET);
22
23
  /* ### Timer ##################################################################################### Timer ### */
24
  __HAL_RCC_TIM4_CLK_ENABLE();
25
  hT4.Instance = TIM4;
26
  hT4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV4; // 168 MHz / 4 = 42 MHz
27
  hT4.Init.Prescaler = 419; // 42 MHz / (419 + 1) = 100 KHz
28
  hT4.Init.Period = 799; // 100 KHz / (799 + 1) = 125 Hz
29
  hT4.Init.CounterMode = TIM_COUNTERMODE_UP;
30
  hT4.Init.RepetitionCounter = 0;
31
  HAL_TIM_Base_Init(&hT4);
32
  //HAL_TIM_Base_Start(&hT4);
33
  HAL_TIM_Base_Start_IT(&hT4);
34
}
35
36
void loop(void) {
37
  static unsigned int i = 0;
38
  i++;
39
  if ((i & 0x00FFFFFF) == 0x00800000) {
40
    HAL_GPIO_WritePin(GPIOH, 0b00001000, GPIO_PIN_SET);
41
    //trace_puts("Alive");
42
    trace_printf("Timer4 state: %i\n", HAL_TIM_Base_GetState(&hT4));
43
    HAL_TIM_StateTypeDef x;
44
  }
45
46
  if ((i & 0x00FFFFFF) == 0x00000000) {
47
    HAL_GPIO_WritePin(GPIOH, 0b00001000, GPIO_PIN_RESET);
48
  }
49
}
50
51
// ----- main() ---------------------------------------------------------------
52
53
// Sample pragmas to cope with warnings. Please note the related line at
54
// the end of this function, used to pop the compiler diagnostics status.
55
#pragma GCC diagnostic push
56
#pragma GCC diagnostic ignored "-Wunused-parameter"
57
#pragma GCC diagnostic ignored "-Wmissing-declarations"
58
#pragma GCC diagnostic ignored "-Wreturn-type"
59
60
int main(int argc, char* argv[]) {
61
  // At this stage the system clock should have already been configured
62
  // at high speed.
63
64
  init();
65
66
  // Infinite loop
67
  while (1) {
68
    loop();
69
  }
70
}
71
72
#pragma GCC diagnostic pop
73
74
// ----------------------------------------------------------------------------

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Christian schrieb:
> GPIO_InitStructure.Pin = 0b00001100;

So etwas kann beim STM32 funktionieren, muss aber nicht, denn sowohl 
CMSIS als auch HAL/Cube erwarten hier ein 16-bit Argument. Nimm lieber 
die 'GPIO_Pin_3' und 'GPIO_Pin_4' Definitionen, denn dafür sind sie da. 
Das gleiche kommt in deinem Code noch woanders vor.
Also
1
 GPIO_InitStructure.Pin = GPIO_Pin_3 | GPIO_Pin_4 ;
Dann sehe ich in deinem Code keine Initialisierung des NVIC. Der wird 
für Interrupts benötigt. In CMSIS Syntax sieht das ungefähr so aus:
1
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
2
  TIM_ClearITPendingBit(TIM4, TIM_IT_Update);   // clr any pending irqs
3
  TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);    // lets enable update events
4
  NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
5
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0b;
6
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
7
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   // ready to run
8
  NVIC_Init(&NVIC_InitStructure);
hier mal für Timer 4. Erst dann kann der Timer periodisch IRQs auslösen, 
in diesem Fall beim Update Event.

: Bearbeitet durch User
von Christian (Gast)


Lesenswert?

Danke für die Info, das wird mir sicher weiterhelfen,

jetzt muss ich mal schauen wo die HAL-Äquivalent zu den CMSIS-Aufrufen 
sind.

von Christian (Gast)


Lesenswert?

Es geht jetzt.

Die HAL-Funktionen habe ich gefunden
1
HAL_NVIC_SetPriority(TIM4_IRQn, 4, 0);
2
HAL_NVIC_EnableIRQ(TIM4_IRQn);

und die ISR musst auch ändern:

statt HAL_TIM_PeriodElapsedCallback()
habe ich jetzt
1
void TIM4_IRQHandler(void) {
2
  static int i = 0;
3
  i++;
4
  if (i == 125) {
5
    HAL_GPIO_WritePin(GPIOH, 0b00000100, GPIO_PIN_RESET);
6
  }
7
  if (i == 250) {
8
    HAL_GPIO_WritePin(GPIOH, 0b00000100, GPIO_PIN_SET);
9
    i = 0;
10
  }
11
  
12
  HAL_TIM_IRQHandler(&hT4);
13
}


Die Makros GPIO_Pin_x usw. sind aus CMSIS. Jetzt mal schauen ob es in 
der HAL auch welche dafür gibt.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Christian schrieb:
> HAL_TIM_Base_Start_IT(&hT4);

Wenn ich HAL richtig kapiere, sollte das eigentlich die ISR 
Initialisierung erledigen, so das das Problem evtl. wirklich nur die 
GPIO Definition betrifft.
Bin aber wirklich mit HAL auf Kriegsfuss - schon CMSIS geht mir über die 
Hutschnur.
Edit: Ahh, lese jetzt dein letztes Posting - fein, das es klappt.
Übrignes gibt es bei einigen STM32 ein Problem mit dem Rumfummeln an 
GPIOs in ISR Routinen, wenn man nicht vorher schon das IT Bit löscht. 
Das betrifft aber eher externe Interrupts - sollte man aber dran 
denken,z.B. so:
1
void EXTI9_5_IRQHandler(void)
2
{
3
  if(EXTI_GetITStatus(PLAY_EXTI_LINE) != RESET)
4
  {
5
 /* Clear the EXTI line pending bit */
6
    EXTI_ClearITPendingBit(PLAY_EXTI_LINE);
7
    if (!fastFlags.PlayUpdate) {
8
        fastFlags.PlayUpdate = TRUE;
9
        DRIVE_GPIO_PORT->ODR ^= REEL_SENSOR_PIN;
10
    }
11
  }
12
}

: Bearbeitet durch User
von Christian (Gast)


Lesenswert?

Das nächste Problem,
meine ISR wird um den Faktor 2 zu häufig aufgerufen, sprich mit 250Hz 
statt 125Hz.

Ist der Timer-Takt ein andere als der CPU-Takt?

Der CPU-Takt sollte vom Startup-Code auf 168Mhz eingestellt sein.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Christian schrieb:
> Ist der Timer-Takt ein andere als der CPU-Takt?

Oh, ja. Schau dir mal den Clock Tree im Reference Manual an (RM0090) auf 
Seite 212/1713, dort steht auch, das die Timer von APB1 oder APB2 
angetrieben werden, typisch 1/2 oder 1/4 CPU Clock. Wie genau die 
Vorteiler stehen, kannst du mittels der SystemClock_Config() einstellen, 
aber voller CPU Takt geht nicht.

: Bearbeitet durch User
von Christian (Gast)


Lesenswert?

OK, also wenn die maximale Timer-Clock, 1/2 CPU-Clock ist, dann läuft 
mein Timer sogar um den Faktor 4 zu schnell.

Also, so als ob diese Zeile kein Effet hat.
1
hT4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV4;

Dann werde ich mir mal Reference Manual reinziehen.

von Christian (Gast)


Lesenswert?

Jep, hab mal ClockDivision auf 0 gesetzt und Blinkt immer noch genau so 
schnell.

von Jens E. (surfjenser)


Lesenswert?

In CubeMx kann man sich ja auch grafisch ganz gut ansehen, wie sie die 
Clocks zusammensetzen

von Sebastian V. (sebi_s)


Lesenswert?

Matthias S. schrieb:
> Christian schrieb:
>> GPIO_InitStructure.Pin = 0b00001100;
>
> So etwas kann beim STM32 funktionieren, muss aber nicht, denn sowohl
> CMSIS als auch HAL/Cube erwarten hier ein 16-bit Argument. Nimm lieber
> die 'GPIO_Pin_3' und 'GPIO_Pin_4' Definitionen

Tatsächlich ist Pin eine 32-bit Variable, was einem als C-Programmierer 
aber auch egal sein kann, da sowieso automatisch konvertiert wird. 
Interessanter ist eher die Frage ob das Bitmuster immer stimmt. Daher 
würde ich auch eher zu den Defines raten, allerdings meintest du wohl 
'GPIO_PIN_2' und 'GPIO_PIN_3', denn hier wird bei 0 angefangen zu 
zählen!

: Bearbeitet durch User
von Steffen R. (steffen_rose)


Lesenswert?

Sebastian V. schrieb:
> Tatsächlich ist Pin eine 32-bit Variable, was einem als C-Programmierer
> aber auch egal sein kann, da sowieso automatisch konvertiert wird.

Darüber, dass die automatische Konvertierung manchmal nicht so 
konvertiert, wie es der unerfahrene C-Programmierer erwartet, ist schon 
so mancher gestolpert.

von Sebastian V. (sebi_s)


Lesenswert?

Steffen R. schrieb:
> Darüber, dass die automatische Konvertierung manchmal nicht so
> konvertiert, wie es der unerfahrene C-Programmierer erwartet, ist schon
> so mancher gestolpert.

Wenn man nicht gerade signed und unsigned mischt kann bei der 
Konvertierung zu größeren Datentypen eigentlich nichts schiefgehen. Bei 
signed zu unsigned gleicher Größe ist auch alles gut wenn man keine 
negativen Werte hat.

von Steffen R. (steffen_rose)


Lesenswert?

Sebastian V. schrieb:
> Wenn man nicht gerade signed und unsigned mischt

>> GPIO_InitStructure.Pin = 0b00001100;

Pin sollte unsigned sein.

0b00001100 naja, dürfte implementierungsspezifisch sein. GGf als int und 
somit signed interpretiert werden.
Üblich angewendet werden hex und binär eher als unsigned.

Ich wäre mir hier zumindest unsicher. Aber das trägt nichts zum Thema 
bei.

von Sebastian V. (sebi_s)


Lesenswert?

Steffen R. schrieb:
> Üblich angewendet werden hex und binär eher als unsigned.

Richtig. Das hat man sich beim Standardkomitee auch wohl bedacht. Daher 
hat 0x7FFFFFFF den Typ int (wenn int 32Bit groß ist) und 0x80000000 den 
Typ unsigned int. In dem 0x7FFFFFFF Fall und alle kleineren Zahlen ist 
es aber auch kein Problem wenn der Wert zu unsigned konvertiert wird, da 
0x7FFFFFFF nicht negativ ist und daher garantiert in einen unsigned int 
passt. Für binary wird es ähnlich sein, auch wenn es nicht 
standardisiert ist. Wenn man sich unsicher ist kann man ja immer noch 
ein 'u' anhängen.

: Bearbeitet durch User
von Martin M. (murmele)


Lesenswert?

Ich versuche derzeit auch den Timer mit Interrupt zum laufen zu 
bekommen. Doch bei mir springt er dauernd in den Default Handler. Warum 
wird mein TIM2_IRQHandler nicht erkannt? Ist die 
"HAL_TIM_PeriodElapsedCallback"-Funktion die in den Beispielen von ST 
verwendet wird, für alle Timer gleichzeitig? In den Beispielen 
funktioniert der Timer auch ohne HAL_NVIC_EnableIRQ(TIM2_IRQn);
1
 //TIM2: APB1
2
// Timer channel 2 as base timer
3
void timer2Init()
4
{
5
  /* Variables */
6
  TIM_HandleTypeDef initTimBase;
7
8
  /* enable Clocks */
9
  __HAL_RCC_TIM2_CLK_ENABLE();
10
11
  // every 1ms an overflow
12
  initTimBase.Instance = TIM2;
13
  initTimBase.Init.CounterMode = TIM_COUNTERMODE_UP;
14
  initTimBase.Init.Period = 32;
15
  initTimBase.Init.Prescaler = 1344;
16
  initTimBase.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
17
  initTimBase.Init.RepetitionCounter = 0;
18
19
20
  //HAL_TIM_Base_Start(&initTimBase);
21
22
  HAL_NVIC_SetPriority(TIM2_IRQn, 4, 1);
23
  HAL_NVIC_EnableIRQ(TIM2_IRQn);
24
25
  HAL_TIM_Base_Init(&initTimBase);   //MspInit haben keinen Rückgabewert
26
  HAL_TIM_Base_Start_IT(&initTimBase);
27
}
28
29
30
void TIM2_IRQHandler(void)
31
{
32
  int i = 0;
33
  i++;
34
}
35
36
37
38
// just defined interrupt function
39
/**
40
 * @brief  Period elapsed callback in non blocking mode
41
 * @param  htim : TIM handle
42
 * @retval None
43
 */
44
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
45
{
46
  static uint32_t time = 0;
47
  time ++;
48
49
  // 1sek
50
  if(!(time % 1000))
51
  {
52
    if((*htim).Instance == TIM2)
53
    {
54
      HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
55
    }
56
  }
57
}

von Steffen R. (steffen_rose)


Lesenswert?

Warum sollte er? Hierzu machst Du keine Angaben, die man überprüfen 
könnte.

Der Interrupt selbst ist aktiv. Du bestätigst ja selbst, dass "ein" 
Interrupthandler aufgerufen wird.
Dein Problem ist eher, dass bei Dir noch der Defaulthandler statt des 
TIM2_IRQHandler als Interrupthandler für den Timer hinterlegt ist.

von Christian (Gast)


Lesenswert?

Du musst in dem Interrupt Handler ein Flag zurück setzen, weiß jetzt 
nicht welches.

Das macht die HAL-Funktion die du aus dem Handler aufrufen musst, wenn 
du es nicht selbst machst.

mach initTimBase global
dann
1
void TIM2_IRQHandler(void){
2
    int i = 0;
3
    i++;
4
    HAL_TIM_IRQHandler(&initTimBase);
5
}

von Martin M. (murmele)


Lesenswert?

Christian schrieb:
> Du musst in dem Interrupt Handler ein Flag zurück setzen, weiß jetzt
> nicht welches.

Hat leider nichts geändert.

von Christian K. (the_kirsch)


Lesenswert?

Sehr komisch,

HAL_NVIC_* eventuell erst nach Start_IT machen.



Übrigens HAL_TIM_PeriodElapsedCallback() wird aus der 
HAL_TIM_IRQHandler() aufgerufen, und die wiederum muss aus 
TIM2_IRQHandler() mit dem richtigen Handler aufgerufen werden.

Hab mich in den letzten Wochen intensiv damit beschäftigt.

von Martin M. (murmele)


Lesenswert?

Aber dann muss ich TIM_HANDLE_Typedef global definieren. Geht das auch 
so, dass ich diese irgendwie lokal erstelle? Im Beispiel von ST wird 
aber HAL_TIM_PeriodElapsedCallback() als Interruptroutine verwendet.
Nein es ändert sich nichts, wenn ich die Zeilen vertausche.

von Christian K. (the_kirsch)


Lesenswert?

Dann schau dir mal die stm32f4xx_it.c in den Beispiel Projekten an, da 
sind die xxx_IRQHandler() definiert, die alle die HAL_xxx_IRQHandler() 
aufrufen.

Die HandleType variablen müssen leider global definiert sein.

: Bearbeitet durch User
von Christian K. (the_kirsch)


Lesenswert?

Was hast du denn als Entwicklungsumgebung?

µVision Keil mit dem MDK-ARM Compiler, oder was auf GCC Basis.

Bei meinem Eclipse wird bei der Projekterstellung bereits CMSIS und die 
HAl eingebunden, und auch durch den Startup Code initialisiert.

von Martin M. (murmele)


Lesenswert?

Ich verwende Eclipse unter Linux

Christian K. schrieb:
> Dann schau dir mal die stm32f4xx_it.c in den Beispiel Projekten an, da
> sind die xxx_IRQHandler() definiert, die alle die HAL_xxx_IRQHandler()
> aufrufen.

Stimmt sorry habe ich übersehen. Muss ich meinen Handler auch in einer 
Datei mit diesem Namen machen oder ist das egal wo ich meinen Interrupt 
Handler erstelle/ die Standardroutine überschreibe?

von Armin (Gast)


Lesenswert?

Kommentier mal den Default Handler für Timer2 aus, bei mir steht er in 
der startupxxx.S
//  .weak  TIM2_IRQHandler
//  .thumb_set TIM2_IRQHandler,Default_Handler
dann wird der Linker schon moppern.

Ich hatte den Fehler auch, meinen Handler hatte ich einer .cpp Datei und 
da wurde er nicht gefunden.

Er muss in C++ als
extern "C" void void TIM2_IRQHandler(void){
...
deklariert werden.

von Martin M. (murmele)


Lesenswert?

1
void __attribute__ ((section(".after_vectors")))
2
Default_Handler(void)
3
{
4
#if defined(DEBUG)
5
  __DEBUG_BKPT();
6
#endif
7
  while (1)
8
    {
9
    }
10
}
Wenn ich das auskommentiere dann kommen alles Fehlermeldungen, da der 
Defaulthandler nicht mehr verfügbar ist.
1
void __attribute__ ((weak, alias ("Default_Handler")))
2
TIM2_IRQHandler(void);
 Wenn ich das auskommentiere, dann kommt ein Fehler, dass 
TIM2_IRQHandler undeclariert ist. Wie kann ich meine Handler funktion 
dazu linken, dass ich Sie verwenden kann?

: Bearbeitet durch User
von Christian K. (the_kirsch)


Lesenswert?

Die Weak-Funktionen brauchen nicht auskommentiert werden.

Weak bedeutet, dass die Funktion nur benutzt wird, wenn keine andere 
gleichnamige vorhanden ist.

Martin M. schrieb:
> Muss ich meinen Handler auch in einer
> Datei mit diesem Namen machen oder ist das egal wo ich meinen Interrupt
> Handler erstelle

ist egal wo sie stehen.


Da du einen anderen Statupcode hast als ich, fehlt bei dir eventuell der

HAL_init() Aufruf, denn musst am Anfang der Main machen.

: Bearbeitet durch User
von Martin M. (murmele)


Angehängte Dateien:

Lesenswert?

Jetzt habe ich die HAL_Init eingebaut. Leider keine Veränderung.
Habe jetzt mal im Datasheet gelesen. Hier steht, dass dies die minimalen 
Dateien sind, die man braucht. Dabei ist auch die stm32f4xx_it.c wo die 
interrupt handler sein sollen. Kann ich die Datei einfach erstellen oder 
wie kann ich das verstehen?

: Bearbeitet durch User
von Steffen R. (steffen_rose)


Lesenswert?

Da der Default Interrupt Handler aufgerufen wird, brauchst Du nicht an 
der Interrupterzeugung herumzudocktern!

Armin schrieb:
> Kommentier mal den Default Handler für Timer2 aus, bei mir steht er in
> der startupxxx.S
> //  .weak  TIM2_IRQHandler
> //  .thumb_set TIM2_IRQHandler,Default_Handler
> dann wird der Linker schon moppern.

Dem stimme ich für die Fehlersuche zu. Das weak führt dazu, dass das 
fehlen des Symbols TIM2_IRQHandler überdeckt wird. Solange du versuchst 
dein Symbol sichtbar zu machen hilft der Linkerfehler weiter.

Da zu wenig Angaben gemacht wurden, hat Armin auch ein Beispiel 
geliefert, warum TIM2_IRQHandler nicht gefunden wird.

Martin M. schrieb:
> void _attribute_ ((weak, alias ("Default_Handler")))
> TIM2_IRQHandler(void); Wenn ich das auskommentiere, dann kommt ein
> Fehler, dass
> TIM2_IRQHandler undeclariert ist. Wie kann ich meine Handler funktion
> dazu linken, dass ich Sie verwenden kann?

Genau das ist dein Problem, was du lösen mußt. Nicht die Erzeugung des 
Interrupts.

Das Problem liegt in der Datei, aus dem dein Eingangs geposteter Code 
stammt. Entweder ist die Funktion nicht global sichtbar oder der 
Compiler nennt diese um. Die Idee von Armin war, dass diese mit (C++) 
gpp übersetzt wird. Und C++ hat ein anderes NamensSchema wie C. Der Code 
ist für eine Übersetzung mit einem C Compiler (gcc).

Vielleicht hast Du die Datei mit *.cpp enden lassen statt mit *.c?
Vielelicht einfach mal die Originaldatei anhängen, welche den 
TIM2_IRQHandler() enthält.

von Christian (Gast)


Lesenswert?

Zeig doch mal deinen gesamten Code.

Mit Main und allen Handlern die du definiert hast. Am besten alles in 
eine Datei reinkopieren, soviel hast du ja noch nicht.


Du verwendest als Startup Code die Assembler-Datei aus dem 
CMSIS-Package.
Die ruft einige Funktionen auf (noch bevor Main losgeht) auf die du 
selbst implementieren musst.

In den Beispielprojekten sind diese in der system_stm32f4xx.c drin.

von Martin M. (murmele)


Lesenswert?

Hier mal der gesamte Code:
1
#include <stdio.h>
2
#include "diag/Trace.h"
3
#include "stm32f411xe.h"
4
#include "stm32f4xx_hal.h"
5
6
void timer2Init();
7
8
9
// ----- main() ---------------------------------------------------------------
10
11
// Sample pragmas to cope with warnings. Please note the related line at
12
// the end of this function, used to pop the compiler diagnostics status.
13
#pragma GCC diagnostic push
14
#pragma GCC diagnostic ignored "-Wunused-parameter"
15
#pragma GCC diagnostic ignored "-Wmissing-declarations"
16
#pragma GCC diagnostic ignored "-Wreturn-type"
17
18
TIM_HandleTypeDef initTimBase;
19
20
int main(int argc, char* argv[])
21
{
22
  /* Variables */
23
  uint32_t i;
24
25
  HAL_Init();
26
  gpioInit();
27
  timer2Init();
28
29
  // Button: PC13
30
  // LED: PA5
31
32
  // Infinite loop
33
  while (1)
34
  {
35
    for(i = 0; i<500000; i++){}
36
    HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
37
  }
38
}
39
40
41
42
//TIM2: APB1
43
// Timer channel 2 as base timer
44
void timer2Init()
45
{
46
47
  /* enable Clocks */
48
  __HAL_RCC_TIM2_CLK_ENABLE();
49
50
  // every 1ms an overflow
51
  initTimBase.Instance = TIM2;
52
  initTimBase.Init.CounterMode = TIM_COUNTERMODE_UP;
53
  initTimBase.Init.Period = 32;
54
  initTimBase.Init.Prescaler = 1344;
55
  initTimBase.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
56
  initTimBase.Init.RepetitionCounter = 0;
57
58
  HAL_TIM_Base_Init(&initTimBase);   //MspInit haben keinen Rückgabewert
59
  HAL_TIM_Base_Start_IT(&initTimBase);
60
61
  HAL_NVIC_SetPriority(TIM2_IRQn, 4, 1);
62
  HAL_NVIC_EnableIRQ(TIM2_IRQn);
63
}
64
65
66
void TIM2_IRQHandler(void)
67
{
68
  HAL_TIM_IRQHandler(&initTimBase);
69
} 
70
71
72
73
// just defined interrupt function
74
/**
75
 * @brief  Period elapsed callback in non blockfaceing mode
76
 * @param  htim : TIM handle
77
 * @retval None
78
 */
79
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
80
{
81
  static uint32_t time = 0;
82
  time ++;
83
84
  // 1sek
85
  if(!(time % 1000))
86
  {
87
    if(htim->Instance == TIM2)
88
    {
89
      HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
90
    }
91
  }
92
}
93
94
#pragma GCC diagnostic pop
95
96
// ----------------------------------------------------------------------------

> Kommentier mal den Default Handler für Timer2 aus, bei mir steht er in
> der startupxxx.S
> //  .weak  TIM2_IRQHandler
> //  .thumb_set TIM2_IRQHandler,Default_Handler
> dann wird der Linker schon moppern.
Ich finde aber keine startupxxx.S Datei

: Bearbeitet durch User
von Christian K. (the_kirsch)


Lesenswert?

Nach dem generierten Main-Code sieht es so aus als ob du Eclipse 
verwendest.

Dann gibt es keine startupxxx.S Datei.
Eclipse verwendet stattdessen µOS++III als Startupcode, welcher komplett 
in C geschrieben ist (statt Assembler)

Im Startupcode wird bereits die Hal und der Systemtakt initialisiert.

Der Aufruf von HAL_Init(); in der Main ist unnötig.

Die If Abfragen in deiner Timer Callback solltest du tauschen, oder es 
direkt in den TIM2_IRQHandler schreiben.
1
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
2
  static uint32_t time = 0;
3
4
  if(htim->Instance == TIM2){
5
    time++;
6
    // 1sek
7
    if(!(time % 1000)){
8
      HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
9
    }
10
  }
11
}

Was passiert denn jetzt, springst du immer noch in den Default_Handler?
Ich sehe jetzt keine Fehler im Code.

von Martin M. (murmele)


Lesenswert?

Hat leider nichts geändert, springt immer noch in den Default Handler.

von Dieter Graef (Gast)


Lesenswert?

Hab grad einen ähnlichen Fall.Bei mir hat der Linker die schwachen 
Symbole aus dem Assemblerfile nicht durch die starken aus dem C -Code 
ersetzt. Linken mit der Option Wl,--whole-archive brachte die 
Fehlermeldung das der Assemblercode kein Objekt ist. Im C Code klappte 
das Ersetzen. Meine Theorie ist das gcc die Dinge auseinanderhalten will 
weil irgendwelche Assemblerdirektiven nicht stimmen, Meine Lösung war 
das Auskommentieren der weak Stellen im Assemblercode.

von Martin M. (murmele)


Lesenswert?

Aber ich habe ja kein Assembler Initfile in Eclipse

von Steffen R. (steffen_rose)


Lesenswert?

Martin M. schrieb:
> #pragma GCC diagnostic ignored "-Wunused-parameter"
> #pragma GCC diagnostic ignored "-Wmissing-declarations"
> #pragma GCC diagnostic ignored "-Wreturn-type"

Wozu die ganzen pragmas?

Martin M. schrieb:
>> Kommentier mal den Default Handler für Timer2 aus, bei mir steht er in
>> der startupxxx.S
>> //  .weak  TIM2_IRQHandler
>> //  .thumb_set TIM2_IRQHandler,Default_Handler
>> dann wird der Linker schon moppern.
> Ich finde aber keine startupxxx.S Datei

Naja, irgendwo mußt du die Interruptvektoren schon eingebunden haben.
Da findest Du dann auch den Code, der TIM2_IRQHandler auf 
Default_Handler umbiegt. Ich hoffe mal, dass du die Vektoren drin hast 
und der Default_Handler nicht durch einen Trap ausgelöst wird.

Dieter Graef schrieb:
> Hab grad einen ähnlichen Fall.Bei mir hat der Linker die schwachen
> Symbole aus dem Assemblerfile nicht durch die starken aus dem C -Code
> ersetzt.

Martin M. schrieb:
> Aber ich habe ja kein Assembler Initfile in Eclipse

Bei Dieter G. wird der relevante Code im Linkerfile sein.

Anm:
Da dein Projekt scheinbar anders ist, als die meisten es von uns gewöhnt 
sind, müßtest Du wohl etwas mehr beschreiben. Es geht um alles, das
TIM2_IRQHandler und Default_Handler enthält.

von Martin M. (murmele)


Lesenswert?

Steffen R. schrieb:
> Wozu die ganzen pragmas?

Die Pragmas hat Eclipse erstellt.

In der vectors_stm32f4.c wird auf den Default Handler verlinkt:
1
void __attribute__ ((weak, alias ("Default_Handler")))
2
TIM2_IRQHandler(void);

Habe mal versucht die Routine direkt hier einzufügen, hat aber nicht 
funktioniert.
Wenn ich es auskommentiere kommt folgender Fehler:
1
../system/src/cmsis/vectors_stm32f4xx.c:532:7: error: 'TIM2_IRQHandler' undeclared here (not in a function)
2
       TIM2_IRQHandler,        // TIM2
3
       ^
4
make: *** [system/src/cmsis/vectors_stm32f4xx.o] Fehler 1
5
system/src/cmsis/subdir.mk:21: die Regel für Ziel „system/src/cmsis/vectors_stm32f4xx.o“ scheiterte

von Steffen R. (steffen_rose)


Lesenswert?

Martin M. schrieb:
> vectors_stm32f4.c

OK. Genau richtig.

Kommentiere nur die 'weak' Funktionalität aus:
1
void /* __attribute__ ((weak, alias ("Default_Handler"))) */
2
TIM2_IRQHandler(void);

Die eigentliche Deklaration brauchst Du für die Vectortabelle.

Er wird vermutlich melden, dass er TIM2_IRQHandler nicht findet. Das 
wäre dann der Beweis, dass es an der Nicht-Sichtbarkeit deines 
Interrupthandlers liegt. Nun ist es an Dir den Linkerfehler zu 
beseitigen.

Wenn diese Linkerwarnung nicht kommt, sondern weiterhin der 
Default-Handler aufgerufen wird, wird ein anderer Interrupt/Trap 
aufgerufen.

Danach kannst Du den Originalzustand in vectors_stm32f4.c wieder 
herstellen.

von Martin M. (murmele)


Lesenswert?

Springt immer noch in den Default Handler. Hab aber in der gleichen .c 
Datei noch das gefunden. kann damit aber leider nichts anfangen.
1
// The vector table.
2
// This relies on the linker script to place at correct location in memory.
3
4
__attribute__ ((section(".isr_vector"),used))
5
pHandler __isr_vectors[] =
6
  {
7
  // Core Level - CM4
8
      (pHandler) &_estack,                      // The initial stack pointer
9
      Reset_Handler,                            // The reset handler
10
11
      NMI_Handler,                              // The NMI handler
12
      HardFault_Handler,                   
13
14
...
15
16
#elif defined(STM32F411xE)
17
18
      WWDG_IRQHandler,        // Window WatchDog
19
      PVD_IRQHandler, // PVD through EXTI Line detection
20
...
21
22
  TIM1_TRG_COM_TIM11_IRQHandler,  // TIM1 Trigger and Commutation and TIM11
23
      TIM1_CC_IRQHandler,     // TIM1 Capture Compare
24
      TIM2_IRQHandler,        // TIM2
25
      TIM3_IRQHandler,        // TIM3
26
      TIM4_IRQHandler,        // TIM4
27
      I2C1_EV_IRQHandler,     // I2C1 Event
28
...

In der HAL_Init() wird der SysClock initialisiert:
1
__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
2
{
3
  /*Configure the SysTick to have interrupt in 1ms time basis*/
4
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
5
6
  /*Configure the SysTick IRQ priority */
7
  HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority ,0);
8
9
  /* Return function status */
10
  return HAL_OK;
11
}
aber die Interrupt Funktion wird nicht aufgerufen und soweit dass andere 
Interrupts noch laufen bin ich noch nicht.

von Dieter Graef (Gast)


Lesenswert?

Martin M. schrieb
>Springt immer noch in den Default Handler. Hab aber in der gleichen >.c
>Datei noch das gefunden. kann damit aber leider nichts anfangen.
Dem Linker muß mitgeteilt werden wo sich was im Mikrokontroller befindet 
(RAM ROM)
Dazu wird dem Linker per Option ein Linkerscript meist mit der 
Dateiendung ld  mitgegeben in dem dann unter anderem steht:

/* Specify the memory areas */
MEMORY
{
FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 512K
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K
}

/* Define output sections */
SECTIONS
{
  /* The startup code goes first into FLASH */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH

von Steffen R. (steffen_rose)


Lesenswert?

Einfach die komplette Datei anhängen. Ist einfacher und enthält auch 
Infos, an die du nicht denkst.

Was sagt das Mapping File?
Hast Du das richtige Derivate ausgewählt oder nur ein ähnliches?

HAL_InitTick() nutzt den Systick interrupt. Aber der sollte bei dir auch 
schon eingerichtet sein, oder? Den genauen Namen hast du mit deinen ... 
verschluckt. Ich glaube Systick_Handler().

Du kannst echt nicht debuggen?

von Steffen R. (steffen_rose)


Lesenswert?

Dieter Graef schrieb:
> Dem Linker muß mitgeteilt werden wo sich was im Mikrokontroller befindet

Ohne diese Angabe wäre er gnadenlos abgestürzt.
Aber richtig:
@Martin: Woher weißt du, dass du im Default_Handler() landest?

von Martin M. (murmele)


Angehängte Dateien:

Lesenswert?

Steffen R. schrieb:
> Woher weißt du, dass du im Default_Handler() landest?
Er springt immer in diese Routine:
1
void __attribute__ ((section(".after_vectors")))
2
Default_Handler(void)
3
{
4
#if defined(DEBUG)
5
  __DEBUG_BKPT();
6
#endif
7
  while (1)
8
    {
9
    }
10
}
Ich habe dort zwar kein Brakepoint gesetzt, aber der Debugger hält hier 
immer.

Im Anhang habe ich jetzt mal das komplette Projekt hochgeladen.

"Placeholder to list other libraries required by the application." Das 
steht in der libs.ld muss ich da eventuell meine C Dateien angeben?

Dieter Graef schrieb:
> Dazu wird dem Linker per Option ein Linkerscript meist mit der
> Dateiendung ld  mitgegeben in dem dann unter anderem steht:

Ja habe ich gefunden.

Steffen R. schrieb:
> Was sagt das Mapping File?
> Hast Du das richtige Derivate ausgewählt oder nur ein ähnliches?

???

Steffen R. schrieb:
> Du kannst echt nicht debuggen?

Doch ich kann Debuggen, habe nie gesagt, dass ich das nicht kann.

von Steffen R. (steffen_rose)


Lesenswert?

Martin M. schrieb:
> Ich habe dort zwar kein Brakepoint gesetzt, aber der Debugger hält hier
> immer.

Na toll.... ;-)

Schau doch gleich in das PSR Register (genauer IPSR, weiß nicht, was bei 
den Core registern angezeigt wird). Dort findest Du den Auslöser des 
Interrupts (Interruptnummer). In deinem Datasheet zu deinem Prozessor 
solltest du die Nummer auflösen können.
(mehr Details im Dokument DM00046982)

Lt. deinem Mappingfile sollte es wohl eines von den Handlern sein, die 
du dort aufgelistet findest:
1
0x0000000008000418        0x4 ./system/src/cmsis/vectors_stm32f4xx.o
2
                0x0000000008000418                RTC_Alarm_IRQHandler
3
                0x0000000008000418                EXTI2_IRQHandler
4
[...]

Christian schrieb:
> Habe hier ein "WaveShare Core 4171" mit einem STM32F407 auf einem
> "WaveShare Open 4171" Breakout-Board.

Martin M. schrieb:
> Steffen R. schrieb:
>> Was sagt das Mapping File?
>> Hast Du das richtige Derivate ausgewählt oder nur ein ähnliches?
>
> ???

Wenn Du einen STM32F407 hast, wäre das Define STM32F411xE offensichtlich 
falsch. Ich vermute STM32F407xx wäre richtig. Das würde dann auch 
erklären, dass der Timer2 Interrupt nicht an der richtigen Stelle wäre.

von Christian K. (the_kirsch)


Lesenswert?

@Martin M.
Erstell nochmal das Projekt neu, und achte das du wirklich den richtigen 
Controller angibst.

Und ändere nichts an den Quellcodedateien im Systemordner.
Eventuell hast du durch dein editieren die Vektortabelle kaputt gemacht.

Alle relevanten Funktionen sind als WEAK Definiert, das heißt du kannst 
sie in deinem Code einfach neu definieren.

@Steffen Rose
Ich bin TO, aber mein Problem ist schon seit längerem gelöst.

von Martin M. (murmele)


Lesenswert?

Steffen R. schrieb:
> Wenn Du einen STM32F407 hast

Nein ich habe einen stm32f411re. Hat am Anfang das Problem dass der 
externe Clock nicht stimmte der Standardmäßig eingestellt wurde, weshalb 
es auch lange nicht ging.

von Steffen R. (steffen_rose)


Lesenswert?

Christian K. schrieb:
> @Martin M.
> Erstell nochmal das Projekt neu, und achte das du wirklich den richtigen
> Controller angibst.
>
> Und ändere nichts an den Quellcodedateien im Systemordner.
> Eventuell hast du durch dein editieren die Vektortabelle kaputt gemacht.

Zugegeben. Korrekterweise gehören Dateien, die man ändert, immer ins 
Projekt.
Uns man sollte immer auch die Originaldateien behalten, um Fehler wieder 
rückgängig zu machen.

> Alle relevanten Funktionen sind als WEAK Definiert, das heißt du kannst
> sie in deinem Code einfach neu definieren.

Meine Vermutung war, dass das Überdefinieren nicht geklappt hat. Durch 
das weak bekommt man aber keinen Fehler. Welche Alternative hätte man?

> @Steffen Rose
> Ich bin TO, aber mein Problem ist schon seit längerem gelöst.

Mist. Ist mir nicht aufgefallen, dass dein Thread nachgenutzt wurde.

Martin M. schrieb:
> Steffen R. schrieb:
>> Wenn Du einen STM32F407 hast
>
> Nein ich habe einen stm32f411re. Hat am Anfang das Problem dass der
> externe Clock nicht stimmte der Standardmäßig eingestellt wurde, weshalb
> es auch lange nicht ging.

Wie soll man hier noch durchblicken. Wäre hier nicht ein eigener Thread 
besser gewesen?

Also weiter mit dem IPSR.

von Dieter Gräf (Gast)


Lesenswert?

@Martin
Hab das Projekt auf einem stm32f407 mit einigen Änderungen  zum laufen 
bekommen.
Mein Linker kam mit der weak Zuweisungen nicht klar
die Methode aus vectors_stm32f4xx.c mit
    void __attribute__((weak))
    Default_Handler(void);
und dann
  void /*__attribute__ ((weak, alias ("Default_Handler"))) */
  TIM2_IRQHandler(void);
mit
  void _attribute_ ((section(".after_vectors")))
  Default_Handler(void)
  {
   #if defined(DEBUG)
   __DEBUG_BKPT();
  #endif
  while (1)
    {
    }
}
sprang generell in die Default routine auch wenn woanders der
TIM2_IRQHandler definiert war. Mit
 void /*__attribute__ ((weak)) */
  TIM2_IRQHandler(void)
{
}
gings aber. Wenn das oben genannte funktioniert spart es Speicherplatz. 
Zusätzlich hab ich noch den ganzen Startuprummel in c durch die von ST 
vorgegebene Assemblermethode mit startup_stm32f407xx.s ersetzen müssen 
da ansonsten gleich ein HardFault kam.

von Martin M. (murmele)


Lesenswert?

Dieter Gräf schrieb:
> TIM2_IRQHandler definiert war. Mit
>  void /*__attribute__ ((weak)) */
>   TIM2_IRQHandler(void)
> {
> }
> gings aber.

Hast du einfach das _attribute_ ((weak)) auskommentiert?

von Dieter Graef (Gast)


Lesenswert?

Martin M schrieb:
>Hast du einfach das attribute ((weak)) auskommentiert?
nee sorry ein copy und paste fehler

__attribute__((weak)) void TIM2_IRQHandler(void)
{
}

ich hab ne echte Funktion draus gemacht keinen alias

m.f.G.
Dieter

von Martin M. (murmele)


Lesenswert?

Wenn ich eine echte Funktion mache und das weak nicht auskommentiere, 
wird immer noch der Default Handler ausgeführt, wenn ich das weak weg 
lasse, dann kommt der Fehler, dass es hier das erste mal definiert 
wurde.

von Dieter Graef (Gast)


Lesenswert?

Martin M. schrieb:
>dann kommt der Fehler, dass es hier das erste mal definiert
>wurde

Das ist richtig da in deiner main.c Datei die Funktion ja schon steht.
Wie gesagt ich hab dann den c startup code aus deinem Projekt durch 
Assembler von ST ersetzt und dann gings.Leider hab ich nur den 407 und 
nicht den 411.Vermutlich ist deine Vorlage gar nicht für den gcc 
Compiler sondern für einen anderen.

m.f.G.
Dieter

von Martin M. (murmele)


Lesenswert?

Ich weiß nicht obs was hilft, aber mein Projekt wird nicht mit dem gcc 
sondern mit der c++ variante kompiliert.

von Steffen R. (steffen_rose)


Lesenswert?


von Martin M. (murmele)


Lesenswert?

Auf meinem Laptop hat sich Eclipse geupdatet. Jetzt konnte ich auswählen 
ob ich ein C oder ein C++ Programm schreiben wollte ( vorher stand immer 
C/C++ Programm jetzt stehen Sie getrennt)
Habe am Code nur das extern "C" eingefügt, was vorher keine Wirkung 
hatte, und siehe da er springt in die Routine rein :)

Ein großes Danke an alle die mir hier geholfen haben!!!

: Bearbeitet durch User
von Sören (Gast)


Lesenswert?

Christian schrieb:
> OK, also wenn die maximale Timer-Clock, 1/2 CPU-Clock ist, dann
> läuft
> mein Timer sogar um den Faktor 4 zu schnell.
>
> Also, so als ob diese Zeile kein Effet hat.hT4.Init.ClockDivision =
> TIM_CLOCKDIVISION_DIV4;
> Dann werde ich mir mal Reference Manual reinziehen.

Ich habe das selbe Problem mit einem STM32F746IGK, dass 
TIM_CLOCKDIVISION_ kein Effekt hat. Konntet ihr das lösen? Mein 
Prescaler ist bereits am Limit, weshalb ich auf die Taktteilung 
angewiesen bin.
Danke

von Christian K. (the_kirsch)


Lesenswert?

Ich hab mich mittlerweile komplett von der Cube-HAL gelöst.

Und greife jetzt ausschließlich über CMSIS (die Hardware-Register 
direkt) zu.

Registerdefinitionen einfach im Datenblatt nachschlagen.

Hier aus meinem letzten Projekt:
timer4.h
1
#ifndef STM32F4_TIMER4_H
2
#define STM32F4_TIMER4_H
3
4
void timer4_init(void);
5
void timer4_enableInt(void);
6
7
//WEAK
8
void timer4_1sec_event1(void);
9
10
#endif /* STM32F4_TIMER4_H */
timer4.c
1
#include <CMSIS_Device/stm32f4xx.h>
2
3
#include "timer4.h"
4
5
void TIM4_IRQHandler(void);
6
7
void TIM4_IRQHandler(void) {
8
  static int i = 0;
9
  if (TIM4->SR & TIM_SR_UIF) {
10
    i++;
11
    if (i == 125) {
12
      timer4_1sec_event1();
13
      i = 0;
14
    }
15
    TIM4->SR = ~TIM_SR_UIF;
16
  }
17
}
18
19
void timer4_init(void) {
20
  /*
21
   * GP 16-Bit Timer
22
   */
23
24
  RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
25
26
  TIM4->PSC = 840 - 1; // 84 MHz / (840) = 100 KHz
27
  TIM4->ARR = 800 - 1; // 100 KHz / (800) = 125 Hz
28
  TIM4->EGR = TIM_EGR_UG; // Generate an update event to reload the Prescaler
29
30
  TIM4->CR1 = TIM_CR1_CEN; // Edge-aligned mode; upcounter; TIM enable
31
  //TIM4->CR2;
32
  //TIM4->SMCR;
33
  //TIM4->DIER = TIM_DIER_UIE; // Enable the TIM Update interrupt
34
  //TIM4->SR;
35
  //TIM4->CCMR1;
36
  //TIM4->CCMR2;
37
  //TIM4->CCER;
38
  //TIM4->CNT;
39
  //TIM4->RCR;
40
  //TIM4->CCR1;
41
  //TIM4->CCR2;
42
  //TIM4->CCR3;
43
  //TIM4->CCR4;
44
  //TIM4->BDTR;
45
  //TIM4->DCR;
46
  //TIM4->DMAR;
47
  //TIM4->OR;
48
49
  NVIC_SetPriority(TIM4_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 6, 0));
50
  NVIC_EnableIRQ(TIM4_IRQn);
51
}
52
53
void timer4_enableInt(void) {
54
  TIM4->DIER = TIM_DIER_UIE; // Enable the TIM Update interrupt
55
}
56
57
void __attribute__ ((weak)) timer4_1sec_event1(void) {
58
}
59
60
//EOF

von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

TIM_CLOCKDIVISION_ ist für etwas anderes gedacht als es auf den 1. Blick 
scheint. Einfach mal uns Manual schauen.

von Koni (Gast)


Lesenswert?

Hallo,

ich bin so frech und knüpfe hier einfach mal an. Ich habe das Problem 
mit dem Timer6, dass wenn ich den Timer mit
1
HAL_TIM_Base_Start_IT(&htim6);
starte und im Anschluss mit
1
HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);
den Interrupt aktiviere, er direkt in die IRQ springt, was ich aber 
nicht möchte und auch absolut keinen Sinn macht.
Muss ich vorher irgendein Bit löschen?
Kennt jemand dieses Problem?

Vielen Dank!

von Reginald L. (Firma: HEGRO GmbH) (reggie)


Lesenswert?

Kein Plan. HAL ist ein Krampf :)

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Koni schrieb:
> Muss ich vorher irgendein Bit löschen?

Ja bitte. Und zwar vermutlich das TIM_IT_Update Bit (oder bei dir das 
DAC Bit, das ich nicht nachschlagen werde). Dann die ISR freigeben. Nu 
frag aber nicht, wie man das mit HAL macht - davon bin ich aus 
medizinischen Gründen befreit worden :-)

: Bearbeitet durch User
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.